jolt-ruby 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitmodules +3 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +228 -0
  5. data/Rakefile +180 -0
  6. data/examples/character_virtual.rb +35 -0
  7. data/examples/falling_sphere.rb +25 -0
  8. data/examples/stagecraft_binding.rb +29 -0
  9. data/ext/jolt_ruby/CMakeLists.txt +42 -0
  10. data/ext/jolt_ruby/character_helper.cpp +44 -0
  11. data/ext/jolt_ruby/constraint_helper.cpp +154 -0
  12. data/ext/jolt_ruby/extconf.rb +56 -0
  13. data/ext/jolt_ruby/helper.cpp +225 -0
  14. data/ext/jolt_ruby/helper.h +103 -0
  15. data/ext/joltc/.github/FUNDING.yml +1 -0
  16. data/ext/joltc/.github/workflows/build.yml +298 -0
  17. data/ext/joltc/.gitignore +272 -0
  18. data/ext/joltc/CMakeLists.txt +431 -0
  19. data/ext/joltc/LICENSE +21 -0
  20. data/ext/joltc/README.md +10 -0
  21. data/ext/joltc/build/cmake_vs2026_arm64.bat +3 -0
  22. data/ext/joltc/build/cmake_vs2026_clang.bat +10 -0
  23. data/ext/joltc/build/cmake_vs2026_x64.bat +3 -0
  24. data/ext/joltc/build/cmake_vs2026_x64_double.bat +3 -0
  25. data/ext/joltc/include/joltc.h +3166 -0
  26. data/ext/joltc/samples/01_HelloWorld/main.cpp +170 -0
  27. data/ext/joltc/samples/CMakeLists.txt +35 -0
  28. data/ext/joltc/src/joltc.c +4 -0
  29. data/ext/joltc/src/joltc.cpp +11812 -0
  30. data/ext/joltc/src/joltc_assert.cpp +271 -0
  31. data/ext/joltc/tests/CMakeLists.txt +77 -0
  32. data/ext/joltc/tests/test_character.cpp +149 -0
  33. data/ext/joltc/tests/test_collision.cpp +146 -0
  34. data/ext/joltc/tests/test_constraints.cpp +353 -0
  35. data/ext/joltc/tests/test_core.cpp +94 -0
  36. data/ext/joltc/tests/test_math.cpp +585 -0
  37. data/ext/joltc/tests/test_physics_system.cpp +465 -0
  38. data/ext/joltc/tests/test_shapes.cpp +789 -0
  39. data/ext/joltc/tests/test_skeleton.cpp +370 -0
  40. data/ext/joltc/tests/test_vehicle.cpp +319 -0
  41. data/generator/generate.rb +237 -0
  42. data/generator/layout_probe.cpp +489 -0
  43. data/generator/verify_layout.rb +32 -0
  44. data/lib/jolt/body.rb +147 -0
  45. data/lib/jolt/body_collection.rb +115 -0
  46. data/lib/jolt/body_dynamics.rb +93 -0
  47. data/lib/jolt/character_virtual.rb +162 -0
  48. data/lib/jolt/constraint.rb +136 -0
  49. data/lib/jolt/constraint_collection.rb +123 -0
  50. data/lib/jolt/contact_events.rb +19 -0
  51. data/lib/jolt/conversions.rb +76 -0
  52. data/lib/jolt/errors.rb +12 -0
  53. data/lib/jolt/fixed_stepper.rb +37 -0
  54. data/lib/jolt/hit.rb +5 -0
  55. data/lib/jolt/layers.rb +182 -0
  56. data/lib/jolt/native/character_functions.rb +16 -0
  57. data/lib/jolt/native/constraint_functions.rb +27 -0
  58. data/lib/jolt/native/core_functions.rb +17 -0
  59. data/lib/jolt/native/generated.rb +1995 -0
  60. data/lib/jolt/native/platform.rb +51 -0
  61. data/lib/jolt/native/query_functions.rb +43 -0
  62. data/lib/jolt/native/types.rb +28 -0
  63. data/lib/jolt/native.rb +94 -0
  64. data/lib/jolt/shape.rb +90 -0
  65. data/lib/jolt/shape_builders.rb +155 -0
  66. data/lib/jolt/system.rb +238 -0
  67. data/lib/jolt/system_characters.rb +25 -0
  68. data/lib/jolt/system_constraints.rb +36 -0
  69. data/lib/jolt/system_contacts.rb +57 -0
  70. data/lib/jolt/system_queries.rb +111 -0
  71. data/lib/jolt/transform.rb +5 -0
  72. data/lib/jolt/version.rb +5 -0
  73. data/lib/jolt.rb +83 -0
  74. data/script/smoke_gem.rb +29 -0
  75. data/script/verify_release.rb +36 -0
  76. metadata +147 -0
