// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "vec3.h"
#include "vec4.h"

#include "transcendental.h"

namespace embree
{
  ////////////////////////////////////////////////////////////////
  // Quaternion Struct
  ////////////////////////////////////////////////////////////////

  template<typename T>
  struct QuaternionT
  {
    typedef Vec3<T> Vector;

    ////////////////////////////////////////////////////////////////////////////////
    /// Construction
    ////////////////////////////////////////////////////////////////////////////////

    __forceinline QuaternionT           ()                     { }
    __forceinline QuaternionT           ( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; }
    __forceinline QuaternionT& operator=( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; return *this; }

    __forceinline          QuaternionT( const T& r       ) : r(r), i(zero), j(zero), k(zero) {}
    __forceinline explicit QuaternionT( const Vec3<T>& v ) : r(zero), i(v.x), j(v.y), k(v.z) {}
    __forceinline explicit QuaternionT( const Vec4<T>& v ) : r(v.x), i(v.y), j(v.z), k(v.w) {}
    __forceinline          QuaternionT( const T& r, const T& i, const T& j, const T& k ) : r(r), i(i), j(j), k(k) {}
    __forceinline          QuaternionT( const T& r, const Vec3<T>& v ) : r(r), i(v.x), j(v.y), k(v.z) {}

    __inline QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz );
    __inline QuaternionT( const T& yaw, const T& pitch, const T& roll );

    ////////////////////////////////////////////////////////////////////////////////
    /// Constants
    ////////////////////////////////////////////////////////////////////////////////

    __forceinline QuaternionT( ZeroTy ) : r(zero), i(zero), j(zero), k(zero) {}
    __forceinline QuaternionT( OneTy  ) : r( one), i(zero), j(zero), k(zero) {}

    /*! return quaternion for rotation around arbitrary axis */
    static __forceinline QuaternionT rotate(const Vec3<T>& u, const T& r) {
      return QuaternionT<T>(cos(T(0.5)*r),sin(T(0.5)*r)*normalize(u));
    }

    /*! returns the rotation axis of the quaternion as a vector */
    __forceinline Vec3<T> v( ) const { return Vec3<T>(i, j, k); }

  public:
    T r, i, j, k;
  };

  template<typename T> __forceinline QuaternionT<T> operator *( const T             & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a * b.r, a * b.i, a * b.j, a * b.k); }
  template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const T             & b ) { return QuaternionT<T>(a.r * b, a.i * b, a.j * b, a.k * b); }

  ////////////////////////////////////////////////////////////////
  // Unary Operators
  ////////////////////////////////////////////////////////////////

  template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a ) { return QuaternionT<T>(+a.r, +a.i, +a.j, +a.k); }
  template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a ) { return QuaternionT<T>(-a.r, -a.i, -a.j, -a.k); }
  template<typename T> __forceinline QuaternionT<T> conj      ( const QuaternionT<T>& a ) { return QuaternionT<T>(a.r, -a.i, -a.j, -a.k); }
  template<typename T> __forceinline T              abs       ( const QuaternionT<T>& a ) { return sqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
  template<typename T> __forceinline QuaternionT<T> rcp       ( const QuaternionT<T>& a ) { return conj(a)*rcp(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }
  template<typename T> __forceinline QuaternionT<T> normalize ( const QuaternionT<T>& a ) { return a*rsqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); }

  // evaluates a*q-r
  template<typename T> __forceinline QuaternionT<T>
  msub(const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)
  {
    return QuaternionT<T>(msub(a, q.r, p.r),
                          msub(a, q.i, p.i),
                          msub(a, q.j, p.j),
                          msub(a, q.k, p.k));
  }
  // evaluates a*q-r
  template<typename T> __forceinline QuaternionT<T>
  madd (const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p)
  {
    return QuaternionT<T>(madd(a, q.r, p.r),
                          madd(a, q.i, p.i),
                          madd(a, q.j, p.j),
                          madd(a, q.k, p.k));
  }

  ////////////////////////////////////////////////////////////////
  // Binary Operators
  ////////////////////////////////////////////////////////////////

  template<typename T> __forceinline QuaternionT<T> operator +( const T             & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a + b.r,  b.i,  b.j,  b.k); }
  template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const T             & b ) { return QuaternionT<T>(a.r + b, a.i, a.j, a.k); }
  template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r + b.r, a.i + b.i, a.j + b.j, a.k + b.k); }
  template<typename T> __forceinline QuaternionT<T> operator -( const T             & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a - b.r, -b.i, -b.j, -b.k); }
  template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const T             & b ) { return QuaternionT<T>(a.r - b, a.i, a.j, a.k); }
  template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r - b.r, a.i - b.i, a.j - b.j, a.k - b.k); }

  template<typename T> __forceinline Vec3<T>       operator *( const QuaternionT<T>& a, const Vec3<T>      & b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); }
  template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const QuaternionT<T>& b ) {
    return QuaternionT<T>(a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k,
                          a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j,
                          a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i,
                          a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r);
  }
  template<typename T> __forceinline QuaternionT<T> operator /( const T             & a, const QuaternionT<T>& b ) { return a*rcp(b); }
  template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const T             & b ) { return a*rcp(b); }
  template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a*rcp(b); }

  template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const T             & b ) { return a = a+b; }
  template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a+b; }
  template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const T             & b ) { return a = a-b; }
  template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a-b; }
  template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const T             & b ) { return a = a*b; }


inline void rcVcross(float* dest, const float* v1, const float* v2)
{
	dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
	dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
	dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
}

/// Derives the dot product of two vectors. (@p v1 . @p v2)
/// @param[in]		v1	A Vector [(x, y, z)]
/// @param[in]		v2	A vector [(x, y, z)]
/// @return The dot product.
inline float rcVdot(const float* v1, const float* v2)
{
	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}

/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
/// @param[out]		dest	The result vector. [(x, y, z)]
/// @param[in]		v1		The base vector. [(x, y, z)]
/// @param[in]		v2		The vector to scale and add to @p v1. [(x, y, z)]
/// @param[in]		s		The amount to scale @p v2 by before adding to @p v1.
inline void rcVmad(float* dest, const float* v1, const float* v2, const float s)
{
	dest[0] = v1[0]+v2[0]*s;
	dest[1] = v1[1]+v2[1]*s;
	dest[2] = v1[2]+v2[2]*s;
}

/// Performs a vector addition. (@p v1 + @p v2)
/// @param[out]		dest	The result vector. [(x, y, z)]
/// @param[in]		v1		The base vector. [(x, y, z)]
/// @param[in]		v2		The vector to add to @p v1. [(x, y, z)]
inline void rcVadd(float* dest, const float* v1, const float* v2)
{
	dest[0] = v1[0]+v2[0];
	dest[1] = v1[1]+v2[1];
	dest[2] = v1[2]+v2[2];
}

/// Performs a vector subtraction. (@p v1 - @p v2)
/// @param[out]		dest	The result vector. [(x, y, z)]
/// @param[in]		v1		The base vector. [(x, y, z)]
/// @param[in]		v2		The vector to subtract from @p v1. [(x, y, z)]
inline void rcVsub(float* dest, const float* v1, const float* v2)
{
	dest[0] = v1[0]-v2[0];
	dest[1] = v1[1]-v2[1];
	dest[2] = v1[2]-v2[2];
}

/// Selects the minimum value of each element from the specified vectors.
/// @param[in,out]	mn	A vector.  (Will be updated with the result.) [(x, y, z)]
/// @param[in]		v	A vector. [(x, y, z)]
inline void rcVmin(float* mn, const float* v)
{
	mn[0] = rcMin(mn[0], v[0]);
	mn[1] = rcMin(mn[1], v[1]);
	mn[2] = rcMin(mn[2], v[2]);
}

/// Selects the maximum value of each element from the specified vectors.
/// @param[in,out]	mx	A vector.  (Will be updated with the result.) [(x, y, z)]
/// @param[in]		v	A vector. [(x, y, z)]
inline void rcVmax(float* mx, const float* v)
{
	mx[0] = rcMax(mx[0], v[0]);
	mx[1] = rcMax(mx[1], v[1]);
	mx[2] = rcMax(mx[2], v[2]);
}

/// Performs a vector copy.
/// @param[out]		dest	The result. [(x, y, z)]
/// @param[in]		v		The vector to copy. [(x, y, z)]
inline void rcVcopy(float* dest, const float* v)
{
	dest[0] = v[0];
	dest[1] = v[1];
	dest[2] = v[2];
}

/// Returns the distance between two points.
/// @param[in]		v1	A point. [(x, y, z)]
/// @param[in]		v2	A point. [(x, y, z)]
/// @return The distance between the two points.
inline float rcVdist(const float* v1, const float* v2)
{
	float dx = v2[0] - v1[0];
	float dy = v2[1] - v1[1];
	float dz = v2[2] - v1[2];
	return rcSqrt(dx*dx + dy*dy + dz*dz);
}

/// Returns the square of the distance between two points.
/// @param[in]		v1	A point. [(x, y, z)]
/// @param[in]		v2	A point. [(x, y, z)]
/// @return The square of the distance between the two points.
inline float rcVdistSqr(const float* v1, const float* v2)
{
	float dx = v2[0] - v1[0];
	float dy = v2[1] - v1[1];
	float dz = v2[2] - v1[2];
	return dx*dx + dy*dy + dz*dz;
}

/// Normalizes the vector.
/// @param[in,out]	v	The vector to normalize. [(x, y, z)]
inline void rcVnormalize(float* v)
{
	float d = 1.0f / rcSqrt(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2]));
	v[0] *= d;
	v[1] *= d;
	v[2] *= d;
}

/// @}
/// @name Heightfield Functions
/// @see rcHeightfield
/// @{

/// Calculates the bounding box of an array of vertices.
/// @ingroup recast
/// @param[in]		verts		An array of vertices. [(x, y, z) * @p nv]
/// @param[in]		numVerts	The number of vertices in the @p verts array.
/// @param[out]		minBounds	The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
/// @param[out]		maxBounds	The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
void rcCalcBounds(const float* verts, int numVerts, float* minBounds, float* maxBounds);

/// Calculates the grid size based on the bounding box and grid cell size.
/// @ingroup recast
/// @param[in]		minBounds	The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
/// @param[in]		maxBounds	The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
/// @param[in]		cellSize	The xz-plane cell size. [Limit: > 0] [Units: wu]
/// @param[out]		sizeX		The width along the x-axis. [Limit: >= 0] [Units: vx]
/// @param[out]		sizeZ		The height along the z-axis. [Limit: >= 0] [Units: vx]
void rcCalcGridSize(const float* minBounds, const float* maxBounds, float cellSize, int* sizeX, int* sizeZ);

