bullet3 0.1.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +194 -0
  4. data/data/cube.urdf +22 -0
  5. data/data/plane.urdf +19 -0
  6. data/ext/bullet3/CMakeLists.txt +224 -0
  7. data/ext/bullet3/bullet3.cpp +34 -0
  8. data/ext/bullet3/collision/rb_collision.cpp +428 -0
  9. data/ext/bullet3/collision/rb_collision.hpp +87 -0
  10. data/ext/bullet3/collision/shapes/rb_collision_shape.cpp +485 -0
  11. data/ext/bullet3/collision/shapes/rb_collision_shape.hpp +5 -0
  12. data/ext/bullet3/constraints/rb_constraints.cpp +1310 -0
  13. data/ext/bullet3/constraints/rb_constraints.hpp +226 -0
  14. data/ext/bullet3/dynamics/rb_dynamics.cpp +862 -0
  15. data/ext/bullet3/dynamics/rb_dynamics.hpp +180 -0
  16. data/ext/bullet3/extconf.rb +57 -0
  17. data/ext/bullet3/io/rb_io.cpp +108 -0
  18. data/ext/bullet3/io/rb_io.hpp +40 -0
  19. data/ext/bullet3/linear_math/rb_matrix3x3.cpp +93 -0
  20. data/ext/bullet3/linear_math/rb_matrix3x3.hpp +5 -0
  21. data/ext/bullet3/linear_math/rb_quaternion.cpp +134 -0
  22. data/ext/bullet3/linear_math/rb_quaternion.hpp +5 -0
  23. data/ext/bullet3/linear_math/rb_transform.cpp +157 -0
  24. data/ext/bullet3/linear_math/rb_transform.hpp +34 -0
  25. data/ext/bullet3/linear_math/rb_vector3.cpp +123 -0
  26. data/ext/bullet3/linear_math/rb_vector3.hpp +5 -0
  27. data/ext/bullet3/multi_body/rb_multi_body.cpp +1000 -0
  28. data/ext/bullet3/multi_body/rb_multi_body.hpp +190 -0
  29. data/ext/bullet3/soft_body/rb_soft_body.cpp +720 -0
  30. data/ext/bullet3/soft_body/rb_soft_body.hpp +122 -0
  31. data/ext/bullet3/util/rb_debug_draw.cpp +250 -0
  32. data/ext/bullet3/util/rb_debug_draw.hpp +47 -0
  33. data/ext/bullet3/util/ruby_cpp_compat.hpp +29 -0
  34. data/ext/bullet3/util/type_conversions.hpp +107 -0
  35. data/ext/bullet3/vehicle/rb_vehicle.cpp +467 -0
  36. data/ext/bullet3/vehicle/rb_vehicle.hpp +115 -0
  37. data/lib/bullet3/collision.rb +6 -0
  38. data/lib/bullet3/constraints.rb +6 -0
  39. data/lib/bullet3/data.rb +39 -0
  40. data/lib/bullet3/debug_draw.rb +73 -0
  41. data/lib/bullet3/dynamics.rb +4 -0
  42. data/lib/bullet3/io.rb +110 -0
  43. data/lib/bullet3/linear_math/matrix3x3.rb +69 -0
  44. data/lib/bullet3/linear_math/quaternion.rb +187 -0
  45. data/lib/bullet3/linear_math/transform.rb +48 -0
  46. data/lib/bullet3/linear_math/vector3.rb +199 -0
  47. data/lib/bullet3/linear_math.rb +6 -0
  48. data/lib/bullet3/multi_body.rb +6 -0
  49. data/lib/bullet3/simulation.rb +1170 -0
  50. data/lib/bullet3/soft_body.rb +6 -0
  51. data/lib/bullet3/vehicle.rb +4 -0
  52. data/lib/bullet3/version.rb +5 -0
  53. data/lib/bullet3.rb +49 -0
  54. metadata +124 -0
