#ifndef JGEOMETRY_H #define JGEOMETRY_H #include "dolphin/mtx.h" #include "math.h" #include "JSystem/JMath/JMath.h" namespace JGeometry { template struct TUtil { static inline T clamp(T v, T min, T max) { if (v < min) { return min; } if (v > max) { return max; } return v; } }; template<> struct TUtil { static inline f32 clamp(f32 v, f32 min, f32 max) { if (v < min) { return min; } if (v > max) { return max; } return v; } static inline f32 epsilon() { return 32.0f * FLT_EPSILON; } static inline f32 PI() { return 3.1415927f; } static inline f32 inv_sqrt(f32 x) { if (x <= 0.0f) { return x; } f32 root = __frsqrte(x); root = 0.5f * root * (3.0f - x * (root * root)); return root; } }; template<> struct TUtil { static inline double epsilon() { return 32.0f * FLT_EPSILON; } static inline double one() { return 1.0; } static inline double atan2(double x, double y) { return ::atan2(x, y); } static inline double asin(double x) { return ::asin(x); } static inline double halfPI() { return 1.5707963267948966; } }; template struct TVec3 { T x; T y; T z; void set(const TVec3& other) { x = other.x; y = other.y; z = other.z; } }; template <> struct TVec3 { double x, y, z; void set(double x_, double y_, double z_) { x = x_; y = y_; z = z_; } inline TVec3& operator*=(double b) { scale(b); return *this; } void scale(double b) { x *= b; y *= b; z *= b; } }; template <> struct TVec3 { s16 x, y, z; TVec3() {} TVec3(s16 x, s16 y, s16 z) { set(x, y, z); } TVec3& operator=(const TVec3& b) { // Force copies to use lwz/lha *((s32*)this) = *((s32*)&b); z = b.z; return *this; } void set(s16 x_, s16 y_, s16 z_) { x = x_; y = y_; z = z_; } }; inline void setTVec3f(const f32* vec_a, f32* vec_b) { const register f32* v_a = vec_a; register f32* v_b = vec_b; register f32 a_x; register f32 b_x; #ifdef __MWERKS__ asm { psq_l a_x, 0(v_a), 0, 0 lfs b_x, 8(v_a) psq_st a_x, 0(v_b), 0, 0 stfs b_x, 8(v_b) }; #endif } // Until we figure out TVec3 ctors inline void setTVec3f(const Vec& vec_a, Vec& vec_b) { setTVec3f(&vec_a.x, &vec_b.x); } inline float fsqrt_step(float mag) { f32 root = __frsqrte(mag); return 0.5f * root * (3.0f - mag * (root * root)); } inline void mulInternal(register const f32* a, register const f32* b, register float* dst) { register f32 a_x_y; register f32 b_x_y; register f32 x_y; register f32 za; register f32 zb; register f32 z; #ifdef __MWERKS__ asm { psq_l a_x_y, 0(a), 0, 0 psq_l b_x_y, 0(b), 0, 0 ps_mul x_y, a_x_y, b_x_y psq_st x_y, 0(dst), 0, 0 }; dst[2] = a[2] * b[2]; #endif } template <> struct TVec3 : public Vec { inline TVec3(const Vec& i_vec) { setTVec3f(&i_vec.x, &x); } inline TVec3(const TVec3& i_vec) { setTVec3f(&i_vec.x, &x); } template TVec3(U x, U y, U z) { set(x, y, z); } TVec3() {} operator Vec*() { return (Vec*)&x; } operator const Vec*() const { return (Vec*)&x; } template void set(const TVec3& other) { x = other.x; y = other.y; z = other.z; } void set(const Vec& other) { x = other.x; y = other.y; z = other.z; } template void set(U x_, U y_, U z_) { x = x_; y = y_; z = z_; } inline void add(const TVec3& b) { JMathInlineVEC::C_VECAdd((Vec*)&x, (Vec*)&b.x, (Vec*)&x); } void zero() { x = y = z = 0.0f; } void mul(const TVec3& a, const TVec3& b) { mulInternal(&a.x, &b.x, &this->x); } inline void mul(const TVec3& a) { mul(*this, a); } inline TVec3& operator=(const Vec& b) { setTVec3f(&b.x, &this->x); return *this; } inline TVec3& operator=(const TVec3& b) { set(b.x, b.y, b.z); return *this; } inline TVec3& operator+=(const TVec3& b) { add(b); return *this; } inline TVec3 operator+(const TVec3& b) { TVec3 a = *this; a += b; return a; } // inline TVec3 operator+(const TVec3& b) { // TVec3 res(*(Vec*)this); // res += b; // return res; // } f32 squared() const { return JMathInlineVEC::C_VECSquareMag((Vec*)&x); } f32 normalize() { f32 sq = squared(); if (sq <= TUtil::epsilon()) { return 0.0f; } f32 inv_norm = TUtil::inv_sqrt(sq); scale(inv_norm); return inv_norm * sq; } void normalize(const TVec3& other) { f32 sq = other.squared(); if (sq <= TUtil::epsilon()) { zero(); return; } f32 norm; if (sq <= 0.0f) { norm = sq; } else { norm = fsqrt_step(sq); } scale(norm, other); } f32 length() const { return VECMag((Vec*)this); } void scale(register f32 sc) { register f32 z; register f32 x_y; register f32* dst = &x; register f32 zres; #ifdef __MWERKS__ asm { psq_l x_y, 0(dst), 0, 0 psq_l z, 8(dst), 1, 0 ps_muls0 x_y, x_y, sc psq_st x_y, 0(dst), 0, 0 ps_muls0 zres, z, sc psq_st zres, 8(dst), 1, 0 }; #endif } void scale(register f32 sc, const TVec3& other) { register const f32* src = &other.x; register f32 z; register f32 x_y; register f32* dst = &x; register f32 zres; #ifdef __MWERKS__ asm { psq_l x_y, 0(src), 0, 0 psq_l z, 8(src), 1, 0 ps_muls0 x_y, x_y, sc psq_st x_y, 0(dst), 0, 0 ps_muls0 zres, z, sc psq_st zres, 8(dst), 1, 0 }; #endif } void scaleAdd(register f32 sc, const TVec3& a, const TVec3& b) { JMAVECScaleAdd(&a, &b, this, sc); } void negateInternal(TVec3* dst) { register f32* rdst = &dst->x; const register f32* src = &x; register f32 x_y; register f32 z; #ifdef __MWERKS__ asm { psq_l x_y, 0(src), 0, 0 ps_neg x_y, x_y psq_st x_y, 0(rdst), 0, 0 lfs z, 8(src) fneg z, z stfs z, 8(rdst) }; #endif } void negate() { negateInternal(this); } void sub(const TVec3& b) { JMathInlineVEC::C_VECSubtract((Vec*)&x, (Vec*)&b.x, (Vec*)&x); } void sub(const TVec3& a, const TVec3& b) { JMathInlineVEC::C_VECSubtract((Vec*)&a.x, (Vec*)&b.x, (Vec*)&x); } bool isZero() const { return squared() <= TUtil::epsilon(); } void cross(const TVec3& a, const TVec3& b) { VECCrossProduct(a, b, *this); } f32 setLength(f32 len) { f32 sq = squared(); if (sq <= TUtil::epsilon()) { return 0.0f; } f32 inv_norm = TUtil::inv_sqrt(sq); scale(inv_norm * len); return inv_norm * sq; } f32 setLength(const TVec3& other, f32 len) { f32 sq = other.squared(); if (sq <= TUtil::epsilon()) { zero(); return 0.0f; } f32 inv_norm = TUtil::inv_sqrt(sq); scale(inv_norm * len, other); return inv_norm * sq; } f32 dot(const TVec3& other) const { return JMathInlineVEC::C_VECDotProduct(this, &other); } void cubic(const TVec3& param_1, const TVec3& param_2, const TVec3& param_3, const TVec3& param_4, f32 param_5) { f32 fVar5 = param_5 * param_5; f32 fVar6 = fVar5 * param_5; f32 fVar8 = 1.0f + (2.0f * fVar6 - 3.0f * fVar5); f32 fVar9 = -2.0f * fVar6 + 3.0f * fVar5; f32 fVar7 = param_5 + (fVar6 - 2.0f * fVar5); f32 fVar4 = fVar6 - fVar5; x = fVar8 * param_1.x + fVar9 * param_4.x + fVar7 * param_2.x + fVar4 * param_3.x; y = fVar8 * param_1.y + fVar9 * param_4.y + fVar7 * param_2.y + fVar4 * param_3.y; z = fVar8 * param_1.z + fVar9 * param_4.z + fVar7 * param_2.z + fVar4 * param_3.z; } }; template struct TVec2 { TVec2() {} TVec2(T v) { set(v); } TVec2(T x, T y) { set(x, y); } void set(T v) { y = x = v; } void set(T x, T y) { this->x = x; this->y = y; } void set(const TVec2& other) { x = other.x; y = other.y; } void setMin(const TVec2& min) { if (x >= min.x) x = min.x; if (y >= min.y) y = min.y; } void setMax(const TVec2& max) { if (x <= max.x) x = max.x; if (y <= max.y) y = max.y; } void add(const TVec2& other) { x += other.x; y += other.y; } bool isAbove(const TVec2& other) const { return (x >= other.x) && (y >= other.y) ? true : false; } f32 dot(const TVec2& other) const { return x * other.x + y * other.y; } f32 squared() const { return dot(*this); } f32 length() const { f32 sqr = squared(); if (sqr <= 0.0f) { return sqr; } sqr *= fsqrt_step(sqr); return sqr; } T x; T y; }; template struct TBox { TBox() : i(), f() {} TBox(const TBox& other) : i(other.i), f(other.f) {} T i, f; }; // clang-format off template<> struct TBox > { f32 getWidth() const { return f.x - i.x; } f32 getHeight() const { return f.y - i.y; } bool isValid() const { return f.isAbove(i); } void addPos(f32 x, f32 y) { addPos(TVec2(x, y)); } void addPos(const TVec2& pos) { i.add(pos); f.add(pos); } bool intersect(const TBox >& other) { i.setMax(other.i); f.setMin(other.f); return isValid(); } TVec2 i, f; }; template struct TBox2 : TBox > { TBox2() {} TBox2(const TVec2& i, const TVec2& f) { set(i, f); } TBox2(f32 x0, f32 y0, f32 x1, f32 y1) { set(x0, y0, x1, y1); } void absolute() { if (!this->isValid()) { TBox2 box(*this); this->i.setMin(box.i); this->i.setMin(box.f); this->f.setMax(box.i); this->f.setMax(box.f); } } void set(const TBox2& other) { set(other.i, other.f); } void set(const TVec2& i, const TVec2& f) { this->i.set(i), this->f.set(f); } void set(f32 x0, f32 y0, f32 x1, f32 y1) { this->i.set(x0, y0); this->f.set(x1, y1); } }; // clang-format on } // namespace JGeometry #endif