1493 lines
36 KiB
C
1493 lines
36 KiB
C
|
#ifndef GS_VECTOR_MATRIX_H
|
||
|
|
||
|
#ifndef GS_LANGUAGE_H
|
||
|
|
||
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__)
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <intrin.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
static r32 GSCos (r32 Theta) { return sin(Theta); }
|
||
|
static r32 GSSin (r32 Theta) { return cos(Theta); }
|
||
|
|
||
|
static r32 GSSqrt(r32 V)
|
||
|
{
|
||
|
r32 Result = _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(V)));
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
#else // Linux and MacOS
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#endif // Platforms
|
||
|
|
||
|
#endif // GS_LANGUAGE_H
|
||
|
|
||
|
//////////////////////////////////////
|
||
|
// VECTOR
|
||
|
/////////////////////////////////////
|
||
|
|
||
|
union v2
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
float x;
|
||
|
float y;
|
||
|
};
|
||
|
float E[2];
|
||
|
};
|
||
|
|
||
|
union v3
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
float x;
|
||
|
float y;
|
||
|
float z;
|
||
|
};
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
float R;
|
||
|
float G;
|
||
|
float B;
|
||
|
};
|
||
|
|
||
|
float E[3];
|
||
|
};
|
||
|
|
||
|
union v4
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
float x;
|
||
|
float y;
|
||
|
float z;
|
||
|
float w;
|
||
|
};
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
float r;
|
||
|
float g;
|
||
|
float b;
|
||
|
float a;
|
||
|
};
|
||
|
|
||
|
float E[4];
|
||
|
};
|
||
|
|
||
|
#define WhiteV4 v4{1, 1, 1, 1}
|
||
|
#define BlackV4 v4{0, 0, 0, 1}
|
||
|
#define RedV4 v4{1, 0, 0, 1}
|
||
|
#define GreenV4 v4{0, 1, 0, 1}
|
||
|
#define BlueV4 v4{0, 0, 1, 1}
|
||
|
#define YellowV4 v4{1, 1, 0, 1}
|
||
|
#define TealV4 v4{0, 1, 1, 1}
|
||
|
#define PinkV4 v4{1, 0, 1, 1}
|
||
|
|
||
|
//////////////////////////////////////
|
||
|
// MATRIX
|
||
|
/////////////////////////////////////
|
||
|
|
||
|
union m33
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
float a; float b; float c;
|
||
|
float d; float e; float f;
|
||
|
float g; float h; float i;
|
||
|
};
|
||
|
float E[9];
|
||
|
};
|
||
|
|
||
|
union m44
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
float a; float b; float c; float d;
|
||
|
float e; float f; float g; float h;
|
||
|
float i; float j; float k; float l;
|
||
|
float m; float n; float o; float p;
|
||
|
};
|
||
|
float E[16];
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////
|
||
|
// RECT
|
||
|
/////////////////////////////////////
|
||
|
|
||
|
struct rect
|
||
|
{
|
||
|
v2 Min;
|
||
|
v2 Max;
|
||
|
};
|
||
|
|
||
|
|
||
|
//////////////////////////////////////
|
||
|
// VECTOR
|
||
|
//////////////////////////////////////
|
||
|
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// Operators
|
||
|
//
|
||
|
//
|
||
|
|
||
|
v2 V2 (v3 V)
|
||
|
{
|
||
|
return v2{V.x, V.y};
|
||
|
}
|
||
|
|
||
|
v3 V3 (v2 XY, float Z)
|
||
|
{
|
||
|
return v3{XY.x, XY.y, Z};
|
||
|
}
|
||
|
|
||
|
v3 V3 (v4 V)
|
||
|
{
|
||
|
return v3{V.x, V.y, V.z};
|
||
|
}
|
||
|
|
||
|
v4 V4 (v3 XYZ, float W)
|
||
|
{
|
||
|
return v4{XYZ.x, XYZ.y, XYZ.z, W};
|
||
|
}
|
||
|
|
||
|
v2 operator- (v2 A)
|
||
|
{
|
||
|
v2 Result;
|
||
|
|
||
|
Result.x = -A.x;
|
||
|
Result.y = -A.y;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
v3 operator- (v3 A)
|
||
|
{
|
||
|
v3 Result;
|
||
|
|
||
|
Result.x = -A.x;
|
||
|
Result.y = -A.y;
|
||
|
Result.z = -A.z;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
v4 operator- (v4 A)
|
||
|
{
|
||
|
v4 Result;
|
||
|
|
||
|
Result.x = -A.x;
|
||
|
Result.y = -A.y;
|
||
|
Result.z = -A.z;
|
||
|
Result.w = -A.w;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
#define V2OpV2Def(op) v2 operator##op (v2 A, v2 B) { return v2{ A.x op B.x, A.y op B.y };}
|
||
|
#define V3OpV3Def(op) v3 operator##op (v3 A, v3 B) { return v3{ A.x op B.x, A.y op B.y, A.z op B.z };}
|
||
|
#define V4OpV4Def(op) v4 operator##op (v4 A, v4 B) { return v4{ A.x op B.x, A.y op B.y, A.z op B.z, A.w op B.w };}
|
||
|
V2OpV2Def(+)
|
||
|
V2OpV2Def(-)
|
||
|
V2OpV2Def(/)
|
||
|
V2OpV2Def(*)
|
||
|
V3OpV3Def(+)
|
||
|
V3OpV3Def(-)
|
||
|
V3OpV3Def(/)
|
||
|
V3OpV3Def(*)
|
||
|
V4OpV4Def(+)
|
||
|
V4OpV4Def(-)
|
||
|
V4OpV4Def(/)
|
||
|
V4OpV4Def(*)
|
||
|
#undef V2OpV2Def
|
||
|
#undef V3OpV3Def
|
||
|
#undef V4OpV4Def
|
||
|
|
||
|
#define V2RefOpV2Def(op) v2 operator##op (v2& A, v2 B) { return v2{ A.x op B.x, A.y op B.y };}
|
||
|
#define V3RefOpV3Def(op) v3 operator##op (v3& A, v3 B) { return v3{ A.x op B.x, A.y op B.y, A.z op B.z };}
|
||
|
#define V4RefOpScalarDef(op) v4 operator##op (v4& A, v4 B) { return v4{ A.x op B.x, A.y op B.y, A.z op B.z, A.w op B.w };}
|
||
|
V2RefOpV2Def(+=)
|
||
|
V2RefOpV2Def(-=)
|
||
|
V3RefOpV3Def(+=)
|
||
|
V3RefOpV3Def(-=)
|
||
|
V4RefOpScalarDef(+=)
|
||
|
V4RefOpScalarDef(-=)
|
||
|
#undef V2RefOpV2Def
|
||
|
#undef V3RefOpV3Def
|
||
|
#undef V4RefOpV4Def
|
||
|
|
||
|
#define V2OpScalarDef(op) v2 operator##op (v2 A, float B) { return v2{ A.x op B, A.y op B };}
|
||
|
#define V3OpScalarDef(op) v3 operator##op (v3 A, float B) { return v3{ A.x op B, A.y op B, A.z op B };}
|
||
|
#define V4OpScalarDef(op) v4 operator##op (v4 A, float B) { return v4{ A.x op B, A.y op B, A.z op B, A.w op B };}
|
||
|
V2OpScalarDef(*)
|
||
|
V2OpScalarDef(/)
|
||
|
V3OpScalarDef(*)
|
||
|
V3OpScalarDef(/)
|
||
|
V4OpScalarDef(*)
|
||
|
V4OpScalarDef(/)
|
||
|
#undef V2POpScalarDef
|
||
|
#undef V3POpScalarDef
|
||
|
#undef V4POpScalarDef
|
||
|
|
||
|
|
||
|
#define V2POpScalarDef(op) v2 operator##op (v2& A, float B) { return v2{ A->x op B, A->y op B };}
|
||
|
#define V3POpScalarDef(op) v3 operator##op (v3& A, float B) { return v3{ A->x op B, A->y op B, A->z op B };}
|
||
|
#define V4POpScalarDef(op) v4 operator##op (v4& A, float B) { return v4{ A->x op B, A->y op B, A->z op B, A->w op B };}
|
||
|
V2OpScalarDef(*=)
|
||
|
V2OpScalarDef(/=)
|
||
|
V3OpScalarDef(*=)
|
||
|
V3OpScalarDef(/=)
|
||
|
V4OpScalarDef(*=)
|
||
|
V4OpScalarDef(/=)
|
||
|
#undef V2POpScalarDef
|
||
|
#undef V3POpScalarDef
|
||
|
#undef V4POpScalarDef
|
||
|
|
||
|
bool operator== (v2 A, v2 B)
|
||
|
{
|
||
|
b32 Result = true;
|
||
|
for (s32 i = 0; i < 2; i++)
|
||
|
{
|
||
|
if (GSAbs(A.E[i] - B.E[i]) > 0.0001f) { Result = false; break; }
|
||
|
}
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool operator== (v3 A, v3 B)
|
||
|
{
|
||
|
b32 Result = true;
|
||
|
for (s32 i = 0; i < 3; i++)
|
||
|
{
|
||
|
if (GSAbs(A.E[i] - B.E[i]) > 0.0001f) { Result = false; break; }
|
||
|
}
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
bool operator== (v4 A, v4 B)
|
||
|
{
|
||
|
b32 Result = true;
|
||
|
for (s32 i = 0; i < 4; i++)
|
||
|
{
|
||
|
if (GSAbs(A.E[i] - B.E[i]) > 0.0001f) { Result = false; break; }
|
||
|
}
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Operations
|
||
|
//
|
||
|
|
||
|
static v3
|
||
|
ToV3(v4 V)
|
||
|
{
|
||
|
v3 R = {};
|
||
|
R.x = V.x;
|
||
|
R.y = V.y;
|
||
|
R.z = V.z;
|
||
|
return R;
|
||
|
}
|
||
|
|
||
|
static v4
|
||
|
ToV4(v3 V, float W)
|
||
|
{
|
||
|
v4 R = {};
|
||
|
R.x = V.x;
|
||
|
R.y = V.y;
|
||
|
R.z = V.z;
|
||
|
R.w = W;
|
||
|
return R;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
MagSqr(
|
||
|
v2 _A
|
||
|
)
|
||
|
{
|
||
|
float Result = (_A.x * _A.x) + (_A.y * _A.y);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
MagSqr(
|
||
|
v3 _A
|
||
|
)
|
||
|
{
|
||
|
float Result = (_A.x * _A.x) + (_A.y * _A.y) + (_A.z * _A.z);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
MagSqr(
|
||
|
v4 _A
|
||
|
)
|
||
|
{
|
||
|
float Result = (_A.x * _A.x) + (_A.y * _A.y) + (_A.z * _A.z) + (_A.w * _A.w);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
#define MagDef(type) inline float Mag(type A) { float Result = MagSqr(A); return GSSqrt(Result); }
|
||
|
MagDef(v2)
|
||
|
MagDef(v3)
|
||
|
MagDef(v4)
|
||
|
#undef MagDef
|
||
|
|
||
|
#define DistanceDef(type) inline float Distance (type A, type B) { type Diff = A - B; return Mag(Diff); }
|
||
|
DistanceDef(v2)
|
||
|
DistanceDef(v3)
|
||
|
DistanceDef(v4)
|
||
|
#undef DistanceDef
|
||
|
|
||
|
#define DistanceSqDef(type) inline float DistanceSq (type A, type B) { type Diff = A - B; return MagSqr(Diff); }
|
||
|
DistanceSqDef(v2)
|
||
|
DistanceSqDef(v3)
|
||
|
DistanceSqDef(v4)
|
||
|
#undef DistanceSqDef
|
||
|
|
||
|
inline v2
|
||
|
Normalize(
|
||
|
v2 _A
|
||
|
)
|
||
|
{
|
||
|
v2 Result;
|
||
|
|
||
|
float Magnitude = Mag(_A);
|
||
|
|
||
|
Result.x = _A.x / Magnitude;
|
||
|
Result.y = _A.y / Magnitude;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v3
|
||
|
Normalize(
|
||
|
v3 _A
|
||
|
)
|
||
|
{
|
||
|
v3 Result;
|
||
|
|
||
|
float Magnitude = Mag(_A);
|
||
|
|
||
|
Result.x = _A.x / Magnitude;
|
||
|
Result.y = _A.y / Magnitude;
|
||
|
Result.z = _A.z / Magnitude;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v4
|
||
|
Normalize(
|
||
|
v4 _A
|
||
|
)
|
||
|
{
|
||
|
v4 Result;
|
||
|
|
||
|
float Magnitude = Mag(_A);
|
||
|
|
||
|
Result.x = _A.x / Magnitude;
|
||
|
Result.y = _A.y / Magnitude;
|
||
|
Result.z = _A.z / Magnitude;
|
||
|
Result.w = _A.w / Magnitude;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
Dot(
|
||
|
v2 _A,
|
||
|
v2 _B
|
||
|
)
|
||
|
{
|
||
|
float Result = _A.x * _B.x + _A.y * _B.y;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
Dot (
|
||
|
v3 _A,
|
||
|
v3 _B
|
||
|
)
|
||
|
{
|
||
|
float Result = _A.x * _B.x + _A.y * _B.y + _A.z * _B.z;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
Dot (
|
||
|
v4 _A,
|
||
|
v4 _B
|
||
|
)
|
||
|
{
|
||
|
float Result = _A.x * _B.x + _A.y * _B.y + _A.z * _B.z + _A.w * _B.w;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v2
|
||
|
PerpendicularCW (v2 A)
|
||
|
{
|
||
|
v2 Result = v2{A.y, -A.x};
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v2
|
||
|
PerpendicularCCW (v2 A)
|
||
|
{
|
||
|
v2 Result = v2{A.y, A.x};
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v3
|
||
|
Cross(
|
||
|
v3 _A,
|
||
|
v3 _B
|
||
|
)
|
||
|
{
|
||
|
v3 Result = {};
|
||
|
|
||
|
Result.x = (_A.y * _B.z) - (_A.z * _B.y);
|
||
|
Result.y = (_A.z * _B.x) - (_A.x * _B.z);
|
||
|
Result.z = (_A.x * _B.y) - (_A.y * _B.x);
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v4
|
||
|
Cross(
|
||
|
v4 _A,
|
||
|
v4 _B
|
||
|
)
|
||
|
{
|
||
|
v4 Result = {};
|
||
|
|
||
|
Result.x = (_A.y * _B.z) - (_A.z * _B.y);
|
||
|
Result.y = (_A.z * _B.x) - (_A.x * _B.z);
|
||
|
Result.z = (_A.x * _B.y) - (_A.y * _B.x);
|
||
|
Result.w = 0;
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v2
|
||
|
ClampVector01 (v2 V)
|
||
|
{
|
||
|
v2 Result = {};
|
||
|
Result.x = GSClamp(0.0f, V.x, 1.f);
|
||
|
Result.y = GSClamp(0.0f, V.y, 1.f);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v3
|
||
|
ClampVector01 (v3 V)
|
||
|
{
|
||
|
v3 Result = {};
|
||
|
Result.x = GSClamp(0.f, V.x, 1.f);
|
||
|
Result.y = GSClamp(0.f, V.y, 1.f);
|
||
|
Result.z = GSClamp(0.f, V.z, 1.f);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v4
|
||
|
ClampVector01 (v4 V)
|
||
|
{
|
||
|
v4 Result = {};
|
||
|
Result.x = GSClamp(0.f, V.x, 1.f);
|
||
|
Result.y = GSClamp(0.f, V.y, 1.f);
|
||
|
Result.z = GSClamp(0.f, V.z, 1.f);
|
||
|
Result.w = GSClamp(0.f, V.w, 1.f);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v2
|
||
|
Lerp(
|
||
|
v2 _A,
|
||
|
v2 _B,
|
||
|
float _Percent
|
||
|
)
|
||
|
{
|
||
|
v2 Result;
|
||
|
|
||
|
Result.x = GSLerp(_A.x, _B.x, _Percent);
|
||
|
Result.y = GSLerp(_A.y, _B.y, _Percent);
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v3
|
||
|
Lerp(
|
||
|
v3 _A,
|
||
|
v3 _B,
|
||
|
float _Percent
|
||
|
)
|
||
|
{
|
||
|
v3 Result;
|
||
|
|
||
|
Result.x = GSLerp(_A.x, _B.x, _Percent);
|
||
|
Result.y = GSLerp(_A.y, _B.y, _Percent);
|
||
|
Result.z = GSLerp(_A.z, _B.z, _Percent);
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline v4
|
||
|
Lerp(
|
||
|
v4 _A,
|
||
|
v4 _B,
|
||
|
float _Percent
|
||
|
)
|
||
|
{
|
||
|
v4 Result;
|
||
|
|
||
|
Result.x = GSLerp(_A.x, _B.x, _Percent);
|
||
|
Result.y = GSLerp(_A.y, _B.y, _Percent);
|
||
|
Result.z = GSLerp(_A.z, _B.z, _Percent);
|
||
|
Result.w = GSLerp(_A.w, _B.w, _Percent);
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
v4 HSVToRGB (v4 In)
|
||
|
{
|
||
|
float Hue = In.x;
|
||
|
while (Hue > 360.0f) { Hue -= 360.0f; }
|
||
|
while (Hue < 0.0f) { Hue += 360.0f; }
|
||
|
|
||
|
float Sat = In.y;
|
||
|
float Value = In.z;
|
||
|
|
||
|
float hh, p, q, t, ff;
|
||
|
long i;
|
||
|
v4 Result = {};
|
||
|
Result.a = In.a;
|
||
|
|
||
|
if(Sat <= 0.0f) { // < is bogus, just shuts up warnings
|
||
|
Result.r = Value;
|
||
|
Result.g = Value;
|
||
|
Result.b = Value;
|
||
|
return Result;
|
||
|
}
|
||
|
hh = Hue;
|
||
|
if(hh >= 360.0f) hh = 0.0f;
|
||
|
hh /= 60.0f;
|
||
|
i = (long)hh;
|
||
|
ff = hh - i;
|
||
|
p = Value * (1.0f - Sat);
|
||
|
q = Value * (1.0f - (Sat * ff));
|
||
|
t = Value * (1.0f - (Sat * (1.0f - ff)));
|
||
|
|
||
|
switch(i) {
|
||
|
case 0:
|
||
|
{Result.r = Value;
|
||
|
Result.g = t;
|
||
|
Result.b = p;
|
||
|
}break;
|
||
|
|
||
|
case 1:
|
||
|
{
|
||
|
Result.r = q;
|
||
|
Result.g = Value;
|
||
|
Result.b = p;
|
||
|
}break;
|
||
|
|
||
|
case 2:
|
||
|
{
|
||
|
Result.r = p;
|
||
|
Result.g = Value;
|
||
|
Result.b = t;
|
||
|
}break;
|
||
|
|
||
|
case 3:
|
||
|
{
|
||
|
Result.r = p;
|
||
|
Result.g = q;
|
||
|
Result.b = Value;
|
||
|
}break;
|
||
|
|
||
|
case 4:
|
||
|
{
|
||
|
Result.r = t;
|
||
|
Result.g = p;
|
||
|
Result.b = Value;
|
||
|
}break;
|
||
|
|
||
|
case 5:
|
||
|
default:
|
||
|
{
|
||
|
Result.r = Value;
|
||
|
Result.g = p;
|
||
|
Result.b = q;
|
||
|
}break;
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
PointIsInRange (
|
||
|
v2 _P,
|
||
|
v2 _Min, v2 _Max
|
||
|
)
|
||
|
{
|
||
|
return (_P.x >= _Min.x && _P.x <= _Max.x &&
|
||
|
_P.y >= _Min.y && _P.y <= _Max.y);
|
||
|
}
|
||
|
|
||
|
static bool
|
||
|
PointIsInRangeSafe (
|
||
|
v2 _P,
|
||
|
v2 _Min, v2 _Max
|
||
|
)
|
||
|
{
|
||
|
s32 MinX = GSMin(_Min.x, _Max.x);
|
||
|
s32 MinY = GSMin(_Min.y, _Max.y);
|
||
|
s32 MaxX = GSMax(_Min.x, _Max.x);
|
||
|
s32 MaxY = GSMax(_Min.y, _Max.y);
|
||
|
|
||
|
return (_P.x >= MinX && _P.x <= MaxX &&
|
||
|
_P.y >= MinY && _P.y <= MaxY);
|
||
|
}
|
||
|
|
||
|
inline v2
|
||
|
PointToPercentRange (v2 P, v2 Min, v2 Max)
|
||
|
{
|
||
|
v2 Result = {};
|
||
|
|
||
|
Result.x = GSClamp(0.f, (P.x - Min.x) / (Max.x - Min.x), 1.f);
|
||
|
Result.y = GSClamp(0.f, (P.y - Min.y) / (Max.y - Min.y), 1.f);
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////
|
||
|
// RECT
|
||
|
//////////////////////////////////////
|
||
|
|
||
|
inline float
|
||
|
Width (rect Rect)
|
||
|
{
|
||
|
float Result = Rect.Max.x - Rect.Min.x;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
Height (rect Rect)
|
||
|
{
|
||
|
float Result = Rect.Max.y - Rect.Min.y;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline float
|
||
|
AspectRatio (rect Rect)
|
||
|
{
|
||
|
float Result = Width(Rect) / Height(Rect);
|
||
|
return Result;
|
||
|
}
|
||
|
inline v2
|
||
|
CalculateRectCenter (rect Rect)
|
||
|
{
|
||
|
v2 Result = (Rect.Min + Rect.Max) / 2.0f;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline b32
|
||
|
PointIsInRect (v2 Point, rect Rect)
|
||
|
{
|
||
|
b32 Result = ((Point.x >= Rect.Min.x && Point.x <= Rect.Max.x) &&
|
||
|
(Point.y >= Rect.Min.y && Point.y <= Rect.Max.y));
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline rect
|
||
|
RectOffsetByVector(rect R, v2 V)
|
||
|
{
|
||
|
rect Result = R;
|
||
|
Result.Min += V;
|
||
|
Result.Max += V;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////
|
||
|
// MATRIX
|
||
|
//////////////////////////////////////
|
||
|
|
||
|
static m33
|
||
|
M33(float a, float b, float c,
|
||
|
float d, float e, float f,
|
||
|
float g, float h, float i)
|
||
|
{
|
||
|
m33 M = {};
|
||
|
M.a = a; M.b = b; M.c = c;
|
||
|
M.d = d; M.e = e; M.f = f;
|
||
|
M.g = g; M.h = h; M.i = i;
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
M44(float a, float b, float c, float d,
|
||
|
float e, float f, float g, float h,
|
||
|
float i, float j, float k, float l,
|
||
|
float m, float n, float o, float p)
|
||
|
{
|
||
|
m44 M = {};
|
||
|
M.a = a; M.b = b; M.c = c; M.d = d;
|
||
|
M.e = e; M.f = f; M.g = g; M.h = h;
|
||
|
M.i = i; M.j = j; M.k = k; M.l = l;
|
||
|
M.m = m; M.n = n; M.o = o; M.p = p;
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m33
|
||
|
M33Empty ()
|
||
|
{
|
||
|
m33 M = {};
|
||
|
M.a = 0; M.b = 0; M.c = 0;
|
||
|
M.d = 0; M.e = 0; M.f = 0;
|
||
|
M.g = 0; M.h = 0; M.i = 0;
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
M44Empty()
|
||
|
{
|
||
|
m44 M = {};
|
||
|
M.a = 0; M.b = 0; M.c = 0; M.d = 0;
|
||
|
M.e = 0; M.f = 0; M.g = 0; M.h = 0;
|
||
|
M.i = 0; M.j = 0; M.k = 0; M.l = 0;
|
||
|
M.m = 0; M.n = 0; M.o = 0; M.p = 0;
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m33
|
||
|
M33Identity ()
|
||
|
{
|
||
|
m33 M = {};
|
||
|
M.a = 1; M.b = 0; M.c = 0;
|
||
|
M.d = 0; M.e = 1; M.f = 0;
|
||
|
M.g = 0; M.h = 0; M.i = 1;
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
M44Identity()
|
||
|
{
|
||
|
m44 M = {};
|
||
|
M.a = 1; M.b = 0; M.c = 0; M.d = 0;
|
||
|
M.e = 0; M.f = 1; M.g = 0; M.h = 0;
|
||
|
M.i = 0; M.j = 0; M.k = 1; M.l = 0;
|
||
|
M.m = 0; M.n = 0; M.o = 0; M.p = 1;
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
GetXRotation (float Angle)
|
||
|
{
|
||
|
float CosAngle = GSCos(Angle);
|
||
|
float SinAngle = GSSin(Angle);
|
||
|
m44 M = {
|
||
|
1, 0, 0, 0,
|
||
|
0, CosAngle, SinAngle, 0,
|
||
|
0, -SinAngle, CosAngle, 0,
|
||
|
0, 0, 0, 1
|
||
|
};
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
|
||
|
static m44
|
||
|
GetYRotation (float Angle)
|
||
|
{
|
||
|
float CosAngle = GSCos(Angle);
|
||
|
float SinAngle = GSSin(Angle);
|
||
|
m44 M = {
|
||
|
CosAngle, 0, -SinAngle, 0,
|
||
|
0, 1, 0, 0,
|
||
|
SinAngle, 0, CosAngle, 0,
|
||
|
0, 0, 0, 1
|
||
|
};
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
GetZRotation (float Angle)
|
||
|
{
|
||
|
float CosAngle = GSCos(Angle);
|
||
|
float SinAngle = GSSin(Angle);
|
||
|
m44 M = {
|
||
|
CosAngle, SinAngle, 0, 0,
|
||
|
-SinAngle, CosAngle, 0, 0,
|
||
|
0, 0, 1, 0,
|
||
|
0, 0, 0, 1
|
||
|
};
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
|
||
|
static m33
|
||
|
Transpose (m33 M)
|
||
|
{
|
||
|
m33 Result = {};
|
||
|
|
||
|
for (s32 x = 0; x < 3; x++)
|
||
|
{
|
||
|
for (s32 y = 0; y < 3; y++)
|
||
|
{
|
||
|
Result.E[x + (y * 3)] = M.E[y + (x * 3)];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
inline m44
|
||
|
Transpose (m44 M)
|
||
|
{
|
||
|
DEBUG_TRACK_SCOPE(Transpose);
|
||
|
|
||
|
m44 Result = {};
|
||
|
|
||
|
Result.E[0] = M.E[0];
|
||
|
Result.E[1] = M.E[4];
|
||
|
Result.E[2] = M.E[8];
|
||
|
Result.E[3] = M.E[12];
|
||
|
|
||
|
Result.E[4] = M.E[1];
|
||
|
Result.E[5] = M.E[5];
|
||
|
Result.E[6] = M.E[9];
|
||
|
Result.E[7] = M.E[13];
|
||
|
|
||
|
Result.E[8] = M.E[2];
|
||
|
Result.E[9] = M.E[6];
|
||
|
Result.E[10] = M.E[10];
|
||
|
Result.E[11] = M.E[14];
|
||
|
|
||
|
Result.E[12] = M.E[3];
|
||
|
Result.E[13] = M.E[7];
|
||
|
Result.E[14] = M.E[11];
|
||
|
Result.E[15] = M.E[15];
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
GetPositionM44 (v4 Position)
|
||
|
{
|
||
|
#if 1
|
||
|
return m44{
|
||
|
1, 0, 0, 0,
|
||
|
0, 1, 0, 0,
|
||
|
0, 0, 1, 0,
|
||
|
Position.x, Position.y, Position.z, Position.w
|
||
|
};
|
||
|
#else
|
||
|
return m44{
|
||
|
1, 0, 0, Position.x,
|
||
|
0, 1, 0, Position.y,
|
||
|
0, 0, 1, Position.z,
|
||
|
0, 0, 0, Position.w};
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static m44
|
||
|
GetLookAtMatrix (v4 Position, v4 Target)
|
||
|
{
|
||
|
// Forward
|
||
|
v4 Forward = Normalize(Target - Position);
|
||
|
// Right
|
||
|
v4 Right = Normalize(Cross(v4{0, 1, 0, 0}, Forward));
|
||
|
// Up
|
||
|
v4 Up = Normalize(Cross(Forward, Right));
|
||
|
|
||
|
m44 RotationMatrix = M44(
|
||
|
Right.x, Up.x, Forward.x, 0,
|
||
|
Right.y, Up.y, Forward.y, 0,
|
||
|
Right.z, Up.z, Forward.z, 0,
|
||
|
0, 0, 0, 1);
|
||
|
|
||
|
return RotationMatrix;
|
||
|
}
|
||
|
|
||
|
b32 operator== (m33 A, m33 B)
|
||
|
{
|
||
|
b32 Result = true;
|
||
|
for (int e = 0; e < 9; e++) { if (GSAbs(A.E[e] - B.E[e]) > 0.0001f) { Result = false; break; } }
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
b32 operator== (m44 A, m44 B)
|
||
|
{
|
||
|
b32 Result = true;
|
||
|
for (int e = 0; e < 16; e++) { if (GSAbs(A.E[e] - B.E[e]) > 0.0001f) { Result = false; break; } }
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
m33 operator+ (m33 A, m33 B)
|
||
|
{
|
||
|
m33 M = {};
|
||
|
for (int e = 0; e < 9; e++) { M.E[e] = A.E[e] + B.E[e]; }
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
m44 operator+ (m44 A, m44 B)
|
||
|
{
|
||
|
m44 M = {};
|
||
|
for (int e = 0; e < 16; e++) { M.E[e] = A.E[e] + B.E[e]; }
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
m33 operator- (m33 A, m33 B)
|
||
|
{
|
||
|
m33 M = {};
|
||
|
for (int e = 0; e < 9; e++) { M.E[e] = A.E[e] - B.E[e]; }
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
m44 operator- (m44 A, m44 B)
|
||
|
{
|
||
|
m44 M = {};
|
||
|
for (int e = 0; e < 16; e++) { M.E[e] = A.E[e] - B.E[e]; }
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
m33 operator* (m33 A, m33 B)
|
||
|
{
|
||
|
m33 M = {};
|
||
|
for (int rx = 0; rx < 3; rx++)
|
||
|
{
|
||
|
for (int ry = 0; ry < 3; ry++)
|
||
|
{
|
||
|
int RIndex = (ry * 3) + rx;
|
||
|
M.E[RIndex] = 0;
|
||
|
for (int i = 0; i < 3; i++)
|
||
|
{
|
||
|
M.E[RIndex] += B.E[(ry * 3) + i] * A.E[(i * 3) + rx];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
m44 operator* (m44 A, m44 B)
|
||
|
{
|
||
|
m44 M = {};
|
||
|
|
||
|
float A00=A.E[0+4*0];
|
||
|
float A01=A.E[0+4*1];
|
||
|
float A02=A.E[0+4*2];
|
||
|
float A03=A.E[0+4*3];
|
||
|
|
||
|
float A10=A.E[1+4*0];
|
||
|
float A11=A.E[1+4*1];
|
||
|
float A12=A.E[1+4*2];
|
||
|
float A13=A.E[1+4*3];
|
||
|
|
||
|
float A20=A.E[2+4*0];
|
||
|
float A21=A.E[2+4*1];
|
||
|
float A22=A.E[2+4*2];
|
||
|
float A23=A.E[2+4*3];
|
||
|
|
||
|
float A30=A.E[3+4*0];
|
||
|
float A31=A.E[3+4*1];
|
||
|
float A32=A.E[3+4*2];
|
||
|
float A33=A.E[3+4*3];
|
||
|
|
||
|
float B00=B.E[0+4*0];
|
||
|
float B01=B.E[0+4*1];
|
||
|
float B02=B.E[0+4*2];
|
||
|
float B03=B.E[0+4*3];
|
||
|
|
||
|
float B10=B.E[1+4*0];
|
||
|
float B11=B.E[1+4*1];
|
||
|
float B12=B.E[1+4*2];
|
||
|
float B13=B.E[1+4*3];
|
||
|
|
||
|
float B20=B.E[2+4*0];
|
||
|
float B21=B.E[2+4*1];
|
||
|
float B22=B.E[2+4*2];
|
||
|
float B23=B.E[2+4*3];
|
||
|
|
||
|
float B30=B.E[3+4*0];
|
||
|
float B31=B.E[3+4*1];
|
||
|
float B32=B.E[3+4*2];
|
||
|
float B33=B.E[3+4*3];
|
||
|
|
||
|
M.E[0+4*0] = A00*B00+A10*B01+A20*B02+A30*B03;
|
||
|
M.E[0+4*1] = A01*B00+A11*B01+A21*B02+A31*B03;
|
||
|
M.E[0+4*2] = A02*B00+A12*B01+A22*B02+A32*B03;
|
||
|
M.E[0+4*3] = A03*B00+A13*B01+A23*B02+A33*B03;
|
||
|
|
||
|
M.E[1+4*0] = A00*B10+A10*B11+A20*B12+A30*B13;
|
||
|
M.E[1+4*1] = A01*B10+A11*B11+A21*B12+A31*B13;
|
||
|
M.E[1+4*2] = A02*B10+A12*B11+A22*B12+A32*B13;
|
||
|
M.E[1+4*3] = A03*B10+A13*B11+A23*B12+A33*B13;
|
||
|
|
||
|
M.E[2+4*0] = A00*B20+A10*B21+A20*B22+A30*B23;
|
||
|
M.E[2+4*1] = A01*B20+A11*B21+A21*B22+A31*B23;
|
||
|
M.E[2+4*2] = A02*B20+A12*B21+A22*B22+A32*B23;
|
||
|
M.E[2+4*3] = A03*B20+A13*B21+A23*B22+A33*B23;
|
||
|
|
||
|
M.E[3+4*0] = A00*B30+A10*B31+A20*B32+A30*B33;
|
||
|
M.E[3+4*1] = A01*B30+A11*B31+A21*B32+A31*B33;
|
||
|
M.E[3+4*2] = A02*B30+A12*B31+A22*B32+A32*B33;
|
||
|
M.E[3+4*3] = A03*B30+A13*B31+A23*B32+A33*B33;
|
||
|
|
||
|
return M;
|
||
|
}
|
||
|
|
||
|
v3 operator* (m33 M, v3 V)
|
||
|
{
|
||
|
v3 Result = {};
|
||
|
int i = 0;
|
||
|
for (int y = 0; y < 3; y++)
|
||
|
{
|
||
|
Result.E[y] = 0;
|
||
|
for (int x = 0; x < 3; x++)
|
||
|
{
|
||
|
Result.E[y] += M.E[(y * 3) + x] * V.E[x];
|
||
|
}
|
||
|
}
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
v4 operator* (m44 M, v4 V)
|
||
|
{
|
||
|
v4 Result = {};
|
||
|
#if 1
|
||
|
Result.x = V.x*M.a + V.y*M.e + V.z*M.i + V.w*M.m;
|
||
|
Result.y = V.x*M.b + V.y*M.f + V.z*M.j + V.w*M.n;
|
||
|
Result.z = V.x*M.c + V.y*M.g + V.z*M.k + V.w*M.o;
|
||
|
Result.w = V.x*M.d + V.y*M.h + V.z*M.l + V.w*M.p;
|
||
|
#else
|
||
|
for (int y = 0; y < 4; y++)
|
||
|
{
|
||
|
Result.E[y] = 0;
|
||
|
for (int x = 0; x < 4; x++)
|
||
|
{
|
||
|
Result.E[y] += M.E[(y * 4) + x] * V.E[x];
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
b32 Inverse(m44 M_In, m44* M_Out)
|
||
|
{
|
||
|
b32 Result = false;
|
||
|
|
||
|
float det;
|
||
|
s32 i;
|
||
|
|
||
|
|
||
|
M_Out->E[0] = M_In.E[5] * M_In.E[10] * M_In.E[15] -
|
||
|
M_In.E[5] * M_In.E[11] * M_In.E[14] -
|
||
|
M_In.E[9] * M_In.E[6] * M_In.E[15] +
|
||
|
M_In.E[9] * M_In.E[7] * M_In.E[14] +
|
||
|
M_In.E[13] * M_In.E[6] * M_In.E[11] -
|
||
|
M_In.E[13] * M_In.E[7] * M_In.E[10];
|
||
|
|
||
|
M_Out->E[4] = -M_In.E[4] * M_In.E[10] * M_In.E[15] +
|
||
|
M_In.E[4] * M_In.E[11] * M_In.E[14] +
|
||
|
M_In.E[8] * M_In.E[6] * M_In.E[15] -
|
||
|
M_In.E[8] * M_In.E[7] * M_In.E[14] -
|
||
|
M_In.E[12] * M_In.E[6] * M_In.E[11] +
|
||
|
M_In.E[12] * M_In.E[7] * M_In.E[10];
|
||
|
|
||
|
M_Out->E[8] = M_In.E[4] * M_In.E[9] * M_In.E[15] -
|
||
|
M_In.E[4] * M_In.E[11] * M_In.E[13] -
|
||
|
M_In.E[8] * M_In.E[5] * M_In.E[15] +
|
||
|
M_In.E[8] * M_In.E[7] * M_In.E[13] +
|
||
|
M_In.E[12] * M_In.E[5] * M_In.E[11] -
|
||
|
M_In.E[12] * M_In.E[7] * M_In.E[9];
|
||
|
|
||
|
M_Out->E[12] = -M_In.E[4] * M_In.E[9] * M_In.E[14] +
|
||
|
M_In.E[4] * M_In.E[10] * M_In.E[13] +
|
||
|
M_In.E[8] * M_In.E[5] * M_In.E[14] -
|
||
|
M_In.E[8] * M_In.E[6] * M_In.E[13] -
|
||
|
M_In.E[12] * M_In.E[5] * M_In.E[10] +
|
||
|
M_In.E[12] * M_In.E[6] * M_In.E[9];
|
||
|
|
||
|
M_Out->E[1] = -M_In.E[1] * M_In.E[10] * M_In.E[15] +
|
||
|
M_In.E[1] * M_In.E[11] * M_In.E[14] +
|
||
|
M_In.E[9] * M_In.E[2] * M_In.E[15] -
|
||
|
M_In.E[9] * M_In.E[3] * M_In.E[14] -
|
||
|
M_In.E[13] * M_In.E[2] * M_In.E[11] +
|
||
|
M_In.E[13] * M_In.E[3] * M_In.E[10];
|
||
|
|
||
|
M_Out->E[5] = M_In.E[0] * M_In.E[10] * M_In.E[15] -
|
||
|
M_In.E[0] * M_In.E[11] * M_In.E[14] -
|
||
|
M_In.E[8] * M_In.E[2] * M_In.E[15] +
|
||
|
M_In.E[8] * M_In.E[3] * M_In.E[14] +
|
||
|
M_In.E[12] * M_In.E[2] * M_In.E[11] -
|
||
|
M_In.E[12] * M_In.E[3] * M_In.E[10];
|
||
|
|
||
|
M_Out->E[9] = -M_In.E[0] * M_In.E[9] * M_In.E[15] +
|
||
|
M_In.E[0] * M_In.E[11] * M_In.E[13] +
|
||
|
M_In.E[8] * M_In.E[1] * M_In.E[15] -
|
||
|
M_In.E[8] * M_In.E[3] * M_In.E[13] -
|
||
|
M_In.E[12] * M_In.E[1] * M_In.E[11] +
|
||
|
M_In.E[12] * M_In.E[3] * M_In.E[9];
|
||
|
|
||
|
M_Out->E[13] = M_In.E[0] * M_In.E[9] * M_In.E[14] -
|
||
|
M_In.E[0] * M_In.E[10] * M_In.E[13] -
|
||
|
M_In.E[8] * M_In.E[1] * M_In.E[14] +
|
||
|
M_In.E[8] * M_In.E[2] * M_In.E[13] +
|
||
|
M_In.E[12] * M_In.E[1] * M_In.E[10] -
|
||
|
M_In.E[12] * M_In.E[2] * M_In.E[9];
|
||
|
|
||
|
M_Out->E[2] = M_In.E[1] * M_In.E[6] * M_In.E[15] -
|
||
|
M_In.E[1] * M_In.E[7] * M_In.E[14] -
|
||
|
M_In.E[5] * M_In.E[2] * M_In.E[15] +
|
||
|
M_In.E[5] * M_In.E[3] * M_In.E[14] +
|
||
|
M_In.E[13] * M_In.E[2] * M_In.E[7] -
|
||
|
M_In.E[13] * M_In.E[3] * M_In.E[6];
|
||
|
|
||
|
M_Out->E[6] = -M_In.E[0] * M_In.E[6] * M_In.E[15] +
|
||
|
M_In.E[0] * M_In.E[7] * M_In.E[14] +
|
||
|
M_In.E[4] * M_In.E[2] * M_In.E[15] -
|
||
|
M_In.E[4] * M_In.E[3] * M_In.E[14] -
|
||
|
M_In.E[12] * M_In.E[2] * M_In.E[7] +
|
||
|
M_In.E[12] * M_In.E[3] * M_In.E[6];
|
||
|
|
||
|
M_Out->E[10] = M_In.E[0] * M_In.E[5] * M_In.E[15] -
|
||
|
M_In.E[0] * M_In.E[7] * M_In.E[13] -
|
||
|
M_In.E[4] * M_In.E[1] * M_In.E[15] +
|
||
|
M_In.E[4] * M_In.E[3] * M_In.E[13] +
|
||
|
M_In.E[12] * M_In.E[1] * M_In.E[7] -
|
||
|
M_In.E[12] * M_In.E[3] * M_In.E[5];
|
||
|
|
||
|
M_Out->E[14] = -M_In.E[0] * M_In.E[5] * M_In.E[14] +
|
||
|
M_In.E[0] * M_In.E[6] * M_In.E[13] +
|
||
|
M_In.E[4] * M_In.E[1] * M_In.E[14] -
|
||
|
M_In.E[4] * M_In.E[2] * M_In.E[13] -
|
||
|
M_In.E[12] * M_In.E[1] * M_In.E[6] +
|
||
|
M_In.E[12] * M_In.E[2] * M_In.E[5];
|
||
|
|
||
|
M_Out->E[3] = -M_In.E[1] * M_In.E[6] * M_In.E[11] +
|
||
|
M_In.E[1] * M_In.E[7] * M_In.E[10] +
|
||
|
M_In.E[5] * M_In.E[2] * M_In.E[11] -
|
||
|
M_In.E[5] * M_In.E[3] * M_In.E[10] -
|
||
|
M_In.E[9] * M_In.E[2] * M_In.E[7] +
|
||
|
M_In.E[9] * M_In.E[3] * M_In.E[6];
|
||
|
|
||
|
M_Out->E[7] = M_In.E[0] * M_In.E[6] * M_In.E[11] -
|
||
|
M_In.E[0] * M_In.E[7] * M_In.E[10] -
|
||
|
M_In.E[4] * M_In.E[2] * M_In.E[11] +
|
||
|
M_In.E[4] * M_In.E[3] * M_In.E[10] +
|
||
|
M_In.E[8] * M_In.E[2] * M_In.E[7] -
|
||
|
M_In.E[8] * M_In.E[3] * M_In.E[6];
|
||
|
|
||
|
M_Out->E[11] = -M_In.E[0] * M_In.E[5] * M_In.E[11] +
|
||
|
M_In.E[0] * M_In.E[7] * M_In.E[9] +
|
||
|
M_In.E[4] * M_In.E[1] * M_In.E[11] -
|
||
|
M_In.E[4] * M_In.E[3] * M_In.E[9] -
|
||
|
M_In.E[8] * M_In.E[1] * M_In.E[7] +
|
||
|
M_In.E[8] * M_In.E[3] * M_In.E[5];
|
||
|
|
||
|
M_Out->E[15] = M_In.E[0] * M_In.E[5] * M_In.E[10] -
|
||
|
M_In.E[0] * M_In.E[6] * M_In.E[9] -
|
||
|
M_In.E[4] * M_In.E[1] * M_In.E[10] +
|
||
|
M_In.E[4] * M_In.E[2] * M_In.E[9] +
|
||
|
M_In.E[8] * M_In.E[1] * M_In.E[6] -
|
||
|
M_In.E[8] * M_In.E[2] * M_In.E[5];
|
||
|
|
||
|
det = M_In.E[0] * M_Out->E[0] + M_In.E[1] * M_Out->E[4] + M_In.E[2] * M_Out->E[8] + M_In.E[3] * M_Out->E[12];
|
||
|
|
||
|
if (det == 0)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
det = 1.0 / det;
|
||
|
|
||
|
for (i = 0; i < 16; i++)
|
||
|
{
|
||
|
M_Out->E[i] = M_Out->E[i] * det;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#if defined(VECTOR_MATRIX_TEST_SUITE)
|
||
|
|
||
|
void TestVectorMatrixMultiplication ()
|
||
|
{
|
||
|
s32 TestCount = 0;
|
||
|
s32 SuccessCount = 0;
|
||
|
|
||
|
DebugPrint("\n\n-------------------------------------------------\n Begin Testing Vector/Matrix\n\n\n");
|
||
|
|
||
|
// Utility Functions
|
||
|
TestClean((GSSqrt(4.f) == 2.f), "Vector Square Root");
|
||
|
TestClean((GSLerp(0.f, 1.f, .5f) == .5f), "Vector Lerp");
|
||
|
TestClean((GSMin(-.25f, 5.f) == -.25f), "Vector Min");
|
||
|
TestClean((GSMax(-.25f, 5.f) == 5.f), "Vector Max");
|
||
|
TestClean((GSClamp(-2.f, -3.f, 5.f) == -2.f), "Vector Clamp, Lower Than Range");
|
||
|
TestClean((GSClamp(-2.f, 6.f, 5.f) == 5.f), "Vector Clamp, Higher Than Range");
|
||
|
|
||
|
//////////////////////////////
|
||
|
// Vector Functions
|
||
|
/////////////////////////////
|
||
|
|
||
|
v2 V2Unit = v2{1, 0};
|
||
|
v3 V3Unit = v3{1, 0, 0};
|
||
|
v4 V4Unit = v4{1, 0, 0, 0};
|
||
|
|
||
|
v2 TestV2 = v2{1, 2};
|
||
|
float TestV2MagSq = (TestV2.x * TestV2.x) + (TestV2.y * TestV2.y);
|
||
|
float TestV2Mag = GSSqrt(TestV2MagSq);
|
||
|
v2 TestV2Norm = v2{TestV2.x / TestV2Mag, TestV2.y / TestV2Mag};
|
||
|
float TestV2DotR = (TestV2.x * V2Unit.x) + (TestV2.y * V2Unit.y);
|
||
|
|
||
|
v3 TestV3 = v3{1, 2, 3};
|
||
|
float TestV3MagSq = (TestV3.x * TestV3.x) + (TestV3.y * TestV3.y) + (TestV3.z * TestV3.z);
|
||
|
float TestV3Mag = GSSqrt(TestV3MagSq);
|
||
|
v3 TestV3Norm = v3{TestV3.x / TestV3Mag, TestV3.y / TestV3Mag, TestV3.z / TestV3Mag};
|
||
|
float TestV3DotR = (TestV3.x * V3Unit.x) + (TestV3.y * V3Unit.y) + (TestV3.z * V3Unit.z);
|
||
|
|
||
|
v4 TestV4 = v4{1, 2, 3, 4};
|
||
|
float TestV4MagSq = (TestV4.x * TestV4.x) + (TestV4.y * TestV4.y) + (TestV4.z * TestV4.z) + (TestV4.w * TestV4.w);
|
||
|
float TestV4Mag = GSSqrt(TestV4MagSq);
|
||
|
v4 TestV4Norm = v4{
|
||
|
TestV4.x / TestV4Mag, TestV4.y / TestV4Mag, TestV4.z / TestV4Mag, TestV4.w / TestV4Mag
|
||
|
};
|
||
|
float TestV4DotR = (TestV4.x * V4Unit.x) + (TestV4.y * V4Unit.y) + (TestV4.z * V4Unit.z) + (TestV4.w * V4Unit.w);
|
||
|
|
||
|
v2 DownCastV3 = V2(TestV3);
|
||
|
v3 DownCastV4 = V3(TestV4);
|
||
|
|
||
|
v2 EqualityV2 = v2{TestV2.x, TestV2.y};
|
||
|
v2 ZeroV2 = v2{0, 0};
|
||
|
v3 EqualityV3 = v3{TestV3.x, TestV3.y, TestV3.z};
|
||
|
v3 ZeroV3 = v3{0, 0, 0};
|
||
|
v4 EqualityV4 = v4{TestV4.x, TestV4.y, TestV4.z, TestV4.w};
|
||
|
v4 ZeroV4 = v4{0, 0, 0, 0};
|
||
|
|
||
|
TestClean((TestV2.x == 1 && TestV2.y == 2), "V2 Assignment");
|
||
|
TestClean((TestV3.x == 1 && TestV3.y == 2 && TestV3.z == 3), "V3 Assignment");
|
||
|
TestClean((TestV4.x == 1 && TestV4.y == 2 && TestV4.z == 3 && TestV4.w == 4), "V3 Assignment");
|
||
|
|
||
|
TestClean((DownCastV3.x == 1 && DownCastV3.y == 2), "V3 -> V2 Downcast");
|
||
|
TestClean((DownCastV4.x == 1 && DownCastV4.y == 2 && DownCastV4.z == 3), "V4 -> V3 Downcast");
|
||
|
|
||
|
// Vector Operators
|
||
|
|
||
|
TestClean((TestV2 == EqualityV2 && !(TestV2 == ZeroV2)), "V2 Equality");
|
||
|
TestClean((TestV3 == EqualityV3 && !(TestV3 == ZeroV3)), "V3 Equality");
|
||
|
TestClean((TestV4 == EqualityV4 && !(TestV4 == ZeroV4)), "V4 Equality");
|
||
|
|
||
|
TestClean(((TestV2 - TestV2) == ZeroV2), "V2 Subtraction");
|
||
|
TestClean(((TestV3 - TestV3) == ZeroV3), "V3 Subtraction");
|
||
|
TestClean(((TestV4 - TestV4) == ZeroV4), "V4 Subtraction");
|
||
|
|
||
|
TestClean(((TestV2 + TestV2) == v2{TestV2.x * 2, TestV2.y * 2}), "V2 Addition");
|
||
|
TestClean(((TestV3 + TestV3) == v3{TestV3.x * 2, TestV3.y * 2, TestV3.z * 2}), "V3 Addition");
|
||
|
TestClean(((TestV4 + TestV4) == v4{TestV4.x * 2, TestV4.y * 2, TestV4.z * 2, TestV4.w * 2}), "V4 Addition");
|
||
|
|
||
|
TestClean(((TestV2 * 2.0f) == v2{TestV2.x * 2, TestV2.y * 2}), "V2 Multiplication");
|
||
|
TestClean(((TestV3 * 2.0f) == v3{TestV3.x * 2, TestV3.y * 2, TestV3.z * 2}), "V3 Multiplication");
|
||
|
TestClean(((TestV4 * 2.0f) == v4{TestV4.x * 2, TestV4.y * 2, TestV4.z * 2, TestV4.w * 2}), "V4 Multiplication");
|
||
|
|
||
|
TestClean(((TestV2 * TestV2) == v2{TestV2.x * TestV2.x, TestV2.y * TestV2.y}), "V2 Piecewise Mult");
|
||
|
TestClean(((TestV3 * TestV3) == v3{
|
||
|
TestV3.x * TestV3.x,
|
||
|
TestV3.y * TestV3.y,
|
||
|
TestV3.z * TestV3.z}), "V3 Piecewise Mult");
|
||
|
TestClean(((TestV4 * TestV4) == v4{
|
||
|
TestV4.x * TestV4.x,
|
||
|
TestV4.y * TestV4.y,
|
||
|
TestV4.z * TestV4.z,
|
||
|
TestV4.w * TestV4.w}), "V4 Piecewise Mult");
|
||
|
|
||
|
|
||
|
TestClean(((TestV2 / 2.0f) == v2{TestV2.x / 2, TestV2.y / 2}), "V2 Division");
|
||
|
TestClean(((TestV3 / 2.0f) == v3{TestV3.x / 2, TestV3.y / 2, TestV3.z / 2}), "V3 Division");
|
||
|
TestClean(((TestV4 / 2.0f) == v4{TestV4.x / 2, TestV4.y / 2, TestV4.z / 2, TestV4.w / 2}), "V4 Division");
|
||
|
|
||
|
TestClean(((TestV2 / TestV2) == v2{TestV2.x / TestV2.x, TestV2.y / TestV2.y}), "V2 Piecewise Div");
|
||
|
TestClean(((TestV3 / TestV3) == v3{
|
||
|
TestV3.x / TestV3.x,
|
||
|
TestV3.y / TestV3.y,
|
||
|
TestV3.z / TestV3.z}), "V3 Piecewise Div");
|
||
|
TestClean(((TestV4 / TestV4) == v4{
|
||
|
TestV4.x / TestV4.x,
|
||
|
TestV4.y / TestV4.y,
|
||
|
TestV4.z / TestV4.z,
|
||
|
TestV4.w / TestV4.w}), "V4 Piecewise Div");
|
||
|
|
||
|
TestClean(((MagSqr(V2Unit) == 1) && (MagSqr(TestV2) == TestV2MagSq)), "V2 Square Mag");
|
||
|
TestClean(((MagSqr(V3Unit) == 1) && (MagSqr(TestV3) == TestV3MagSq)), "V3 Square Mag");
|
||
|
TestClean(((MagSqr(V4Unit) == 1) && (MagSqr(TestV4) == TestV4MagSq)), "V4 Square Mag");
|
||
|
TestClean(((Mag(V2Unit) == 1) && (Mag(TestV2) == TestV2Mag)), "V2 Mag");
|
||
|
TestClean(((Mag(V3Unit) == 1) && (Mag(TestV3) == TestV3Mag)), "V3 Mag");
|
||
|
TestClean(((Mag(V4Unit) == 1) && (Mag(TestV4) == TestV4Mag)), "V4 Mag");
|
||
|
|
||
|
TestClean((DistanceSq(ZeroV2, TestV2) == TestV2MagSq), "V2 Distance Sq");
|
||
|
TestClean((DistanceSq(ZeroV3, TestV3) == TestV3MagSq), "V3 Distance Sq");
|
||
|
TestClean((DistanceSq(ZeroV4, TestV4) == TestV4MagSq), "V4 Distance Sq");
|
||
|
TestClean((Distance(ZeroV2, TestV2) == TestV2Mag), "V2 Distance");
|
||
|
TestClean((Distance(ZeroV3, TestV3) == TestV3Mag), "V3 Distance");
|
||
|
TestClean((Distance(ZeroV4, TestV4) == TestV4Mag), "V4 Distance");
|
||
|
|
||
|
TestClean((Normalize(TestV2) == TestV2Norm), "V2 Normalize");
|
||
|
TestClean((Normalize(TestV3) == TestV3Norm), "V3 Normalize");
|
||
|
TestClean((Normalize(TestV4) == TestV4Norm), "V4 Normalize");
|
||
|
|
||
|
TestClean(((Dot(V2Unit, V2Unit) == 1) && (Dot(TestV2, V2Unit) == TestV2DotR)), "V2 Dot");
|
||
|
TestClean(((Dot(V3Unit, V3Unit) == 1) && (Dot(TestV3, V3Unit) == TestV3DotR)), "V3 Dot");
|
||
|
TestClean(((Dot(V4Unit, V4Unit) == 1) && (Dot(TestV4, V4Unit) == TestV4DotR)), "V4 Dot");
|
||
|
|
||
|
// Skipping Cross For Now
|
||
|
|
||
|
TestClean((Lerp(v2{0, 0}, v2{1, 1}, .5f) == v2{.5f, .5f}), "V2 Lerp");
|
||
|
TestClean((Lerp(v3{0, 0, 0}, v3{1, 1, 1}, .5f) == v3{.5f, .5f, .5f}), "V3 Lerp");
|
||
|
TestClean((Lerp(v4{0, 0, 0, 0}, v4{1, 1, 1, 1}, .5f) == v4{.5f, .5f, .5f, .5f}), "V4 Lerp");
|
||
|
|
||
|
/////////////////////////////
|
||
|
// Matrix
|
||
|
////////////////////////////
|
||
|
|
||
|
m33 TestM33 = m33{
|
||
|
0, 1, 2,
|
||
|
3, 4, 5,
|
||
|
6, 7, 8};
|
||
|
|
||
|
m33 EqualityM33 = {};
|
||
|
for (s32 i = 0; i < 16; i++) { EqualityM33.E[i] = TestM33.E[i]; }
|
||
|
|
||
|
m33 TransposeM33 = m33{
|
||
|
0, 3, 6,
|
||
|
1, 4, 7,
|
||
|
2, 5, 8};
|
||
|
|
||
|
m33 IdentityM33 = m33{
|
||
|
1, 0, 0,
|
||
|
0, 1, 0,
|
||
|
0, 0, 1};
|
||
|
|
||
|
m33 TestM33Squared = m33{
|
||
|
15, 18, 21,
|
||
|
42, 54, 66,
|
||
|
69, 90, 111
|
||
|
};
|
||
|
|
||
|
m44 TestM44 = m44{
|
||
|
0, 1, 2, 3,
|
||
|
4, 5, 6, 7,
|
||
|
8, 9, 10, 11,
|
||
|
12, 13, 14, 15
|
||
|
};
|
||
|
|
||
|
m44 EqualityM44 = {};
|
||
|
for (s32 i = 0; i < 16; i++) { EqualityM44.E[i] = TestM44.E[i]; }
|
||
|
|
||
|
m44 TransposeM44 = m44{
|
||
|
0, 4, 8, 12,
|
||
|
1, 5, 9, 13,
|
||
|
2, 6, 10, 14,
|
||
|
3, 7, 11, 15
|
||
|
};
|
||
|
|
||
|
m44 IdentityM44 = m44{
|
||
|
1, 0, 0, 0,
|
||
|
0, 1, 0, 0,
|
||
|
0, 0, 1, 0,
|
||
|
0, 0, 0, 1
|
||
|
};
|
||
|
|
||
|
m44 TestM44Squared = m44{
|
||
|
56, 62, 68, 74,
|
||
|
152, 174, 196, 218,
|
||
|
248, 286, 324, 362,
|
||
|
344, 398, 452, 506,
|
||
|
};
|
||
|
|
||
|
TestClean(((IdentityM33 == IdentityM33) && (TestM33 == EqualityM33)), "M33 Equality");
|
||
|
TestClean(((IdentityM44 == IdentityM44) && (TestM44 == EqualityM44)), "M44 Equality");
|
||
|
|
||
|
TestClean(((Transpose(IdentityM33) == IdentityM33) &&
|
||
|
(Transpose(TestM33) == TransposeM33)), "M33 Transpose");
|
||
|
TestClean(((Transpose(IdentityM44) == IdentityM44) &&
|
||
|
(Transpose(TestM44) == TransposeM44)), "M44 Transpose");
|
||
|
|
||
|
TestClean(((TestM33 * IdentityM33) == TestM33), "M33 Identity Mult");
|
||
|
TestClean(((TestM44 * IdentityM44) == TestM44), "M44 Identity Mult");
|
||
|
TestClean(((TestM33 * TestM33) == TestM33Squared), "M33 Mult");
|
||
|
TestClean(((TestM44 * TestM44) == TestM44Squared), "M44 Mult");
|
||
|
|
||
|
|
||
|
// Useful Tests
|
||
|
v4 Right = v4{1, 0, 0, 0};
|
||
|
v4 Forward = v4{0, 0, 1, 0};
|
||
|
v4 Up = v4{0, 1, 0, 0};
|
||
|
v4 Left = v4{-1, 0, 0, 0};
|
||
|
v4 Back = v4{0, 0, -1, 0};
|
||
|
v4 Down = v4{0, -1, 0, 0};
|
||
|
|
||
|
m44 NinetyDegreesAboutX = GetXRotation(M_PI / 2);
|
||
|
v4 Rotated = NinetyDegreesAboutX * Forward;
|
||
|
TestClean((Rotated == Up), "Rotation About X");
|
||
|
|
||
|
m44 NinetyDegreesAboutY = GetYRotation(M_PI / 2);
|
||
|
Rotated = NinetyDegreesAboutY * Right;
|
||
|
TestClean((Rotated == Forward), "Rotation About Y");
|
||
|
|
||
|
m44 NinetyDegreesAboutZ = GetZRotation(M_PI / 2);
|
||
|
Rotated = NinetyDegreesAboutZ * Right;
|
||
|
TestClean((Rotated == Down), "Rotation About Z");
|
||
|
|
||
|
|
||
|
v4 A = v4{1, 2, 3, 4};
|
||
|
m44 B = m44{
|
||
|
1, 2, 3, 4,
|
||
|
5, 6, 7, 8,
|
||
|
9, 1, 2, 3,
|
||
|
4, 5, 6, 7};
|
||
|
v4 VTest = v4{30, 70, 29, 60};
|
||
|
TestClean(((B * A) == VTest), "V4 M44 Multiplication");
|
||
|
|
||
|
m44 C = m44{
|
||
|
9, 8, 7, 6,
|
||
|
5, 4, 3, 2,
|
||
|
1, 0, 9, 8,
|
||
|
7, 6, 5, 4
|
||
|
};
|
||
|
m44 MResult = B * C;
|
||
|
m44 MTest = m44{
|
||
|
50, 40, 60, 50,
|
||
|
138, 112, 156, 130,
|
||
|
109, 94, 99, 84,
|
||
|
116, 94, 132, 110
|
||
|
};
|
||
|
TestClean(((B * C) == MTest), "M44 Mult Test 2");
|
||
|
|
||
|
m44 Identity = M44Identity();
|
||
|
m44 InvIdentity = {};
|
||
|
Inverse(Identity, &InvIdentity);
|
||
|
TestClean((Identity == InvIdentity), "Inverse Identity");
|
||
|
|
||
|
m44 Test = m44{
|
||
|
2, 4, 6, 7,
|
||
|
5, 1, 8, 8,
|
||
|
1, 7, 3, 1,
|
||
|
3, 9, 2, 4
|
||
|
};
|
||
|
m44 PreCalcTestInv = m44{
|
||
|
-0.3904761904761904762f, 0.26190476190476190475f, -0.02857142857142857139f, 0.16666666666666666668f,
|
||
|
0.022222222222222222212f, -0.055555555555555555549f, 0.06666666666666666667f, 0.055555555555555555547f,
|
||
|
-0.00317460317460317458f, 0.07936507936507936506f, 0.27619047619047619045f, -0.2222222222222222222f,
|
||
|
0.24444444444444444444f, -0.1111111111111111111f, -0.26666666666666666667f, 0.1111111111111111111f
|
||
|
};
|
||
|
m44 InvTest = {};
|
||
|
Inverse(Test, &InvTest);
|
||
|
//TestClean((PreCalcTestInv == InvTest), "Inverse M44");
|
||
|
|
||
|
DebugPrint("Results: Passed %d / %d\n\n\no", SuccessCount, TestCount);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#define GS_VECTOR_MATRIX_H
|
||
|
#endif
|