/// Initializes a new heightfield.
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocHeightfield, rcHeightfield
/// @ingroup recast
///
/// @param[in,out]	context		The build context to use during the operation.
/// @param[in,out]	heightfield	The allocated heightfield to initialize.
/// @param[in]		sizeX		The width of the field along the x-axis. [Limit: >= 0] [Units: vx]
/// @param[in]		sizeZ		The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
/// @param[in]		minBounds	The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
/// @param[in]		maxBounds	The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]


namespace VHACD {
// -- GODOT end --

/**@brief btVector3 can be used to represent 3D points and vectors.
 * It has an un-used w component to suit 16-byte alignment when btVector3 is stored in containers. This extra component can be used by derived classes (Quaternion?) or by user
 * Ideally, this class should be replaced by a platform optimized SIMD version that keeps the data in registers
 */
ATTRIBUTE_ALIGNED16(class)
btVector3
{
public:
#if defined(__SPU__) && defined(__CELLOS_LV2__)
    btScalar m_floats[4];

public:
    SIMD_FORCE_INLINE const vec_float4& get128() const
    {
        return *((const vec_float4*)&m_floats[0]);
    }

public:
#else //__CELLOS_LV2__ __SPU__
#ifdef BT_USE_SSE // _WIN32
    union {
        __m128 mVec128;
        btScalar m_floats[4];
    };
    SIMD_FORCE_INLINE __m128 get128() const
    {
        return mVec128;
    }
    SIMD_FORCE_INLINE void set128(__m128 v128)
    {
        mVec128 = v128;
    }
#else
    btScalar m_floats[4];
#endif
#endif //__CELLOS_LV2__ __SPU__

public:
    /**@brief No initialization constructor */
    SIMD_FORCE_INLINE btVector3() {}

    /**@brief Constructor from scalars
   * @param x X value
   * @param y Y value
   * @param z Z value
   */
    SIMD_FORCE_INLINE btVector3(const btScalar& x, const btScalar& y, const btScalar& z)
    {
        m_floats[0] = x;
        m_floats[1] = y;
        m_floats[2] = z;
        m_floats[3] = btScalar(0.);
    }

    /**@brief Add a vector to this one
 * @param The vector to add to this one */
    SIMD_FORCE_INLINE btVector3& operator+=(const btVector3& v)
    {

        m_floats[0] += v.m_floats[0];
        m_floats[1] += v.m_floats[1];
        m_floats[2] += v.m_floats[2];
        return *this;
    }

    /**@brief Subtract a vector from this one
   * @param The vector to subtract */
    SIMD_FORCE_INLINE btVector3& operator-=(const btVector3& v)
    {
        m_floats[0] -= v.m_floats[0];
        m_floats[1] -= v.m_floats[1];
        m_floats[2] -= v.m_floats[2];
        return *this;
    }
    /**@brief Scale the vector
   * @param s Scale factor */
    SIMD_FORCE_INLINE btVector3& operator*=(const btScalar& s)
    {
        m_floats[0] *= s;
        m_floats[1] *= s;
        m_floats[2] *= s;
        return *this;
    }

    /**@brief Inversely scale the vector
   * @param s Scale factor to divide by */
    SIMD_FORCE_INLINE btVector3& operator/=(const btScalar& s)
    {
        btFullAssert(s != btScalar(0.0));
        return * this *= btScalar(1.0) / s;
    }

    /**@brief Return the dot product
   * @param v The other vector in the dot product */
    SIMD_FORCE_INLINE btScalar dot(const btVector3& v) const
    {
        return m_floats[0] * v.m_floats[0] + m_floats[1] * v.m_floats[1] + m_floats[2] * v.m_floats[2];
    }

    /**@brief Return the length of the vector squared */
    SIMD_FORCE_INLINE btScalar length2() const
    {
        return dot(*this);
    }

    /**@brief Return the length of the vector */
    SIMD_FORCE_INLINE btScalar length() const
    {
        return btSqrt(length2());
    }

    /**@brief Return the distance squared between the ends of this and another vector
   * This is symantically treating the vector like a point */
    SIMD_FORCE_INLINE btScalar distance2(const btVector3& v) const;

    /**@brief Return the distance between the ends of this and another vector
   * This is symantically treating the vector like a point */
    SIMD_FORCE_INLINE btScalar distance(const btVector3& v) const;

    SIMD_FORCE_INLINE btVector3& safeNormalize()
    {
        btVector3 absVec = this->absolute();
        int32_t maxIndex = absVec.maxAxis();
        if (absVec[maxIndex] > 0) {
            *this /= absVec[maxIndex];
            return * this /= length();
        }
        setValue(1, 0, 0);
        return *this;
    }

    /**@brief Normalize this vector
   * x^2 + y^2 + z^2 = 1 */
    SIMD_FORCE_INLINE btVector3& normalize()
    {
        return * this /= length();
    }

    /**@brief Return a normalized version of this vector */
    SIMD_FORCE_INLINE btVector3 normalized() const;

    /**@brief Return a rotated version of this vector
   * @param wAxis The axis to rotate about
   * @param angle The angle to rotate by */
    SIMD_FORCE_INLINE btVector3 rotate(const btVector3& wAxis, const btScalar angle) const;

    /**@brief Return the angle between this and another vector
   * @param v The other vector */
    SIMD_FORCE_INLINE btScalar angle(const btVector3& v) const
    {
        btScalar s = btSqrt(length2() * v.length2());
        btFullAssert(s != btScalar(0.0));
        return btAcos(dot(v) / s);
    }
    /**@brief Return a vector will the absolute values of each element */
    SIMD_FORCE_INLINE btVector3 absolute() const
    {
        return btVector3(
            btFabs(m_floats[0]),
            btFabs(m_floats[1]),
            btFabs(m_floats[2]));
    }
    /**@brief Return the cross product between this and another vector
   * @param v The other vector */
    SIMD_FORCE_INLINE btVector3 cross(const btVector3& v) const
    {
        return btVector3(
            m_floats[1] * v.m_floats[2] - m_floats[2] * v.m_floats[1],
            m_floats[2] * v.m_floats[0] - m_floats[0] * v.m_floats[2],
            m_floats[0] * v.m_floats[1] - m_floats[1] * v.m_floats[0]);
    }

    SIMD_FORCE_INLINE btScalar triple(const btVector3& v1, const btVector3& v2) const
    {
        return m_floats[0] * (v1.m_floats[1] * v2.m_floats[2] - v1.m_floats[2] * v2.m_floats[1]) + m_floats[1] * (v1.m_floats[2] * v2.m_floats[0] - v1.m_floats[0] * v2.m_floats[2]) + m_floats[2] * (v1.m_floats[0] * v2.m_floats[1] - v1.m_floats[1] * v2.m_floats[0]);
    }

    /**@brief Return the axis with the smallest value
   * Note return values are 0,1,2 for x, y, or z */
    SIMD_FORCE_INLINE int32_t minAxis() const
    {
        return m_floats[0] < m_floats[1] ? (m_floats[0] < m_floats[2] ? 0 : 2) : (m_floats[1] < m_floats[2] ? 1 : 2);
    }

    /**@brief Return the axis with the largest value
   * Note return values are 0,1,2 for x, y, or z */
    SIMD_FORCE_INLINE int32_t maxAxis() const
    {
        return m_floats[0] < m_floats[1] ? (m_floats[1] < m_floats[2] ? 2 : 1) : (m_floats[0] < m_floats[2] ? 2 : 0);
    }

    SIMD_FORCE_INLINE int32_t furthestAxis() const
    {
        return absolute().minAxis();
    }

    SIMD_FORCE_INLINE int32_t closestAxis() const
    {
        return absolute().maxAxis();
    }


operator*(const btVector3& v, const btScalar& s)
{
    return btVector3(v.m_floats[0] * s, v.m_floats[1] * s, v.m_floats[2] * s);
}

/**@brief Return the vector scaled by s */
SIMD_FORCE_INLINE btVector3
operator*(const btScalar& s, const btVector3& v)
{
    return v * s;
}

/**@brief Return the vector inversely scaled by s */
SIMD_FORCE_INLINE btVector3
operator/(const btVector3& v, const btScalar& s)
{
    btFullAssert(s != btScalar(0.0));
    return v * (btScalar(1.0) / s);
}

/**@brief Return the vector inversely scaled by s */
SIMD_FORCE_INLINE btVector3
operator/(const btVector3& v1, const btVector3& v2)
{
    return btVector3(v1.m_floats[0] / v2.m_floats[0], v1.m_floats[1] / v2.m_floats[1], v1.m_floats[2] / v2.m_floats[2]);
}

/**@brief Return the dot product between two vectors */
SIMD_FORCE_INLINE btScalar
btDot(const btVector3& v1, const btVector3& v2)
{
    return v1.dot(v2);
}

/**@brief Return the distance squared between two vectors */
SIMD_FORCE_INLINE btScalar
btDistance2(const btVector3& v1, const btVector3& v2)
{
    return v1.distance2(v2);
}

/**@brief Return the distance between two vectors */
SIMD_FORCE_INLINE btScalar
btDistance(const btVector3& v1, const btVector3& v2)
{
    return v1.distance(v2);
}

/**@brief Return the angle between two vectors */
SIMD_FORCE_INLINE btScalar
btAngle(const btVector3& v1, const btVector3& v2)
{
    return v1.angle(v2);
}

/**@brief Return the cross product of two vectors */
SIMD_FORCE_INLINE btVector3
btCross(const btVector3& v1, const btVector3& v2)
{
    return v1.cross(v2);
}

SIMD_FORCE_INLINE btScalar
btTriple(const btVector3& v1, const btVector3& v2, const btVector3& v3)
{
    return v1.triple(v2, v3);
}

/**@brief Return the linear interpolation between two vectors
 * @param v1 One vector
 * @param v2 The other vector
 * @param t The ration of this to v (t = 0 => return v1, t=1 => return v2) */
SIMD_FORCE_INLINE btVector3
lerp(const btVector3& v1, const btVector3& v2, const btScalar& t)
{
    return v1.lerp(v2, t);
}

SIMD_FORCE_INLINE btScalar btVector3::distance2(const btVector3& v) const
{
    return (v - *this).length2();
}

SIMD_FORCE_INLINE btScalar btVector3::distance(const btVector3& v) const
{
    return (v - *this).length();
}

SIMD_FORCE_INLINE btVector3 btVector3::normalized() const
{
    return *this / length();
}

SIMD_FORCE_INLINE btVector3 btVector3::rotate(const btVector3& wAxis, const btScalar angle) const
{
    // wAxis must be a unit lenght vector

    btVector3 o = wAxis * wAxis.dot(*this);
    btVector3 x = *this - o;
    btVector3 y;

    y = wAxis.cross(*this);

    return (o + x * btCos(angle) + y * btSin(angle));
}

class btVector4 : public btVector3 {
public:
    SIMD_FORCE_INLINE btVector4() {}

    SIMD_FORCE_INLINE btVector4(const btScalar& x, const btScalar& y, const btScalar& z, const btScalar& w)
        : btVector3(x, y, z)
    {
        m_floats[3] = w;
    }

    SIMD_FORCE_INLINE btVector4 absolute4() const
    {
        return btVector4(
            btFabs(m_floats[0]),
            btFabs(m_floats[1]),
            btFabs(m_floats[2]),
            btFabs(m_floats[3]));
    }

    btScalar getW() const { return m_floats[3]; }

    SIMD_FORCE_INLINE int32_t maxAxis4() const
    {
        int32_t maxIndex = -1;
        btScalar maxVal = btScalar(-BT_LARGE_FLOAT);
        if (m_floats[0] > maxVal) {
            maxIndex = 0;
            maxVal = m_floats[0];
        }
        if (m_floats[1] > maxVal) {
            maxIndex = 1;
            maxVal = m_floats[1];
        }
        if (m_floats[2] > maxVal) {
            maxIndex = 2;
            maxVal = m_floats[2];
        }
        if (m_floats[3] > maxVal) {
            maxIndex = 3;
        }
        return maxIndex;
    }

    SIMD_FORCE_INLINE int32_t minAxis4() const
    {
        int32_t minIndex = -1;
        btScalar minVal = btScalar(BT_LARGE_FLOAT);
        if (m_floats[0] < minVal) {
            minIndex = 0;
            minVal = m_floats[0];
        }
        if (m_floats[1] < minVal) {
            minIndex = 1;
            minVal = m_floats[1];
        }
        if (m_floats[2] < minVal) {
            minIndex = 2;
            minVal = m_floats[2];
        }
        if (m_floats[3] < minVal) {
            minIndex = 3;
        }

        return minIndex;
    }

    SIMD_FORCE_INLINE int32_t closestAxis4() const
    {
        return absolute4().maxAxis4();
    }

    /**@brief Set x,y,z and zero w
   * @param x Value of x
   * @param y Value of y
   * @param z Value of z
   */

    /*		void getValue(btScalar *m) const
		{
			m[0] = m_floats[0];
			m[1] = m_floats[1];
			m[2] =m_floats[2];
		}
*/
    /**@brief Set the values
   * @param x Value of x
   * @param y Value of y
   * @param z Value of z
   * @param w Value of w
   */
    SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z, const btScalar& w)
    {
        m_floats[0] = x;
        m_floats[1] = y;
        m_floats[2] = z;
        m_floats[3] = w;
    }
};

///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btSwapScalarEndian(const btScalar& sourceVal, btScalar& destVal)
{
#ifdef BT_USE_DOUBLE_PRECISION
    unsigned char* dest = (unsigned char*)&destVal;
    unsigned char* src = (unsigned char*)&sourceVal;
    dest[0] = src[7];
    dest[1] = src[6];
    dest[2] = src[5];
    dest[3] = src[4];
    dest[4] = src[3];
    dest[5] = src[2];
    dest[6] = src[1];
    dest[7] = src[0];
#else
    unsigned char* dest = (unsigned char*)&destVal;
    unsigned char* src = (unsigned char*)&sourceVal;
    dest[0] = src[3];
    dest[1] = src[2];
    dest[2] = src[1];
    dest[3] = src[0];
#endif //BT_USE_DOUBLE_PRECISION
}
///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btSwapVector3Endian(const btVector3& sourceVec, btVector3& destVec)
{
    for (int32_t i = 0; i < 4; i++) {
        btSwapScalarEndian(sourceVec[i], destVec[i]);
    }
}

///btUnSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btUnSwapVector3Endian(btVector3& vector)
{

    btVector3 swappedVec;
    for (int32_t i = 0; i < 4; i++) {
        btSwapScalarEndian(vector[i], swappedVec[i]);
    }
    vector = swappedVec;
}


void fm_catmullRom(REAL *out_vector,const REAL *p1,const REAL *p2,const REAL *p3,const REAL *p4, const REAL s)
{
  REAL s_squared = s * s;
  REAL s_cubed = s_squared * s;

  REAL coefficient_p1 = -s_cubed + 2*s_squared - s;
  REAL coefficient_p2 = 3 * s_cubed - 5 * s_squared + 2;
  REAL coefficient_p3 = -3 * s_cubed +4 * s_squared + s;
  REAL coefficient_p4 = s_cubed - s_squared;

  out_vector[0] = (coefficient_p1 * p1[0] + coefficient_p2 * p2[0] + coefficient_p3 * p3[0] + coefficient_p4 * p4[0])*0.5f;
  out_vector[1] = (coefficient_p1 * p1[1] + coefficient_p2 * p2[1] + coefficient_p3 * p3[1] + coefficient_p4 * p4[1])*0.5f;
  out_vector[2] = (coefficient_p1 * p1[2] + coefficient_p2 * p2[2] + coefficient_p3 * p3[2] + coefficient_p4 * p4[2])*0.5f;
}

bool fm_intersectAABB(const REAL *bmin1,const REAL *bmax1,const REAL *bmin2,const REAL *bmax2)
{
  if ((bmin1[0] > bmax2[0]) || (bmin2[0] > bmax1[0])) return false;
  if ((bmin1[1] > bmax2[1]) || (bmin2[1] > bmax1[1])) return false;
  if ((bmin1[2] > bmax2[2]) || (bmin2[2] > bmax1[2])) return false;
  return true;

}

bool  fm_insideAABB(const REAL *obmin,const REAL *obmax,const REAL *tbmin,const REAL *tbmax) // test if bounding box tbmin/tmbax is fully inside obmin/obmax
{
  bool ret = false;

  if ( tbmax[0] <= obmax[0] &&
	   tbmax[1] <= obmax[1] &&
	   tbmax[2] <= obmax[2] &&
	   tbmin[0] >= obmin[0] &&
	   tbmin[1] >= obmin[1] &&
	   tbmin[2] >= obmin[2] ) ret = true;

  return ret;
}

// Reference, from Stan Melax in Game Gems I
//  Quaternion q;
//  vector3 c = CrossProduct(v0,v1);
//  REAL   d = DotProduct(v0,v1);
//  REAL   s = (REAL)sqrt((1+d)*2);
//  q.x = c.x / s;
//  q.y = c.y / s;
//  q.z = c.z / s;
//  q.w = s /2.0f;
//  return q;
void fm_rotationArc(const REAL *v0,const REAL *v1,REAL *quat)
{
  REAL cross[3];

  fm_cross(cross,v0,v1);
  REAL d = fm_dot(v0,v1);

  if( d<= -0.99999f ) // 180 about x axis
  {
	  if ( fabsf((float)v0[0]) < 0.1f )
	  {
		  quat[0] = 0;
		  quat[1] = v0[2];
		  quat[2] = -v0[1];
		  quat[3] = 0;
	  }
	  else
	  {
		  quat[0] = v0[1];
		  quat[1] = -v0[0];
		  quat[2] = 0;
		  quat[3] = 0;
	  }
	  REAL magnitudeSquared = quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2] + quat[3]*quat[3];
	  REAL magnitude = sqrtf((float)magnitudeSquared);
	  REAL recip = 1.0f / magnitude;
	  quat[0]*=recip;
	  quat[1]*=recip;
	  quat[2]*=recip;
	  quat[3]*=recip;
  }
  else
  {
	  REAL s = (REAL)sqrt((1+d)*2);
	  REAL recip = 1.0f / s;

	  quat[0] = cross[0] * recip;
	  quat[1] = cross[1] * recip;
	  quat[2] = cross[2] * recip;
	  quat[3] = s * 0.5f;
  }
}

