mirror of
https://github.com/HandmadeMath/HandmadeMath.git
synced 2025-12-28 23:54:32 +00:00
Compare commits
5 Commits
2.0.0-rc1
...
v2.0.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50ab55b3bc | ||
|
|
22d743ce3d | ||
|
|
d4918a514e | ||
|
|
37aa3fa6a0 | ||
|
|
7e493a5481 |
509
HandmadeMath.h
509
HandmadeMath.h
@@ -26,20 +26,6 @@
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
By default, Handmade Math's projection matrices use a Normalized Device
|
||||
Coordinates (NDC) range of X: [-1, 1], Y: [-1, 1], Z: [-1, 1], as is standard
|
||||
in OpenGL. However, other graphics APIs require the range with Z: [0, 1], as
|
||||
this has better numerical properties for depth buffers.
|
||||
|
||||
To use NDC with Z: [0, 1], you must define HANDMADE_MATH_USE_NDC_Z01 before
|
||||
including this header, which will make HMM_Perspective and HMM_Orthographic
|
||||
functions project Z to [0, 1]:
|
||||
|
||||
#define HANDMADE_MATH_USE_NDC_Z01
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Handmade Math ships with SSE (SIMD) implementations of several common
|
||||
operations. To disable the use of SSE intrinsics, you must
|
||||
define HANDMADE_MATH_NO_SSE before including this file:
|
||||
@@ -541,13 +527,7 @@ static inline float HMM_InvSqrtF(float Float)
|
||||
|
||||
float Result;
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
__m128 In = _mm_set_ss(Float);
|
||||
__m128 Out = _mm_rsqrt_ss(In);
|
||||
Result = _mm_cvtss_f32(Out);
|
||||
#else
|
||||
Result = 1.0f/HMM_SqrtF(Float);
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -974,7 +954,7 @@ static inline float HMM_DotV4(HMM_Vec4 Left, HMM_Vec4 Right)
|
||||
SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
|
||||
_mm_store_ss(&Result, SSEResultOne);
|
||||
#else
|
||||
Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W);
|
||||
Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W));
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1102,16 +1082,25 @@ static inline HMM_Vec4 HMM_LinearCombineV4M4(HMM_Vec4 Left, HMM_Mat4 Right)
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xaa), Right.Columns[2].SSE));
|
||||
Result.SSE = _mm_add_ps(Result.SSE, _mm_mul_ps(_mm_shuffle_ps(Left.SSE, Left.SSE, 0xff), Right.Columns[3].SSE));
|
||||
#else
|
||||
int Columns, Rows;
|
||||
for(Rows = 0; Rows < 4; ++Rows)
|
||||
{
|
||||
float Sum = 0;
|
||||
for(Columns = 0; Columns < 4; ++Columns)
|
||||
{
|
||||
Sum += Left.Elements[Columns]*Right.Elements[Columns][Rows];
|
||||
}
|
||||
Result.Elements[Rows] = Sum;
|
||||
}
|
||||
Result.X = Left.Elements[0] * Right.Columns[0].X;
|
||||
Result.Y = Left.Elements[0] * Right.Columns[0].Y;
|
||||
Result.Z = Left.Elements[0] * Right.Columns[0].Z;
|
||||
Result.W = Left.Elements[0] * Right.Columns[0].W;
|
||||
|
||||
Result.X += Left.Elements[1] * Right.Columns[1].X;
|
||||
Result.Y += Left.Elements[1] * Right.Columns[1].Y;
|
||||
Result.Z += Left.Elements[1] * Right.Columns[1].Z;
|
||||
Result.W += Left.Elements[1] * Right.Columns[1].W;
|
||||
|
||||
Result.X += Left.Elements[2] * Right.Columns[2].X;
|
||||
Result.Y += Left.Elements[2] * Right.Columns[2].Y;
|
||||
Result.Z += Left.Elements[2] * Right.Columns[2].Z;
|
||||
Result.W += Left.Elements[2] * Right.Columns[2].W;
|
||||
|
||||
Result.X += Left.Elements[3] * Right.Columns[3].X;
|
||||
Result.Y += Left.Elements[3] * Right.Columns[3].Y;
|
||||
Result.Z += Left.Elements[3] * Right.Columns[3].Z;
|
||||
Result.W += Left.Elements[3] * Right.Columns[3].W;
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1146,16 +1135,10 @@ static inline HMM_Mat2 HMM_TransposeM2(HMM_Mat2 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_TransposeM2);
|
||||
|
||||
HMM_Mat2 Result;
|
||||
HMM_Mat2 Result = Matrix;
|
||||
|
||||
int Columns, Rows;
|
||||
for(Columns = 0; Columns < 2; ++Columns)
|
||||
{
|
||||
for(Rows = 0; Rows < 2; ++Rows)
|
||||
{
|
||||
Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
Result.Elements[0][1] = Matrix.Elements[1][0];
|
||||
Result.Elements[1][0] = Matrix.Elements[0][1];
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1166,15 +1149,11 @@ static inline HMM_Mat2 HMM_AddM2(HMM_Mat2 Left, HMM_Mat2 Right)
|
||||
ASSERT_COVERED(HMM_AddM2);
|
||||
|
||||
HMM_Mat2 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 2; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 2; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1185,16 +1164,12 @@ static inline HMM_Mat2 HMM_SubM2(HMM_Mat2 Left, HMM_Mat2 Right)
|
||||
ASSERT_COVERED(HMM_SubM2);
|
||||
|
||||
HMM_Mat2 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 2; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 2; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1204,16 +1179,12 @@ static inline HMM_Vec2 HMM_MulM2V2(HMM_Mat2 Matrix, HMM_Vec2 Vector)
|
||||
ASSERT_COVERED(HMM_MulM2V2);
|
||||
|
||||
HMM_Vec2 Result;
|
||||
int Columns, Rows;
|
||||
for(Rows = 0; Rows < 2; ++Rows)
|
||||
{
|
||||
float Sum = 0.0f;
|
||||
for(Columns = 0; Columns < 2; ++Columns)
|
||||
{
|
||||
Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns];
|
||||
}
|
||||
Result.Elements[Rows] = Sum;
|
||||
}
|
||||
|
||||
Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
|
||||
Result.Y = Vector.Elements[0] * Matrix.Columns[0].Y;
|
||||
|
||||
Result.X += Vector.Elements[1] * Matrix.Columns[1].X;
|
||||
Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y;
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1236,16 +1207,12 @@ static inline HMM_Mat2 HMM_MulM2F(HMM_Mat2 Matrix, float Scalar)
|
||||
ASSERT_COVERED(HMM_MulM2F);
|
||||
|
||||
HMM_Mat2 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 2; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 2; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar;
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1255,15 +1222,11 @@ static inline HMM_Mat2 HMM_DivM2F(HMM_Mat2 Matrix, float Scalar)
|
||||
ASSERT_COVERED(HMM_DivM2F);
|
||||
|
||||
HMM_Mat2 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 2; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 2; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar;
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar;
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1321,17 +1284,14 @@ static inline HMM_Mat3 HMM_TransposeM3(HMM_Mat3 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_TransposeM3);
|
||||
|
||||
HMM_Mat3 Result;
|
||||
HMM_Mat3 Result = Matrix;
|
||||
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 3; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 3; ++Rows)
|
||||
{
|
||||
Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
Result.Elements[0][1] = Matrix.Elements[1][0];
|
||||
Result.Elements[0][2] = Matrix.Elements[2][0];
|
||||
Result.Elements[1][0] = Matrix.Elements[0][1];
|
||||
Result.Elements[1][2] = Matrix.Elements[2][1];
|
||||
Result.Elements[2][1] = Matrix.Elements[1][2];
|
||||
Result.Elements[2][0] = Matrix.Elements[0][2];
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1342,16 +1302,17 @@ static inline HMM_Mat3 HMM_AddM3(HMM_Mat3 Left, HMM_Mat3 Right)
|
||||
ASSERT_COVERED(HMM_AddM3);
|
||||
|
||||
HMM_Mat3 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 3; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 3; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
|
||||
Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
|
||||
Result.Elements[1][2] = Left.Elements[1][2] + Right.Elements[1][2];
|
||||
Result.Elements[2][0] = Left.Elements[2][0] + Right.Elements[2][0];
|
||||
Result.Elements[2][1] = Left.Elements[2][1] + Right.Elements[2][1];
|
||||
Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1361,15 +1322,16 @@ static inline HMM_Mat3 HMM_SubM3(HMM_Mat3 Left, HMM_Mat3 Right)
|
||||
ASSERT_COVERED(HMM_SubM3);
|
||||
|
||||
HMM_Mat3 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 3; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 3; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1];
|
||||
Result.Elements[0][2] = Left.Elements[0][2] - Right.Elements[0][2];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
|
||||
Result.Elements[1][2] = Left.Elements[1][2] - Right.Elements[1][2];
|
||||
Result.Elements[2][0] = Left.Elements[2][0] - Right.Elements[2][0];
|
||||
Result.Elements[2][1] = Left.Elements[2][1] - Right.Elements[2][1];
|
||||
Result.Elements[2][2] = Left.Elements[2][2] - Right.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1380,17 +1342,19 @@ static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector)
|
||||
ASSERT_COVERED(HMM_MulM3V3);
|
||||
|
||||
HMM_Vec3 Result;
|
||||
int Columns, Rows;
|
||||
for(Rows = 0; Rows < 3; ++Rows)
|
||||
{
|
||||
float Sum = 0.0f;
|
||||
for(Columns = 0; Columns < 3; ++Columns)
|
||||
{
|
||||
Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns];
|
||||
}
|
||||
Result.Elements[Rows] = Sum;
|
||||
}
|
||||
|
||||
Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
|
||||
Result.Y = Vector.Elements[0] * Matrix.Columns[0].Y;
|
||||
Result.Z = Vector.Elements[0] * Matrix.Columns[0].Z;
|
||||
|
||||
Result.X += Vector.Elements[1] * Matrix.Columns[1].X;
|
||||
Result.Y += Vector.Elements[1] * Matrix.Columns[1].Y;
|
||||
Result.Z += Vector.Elements[1] * Matrix.Columns[1].Z;
|
||||
|
||||
Result.X += Vector.Elements[2] * Matrix.Columns[2].X;
|
||||
Result.Y += Vector.Elements[2] * Matrix.Columns[2].Y;
|
||||
Result.Z += Vector.Elements[2] * Matrix.Columns[2].Z;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -1413,15 +1377,16 @@ static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar)
|
||||
ASSERT_COVERED(HMM_MulM3F);
|
||||
|
||||
HMM_Mat3 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 3; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 3; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar;
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
|
||||
Result.Elements[0][2] = Matrix.Elements[0][2] * Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
|
||||
Result.Elements[1][2] = Matrix.Elements[1][2] * Scalar;
|
||||
Result.Elements[2][0] = Matrix.Elements[2][0] * Scalar;
|
||||
Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar;
|
||||
Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar;
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1432,15 +1397,16 @@ static inline HMM_Mat3 HMM_DivM3F(HMM_Mat3 Matrix, float Scalar)
|
||||
ASSERT_COVERED(HMM_DivM3);
|
||||
|
||||
HMM_Mat3 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 3; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 3; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar;
|
||||
}
|
||||
}
|
||||
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
|
||||
Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar;
|
||||
Result.Elements[1][2] = Matrix.Elements[1][2] / Scalar;
|
||||
Result.Elements[2][0] = Matrix.Elements[2][0] / Scalar;
|
||||
Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar;
|
||||
Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar;
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -1509,20 +1475,22 @@ static inline HMM_Mat4 HMM_TransposeM4(HMM_Mat4 Matrix)
|
||||
{
|
||||
ASSERT_COVERED(HMM_TransposeM4);
|
||||
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
HMM_Mat4 Result = Matrix;
|
||||
#ifdef HANDMADE_MATH__USE_SSE
|
||||
_MM_TRANSPOSE4_PS(Result.Columns[0].SSE, Result.Columns[1].SSE, Result.Columns[2].SSE, Result.Columns[3].SSE);
|
||||
#else
|
||||
HMM_Mat4 Result;
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 4; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 4; ++Rows)
|
||||
{
|
||||
Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
Result.Elements[0][1] = Matrix.Elements[1][0];
|
||||
Result.Elements[0][2] = Matrix.Elements[2][0];
|
||||
Result.Elements[0][3] = Matrix.Elements[3][0];
|
||||
Result.Elements[1][0] = Matrix.Elements[0][1];
|
||||
Result.Elements[1][2] = Matrix.Elements[2][1];
|
||||
Result.Elements[1][3] = Matrix.Elements[3][1];
|
||||
Result.Elements[2][1] = Matrix.Elements[1][2];
|
||||
Result.Elements[2][0] = Matrix.Elements[0][2];
|
||||
Result.Elements[2][3] = Matrix.Elements[3][2];
|
||||
Result.Elements[3][1] = Matrix.Elements[1][3];
|
||||
Result.Elements[3][2] = Matrix.Elements[2][3];
|
||||
Result.Elements[3][0] = Matrix.Elements[0][3];
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1541,15 +1509,22 @@ static inline HMM_Mat4 HMM_AddM4(HMM_Mat4 Left, HMM_Mat4 Right)
|
||||
Result.Columns[2].SSE = _mm_add_ps(Left.Columns[2].SSE, Right.Columns[2].SSE);
|
||||
Result.Columns[3].SSE = _mm_add_ps(Left.Columns[3].SSE, Right.Columns[3].SSE);
|
||||
#else
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 4; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 4; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
Result.Elements[0][0] = Left.Elements[0][0] + Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] + Right.Elements[0][1];
|
||||
Result.Elements[0][2] = Left.Elements[0][2] + Right.Elements[0][2];
|
||||
Result.Elements[0][3] = Left.Elements[0][3] + Right.Elements[0][3];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] + Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] + Right.Elements[1][1];
|
||||
Result.Elements[1][2] = Left.Elements[1][2] + Right.Elements[1][2];
|
||||
Result.Elements[1][3] = Left.Elements[1][3] + Right.Elements[1][3];
|
||||
Result.Elements[2][0] = Left.Elements[2][0] + Right.Elements[2][0];
|
||||
Result.Elements[2][1] = Left.Elements[2][1] + Right.Elements[2][1];
|
||||
Result.Elements[2][2] = Left.Elements[2][2] + Right.Elements[2][2];
|
||||
Result.Elements[2][3] = Left.Elements[2][3] + Right.Elements[2][3];
|
||||
Result.Elements[3][0] = Left.Elements[3][0] + Right.Elements[3][0];
|
||||
Result.Elements[3][1] = Left.Elements[3][1] + Right.Elements[3][1];
|
||||
Result.Elements[3][2] = Left.Elements[3][2] + Right.Elements[3][2];
|
||||
Result.Elements[3][3] = Left.Elements[3][3] + Right.Elements[3][3];
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1568,15 +1543,22 @@ static inline HMM_Mat4 HMM_SubM4(HMM_Mat4 Left, HMM_Mat4 Right)
|
||||
Result.Columns[2].SSE = _mm_sub_ps(Left.Columns[2].SSE, Right.Columns[2].SSE);
|
||||
Result.Columns[3].SSE = _mm_sub_ps(Left.Columns[3].SSE, Right.Columns[3].SSE);
|
||||
#else
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 4; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 4; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows];
|
||||
}
|
||||
}
|
||||
Result.Elements[0][0] = Left.Elements[0][0] - Right.Elements[0][0];
|
||||
Result.Elements[0][1] = Left.Elements[0][1] - Right.Elements[0][1];
|
||||
Result.Elements[0][2] = Left.Elements[0][2] - Right.Elements[0][2];
|
||||
Result.Elements[0][3] = Left.Elements[0][3] - Right.Elements[0][3];
|
||||
Result.Elements[1][0] = Left.Elements[1][0] - Right.Elements[1][0];
|
||||
Result.Elements[1][1] = Left.Elements[1][1] - Right.Elements[1][1];
|
||||
Result.Elements[1][2] = Left.Elements[1][2] - Right.Elements[1][2];
|
||||
Result.Elements[1][3] = Left.Elements[1][3] - Right.Elements[1][3];
|
||||
Result.Elements[2][0] = Left.Elements[2][0] - Right.Elements[2][0];
|
||||
Result.Elements[2][1] = Left.Elements[2][1] - Right.Elements[2][1];
|
||||
Result.Elements[2][2] = Left.Elements[2][2] - Right.Elements[2][2];
|
||||
Result.Elements[2][3] = Left.Elements[2][3] - Right.Elements[2][3];
|
||||
Result.Elements[3][0] = Left.Elements[3][0] - Right.Elements[3][0];
|
||||
Result.Elements[3][1] = Left.Elements[3][1] - Right.Elements[3][1];
|
||||
Result.Elements[3][2] = Left.Elements[3][2] - Right.Elements[3][2];
|
||||
Result.Elements[3][3] = Left.Elements[3][3] - Right.Elements[3][3];
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1610,15 +1592,22 @@ static inline HMM_Mat4 HMM_MulM4F(HMM_Mat4 Matrix, float Scalar)
|
||||
Result.Columns[2].SSE = _mm_mul_ps(Matrix.Columns[2].SSE, SSEScalar);
|
||||
Result.Columns[3].SSE = _mm_mul_ps(Matrix.Columns[3].SSE, SSEScalar);
|
||||
#else
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 4; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 4; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar;
|
||||
}
|
||||
}
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] * Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] * Scalar;
|
||||
Result.Elements[0][2] = Matrix.Elements[0][2] * Scalar;
|
||||
Result.Elements[0][3] = Matrix.Elements[0][3] * Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] * Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] * Scalar;
|
||||
Result.Elements[1][2] = Matrix.Elements[1][2] * Scalar;
|
||||
Result.Elements[1][3] = Matrix.Elements[1][3] * Scalar;
|
||||
Result.Elements[2][0] = Matrix.Elements[2][0] * Scalar;
|
||||
Result.Elements[2][1] = Matrix.Elements[2][1] * Scalar;
|
||||
Result.Elements[2][2] = Matrix.Elements[2][2] * Scalar;
|
||||
Result.Elements[2][3] = Matrix.Elements[2][3] * Scalar;
|
||||
Result.Elements[3][0] = Matrix.Elements[3][0] * Scalar;
|
||||
Result.Elements[3][1] = Matrix.Elements[3][1] * Scalar;
|
||||
Result.Elements[3][2] = Matrix.Elements[3][2] * Scalar;
|
||||
Result.Elements[3][3] = Matrix.Elements[3][3] * Scalar;
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1645,15 +1634,22 @@ static inline HMM_Mat4 HMM_DivM4F(HMM_Mat4 Matrix, float Scalar)
|
||||
Result.Columns[2].SSE = _mm_div_ps(Matrix.Columns[2].SSE, SSEScalar);
|
||||
Result.Columns[3].SSE = _mm_div_ps(Matrix.Columns[3].SSE, SSEScalar);
|
||||
#else
|
||||
int Columns;
|
||||
for(Columns = 0; Columns < 4; ++Columns)
|
||||
{
|
||||
int Rows;
|
||||
for(Rows = 0; Rows < 4; ++Rows)
|
||||
{
|
||||
Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar;
|
||||
}
|
||||
}
|
||||
Result.Elements[0][0] = Matrix.Elements[0][0] / Scalar;
|
||||
Result.Elements[0][1] = Matrix.Elements[0][1] / Scalar;
|
||||
Result.Elements[0][2] = Matrix.Elements[0][2] / Scalar;
|
||||
Result.Elements[0][3] = Matrix.Elements[0][3] / Scalar;
|
||||
Result.Elements[1][0] = Matrix.Elements[1][0] / Scalar;
|
||||
Result.Elements[1][1] = Matrix.Elements[1][1] / Scalar;
|
||||
Result.Elements[1][2] = Matrix.Elements[1][2] / Scalar;
|
||||
Result.Elements[1][3] = Matrix.Elements[1][3] / Scalar;
|
||||
Result.Elements[2][0] = Matrix.Elements[2][0] / Scalar;
|
||||
Result.Elements[2][1] = Matrix.Elements[2][1] / Scalar;
|
||||
Result.Elements[2][2] = Matrix.Elements[2][2] / Scalar;
|
||||
Result.Elements[2][3] = Matrix.Elements[2][3] / Scalar;
|
||||
Result.Elements[3][0] = Matrix.Elements[3][0] / Scalar;
|
||||
Result.Elements[3][1] = Matrix.Elements[3][1] / Scalar;
|
||||
Result.Elements[3][2] = Matrix.Elements[3][2] / Scalar;
|
||||
Result.Elements[3][3] = Matrix.Elements[3][3] / Scalar;
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -1701,10 +1697,10 @@ static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
* Common graphics transformations
|
||||
*/
|
||||
|
||||
COVERAGE(HMM_Orthographic_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_RH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
COVERAGE(HMM_Orthographic_RH_NO, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_RH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_RH);
|
||||
ASSERT_COVERED(HMM_Orthographic_RH_NO);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
@@ -1715,23 +1711,49 @@ static inline HMM_Mat4 HMM_Orthographic_RH(float Left, float Right, float Bottom
|
||||
Result.Elements[3][0] = (Left + Right) / (Left - Right);
|
||||
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
|
||||
|
||||
#ifdef HANDMADE_MATH_USE_NDC_Z01
|
||||
Result.Elements[2][2] = 1.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Near) / (Near - Far);
|
||||
#else
|
||||
Result.Elements[2][2] = 2.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Far + Near) / (Near - Far);
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_LH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
COVERAGE(HMM_Orthographic_RH_ZO, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_RH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_LH);
|
||||
ASSERT_COVERED(HMM_Orthographic_RH_ZO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_RH(Left, Right, Bottom, Top, Near, Far);
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
Result.Elements[0][0] = 2.0f / (Right - Left);
|
||||
Result.Elements[1][1] = 2.0f / (Top - Bottom);
|
||||
Result.Elements[3][3] = 1.0f;
|
||||
|
||||
Result.Elements[3][0] = (Left + Right) / (Left - Right);
|
||||
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
|
||||
|
||||
Result.Elements[2][2] = 1.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Near) / (Near - Far);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_LH_NO, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_LH_NO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_LH_NO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_RH_NO(Left, Right, Bottom, Top, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_LH_ZO, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_LH_ZO(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_LH_ZO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_RH_ZO(Left, Right, Bottom, Top, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
@@ -1755,41 +1777,67 @@ static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_RH(float FOV, float AspectRatio, float Near, float Far)
|
||||
COVERAGE(HMM_Perspective_RH_NO, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_RH_NO(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_RH);
|
||||
ASSERT_COVERED(HMM_Perspective_RH_NO);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
// See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||
|
||||
float Cotangent = 1.0f / HMM_TanF(FOV / 2.0f);
|
||||
|
||||
Result.Elements[0][0] = Cotangent / AspectRatio;
|
||||
Result.Elements[1][1] = Cotangent;
|
||||
|
||||
Result.Elements[2][3] = -1.0f;
|
||||
|
||||
#ifdef HANDMADE_MATH_USE_NDC_Z01
|
||||
Result.Elements[2][2] = (Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (Near * Far) / (Near - Far);
|
||||
#else
|
||||
Result.Elements[2][2] = (Near + Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_RH_ZO, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_RH_ZO(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_RH_ZO);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
// See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||
|
||||
float Cotangent = 1.0f / HMM_TanF(FOV / 2.0f);
|
||||
Result.Elements[0][0] = Cotangent / AspectRatio;
|
||||
Result.Elements[1][1] = Cotangent;
|
||||
Result.Elements[2][3] = -1.0f;
|
||||
|
||||
Result.Elements[2][2] = (Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (Near * Far) / (Near - Far);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_LH(float FOV, float AspectRatio, float Near, float Far)
|
||||
COVERAGE(HMM_Perspective_LH_NO, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_LH_NO(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_LH);
|
||||
ASSERT_COVERED(HMM_Perspective_LH_NO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_RH(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][3] = +1.0f;
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_RH_NO(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
Result.Elements[2][3] = -Result.Elements[2][3];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_LH_ZO, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_LH_ZO(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_LH_ZO);
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_RH_ZO(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
Result.Elements[2][3] = -Result.Elements[2][3];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
@@ -2088,10 +2136,25 @@ static inline HMM_Quat HMM_MulQ(HMM_Quat Left, HMM_Quat Right)
|
||||
SSEResultTwo = _mm_shuffle_ps(Right.SSE, Right.SSE, _MM_SHUFFLE(3, 2, 1, 0));
|
||||
Result.SSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne));
|
||||
#else
|
||||
Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X);
|
||||
Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y);
|
||||
Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z);
|
||||
Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W);
|
||||
Result.X = Right.Elements[3] * +Left.Elements[0];
|
||||
Result.Y = Right.Elements[2] * -Left.Elements[0];
|
||||
Result.Z = Right.Elements[1] * +Left.Elements[0];
|
||||
Result.W = Right.Elements[0] * -Left.Elements[0];
|
||||
|
||||
Result.X += Right.Elements[2] * +Left.Elements[1];
|
||||
Result.Y += Right.Elements[3] * +Left.Elements[1];
|
||||
Result.Z += Right.Elements[0] * -Left.Elements[1];
|
||||
Result.W += Right.Elements[1] * -Left.Elements[1];
|
||||
|
||||
Result.X += Right.Elements[1] * -Left.Elements[2];
|
||||
Result.Y += Right.Elements[0] * +Left.Elements[2];
|
||||
Result.Z += Right.Elements[3] * +Left.Elements[2];
|
||||
Result.W += Right.Elements[2] * -Left.Elements[2];
|
||||
|
||||
Result.X += Right.Elements[0] * +Left.Elements[3];
|
||||
Result.Y += Right.Elements[1] * +Left.Elements[3];
|
||||
Result.Z += Right.Elements[2] * +Left.Elements[3];
|
||||
Result.W += Right.Elements[3] * +Left.Elements[3];
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
@@ -2152,7 +2215,7 @@ static inline float HMM_DotQ(HMM_Quat Left, HMM_Quat Right)
|
||||
SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo);
|
||||
_mm_store_ss(&Result, SSEResultOne);
|
||||
#else
|
||||
Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W);
|
||||
Result = ((Left.X * Right.X) + (Left.Z * Right.Z)) + ((Left.Y * Right.Y) + (Left.W * Right.W));
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
|
||||
@@ -249,7 +249,7 @@ TEST(InvMatrix, InvGeneral)
|
||||
TEST(InvMatrix, Mat4Inverses)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_RH(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_RH_NO(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvOrthographic(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
@@ -272,10 +272,10 @@ TEST(InvMatrix, Mat4Inverses)
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_RH(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Matrix = HMM_Perspective_RH_NO(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
@@ -3,47 +3,66 @@
|
||||
TEST(Projection, Orthographic)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_RH(-10.0f, 10.0f, -5.0f, 5.0f, 0.0f, -10.0f);
|
||||
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -5.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
HMM_Mat4 projection = HMM_Orthographic_RH_NO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, 10.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
|
||||
EXPECT_FLOAT_EQ(projected.X, 0.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -2.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Orthographic_RH_ZO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_LH(-10.0f, 10.0f, -5.0f, 5.0f, 0.0f, 10.0f);
|
||||
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -5.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
|
||||
HMM_Mat4 projection = HMM_Orthographic_LH_NO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
|
||||
EXPECT_FLOAT_EQ(projected.X, 0.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -2.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Orthographic_LH_ZO(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Projection, Perspective)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_RH(HMM_AngleDeg(90.0f), 2.0f, 5.0f, 15.0f);
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -15.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
HMM_Mat4 projection = HMM_Perspective_RH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* ZO */
|
||||
projection = HMM_Perspective_RH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_LH(HMM_AngleDeg(90.0f), 2.0f, 5.0f, 15.0f);
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -15.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
HMM_Mat4 projection = HMM_Perspective_LH_NO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, -15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* ZO */
|
||||
projection = HMM_Perspective_LH_ZO(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,24 @@
|
||||
# Handmade Math 2.0 Update Tool
|
||||
|
||||
Due to the large number of breaking naming changes in Handmade Math 2, we provide a small tool to update your programs automatically. It's a C program that takes a list of files and updates their text, along with some scripts to recursively run the program on all code in a directory.
|
||||
Due to the large number of breaking naming changes in Handmade Math 2, we provide a small Python script to update your programs automatically. It can run on individual files or on all files in a directory (recursively).
|
||||
|
||||
You can compile the tool yourself with any C/C++ compiler:
|
||||
**Warning!** This tool is not very smart! Please ensure that your work is committed and backed up, in case you have to revert this tool's changes.
|
||||
|
||||
```bash
|
||||
# MSVC (Windows)
|
||||
cl update_hmm.c
|
||||
|
||||
# gcc
|
||||
gcc update_hmm.c -o update_hmm
|
||||
|
||||
# clang
|
||||
clang update_hmm.c -o update_hmm
|
||||
```
|
||||
# see usage info and options
|
||||
> python3 update_hmm.py -h
|
||||
usage: update_hmm [-h] [--exts .foo [.foo ...]] filename [filename ...]
|
||||
...
|
||||
|
||||
Once built, the tool can be run on any C or C++ files:
|
||||
# run on individual files
|
||||
> python3 update_hmm.py MyPlatformLayer.c MyPlatformLayer.h
|
||||
Updating: MyPlatformLayer.c
|
||||
Updating: MyPlatformLayer.h
|
||||
Updated 2 files with 0 warnings.
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
update_hmm.exe MyGame.cpp MyPlatformLayer.cpp
|
||||
|
||||
# Other platforms
|
||||
update_hmm MyGame.cpp MyPlatformLayer.cpp
|
||||
```
|
||||
|
||||
Or, update all C/C++ files in a directory by running one of the provided shell scripts:
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
update_hmm_all.bat "path\to\project"
|
||||
|
||||
# Other platforms
|
||||
update_hmm_all.sh path/to/project
|
||||
# run on a whole directory
|
||||
> python3 update_hmm.py projects/MyCoolGame
|
||||
Updating: projects/MyCoolGame/src/MyPlatformLayer.c
|
||||
Updating: projects/MyCoolGame/include/MyPlatformLayer.h
|
||||
...
|
||||
```
|
||||
|
||||
@@ -1,562 +0,0 @@
|
||||
/* Compile:
|
||||
Windows (MSVC): cl update_hmm.c
|
||||
Linux (GCC): gcc update_hmm.c -o update_hmm
|
||||
*/
|
||||
|
||||
/** LCF stuff **/
|
||||
/* I used my personally library when writing this so I am dumping the necessary things here
|
||||
so that it's all in one file. */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
/* Types */
|
||||
#define global static
|
||||
#define internal static
|
||||
typedef int32_t s32; global s32 s32_MAX = 0x7FFFFFFF; global s32 s32_MIN = -1 - 0x7FFFFFFF;
|
||||
typedef int64_t s64; global s64 s64_MAX = 0x7FFFFFFFFFFFFFFF; global s64 s64_MIN = -1 - 0x7FFFFFFFFFFFFFFF;
|
||||
typedef uint32_t u32; global u32 u32_MAX = 0xFFFFFFFF; global u32 u32_MIN = 0;
|
||||
typedef uint64_t u64; global u64 u64_MAX = 0xFFFFFFFFFFFFFFFF; global u64 u64_MIN = 0;
|
||||
typedef u32 b32;
|
||||
typedef u64 b64;
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define CLAMPTOP(a,b) MIN(a,b)
|
||||
|
||||
/* Memory */
|
||||
struct lcf_Arena {
|
||||
u64 pos;
|
||||
u64 size;
|
||||
u64 alignment;
|
||||
u64 commited_pos;
|
||||
};
|
||||
typedef struct lcf_Arena Arena;
|
||||
#define KB(x) ((x) << 10)
|
||||
#define GB(x) ((x) << 30)
|
||||
Arena* Arena_create(u64 size);
|
||||
void* Arena_take(Arena *a, u64 size);
|
||||
void* Arena_take_custom(Arena *a, u64 size, u64 alignment);
|
||||
#define Arena_take_array(a, type, count) ((type*) Arena_take(a, sizeof(type)*count))
|
||||
void Arena_reset_all(Arena *a);
|
||||
|
||||
#define LCF_MEMORY_PROVIDE_MEMORY "stdlib"
|
||||
#define LCF_MEMORY_RESERVE_MEMORY(name) void* name(u64 size)
|
||||
#define LCF_MEMORY_COMMIT_MEMORY(name) b32 name(void* memory, u64 size)
|
||||
#define LCF_MEMORY_DECOMMIT_MEMORY(name) void name(void* memory, u64 size)
|
||||
#define LCF_MEMORY_FREE_MEMORY(name) void name(void* memory, u64 size)
|
||||
/* This implementation of an arena doesn't take advantage of virtual memory at all.
|
||||
It's just convenient to have something portable so I can use the Arena API I'm used to. */
|
||||
internal LCF_MEMORY_RESERVE_MEMORY(_lcf_memory_default_reserve) {
|
||||
return malloc(size);
|
||||
}
|
||||
internal LCF_MEMORY_COMMIT_MEMORY(_lcf_memory_default_commit) {
|
||||
(void) size, memory;
|
||||
return 1; /* malloc commits memory automatically */
|
||||
}
|
||||
internal LCF_MEMORY_DECOMMIT_MEMORY(_lcf_memory_default_decommit) {
|
||||
(void) size, memory;
|
||||
return;
|
||||
}
|
||||
internal LCF_MEMORY_FREE_MEMORY(_lcf_memory_default_free) {
|
||||
(void) size;
|
||||
free(memory);
|
||||
}
|
||||
#define LCF_MEMORY_reserve _lcf_memory_default_reserve
|
||||
#define LCF_MEMORY_commit _lcf_memory_default_commit
|
||||
#define LCF_MEMORY_decommit _lcf_memory_default_decommit
|
||||
#define LCF_MEMORY_free _lcf_memory_default_free
|
||||
#define LCF_MEMORY_RESERVE_SIZE GB(1)
|
||||
#define LCF_MEMORY_COMMIT_SIZE KB(4)
|
||||
#define LCF_MEMORY_ALIGNMENT (sizeof(void*))
|
||||
|
||||
Arena* Arena_create(u64 size) {
|
||||
Arena* a = (Arena*) LCF_MEMORY_reserve(size);
|
||||
LCF_MEMORY_commit(a, LCF_MEMORY_COMMIT_SIZE);
|
||||
a->size = size;
|
||||
a->pos = sizeof(Arena);
|
||||
a->commited_pos = LCF_MEMORY_COMMIT_SIZE;
|
||||
a->alignment = LCF_MEMORY_ALIGNMENT;
|
||||
return a;
|
||||
}
|
||||
#define B_PTR(p) (u8*)(p)
|
||||
|
||||
internal b32 is_power_of_2(u64 x) {
|
||||
return ((x & (x-1)) == 0);
|
||||
}
|
||||
internal u64 next_alignment(u64 ptr, u64 alignment) {
|
||||
/* Fast replacement for mod because alignment is power of 2 */
|
||||
u64 modulo = ptr & (alignment-1);
|
||||
|
||||
if (modulo != 0) {
|
||||
ptr += alignment - modulo;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
void* Arena_take_custom(Arena *a, u64 size, u64 alignment) {
|
||||
void* result = 0;
|
||||
|
||||
/* Align pos pointer to check if "size" can fit */
|
||||
u64 mem = (u64) a;
|
||||
u64 aligned_pos = next_alignment(mem + a->pos, alignment) - mem;
|
||||
u64 new_pos = aligned_pos + size;
|
||||
|
||||
/* Check that there is space */
|
||||
if (new_pos < a->size) {
|
||||
u64 commited_pos = a->commited_pos;
|
||||
|
||||
/* Commit memory if needed */
|
||||
if (new_pos > commited_pos) {
|
||||
u64 new_commited_pos = next_alignment(mem + new_pos, LCF_MEMORY_COMMIT_SIZE)-mem;
|
||||
if (LCF_MEMORY_commit(a, new_commited_pos)) {
|
||||
a->commited_pos = commited_pos = new_commited_pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* If enough memory is commited, set result and pos. */
|
||||
if (new_pos <= commited_pos) {
|
||||
result = (void*)(mem + aligned_pos);
|
||||
a->pos = new_pos;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
void* Arena_take(Arena *a, u64 size) {
|
||||
return Arena_take_custom(a, size, LCF_MEMORY_ALIGNMENT);
|
||||
}
|
||||
void Arena_reset_all(Arena *a) {
|
||||
a->pos = 0;
|
||||
}
|
||||
|
||||
/* String */
|
||||
typedef char chr8;
|
||||
struct str8 {
|
||||
u64 len;
|
||||
chr8 *str;
|
||||
};
|
||||
typedef struct str8 str8;
|
||||
#define str8_PRINTF_ARGS(s) (int)(s).len, (s).str
|
||||
#define str8_lit(s) str8_from((chr8*)(s),(u64)sizeof(s)-1) /* -1 to exclude null character */
|
||||
#define str8_is_empty(s) ((b32)((s).len == 0))
|
||||
#define LCF_STRING_NO_MATCH 0x8000000000000000
|
||||
#define str8_iter_custom(s, i, c) \
|
||||
s64 i = 0; \
|
||||
chr8 c = s.str[i]; \
|
||||
for (; (i < (s64) s.len); i++, c = s.str[i])
|
||||
|
||||
#define str8_iter(s) str8_iter_custom(s, i, c)
|
||||
|
||||
str8 str8_from(chr8* s, u64 len);
|
||||
str8 str8_from_cstring(chr8 *cstr);
|
||||
str8 str8_first(str8 s, u64 len);
|
||||
str8 str8_skip(str8 s, u64 len);
|
||||
b32 chr8_is_whitespace(chr8 c);
|
||||
b32 str8_contains_char(str8 s, chr8 c);
|
||||
u64 str8_char_location(str8 s, chr8 c);
|
||||
|
||||
#define RET_STR8(s,l) \
|
||||
str8 _str8; \
|
||||
_str8.str = (s); \
|
||||
_str8.len = (l); \
|
||||
return _str8
|
||||
str8 str8_from(chr8* s, u64 len) {
|
||||
RET_STR8(s, len);
|
||||
}
|
||||
str8 str8_from_cstring(chr8 *cstr) {
|
||||
chr8* p2 = cstr;
|
||||
while(*p2 != 0)
|
||||
p2++;
|
||||
RET_STR8(cstr, (u64)(p2 - cstr));
|
||||
}
|
||||
str8 str8_first(str8 s, u64 len) {
|
||||
u64 len_clamped = CLAMPTOP(len, s.len);
|
||||
RET_STR8(s.str, len_clamped);
|
||||
}
|
||||
str8 str8_skip(str8 s, u64 len) {
|
||||
u64 len_clamped = CLAMPTOP(len, s.len);
|
||||
RET_STR8(s.str + len_clamped, s.len - len_clamped);
|
||||
}
|
||||
b32 chr8_is_whitespace(chr8 c) {
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\t':
|
||||
case '\r':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
b32 str8_contains_char(str8 s, chr8 find) {
|
||||
return str8_char_location(s,find) != LCF_STRING_NO_MATCH;
|
||||
}
|
||||
u64 str8_char_location(str8 s, chr8 find) {
|
||||
str8_iter(s) {
|
||||
if (c == find) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return LCF_STRING_NO_MATCH;
|
||||
}
|
||||
#undef RET_STR8
|
||||
|
||||
struct Str8Node {
|
||||
struct Str8Node *next;
|
||||
struct str8 str;
|
||||
};
|
||||
struct Str8List {
|
||||
struct Str8Node *first;
|
||||
struct Str8Node *last;
|
||||
u64 count;
|
||||
u64 total_len;
|
||||
};
|
||||
typedef struct Str8Node Str8Node;
|
||||
typedef struct Str8List Str8List;
|
||||
|
||||
void Str8List_add_node(Str8List *list, Str8Node *n);
|
||||
void Str8List_add(Arena *arena, Str8List *list, str8 str);
|
||||
void Str8List_add_node(Str8List *list, Str8Node *n) {
|
||||
if (list->last) {
|
||||
list->last->next = n;
|
||||
} else {
|
||||
list->first = n;
|
||||
}
|
||||
list->last = n;
|
||||
list->count++;
|
||||
list->total_len += n->str.len;
|
||||
}
|
||||
void Str8List_add(Arena *arena, Str8List *list, str8 str) {
|
||||
Str8Node *n = Arena_take_array(arena, Str8Node, 1);
|
||||
n->str = str;
|
||||
n->next = 0;
|
||||
Str8List_add_node(list, n);
|
||||
}
|
||||
|
||||
/* CRT - stdio */
|
||||
str8 stdio_load_entire_file(Arena *arena, str8 filepath);
|
||||
b32 stdio_write_file(str8 filepath, Str8List text);
|
||||
|
||||
str8 stdio_load_entire_file(Arena *arena, str8 filepath) {
|
||||
str8 file_content = {0};
|
||||
|
||||
FILE *file = fopen(filepath.str, "rb");
|
||||
if (file != 0) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
u64 file_len = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
file_content.str = (chr8*) Arena_take(arena, file_len+1);
|
||||
if (file_content.str != 0) {
|
||||
file_content.len = file_len;
|
||||
fread(file_content.str, 1, file_len, file);
|
||||
file_content.str[file_content.len] = 0;
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
return file_content;
|
||||
}
|
||||
b32 stdio_write_file(str8 filepath, Str8List text) {
|
||||
u64 bytes_written = 0;
|
||||
FILE *file = fopen(filepath.str, "wb");
|
||||
if (file != 0) {
|
||||
Str8Node* n = text.first;
|
||||
for (s64 i = 0; i < text.count; i++, n = n->next) {
|
||||
if (!fwrite(n->str.str, n->str.len, 1, file)) {
|
||||
break;
|
||||
}
|
||||
bytes_written += n->str.len;
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
return bytes_written == text.total_len;
|
||||
}
|
||||
|
||||
/** HMM2.0 Update Tool **/
|
||||
enum Targets {
|
||||
/* hmm_ and HMM_ prefixes */
|
||||
PREFIX_TYPE, PREFIX_FUNCTION,
|
||||
PREFIXES_Size,
|
||||
/* Struct/Union types */
|
||||
TYPE_VEC, TYPE_MAT, TYPE_QUATERNION, TYPE_BOOL,
|
||||
TYPE_INTERNAL_ELEMENTS_SSE,
|
||||
TYPES_Size,
|
||||
/* Types in Function Names */
|
||||
FUN_VEC, FUN_MAT, FUN_QUATERNION,
|
||||
/* Function Names for Common Operations */
|
||||
FUN_EQUALS, FUN_SUBTRACT, FUN_MULTIPLY, FUN_DIVIDE,
|
||||
FUN_INVERSE, FUN_R_SQUARE_ROOT, FUN_SQUARE_ROOT,
|
||||
FUN_LENGTH_SQUARED, FUN_LENGTH, FUN_FAST_NORM, FUN_NORM,
|
||||
FUN_SLERP, FUN_BY,
|
||||
FUN_LINEAR_COMBINE_SSE, FUN_TRANSPOSE,
|
||||
FUNCTIONS_Size,
|
||||
/* Handedness */
|
||||
HAND_PERSPECTIVE, HAND_ROTATE,
|
||||
HAND_ORTHO, HAND_LOOK_AT, HAND_QUAT_AXIS_ANGLE, HAND_MAT_TO_QUAT,
|
||||
HAND_Size,
|
||||
};
|
||||
|
||||
Str8List update_file_content(Arena* arena, str8 file_content) {
|
||||
Str8List out = {0};
|
||||
|
||||
str8 Find[HAND_Size];
|
||||
str8 Repl[HAND_Size];
|
||||
{ /* NOTE: Initialization */
|
||||
Find[PREFIX_TYPE] = str8_lit("hmm_");
|
||||
Find[PREFIX_FUNCTION] = str8_lit("HMM_");
|
||||
Repl[PREFIX_TYPE] = Find[PREFIX_FUNCTION];
|
||||
|
||||
Find[TYPE_VEC] = str8_lit("vec");
|
||||
Repl[TYPE_VEC] = str8_lit("Vec");
|
||||
Find[TYPE_MAT] = str8_lit("mat");
|
||||
Repl[TYPE_MAT] = str8_lit("Mat");
|
||||
Find[TYPE_QUATERNION] = str8_lit("quaternion");
|
||||
Repl[TYPE_QUATERNION] = str8_lit("Quat");
|
||||
Find[TYPE_BOOL] = str8_lit("bool");
|
||||
Repl[TYPE_BOOL] = str8_lit("Bool");
|
||||
Find[TYPE_INTERNAL_ELEMENTS_SSE] = str8_lit(".InternalElementsSSE");
|
||||
Repl[TYPE_INTERNAL_ELEMENTS_SSE] = str8_lit(".SSE");
|
||||
|
||||
Find[FUN_VEC] = str8_lit("Vec");
|
||||
Repl[FUN_VEC] = str8_lit("V");
|
||||
Find[FUN_MAT] = str8_lit("Mat");
|
||||
Repl[FUN_MAT] = str8_lit("M");
|
||||
Find[FUN_QUATERNION] = str8_lit("Quaternion");
|
||||
Repl[FUN_QUATERNION] = str8_lit("Q");
|
||||
Find[FUN_EQUALS] = str8_lit("Equals");
|
||||
Repl[FUN_EQUALS] = str8_lit("Eq");
|
||||
Find[FUN_SUBTRACT] = str8_lit("Subtract");
|
||||
Repl[FUN_SUBTRACT] = str8_lit("Sub");
|
||||
Find[FUN_MULTIPLY] = str8_lit("Multiply");
|
||||
Repl[FUN_MULTIPLY] = str8_lit("Mul");
|
||||
Find[FUN_DIVIDE] = str8_lit("Divide");
|
||||
Repl[FUN_DIVIDE] = str8_lit("Div");
|
||||
Find[FUN_INVERSE] = str8_lit("Inverse");
|
||||
Repl[FUN_INVERSE] = str8_lit("Inv");
|
||||
Find[FUN_R_SQUARE_ROOT] = str8_lit("RSquareRoot");
|
||||
Repl[FUN_R_SQUARE_ROOT] = str8_lit("InvSqrt");
|
||||
Find[FUN_SQUARE_ROOT] = str8_lit("SquareRoot");
|
||||
Repl[FUN_SQUARE_ROOT] = str8_lit("Sqrt");
|
||||
Find[FUN_LENGTH_SQUARED] = str8_lit("Squared");
|
||||
Repl[FUN_LENGTH_SQUARED] = str8_lit("Sqr"); /* FIXME: not working for some reason */
|
||||
Find[FUN_LENGTH] = str8_lit("Length");
|
||||
Repl[FUN_LENGTH] = str8_lit("Len");
|
||||
|
||||
Find[FUN_SLERP] = str8_lit("Slerp");
|
||||
Repl[FUN_SLERP] = str8_lit("SLerp");
|
||||
Find[FUN_BY] = str8_lit("By");
|
||||
Repl[FUN_BY] = str8_lit("");
|
||||
Find[FUN_LINEAR_COMBINE_SSE] = str8_lit("LinearCombineSSE"); /* TODO: emit warning */
|
||||
Repl[FUN_LINEAR_COMBINE_SSE] = str8_lit("LinearCombineV4M4");
|
||||
Find[FUN_TRANSPOSE] = str8_lit("Transpose");
|
||||
Repl[FUN_TRANSPOSE] = str8_lit("TransposeM4");
|
||||
Find[FUN_FAST_NORM] = str8_lit("Fast"); /* TODO: emit warning, lower precision. */
|
||||
Repl[FUN_FAST_NORM] = str8_lit("");
|
||||
Find[FUN_NORM] = str8_lit("Normalize");
|
||||
Repl[FUN_NORM] = str8_lit("Norm");
|
||||
|
||||
Find[HAND_PERSPECTIVE] = str8_lit("Perspective");
|
||||
Find[HAND_ROTATE] = str8_lit("Rotate");
|
||||
Find[HAND_ORTHO] = str8_lit("Orthographic");
|
||||
Find[HAND_LOOK_AT] = str8_lit("LookAt");
|
||||
Find[HAND_QUAT_AXIS_ANGLE] = str8_lit("FromAxisAngle");
|
||||
Find[HAND_MAT_TO_QUAT] = str8_lit("ToQuaternion");
|
||||
}
|
||||
|
||||
/* Match with a bunch of sliding windows, skipping when there can't be a match */
|
||||
u64 MatchProgress[HAND_Size] = {0};
|
||||
b32 FoundTypePrefix = 0;
|
||||
b32 FoundFunctionPrefix = 0;
|
||||
u32 Line = 1;
|
||||
str8_iter(file_content) {
|
||||
if (c == '\n') {
|
||||
Line++;
|
||||
}
|
||||
if (FoundTypePrefix || FoundFunctionPrefix) {
|
||||
if (chr8_is_whitespace(c)
|
||||
|| str8_contains_char(str8_lit("(){}[]:;,.<>~?!@#$%^&+-*/'\""), c)) {
|
||||
FoundTypePrefix = 0;
|
||||
FoundFunctionPrefix = 0;
|
||||
}
|
||||
}
|
||||
for (u32 t = 0; t < PREFIXES_Size; t++) {
|
||||
if (c == Find[t].str[MatchProgress[t]]) {
|
||||
MatchProgress[t]++;
|
||||
if (MatchProgress[t] == Find[t].len) {
|
||||
if (t == PREFIX_TYPE) {
|
||||
FoundTypePrefix = 1;
|
||||
} else if (t == PREFIX_FUNCTION) {
|
||||
FoundFunctionPrefix = 1;
|
||||
}
|
||||
MatchProgress[t] = 0;
|
||||
}
|
||||
} else {
|
||||
MatchProgress[t] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace hmm_ types */
|
||||
if (FoundTypePrefix) {
|
||||
for (u32 t = PREFIXES_Size+1; t < TYPES_Size; t++) {
|
||||
if (c == Find[t].str[MatchProgress[t]]) {
|
||||
MatchProgress[t]++;
|
||||
if (MatchProgress[t] == Find[t].len) {
|
||||
MatchProgress[t] = 0;
|
||||
printf("\t[%u]: Find: %.*s, Repl: %.*s.\n", Line, str8_PRINTF_ARGS(Find[t]), str8_PRINTF_ARGS(Repl[t]));
|
||||
Str8List_add(arena, &out,
|
||||
str8_first(file_content,
|
||||
i + 1 - (Find[t].len + Find[PREFIX_TYPE].len)));
|
||||
Str8List_add(arena, &out, Repl[PREFIX_TYPE]);
|
||||
Str8List_add(arena, &out, Repl[t]);
|
||||
file_content = str8_skip(file_content, i+1);
|
||||
i = -1;
|
||||
}
|
||||
} else {
|
||||
MatchProgress[t] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If in a HMM_ function, do function name replacements */
|
||||
if (FoundFunctionPrefix) {
|
||||
for (u32 t = TYPES_Size+1; t < FUNCTIONS_Size; t++) {
|
||||
if (c == Find[t].str[MatchProgress[t]]) {
|
||||
MatchProgress[t]++;
|
||||
if (MatchProgress[t] == Find[t].len) {
|
||||
MatchProgress[t] = 0;
|
||||
printf("\t[%u]: Find: %.*s, Repl: %.*s.\n", Line, str8_PRINTF_ARGS(Find[t]), str8_PRINTF_ARGS(Repl[t]));
|
||||
Str8List_add(arena, &out, str8_first(file_content, i + 1 - Find[t].len));
|
||||
Str8List_add(arena, &out, Repl[t]);
|
||||
file_content = str8_skip(file_content, i+1);
|
||||
i = -1;
|
||||
|
||||
/* NOTE(lcf): Special case because Find[] overlaps here */
|
||||
if (t == FUN_R_SQUARE_ROOT) {
|
||||
MatchProgress[FUN_SQUARE_ROOT] = 0;
|
||||
}
|
||||
|
||||
if (t == FUN_LINEAR_COMBINE_SSE) {
|
||||
printf("\t[%u]: HMM_LinearCombineSSE is now HMM_LinearCombineV4M4, and will now use a fallback method when SSE is not available. \n\tYou no longer need to check for the availability of SSE.\n", Line);
|
||||
}
|
||||
|
||||
if (t == FUN_VEC) {
|
||||
/* NOTE(lcf): if pattern is Vec2i, this is now i */
|
||||
c = file_content.str[1];
|
||||
if (c == 'i') {
|
||||
Str8List_add(arena, &out, str8_first(file_content, 1));
|
||||
Str8List_add(arena, &out, str8_lit("I"));
|
||||
file_content = str8_skip(file_content, 2);
|
||||
} else if (c == 'v') {
|
||||
Str8List_add(arena, &out, str8_first(file_content, 1));
|
||||
Str8List_add(arena, &out, str8_lit("V"));
|
||||
file_content = str8_skip(file_content, 2);
|
||||
} else if (c == 'f') {
|
||||
Str8List_add(arena, &out, str8_first(file_content, 1));
|
||||
Str8List_add(arena, &out, str8_lit("F"));
|
||||
file_content = str8_skip(file_content, 2);
|
||||
}
|
||||
} else if (t == FUN_MAT) {
|
||||
/* if pattern is Mat4d, this is now d */
|
||||
c = file_content.str[1];
|
||||
if (c == 'd') {
|
||||
Str8List_add(arena, &out, str8_first(file_content, 1));
|
||||
Str8List_add(arena, &out, str8_lit("D"));
|
||||
file_content = str8_skip(file_content, 2);
|
||||
} else if (c == 'f') {
|
||||
Str8List_add(arena, &out, str8_first(file_content, 1));
|
||||
Str8List_add(arena, &out, str8_lit("F"));
|
||||
file_content = str8_skip(file_content, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MatchProgress[t] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handedness cases. */
|
||||
if (FoundFunctionPrefix) {
|
||||
for (u32 t = FUNCTIONS_Size+1; t < HAND_Size; t++) {
|
||||
if (c == Find[t].str[MatchProgress[t]]) {
|
||||
MatchProgress[t]++;
|
||||
if (MatchProgress[t] == Find[t].len) {
|
||||
MatchProgress[t] = 0;
|
||||
|
||||
chr8 check = file_content.str[i+1];
|
||||
if (check == '(') {
|
||||
printf("\t[%u]: Find: %.*s, Appending: _RH for old default handedness.\n", Line, str8_PRINTF_ARGS(Find[t]));
|
||||
Str8List_add(arena, &out, str8_first(file_content, i + 1));
|
||||
Str8List_add(arena, &out, str8_lit("_RH("));
|
||||
file_content = str8_skip(file_content, i+2);
|
||||
i = -1;
|
||||
|
||||
if (t == HAND_PERSPECTIVE || t == HAND_ROTATE) {
|
||||
printf("\t[%u]: ", Line);
|
||||
if (t == HAND_PERSPECTIVE) {
|
||||
printf("HMM_Perspective_RH()");
|
||||
} else {
|
||||
printf("HMM_Rotate_RH()");
|
||||
}
|
||||
printf(" now takes Radians. Wrapping Degrees with HMM_AngleDeg()\n");
|
||||
u64 end_arg = str8_char_location(file_content, ',');
|
||||
if (end_arg != LCF_STRING_NO_MATCH) {
|
||||
Str8List_add(arena, &out, str8_lit("HMM_AngleDeg("));
|
||||
Str8List_add(arena, &out, str8_first(file_content, end_arg));
|
||||
Str8List_add(arena, &out, str8_lit(")"));
|
||||
file_content = str8_skip(file_content, end_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MatchProgress[t] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Str8List_add(arena, &out, file_content);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void print_usage() {
|
||||
printf("Updates C and C++ source code to use Handmade Math version 2.\n");
|
||||
#ifdef _WIN32
|
||||
printf("Usage: update_hmm.exe <filename> [<filename>...]\n");
|
||||
#else
|
||||
printf("Usage: update_hmm <filename> [<filename>...]\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
Arena *tempa = Arena_create(GB(1));
|
||||
|
||||
if (argc == 1) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 argi = 1;
|
||||
str8 arg = str8_from_cstring(argv[argi]);
|
||||
|
||||
if (arg.len == 2 && (arg.str[1] == 'h' || arg.str[1] == '?')) {
|
||||
print_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; argi < argc; argi++) {
|
||||
arg = str8_from_cstring(argv[argi]);
|
||||
str8 file_content = stdio_load_entire_file(tempa, arg);
|
||||
if (str8_is_empty(file_content)) {
|
||||
printf("X - Invalid file name: %.*s\n\n", str8_PRINTF_ARGS(arg));
|
||||
continue;
|
||||
}
|
||||
printf("O - Updating file: %.*s -------------------\n", str8_PRINTF_ARGS(arg));
|
||||
Str8List result = update_file_content(tempa, file_content);
|
||||
printf("\n");
|
||||
stdio_write_file(arg, result);
|
||||
|
||||
Arena_reset_all(tempa);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
166
update/update_hmm.py
Executable file
166
update/update_hmm.py
Executable file
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
typeReplacements = [
|
||||
('hmm_', 'HMM_'),
|
||||
|
||||
('vec', 'Vec'),
|
||||
('mat', 'Mat'),
|
||||
('quaternion', 'Quaternion'),
|
||||
('bool', 'Bool'),
|
||||
('.InternalElementsSSE', '.SSE'),
|
||||
]
|
||||
|
||||
funcReplacements = [
|
||||
('HMM_', 'HMM_'),
|
||||
|
||||
('Vec', 'V'),
|
||||
('Mat', 'M'),
|
||||
('Quaternion', 'Q'),
|
||||
('Equals', 'Eq'),
|
||||
('Subtract', 'Sub'),
|
||||
('Multiply', 'Mul'),
|
||||
('Divide', 'Div'),
|
||||
('Inverse', 'Inv'),
|
||||
('RSquareRoot', 'InvSqrt'),
|
||||
('SquareRoot', 'Sqrt'),
|
||||
('Squared', 'Sqr'),
|
||||
('Length', 'Len'),
|
||||
|
||||
('Slerp', 'SLerp'),
|
||||
('By', ''),
|
||||
('LinearCombineSSE', 'LinearCombineV4M4'),
|
||||
('Transpose', 'TransposeM4'),
|
||||
('Fast', ''), # TODO(port): emit warning, lower precision
|
||||
('Normalize', 'Norm'),
|
||||
('ToRadians', 'ToRad')
|
||||
]
|
||||
|
||||
handedFuncs = [
|
||||
'Perspective',
|
||||
'Rotate',
|
||||
'Orthographic',
|
||||
'LookAt',
|
||||
'FromAxisAngle',
|
||||
'ToQuaternion',
|
||||
]
|
||||
|
||||
projectionFuncs = [
|
||||
'Perspective',
|
||||
'Orthographic',
|
||||
]
|
||||
|
||||
numFiles = 0
|
||||
numWarnings = 0
|
||||
|
||||
def printWarning(msg):
|
||||
global numWarnings
|
||||
numWarnings += 1
|
||||
print('WARNING: {}'.format(msg))
|
||||
|
||||
def updateFile(filename):
|
||||
global numFiles
|
||||
print('Updating: {}'.format(filename))
|
||||
numFiles += 1
|
||||
result = ''
|
||||
with open(filename, 'r', newline='') as f:
|
||||
for lineNo, line in enumerate(f):
|
||||
updatedLine = line
|
||||
|
||||
def printLineWarning(msg):
|
||||
printWarning(' Line {}: {}'.format(lineNo + 1, msg))
|
||||
|
||||
def replaceName(m):
|
||||
name = m.group()
|
||||
if name.startswith('hmm_'):
|
||||
# do type replacements
|
||||
for before, after in typeReplacements:
|
||||
if before not in name:
|
||||
continue
|
||||
name = name.replace(before, after)
|
||||
else:
|
||||
# do func replacements
|
||||
for before, after in funcReplacements:
|
||||
if before not in name:
|
||||
continue
|
||||
name = name.replace(before, after)
|
||||
|
||||
if after == 'LinearCombineV4M4':
|
||||
printLineWarning('HMM_LinearCombineSSE is now HMM_LinearCombineV4M4, and will now use a fallback method when SSE is not available. You no longer need to check for the availability of SSE.')
|
||||
if after == 'V' or after == 'M':
|
||||
# uppercase the modifier, if any
|
||||
name = re.sub(
|
||||
r'[VM]\d[ivfd]?',
|
||||
lambda m: m.group().upper(),
|
||||
name
|
||||
)
|
||||
# and also nuke the integer constructors
|
||||
vecIntMatch = re.search(r'(V\d)I', name)
|
||||
if vecIntMatch:
|
||||
name = name.replace(vecIntMatch.group(), vecIntMatch.group(1))
|
||||
|
||||
# add handedness / NDC modifiers
|
||||
if not any(x in name for x in ['RH', 'LH', 'NO', 'ZO']):
|
||||
for handedFunc in handedFuncs:
|
||||
suffixed = handedFunc + '_RH'
|
||||
if handedFunc in projectionFuncs:
|
||||
suffixed += '_NO'
|
||||
name = name.replace(handedFunc, suffixed)
|
||||
return name
|
||||
|
||||
def wrapDegrees(m):
|
||||
name = m.group('name')
|
||||
arg = m.group('arg')
|
||||
if '(' in arg:
|
||||
# all bets are off, don't wrap the argument
|
||||
printLineWarning('{} now takes radians, but we were unable to automatically wrap the first argument with HMM_AngleDeg().'.format(name))
|
||||
return m.group()
|
||||
return '{}(HMM_AngleDeg({}),'.format(name, arg)
|
||||
|
||||
updatedLine = re.sub(r'(hmm_|HMM_)\w+', replaceName, updatedLine)
|
||||
updatedLine = re.sub(r'(?P<name>HMM_Perspective_RH_NO|HMM_Rotate_RH)\((?P<arg>.*?),', wrapDegrees, updatedLine)
|
||||
|
||||
result += updatedLine
|
||||
|
||||
with open(filename, 'w', newline='') as f:
|
||||
f.write(result)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog = 'update_hmm',
|
||||
description = 'Updates C and C++ source code to use Handmade Math 2.0.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'filename', nargs='+',
|
||||
help='A file or directory to update to HMM 2.0. If a directory, all files with extensions from --exts will be processed.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--exts', nargs='+', default=['.c', '.cpp', '.h', '.hpp'],
|
||||
help='File extensions to run the script on, when targeting a directory. Default: .c, .cpp, .h, .hpp.',
|
||||
metavar='.foo',
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
for path in args.filename:
|
||||
filenames = []
|
||||
if os.path.isfile(path):
|
||||
filenames = [path]
|
||||
else:
|
||||
for root, dirs, files in os.walk(path):
|
||||
for file in files:
|
||||
if file == 'HandmadeMath.h':
|
||||
printWarning('HandmadeMath.h will not be replaced by this script.')
|
||||
elif file.endswith(tuple(args.exts)):
|
||||
filenames.append(os.path.join(root, file))
|
||||
|
||||
for filename in filenames:
|
||||
try:
|
||||
updateFile(filename)
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
||||
print('Updated {} files with {} warnings.'.format(numFiles, numWarnings))
|
||||
@@ -1,12 +0,0 @@
|
||||
@REM Batch script to run update_hmm.exe on all your code files.
|
||||
@REM Example:
|
||||
@REM "update_hmm_all.bat Code\Project\" -> Recursively update all files/folders in .\Code\Project\
|
||||
|
||||
for /r %1 %%v in (*.c) do update_hmm.exe "%%v"
|
||||
for /r %1 %%v in (*.h) do update_hmm.exe "%%v"
|
||||
for /r %1 %%v in (*.cpp) do update_hmm.exe "%%v"
|
||||
for /r %1 %%v in (*.hpp) do update_hmm.exe "%%v"
|
||||
|
||||
@REM @REM Uncomment for sokol-samples
|
||||
@REM for /r %1 %%v in (*.glsl) do update_hmm.exe "%%v"
|
||||
@REM for /r %1 %%v in (*.hlsl) do update_hmm.exe "%%v"
|
||||
@@ -1,12 +0,0 @@
|
||||
# Bash script to run update_hmm on all your code files.
|
||||
# Example:
|
||||
# "update_hmm_all Code/Project/" -> Recursively update all files/folders in ./Code/Project/
|
||||
echo $1
|
||||
for file in "$1"/*.{c,h,cpp,hpp} "$1"/**/*.{c,h,cpp,hpp} ; do
|
||||
./update_hmm "$file"
|
||||
done
|
||||
|
||||
# # Uncomment for sokol-samples
|
||||
# for file in "$1"/*.{glsl,hlsl} "$1"/**/*.{glsl,hlsl} ; do
|
||||
# ./update_hmm "$file"
|
||||
# done
|
||||
Reference in New Issue
Block a user