#ifndef GS_VECTOR_MATRIX_H #ifndef GS_LANGUAGE_H #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) #include #include #include 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 #endif // Platforms #endif // GS_LANGUAGE_H ////////////////////////////////////// // VECTOR ///////////////////////////////////// union v2 { struct { r32 x, y; }; r32 E[2]; }; union v3 { struct { r32 x, y, z; }; struct { r32 R, G, B; }; r32 E[3]; }; union v4 { struct { r32 x, y, z, w; }; struct { r32 r, g, b, a; }; r32 E[4]; }; ////////////////////////////////////// // MATRIX ///////////////////////////////////// union m33 { struct { float a, b, c; float d, e, f; float g, h, i; }; float E[9]; }; union m44 { struct { float a, b, c, d; float e, f, g, h; float i, j, k, l; float m, n, o, p; }; float E[16]; }; ////////////////////////////////////// // RECT ///////////////////////////////////// struct rect { v2 LowerLeft; v2 UpperRight; }; ////////////////////////////////////// // VECTOR ////////////////////////////////////// // // // Operators // // v2 V2 (v3 V) { return v2{V.x, V.y}; } v3 V3 (v2 XY, r32 Z) { return v3{XY.x, XY.y, Z}; } v3 V3 (v4 V) { return v3{V.x, V.y, V.z}; } v4 V4 (v3 XYZ, r32 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 V2OpScalarDef(op) v2 operator##op (v2 A, r32 B) { return v2{ A.x op B, A.y op B };} #define V3OpScalarDef(op) v3 operator##op (v3 A, r32 B) { return v3{ A.x op B, A.y op B, A.z op B };} #define V4OpScalarDef(op) v4 operator##op (v4 A, r32 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, r32 B) { return v2{ A->x op B, A->y op B };} #define V3POpScalarDef(op) v3 operator##op (v3* A, r32 B) { return v3{ A->x op B, A->y op B, A->z op B };} #define V4POpScalarDef(op) v4 operator##op (v4* A, r32 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, r32 W) { v4 R = {}; R.x = V.x; R.y = V.y; R.z = V.z; R.w = W; return R; } inline r32 MagSqr( v2 _A ) { r32 Result = (_A.x * _A.x) + (_A.y * _A.y); return Result; } inline r32 MagSqr( v3 _A ) { r32 Result = (_A.x * _A.x) + (_A.y * _A.y) + (_A.z * _A.z); return Result; } inline r32 MagSqr( v4 _A ) { r32 Result = (_A.x * _A.x) + (_A.y * _A.y) + (_A.z * _A.z) + (_A.w * _A.w); return Result; } #define MagDef(type) inline r32 Mag(type A) { r32 Result = MagSqr(A); return GSSqrt(Result); } MagDef(v2) MagDef(v3) MagDef(v4) #undef MagDef #define DistanceDef(type) inline r32 Distance (type A, type B) { type Diff = A - B; return Mag(Diff); } DistanceDef(v2) DistanceDef(v3) DistanceDef(v4) #undef DistanceDef #define DistanceSqDef(type) inline r32 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; r32 Magnitude = Mag(_A); Result.x = _A.x / Magnitude; Result.y = _A.y / Magnitude; return Result; } inline v3 Normalize( v3 _A ) { v3 Result; r32 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; r32 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 r32 Dot( v2 _A, v2 _B ) { r32 Result = _A.x * _B.x + _A.y * _B.y; return Result; } inline r32 Dot ( v3 _A, v3 _B ) { r32 Result = _A.x * _B.x + _A.y * _B.y + _A.z * _B.z; return Result; } inline r32 Dot ( v4 _A, v4 _B ) { r32 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, r32 _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, r32 _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, r32 _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) { r32 Hue = In.x; while (Hue > 360.0f) { Hue -= 360.0f; } while (Hue < 0.0f) { Hue += 360.0f; } r32 Sat = In.y; r32 Value = In.z; r32 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); } 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; } ////////////////////////////////////// // MATRIX ////////////////////////////////////// static m33 M33(r32 a, r32 b, r32 c, r32 d, r32 e, r32 f, r32 g, r32 h, r32 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(r32 a, r32 b, r32 c, r32 d, r32 e, r32 f, r32 g, r32 h, r32 i, r32 j, r32 k, r32 l, r32 m, r32 n, r32 o, r32 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 (r32 Angle) { r32 CosAngle = GSCos(Angle); r32 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 (r32 Angle) { r32 CosAngle = GSCos(Angle); r32 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 (r32 Angle) { r32 CosAngle = GSCos(Angle); r32 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) { DEBUG_TRACK_SCOPE(GetPositionM44); #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 = {}; r32 A00=A.E[0+4*0]; r32 A01=A.E[0+4*1]; r32 A02=A.E[0+4*2]; r32 A03=A.E[0+4*3]; r32 A10=A.E[1+4*0]; r32 A11=A.E[1+4*1]; r32 A12=A.E[1+4*2]; r32 A13=A.E[1+4*3]; r32 A20=A.E[2+4*0]; r32 A21=A.E[2+4*1]; r32 A22=A.E[2+4*2]; r32 A23=A.E[2+4*3]; r32 A30=A.E[3+4*0]; r32 A31=A.E[3+4*1]; r32 A32=A.E[3+4*2]; r32 A33=A.E[3+4*3]; r32 B00=B.E[0+4*0]; r32 B01=B.E[0+4*1]; r32 B02=B.E[0+4*2]; r32 B03=B.E[0+4*3]; r32 B10=B.E[1+4*0]; r32 B11=B.E[1+4*1]; r32 B12=B.E[1+4*2]; r32 B13=B.E[1+4*3]; r32 B20=B.E[2+4*0]; r32 B21=B.E[2+4*1]; r32 B22=B.E[2+4*2]; r32 B23=B.E[2+4*3]; r32 B30=B.E[3+4*0]; r32 B31=B.E[3+4*1]; r32 B32=B.E[3+4*2]; r32 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; r32 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}; r32 TestV2MagSq = (TestV2.x * TestV2.x) + (TestV2.y * TestV2.y); r32 TestV2Mag = GSSqrt(TestV2MagSq); v2 TestV2Norm = v2{TestV2.x / TestV2Mag, TestV2.y / TestV2Mag}; r32 TestV2DotR = (TestV2.x * V2Unit.x) + (TestV2.y * V2Unit.y); v3 TestV3 = v3{1, 2, 3}; r32 TestV3MagSq = (TestV3.x * TestV3.x) + (TestV3.y * TestV3.y) + (TestV3.z * TestV3.z); r32 TestV3Mag = GSSqrt(TestV3MagSq); v3 TestV3Norm = v3{TestV3.x / TestV3Mag, TestV3.y / TestV3Mag, TestV3.z / TestV3Mag}; r32 TestV3DotR = (TestV3.x * V3Unit.x) + (TestV3.y * V3Unit.y) + (TestV3.z * V3Unit.z); v4 TestV4 = v4{1, 2, 3, 4}; r32 TestV4MagSq = (TestV4.x * TestV4.x) + (TestV4.y * TestV4.y) + (TestV4.z * TestV4.z) + (TestV4.w * TestV4.w); r32 TestV4Mag = GSSqrt(TestV4MagSq); v4 TestV4Norm = v4{ TestV4.x / TestV4Mag, TestV4.y / TestV4Mag, TestV4.z / TestV4Mag, TestV4.w / TestV4Mag }; r32 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