REAL fm_distancePointLineSegment(const REAL *Point,const REAL *LineStart,const REAL *LineEnd,REAL *intersection,LineSegmentType &type,REAL epsilon)
{
  REAL ret;

  REAL LineMag = fm_distance( LineEnd, LineStart );

  if ( LineMag > 0 )
  {
	REAL U = ( ( ( Point[0] - LineStart[0] ) * ( LineEnd[0] - LineStart[0] ) ) + ( ( Point[1] - LineStart[1] ) * ( LineEnd[1] - LineStart[1] ) ) + ( ( Point[2] - LineStart[2] ) * ( LineEnd[2] - LineStart[2] ) ) ) / ( LineMag * LineMag );
	if( U < 0.0f || U > 1.0f )
	{
	  REAL d1 = fm_distanceSquared(Point,LineStart);
	  REAL d2 = fm_distanceSquared(Point,LineEnd);
	  if ( d1 <= d2 )
	  {
		ret = (REAL)sqrt(d1);
		intersection[0] = LineStart[0];
		intersection[1] = LineStart[1];
		intersection[2] = LineStart[2];
		type = LS_START;
	  }
	  else
	  {
		ret = (REAL)sqrt(d2);
		intersection[0] = LineEnd[0];
		intersection[1] = LineEnd[1];
		intersection[2] = LineEnd[2];
		type = LS_END;
	  }
	}
	else
	{
	  intersection[0] = LineStart[0] + U * ( LineEnd[0] - LineStart[0] );
	  intersection[1] = LineStart[1] + U * ( LineEnd[1] - LineStart[1] );
	  intersection[2] = LineStart[2] + U * ( LineEnd[2] - LineStart[2] );

	  ret = fm_distance(Point,intersection);

	  REAL d1 = fm_distanceSquared(intersection,LineStart);
	  REAL d2 = fm_distanceSquared(intersection,LineEnd);
	  REAL mag = (epsilon*2)*(epsilon*2);

	  if ( d1 < mag ) // if less than 1/100th the total distance, treat is as the 'start'
	  {
		type = LS_START;
	  }
	  else if ( d2 < mag )
	  {
		type = LS_END;
	  }
	  else
	  {
		type = LS_MIDDLE;
	  }

	}
  }
  else
  {
	ret = LineMag;
	intersection[0] = LineEnd[0];
	intersection[1] = LineEnd[1];
	intersection[2] = LineEnd[2];
	type = LS_END;
  }

  return ret;
}

#ifndef BEST_FIT_PLANE_H

#define BEST_FIT_PLANE_H

