From e210d8729be1c7a1ff784474eb3820de60338a37 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 3 Nov 2023 11:34:49 -0500 Subject: [PATCH] Add HMM_RotateV2 --- HandmadeMath.h | 11 ++++++ test/HandmadeTest.h | 4 +- test/categories/MatrixOps.h | 64 ++++++++++++++++---------------- test/categories/Transformation.h | 30 ++++++++++++++- 4 files changed, 74 insertions(+), 35 deletions(-) diff --git a/HandmadeMath.h b/HandmadeMath.h index 641c378..c384272 100644 --- a/HandmadeMath.h +++ b/HandmadeMath.h @@ -2527,6 +2527,17 @@ static inline HMM_Quat HMM_QFromAxisAngle_LH(HMM_Vec3 Axis, float Angle) return HMM_QFromAxisAngle_RH(Axis, -Angle); } +COVERAGE(HMM_RotateV2, 1) +static inline HMM_Vec2 HMM_RotateV2(HMM_Vec2 V, float Angle) +{ + ASSERT_COVERED(HMM_RotateV2) + + float sinA = HMM_SinF(Angle); + float cosA = HMM_CosF(Angle); + + return HMM_V2(V.X * cosA - V.Y * sinA, V.X * sinA + V.Y * cosA); +} + // implementation from // https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/ COVERAGE(HMM_RotateV3Q, 1) diff --git a/test/HandmadeTest.h b/test/HandmadeTest.h index a6c9362..b3ca6c3 100644 --- a/test/HandmadeTest.h +++ b/test/HandmadeTest.h @@ -155,9 +155,9 @@ INITIALIZER(_HMT_COVERCASE_FUNCNAME_INIT(name)) { \ if (diff < -FLT_EPSILON || FLT_EPSILON < diff) { \ _HMT_CASE_FAIL(); \ if ((_msg)[0] == 0) { \ - printf("Expected %f, got %f", (_expected), actual); \ + printf("Expected %f, got %f (error: %.9g)", (_expected), actual, diff); \ } else { \ - printf("%s: Expected %f, got %f", (_msg), (_expected), actual); \ + printf("%s: Expected %f, got %f (error: %.9g)", (_msg), (_expected), actual, diff); \ } \ } \ } diff --git a/test/categories/MatrixOps.h b/test/categories/MatrixOps.h index 4d77fdc..6e6fdf8 100644 --- a/test/categories/MatrixOps.h +++ b/test/categories/MatrixOps.h @@ -129,22 +129,22 @@ TEST(InvMatrix, InvGeneral) float Det = HMM_DeterminantM4(Matrix); EXPECT_FLOAT_EQ(Det, -80.0f); - EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]); - EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]); - EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]); - EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]); - EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]); - EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]); - EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]); - EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]); - EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]); - EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]); - EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]); - EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]); - 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_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.00001f); + EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.00001f); + EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.00001f); + EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.00001f); + EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.00001f); + EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.00001f); + EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.00001f); + EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.00001f); + EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.00001f); + EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.00001f); + EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.00001f); + EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.00001f); + EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.00001f); + EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.00001f); + EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.00001f); + EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.00001f); #ifdef __cplusplus Inverse = HMM_InvGeneral(Matrix); @@ -153,22 +153,22 @@ TEST(InvMatrix, InvGeneral) Det = HMM_Determinant(Matrix); EXPECT_FLOAT_EQ(Det, -80.0f); - EXPECT_FLOAT_EQ(Result.Elements[0][0], Expect.Elements[0][0]); - EXPECT_FLOAT_EQ(Result.Elements[0][1], Expect.Elements[0][1]); - EXPECT_FLOAT_EQ(Result.Elements[0][2], Expect.Elements[0][2]); - EXPECT_FLOAT_EQ(Result.Elements[0][3], Expect.Elements[0][3]); - EXPECT_FLOAT_EQ(Result.Elements[1][0], Expect.Elements[1][0]); - EXPECT_FLOAT_EQ(Result.Elements[1][1], Expect.Elements[1][1]); - EXPECT_FLOAT_EQ(Result.Elements[1][2], Expect.Elements[1][2]); - EXPECT_FLOAT_EQ(Result.Elements[1][3], Expect.Elements[1][3]); - EXPECT_FLOAT_EQ(Result.Elements[2][0], Expect.Elements[2][0]); - EXPECT_FLOAT_EQ(Result.Elements[2][1], Expect.Elements[2][1]); - EXPECT_FLOAT_EQ(Result.Elements[2][2], Expect.Elements[2][2]); - EXPECT_FLOAT_EQ(Result.Elements[2][3], Expect.Elements[2][3]); - 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_NEAR(Result.Elements[0][0], Expect.Elements[0][0], 0.00001f); + EXPECT_NEAR(Result.Elements[0][1], Expect.Elements[0][1], 0.00001f); + EXPECT_NEAR(Result.Elements[0][2], Expect.Elements[0][2], 0.00001f); + EXPECT_NEAR(Result.Elements[0][3], Expect.Elements[0][3], 0.00001f); + EXPECT_NEAR(Result.Elements[1][0], Expect.Elements[1][0], 0.00001f); + EXPECT_NEAR(Result.Elements[1][1], Expect.Elements[1][1], 0.00001f); + EXPECT_NEAR(Result.Elements[1][2], Expect.Elements[1][2], 0.00001f); + EXPECT_NEAR(Result.Elements[1][3], Expect.Elements[1][3], 0.00001f); + EXPECT_NEAR(Result.Elements[2][0], Expect.Elements[2][0], 0.00001f); + EXPECT_NEAR(Result.Elements[2][1], Expect.Elements[2][1], 0.00001f); + EXPECT_NEAR(Result.Elements[2][2], Expect.Elements[2][2], 0.00001f); + EXPECT_NEAR(Result.Elements[2][3], Expect.Elements[2][3], 0.00001f); + EXPECT_NEAR(Result.Elements[3][0], Expect.Elements[3][0], 0.00001f); + EXPECT_NEAR(Result.Elements[3][1], Expect.Elements[3][1], 0.00001f); + EXPECT_NEAR(Result.Elements[3][2], Expect.Elements[3][2], 0.00001f); + EXPECT_NEAR(Result.Elements[3][3], Expect.Elements[3][3], 0.00001f); #endif } diff --git a/test/categories/Transformation.h b/test/categories/Transformation.h index defdbc6..7d37f2a 100644 --- a/test/categories/Transformation.h +++ b/test/categories/Transformation.h @@ -63,7 +63,8 @@ TEST(Transformations, LookAt) { const float abs_error = 0.001f; - { HMM_Mat4 result = HMM_LookAt_RH(HMM_V3(1.0f, 0.0f, 0.0f), HMM_V3(0.0f, 2.0f, 1.0f), HMM_V3(2.0f, 1.0f, 1.0f)); + { + HMM_Mat4 result = HMM_LookAt_RH(HMM_V3(1.0f, 0.0f, 0.0f), HMM_V3(0.0f, 2.0f, 1.0f), HMM_V3(2.0f, 1.0f, 1.0f)); EXPECT_NEAR(result.Elements[0][0], 0.169031f, abs_error); EXPECT_NEAR(result.Elements[0][1], 0.897085f, abs_error); @@ -103,3 +104,30 @@ TEST(Transformations, LookAt) EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error); } } + +TEST(Transformations, RotateV2) +{ + HMM_Vec2 v2 = HMM_V2(1, 2); + + float epsilon = 0.000001f; + { + HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(90)); + EXPECT_NEAR(res.X, -2.0f, epsilon); + EXPECT_NEAR(res.Y, 1.0f, epsilon); + } + { + HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(180)); + EXPECT_NEAR(res.X, -1.0f, epsilon); + EXPECT_NEAR(res.Y, -2.0f, epsilon); + } + { + HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(270)); + EXPECT_NEAR(res.X, 2.0f, epsilon); + EXPECT_NEAR(res.Y, -1.0f, epsilon); + } + { + HMM_Vec2 res = HMM_RotateV2(v2, HMM_AngleDeg(360)); + EXPECT_NEAR(res.X, 1.0f, epsilon); + EXPECT_NEAR(res.Y, 2.0f, epsilon); + } +}