@@ -0,0 +1,862 @@
1
+ #include "rb_dynamics.hpp"
2
+
3
+ #include <functional>
4
+ #include <stdexcept>
5
+ #include <utility>
6
+
7
+ #include <ruby/thread.h>
8
+
9
+ #include "../constraints/rb_constraints.hpp"
10
+ #include "../util/type_conversions.hpp"
11
+ #include "../vehicle/rb_vehicle.hpp"
12
+
13
+ namespace {
14
+ btCollisionShape* coerce_collision_shape(Rice::Object object)
15
+ {
16
+ btCollisionShape* shape = Rice::detail::From_Ruby<btCollisionShape*>().convert(object);
17
+ if (shape == nullptr) {
18
+ throw std::invalid_argument("expected Bullet3::Shapes::CollisionShape");
19
+ }
20
+
21
+ return shape;
22
+ }
23
+
24
+ btVector3 calculate_local_inertia(btCollisionShape& shape, btScalar mass)
25
+ {
26
+ btVector3 inertia(0, 0, 0);
27
+ if (mass != btScalar(0)) {
28
+ shape.calculateLocalInertia(mass, inertia);
29
+ }
30
+ return inertia;
31
+ }
32
+
33
+ struct StepSimulationArgs {
34
+ btDiscreteDynamicsWorld* world;
35
+ btScalar time_step;
36
+ int max_sub_steps;
37
+ btScalar fixed_time_step;
38
+ int result;
39
+ };
40
+
41
+ void* step_simulation_without_gvl(void* pointer)
42
+ {
43
+ auto* args = static_cast<StepSimulationArgs*>(pointer);
44
+ args->result = args->world->stepSimulation(args->time_step, args->max_sub_steps, args->fixed_time_step);
45
+ return nullptr;
46
+ }
47
+
48
+ void set_vector_hash_value(Rice::Hash& hash, const char* key, const btVector3& value)
49
+ {
50
+ hash[Rice::Symbol(key)] = Rice::Object(Rice::detail::To_Ruby<btVector3>().convert(btVector3(value)));
51
+ }
52
+
53
+ bullet3::RigidBody* rigid_body_from_value(VALUE value)
54
+ {
55
+ bullet3::RigidBody* body = Rice::detail::From_Ruby<bullet3::RigidBody*>().convert(value);
56
+ if (body == nullptr) {
57
+ throw std::invalid_argument("expected Bullet3::RigidBody");
58
+ }
59
+ return body;
60
+ }
61
+
62
+ class ContactCollector : public btCollisionWorld::ContactResultCallback {
63
+ public:
64
+ explicit ContactCollector(std::function<VALUE(const btCollisionObject*)> ruby_object_for)
65
+ : ruby_object_for_(std::move(ruby_object_for))
66
+ {
67
+ }
68
+
69
+ btScalar addSingleResult(btManifoldPoint& contact_point,
70
+ const btCollisionObjectWrapper* object0,
71
+ int part_id0,
72
+ int index0,
73
+ const btCollisionObjectWrapper* object1,
74
+ int part_id1,
75
+ int index1) override
76
+ {
77
+ Rice::Hash contact;
78
+ contact[Rice::Symbol("body0")] = Rice::Object(ruby_object_for_(object0->getCollisionObject()));
79
+ contact[Rice::Symbol("body1")] = Rice::Object(ruby_object_for_(object1->getCollisionObject()));
80
+ set_vector_hash_value(contact, "position_world_on_a", contact_point.getPositionWorldOnA());
81
+ set_vector_hash_value(contact, "position_world_on_b", contact_point.getPositionWorldOnB());
82
+ set_vector_hash_value(contact, "normal_world_on_b", contact_point.m_normalWorldOnB);
83
+ contact[Rice::Symbol("distance")] = contact_point.getDistance();
84
+ contact[Rice::Symbol("part_id0")] = part_id0;
85
+ contact[Rice::Symbol("index0")] = index0;
86
+ contact[Rice::Symbol("part_id1")] = part_id1;
87
+ contact[Rice::Symbol("index1")] = index1;
88
+ contacts.push(contact);
89
+ return btScalar(0);
90
+ }
91
+
92
+ Rice::Array contacts;
93
+
94
+ private:
95
+ std::function<VALUE(const btCollisionObject*)> ruby_object_for_;
96
+ };
97
+ } // namespace
98
+
99
+ namespace bullet3 {
100
+ CollisionConfiguration::CollisionConfiguration()
101
+ : configuration_(std::make_unique<btDefaultCollisionConfiguration>())
102
+ {
103
+ }
104
+
105
+ btDefaultCollisionConfiguration* CollisionConfiguration::get()
106
+ {
107
+ return configuration_.get();
108
+ }
109
+
110
+ CollisionDispatcher::CollisionDispatcher(CollisionConfiguration& configuration)
111
+ : dispatcher_(std::make_unique<btCollisionDispatcher>(configuration.get()))
112
+ {
113
+ }
114
+
115
+ btCollisionDispatcher* CollisionDispatcher::get()
116
+ {
117
+ return dispatcher_.get();
118
+ }
119
+
120
+ DbvtBroadphase::DbvtBroadphase()
121
+ : broadphase_(std::make_unique<btDbvtBroadphase>())
122
+ {
123
+ }
124
+
125
+ btDbvtBroadphase* DbvtBroadphase::get()
126
+ {
127
+ return broadphase_.get();
128
+ }
129
+
130
+ SequentialImpulseConstraintSolver::SequentialImpulseConstraintSolver()
131
+ : solver_(std::make_unique<btSequentialImpulseConstraintSolver>())
132
+ {
133
+ }
134
+
135
+ btSequentialImpulseConstraintSolver* SequentialImpulseConstraintSolver::get()
136
+ {
137
+ return solver_.get();
138
+ }
139
+
140
+ MotionState::MotionState()
141
+ : motion_state_(std::make_unique<btDefaultMotionState>(btTransform::getIdentity()))
142
+ {
143
+ }
144
+
145
+ MotionState::MotionState(VALUE start_transform)
146
+ : motion_state_(std::make_unique<btDefaultMotionState>(coerce_transform(Rice::Object(start_transform))))
147
+ {
148
+ }
149
+
150
+ btMotionState* MotionState::get()
151
+ {
152
+ return motion_state_.get();
153
+ }
154
+
155
+ Transform MotionState::world_transform() const
156
+ {
157
+ btTransform transform;
158
+ motion_state_->getWorldTransform(transform);
159
+ return Transform(transform);
160
+ }
161
+
162
+ Transform MotionState::set_world_transform(Rice::Object transform)
163
+ {
164
+ btTransform value = coerce_transform(transform);
165
+ motion_state_->setWorldTransform(value);
166
+ return Transform(value);
167
+ }
168
+
169
+ RigidBodyConstructionInfo::RigidBodyConstructionInfo(btScalar mass,
170
+ MotionState& motion_state,
171
+ VALUE collision_shape)
172
+ : local_inertia_(calculate_local_inertia(*coerce_collision_shape(Rice::Object(collision_shape)), mass)),
173
+ info_(std::make_unique<btRigidBody::btRigidBodyConstructionInfo>(
174
+ mass,
175
+ motion_state.get(),
176
+ coerce_collision_shape(Rice::Object(collision_shape)),
177
+ local_inertia_))
178
+ {
179
+ }
180
+
181
+ RigidBodyConstructionInfo::RigidBodyConstructionInfo(btScalar mass,
182
+ MotionState& motion_state,
183
+ VALUE collision_shape,
184
+ VALUE local_inertia)
185
+ : local_inertia_(coerce_vector(Rice::Object(local_inertia))),
186
+ info_(std::make_unique<btRigidBody::btRigidBodyConstructionInfo>(
187
+ mass,
188
+ motion_state.get(),
189
+ coerce_collision_shape(Rice::Object(collision_shape)),
190
+ local_inertia_))
191
+ {
192
+ }
193
+
194
+ btRigidBody::btRigidBodyConstructionInfo& RigidBodyConstructionInfo::get()
195
+ {
196
+ return *info_;
197
+ }
198
+
199
+ btScalar RigidBodyConstructionInfo::mass() const
200
+ {
201
+ return info_->m_mass;
202
+ }
203
+
204
+ btVector3 RigidBodyConstructionInfo::local_inertia() const
205
+ {
206
+ return info_->m_localInertia;
207
+ }
208
+
209
+ btScalar RigidBodyConstructionInfo::friction() const
210
+ {
211
+ return info_->m_friction;
212
+ }
213
+
214
+ btScalar RigidBodyConstructionInfo::set_friction(btScalar friction)
215
+ {
216
+ info_->m_friction = friction;
217
+ return friction;
218
+ }
219
+
220
+ btScalar RigidBodyConstructionInfo::restitution() const
221
+ {
222
+ return info_->m_restitution;
223
+ }
224
+
225
+ btScalar RigidBodyConstructionInfo::set_restitution(btScalar restitution)
226
+ {
227
+ info_->m_restitution = restitution;
228
+ return restitution;
229
+ }
230
+
231
+ RigidBody::RigidBody(RigidBodyConstructionInfo& construction_info)
232
+ : rigid_body_(std::make_unique<btRigidBody>(construction_info.get()))
233
+ {
234
+ }
235
+
236
+ btRigidBody* RigidBody::get()
237
+ {
238
+ return rigid_body_.get();
239
+ }
240
+
241
+ const btRigidBody* RigidBody::get() const
242
+ {
243
+ return rigid_body_.get();
244
+ }
245
+
246
+ btScalar RigidBody::mass() const
247
+ {
248
+ btScalar inverse_mass = rigid_body_->getInvMass();
249
+ return inverse_mass == btScalar(0) ? btScalar(0) : btScalar(1) / inverse_mass;
250
+ }
251
+
252
+ btCollisionShape* RigidBody::collision_shape() const
253
+ {
254
+ return rigid_body_->getCollisionShape();
255
+ }
256
+
257
+ Transform RigidBody::world_transform() const
258
+ {
259
+ btTransform transform;
260
+ if (rigid_body_->getMotionState() != nullptr) {
261
+ rigid_body_->getMotionState()->getWorldTransform(transform);
262
+ } else {
263
+ transform = rigid_body_->getWorldTransform();
264
+ }
265
+ return Transform(transform);
266
+ }
267
+
268
+ Transform RigidBody::set_world_transform(Rice::Object transform)
269
+ {
270
+ btTransform value = coerce_transform(transform);
271
+ rigid_body_->setWorldTransform(value);
272
+ rigid_body_->setCenterOfMassTransform(value);
273
+ if (rigid_body_->getMotionState() != nullptr) {
274
+ rigid_body_->getMotionState()->setWorldTransform(value);
275
+ }
276
+ return Transform(value);
277
+ }
278
+
279
+ btVector3 RigidBody::linear_velocity() const
280
+ {
281
+ return rigid_body_->getLinearVelocity();
282
+ }
283
+
284
+ btVector3 RigidBody::set_linear_velocity(Rice::Object velocity)
285
+ {
286
+ btVector3 vector = coerce_vector(velocity);
287
+ rigid_body_->setLinearVelocity(vector);
288
+ return vector;
289
+ }
290
+
291
+ btVector3 RigidBody::angular_velocity() const
292
+ {
293
+ return rigid_body_->getAngularVelocity();
294
+ }
295
+
296
+ btVector3 RigidBody::set_angular_velocity(Rice::Object velocity)
297
+ {
298
+ btVector3 vector = coerce_vector(velocity);
299
+ rigid_body_->setAngularVelocity(vector);
300
+ return vector;
301
+ }
302
+
303
+ btVector3 RigidBody::total_force() const
304
+ {
305
+ return rigid_body_->getTotalForce();
306
+ }
307
+
308
+ btVector3 RigidBody::total_torque() const
309
+ {
310
+ return rigid_body_->getTotalTorque();
311
+ }
312
+
313
+ btScalar RigidBody::friction() const
314
+ {
315
+ return rigid_body_->getFriction();
316
+ }
317
+
318
+ btScalar RigidBody::set_friction(btScalar friction)
319
+ {
320
+ rigid_body_->setFriction(friction);
321
+ return friction;
322
+ }
323
+
324
+ btScalar RigidBody::restitution() const
325
+ {
326
+ return rigid_body_->getRestitution();
327
+ }
328
+
329
+ btScalar RigidBody::set_restitution(btScalar restitution)
330
+ {
331
+ rigid_body_->setRestitution(restitution);
332
+ return restitution;
333
+ }
334
+
335
+ Rice::Array RigidBody::damping() const
336
+ {
337
+ Rice::Array array;
338
+ array.push(rigid_body_->getLinearDamping());
339
+ array.push(rigid_body_->getAngularDamping());
340
+ return array;
341
+ }
342
+
343
+ Rice::Array RigidBody::set_damping(btScalar linear_damping, btScalar angular_damping)
344
+ {
345
+ rigid_body_->setDamping(linear_damping, angular_damping);
346
+ return damping();
347
+ }
348
+
349
+ void RigidBody::apply_central_force(Rice::Object force)
350
+ {
351
+ rigid_body_->applyCentralForce(coerce_vector(force));
352
+ }
353
+
354
+ void RigidBody::apply_force(Rice::Object force, Rice::Object relative_position)
355
+ {
356
+ rigid_body_->applyForce(coerce_vector(force), coerce_vector(relative_position));
357
+ }
358
+
359
+ void RigidBody::apply_torque(Rice::Object torque)
360
+ {
361
+ rigid_body_->applyTorque(coerce_vector(torque));
362
+ }
363
+
364
+ void RigidBody::apply_central_impulse(Rice::Object impulse)
365
+ {
366
+ rigid_body_->applyCentralImpulse(coerce_vector(impulse));
367
+ }
368
+
369
+ void RigidBody::apply_impulse(Rice::Object impulse, Rice::Object relative_position)
370
+ {
371
+ rigid_body_->applyImpulse(coerce_vector(impulse), coerce_vector(relative_position));
372
+ }
373
+
374
+ void RigidBody::clear_forces()
375
+ {
376
+ rigid_body_->clearForces();
377
+ }
378
+
379
+ void RigidBody::activate()
380
+ {
381
+ rigid_body_->activate(true);
382
+ }
383
+
384
+ bool RigidBody::active() const
385
+ {
386
+ return rigid_body_->isActive();
387
+ }
388
+
389
+ bool RigidBody::static_object() const
390
+ {
391
+ return rigid_body_->isStaticObject();
392
+ }
393
+
394
+ bool RigidBody::kinematic_object() const
395
+ {
396
+ return rigid_body_->isKinematicObject();
397
+ }
398
+
399
+ DiscreteDynamicsWorld::DiscreteDynamicsWorld()
400
+ {
401
+ build_owned_world();
402
+ }
403
+
404
+ DiscreteDynamicsWorld::DiscreteDynamicsWorld(CollisionDispatcher& dispatcher,
405
+ DbvtBroadphase& broadphase,
406
+ SequentialImpulseConstraintSolver& solver,
407
+ CollisionConfiguration& configuration)
408
+ : world_(std::make_unique<btDiscreteDynamicsWorld>(
409
+ dispatcher.get(),
410
+ broadphase.get(),
411
+ solver.get(),
412
+ configuration.get()))
413
+ {
414
+ }
415
+
416
+ DiscreteDynamicsWorld::~DiscreteDynamicsWorld()
417
+ {
418
+ actions_.clear();
419
+ constraints_.clear();
420
+ rigid_bodies_.clear();
421
+ action_values_.clear();
422
+ constraint_values_.clear();
423
+ collision_object_values_.clear();
424
+ }
425
+
426
+ void DiscreteDynamicsWorld::build_owned_world()
427
+ {
428
+ owned_configuration_ = std::make_unique<btDefaultCollisionConfiguration>();
429
+ owned_dispatcher_ = std::make_unique<btCollisionDispatcher>(owned_configuration_.get());
430
+ owned_broadphase_ = std::make_unique<btDbvtBroadphase>();
431
+ owned_solver_ = std::make_unique<btSequentialImpulseConstraintSolver>();
432
+ world_ = std::make_unique<btDiscreteDynamicsWorld>(
433
+ owned_dispatcher_.get(),
434
+ owned_broadphase_.get(),
435
+ owned_solver_.get(),
436
+ owned_configuration_.get());
437
+ }
438
+
439
+ btDiscreteDynamicsWorld* DiscreteDynamicsWorld::get()
440
+ {
441
+ return world_.get();
442
+ }
443
+
444
+ btVector3 DiscreteDynamicsWorld::gravity() const
445
+ {
446
+ return world_->getGravity();
447
+ }
448
+
449
+ btVector3 DiscreteDynamicsWorld::set_gravity(Rice::Object gravity)
450
+ {
451
+ btVector3 vector = coerce_vector(gravity);
452
+ world_->setGravity(vector);
453
+ return vector;
454
+ }
455
+
456
+ void DiscreteDynamicsWorld::add_rigid_body(RigidBody& rigid_body)
457
+ {
458
+ btRigidBody* body = rigid_body.get();
459
+ if (rigid_bodies_.insert(body).second) {
460
+ world_->addRigidBody(body);
461
+ }
462
+ }
463
+
464
+ void DiscreteDynamicsWorld::add_rigid_body_object(VALUE rigid_body)
465
+ {
466
+ RigidBody* body = Rice::detail::From_Ruby<RigidBody*>().convert(rigid_body);
467
+ add_rigid_body(*body);
468
+ collision_object_values_[body->get()] = rigid_body;
469
+ }
470
+
471
+ void DiscreteDynamicsWorld::remove_rigid_body(RigidBody& rigid_body)
472
+ {
473
+ btRigidBody* body = rigid_body.get();
474
+ auto iterator = rigid_bodies_.find(body);
475
+ if (iterator != rigid_bodies_.end()) {
476
+ world_->removeRigidBody(body);
477
+ rigid_bodies_.erase(iterator);
478
+ }
479
+ collision_object_values_.erase(body);
480
+ }
481
+
482
+ void DiscreteDynamicsWorld::remove_rigid_body_object(VALUE rigid_body)
483
+ {
484
+ RigidBody* body = Rice::detail::From_Ruby<RigidBody*>().convert(rigid_body);
485
+ remove_rigid_body(*body);
486
+ }
487
+
488
+ void DiscreteDynamicsWorld::add_constraint_object(VALUE constraint, bool disable_collisions_between_linked_bodies)
489
+ {
490
+ TypedConstraint* typed_constraint = Rice::detail::From_Ruby<TypedConstraint*>().convert(constraint);
491
+ if (typed_constraint == nullptr) {
492
+ throw std::invalid_argument("expected Bullet3::Constraints::TypedConstraint");
493
+ }
494
+
495
+ btTypedConstraint* bullet_constraint = typed_constraint->get();
496
+ if (constraints_.insert(bullet_constraint).second) {
497
+ world_->addConstraint(bullet_constraint, disable_collisions_between_linked_bodies);
498
+ constraint_values_[bullet_constraint] = constraint;
499
+ }
500
+ }
501
+
502
+ void DiscreteDynamicsWorld::remove_constraint_object(VALUE constraint)
503
+ {
504
+ TypedConstraint* typed_constraint = Rice::detail::From_Ruby<TypedConstraint*>().convert(constraint);
505
+ if (typed_constraint == nullptr) {
506
+ throw std::invalid_argument("expected Bullet3::Constraints::TypedConstraint");
507
+ }
508
+
509
+ btTypedConstraint* bullet_constraint = typed_constraint->get();
510
+ auto iterator = constraints_.find(bullet_constraint);
511
+ if (iterator != constraints_.end()) {
512
+ world_->removeConstraint(bullet_constraint);
513
+ constraints_.erase(iterator);
514
+ }
515
+ constraint_values_.erase(bullet_constraint);
516
+ }
517
+
518
+ void DiscreteDynamicsWorld::add_vehicle_object(VALUE vehicle)
519
+ {
520
+ RaycastVehicle* raycast_vehicle = Rice::detail::From_Ruby<RaycastVehicle*>().convert(vehicle);
521
+ if (raycast_vehicle == nullptr) {
522
+ throw std::invalid_argument("expected Bullet3::RaycastVehicle");
523
+ }
524
+
525
+ btRaycastVehicle* bullet_vehicle = raycast_vehicle->get();
526
+ if (actions_.insert(bullet_vehicle).second) {
527
+ world_->addAction(bullet_vehicle);
528
+ action_values_[bullet_vehicle] = vehicle;
529
+ }
530
+ }
531
+
532
+ void DiscreteDynamicsWorld::remove_vehicle_object(VALUE vehicle)
533
+ {
534
+ RaycastVehicle* raycast_vehicle = Rice::detail::From_Ruby<RaycastVehicle*>().convert(vehicle);
535
+ if (raycast_vehicle == nullptr) {
536
+ throw std::invalid_argument("expected Bullet3::RaycastVehicle");
537
+ }
538
+
539
+ btRaycastVehicle* bullet_vehicle = raycast_vehicle->get();
540
+ auto iterator = actions_.find(bullet_vehicle);
541
+ if (iterator != actions_.end()) {
542
+ world_->removeAction(bullet_vehicle);
543
+ actions_.erase(iterator);
544
+ }
545
+ action_values_.erase(bullet_vehicle);
546
+ }
547
+
548
+ int DiscreteDynamicsWorld::step_simulation(btScalar time_step, int max_sub_steps, btScalar fixed_time_step)
549
+ {
550
+ StepSimulationArgs args{world_.get(), time_step, max_sub_steps, fixed_time_step, 0};
551
+ rb_thread_call_without_gvl(step_simulation_without_gvl, &args, nullptr, nullptr);
552
+ return args.result;
553
+ }
554
+
555
+ int DiscreteDynamicsWorld::num_collision_objects() const
556
+ {
557
+ return world_->getNumCollisionObjects();
558
+ }
559
+
560
+ int DiscreteDynamicsWorld::num_constraints() const
561
+ {
562
+ return world_->getNumConstraints();
563
+ }
564
+
565
+ void DiscreteDynamicsWorld::clear_forces()
566
+ {
567
+ world_->clearForces();
568
+ }
569
+
570
+ void DiscreteDynamicsWorld::synchronize_motion_states()
571
+ {
572
+ world_->synchronizeMotionStates();
573
+ }
574
+
575
+ VALUE DiscreteDynamicsWorld::ruby_object_for(const btCollisionObject* collision_object) const
576
+ {
577
+ auto iterator = collision_object_values_.find(collision_object);
578
+ if (iterator == collision_object_values_.end()) {
579
+ return Qnil;
580
+ }
581
+ return iterator->second;
582
+ }
583
+
584
+ Rice::Object DiscreteDynamicsWorld::ray_test_closest(Rice::Object from, Rice::Object to) const
585
+ {
586
+ btVector3 ray_from = coerce_vector(from);
587
+ btVector3 ray_to = coerce_vector(to);
588
+ btCollisionWorld::ClosestRayResultCallback callback(ray_from, ray_to);
589
+ world_->rayTest(ray_from, ray_to, callback);
590
+
591
+ if (!callback.hasHit()) {
592
+ return Rice::Object(Qnil);
593
+ }
594
+
595
+ Rice::Hash hit;
596
+ hit[Rice::Symbol("body")] = Rice::Object(ruby_object_for(callback.m_collisionObject));
597
+ hit[Rice::Symbol("fraction")] = callback.m_closestHitFraction;
598
+ set_vector_hash_value(hit, "point", callback.m_hitPointWorld);
599
+ set_vector_hash_value(hit, "normal", callback.m_hitNormalWorld);
600
+ return hit;
601
+ }
602
+
603
+ Rice::Array DiscreteDynamicsWorld::ray_test_all(Rice::Object from, Rice::Object to) const
604
+ {
605
+ btVector3 ray_from = coerce_vector(from);
606
+ btVector3 ray_to = coerce_vector(to);
607
+ btCollisionWorld::AllHitsRayResultCallback callback(ray_from, ray_to);
608
+ world_->rayTest(ray_from, ray_to, callback);
609
+
610
+ Rice::Array hits;
611
+ for (int index = 0; index < callback.m_collisionObjects.size(); ++index) {
612
+ Rice::Hash hit;
613
+ hit[Rice::Symbol("body")] = Rice::Object(ruby_object_for(callback.m_collisionObjects[index]));
614
+ hit[Rice::Symbol("fraction")] = callback.m_hitFractions[index];
615
+ set_vector_hash_value(hit, "point", callback.m_hitPointWorld[index]);
616
+ set_vector_hash_value(hit, "normal", callback.m_hitNormalWorld[index]);
617
+ hits.push(hit);
618
+ }
619
+ return hits;
620
+ }
621
+
622
+ Rice::Array DiscreteDynamicsWorld::contact_test(VALUE rigid_body) const
623
+ {
624
+ RigidBody* body = rigid_body_from_value(rigid_body);
625
+ ContactCollector callback([this](const btCollisionObject* collision_object) {
626
+ return ruby_object_for(collision_object);
627
+ });
628
+ world_->contactTest(body->get(), callback);
629
+ return callback.contacts;
630
+ }
631
+
632
+ Rice::Array DiscreteDynamicsWorld::contact_pair_test(VALUE rigid_body_a, VALUE rigid_body_b) const
633
+ {
634
+ RigidBody* body_a = rigid_body_from_value(rigid_body_a);
635
+ RigidBody* body_b = rigid_body_from_value(rigid_body_b);
636
+ ContactCollector callback([this](const btCollisionObject* collision_object) {
637
+ return ruby_object_for(collision_object);
638
+ });
639
+ world_->contactPairTest(body_a->get(), body_b->get(), callback);
640
+ return callback.contacts;
641
+ }
642
+
643
+ Rice::Array DiscreteDynamicsWorld::closest_points(VALUE rigid_body_a, VALUE rigid_body_b, btScalar distance_threshold) const
644
+ {
645
+ RigidBody* body_a = rigid_body_from_value(rigid_body_a);
646
+ RigidBody* body_b = rigid_body_from_value(rigid_body_b);
647
+ ContactCollector callback([this](const btCollisionObject* collision_object) {
648
+ return ruby_object_for(collision_object);
649
+ });
650
+ callback.m_closestDistanceThreshold = distance_threshold;
651
+ world_->contactPairTest(body_a->get(), body_b->get(), callback);
652
+ return callback.contacts;
653
+ }
654
+
655
+ Rice::Array DiscreteDynamicsWorld::contact_manifolds() const
656
+ {
657
+ Rice::Array manifolds;
658
+ btDispatcher* dispatcher = world_->getDispatcher();
659
+ int manifold_count = dispatcher->getNumManifolds();
660
+
661
+ for (int manifold_index = 0; manifold_index < manifold_count; ++manifold_index) {
662
+ btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(manifold_index);
663
+ Rice::Hash manifold_hash;
664
+ manifold_hash[Rice::Symbol("body0")] = Rice::Object(ruby_object_for(static_cast<const btCollisionObject*>(manifold->getBody0())));
665
+ manifold_hash[Rice::Symbol("body1")] = Rice::Object(ruby_object_for(static_cast<const btCollisionObject*>(manifold->getBody1())));
666
+
667
+ Rice::Array points;
668
+ for (int point_index = 0; point_index < manifold->getNumContacts(); ++point_index) {
669
+ const btManifoldPoint& point = manifold->getContactPoint(point_index);
670
+ Rice::Hash point_hash;
671
+ set_vector_hash_value(point_hash, "position_world_on_a", point.getPositionWorldOnA());
672
+ set_vector_hash_value(point_hash, "position_world_on_b", point.getPositionWorldOnB());
673
+ set_vector_hash_value(point_hash, "normal_world_on_b", point.m_normalWorldOnB);
674
+ point_hash[Rice::Symbol("distance")] = point.getDistance();
675
+ point_hash[Rice::Symbol("life_time")] = point.getLifeTime();
676
+ points.push(point_hash);
677
+ }
678
+
679
+ manifold_hash[Rice::Symbol("points")] = points;
680
+ manifolds.push(manifold_hash);
681
+ }
682
+
683
+ return manifolds;
684
+ }
685
+
686
+ void DiscreteDynamicsWorld::set_debug_drawer(VALUE debug_drawer)
687
+ {
688
+ DebugDraw* drawer = Rice::detail::From_Ruby<DebugDraw*>().convert(debug_drawer);
689
+ if (drawer == nullptr) {
690
+ throw std::invalid_argument("expected Bullet3::DebugDraw");
691
+ }
692
+
693
+ debug_drawer_value_ = debug_drawer;
694
+ world_->setDebugDrawer(drawer->get());
695
+ }
696
+
697
+ VALUE DiscreteDynamicsWorld::debug_drawer() const
698
+ {
699
+ return debug_drawer_value_;
700
+ }
701
+
702
+ void DiscreteDynamicsWorld::debug_draw_world()
703
+ {
704
+ world_->debugDrawWorld();
705
+ }
706
+
707
+ void DiscreteDynamicsWorld::mark() const
708
+ {
709
+ for (const auto& entry : collision_object_values_) {
710
+ rb_gc_mark(entry.second);
711
+ }
712
+ for (const auto& entry : constraint_values_) {
713
+ rb_gc_mark(entry.second);
714
+ }
715
+ for (const auto& entry : action_values_) {
716
+ rb_gc_mark(entry.second);
717
+ }
718
+ rb_gc_mark(debug_drawer_value_);
719
+ }
720
+ } // namespace bullet3
721
+
722
+ namespace Rice {
723
+ template <>
724
+ void ruby_mark<bullet3::DiscreteDynamicsWorld>(bullet3::DiscreteDynamicsWorld* world)
725
+ {
726
+ if (world != nullptr) {
727
+ world->mark();
728
+ }
729
+ }
730
+ } // namespace Rice
731
+
732
+ void Init_Dynamics(Rice::Module rb_mBullet)
733
+ {
734
+ Rice::define_class_under<bullet3::CollisionConfiguration>(rb_mBullet, "CollisionConfiguration")
735
+ .define_constructor(Rice::Constructor<bullet3::CollisionConfiguration>());
736
+
737
+ Rice::define_class_under<bullet3::CollisionDispatcher>(rb_mBullet, "CollisionDispatcher")
738
+ .define_constructor(Rice::Constructor<bullet3::CollisionDispatcher, bullet3::CollisionConfiguration&>(),
739
+ Rice::Arg("configuration").keepAlive());
740
+
741
+ Rice::define_class_under<bullet3::DbvtBroadphase>(rb_mBullet, "DbvtBroadphase")
742
+ .define_constructor(Rice::Constructor<bullet3::DbvtBroadphase>());
743
+
744
+ Rice::define_class_under<bullet3::SequentialImpulseConstraintSolver>(rb_mBullet, "SequentialImpulseConstraintSolver")
745
+ .define_constructor(Rice::Constructor<bullet3::SequentialImpulseConstraintSolver>());
746
+
747
+ Rice::define_class_under<bullet3::MotionState>(rb_mBullet, "MotionState")
748
+ .define_constructor(Rice::Constructor<bullet3::MotionState>())
749
+ .define_constructor(Rice::Constructor<bullet3::MotionState, VALUE>(),
750
+ Rice::Arg("start_transform").setValue())
751
+ .define_method("world_transform", &bullet3::MotionState::world_transform)
752
+ .define_method("world_transform=", &bullet3::MotionState::set_world_transform);
753
+
754
+ Rice::define_class_under<bullet3::RigidBodyConstructionInfo>(rb_mBullet, "RigidBodyConstructionInfo")
755
+ .define_constructor(Rice::Constructor<bullet3::RigidBodyConstructionInfo,
756
+ btScalar,
757
+ bullet3::MotionState&,
758
+ VALUE>(),
759
+ Rice::Arg("mass"),
760
+ Rice::Arg("motion_state").keepAlive(),
761
+ Rice::Arg("collision_shape").setValue().keepAlive())
762
+ .define_constructor(Rice::Constructor<bullet3::RigidBodyConstructionInfo,
763
+ btScalar,
764
+ bullet3::MotionState&,
765
+ VALUE,
766
+ VALUE>(),
767
+ Rice::Arg("mass"),
768
+ Rice::Arg("motion_state").keepAlive(),
769
+ Rice::Arg("collision_shape").setValue().keepAlive(),
770
+ Rice::Arg("local_inertia").setValue())
771
+ .define_method("mass", &bullet3::RigidBodyConstructionInfo::mass)
772
+ .define_method("local_inertia", &bullet3::RigidBodyConstructionInfo::local_inertia)
773
+ .define_method("friction", &bullet3::RigidBodyConstructionInfo::friction)
774
+ .define_method("friction=", &bullet3::RigidBodyConstructionInfo::set_friction)
775
+ .define_method("restitution", &bullet3::RigidBodyConstructionInfo::restitution)
776
+ .define_method("restitution=", &bullet3::RigidBodyConstructionInfo::set_restitution);
777
+
778
+ Rice::define_class_under<bullet3::RigidBody>(rb_mBullet, "RigidBody")
779
+ .define_constructor(Rice::Constructor<bullet3::RigidBody, bullet3::RigidBodyConstructionInfo&>(),
780
+ Rice::Arg("construction_info").keepAlive())
781
+ .define_method("mass", &bullet3::RigidBody::mass)
782
+ .define_method("collision_shape", &bullet3::RigidBody::collision_shape)
783
+ .define_method("world_transform", &bullet3::RigidBody::world_transform)
784
+ .define_method("world_transform=", &bullet3::RigidBody::set_world_transform)
785
+ .define_method("linear_velocity", &bullet3::RigidBody::linear_velocity)
786
+ .define_method("linear_velocity=", &bullet3::RigidBody::set_linear_velocity)
787
+ .define_method("angular_velocity", &bullet3::RigidBody::angular_velocity)
788
+ .define_method("angular_velocity=", &bullet3::RigidBody::set_angular_velocity)
789
+ .define_method("total_force", &bullet3::RigidBody::total_force)
790
+ .define_method("total_torque", &bullet3::RigidBody::total_torque)
791
+ .define_method("friction", &bullet3::RigidBody::friction)
792
+ .define_method("friction=", &bullet3::RigidBody::set_friction)
793
+ .define_method("restitution", &bullet3::RigidBody::restitution)
794
+ .define_method("restitution=", &bullet3::RigidBody::set_restitution)
795
+ .define_method("damping", &bullet3::RigidBody::damping)
796
+ .define_method("set_damping", &bullet3::RigidBody::set_damping)
797
+ .define_method("apply_central_force", &bullet3::RigidBody::apply_central_force)
798
+ .define_method("apply_force", &bullet3::RigidBody::apply_force)
799
+ .define_method("apply_torque", &bullet3::RigidBody::apply_torque)
800
+ .define_method("apply_central_impulse", &bullet3::RigidBody::apply_central_impulse)
801
+ .define_method("apply_impulse", &bullet3::RigidBody::apply_impulse)
802
+ .define_method("clear_forces", &bullet3::RigidBody::clear_forces)
803
+ .define_method("activate", &bullet3::RigidBody::activate)
804
+ .define_method("active?", &bullet3::RigidBody::active)
805
+ .define_method("static?", &bullet3::RigidBody::static_object)
806
+ .define_method("kinematic?", &bullet3::RigidBody::kinematic_object);
807
+
808
+ Rice::define_class_under<bullet3::DiscreteDynamicsWorld>(rb_mBullet, "DiscreteDynamicsWorld")
809
+ .define_constructor(Rice::Constructor<bullet3::DiscreteDynamicsWorld>())
810
+ .define_constructor(Rice::Constructor<bullet3::DiscreteDynamicsWorld,
811
+ bullet3::CollisionDispatcher&,
812
+ bullet3::DbvtBroadphase&,
813
+ bullet3::SequentialImpulseConstraintSolver&,
814
+ bullet3::CollisionConfiguration&>(),
815
+ Rice::Arg("dispatcher").keepAlive(),
816
+ Rice::Arg("broadphase").keepAlive(),
817
+ Rice::Arg("solver").keepAlive(),
818
+ Rice::Arg("configuration").keepAlive())
819
+ .define_singleton_method("create", [](Rice::Object) -> bullet3::DiscreteDynamicsWorld* {
820
+ return new bullet3::DiscreteDynamicsWorld();
821
+ }, Rice::Return().takeOwnership())
822
+ .define_method("gravity", &bullet3::DiscreteDynamicsWorld::gravity)
823
+ .define_method("gravity=", &bullet3::DiscreteDynamicsWorld::set_gravity)
824
+ .define_method("add_rigid_body", &bullet3::DiscreteDynamicsWorld::add_rigid_body_object,
825
+ Rice::Arg("rigid_body").setValue().keepAlive())
826
+ .define_method("remove_rigid_body", &bullet3::DiscreteDynamicsWorld::remove_rigid_body_object,
827
+ Rice::Arg("rigid_body").setValue())
828
+ .define_method("add_constraint", &bullet3::DiscreteDynamicsWorld::add_constraint_object,
829
+ Rice::Arg("constraint").setValue().keepAlive(),
830
+ Rice::Arg("disable_collisions_between_linked_bodies") = false)
831
+ .define_method("remove_constraint", &bullet3::DiscreteDynamicsWorld::remove_constraint_object,
832
+ Rice::Arg("constraint").setValue())
833
+ .define_method("add_vehicle", &bullet3::DiscreteDynamicsWorld::add_vehicle_object,
834
+ Rice::Arg("vehicle").setValue().keepAlive())
835
+ .define_method("remove_vehicle", &bullet3::DiscreteDynamicsWorld::remove_vehicle_object,
836
+ Rice::Arg("vehicle").setValue())
837
+ .define_method("step_simulation", &bullet3::DiscreteDynamicsWorld::step_simulation,
838
+ Rice::Arg("time_step"),
839
+ Rice::Arg("max_sub_steps") = 1,
840
+ Rice::Arg("fixed_time_step") = btScalar(1.0 / 60.0))
841
+ .define_method("num_collision_objects", &bullet3::DiscreteDynamicsWorld::num_collision_objects)
842
+ .define_method("num_constraints", &bullet3::DiscreteDynamicsWorld::num_constraints)
843
+ .define_method("clear_forces", &bullet3::DiscreteDynamicsWorld::clear_forces)
844
+ .define_method("synchronize_motion_states", &bullet3::DiscreteDynamicsWorld::synchronize_motion_states)
845
+ .define_method("ray_test_closest", &bullet3::DiscreteDynamicsWorld::ray_test_closest)
846
+ .define_method("ray_test", &bullet3::DiscreteDynamicsWorld::ray_test_closest)
847
+ .define_method("ray_test_all", &bullet3::DiscreteDynamicsWorld::ray_test_all)
848
+ .define_method("contact_test", &bullet3::DiscreteDynamicsWorld::contact_test,
849
+ Rice::Arg("rigid_body").setValue())
850
+ .define_method("contact_pair_test", &bullet3::DiscreteDynamicsWorld::contact_pair_test,
851
+ Rice::Arg("rigid_body_a").setValue(),
852
+ Rice::Arg("rigid_body_b").setValue())
853
+ .define_method("closest_points", &bullet3::DiscreteDynamicsWorld::closest_points,
854
+ Rice::Arg("rigid_body_a").setValue(),
855
+ Rice::Arg("rigid_body_b").setValue(),
856
+ Rice::Arg("distance_threshold") = btScalar(0.0))
857
+ .define_method("contact_manifolds", &bullet3::DiscreteDynamicsWorld::contact_manifolds)
858
+ .define_method("debug_drawer", &bullet3::DiscreteDynamicsWorld::debug_drawer)
859
+ .define_method("debug_drawer=", &bullet3::DiscreteDynamicsWorld::set_debug_drawer,
860
+ Rice::Arg("debug_drawer").setValue().keepAlive())
861
+ .define_method("debug_draw_world", &bullet3::DiscreteDynamicsWorld::debug_draw_world);
862
+ }