template <class Type> class Eigen
{
public:


float get_scanning_progress() const;
	void scan();
	void scan_changes();
	void update_file(const String &p_file);
	void update_files(const Vector<String> &p_script_paths);
	HashSet<String> get_valid_extensions() const;
	void register_global_class_script(const String &p_search_path, const String &p_target_path);

	EditorFileSystemDirectory *get_filesystem_path(const String &p_path);
	String get_file_type(const String &p_file) const;
	EditorFileSystemDirectory *find_file(const String &p_file, int *r_index) const;

	void reimport_files(const Vector<String> &p_files);
	Error reimport_append(const String &p_file, const HashMap<StringName, Variant> &p_custom_options, const String &p_custom_importer, Variant p_generator_parameters);

	void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params);

	bool is_group_file(const String &p_path) const;
	void move_group_file(const String &p_path, const String &p_new_path);

	Error make_dir_recursive(const String &p_path, const String &p_base_path = String());
	Error copy_file(const String &p_from, const String &p_to);
	Error copy_directory(const String &p_from, const String &p_to);

	static bool _should_skip_directory(const String &p_path);

	void add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
	void remove_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query);
	EditorFileSystem();
	~EditorFileSystem();
};

#endif // EDITOR_FILE_SYSTEM_H


/**************************************************************************/
/*  import_defaults_editor.h                                              */
/**************************************************************************/
/*                         This file is part of:                          */
/*                             GODOT ENGINE                               */
/*                        https://godotengine.org                         */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
/*                                                                        */
/* Permission is hereby granted, free of charge, to any person obtaining  */
/* a copy of this software and associated documentation files (the        */
/* "Software"), to deal in the Software without restriction, including    */
/* without limitation the rights to use, copy, modify, merge, publish,    */
/* distribute, sublicense, and/or sell copies of the Software, and to     */
/* permit persons to whom the Software is furnished to do so, subject to  */
/* the following conditions:                                              */
/*                                                                        */
/* The above copyright notice and this permission notice shall be         */
/* included in all copies or substantial portions of the Software.        */
/*                                                                        */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
/**************************************************************************/

#ifndef IMPORT_DEFAULTS_EDITOR_H
#define IMPORT_DEFAULTS_EDITOR_H

#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/option_button.h"

class ImportDefaultsEditorSettings;
class EditorInspector;

class ImportDefaultsEditor : public VBoxContainer {
	GDCLASS(ImportDefaultsEditor, VBoxContainer)

	OptionButton *importers = nullptr;
	Button *save_defaults = nullptr;
	Button *reset_defaults = nullptr;

	EditorInspector *inspector = nullptr;

	ImportDefaultsEditorSettings *settings = nullptr;

	void _update_importer();
	void _importer_selected(int p_index);

	void _reset();
	void _save();

protected:
	void _notification(int p_what);

public:
	void clear();

	ImportDefaultsEditor();
	~ImportDefaultsEditor();
};

#endif // IMPORT_DEFAULTS_EDITOR_H


/**************************************************************************/
/*  editor_import_plugin.h                                                */
/**************************************************************************/
/*                         This file is part of:                          */
/*                             GODOT ENGINE                               */
/*                        https://godotengine.org                         */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
/*                                                                        */
/* Permission is hereby granted, free of charge, to any person obtaining  */
/* a copy of this software and associated documentation files (the        */
/* "Software"), to deal in the Software without restriction, including    */
/* without limitation the rights to use, copy, modify, merge, publish,    */
/* distribute, sublicense, and/or sell copies of the Software, and to     */
/* permit persons to whom the Software is furnished to do so, subject to  */
/* the following conditions:                                              */
/*                                                                        */
/* The above copyright notice and this permission notice shall be         */
/* included in all copies or substantial portions of the Software.        */
/*                                                                        */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
/**************************************************************************/

#ifndef EDITOR_IMPORT_PLUGIN_H
#define EDITOR_IMPORT_PLUGIN_H

#include "core/io/resource_importer.h"
#include "core/variant/typed_array.h"

class EditorImportPlugin : public ResourceImporter {
	GDCLASS(EditorImportPlugin, ResourceImporter);

protected:
	static void _bind_methods();

	GDVIRTUAL0RC(String, _get_importer_name)
	GDVIRTUAL0RC(String, _get_visible_name)
	GDVIRTUAL0RC(int, _get_preset_count)
	GDVIRTUAL1RC(String, _get_preset_name, int)
	GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
	GDVIRTUAL2RC(TypedArray<Dictionary>, _get_import_options, String, int)
	GDVIRTUAL0RC(String, _get_save_extension)
	GDVIRTUAL0RC(String, _get_resource_type)
	GDVIRTUAL0RC(float, _get_priority)
	GDVIRTUAL0RC(int, _get_import_order)
	GDVIRTUAL3RC(bool, _get_option_visibility, String, StringName, Dictionary)
	GDVIRTUAL5RC(Error, _import, String, String, Dictionary, TypedArray<String>, TypedArray<String>)
	GDVIRTUAL0RC(bool, _can_import_threaded)

	Error _append_import_external_resource(const String &p_file, const Dictionary &p_custom_options = Dictionary(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());

public:
	EditorImportPlugin();
	virtual String get_importer_name() const override;
	virtual String get_visible_name() const override;
	virtual void get_recognized_extensions(List<String> *p_extensions) const override;
	virtual String get_preset_name(int p_idx) const override;
	virtual int get_preset_count() const override;
	virtual String get_save_extension() const override;
	virtual String get_resource_type() const override;
	virtual float get_priority() const override;
	virtual int get_import_order() const override;
	virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const override;
	virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
	virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata = nullptr) override;
	virtual bool can_import_threaded() const override;
	Error append_import_external_resource(const String &p_file, const HashMap<StringName, Variant> &p_custom_options = HashMap<StringName, Variant>(), const String &p_custom_importer = String(), Variant p_generator_parameters = Variant());
};

#endif // EDITOR_IMPORT_PLUGIN_H


defaults:
  4:
    templates: export_templates.tpz
    editor:
      android.apk: android_editor.apk
      android.horizonos: android_editor_horizonos.apk
      linux.64: linux.x86_64.zip
      linux.32: linux.x86_32.zip
      linux.arm64: linux.arm64.zip
      linux.arm32: linux.arm32.zip
      macos.universal: macos.universal.zip
      windows.64: win64.exe.zip
      windows.32: win32.exe.zip
      windows.arm64: windows_arm64.exe.zip
      web: web_editor.zip
    mono:
      templates: mono_export_templates.tpz
      editor:
        linux.64: mono_linux_x86_64.zip
        linux.32: mono_linux_x86_32.zip
        linux.arm64: mono_linux_arm64.zip
        linux.arm32: mono_linux_arm32.zip
        macos.universal: mono_macos.universal.zip
        windows.64: mono_win64.zip
        windows.32: mono_win32.zip
        windows.arm64: mono_windows_arm64.zip
    extras:
      aar_library: template_release.aar

  3:
    templates: export_templates.tpz
    editor:
      android.apk: android_editor.apk
      linux.64: x11.64.zip
      linux.32: x11.32.zip
      macos.universal: osx.universal.zip
      windows.64: win64.exe.zip
      windows.32: win32.exe.zip
      linux_server.headless.64: linux_headless.64.zip
      linux_server.64: linux_server.64.zip
      web: web_editor.zip
    extras:
      aar_library: release.aar

    mono:
      templates: mono_export_templates.tpz
      editor:
        linux.64: mono_x11_64.zip
        linux.32: mono_x11_32.zip
        macos.universal: mono_osx.universal.zip
        windows.64: mono_win64.zip
        windows.32: mono_win32.zip
        linux_server.headless.64: mono_linux_headless_64.zip
        linux_server.64: mono_linux_server_64.zip
      extras:
        aar_library: mono.release.aar

  2:
    templates: export_templates.tpz
    editor:
      linux.64: x11.64.zip
      linux.32: x11.32.zip
      macos.universal: osx.fat.zip
      windows.64: win64.exe.zip
      windows.32: win32.exe.zip
      linux_server.64: linux_server.64.zip

  1:
    templates: export_templates.tpz
    editor:
      linux.64: x11.64.zip
      linux.32: x11.32.zip
      macos.universal: osx32.zip
      windows.64: win64.exe.zip
      windows.32: win32.exe.zip
      linux_server.64: linux_server.64.zip

overrides:
  # Mono version of Godot 4 was only introduced in 4.0 alpha 17.
  - version: 4
    range:
      - "4.0-alpha1"
      - "4.0-alpha16"
    config:
      templates: export_templates.tpz
      editor:
        android.apk: android_editor.apk
        linux.64: linux.x86_64.zip
        linux.32: linux.x86_32.zip
        macos.universal: macos.universal.zip
        windows.64: win64.exe.zip
        windows.32: win32.exe.zip
        web: web_editor.zip
      extras:
        aar_library: template_release.aar

  # Godot 4.2 beta 5 introduced Linux ARM builds.
  - version: 4
    range:
      - "4.0-alpha17"
      - "4.2-beta4"
    config:
      templates: export_templates.tpz
      editor:
        android.apk: android_editor.apk
        linux.64: linux.x86_64.zip
        linux.32: linux.x86_32.zip
        macos.universal: macos.universal.zip
        windows.64: win64.exe.zip
        windows.32: win32.exe.zip
        web: web_editor.zip
      mono:
        templates: mono_export_templates.tpz
        editor:
          linux.64: mono_linux_x86_64.zip
          linux.32: mono_linux_x86_32.zip
          macos.universal: mono_macos.universal.zip
          windows.64: mono_win64.zip
          windows.32: mono_win32.zip
      extras:
        aar_library: template_release.aar

  # Godot 4.3 RC 1 introduced Windows ARM builds.
  - version: 4
    range:
      - "4.2-beta5"
      - "4.3-beta3"
    config:
      templates: export_templates.tpz
      editor:
        android.apk: android_editor.apk
        linux.64: linux.x86_64.zip
        linux.32: linux.x86_32.zip
        linux.arm64: linux.arm64.zip
        linux.arm32: linux.arm32.zip
        macos.universal: macos.universal.zip
        windows.64: win64.exe.zip
        windows.32: win32.exe.zip
        web: web_editor.zip
      mono:
        templates: mono_export_templates.tpz
        editor:
          linux.64: mono_linux_x86_64.zip
          linux.32: mono_linux_x86_32.zip
          linux.arm64: mono_linux_arm64.zip
          linux.arm32: mono_linux_arm32.zip
          macos.universal: mono_macos.universal.zip
          windows.64: mono_win64.zip
          windows.32: mono_win32.zip
      extras:
        aar_library: template_release.aar

  # Godot 4.4 dev 2 introduced Android Horizon OS builds.
  - version: 4
    range:
      - "4.3-rc1"
      - "4.4-dev1"
    config:
      templates: export_templates.tpz
      editor:
        android.apk: android_editor.apk
        linux.64: linux.x86_64.zip
        linux.32: linux.x86_32.zip
        linux.arm64: linux.arm64.zip
        linux.arm32: linux.arm32.zip
        macos.universal: macos.universal.zip
        windows.64: win64.exe.zip
        windows.32: win32.exe.zip
        windows.arm64: windows_arm64.exe.zip
        web: web_editor.zip
      mono:
        templates: mono_export_templates.tpz
        editor:
          linux.64: mono_linux_x86_64.zip
          linux.32: mono_linux_x86_32.zip
          linux.arm64: mono_linux_arm64.zip
          linux.arm32: mono_linux_arm32.zip
          macos.universal: mono_macos.universal.zip
          windows.64: mono_win64.zip
          windows.32: mono_win32.zip
          windows.arm64: mono_windows_arm64.zip
      extras:
        aar_library: template_release.aar


