Skip to content

Commit a324945

Browse files
committed
Add unit tests for most q_math transform_t functions
And fix a bug in one implementation of TransInsScale (this function is not used in the codebase). These transform_t functions deal with composing rotation, translation, and scale operations. So transform_t represents a similarity-preserving transformation. All of the q_math transform functions get a test, except the 3 that have to do with interpolation (I'm not sure how that is supposed to work).
1 parent e8ed3cc commit a324945

File tree

4 files changed

+228
-12
lines changed

4 files changed

+228
-12
lines changed

src.cmake

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ if (DAEMON_PARENT_SCOPE_DIR)
8686
set(COMMONLIST ${COMMONLIST} PARENT_SCOPE)
8787
endif()
8888

89+
# Tests for code shared by engine and gamelogic
90+
set(COMMONTESTLIST
91+
${LIB_DIR}/tinyformat/TinyformatTest.cpp
92+
${COMMON_DIR}/ColorTest.cpp
93+
${COMMON_DIR}/FileSystemTest.cpp
94+
${COMMON_DIR}/StringTest.cpp
95+
${COMMON_DIR}/cm/unittest.cpp
96+
${COMMON_DIR}/MathTest.cpp
97+
${COMMON_DIR}/UtilTest.cpp
98+
${ENGINE_DIR}/qcommon/q_math_test.cpp
99+
)
100+
89101
set(RENDERERLIST
90102
${ENGINE_DIR}/renderer/DetectGLVendors.cpp
91103
${ENGINE_DIR}/renderer/DetectGLVendors.h
@@ -279,15 +291,8 @@ else()
279291
)
280292
endif()
281293

282-
# Tests for engine-lib
283-
set(ENGINETESTLIST
284-
${LIB_DIR}/tinyformat/TinyformatTest.cpp
285-
${COMMON_DIR}/ColorTest.cpp
286-
${COMMON_DIR}/FileSystemTest.cpp
287-
${COMMON_DIR}/StringTest.cpp
288-
${COMMON_DIR}/cm/unittest.cpp
289-
${COMMON_DIR}/MathTest.cpp
290-
${COMMON_DIR}/UtilTest.cpp
294+
# Tests runnable for any engine variant
295+
set(ENGINETESTLIST ${COMMONTESTLIST}
291296
${ENGINE_DIR}/framework/CommandSystemTest.cpp
292297
)
293298

src/engine/qcommon/q_math.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3279,9 +3279,9 @@ void TransAddScale( float factor, transform_t *t )
32793279
void TransInsTranslation( const vec3_t vec, transform_t *t )
32803280
{
32813281
vec3_t tmp;
3282-
3283-
TransformPoint( t, vec, tmp );
3284-
VectorAdd( t->trans, tmp, t->trans );
3282+
QuatTransformVector( t->rot, vec, tmp );
3283+
VectorScale( tmp, t->scale, tmp );
3284+
VectorAdd( tmp, t->trans, t->trans );
32853285
}
32863286

32873287
// add a translation at the end of an existing transformation

src/engine/qcommon/q_math_test.cpp

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
===========================================================================
3+
Daemon BSD Source Code
4+
Copyright (c) 2024, Daemon Developers
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
* Redistributions of source code must retain the above copyright
10+
notice, this list of conditions and the following disclaimer.
11+
* Redistributions in binary form must reproduce the above copyright
12+
notice, this list of conditions and the following disclaimer in the
13+
documentation and/or other materials provided with the distribution.
14+
* Neither the name of the Daemon developers nor the
15+
names of its contributors may be used to endorse or promote products
16+
derived from this software without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY
22+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
===========================================================================
29+
*/
30+
31+
#include <gtest/gtest.h>
32+
#include <gmock/gmock.h>
33+
34+
#include "common/Common.h"
35+
36+
// TODO: add transform tests with quats with negative real component
37+
// the calculator I used always made it positive
38+
39+
namespace {
40+
41+
using ::testing::Pointwise;
42+
using ::testing::FloatNear;
43+
44+
// Using a function for this in case we want to change how transform_t is set
45+
// to avoid undefined behaviors with the union
46+
transform_t MakeTransform(
47+
const std::array<float, 4>& quat,
48+
const std::array<float, 3>& translation,
49+
float scale)
50+
{
51+
transform_t t;
52+
Vector4Copy(quat, t.rot);
53+
VectorCopy(translation, t.trans);
54+
t.scale = scale;
55+
return t;
56+
}
57+
58+
void ExpectTransformEqual(
59+
const transform_t& t,
60+
const std::array<float, 4>& expectedQuat,
61+
const std::array<float, 3>& expectedTranslation,
62+
float expectedScale)
63+
{
64+
const char* base = reinterpret_cast<const char*>(&t);
65+
std::array<float, 4> actualQuat;
66+
std::array<float, 3> actualTranslation;
67+
float actualScale;
68+
memcpy(&actualQuat, base + offsetof(transform_t, rot), sizeof(actualQuat));
69+
memcpy(&actualTranslation, base + offsetof(transform_t, trans), sizeof(actualTranslation));
70+
memcpy(&actualScale, base + offsetof(transform_t, scale), sizeof(actualScale));
71+
EXPECT_THAT(actualQuat, Pointwise(FloatNear(1e-4), expectedQuat));
72+
EXPECT_THAT(actualTranslation, Pointwise(FloatNear(1e-3), expectedTranslation));
73+
EXPECT_THAT(actualScale, FloatNear(1e-5, expectedScale));
74+
}
75+
76+
TEST(QMathTransformTest, TransInit)
77+
{
78+
transform_t t;
79+
TransInit(&t);
80+
ExpectTransformEqual(t, {0, 0, 0, 1}, {0, 0, 0}, 1);
81+
}
82+
83+
TEST(QMathTransformTest, TransformPoint)
84+
{
85+
transform_t t = MakeTransform(
86+
{0.3155654, 0.121273, 0.7211766, 0.6046616}, {-11, -26, 55}, 1.2);
87+
const vec3_t pointIn = {12, 19, -30};
88+
vec3_t pointOut;
89+
TransformPoint(&t, pointIn, pointOut);
90+
const vec3_t expectedPoint = {-51.8073, -10.3551, 44.3603};
91+
EXPECT_THAT(pointOut, Pointwise(FloatNear(0.001), expectedPoint));
92+
}
93+
94+
TEST(QMathTransformTest, TransformNormalVector)
95+
{
96+
const transform_t t = MakeTransform(
97+
{0.1641059, -0.6753088, 0.2253332, -0.6828266}, {235, 52, 42}, 8);
98+
const vec3_t vector = { 0.48, 0.64, 0.6 };
99+
vec3_t transformedVector;
100+
TransformNormalVector(&t, vector, transformedVector);
101+
const vec3_t expectedVector = {0.6462654,0.2383020,-0.7249505};
102+
EXPECT_THAT(transformedVector, Pointwise(FloatNear(1e-6), expectedVector));
103+
}
104+
105+
TEST(QMathTransformTest, TransInitRotationQuat)
106+
{
107+
const quat_t q = { -0.1423769, 0.5422508, 0.7235357, -0.402727 };
108+
transform_t t;
109+
TransInitRotationQuat(q, &t);
110+
ExpectTransformEqual(t, {-0.1423769, 0.5422508, 0.7235357, -0.402727}, {0, 0, 0}, 1);
111+
}
112+
113+
TEST(QMathTransformTest, TransInitTranslation)
114+
{
115+
const vec3_t translation = {-9, -32, -0.5};
116+
transform_t t;
117+
TransInitTranslation(translation, &t);
118+
ExpectTransformEqual(t, {0, 0, 0, 1}, {-9, -32, -0.5}, 1);
119+
}
120+
121+
TEST(QMathTransformTest, TransInitScale)
122+
{
123+
transform_t t;
124+
TransInitScale(4.3, &t);
125+
ExpectTransformEqual(t, {0, 0, 0, 1}, {0, 0, 0}, 4.3);
126+
}
127+
128+
TEST(QMathTransformTest, TransInsRotationQuat)
129+
{
130+
const quat_t q = {0.3694065, -0.6226631, 0.1538449, -0.6724294};
131+
transform_t t = MakeTransform(
132+
{-0.5881667, -0.3748035, 0.6614826, 0.2757227}, {1.8, -1.8, -4}, 3);
133+
TransInsRotationQuat(q, &t);
134+
ExpectTransformEqual(t, {0.8515735, 0.4151890, 0.1023027, -0.3032735}, {1.8, -1.8, -4}, 3);
135+
}
136+
137+
TEST(QMathTransformTest, TransAddRotationQuat)
138+
{
139+
const quat_t rot = {-0.4217441, -0.6010819, -0.3683214, -0.5702384};
140+
transform_t t = MakeTransform(
141+
{-0.1167623, -0.9282776, 0.3395844, 0.096694}, {12.5, 93.7, -14.1}, 2.9);
142+
TransAddRotationQuat(rot, &t);
143+
ExpectTransformEqual(t, {-0.5202203, 0.6574423, 0.09205336, -0.5372771},
144+
{-5.823749, 47.07177, 82.97640}, 2.9);
145+
}
146+
147+
TEST(QMathTransformTest, TransInsScale)
148+
{
149+
transform_t t = MakeTransform(
150+
{-0.8678937, 0.0774454, -0.2533126, -0.4202326}, {25, 25, 17}, 4.6);
151+
TransInsScale(3, &t);
152+
ExpectTransformEqual(t,
153+
{-0.8678937, 0.0774454, -0.2533126, -0.4202326}, {25, 25, 17}, 13.8);
154+
}
155+
156+
TEST(QMathTransformTest, TransAddScale)
157+
{
158+
transform_t t = MakeTransform(
159+
{-0.9884186, -0.0914321, 0.1088879, 0.053031}, {-9, -12, -70}, 6);
160+
TransAddScale(1.2, &t);
161+
ExpectTransformEqual(t,
162+
{-0.9884186, -0.0914321, 0.1088879, 0.053031}, {-10.8, -14.4, -84}, 7.2);
163+
}
164+
165+
TEST(QMathTransformTest, TransInsTranslation)
166+
{
167+
const vec3_t translation = {3.6, 20, 5.3};
168+
transform_t t = MakeTransform(
169+
{0.5002998, 0.3780266, 0.7196359, 0.2981948}, {-8, 28, 27}, 5.5);
170+
TransInsTranslation(translation, &t);
171+
ExpectTransformEqual(t,
172+
{0.5002998, 0.3780266, 0.7196359, 0.2981948}, {7.592672, -7.848988, 135.6898}, 5.5);
173+
}
174+
175+
TEST(QMathTransformTest, TransAddTranslation)
176+
{
177+
const vec3_t translation = { 18, -1.1, -6};
178+
transform_t t = MakeTransform(
179+
{0.3917585, -0.3411706, -0.1357459, 0.8436237}, {-23, 56, 52}, 4);
180+
TransAddTranslation(translation, &t);
181+
ExpectTransformEqual(t,
182+
{0.3917585, -0.3411706, -0.1357459, 0.8436237}, {-5, 54.9, 46}, 4);
183+
}
184+
185+
TEST(QMathTransformTest, TransCombine)
186+
{
187+
const transform_t left = MakeTransform(
188+
{-0.5029552, 0.4741776, -0.5393551, 0.4809239}, {-3, -50, 7}, 1.9);
189+
const transform_t right = MakeTransform(
190+
{0.4461722, 0.8836869, 0.1121932, -0.0862585}, {-25, 11, 16}, 1.6);
191+
transform_t combined;
192+
TransCombine(&right, &left, &combined);
193+
ExpectTransformEqual(combined,
194+
{0.7877796, 0.1998672, -0.5555394, -0.1755917}, {29.72799, -5.378298, -16.55849}, 3.04);
195+
}
196+
197+
TEST(QMathTransformTest, TransInverse)
198+
{
199+
const transform_t t = MakeTransform(
200+
{0.4833702, -0.42157, -0.7551386, -0.1356377}, {2.5, 3.4, 1.4}, 2.5);
201+
transform_t inverse;
202+
TransInverse(&t, &inverse);
203+
// This quat multiplied by -1 would also be acceptable
204+
ExpectTransformEqual(inverse,
205+
{-0.4833702, 0.42157, 0.7551386, -0.1356377}, {1.244436,1.155842,-0.5278334}, 0.4);
206+
}
207+
208+
} // namespace

src/engine/qcommon/q_shared.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,7 @@ inline vec_t VectorNormalize2( const vec3_t v, vec3_t out )
11971197
return sseLoadInts( vec.data() );
11981198
}
11991199

1200+
// returns the dot product in all 4 elements
12001201
inline __m128 sseDot4( __m128 a, __m128 b ) {
12011202
__m128 prod = _mm_mul_ps( a, b );
12021203
__m128 sum1 = _mm_add_ps( prod, sseSwizzle( prod, YXWZ ) );
@@ -1391,6 +1392,8 @@ inline vec_t VectorNormalize2( const vec3_t v, vec3_t out )
13911392
void TransInsTranslation( const vec3_t vec, transform_t *t );
13921393
void TransAddTranslation( const vec3_t vec, transform_t *t );
13931394

1395+
// "a" is the first one that would be applied to a vector
1396+
// so as a matrix multiplication this is B * A
13941397
void TransCombine( const transform_t *a, const transform_t *b,
13951398
transform_t *c );
13961399
void TransInverse( const transform_t *in, transform_t *out );

0 commit comments

Comments
 (0)