box2d_bindings.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #pragma once
  2. #include "box2d/b2_world.h"
  3. #include "box2d/box2d.h"
  4. #include "pocketpy/pocketpy.h"
  5. namespace pkpy{
  6. template<>
  7. inline b2Vec2 py_cast<b2Vec2>(VM* vm, PyObject* obj){
  8. Vec2 v = py_cast<Vec2>(vm, obj);
  9. return b2Vec2(v.x, v.y);
  10. }
  11. template<>
  12. inline b2Vec2 _py_cast<b2Vec2>(VM* vm, PyObject* obj){
  13. Vec2 v = _py_cast<Vec2>(vm, obj);
  14. return b2Vec2(v.x, v.y);
  15. }
  16. inline PyObject* py_var(VM* vm, b2Vec2 v){
  17. return py_var(vm, Vec2(v.x, v.y));
  18. }
  19. }
  20. using namespace pkpy;
  21. namespace imbox2d{
  22. inline PyObject* get_body_object(b2Body* p){
  23. auto userdata = p->GetUserData().pointer;
  24. return reinterpret_cast<PyObject*>(userdata);
  25. }
  26. // maybe we will use this class later
  27. struct PyDebugDraw: b2Draw{
  28. PK_ALWAYS_PASS_BY_POINTER(PyDebugDraw)
  29. VM* vm;
  30. PyObject* draw_like;
  31. PyDebugDraw(VM* vm): vm(vm){}
  32. void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
  33. }
  34. void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
  35. }
  36. void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override{
  37. }
  38. void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override{
  39. }
  40. void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override{
  41. }
  42. void DrawTransform(const b2Transform& xf) override{
  43. }
  44. void DrawPoint(const b2Vec2& p, float size, const b2Color& color) override{
  45. }
  46. };
  47. struct PyContactListener: b2ContactListener{
  48. PK_ALWAYS_PASS_BY_POINTER(PyContactListener)
  49. VM* vm;
  50. PyContactListener(VM* vm): vm(vm){}
  51. void _contact_f(b2Contact* contact, StrName name){
  52. b2Body* bodyA = contact->GetFixtureA()->GetBody();
  53. b2Body* bodyB = contact->GetFixtureB()->GetBody();
  54. PyObject* a = get_body_object(bodyA);
  55. PyObject* b = get_body_object(bodyB);
  56. PyObject* self;
  57. PyObject* f;
  58. f = vm->get_unbound_method(a, name, &self, false);
  59. if(f != nullptr) vm->call_method(self, f, b);
  60. f = vm->get_unbound_method(b, name, &self, false);
  61. if(f != nullptr) vm->call_method(self, f, a);
  62. }
  63. void BeginContact(b2Contact* contact) override {
  64. DEF_SNAME(on_contact_begin);
  65. _contact_f(contact, on_contact_begin);
  66. }
  67. void EndContact(b2Contact* contact) override {
  68. DEF_SNAME(on_contact_end);
  69. _contact_f(contact, on_contact_end);
  70. }
  71. };
  72. struct PyBody{
  73. PY_CLASS(PyBody, box2d, Body)
  74. PK_ALWAYS_PASS_BY_POINTER(PyBody)
  75. b2Body* body;
  76. b2Fixture* fixture;
  77. PyObject* node_like;
  78. PyBody() = default;
  79. void _gc_mark() {
  80. PK_OBJ_MARK(node_like);
  81. }
  82. PyBody& _() { return *this; }
  83. b2Body& _b2Body() { return *body; }
  84. b2Fixture& _b2Fixture() { return *fixture; }
  85. static void _register(VM* vm, PyObject* mod, PyObject* type);
  86. // methods
  87. b2Vec2 get_position() const { return body->GetPosition(); }
  88. void set_position(b2Vec2 v){ body->SetTransform(v, body->GetAngle()); }
  89. float get_rotation() const { return body->GetAngle(); }
  90. void set_rotation(float v){ body->SetTransform(body->GetPosition(), v); }
  91. void apply_force(b2Vec2 force, b2Vec2 point){ body->ApplyForce(force, point, true); }
  92. void apply_force_to_center(b2Vec2 force){ body->ApplyForceToCenter(force, true); }
  93. void apply_torque(float torque){ body->ApplyTorque(torque, true); }
  94. void apply_impulse(b2Vec2 impulse, b2Vec2 point){
  95. body->ApplyLinearImpulse(impulse, point, true);
  96. }
  97. void apply_impulse_to_center(b2Vec2 impulse){
  98. body->ApplyLinearImpulseToCenter(impulse, true);
  99. }
  100. void apply_angular_impulse(float impulse){
  101. body->ApplyAngularImpulse(impulse, true);
  102. }
  103. };
  104. struct PyWorld {
  105. PY_CLASS(PyWorld, box2d, World)
  106. PK_ALWAYS_PASS_BY_POINTER(PyWorld)
  107. b2World world;
  108. PyContactListener _contact_listener;
  109. PyDebugDraw _debug_draw;
  110. PyWorld(VM* vm);
  111. void _gc_mark(){
  112. PK_OBJ_MARK(_debug_draw.draw_like);
  113. }
  114. static void _register(VM* vm, PyObject* mod, PyObject* type);
  115. };
  116. struct Body final{
  117. b2Body* body;
  118. b2Fixture* fixture;
  119. PyObject* obj;
  120. Vec4 debug_color;
  121. Body(b2World* world, PyObject* obj){
  122. b2BodyDef def;
  123. def.type = b2_dynamicBody;
  124. // a weak reference to the object, no need to mark it
  125. def.userData.pointer = reinterpret_cast<uintptr_t>(this);
  126. body = world->CreateBody(&def);
  127. fixture = nullptr;
  128. this->obj = obj;
  129. this->debug_color = Vec4(std::rand() / float(RAND_MAX), std::rand() / float(RAND_MAX), std::rand() / float(RAND_MAX), 1.0f);
  130. }
  131. void _update_fixture(b2Shape* shape){
  132. body->DestroyFixture(fixture); // this takes care of NULL case
  133. fixture = body->CreateFixture(shape, 1.0f);
  134. }
  135. Vec4 get_debug_color() const{ return debug_color; }
  136. b2Vec2 get_position() const{ return body->GetPosition(); }
  137. void set_position(b2Vec2 v){ body->SetTransform(v, get_rotation()); }
  138. void set_rotation(float angle){ body->SetTransform(get_position(), angle); }
  139. float get_rotation() const{ return body->GetAngle(); }
  140. void set_velocity(b2Vec2 v){ body->SetLinearVelocity(v); }
  141. b2Vec2 get_velocity() const{ return body->GetLinearVelocity(); }
  142. void set_angular_velocity(float omega){ body->SetAngularVelocity(omega); }
  143. float get_angular_velocity() const{ return body->GetAngularVelocity(); }
  144. void set_damping(float damping){ body->SetLinearDamping(damping); }
  145. float get_damping(){ return body->GetLinearDamping(); }
  146. void set_angular_damping(float damping){ body->SetAngularDamping(damping); }
  147. float get_angular_damping() const{ return body->GetAngularDamping(); }
  148. void set_gravity_scale(float scale){ body->SetGravityScale(scale); }
  149. float get_gravity_scale() const{ return body->GetGravityScale(); }
  150. void set_type(int type){ body->SetType(static_cast<b2BodyType>(type)); }
  151. int get_type() const{ return static_cast<int>(body->GetType()); }
  152. float get_mass() const{ return body->GetMass(); }
  153. float get_inertia() const{ return body->GetInertia(); }
  154. bool get_fixed_rotation() const{ return body->IsFixedRotation(); }
  155. void set_fixed_rotation(bool fixed){ body->SetFixedRotation(fixed); }
  156. // fixture settings
  157. float get_density() const{ return fixture->GetDensity(); }
  158. void set_density(float density){ fixture->SetDensity(density); }
  159. float get_friction() const{ return fixture->GetFriction(); }
  160. void set_friction(float friction){ fixture->SetFriction(friction); }
  161. float get_restitution() const{ return fixture->GetRestitution(); }
  162. void set_restitution(float restitution){ fixture->SetRestitution(restitution); }
  163. float get_restitution_threshold() const{ return fixture->GetRestitutionThreshold(); }
  164. void set_restitution_threshold(float threshold){ fixture->SetRestitutionThreshold(threshold); }
  165. bool get_is_trigger() const{ return fixture->IsSensor(); }
  166. void set_is_trigger(bool trigger){ fixture->SetSensor(trigger); }
  167. // methods
  168. void apply_force(b2Vec2 force, b2Vec2 point){
  169. body->ApplyForce(force, point, true);
  170. }
  171. void apply_force_to_center(b2Vec2 force){
  172. body->ApplyForceToCenter(force, true);
  173. }
  174. void apply_torque(float torque){
  175. body->ApplyTorque(torque, true);
  176. }
  177. void apply_linear_impulse(b2Vec2 impulse, b2Vec2 point){
  178. body->ApplyLinearImpulse(impulse, point, true);
  179. }
  180. void apply_linear_impulse_to_center(b2Vec2 impulse){
  181. body->ApplyLinearImpulseToCenter(impulse, true);
  182. }
  183. void apply_angular_impulse(float impulse){
  184. body->ApplyAngularImpulse(impulse, true);
  185. }
  186. void destroy(){
  187. if(body == nullptr) return;
  188. body->GetWorld()->DestroyBody(body);
  189. body = nullptr;
  190. }
  191. };
  192. } // namespace imbox2d
  193. namespace pkpy{
  194. inline void add_module_box2d(VM* vm){
  195. PyObject* mod = vm->new_module("box2d");
  196. imbox2d::PyBody::register_class(vm, mod);
  197. imbox2d::PyWorld::register_class(vm, mod);
  198. }
  199. }