# New asset workflow

Godot 3.0 has changed how the assets pipeline work. We now use the more familiar scheme of automatically importing assets. Simply drop an asset into the project folder and it will automatically be imported with configurable default parameters. Options can be changed afterwards after importing.

![Editor screenshot with import options](/storage/app/media/3.0%20release/import_system.png)

One interesting point about how this works is that copying the import folder between computers works perfectly, the editor will not attempt reimporting something until it has really changed.

Another big plus of this new system, besides improved ease of use, is that running on a device with a networked filesystem (for very fast testing times) works much better than before. Godot will pick the right compression for textures when importing for mobile, and supply them over the network.

The 3D asset workflow has also seen great improvements. It is possible to either import a scene as a single file, or to split it into multiple instantiated subscenes, keep materials, meshes and animations external, etc. Changes to resources can also be merged.

#### glTF 2.0 support

Godot now supports importing glTF 2.0 scenes. This is a new open standard by Khronos which we [encourage you](/article/we-should-all-use-gltf-20-export-3d-assets-game-engines) to use and support.

![glTF 2.0 scene imported in Godot](/storage/app/media/3.0%20release/gltf.png)

The importer is new and likely not as mature as the Collada importer, but it will get better over time.

#### Improved OBJ support

The venerable OBJ format is now much better supported. Materials can be read from it and importing as a full scene is now also possible.

#### SVG support

