Vec3Tests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. TEST_SUITE("Vec3Tests")
  6. {
  7. TEST_CASE("TestVec3ConstructComponents")
  8. {
  9. Vec3 v(1, 2, 3);
  10. // Test component access
  11. CHECK(v.GetX() == 1);
  12. CHECK(v.GetY() == 2);
  13. CHECK(v.GetZ() == 3);
  14. // Test component access by [] operators
  15. CHECK(v[0] == 1);
  16. CHECK(v[1] == 2);
  17. CHECK(v[2] == 3);
  18. // Test == and != operators
  19. CHECK(v == Vec3(1, 2, 3));
  20. CHECK(v != Vec3(1, 2, 4));
  21. // Set the components
  22. v.SetComponent(0, 4);
  23. v.SetComponent(1, 5);
  24. v.SetComponent(2, 6);
  25. CHECK(v == Vec3(4, 5, 6));
  26. }
  27. TEST_CASE("TestVec3LoadStoreFloat3")
  28. {
  29. float f4[] = { 1, 2, 3, 4 }; // Extra element since we read one too many in sLoadFloat3Unsafe
  30. Float3 &f3 = *(Float3 *)f4;
  31. CHECK(Vec3(f3) == Vec3(1, 2, 3));
  32. CHECK(Vec3::sLoadFloat3Unsafe(f3) == Vec3(1, 2, 3));
  33. Float3 f3_out;
  34. Vec3(1, 2, 3).StoreFloat3(&f3_out);
  35. CHECK(f3 == f3_out);
  36. }
  37. TEST_CASE("TestVec3ConstructVec4")
  38. {
  39. Vec4 v4(1, 2, 3, 4);
  40. CHECK(Vec3(v4) == Vec3(1, 2, 3));
  41. }
  42. TEST_CASE("TestVec3Zero")
  43. {
  44. Vec3 v = Vec3::sZero();
  45. CHECK(v.GetX() == 0);
  46. CHECK(v.GetY() == 0);
  47. CHECK(v.GetZ() == 0);
  48. }
  49. TEST_CASE("TestVec3NaN")
  50. {
  51. Vec3 v = Vec3::sNaN();
  52. CHECK(isnan(v.GetX()));
  53. CHECK(isnan(v.GetY()));
  54. CHECK(isnan(v.GetZ()));
  55. CHECK(v.IsNaN());
  56. v.SetComponent(0, 0);
  57. CHECK(v.IsNaN());
  58. v.SetComponent(1, 0);
  59. CHECK(v.IsNaN());
  60. v.SetComponent(2, 0);
  61. CHECK(!v.IsNaN());
  62. }
  63. TEST_CASE("TestVec3Replicate")
  64. {
  65. CHECK(Vec3::sReplicate(2) == Vec3(2, 2, 2));
  66. }
  67. TEST_CASE("TestVec3MinMax")
  68. {
  69. Vec3 v1(1, 5, 3);
  70. Vec3 v2(4, 2, 6);
  71. Vec3 v3(6, 4, 2);
  72. CHECK(Vec3::sMin(v1, v2) == Vec3(1, 2, 3));
  73. CHECK(Vec3::sMax(v1, v2) == Vec3(4, 5, 6));
  74. CHECK(v1.ReduceMin() == 1);
  75. CHECK(v1.ReduceMax() == 5);
  76. CHECK(v2.ReduceMin() == 2);
  77. CHECK(v2.ReduceMax() == 6);
  78. CHECK(v1.GetLowestComponentIndex() == 0);
  79. CHECK(v1.GetHighestComponentIndex() == 1);
  80. CHECK(v2.GetLowestComponentIndex() == 1);
  81. CHECK(v2.GetHighestComponentIndex() == 2);
  82. CHECK(v3.GetLowestComponentIndex() == 2);
  83. CHECK(v3.GetHighestComponentIndex() == 0);
  84. }
  85. TEST_CASE("TestVec3Clamp")
  86. {
  87. Vec3 v1(1, 2, 3);
  88. Vec3 v2(4, 5, 6);
  89. Vec3 v(-1, 3, 7);
  90. CHECK(Vec3::sClamp(v, v1, v2) == Vec3(1, 3, 6));
  91. }
  92. TEST_CASE("TestVec3Comparisons")
  93. {
  94. CHECK(Vec3::sEquals(Vec3(1, 2, 3), Vec3(1, 4, 3)) == UVec4(0xffffffffU, 0, 0xffffffffU, 0xffffffffU)); // W is always Z for comparisons
  95. CHECK(Vec3::sLess(Vec3(1, 2, 4), Vec3(1, 4, 3)) == UVec4(0, 0xffffffffU, 0, 0));
  96. CHECK(Vec3::sLessOrEqual(Vec3(1, 2, 4), Vec3(1, 4, 3)) == UVec4(0xffffffffU, 0xffffffffU, 0, 0));
  97. CHECK(Vec3::sGreater(Vec3(1, 2, 4), Vec3(1, 4, 3)) == UVec4(0, 0, 0xffffffffU, 0xffffffffU));
  98. CHECK(Vec3::sGreaterOrEqual(Vec3(1, 2, 4), Vec3(1, 4, 3)) == UVec4(0xffffffffU, 0, 0xffffffffU, 0xffffffffU));
  99. }
  100. TEST_CASE("TestVec3FMA")
  101. {
  102. CHECK(Vec3::sFusedMultiplyAdd(Vec3(1, 2, 3), Vec3(4, 5, 6), Vec3(7, 8, 9)) == Vec3(1 * 4 + 7, 2 * 5 + 8, 3 * 6 + 9));
  103. }
  104. TEST_CASE("TestVec3Select")
  105. {
  106. CHECK(Vec3::sSelect(Vec3(1, 2, 3), Vec3(4, 5, 6), UVec4(0x80000000U, 0, 0x80000000U, 0)) == Vec3(4, 2, 6));
  107. CHECK(Vec3::sSelect(Vec3(1, 2, 3), Vec3(4, 5, 6), UVec4(0, 0x80000000U, 0, 0x80000000U)) == Vec3(1, 5, 3));
  108. CHECK(Vec3::sSelect(Vec3(1, 2, 3), Vec3(4, 5, 6), UVec4(0xffffffffU, 0x7fffffffU, 0xffffffffU, 0x7fffffffU)) == Vec3(4, 2, 6));
  109. CHECK(Vec3::sSelect(Vec3(1, 2, 3), Vec3(4, 5, 6), UVec4(0x7fffffffU, 0xffffffffU, 0x7fffffffU, 0xffffffffU)) == Vec3(1, 5, 3));
  110. }
  111. TEST_CASE("TestVec3BitOps")
  112. {
  113. // Test all bit permutations
  114. Vec3 v1(UVec4(0b0011, 0b00110, 0b001100, 0).ReinterpretAsFloat());
  115. Vec3 v2(UVec4(0b0101, 0b01010, 0b010100, 0).ReinterpretAsFloat());
  116. CHECK(Vec3::sOr(v1, v2) == Vec3(UVec4(0b0111, 0b01110, 0b011100, 0).ReinterpretAsFloat()));
  117. CHECK(Vec3::sXor(v1, v2) == Vec3(UVec4(0b0110, 0b01100, 0b011000, 0).ReinterpretAsFloat()));
  118. CHECK(Vec3::sAnd(v1, v2) == Vec3(UVec4(0b0001, 0b00010, 0b000100, 0).ReinterpretAsFloat()));
  119. }
  120. TEST_CASE("TestVec3Close")
  121. {
  122. CHECK(Vec3(1, 2, 3).IsClose(Vec3(1.001f, 2.001f, 3.001f), 1.0e-4f));
  123. CHECK(!Vec3(1, 2, 3).IsClose(Vec3(1.001f, 2.001f, 3.001f), 1.0e-6f));
  124. CHECK(Vec3(1.001f, 0, 0).IsNormalized(1.0e-2f));
  125. CHECK(!Vec3(0, 1.001f, 0).IsNormalized(1.0e-4f));
  126. CHECK(Vec3(-1.0e-7f, 1.0e-7f, 1.0e-8f).IsNearZero());
  127. CHECK(!Vec3(-1.0e-7f, 1.0e-7f, -1.0e-5f).IsNearZero());
  128. }
  129. TEST_CASE("TestVec3Operators")
  130. {
  131. CHECK(-Vec3(1, 2, 3) == Vec3(-1, -2, -3));
  132. Vec3 neg_zero = -Vec3::sZero();
  133. CHECK(neg_zero == Vec3::sZero());
  134. #ifdef JPH_CROSS_PLATFORM_DETERMINISTIC
  135. // When cross platform deterministic, we want to make sure that -0 is represented as 0
  136. UVec4 neg_zero_bin = neg_zero.ReinterpretAsInt();
  137. CHECK(neg_zero_bin.GetX() == 0);
  138. CHECK(neg_zero_bin.GetY() == 0);
  139. CHECK(neg_zero_bin.GetZ() == 0);
  140. #endif // JPH_CROSS_PLATFORM_DETERMINISTIC
  141. CHECK(Vec3(1, 2, 3) + Vec3(4, 5, 6) == Vec3(5, 7, 9));
  142. CHECK(Vec3(1, 2, 3) - Vec3(6, 5, 4) == Vec3(-5, -3, -1));
  143. CHECK(Vec3(1, 2, 3) * Vec3(4, 5, 6) == Vec3(4, 10, 18));
  144. CHECK(Vec3(1, 2, 3) * 2 == Vec3(2, 4, 6));
  145. CHECK(4 * Vec3(1, 2, 3) == Vec3(4, 8, 12));
  146. CHECK(Vec3(1, 2, 3) / 2 == Vec3(0.5f, 1.0f, 1.5f));
  147. CHECK(Vec3(1, 2, 3) / Vec3(2, 8, 24) == Vec3(0.5f, 0.25f, 0.125f));
  148. Vec3 v = Vec3(1, 2, 3);
  149. v *= Vec3(4, 5, 6);
  150. CHECK(v == Vec3(4, 10, 18));
  151. v *= 2;
  152. CHECK(v == Vec3(8, 20, 36));
  153. v /= 2;
  154. CHECK(v == Vec3(4, 10, 18));
  155. v += Vec3(1, 2, 3);
  156. CHECK(v == Vec3(5, 12, 21));
  157. v -= Vec3(1, 2, 3);
  158. CHECK(v == Vec3(4, 10, 18));
  159. CHECK(Vec3(2, 4, 8).Reciprocal() == Vec3(0.5f, 0.25f, 0.125f));
  160. }
  161. TEST_CASE("TestVec3Swizzle")
  162. {
  163. Vec3 v(1, 2, 3);
  164. CHECK(v.SplatX() == Vec4::sReplicate(1));
  165. CHECK(v.SplatY() == Vec4::sReplicate(2));
  166. CHECK(v.SplatZ() == Vec4::sReplicate(3));
  167. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_X, SWIZZLE_X>() == Vec3(1, 1, 1));
  168. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_X, SWIZZLE_Y>() == Vec3(1, 1, 2));
  169. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_X, SWIZZLE_Z>() == Vec3(1, 1, 3));
  170. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_X>() == Vec3(1, 2, 1));
  171. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y>() == Vec3(1, 2, 2));
  172. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z>() == Vec3(1, 2, 3));
  173. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_X>() == Vec3(1, 3, 1));
  174. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Y>() == Vec3(1, 3, 2));
  175. CHECK(v.Swizzle<SWIZZLE_X, SWIZZLE_Z, SWIZZLE_Z>() == Vec3(1, 3, 3));
  176. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_X>() == Vec3(2, 1, 1));
  177. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_Y>() == Vec3(2, 1, 2));
  178. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_X, SWIZZLE_Z>() == Vec3(2, 1, 3));
  179. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_X>() == Vec3(2, 2, 1));
  180. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y>() == Vec3(2, 2, 2));
  181. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Z>() == Vec3(2, 2, 3));
  182. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>() == Vec3(2, 3, 1));
  183. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Y>() == Vec3(2, 3, 2));
  184. CHECK(v.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z>() == Vec3(2, 3, 3));
  185. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_X>() == Vec3(3, 1, 1));
  186. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>() == Vec3(3, 1, 2));
  187. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Z>() == Vec3(3, 1, 3));
  188. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>() == Vec3(3, 2, 1));
  189. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_Y>() == Vec3(3, 2, 2));
  190. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_Z>() == Vec3(3, 2, 3));
  191. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_X>() == Vec3(3, 3, 1));
  192. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Y>() == Vec3(3, 3, 2));
  193. CHECK(v.Swizzle<SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z>() == Vec3(3, 3, 3));
  194. }
  195. TEST_CASE("TestVec3Abs")
  196. {
  197. CHECK(Vec3(1, -2, 3).Abs() == Vec3(1, 2, 3));
  198. CHECK(Vec3(-1, 2, -3).Abs() == Vec3(1, 2, 3));
  199. }
  200. TEST_CASE("TestVec3Dot")
  201. {
  202. CHECK(Vec3(1, 2, 3).Dot(Vec3(4, 5, 6)) == float(1 * 4 + 2 * 5 + 3 * 6));
  203. CHECK(Vec3(1, 2, 3).DotV(Vec3(4, 5, 6)) == Vec3::sReplicate(1 * 4 + 2 * 5 + 3 * 6));
  204. CHECK(Vec3(1, 2, 3).DotV4(Vec3(4, 5, 6)) == Vec4::sReplicate(1 * 4 + 2 * 5 + 3 * 6));
  205. }
  206. TEST_CASE("TestVec3Length")
  207. {
  208. CHECK(Vec3(1, 2, 3).LengthSq() == float(1 + 4 + 9));
  209. CHECK(Vec3(1, 2, 3).Length() == sqrt(float(1 + 4 + 9)));
  210. }
  211. TEST_CASE("TestVec3Sqrt")
  212. {
  213. CHECK_APPROX_EQUAL(Vec3(13, 15, 17).Sqrt(), Vec3(sqrt(13.0f), sqrt(15.0f), sqrt(17.0f)));
  214. }
  215. TEST_CASE("TestVec3Cross")
  216. {
  217. CHECK(Vec3(1, 0, 0).Cross(Vec3(0, 1, 0)) == Vec3(0, 0, 1));
  218. CHECK(Vec3(0, 1, 0).Cross(Vec3(1, 0, 0)) == Vec3(0, 0, -1));
  219. CHECK(Vec3(0, 1, 0).Cross(Vec3(0, 0, 1)) == Vec3(1, 0, 0));
  220. CHECK(Vec3(0, 0, 1).Cross(Vec3(0, 1, 0)) == Vec3(-1, 0, 0));
  221. CHECK(Vec3(0, 0, 1).Cross(Vec3(1, 0, 0)) == Vec3(0, 1, 0));
  222. CHECK(Vec3(1, 0, 0).Cross(Vec3(0, 0, 1)) == Vec3(0, -1, 0));
  223. }
  224. TEST_CASE("TestVec3Normalize")
  225. {
  226. CHECK(Vec3(3, 2, 1).Normalized() == Vec3(3, 2, 1) / sqrt(9.0f + 4.0f + 1.0f));
  227. CHECK(Vec3(3, 2, 1).NormalizedOr(Vec3(1, 2, 3)) == Vec3(3, 2, 1) / sqrt(9.0f + 4.0f + 1.0f));
  228. CHECK(Vec3::sZero().NormalizedOr(Vec3(1, 2, 3)) == Vec3(1, 2, 3));
  229. }
  230. TEST_CASE("TestVec3Cast")
  231. {
  232. CHECK(UVec4::sEquals(Vec3(1, 2, 3).ToInt(), UVec4(1, 2, 3, 0)).TestAllXYZTrue());
  233. CHECK(UVec4::sEquals(Vec3(1, 2, 3).ReinterpretAsInt(), UVec4(0x3f800000U, 0x40000000U, 0x40400000U, 0)).TestAllXYZTrue());
  234. }
  235. TEST_CASE("TestVec3NormalizedPerpendicular")
  236. {
  237. UnitTestRandom random;
  238. uniform_real_distribution<float> one_to_ten(1.0f, 10.0f);
  239. for (int i = 0; i < 100; ++i)
  240. {
  241. Vec3 v = Vec3::sRandom(random);
  242. CHECK(v.IsNormalized());
  243. v *= one_to_ten(random);
  244. Vec3 p = v.GetNormalizedPerpendicular();
  245. CHECK(p.IsNormalized());
  246. CHECK(abs(v.Dot(p)) < 1.0e-6f);
  247. }
  248. }
  249. TEST_CASE("TestVec3Sign")
  250. {
  251. CHECK(Vec3(1.2345f, -6.7891f, 0).GetSign() == Vec3(1, -1, 1));
  252. CHECK(Vec3(0, 2.3456f, -7.8912f).GetSign() == Vec3(1, 1, -1));
  253. }
  254. #ifdef JPH_FLOATING_POINT_EXCEPTIONS_ENABLED
  255. TEST_CASE("TestVec3SyncW")
  256. {
  257. {
  258. // Check that W equals Z
  259. Vec3 v(1, 2, 3);
  260. CHECK(Vec4(v) == Vec4(1, 2, 3, 3));
  261. }
  262. {
  263. // Check that setting individual components syncs W and Z
  264. Vec3 v;
  265. v.SetComponent(2, 3);
  266. v.SetComponent(1, 2);
  267. v.SetComponent(0, 1);
  268. CHECK(v == Vec3(1, 2, 3));
  269. CHECK(Vec4(v) == Vec4(1, 2, 3, 3));
  270. }
  271. {
  272. // Check that W and Z are still synced after a simple addition
  273. CHECK(Vec4(Vec3(1, 2, 3) + Vec3(4, 5, 6)) == Vec4(5, 7, 9, 9));
  274. }
  275. {
  276. // Test that casting a Vec4 to Vec3 syncs W and Z
  277. CHECK(Vec4(Vec3(Vec4(1, 2, 3, 4))) == Vec4(1, 2, 3, 3));
  278. }
  279. {
  280. // Test that loading from Float3 syncs W and Z
  281. CHECK(Vec4(Vec3(Float3(1, 2, 3))) == Vec4(1, 2, 3, 3));
  282. }
  283. {
  284. // Test that loading unsafe from Float3 syncs W and Z
  285. Float4 v(1, 2, 3, 4);
  286. CHECK(Vec4(Vec3::sLoadFloat3Unsafe(*(Float3 *)&v)) == Vec4(1, 2, 3, 3));
  287. }
  288. {
  289. // Test swizzle syncs W and Z
  290. CHECK(Vec4(Vec3(1, 2, 3).Swizzle<SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>()) == Vec4(3, 2, 1, 1));
  291. }
  292. {
  293. // Test cross product syncs W and Z
  294. CHECK(Vec4(Vec3(1, 0, 0).Cross(Vec3(0, 1, 0))) == Vec4(0, 0, 1, 1));
  295. CHECK(Vec4(Vec3(0, 1, 0).Cross(Vec3(0, 0, 1))) == Vec4(1, 0, 0, 0));
  296. }
  297. }
  298. #endif // JPH_FLOATING_POINT_EXCEPTIONS_ENABLED
  299. }