@@ -0,0 +1,370 @@
1
+ // Copyright (c) Amer Koleci and Contributors.
2
+ // Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
3
+
4
+ #include <gtest/gtest.h>
5
+ #include "joltc.h"
6
+
7
+ namespace BroadPhaseLayers {
8
+ static constexpr JPH_BroadPhaseLayer NON_MOVING = 0;
9
+ static constexpr JPH_BroadPhaseLayer MOVING = 1;
10
+ static constexpr uint32_t NUM_LAYERS = 2;
11
+ }
12
+
13
+ namespace ObjectLayers {
14
+ static constexpr JPH_ObjectLayer NON_MOVING = 0;
15
+ static constexpr JPH_ObjectLayer MOVING = 1;
16
+ static constexpr uint32_t NUM_LAYERS = 2;
17
+ }
18
+
19
+ class SkeletonTest : public ::testing::Test {
20
+ protected:
21
+ JPH_PhysicsSystem* physicsSystem = nullptr;
22
+ JPH_BroadPhaseLayerInterface* bpLayer = nullptr;
23
+ JPH_ObjectLayerPairFilter* objPairFilter = nullptr;
24
+ JPH_ObjectVsBroadPhaseLayerFilter* objVsBpFilter = nullptr;
25
+
26
+ void SetUp() override {
27
+ ASSERT_TRUE(JPH_Init());
28
+
29
+ bpLayer = JPH_BroadPhaseLayerInterfaceTable_Create(ObjectLayers::NUM_LAYERS, BroadPhaseLayers::NUM_LAYERS);
30
+ JPH_BroadPhaseLayerInterfaceTable_MapObjectToBroadPhaseLayer(bpLayer, ObjectLayers::NON_MOVING, BroadPhaseLayers::NON_MOVING);
31
+ JPH_BroadPhaseLayerInterfaceTable_MapObjectToBroadPhaseLayer(bpLayer, ObjectLayers::MOVING, BroadPhaseLayers::MOVING);
32
+
33
+ objPairFilter = JPH_ObjectLayerPairFilterTable_Create(ObjectLayers::NUM_LAYERS);
34
+ JPH_ObjectLayerPairFilterTable_EnableCollision(objPairFilter, ObjectLayers::NON_MOVING, ObjectLayers::MOVING);
35
+ JPH_ObjectLayerPairFilterTable_EnableCollision(objPairFilter, ObjectLayers::MOVING, ObjectLayers::MOVING);
36
+
37
+ objVsBpFilter = JPH_ObjectVsBroadPhaseLayerFilterTable_Create(
38
+ bpLayer, BroadPhaseLayers::NUM_LAYERS,
39
+ objPairFilter, ObjectLayers::NUM_LAYERS);
40
+
41
+ JPH_PhysicsSystemSettings settings = {};
42
+ settings.maxBodies = 1024;
43
+ settings.maxBodyPairs = 1024;
44
+ settings.maxContactConstraints = 1024;
45
+ settings.broadPhaseLayerInterface = bpLayer;
46
+ settings.objectVsBroadPhaseLayerFilter = objVsBpFilter;
47
+ settings.objectLayerPairFilter = objPairFilter;
48
+
49
+ physicsSystem = JPH_PhysicsSystem_Create(&settings);
50
+ }
51
+
52
+ void TearDown() override {
53
+ if (physicsSystem) JPH_PhysicsSystem_Destroy(physicsSystem);
54
+ JPH_Shutdown();
55
+ }
56
+ };
57
+
58
+ // ============================================================================
59
+ // Skeleton Tests
60
+ // ============================================================================
61
+
62
+ TEST_F(SkeletonTest, Skeleton_Create) {
63
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
64
+ ASSERT_NE(skeleton, nullptr);
65
+
66
+ EXPECT_EQ(JPH_Skeleton_GetJointCount(skeleton), 0);
67
+
68
+ JPH_Skeleton_Destroy(skeleton);
69
+ }
70
+
71
+ TEST_F(SkeletonTest, Skeleton_AddJoint) {
72
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
73
+
74
+ uint32_t rootIndex = JPH_Skeleton_AddJoint(skeleton, "root");
75
+ EXPECT_EQ(rootIndex, 0u);
76
+ EXPECT_EQ(JPH_Skeleton_GetJointCount(skeleton), 1);
77
+
78
+ uint32_t childIndex = JPH_Skeleton_AddJoint2(skeleton, "child", 0);
79
+ EXPECT_EQ(childIndex, 1u);
80
+ EXPECT_EQ(JPH_Skeleton_GetJointCount(skeleton), 2);
81
+
82
+ JPH_Skeleton_Destroy(skeleton);
83
+ }
84
+
85
+ TEST_F(SkeletonTest, Skeleton_AddJointByName) {
86
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
87
+
88
+ JPH_Skeleton_AddJoint(skeleton, "root");
89
+ uint32_t childIndex = JPH_Skeleton_AddJoint3(skeleton, "child", "root");
90
+ EXPECT_EQ(childIndex, 1u);
91
+
92
+ JPH_Skeleton_Destroy(skeleton);
93
+ }
94
+
95
+ TEST_F(SkeletonTest, Skeleton_GetJoint) {
96
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
97
+
98
+ JPH_Skeleton_AddJoint(skeleton, "root");
99
+ JPH_Skeleton_AddJoint2(skeleton, "spine", 0);
100
+
101
+ JPH_SkeletonJoint joint;
102
+ JPH_Skeleton_GetJoint(skeleton, 0, &joint);
103
+ EXPECT_STREQ(joint.name, "root");
104
+ EXPECT_EQ(joint.parentJointIndex, -1);
105
+
106
+ JPH_Skeleton_GetJoint(skeleton, 1, &joint);
107
+ EXPECT_STREQ(joint.name, "spine");
108
+ EXPECT_EQ(joint.parentJointIndex, 0);
109
+
110
+ JPH_Skeleton_Destroy(skeleton);
111
+ }
112
+
113
+ TEST_F(SkeletonTest, Skeleton_GetJointIndex) {
114
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
115
+
116
+ JPH_Skeleton_AddJoint(skeleton, "root");
117
+ JPH_Skeleton_AddJoint2(skeleton, "spine", 0);
118
+ JPH_Skeleton_AddJoint2(skeleton, "head", 1);
119
+
120
+ EXPECT_EQ(JPH_Skeleton_GetJointIndex(skeleton, "root"), 0);
121
+ EXPECT_EQ(JPH_Skeleton_GetJointIndex(skeleton, "spine"), 1);
122
+ EXPECT_EQ(JPH_Skeleton_GetJointIndex(skeleton, "head"), 2);
123
+ EXPECT_EQ(JPH_Skeleton_GetJointIndex(skeleton, "nonexistent"), -1);
124
+
125
+ JPH_Skeleton_Destroy(skeleton);
126
+ }
127
+
128
+ TEST_F(SkeletonTest, Skeleton_JointsCorrectlyOrdered) {
129
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
130
+
131
+ JPH_Skeleton_AddJoint(skeleton, "root");
132
+ JPH_Skeleton_AddJoint2(skeleton, "child", 0);
133
+
134
+ EXPECT_TRUE(JPH_Skeleton_AreJointsCorrectlyOrdered(skeleton));
135
+
136
+ JPH_Skeleton_Destroy(skeleton);
137
+ }
138
+
139
+ // ============================================================================
140
+ // SkeletonPose Tests
141
+ // ============================================================================
142
+
143
+ TEST_F(SkeletonTest, SkeletonPose_Create) {
144
+ JPH_SkeletonPose* pose = JPH_SkeletonPose_Create();
145
+ ASSERT_NE(pose, nullptr);
146
+
147
+ JPH_SkeletonPose_Destroy(pose);
148
+ }
149
+
150
+ TEST_F(SkeletonTest, SkeletonPose_SetSkeleton) {
151
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
152
+ JPH_Skeleton_AddJoint(skeleton, "root");
153
+ JPH_Skeleton_AddJoint2(skeleton, "child", 0);
154
+
155
+ JPH_SkeletonPose* pose = JPH_SkeletonPose_Create();
156
+ JPH_SkeletonPose_SetSkeleton(pose, skeleton);
157
+
158
+ const JPH_Skeleton* retrievedSkeleton = JPH_SkeletonPose_GetSkeleton(pose);
159
+ EXPECT_EQ(retrievedSkeleton, skeleton);
160
+ EXPECT_EQ(JPH_SkeletonPose_GetJointCount(pose), 2);
161
+
162
+ JPH_SkeletonPose_Destroy(pose);
163
+ JPH_Skeleton_Destroy(skeleton);
164
+ }
165
+
166
+ TEST_F(SkeletonTest, SkeletonPose_RootOffset) {
167
+ JPH_SkeletonPose* pose = JPH_SkeletonPose_Create();
168
+
169
+ JPH_RVec3 offset = {1.0f, 2.0f, 3.0f};
170
+ JPH_SkeletonPose_SetRootOffset(pose, &offset);
171
+
172
+ JPH_RVec3 result;
173
+ JPH_SkeletonPose_GetRootOffset(pose, &result);
174
+ EXPECT_FLOAT_EQ(result.x, 1.0f);
175
+ EXPECT_FLOAT_EQ(result.y, 2.0f);
176
+ EXPECT_FLOAT_EQ(result.z, 3.0f);
177
+
178
+ JPH_SkeletonPose_Destroy(pose);
179
+ }
180
+
181
+ TEST_F(SkeletonTest, SkeletonPose_JointState) {
182
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
183
+ JPH_Skeleton_AddJoint(skeleton, "root");
184
+
185
+ JPH_SkeletonPose* pose = JPH_SkeletonPose_Create();
186
+ JPH_SkeletonPose_SetSkeleton(pose, skeleton);
187
+
188
+ JPH_Vec3 translation = {1.0f, 2.0f, 3.0f};
189
+ JPH_Quat rotation = {0.0f, 0.0f, 0.0f, 1.0f};
190
+ JPH_SkeletonPose_SetJointState(pose, 0, &translation, &rotation);
191
+
192
+ JPH_Vec3 outTranslation;
193
+ JPH_Quat outRotation;
194
+ JPH_SkeletonPose_GetJointState(pose, 0, &outTranslation, &outRotation);
195
+ EXPECT_FLOAT_EQ(outTranslation.x, 1.0f);
196
+ EXPECT_FLOAT_EQ(outTranslation.y, 2.0f);
197
+ EXPECT_FLOAT_EQ(outTranslation.z, 3.0f);
198
+ EXPECT_FLOAT_EQ(outRotation.w, 1.0f);
199
+
200
+ JPH_SkeletonPose_Destroy(pose);
201
+ JPH_Skeleton_Destroy(skeleton);
202
+ }
203
+
204
+ // ============================================================================
205
+ // RagdollSettings Tests
206
+ // ============================================================================
207
+
208
+ TEST_F(SkeletonTest, RagdollSettings_Create) {
209
+ JPH_RagdollSettings* settings = JPH_RagdollSettings_Create();
210
+ ASSERT_NE(settings, nullptr);
211
+
212
+ JPH_RagdollSettings_Destroy(settings);
213
+ }
214
+
215
+ TEST_F(SkeletonTest, RagdollSettings_SetSkeleton) {
216
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
217
+ JPH_Skeleton_AddJoint(skeleton, "root");
218
+
219
+ JPH_RagdollSettings* settings = JPH_RagdollSettings_Create();
220
+ JPH_RagdollSettings_SetSkeleton(settings, skeleton);
221
+
222
+ const JPH_Skeleton* retrievedSkeleton = JPH_RagdollSettings_GetSkeleton(settings);
223
+ EXPECT_EQ(retrievedSkeleton, skeleton);
224
+
225
+ JPH_RagdollSettings_Destroy(settings);
226
+ JPH_Skeleton_Destroy(skeleton);
227
+ }
228
+
229
+ TEST_F(SkeletonTest, RagdollSettings_Parts) {
230
+ JPH_RagdollSettings* settings = JPH_RagdollSettings_Create();
231
+
232
+ JPH_RagdollSettings_ResizeParts(settings, 3);
233
+ EXPECT_EQ(JPH_RagdollSettings_GetPartCount(settings), 3);
234
+
235
+ // Set part properties
236
+ JPH_SphereShape* shape = JPH_SphereShape_Create(0.5f);
237
+ JPH_RVec3 position = {0.0f, 1.0f, 0.0f};
238
+ JPH_Quat rotation = {0.0f, 0.0f, 0.0f, 1.0f};
239
+
240
+ JPH_RagdollSettings_SetPartShape(settings, 0, (JPH_Shape*)shape);
241
+ JPH_RagdollSettings_SetPartPosition(settings, 0, &position);
242
+ JPH_RagdollSettings_SetPartRotation(settings, 0, &rotation);
243
+ JPH_RagdollSettings_SetPartMotionType(settings, 0, JPH_MotionType_Dynamic);
244
+ JPH_RagdollSettings_SetPartObjectLayer(settings, 0, ObjectLayers::MOVING);
245
+
246
+ JPH_RagdollSettings_Destroy(settings);
247
+ JPH_Shape_Destroy((JPH_Shape*)shape);
248
+ }
249
+
250
+ // ============================================================================
251
+ // Ragdoll Tests
252
+ // ============================================================================
253
+
254
+ TEST_F(SkeletonTest, Ragdoll_CreateSimple) {
255
+ // Create skeleton
256
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
257
+ JPH_Skeleton_AddJoint(skeleton, "root");
258
+
259
+ // Create ragdoll settings
260
+ JPH_RagdollSettings* settings = JPH_RagdollSettings_Create();
261
+ JPH_RagdollSettings_SetSkeleton(settings, skeleton);
262
+ JPH_RagdollSettings_ResizeParts(settings, 1);
263
+
264
+ // Set up part
265
+ JPH_SphereShape* shape = JPH_SphereShape_Create(0.5f);
266
+ JPH_RVec3 position = {0.0f, 1.0f, 0.0f};
267
+ JPH_Quat rotation = {0.0f, 0.0f, 0.0f, 1.0f};
268
+
269
+ JPH_RagdollSettings_SetPartShape(settings, 0, (JPH_Shape*)shape);
270
+ JPH_RagdollSettings_SetPartPosition(settings, 0, &position);
271
+ JPH_RagdollSettings_SetPartRotation(settings, 0, &rotation);
272
+ JPH_RagdollSettings_SetPartMotionType(settings, 0, JPH_MotionType_Dynamic);
273
+ JPH_RagdollSettings_SetPartObjectLayer(settings, 0, ObjectLayers::MOVING);
274
+
275
+ // Create ragdoll
276
+ JPH_Ragdoll* ragdoll = JPH_RagdollSettings_CreateRagdoll(settings, physicsSystem, 0, 0);
277
+ ASSERT_NE(ragdoll, nullptr);
278
+
279
+ EXPECT_EQ(JPH_Ragdoll_GetBodyCount(ragdoll), 1);
280
+
281
+ JPH_BodyID bodyId = JPH_Ragdoll_GetBodyID(ragdoll, 0);
282
+ EXPECT_NE(bodyId, 0xFFFFFFFF);
283
+
284
+ JPH_Ragdoll_Destroy(ragdoll);
285
+ JPH_RagdollSettings_Destroy(settings);
286
+ JPH_Shape_Destroy((JPH_Shape*)shape);
287
+ JPH_Skeleton_Destroy(skeleton);
288
+ }
289
+
290
+ TEST_F(SkeletonTest, Ragdoll_AddRemoveFromPhysicsSystem) {
291
+ // Create skeleton
292
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
293
+ JPH_Skeleton_AddJoint(skeleton, "root");
294
+
295
+ // Create ragdoll settings
296
+ JPH_RagdollSettings* settings = JPH_RagdollSettings_Create();
297
+ JPH_RagdollSettings_SetSkeleton(settings, skeleton);
298
+ JPH_RagdollSettings_ResizeParts(settings, 1);
299
+
300
+ JPH_SphereShape* shape = JPH_SphereShape_Create(0.5f);
301
+ JPH_RVec3 position = {0.0f, 1.0f, 0.0f};
302
+ JPH_Quat rotation = {0.0f, 0.0f, 0.0f, 1.0f};
303
+
304
+ JPH_RagdollSettings_SetPartShape(settings, 0, (JPH_Shape*)shape);
305
+ JPH_RagdollSettings_SetPartPosition(settings, 0, &position);
306
+ JPH_RagdollSettings_SetPartRotation(settings, 0, &rotation);
307
+ JPH_RagdollSettings_SetPartMotionType(settings, 0, JPH_MotionType_Dynamic);
308
+ JPH_RagdollSettings_SetPartObjectLayer(settings, 0, ObjectLayers::MOVING);
309
+
310
+ JPH_Ragdoll* ragdoll = JPH_RagdollSettings_CreateRagdoll(settings, physicsSystem, 0, 0);
311
+
312
+ // Add to physics system
313
+ JPH_Ragdoll_AddToPhysicsSystem(ragdoll, JPH_Activation_Activate, true);
314
+ EXPECT_TRUE(JPH_Ragdoll_IsActive(ragdoll, true));
315
+
316
+ // Remove from physics system
317
+ JPH_Ragdoll_RemoveFromPhysicsSystem(ragdoll, true);
318
+
319
+ JPH_Ragdoll_Destroy(ragdoll);
320
+ JPH_RagdollSettings_Destroy(settings);
321
+ JPH_Shape_Destroy((JPH_Shape*)shape);
322
+ JPH_Skeleton_Destroy(skeleton);
323
+ }
324
+
325
+ TEST_F(SkeletonTest, Ragdoll_GetRootTransform) {
326
+ JPH_Skeleton* skeleton = JPH_Skeleton_Create();
327
+ JPH_Skeleton_AddJoint(skeleton, "root");
328
+
329
+ JPH_RagdollSettings* settings = JPH_RagdollSettings_Create();
330
+ JPH_RagdollSettings_SetSkeleton(settings, skeleton);
331
+ JPH_RagdollSettings_ResizeParts(settings, 1);
332
+
333
+ JPH_SphereShape* shape = JPH_SphereShape_Create(0.5f);
334
+ JPH_RVec3 position = {1.0f, 2.0f, 3.0f};
335
+ JPH_Quat rotation = {0.0f, 0.0f, 0.0f, 1.0f};
336
+
337
+ JPH_RagdollSettings_SetPartShape(settings, 0, (JPH_Shape*)shape);
338
+ JPH_RagdollSettings_SetPartPosition(settings, 0, &position);
339
+ JPH_RagdollSettings_SetPartRotation(settings, 0, &rotation);
340
+ JPH_RagdollSettings_SetPartMotionType(settings, 0, JPH_MotionType_Dynamic);
341
+ JPH_RagdollSettings_SetPartObjectLayer(settings, 0, ObjectLayers::MOVING);
342
+
343
+ JPH_Ragdoll* ragdoll = JPH_RagdollSettings_CreateRagdoll(settings, physicsSystem, 0, 0);
344
+ JPH_Ragdoll_AddToPhysicsSystem(ragdoll, JPH_Activation_Activate, true);
345
+
346
+ JPH_RVec3 outPosition;
347
+ JPH_Quat outRotation;
348
+ JPH_Ragdoll_GetRootTransform(ragdoll, &outPosition, &outRotation, true);
349
+
350
+ EXPECT_FLOAT_EQ(outPosition.x, 1.0f);
351
+ EXPECT_FLOAT_EQ(outPosition.y, 2.0f);
352
+ EXPECT_FLOAT_EQ(outPosition.z, 3.0f);
353
+
354
+ JPH_Ragdoll_RemoveFromPhysicsSystem(ragdoll, true);
355
+ JPH_Ragdoll_Destroy(ragdoll);
356
+ JPH_RagdollSettings_Destroy(settings);
357
+ JPH_Shape_Destroy((JPH_Shape*)shape);
358
+ JPH_Skeleton_Destroy(skeleton);
359
+ }
360
+
361
+ // ============================================================================
362
+ // SkeletonMapper Tests
363
+ // ============================================================================
364
+
365
+ TEST_F(SkeletonTest, SkeletonMapper_Create) {
366
+ JPH_SkeletonMapper* mapper = JPH_SkeletonMapper_Create();
367
+ ASSERT_NE(mapper, nullptr);
368
+
369
+ JPH_SkeletonMapper_Destroy(mapper);
370
+ }
@@ -0,0 +1,319 @@
1
+ // Copyright (c) Amer Koleci and Contributors.
2
+ // Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
3
+
4
+ #include <gtest/gtest.h>
5
+ #include "joltc.h"
6
+
7
+ namespace BroadPhaseLayers {
8
+ static constexpr JPH_BroadPhaseLayer NON_MOVING = 0;
9
+ static constexpr JPH_BroadPhaseLayer MOVING = 1;
10
+ static constexpr uint32_t NUM_LAYERS = 2;
11
+ }
12
+
13
+ namespace ObjectLayers {
14
+ static constexpr JPH_ObjectLayer NON_MOVING = 0;
15
+ static constexpr JPH_ObjectLayer MOVING = 1;
16
+ static constexpr uint32_t NUM_LAYERS = 2;
17
+ }
18
+
19
+ class VehicleTest : public ::testing::Test {
20
+ protected:
21
+ JPH_PhysicsSystem* physicsSystem = nullptr;
22
+ JPH_BodyInterface* bodyInterface = nullptr;
23
+ JPH_BroadPhaseLayerInterface* bpLayer = nullptr;
24
+ JPH_ObjectLayerPairFilter* objPairFilter = nullptr;
25
+ JPH_ObjectVsBroadPhaseLayerFilter* objVsBpFilter = nullptr;
26
+
27
+ void SetUp() override {
28
+ ASSERT_TRUE(JPH_Init());
29
+
30
+ bpLayer = JPH_BroadPhaseLayerInterfaceTable_Create(ObjectLayers::NUM_LAYERS, BroadPhaseLayers::NUM_LAYERS);
31
+ JPH_BroadPhaseLayerInterfaceTable_MapObjectToBroadPhaseLayer(bpLayer, ObjectLayers::NON_MOVING, BroadPhaseLayers::NON_MOVING);
32
+ JPH_BroadPhaseLayerInterfaceTable_MapObjectToBroadPhaseLayer(bpLayer, ObjectLayers::MOVING, BroadPhaseLayers::MOVING);
33
+
34
+ objPairFilter = JPH_ObjectLayerPairFilterTable_Create(ObjectLayers::NUM_LAYERS);
35
+ JPH_ObjectLayerPairFilterTable_EnableCollision(objPairFilter, ObjectLayers::NON_MOVING, ObjectLayers::MOVING);
36
+ JPH_ObjectLayerPairFilterTable_EnableCollision(objPairFilter, ObjectLayers::MOVING, ObjectLayers::MOVING);
37
+
38
+ objVsBpFilter = JPH_ObjectVsBroadPhaseLayerFilterTable_Create(
39
+ bpLayer, BroadPhaseLayers::NUM_LAYERS,
40
+ objPairFilter, ObjectLayers::NUM_LAYERS);
41
+
42
+ JPH_PhysicsSystemSettings settings = {};
43
+ settings.maxBodies = 1024;
44
+ settings.maxBodyPairs = 1024;
45
+ settings.maxContactConstraints = 1024;
46
+ settings.broadPhaseLayerInterface = bpLayer;
47
+ settings.objectVsBroadPhaseLayerFilter = objVsBpFilter;
48
+ settings.objectLayerPairFilter = objPairFilter;
49
+
50
+ physicsSystem = JPH_PhysicsSystem_Create(&settings);
51
+ bodyInterface = JPH_PhysicsSystem_GetBodyInterface(physicsSystem);
52
+ }
53
+
54
+ void TearDown() override {
55
+ if (physicsSystem) JPH_PhysicsSystem_Destroy(physicsSystem);
56
+ JPH_Shutdown();
57
+ }
58
+ };
59
+
60
+ // ============================================================================
61
+ // WheelSettings Tests
62
+ // ============================================================================
63
+
64
+ TEST_F(VehicleTest, WheelSettings_Create) {
65
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
66
+ ASSERT_NE(settings, nullptr);
67
+
68
+ JPH_WheelSettings_Destroy(settings);
69
+ }
70
+
71
+ TEST_F(VehicleTest, WheelSettings_Position) {
72
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
73
+
74
+ JPH_Vec3 pos = {1.0f, 0.0f, 2.0f};
75
+ JPH_WheelSettings_SetPosition(settings, &pos);
76
+
77
+ JPH_Vec3 result;
78
+ JPH_WheelSettings_GetPosition(settings, &result);
79
+ EXPECT_FLOAT_EQ(result.x, 1.0f);
80
+ EXPECT_FLOAT_EQ(result.z, 2.0f);
81
+
82
+ JPH_WheelSettings_Destroy(settings);
83
+ }
84
+
85
+ TEST_F(VehicleTest, WheelSettings_Radius) {
86
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
87
+
88
+ JPH_WheelSettings_SetRadius(settings, 0.5f);
89
+ EXPECT_FLOAT_EQ(JPH_WheelSettings_GetRadius(settings), 0.5f);
90
+
91
+ JPH_WheelSettings_Destroy(settings);
92
+ }
93
+
94
+ TEST_F(VehicleTest, WheelSettings_Width) {
95
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
96
+
97
+ JPH_WheelSettings_SetWidth(settings, 0.3f);
98
+ EXPECT_FLOAT_EQ(JPH_WheelSettings_GetWidth(settings), 0.3f);
99
+
100
+ JPH_WheelSettings_Destroy(settings);
101
+ }
102
+
103
+ TEST_F(VehicleTest, WheelSettings_Suspension) {
104
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
105
+
106
+ JPH_WheelSettings_SetSuspensionMinLength(settings, 0.1f);
107
+ JPH_WheelSettings_SetSuspensionMaxLength(settings, 0.5f);
108
+
109
+ EXPECT_FLOAT_EQ(JPH_WheelSettings_GetSuspensionMinLength(settings), 0.1f);
110
+ EXPECT_FLOAT_EQ(JPH_WheelSettings_GetSuspensionMaxLength(settings), 0.5f);
111
+
112
+ JPH_WheelSettings_Destroy(settings);
113
+ }
114
+
115
+ // ============================================================================
116
+ // Wheel Tests
117
+ // ============================================================================
118
+
119
+ TEST_F(VehicleTest, Wheel_Create) {
120
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
121
+ JPH_Wheel* wheel = JPH_Wheel_Create(settings);
122
+ ASSERT_NE(wheel, nullptr);
123
+
124
+ JPH_Wheel_Destroy(wheel);
125
+ JPH_WheelSettings_Destroy(settings);
126
+ }
127
+
128
+ TEST_F(VehicleTest, Wheel_AngularVelocity) {
129
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
130
+ JPH_Wheel* wheel = JPH_Wheel_Create(settings);
131
+
132
+ JPH_Wheel_SetAngularVelocity(wheel, 10.0f);
133
+ EXPECT_FLOAT_EQ(JPH_Wheel_GetAngularVelocity(wheel), 10.0f);
134
+
135
+ JPH_Wheel_Destroy(wheel);
136
+ JPH_WheelSettings_Destroy(settings);
137
+ }
138
+
139
+ TEST_F(VehicleTest, Wheel_RotationAngle) {
140
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
141
+ JPH_Wheel* wheel = JPH_Wheel_Create(settings);
142
+
143
+ JPH_Wheel_SetRotationAngle(wheel, JPH_M_PI / 4.0f);
144
+ EXPECT_NEAR(JPH_Wheel_GetRotationAngle(wheel), JPH_M_PI / 4.0f, 0.001f);
145
+
146
+ JPH_Wheel_Destroy(wheel);
147
+ JPH_WheelSettings_Destroy(settings);
148
+ }
149
+
150
+ TEST_F(VehicleTest, Wheel_SteerAngle) {
151
+ JPH_WheelSettings* settings = JPH_WheelSettings_Create();
152
+ JPH_Wheel* wheel = JPH_Wheel_Create(settings);
153
+
154
+ JPH_Wheel_SetSteerAngle(wheel, 0.1f);
155
+ EXPECT_FLOAT_EQ(JPH_Wheel_GetSteerAngle(wheel), 0.1f);
156
+
157
+ JPH_Wheel_Destroy(wheel);
158
+ JPH_WheelSettings_Destroy(settings);
159
+ }
160
+
161
+ // ============================================================================
162
+ // VehicleCollisionTester Tests
163
+ // ============================================================================
164
+
165
+ TEST_F(VehicleTest, VehicleCollisionTesterRay_Create) {
166
+ JPH_Vec3 up = {0.0f, 1.0f, 0.0f};
167
+ JPH_VehicleCollisionTesterRay* tester = JPH_VehicleCollisionTesterRay_Create(ObjectLayers::MOVING, &up, JPH_M_PI / 4.0f);
168
+ ASSERT_NE(tester, nullptr);
169
+
170
+ EXPECT_EQ(JPH_VehicleCollisionTester_GetObjectLayer((JPH_VehicleCollisionTester*)tester), ObjectLayers::MOVING);
171
+
172
+ JPH_VehicleCollisionTester_Destroy((JPH_VehicleCollisionTester*)tester);
173
+ }
174
+
175
+ TEST_F(VehicleTest, VehicleCollisionTesterCastSphere_Create) {
176
+ JPH_Vec3 up = {0.0f, 1.0f, 0.0f};
177
+ JPH_VehicleCollisionTesterCastSphere* tester = JPH_VehicleCollisionTesterCastSphere_Create(ObjectLayers::MOVING, 0.1f, &up, JPH_M_PI / 4.0f);
178
+ ASSERT_NE(tester, nullptr);
179
+
180
+ JPH_VehicleCollisionTester_Destroy((JPH_VehicleCollisionTester*)tester);
181
+ }
182
+
183
+ TEST_F(VehicleTest, VehicleCollisionTesterCastCylinder_Create) {
184
+ JPH_VehicleCollisionTesterCastCylinder* tester = JPH_VehicleCollisionTesterCastCylinder_Create(ObjectLayers::MOVING, 0.05f);
185
+ ASSERT_NE(tester, nullptr);
186
+
187
+ JPH_VehicleCollisionTester_Destroy((JPH_VehicleCollisionTester*)tester);
188
+ }
189
+
190
+ // ============================================================================
191
+ // VehicleEngineSettings Tests
192
+ // ============================================================================
193
+
194
+ TEST_F(VehicleTest, VehicleEngineSettings_Init) {
195
+ JPH_VehicleEngineSettings settings;
196
+ JPH_VehicleEngineSettings_Init(&settings);
197
+
198
+ EXPECT_GT(settings.maxRPM, 0.0f);
199
+ EXPECT_GT(settings.maxTorque, 0.0f);
200
+ }
201
+
202
+ // ============================================================================
203
+ // VehicleDifferentialSettings Tests
204
+ // ============================================================================
205
+
206
+ TEST_F(VehicleTest, VehicleDifferentialSettings_Init) {
207
+ JPH_VehicleDifferentialSettings settings;
208
+ JPH_VehicleDifferentialSettings_Init(&settings);
209
+
210
+ // Default values should be set
211
+ EXPECT_GE(settings.leftWheel, -1);
212
+ }
213
+
214
+ // ============================================================================
215
+ // VehicleTransmissionSettings Tests
216
+ // ============================================================================
217
+
218
+ TEST_F(VehicleTest, VehicleTransmissionSettings_Create) {
219
+ JPH_VehicleTransmissionSettings* settings = JPH_VehicleTransmissionSettings_Create();
220
+ ASSERT_NE(settings, nullptr);
221
+
222
+ JPH_VehicleTransmissionSettings_Destroy(settings);
223
+ }
224
+
225
+ TEST_F(VehicleTest, VehicleTransmissionSettings_Mode) {
226
+ JPH_VehicleTransmissionSettings* settings = JPH_VehicleTransmissionSettings_Create();
227
+
228
+ JPH_VehicleTransmissionSettings_SetMode(settings, JPH_TransmissionMode_Manual);
229
+ EXPECT_EQ(JPH_VehicleTransmissionSettings_GetMode(settings), JPH_TransmissionMode_Manual);
230
+
231
+ JPH_VehicleTransmissionSettings_SetMode(settings, JPH_TransmissionMode_Auto);
232
+ EXPECT_EQ(JPH_VehicleTransmissionSettings_GetMode(settings), JPH_TransmissionMode_Auto);
233
+
234
+ JPH_VehicleTransmissionSettings_Destroy(settings);
235
+ }
236
+
237
+ TEST_F(VehicleTest, VehicleTransmissionSettings_GearRatios) {
238
+ JPH_VehicleTransmissionSettings* settings = JPH_VehicleTransmissionSettings_Create();
239
+
240
+ float gears[] = {3.0f, 2.0f, 1.5f, 1.0f, 0.8f};
241
+ JPH_VehicleTransmissionSettings_SetGearRatios(settings, gears, 5);
242
+
243
+ EXPECT_EQ(JPH_VehicleTransmissionSettings_GetGearRatioCount(settings), 5u);
244
+ EXPECT_FLOAT_EQ(JPH_VehicleTransmissionSettings_GetGearRatio(settings, 0), 3.0f);
245
+ EXPECT_FLOAT_EQ(JPH_VehicleTransmissionSettings_GetGearRatio(settings, 4), 0.8f);
246
+
247
+ JPH_VehicleTransmissionSettings_Destroy(settings);
248
+ }
249
+
250
+ TEST_F(VehicleTest, VehicleTransmissionSettings_Timing) {
251
+ JPH_VehicleTransmissionSettings* settings = JPH_VehicleTransmissionSettings_Create();
252
+
253
+ JPH_VehicleTransmissionSettings_SetSwitchTime(settings, 0.5f);
254
+ EXPECT_FLOAT_EQ(JPH_VehicleTransmissionSettings_GetSwitchTime(settings), 0.5f);
255
+
256
+ JPH_VehicleTransmissionSettings_SetClutchReleaseTime(settings, 0.3f);
257
+ EXPECT_FLOAT_EQ(JPH_VehicleTransmissionSettings_GetClutchReleaseTime(settings), 0.3f);
258
+
259
+ JPH_VehicleTransmissionSettings_SetShiftUpRPM(settings, 5000.0f);
260
+ EXPECT_FLOAT_EQ(JPH_VehicleTransmissionSettings_GetShiftUpRPM(settings), 5000.0f);
261
+
262
+ JPH_VehicleTransmissionSettings_SetShiftDownRPM(settings, 2000.0f);
263
+ EXPECT_FLOAT_EQ(JPH_VehicleTransmissionSettings_GetShiftDownRPM(settings), 2000.0f);
264
+
265
+ JPH_VehicleTransmissionSettings_Destroy(settings);
266
+ }
267
+
268
+ // ============================================================================
269
+ // WheeledVehicleControllerSettings Tests
270
+ // ============================================================================
271
+
272
+ TEST_F(VehicleTest, WheeledVehicleControllerSettings_Create) {
273
+ JPH_WheeledVehicleControllerSettings* settings = JPH_WheeledVehicleControllerSettings_Create();
274
+ ASSERT_NE(settings, nullptr);
275
+
276
+ JPH_VehicleControllerSettings_Destroy((JPH_VehicleControllerSettings*)settings);
277
+ }
278
+
279
+ TEST_F(VehicleTest, WheeledVehicleControllerSettings_Engine) {
280
+ JPH_WheeledVehicleControllerSettings* settings = JPH_WheeledVehicleControllerSettings_Create();
281
+
282
+ JPH_VehicleEngineSettings engineSettings;
283
+ JPH_VehicleEngineSettings_Init(&engineSettings);
284
+ engineSettings.maxRPM = 8000.0f;
285
+ engineSettings.maxTorque = 500.0f;
286
+
287
+ JPH_WheeledVehicleControllerSettings_SetEngine(settings, &engineSettings);
288
+
289
+ JPH_VehicleEngineSettings result;
290
+ JPH_WheeledVehicleControllerSettings_GetEngine(settings, &result);
291
+ EXPECT_FLOAT_EQ(result.maxRPM, 8000.0f);
292
+ EXPECT_FLOAT_EQ(result.maxTorque, 500.0f);
293
+
294
+ JPH_VehicleControllerSettings_Destroy((JPH_VehicleControllerSettings*)settings);
295
+ }
296
+
297
+ // ============================================================================
298
+ // VehicleAntiRollBar Tests
299
+ // ============================================================================
300
+
301
+ TEST_F(VehicleTest, VehicleAntiRollBar_Init) {
302
+ JPH_VehicleAntiRollBar antiRollBar;
303
+ JPH_VehicleAntiRollBar_Init(&antiRollBar);
304
+
305
+ // Default values should be set
306
+ EXPECT_GE(antiRollBar.leftWheel, 0);
307
+ }
308
+
309
+ // ============================================================================
310
+ // VehicleConstraintSettings Tests
311
+ // ============================================================================
312
+
313
+ TEST_F(VehicleTest, VehicleConstraintSettings_Init) {
314
+ JPH_VehicleConstraintSettings settings;
315
+ JPH_VehicleConstraintSettings_Init(&settings);
316
+
317
+ // Default forward should be set
318
+ EXPECT_FALSE(settings.forward.x == 0.0f && settings.forward.y == 0.0f && settings.forward.z == 0.0f);
319
+ }