Daniel Ramirez ([djrm](https://github.com/djrm)) implemented importing SVG as bitmaps (with customizable resolution). This functionality is also used to better support HiDPI modes, as editor icons are converted to native resolution when the editor starts up.

This does not let you use SVGs directly as 2D meshes yet, but it's on the roadmap for future releases.

## GDNative

![C++ scripting via GDNative](/storage/app/media/3.0%20release/gdnative.png)

GDNative is our new framework for extending Godot via external libraries. It was mostly developed by [karroffel](https://github.com/karroffel), and it's truly amazing.

Using GDNative, it's possible to easily extend Godot in C/C++ without recompiling the engine, and that for any platform. This also means that it's easy to bundle external libraries (such as OpenVR, Steam, Kinect, SQLite, etc.), or provide support for video/audio codecs, VR, etc. as pluggable libraries.

But that's not all. GDNative allows setting up extra scripting languages and using them on the fly without recompiling the engine, with pretty much native performance. Currently, work is in an advanced state for community-maintained [Python](https://github.com/touilleMan/godot-python) (via the PluginScript interface), [Nim](https://pragmagic.github.io/godot-nim/master/index.html) and [D](https://github.com/GodotNativeTools/godot-d) support, as well of course as official [C++](https://github.com/GodotNativeTools/godot-cpp) bindings; others might follow if community members are interested in working on it.

You can read more about it on its [original announcement](/article/dlscript-here) and a later [in-depth look at its architecture](/article/look-gdnative-architecture).

## Mono / C# support

![C# scripting via the Mono flavour](/storage/app/media/3.0%20release/monogodot.png)

Thanks to a generous grant from Microsoft, Ignacio Roldán Etcheverry ([neikeq](https://github.com/neikeq)) did a fantastic job and implemented Mono support in Godot.

It is now possible to fully script [Godot using C#](/article/introducing-csharp-godot), using your favorite IDE and the latest version of the language.

Due to popular demand, we also implemented an API mostly conformant with the C# conventions, so for C# users, the API is mostly PascalCase (instead of snake_case). The generated C# code API includes the full documentation embedded, so code completion works very well with it.

**Note:** The language support is mostly complete and it's fully usable, but it will continue improving over the next months - the main missing feature as of 3.0 is the ability to export games coded in C#, as such it's not fully usable in production yet. There's not much left to implement for this to work though, and it will be available in Godot 3.0.1 within a few weeks.

So as not to impose the additional dependency on the Mono SDK to users of other scripting languages such as GDScript or VisualScript, the C# support comes in a separate build of Godot (labeled the "mono" build).

## Visual Scripting

Godot 3.0 also comes with a brand new visual scripting language (originally named VisualScript), in the typical "boxes and connections" fashion. The default implementation is rather low-level, but is extensible enough for users to create more high-level behaviors.

![](/storage/app/media/3.0%20release/visual_script.png)

Visual scripting is ideal for non-programmers, or for programmers exposing behaviors to game designers, artists, etc.
One of the nice features of our implementation is that it's possible to drag elements from most Godot panels (filesystem, scene, properties, etc.) to the canvas, greatly improving usability.

Since this is the first stable release shipping with VisualScript, we are looking forward to your feedback to continue improving it further in future releases.

## GDScript

GDScript has seen many improvements since 2.1. The main one is that the API has changed mostly from using functions to properties. This makes it less verbose, easier for newcomers and for finding the right property in the documentation.

The `get_node()` function also got syntactic sugar to obtain nodes in the local scene tree by writing less code, using the `$` alias.

![New GDScript API in 3.0](/storage/app/media/3.0%20release/gdscript3.png)

GDScript has also seen a huge performance boost thanks to the work of HP van Braam ([hpvb/TMM](https://github.com/hpvb)), which makes its execution much faster.

A new pattern matching API is also available, courtesy of [karroffel](https://github.com/karroffel).

Code completion has also seen a great increase in accuracy.

## New audio engine

Godot 3.0 comes with a brand new audio engine; the old one has been completely wiped out. This version is entirely focused on AudioStreams (samples are no longer supported). Streams (supported as .wav and .ogg files) can be played in real-time.

Stream players can now send their output to buses in a rack, allowing very high efficiency and freedom in game sound design:

![Audio rack with multiple buses](/storage/app/media/3.0%20release/audiorack.png)

There is also a large library of built-in sound effects than can be put in each channel:

![Overview of the built-in sound effects](/storage/app/media/3.0%20release/builtinfx.png)

Positional audio is also now fully supported, including stereo, 5.1 and 7.1 speaker configurations. 3D audio can be sent to any channel, but also areas will capture it and send it to custom channels (with split reverb).

This allows different areas to have different reverberation and effects (reverb is not the same in small and large rooms), without having to tweak snapshots like other engines do. Here is an example using the older 3D platformer demo:

##


---
title: "Maintenance release: Godot 4.2.1"
excerpt: "This first maintenance release fixes a number of platform compatibility issues introduced in Godot 4.2, which should make it much easier to upgrade from 4.1 or start new projects on all platforms."
categories: ["release"]
author: Rémi Verschelde
image: /storage/blog/covers/maintenance-release-godot-4-2-1.webp
image_caption_title: Voice of Flowers
image_caption_description: A game by Tomasz Chabora
date: 2023-12-12 13:00:00
---

We released [Godot 4.2](/article/godot-4-2-arrives-in-style/) two weeks ago, with major improvements and bug fixes all around the engine. Like any big feature release, it had a few rough edges which we've been focusing on addressing in the past couple of weeks. This allows us to already publish this first maintenance release, Godot 4.2.1, which irons out some of those issues while fully preserving compatibility.

Some of the most important fixes in this release are:

- For the GL Compatibility renderer on macOS, we switched from the Metal ANGLE backend back to native OpenGL drivers. Our hope was that ANGLE's Metal backend would make the Compatibility renderer future proof (as Apple deprecated their native OpenGL support), and fix some known driver bugs with OpenGL drivers on macOS. It turns out that ANGLE's Metal backend brings more issues than it solves, so we rolled back that change of default backend ([GH-85785](https://github.com/godotengine/godot/pull/85785)).

- Still on macOS, the new iOS one click deploy feature requires Xcode to be installed, and would use `xcode-select` to check that when the editor starts. This could trigger an install dialog that would make Godot appear frozen, without making the issue explicit to users. We switched to use `mdfind` to check if Xcode is installed, which should solve this issue ([GH-85774](https://github.com/godotengine/godot/pull/85774)).

- A number of bugs have been solved for the Vulkan renderers on Android, which could cause crashes or corrupted meshes ([GH-84852](https://github.com/godotengine/godot/pull/84852)). This might also have solved issues with garbled tilemap rendering on some Android devices, though we still need confirmation on that.

- Many users of the [Godot Jolt](https://github.com/godot-jolt/godot-jolt/) addon in 4.1 experienced the editor crashing when upgrading their project to 4.2, due to a bug in older versions of Godot Jolt which made it incompatible with Godot 4.2. Given how widespread the issue seems to be, we decided to add a hack for Godot Jolt specifically to prevent loading older versions which are known incompatible with Godot 4.2 ([GH-85779](https://github.com/godotengine/godot/pull/85779)). After successfully loading a project with Godot Jolt disabled, you should delete the old version you have installed, and reinstall the latest version (0.11.0 at the time of writing) which is compatible with Godot 4.2.

- A regression with handling of TileMap occluders was also fixed ([GH-85893](https://github.com/godotengine/godot/pull/85893)).

- Recent Emscripten releases changed their default stack size, which caused issues for Web export in Godot 4.2 when using certain APIs. We added the needed linker flags to restore the behavior from older Emscripten versions, ensuring that Godot can run successfully after being compiled by the latest Emscripten releases ([GH-86036](https://github.com/godotengine/godot/pull/86036)).

[**Download Godot 4.2.1 now**](/download/) or try the [online version of the Godot editor](https://editor.godotengine.org/4.2.1.stable/).

{% include articles/download_card.html version="4.2.1" release="stable" article=page %}

*The illustration picture used in this announcement is from* [**Voice of Flowers**](https://store.steampowered.com/app/2609560?utm_source=GodotWebsite&utm_medium=blog&utm_campaign=421), *a metroidvania that takes great inspiration from Mario games, developed in Godot 4 by [Tomasz Chabora](https://twitter.com/KoBeWi_/) ([KoBeWi](https://github.com/KoBeWi/)) – one of Godot's most profilic maintainers! You can wishlist the game [on Steam](https://store.steampowered.com/app/2609560?utm_source=GodotWebsite&utm_medium=blog&utm_campaign=421), play the latest demo [on itch.io](https://kobewi.itch.io/voice-of-flowers), and follow development on [Discord](https://discord.gg/PGhFXeHApR) and [Twitter](https://twitter.com/KoBeWi_/).*

## Changes

**42 contributors** submitted around **74 improvements** for this release. You can review the complete list of changes with our [interactive changelog](https://godotengine.github.io/godot-interactive-changelog/#4.2.1), which contains links to relevant commits and PRs for this and every previous release. Here is the complete list of changes in this release:

-


### Make rendering always happen in Linear colorspace

Texture and color information edited by users exists only in the SRGB colorspace. This happens because monitor colors are adjusted by a Gamma function, elevating them to a roughly 2.2 or 2.4 power.

To make lighting more realistic, all computations must happen in a linear color space, then converted to Gamma at the end via tonemapping.

Godot 2.x already supported linear space rendering, but this was optional. In 3.0, as we are aiming to a more realistic and high quality backend, the only supported rendering mode is linear.

### Investigate Physically Based Rendering (PBR), using GGX and alternatives

Thorough investigation was carried out on more modern rendering techniques for Godot.

As a result, we decided to use the [Disney PBR](https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf) specification.

Godot will use a similar parameter set for materials and shaders.

### Investigate cubemap filtering

The most common way to implement PBR in real-time is to use a pre-filtered cubemap for material roughness. This makes the reflected light more or less smoothed on demand:

![](/storage/app/media/devlog/progress1/progress_1_pbr.png)

Cubemap filtering was implemented and it's working well, but doubts arise whether using this or dual paraboloid maps is better. The reason is that cubemaps don't blend well between cube sides in several platforms.

### Create a new FixedMaterial that reflects PBR capabilities

A new FixedSceneMaterial resource was created, which allows editing simple materials without having to edit shaders manually. It also has the advtange of reusing shaders for similar material configurations:

![](/storage/app/media/devlog/progress1/progress_1_material.png)

### Implement PBR

The minimum required parameters for PBR are implemented and working:

* Albedo
* Specular
* Roughness
* Environment (skybox)

### Convert gizmos to use the new FixedMaterial

All gizmos were converted to use the new FixedSceneMaterial, as mentioned before.

### Add Lighting using PBR

Additive lighting has been added for the PBR backend (in Milestone 3, clustered lighting will be added).

![](/storage/app/media/devlog/progress1/progress_1_lighting.png)

### Investigate a ShadowAtlas allocation strategy

Godot 2.0 used individual textures for each shadow map. In the wake of more modern techniques such as clustered renderering, it is required that all shadowmaps are contained within a single texture.

Research was done first into dynamic allocation strategies for light shadows into a shadow atlas, but nothing useful was found. Every dynamic scheme implies moving around shadowmaps if no more space is available, which incurs a considerable cost.

In the end, a more static approach will take place. The shadow atlas will be divided into 4 "Quadrants" and the user will be able to specify how they want each of them subdivided. A default subdivision should cover most use cases:

![](/storage/app/media/devlog/progress1/progress_1_atlas.png)

But the possibility is open for developers to tweak this subdivision for games that might look better with a different scheme.

The logic to tell which cell size must be used for which light is straightforward. Every time the camera moves, each visible light computes a "coverage" value, which represents their size on screen, as example:

```
average_screen_size = (screen_width + screen_height) / 2
coverage = diameter_in_screen_pixels / average_screen_size
```

The coverage is then a value ranging from 0 to 1. To determine which cell size it must be used, the following logic applies:

```
desired_cell_size = nearest_power_of_2(largest_cell_size * coverage)
```

## Future

This has been our first report on the new renderer progress towards Godot 3.0 new renderer, hope everything was clear!

## Seeing the code

If you are interested in seeing what each feature looks like in the code, you can check the [*gles3* branch](https://github.com/godotengine/godot/commits/gles3) on GitHub.


---
title: "GDScript progress report: New GDScript is now merged"
excerpt: "New GDScript code is now merged. Here I talk a bit of what has changed, report what else I did this month and talk a bit about my current work and plans for the future."
categories: ["progress-report"]
author: George Marques
image: /storage/app/uploads/public/5f2/966/b6d/5f2966b6dca1a217164497.png
date: 2020-08-04 00:00:00
---

As some of you might be aware, the refactor that I have been working on lately is now [merged](https://github.com/godotengine/godot/pull/40598) into the `master` branch. This is the work explained in previous progress reports.

*See other articles in this Godot 4.0 GDScript series:*

1. [GDScript progress report: Writing a tokenizer](https://godotengine.org/article/gdscript-progress-report-writing-tokenizer)
2. [GDScript progress report: Writing a new parser](https://godotengine.org/article/gdscript-progress-report-writing-new-parser)
3. [GDScript progress report: Type checking is back](https://godotengine.org/article/gdscript-progress-report-type-checking-back)
4. (you are here) [GDScript progress report: New GDScript is now merged](https://godotengine.org/article/gdscript-progress-report-new-gdscript-now-merged)
5. [GDScript progress report: Typed instructions](https://godotengine.org/article/gdscript-progress-report-typed-instructions)
6. [GDScript progress report: Feature-complete for 4.0](https://godotengine.org/article/gdscript-progress-report-feature-complete-40)

## Main changes

While I did already open a pull request to [update the documentation](https://github.com/godotengine/godot-docs/pull/3623), I'll put here a short description of what have changed.

### Annotations

We now have annotation support and that is used to replace a few of the keywords that were introduced along the way. This includes the RPC keywords, such as `@master`, `@puppet`, and `@remote`.

The previous `export` keyword is now replaced by a list of specialized annotations for each case. For example, if you want a range, you can use the `@export_range` annotation. There's no need to set the type as an argument anymore, since it can be retrieved from the variable's type specifier (e.g. `@export var my_number: int`).

This has an added benefit because those annotations feature code completion and hints for their arguments, which makes them much easier to use without having to remember all the possible combinations like before.

This also includes an `@icon` annotation that must be used instead of adding after the `class_name` like before.

### Properties

The previous `setget` syntax was removed in favor of [properties](https://github.com/godotengine/godot-proposals/issues/844). It is meant to be more tied to the variable declaration and avoid you having to create dedicated functions (though you still can if you prefer). Another change is that, unlike `setget` properties always call their setter/getter even inside the same class. This gives users a consistent behavior which won't cause confusion or lead to potential mistakes during a refactor.

### `await` instead of `yield`

As you might already know, the `yield` keyword is removed in favor of `await`. It not only have a more meaningful name but it also takes advantage of first-class signals that were introduced in the `master` branch of Godot. The syntax is easier to understand and have less boilerplate (you don't need to write the `"completed"` signal when waiting coroutines.

It is also more transparent if the function you called doesn't always work as a coroutine (you don't need to treat the special case), and it's type-safe since you can't receive a function state when you were expecting the return value.

### `super` keyword

Instead of prefixing the function name with a period (`.`) now you must use the `super` keyword to call a function defined in the superclass instead of the overridden version. This also applies to constructors, making it more consistent in general and improving the flexibility.

Calling `super()` on its own will call the same function you are in but using the superclass implementation. If you need to call a different function you can use `super.function_name()`.

## Code completion

As mentioned in the previous report, code completion was a working in progress. Now it is essentially complete. I am aware that it could use some quality-of-life improvements, but this will be worked on later. For now it should be the same as it was before. If something is missing feel free to report an issue.

## Remove multi-level calls

Another common source of confusion was [removed](https://github.com/godotengine/godot/pull/40670). If you create an override of some lifecycle functions (such as `_process` or `_ready`) it still called the superclass implementation implicitly. Worse yet: some functions called the superclass before the subclass, and some went on the other direction.

This behavior is now completely removed. If you need to call the parent implementation, you can use the `super` keyword as mentioned above. This is common in <abbr title="Object-Oriented Programming">OOP</abbr> languages, so it should be more aligned to what user expects (which is evidenced by multiple issues reporting this behavior in the past). It also gives users control of _when_ the super implementation should be called.

Note that methods defined in the C++ code are still called. This is needed to make sure engine behavior is correct (like the button `_gui_input` which is needed to execute the pressing behavior).

## Testing

I spent a good chunk of the time testing GDScript implementation and fixed an amount of bugs and crashes along the way. If you find crashes or issues don't be afraid to [report it](https://github.com/godotengine/godot/issues) (if it wasn't reported before). Eventually I'll do a big round of bug fixes to stabilize it for release, but for now I'll try to keep GDScript in a workable state and especially without crashes.

## Future

Currently I'm working on an abstraction for the code generation interface. This will be helpful to create an ability to change the target backend language (which currently is only the GDScript VM itself) without having to change the compiler, eventually paving way to code optimization as well. More details on this will come in the next progress report.

After that I'll start adding typed instructions to the VM which should increase the speed massively for when you use static typing in the script.


articles/download_card.html version="4.2" release="beta1" article=page %}

**Standard build** includes support for GDScript and GDExtension.

**.NET build** (marked as `mono`) includes support for C#, as well as GDScript and GDExtension.
- .NET build requires [.NET SDK 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) or [7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) installed in a standard location.
- To export to Android, .NET 7.0 or later is required. To export to iOS, .NET 8.0 is required. Make sure to set the target framework in the `.csproj` file.

{% include articles/prerelease_notice.html %}

## Known issues

There are currently no known issues introduced by this release.

With every release we accept that there are going to be various issues, which have already been reported but haven't been fixed yet. See the GitHub issue tracker for a complete list of [known bugs](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Abug+).

## Bug reports

As a tester, we encourage you to [open bug reports](https://github.com/godotengine/godot/issues) if you experience issues with this release. Please check the [existing issues on GitHub](https://github.com/godotengine/godot/issues) first, using the search function with relevant keywords, to ensure that the bug you experience is not already known.

In particular, any change that would cause a regression in your projects is very important to report (e.g. if something that worked fine in previous 4.x releases, but no longer works in 4.2 beta 1).

## Support

Godot is a non-profit, open source game engine developed by hundreds of contributors on their free time, as well as a handful of part or full-time developers hired thanks to [generous donations from the Godot community](https://fund.godotengine.org/). A big thank you to everyone who has contributed [their time](https://github.com/godotengine/godot/blob/master/AUTHORS.md) or [their financial support](https://github.com/godotengine/godot/blob/master/DONORS.md) to the project!

If you'd like to support the project financially and help us secure our future hires, you can do so using the [Godot Development Fund](https://fund.godotengine.org/) platform managed by [Godot Foundation](https://godot.foundation/). There are also several [alternative ways to donate](/donate) which you may find more suitable.


---
title: "Web Editor beta, AudioWorklet, GDNative and more!"
excerpt: "The Web Editor reaches beta (3.2.4 beta 4), GDNative lands on the web, thread-enabled HTML5 builds now come with an improved audio driver using the AudioWorklet API."
categories: ["progress-report"]
author: Fabio Alessandrelli
image: /storage/app/uploads/public/5fe/1bf/c80/5fe1bfc80c475551734903.png
date: 2020-12-24 17:00:00
---

Howdy Godotters! The year is almost over and it's about time we give you some news about the Web Editor and the HTML5 export.

It's been a very fruitful year for Godot on the Web since the announcement of the first [web editor prototype](https://godotengine.org/article/godot-editor-running-web-browser).
As expected in the rationale of the original post, this has produced a lot of improvements to the HTML5 export in general, including support for threads, file drag and drop, <abbr title="Link-Time Optimization">LTO</abbr> for smaller and faster builds, low-processor mode with optional lower framerate, and better control over audio output latency and mix rate. See the [second](https://godotengine.org/article/godot-web-progress-report-2) and [third](https://godotengine.org/article/godot-web-progress-report-3) reports for more details.

With this new report, as you may know if you checked out the last [Godot Live Q&A](https://www.youtube.com/watch?v=zGmCbnE0UqA), we're happy to announce that we have added optional **GDNative support** in HTML5 exports, that the optional **Thread support** now comes with an improved audio driver using the **AudioWorklet API**, and that the **Web Editor has reached the beta stage**.

Optional GDNative/Threads support
=================================

If you tried out Godot [3.2.4 beta 4](https://godotengine.org/article/dev-snapshot-godot-3-2-4-beta-4) you might have noticed that the HTML5 export now has a new option called `Export Type`, which allows you to select either the `Regular`, `Threads`, or `GDNative` build.
Sadly, as of now, it is not possible to have an export that supports both GDNative and Threads. This is a [documentated limitation](https://github.com/emscripten-core/emscripten/wiki/Linking#pthreads-support) of the toolchain used to create the web export, and the WebAssembly specification itself. We are still investigating a workaround for that, but it's going to take some more time.

![Selecting HTML5 export template type](/storage/app/uploads/public/5fe/0b6/6f9/5fe0b66f9ef85260274295.png)

Each export type has advantages and disadvantages, so you should choose depending on the scope and target of your game:

- **Regular**: It is the most compatible acrosss browsers but does not support multithreading nor GDNative.
- **Threads**: Supports multithreading via the [Thread](https://docs.godotengine.org/en/stable/classes/class_thread.html) and [Mutex](https://docs.godotengine.org/en/stable/classes/class_mutex.html) classes and comes with a low latency audio driver that runs off the main thread preventing it from stalling or crackling when framerate drops or when changing scenes. However, it is currently not supported by all browsers (notably, Safari and thus iOS does not support it yet). It also requires some [extra care when distributing](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#Security_requirements).
- **GDNative**: Supports GDNative libraries, allowing to write your code in other languages (e.g. C++) so you can further optimize your game and speed up execution, or bind external libraries to add extra functionalities to the engine. On the downsides, it will result in a bigger build size, thus increasing the startup time and memory usage.

In general, my suggestion if you are not interested in mobile browser support is to use the *Threads* build to get the best performance with the smallest effort.
Hopefully, Safari's support for WebAssembly threads will ship next year thanks to the great work people are doing on the WebKit project, and even developers interested in HTML5 exports for mobile will be able to use the threaded version.

Web Editor beta
===============

A new version of the web editor has been published at [this temporary address](https://godotengine.org/editor/).

This is the first release tagged as "official" and based on the exact same sources of the other [3.2.4 beta 4](https://godotengine.org/article/dev-snapshot-godot-3-2-4-beta-4) builds. The goal is to keep the editor in sync with stable builds (starting from 3.2.4 stable). Old versions will still be available at dedicated locations.

![Web editor landing page](/storage/app/uploads/public/5fe/0b7/741/5fe0b77416fd2727783264.png)

The highlights of the new version are:

- A new improved look and feel of the HTML page that looks more integrated with the editor (special thanks to [Calinou](https://github.com/Calinou)).
- All importing issues should have been fixed. Most notably, audio samples can now be imported correctly, so the demo project now contains audio too.
- An old bug in the thirdparty Tween functions has been fixed that caused weird behaviors on HTML5 exports (and potentially other platforms too).
- Few bugs have been fixed in the JavaScript code that interfaces HTML5 exports with the browser (that glue-code has been mostly rewritten).

Honorable mentions
==================

I would like to give a shout-out to the amazing work done by [dsnopek](https://github.com/dsnopek) and [lawnjelly](https://github.com/lawnjelly) on [WebXR](https://github.com/godotengine/godot/pull/42397) and [GLES/WebGL in Godot 4.0](https://twitter.com/lawnjelly/status/1336767514227957761) respectively. You well deserve the Web export medal of honor.

Future work
===========

We feel like the web editor is almost ready to become stable, and plan to release it as such when 3.2.4 is released, but there are still few things that needs to be improved for web exports before I can refocus my work on some other ideas I've been sketching for networking and server exports:

The HTML5-related **documentation** needs some love to be more in sync with the current status.

**Gamepad** support on HTML5 is in an abysmal state, this is for many reasons. First of all the W3C specification is incomplete and does not allow to easily identify devices in a unique way. Additionally, the sheer amount of work required to support all possible devices is too much for browser vendors.
In an effort to improve the current situation, we plan to create a small addon that allows to remap the gamepad on the fly that you can bundle in your game, or send your generated mappings to us (so we can bundle them in future Godot versions). While this won't solve all the problems until the specification is improved and browser support gets better, it should allow for many more controller to work out of the box across different platforms.

I've recently proposed a better way than `eval` to **communicate with JavaScript**, and that will need a tentative implementation.

Stay tuned for the next announcement!

References
==========

[GDNative support](https://github.com/godotengine/godot/pull/44076) [(3.2)](https://github.com/godotengine/godot/pull/44170)

[Threads/AudioWorklet](https://github.com/godotengine/godot/pull/43443) [(3.2)](https://github.com/godotengine/godot/pull/43454)

[Importing issues](https://github.com/godotengine/godot/pull/44161)

[Tween bug](https://github.com/godotengine/godot/pull/44197)

[Editor style](https://github.com/godotengine/godot/pull/44221) [(3.2)](https://github.com/godotengine/godot/pull/44256)


---
title: "Basic cryptography, SSL improvements"
excerpt: "As part of the MOSS project sponsored by Mozilla, during July I worked on some new features regarding cryptography and SSL to improve the quality and security of Godot networking."
categories: ["progress-report"]
author: Fabio Alessandrelli
image: /storage/app/uploads/public/5d8/f4b/b0a/5d8f4bb0a3174096196968.png
date: 2019-09-28 12:15:00
---

As part of the MOSS project sponsored by Mozilla, during July I worked on some new features regarding cryptography and SSL to improve the quality and security of Godot networking.

Certificates and keys as resources
----------------------------------

SSL certificates (in the form of `*.crt` files) and private keys (in the form of `*.key` files) are now treated as resources in Godot. This means they will be exported automatically and they can be loaded via the GDScript `load()` function.

Crypto class
------------

A new [`Crypto`](http://docs.godotengine.org/en/latest/classes/class_crypto.html) class was introduced that allows to access some basic cryptographic functions.

- You can generate cryptographically secure random bytes via the `generate_random_bytes()` function. The bytes are returned in a `PoolByteArray`.
- You can generate RSA keys that can be used by `StreamPeerSSL` to act as a server.
- You can generate SSL self-signed certificates that again, can be used by `StreamPeerSSL` to act as a server.

Hashing Context
---------------

A new [`HashingContext`](http://docs.godotengine.org/en/latest/classes/class_hashingcontext.html) class now provides an interface for computing cryptographic hashes (MD5, SHA-1, SHA-256) over multiple iterations.

This is useful for example when computing hashes of big files (so you don't have to load them all in memory), network streams, and data streams in general (so you don't have to hold buffers). Here is an example of how it works:

```
const CHUNK_SIZE = 1024

func hash_file(path):
	var ctx = HashingContext.new()
	var file = File.new()
	# Start a SHA-256 context.
	ctx.start(HashingContext.HASH_SHA256)
	# Check that file exists.
	if not file.file_exists(path):
	    return
	# Open the file to hash.
	file.open(path, File.READ)
	# Update the context after reading each chunk.
	while not file.eof_reached():
	    ctx.update(file.get_buffer(CHUNK_SIZE))
	# Get the computed hash.
	var res = ctx.finish()
	# Print the result as hex string and array.
	printt(res.hex_encode(), Array(res))
```

SSL improvements
----------------

[`StreamPeerSSL`](http://docs.godotengine.org/en/latest/classes/class_streampeerssl.html) can now use a per-object SSL certificate (i.e. you no longer have to set the trusted certificates om project settings), you can specify the valid certificate by passing an `X509Certificate ` as last parameter in `connect_to_stream()`.

`StreamPeerSSL` can now act as a server. The new `accept_stream()` function, which accepts a private key, a certificate, and an optional CA chain, will try to establish a connection with the given stream acting as a server. This will soon also allow us to support acting as a WebSocket server over TLS.

Here is an example of a test HTTPS server made in GDScript... not meant to be used in production ;-)

```
extends Node

# A class that represents a client accepted by our server.
class Client extends Reference:
	# The SSL stream of this client.
	var ssl = StreamPeerSSL.new()
	# Received request.
	var recv = ""

	# Set the stream for this client.
	func set_stream(stream, key, cert):
		ssl.blocking_handshake = false
		ssl.accept_stream(stream, key, cert)

	# Process network operations for this client.
	func process():
		if ssl.get_status() == StreamPeerSSL.STATUS_HANDSHAKING:
			# Still performing handshake.
			ssl.poll()
			return
		if ssl.get_status() != StreamPeerSSL.STATUS_CONNECTED:
			# Disconnected.
			return
		ssl.poll()
		# Read available bytes.
		if ssl.get_available_bytes() > 0:
			recv += ssl.get_data(ssl.get_available_bytes())[1].get_string_from_utf8()
		# Send response if request is complete.
		if recv.ends_with("\r\n\r\n"):
			ssl.put_data(("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" + \
						"<h2>Godot TLS Test Server</h2>\r\n" + \
						"<p>Successful connection using SSL</p>\r\n").to_utf8())
			ssl.disconnect_from_stream()

	func is_disconnected():
		return ssl.get_status() != StreamPeerSSL.STATUS_HANDSHAKING and \
		    ssl.get_status() != StreamPeerSSL.STATUS_CONNECTED

# Our TCP server.
var _server = TCP_Server.new()
# A list of connected clients.
var _clients = []

# Our private key and certificate.
var _key = null
var _cert = null

func _ready():
	var crypto = Crypto.new()
	# Generate an RSA key (this should be done in a thread to avoid blocking).
	_key = crypto.generate_rsa(4096)
	# Generate a self signed certificate to use with our server.
	_cert = crypto.generate_self_signed_certificate(_key, "CN=example.com,O=A Game Company,C=IT")
	# Start listening on "*:4343".
	_server.listen(4343)

func _process(delta):
	# Take new connections.
	if _server.is_connection_available():
		var c = Client.new()
		c.set_stream(_server.take_connection(), _key, _cert)
		_clients.append(c)

	# Take note of disconnected clients.
	var to_rem = []
	# Process clients and send response when done.
	for c in _clients:
		c.process()
		if c.is_disconnected():
			to_rem.append(c)

	# Remove disconnected clients.
	for c in to_rem:
		_clients.erase(c)
```

Future work
-----------

This has been quite a long work, and included some refactoring of the `core` code to use a single library for cryptography (mbedTLS) instead of multiple specific libraries for hashing algorithms and AES. This work will allow us to introduce support for AES encryption and more at scripting level in future versions.

Additionally, the SSL overhaul helped a lot in developing the upcoming DTLS implementation.

References
----------

- [PR refactoring the `core` crypto code](https://github.com/godotengine/godot/pull/30239)
- [PR adding Crypto class, Hashing contexts, SSL server](https://github.com/godotengine/godot/pull/29871)
- [PR adding documentation for above-mentioned additions](https://github.com/godotengine/godot/pull/32285)


# Downloads

{% include articles/download_card.html version="4.1.4" release="rc3" article=page %}

**Standard build** includes support for GDScript and GDExtension.

**.NET 6 build** (marked as `mono`) includes support for C#, as well as GDScript and GDExtension.
- .NET build requires [.NET SDK 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) or [7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) installed in a standard location.

{% include articles/download_card.html version="4.2.2" release="rc3" article=page %}

**Standard build** includes support for GDScript and GDExtension.

**.NET build** (marked as `mono`) includes support for C#, as well as GDScript and GDExtension.
- .NET build requires [.NET SDK 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0), [7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0), or [8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) installed in a standard location.
- To export to Android, .NET 7.0 or later is required. To export to iOS, .NET 8.0 is required. Make sure to set the target framework in the `.csproj` file.

{% include articles/prerelease_notice.html %}

## Known issues

There are currently no known issues introduced by these releases.

With every release we accept that there are going to be various issues, which have already been reported but haven't been fixed yet. See the GitHub issue tracker for a complete list of [known bugs](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aopen+label%3Abug+).

## Bug reports

As a tester, we encourage you to [open bug reports](https://github.com/godotengine/godot/issues) if you experience issues with this release. Please check the [existing issues on GitHub](https://github.com/godotengine/godot/issues) first, using the search function with relevant keywords, to ensure that the bug you experience is not already known.

In particular, any change that would cause a regression in your projects is very important to report (e.g. if something that worked fine in previous 4.x releases no longer works).

## Support

Godot is a non-profit, open source game engine developed by hundreds of contributors on their free time, as well as a handful of part or full-time developers hired thanks to [generous donations from the Godot community](https://fund.godotengine.org/). A big thank you to everyone who has contributed [their time](https://github.com/godotengine/godot/blob/master/AUTHORS.md) or [their financial support](https://github.com/godotengine/godot/blob/master/DONORS.md) to the project!

If you'd like to support the project financially and help us secure our future hires, you can do so using the [Godot Development Fund](https://fund.godotengine.org/) platform managed by [Godot Foundation](https://godot.foundation/). There are also several [alternative ways to donate](/donate) which you may find more suitable.


Solution

### Preparation

Solving the problems identified above does not actually require the introduction of an acyclic graph: inserting synchronization barriers and performing dependency tracking is entirely possible without applying this technique. This was actually debated internally for a while, but it was determined that if the engine was able to reorder commands, it'd allow for grouping them more effectively between the mandatory synchronization points and would result in better performance.

However, being able to reorder commands meant that an intermediate step had to be introduced where commands were recorded into an auxiliary structure that could be reordered and then converted to the corresponding native API commands. One possibility was encoding the Vulkan command arguments into the auxiliary buffer, but that approach meant the entire graph structure and logic would need to be implemented for every other backend as well. Therefore, it was deemed it'd be necessary for Pedro to work on his [pull request](https://github.com/godotengine/godot/pull/83452) that introduces an abstract interface for all the supported graphic APIs, including Vulkan, D3D12 and Metal in the near future. Thanks to this change, it was possible to use a single abstract API to encode commands into the auxiliary buffer.

The initial redesign was laid out in *reduz*'s [draft](https://gist.github.com/reduz/980b9b2547d57e6a915b2bb7e1e76e08), which was largely inspired by [Pavlo Muratov's "Organizing GPU Work with Directed Acyclic Graphs"](https://levelup.gitconnected.com/organizing-gpu-work-with-directed-acyclic-graphs-f3fd5f2c2af3) and showed the possibility of how the concept could be applied to Godot's existing design. Not everything stated in the document made it into the final version: in fact, the changes to RenderingDevice were much less severe than initially indicated and the interface remained largely compatible. While the article that was used as inspiration includes a very detailed algorithm in how to implement multi-queue submission by using the graph, the team made the decision to cut this idea short and stick to a single command queue to begin with, as the difficulty of the task would come from building the graph automatically and would already take a significant amount of development time.

### Acyclic graph

The unique aspect of the implemented graph is that its construction is completely invisible to the programmer using RenderingDevice. Commands requested from the class are logged internally and each command maintains an adjacency list that is updated as new dependencies are detected. Since these adjacencies only work one way and older commands cannot depend on future commands, it is virtually impossible for cyclic dependencies to form (hence the "acyclic" part of the graph). While a graph can be constructed in many ways, a list of vertices and an adjacency list are sufficient. Render commands play the role of vertices, and commands store the indices of their adjacent commands.

| ![](/storage/blog/acyclic-graph/command-graph.webp) |
|:--:|
| *The rendering operations of a frame and their dependencies represented as a graph.* |

An important decision that was made to allow this structure to scale more effectively is that each instance of a draw list or a compute list are considered as **one node in the graph**. There is no benefit to allowing reordering within these structures and Godot already has a clear concept of what these lists are used for. Games often draw a lot of geometry, but they don't create tons of render passes per frame, as that doesn't result in efficient use of the GPU. To put it in numbers, one of the benchmark scenes used during testing could easily reach hundreds of thousands of nodes if each individual command was recorded into the graph. Making the distinction to correlate render passes to individual nodes brought this number down to about **300 nodes per frame**. Operating with a graph of this scale was a very good sign that the performance overhead would be very small.

Once all commands for the frame have been recorded, a [topological sort](https://en.wikipedia.org/wiki/Topological_sorting) is performed on the graph to get an ordered list of commands. During this step the "levels" of the commands are detected to determine how they can be grouped and where synchronization points (barriers) should be introduced. All commands belonging to a particular level in the graph can be executed in parallel as no dependencies have been detected between them, meaning that no barriers are required until the next level is reached. This sorting step is where the magic behind the performance gains happens.

| ![](/storage/blog/acyclic-graph/command-graph-levels.webp) |
|:--:|
| *After sorting, all commands that belong to the same level can be executed in any order, resulting in multiple possible command sequences.* |

One important detail that resulted in frametime reductions during this step was to take into account the type of command as a sorting factor: grouping together operations based on whether they were related to copying data, drawing or compute dispatches provided some noticeable increases in performance. While the exact reason behind this has not been determined, it seems likely that GPUs prefer to change the type of pipeline they need to use within a command buffer as little as possible.

While the concept of using a structure like a graph and using sorting algorithms might sound like the most daunting part of the task due to the level of abstraction involved, it is the dependency tracking and adjacency list detection during command recording where most problems arise. The relationships shown in the diagrams above were not specified by the programmer using RenderingDevice: they must be detected automatically based on how the resources were used in the frame, and this turned out to be no small task due to some particular details of how Godot works.

### Resource tracking

The resources used by RenderingDevice in Godot are buffers or textures. While these are separate objects at the lower level depending on the API being used, the graph considers them both as one to share much of the logic during implementation. However, a distinction will be made later when texture slices are introduced, which is something Godot uses quite a bit in various parts of its rendering code. Textures also have the additional requirement that they need to make layout transitions to be ready for use in different commands, while buffers don't need to do this at all.

Whenever a resource is created, a new "tracker" structure is introduced to store the information relevant to the graph construction during command recording. The tracker holds references to which commands are writing or reading from the resource and modifies these lists accordingly as more commands are recorded. It also stores a "usage" variable that indicates what the current use of the resource is at the time of recording. Usages are both classified as "read" or "read-write" operations, and which one is used has strong implications for how dependencies between commands will be detected. For example, a command that reads from Resource A can be executed in parallel with another command that reads from Resource A, but that will not be valid if the other command can write to Resource A. In this case, a dependency is inserted between the two commands to ensure that the first command can finish reading the resource correctly before the next command modifies it.

| ![](/storage/blog/acyclic-graph/resource-tracking.webp) |
|:--:|
| *The tracker holds the current usage of a resource and determines whether it is necessary to perform a transition based on the type of command that references it.* |

Textures also have a particular requirement: changing the usage implies a memory layout transition even if it's just for read-only operations. For example, there's different layouts for a texture being used as the source of a copy operation and for a texture being used for sampling in a shader. While this distinction might not necessarily be true at the hardware level, it is actually possible to witness texture corruption if these transitions are not performed correctly depending on the GPU's architecture (AMD is really good for testing these out!). Therefore, any change in usage when textures are involved is usually considered a write operation as most of them require a particular layout. This introduces some dependencies between commands that might not be very obvious but are completely required for the operations to work correctly: continuing with the previous example, it's not possible to use the optimal memory layout for copying a texture and sampling it in a shader in parallel, even if both are read-only operations.

##