BLUELOVETH 2 лет назад
Родитель
Сommit
f9d4269caf

+ 3 - 1
3rd/box2d/CMakeLists.txt

@@ -12,6 +12,8 @@ aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/common BOX2D_SRC_1)
 aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/dynamics BOX2D_SRC_2)
 aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src/rope BOX2D_SRC_3)
 
+aux_source_directory(${CMAKE_CURRENT_LIST_DIR}/src BOX2D_BINDINGS_SRC)
+
 set(CMAKE_CXX_FLAGS_RELEASE "-O2")
 
 set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@@ -20,5 +22,5 @@ add_library(
     box2d
     STATIC
     ${BOX2D_SRC_0} ${BOX2D_SRC_1} ${BOX2D_SRC_2} ${BOX2D_SRC_3}
-    ${CMAKE_CURRENT_LIST_DIR}/src/box2d_bindings.cpp
+    ${BOX2D_BINDINGS_SRC}
 )

+ 2 - 5
3rd/box2d/include/box2d_bindings.hpp

@@ -1,5 +1,6 @@
 #pragma once
 
+#include "box2d/b2_world.h"
 #include "box2d/box2d.h"
 #include "pocketpy/pocketpy.h"
 #include <cstdlib>
@@ -24,6 +25,7 @@ inline PyObject* py_var(VM* vm, b2Vec2 v){
 
 namespace imbox2d{
 
+
 struct Body final{
     b2Body* body;
     b2Fixture* fixture;
@@ -133,12 +135,7 @@ struct PyBody: OpaquePointer<Body>{
     static void _register(VM* vm, PyObject* mod, PyObject* type);
 };
 
-struct PyWorld: OpaquePointer<b2World>{
-    PY_CLASS(PyWorld, box2d, World)
 
-    using OpaquePointer<b2World>::OpaquePointer;
-    static void _register(VM* vm, PyObject* mod, PyObject* type);
-};
 
 }   // namespace imbox2d
 

+ 0 - 0
3rd/box2d/src/box2d_Body.cpp


+ 194 - 0
3rd/box2d/src/box2d_World.cpp

@@ -0,0 +1,194 @@
+#include "box2d/b2_world.h"
+#include "box2d/b2_world_callbacks.h"
+#include "box2d_bindings.hpp"
+
+namespace pkpy{
+    namespace imbox2d{
+
+// This class captures the closest hit shape.
+class MyRayCastCallback : public b2RayCastCallback
+{
+    VM* vm;
+public:
+    List result;
+    MyRayCastCallback(VM* vm): vm(vm) {}
+ 
+    float ReportFixture(b2Fixture* fixture, const b2Vec2& point,
+                        const b2Vec2& normal, float fraction)
+    {
+        auto userdata = fixture->GetBody()->GetUserData().pointer;
+        Body* body = reinterpret_cast<Body*>(userdata);
+        result.push_back(VAR_T(PyBody, body));
+        // if(only_one) return 0;
+        return fraction;
+    }
+};
+
+class MyBoxCastCallback: public b2QueryCallback{
+    VM* vm;
+public:
+    List result;
+    MyBoxCastCallback(VM* vm): vm(vm) {}
+
+    bool ReportFixture(b2Fixture* fixture) override{
+        auto userdata = fixture->GetBody()->GetUserData().pointer;
+        Body* body = reinterpret_cast<Body*>(userdata);
+        result.push_back(VAR_T(PyBody, body));
+        return true;
+    }
+};
+
+// maybe we will use this class later
+class PyDebugDraw: public b2Draw{
+    VM* vm;
+public:
+    PyDebugDraw(VM* vm): vm(vm){}
+
+    void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
+    }
+
+    void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
+    }
+
+    void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override{
+    }
+
+    void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override{
+    }
+
+    void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override{
+    }
+
+    void DrawTransform(const b2Transform& xf) override{
+    }
+
+    void DrawPoint(const b2Vec2& p, float size, const b2Color& color) override{
+    }
+};
+
+class PyContactListener : public b2ContactListener{
+    VM* vm;
+public:
+    PyContactListener(VM* vm): vm(vm){}
+
+    void _contact_f(b2Contact* contact, StrName name){
+        auto a = contact->GetFixtureA()->GetBody()->GetUserData().pointer;
+        auto b = contact->GetFixtureB()->GetBody()->GetUserData().pointer;
+        Body* bodyA = reinterpret_cast<Body*>(a);
+        Body* bodyB = reinterpret_cast<Body*>(b);
+        PyObject* self;
+        PyObject* f;
+        f = vm->get_unbound_method(bodyA->obj, name, &self, false);
+        if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyB));
+        f = vm->get_unbound_method(bodyB->obj, name, &self, false);
+        if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyA));
+    }
+
+	void BeginContact(b2Contact* contact) override {
+        DEF_SNAME(on_contact_begin);
+        _contact_f(contact, on_contact_begin);
+    }
+
+    void EndContact(b2Contact* contact) override {
+        DEF_SNAME(on_contact_end);
+        _contact_f(contact, on_contact_end);
+    }
+};
+
+// implement placement VAR_T...!!!!
+struct PyWorld {
+    PY_CLASS(PyWorld, box2d, World)
+
+    // this object is too large, so we use unique_ptr
+    std::unique_ptr<b2World> world;
+    std::unique_ptr<PyContactListener> _contact_listener;
+    std::unique_ptr<PyDebugDraw> _debug_draw;
+
+    PyWorld(VM* vm):
+            world(new b2World(b2Vec2(0, 0))),
+            _contact_listener(new PyContactListener(vm)),
+            _debug_draw(new PyDebugDraw(vm)){
+        world->SetAllowSleeping(true);
+        world->SetAutoClearForces(true);
+        world->SetContactListener(_contact_listener.get());
+        world->SetDebugDraw(_debug_draw.get());
+    }
+
+    PyWorld(const PyWorld&) = delete;
+    PyWorld& operator=(const PyWorld&) = delete;
+
+    static void _register(VM* vm, PyObject* mod, PyObject* type){
+    vm->bind(type, "__new__(cls)", [](VM* vm, ArgsView args){
+        return VAR_T(PyWorld, PyWorld(vm));
+    });
+
+    // gravity
+    vm->bind_property(type, "gravity", "vec2", [](VM* vm, ArgsView args){
+        PyWorld& self = _CAST(PyWorld&, args[0]);
+        return VAR(self.world->GetGravity());
+    }, [](VM* vm, ArgsView args){
+        PyWorld& self = _CAST(PyWorld&, args[0]);
+        self.world->SetGravity(CAST(b2Vec2, args[1]));
+        return vm->None;
+    });
+
+    vm->bind(type, "get_bodies(self) -> list[Body]", [](VM* vm, ArgsView args){
+        PyWorld& self = _CAST(PyWorld&, args[0]);
+        List list;
+        b2Body* p = self.world->GetBodyList();
+        while(p != nullptr){
+            Body* body = (Body*)p->GetUserData().pointer;
+            list.push_back(VAR_T(PyBody, body));
+            p = p->GetNext();
+        }
+        return VAR(std::move(list));
+    });
+
+    vm->bind(type, "ray_cast(self, start: vec2, end: vec2) -> list[Body]", [](VM* vm, ArgsView args){
+        auto _lock = vm->heap.gc_scope_lock();
+        PyWorld& self = _CAST(PyWorld&, args[0]);
+        b2Vec2 start = CAST(b2Vec2, args[1]);
+        b2Vec2 end = CAST(b2Vec2, args[2]);
+        MyRayCastCallback callback(vm);
+        self.world->RayCast(&callback, start, end);
+        return VAR(std::move(callback.result));
+    });
+
+    vm->bind(type, "box_cast(self, lower: vec2, upper: vec2) -> list[Body]", [](VM* vm, ArgsView args){
+        auto _lock = vm->heap.gc_scope_lock();
+        PyWorld& self = _CAST(PyWorld&, args[0]);
+        b2AABB aabb;
+        aabb.lowerBound = CAST(b2Vec2, args[1]);
+        aabb.upperBound = CAST(b2Vec2, args[2]);
+        MyBoxCastCallback callback(vm);
+        self.world->QueryAABB(&callback, aabb);
+        return VAR(std::move(callback.result));
+    });
+
+    vm->bind(type, "step(self, dt: float, velocity_iterations: int, position_iterations: int)",
+        [](VM* vm, ArgsView args){
+            PyWorld& self = _CAST(PyWorld&, args[0]);
+            float dt = CAST(float, args[1]);
+            int velocity_iterations = CAST(int, args[2]);
+            int position_iterations = CAST(int, args[3]);
+
+            auto f = [](VM* vm, b2Body* p, StrName name){
+                while(p != nullptr){
+                    Body* body = (Body*)p->GetUserData().pointer;
+                    vm->call_method(body->obj, name);
+                    p = p->GetNext();
+                }
+            };
+
+            DEF_SNAME(on_box2d_pre_step);
+            DEF_SNAME(on_box2d_post_step);
+            f(vm, self.world->GetBodyList(), on_box2d_pre_step);
+            self.world->Step(dt, velocity_iterations, position_iterations);
+            f(vm, self.world->GetBodyList(), on_box2d_post_step);
+            return vm->None;
+        });
+    }
+};
+
+    }   // namespace imbox2d
+}   // namespace pkpy

+ 0 - 145
3rd/box2d/src/box2d_bindings.cpp

@@ -10,62 +10,7 @@ void add_module_box2d(VM *vm){
 
 namespace imbox2d{
 
-// maybe we will use this class later
-class PyDebugDraw: public b2Draw{
-    VM* vm;
-public:
-    PyDebugDraw(VM* vm): vm(vm){}
 
-    void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
-    }
-
-    void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) override{
-    }
-
-    void DrawCircle(const b2Vec2& center, float radius, const b2Color& color) override{
-    }
-
-    void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color) override{
-    }
-
-    void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) override{
-    }
-
-    void DrawTransform(const b2Transform& xf) override{
-    }
-
-    void DrawPoint(const b2Vec2& p, float size, const b2Color& color) override{
-    }
-};
-
-class PyContactListener : public b2ContactListener{
-    VM* vm;
-public:
-    PyContactListener(VM* vm): vm(vm){}
-
-    void _contact_f(b2Contact* contact, StrName name){
-        auto a = contact->GetFixtureA()->GetBody()->GetUserData().pointer;
-        auto b = contact->GetFixtureB()->GetBody()->GetUserData().pointer;
-        Body* bodyA = reinterpret_cast<Body*>(a);
-        Body* bodyB = reinterpret_cast<Body*>(b);
-        PyObject* self;
-        PyObject* f;
-        f = vm->get_unbound_method(bodyA->obj, name, &self, false);
-        if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyB));
-        f = vm->get_unbound_method(bodyB->obj, name, &self, false);
-        if(f != nullptr) vm->call_method(self, f, VAR_T(PyBody, bodyA));
-    }
-
-	void BeginContact(b2Contact* contact) override {
-        DEF_SNAME(on_contact_begin);
-        _contact_f(contact, on_contact_begin);
-    }
-
-    void EndContact(b2Contact* contact) override {
-        DEF_SNAME(on_contact_end);
-        _contact_f(contact, on_contact_end);
-    }
-};
 
     void PyBody::_register(VM* vm, PyObject* mod, PyObject* type){
         vm->bind_notimplemented_constructor<PyBody>(type);
@@ -221,100 +166,10 @@ public:
         });
     }
 
-// This class captures the closest hit shape.
-class MyRayCastCallback : public b2RayCastCallback
-{
-    VM* vm;
-public:
-    List result;
-    MyRayCastCallback(VM* vm): vm(vm) {}
- 
-    float ReportFixture(b2Fixture* fixture, const b2Vec2& point,
-                        const b2Vec2& normal, float fraction)
-    {
-        auto userdata = fixture->GetBody()->GetUserData().pointer;
-        Body* body = reinterpret_cast<Body*>(userdata);
-        result.push_back(VAR_T(PyBody, body));
-        // if(only_one) return 0;
-        return fraction;
-    }
-};
-
-
-    void PyWorld::_register(VM* vm, PyObject* mod, PyObject* type){
-        vm->bind(type, "__new__(cls)", [](VM* vm, ArgsView args){
-            b2World* w = new b2World(b2Vec2(0, 0));
-            w->SetAllowSleeping(true);
-            w->SetAutoClearForces(true);
-            // the contact listener will leak memory after the world is destroyed
-            // but it's not a big deal since the world is only destroyed when the game exits
-            w->SetContactListener(new PyContactListener(vm));
-            w->SetDebugDraw(new PyDebugDraw(vm));
-            return VAR_T(PyWorld, w);
-        });
-
-        // gravity
-        vm->bind_property(type, "gravity", "vec2", [](VM* vm, ArgsView args){
-            PyWorld& self = _CAST(PyWorld&, args[0]);
-            return VAR(self->GetGravity());
-        }, [](VM* vm, ArgsView args){
-            PyWorld& self = _CAST(PyWorld&, args[0]);
-            self->SetGravity(CAST(b2Vec2, args[1]));
-            return vm->None;
-        });
-
-        // body
-        vm->bind(type, "create_body(self, obj) -> Body", [](VM* vm, ArgsView args){
-            PyWorld& self = _CAST(PyWorld&, args[0]);
-            return VAR_T(PyBody, new Body(self.ptr, args[1]));
-        });
-        vm->bind(type, "get_bodies(self) -> list[Body]", [](VM* vm, ArgsView args){
-            PyWorld& self = _CAST(PyWorld&, args[0]);
-            List list;
-            b2Body* p = self->GetBodyList();
-            while(p != nullptr){
-                Body* body = (Body*)p->GetUserData().pointer;
-                list.push_back(VAR_T(PyBody, body));
-                p = p->GetNext();
-            }
-            return VAR(std::move(list));
-        });
 
-        // step
-        vm->bind(type, "step(self, dt: float, velocity_iterations: int, position_iterations: int)",
-            [](VM* vm, ArgsView args){
-                PyWorld& self = _CAST(PyWorld&, args[0]);
-                float dt = CAST(float, args[1]);
-                int velocity_iterations = CAST(int, args[2]);
-                int position_iterations = CAST(int, args[3]);
 
-                auto f = [](VM* vm, b2Body* p, StrName name){
-                    while(p != nullptr){
-                        Body* body = (Body*)p->GetUserData().pointer;
-                        vm->call_method(body->obj, name);
-                        p = p->GetNext();
-                    }
-                };
 
-                DEF_SNAME(on_box2d_pre_step);
-                DEF_SNAME(on_box2d_post_step);
-                f(vm, self->GetBodyList(), on_box2d_pre_step);
-                self->Step(dt, velocity_iterations, position_iterations);
-                f(vm, self->GetBodyList(), on_box2d_post_step);
-                return vm->None;
-            });
 
-        // raycast
-        vm->bind(type, "raycast(self, start: vec2, end: vec2) -> list[Body]", [](VM* vm, ArgsView args){
-            auto _lock = vm->heap.gc_scope_lock();
-            PyWorld& self = _CAST(PyWorld&, args[0]);
-            b2Vec2 start = CAST(b2Vec2, args[1]);
-            b2Vec2 end = CAST(b2Vec2, args[2]);
-            MyRayCastCallback callback(vm);
-            self->RayCast(&callback, start, end);
-            return VAR(std::move(callback.result));
-        });
-    }
 
 }
 

+ 1 - 4
docs/modules/box2d.md

@@ -68,15 +68,12 @@ class World:
     def ray_cast(self, start: vec2, end: vec2) -> list['Body']:
         """raycast from start to end"""
 
-    def box_cast(self, p0: vec2, p1: vec2) -> list['Body']:
+    def box_cast(self, lower: vec2, upper: vec2) -> list['Body']:
         """query bodies in the AABB region."""
 
     def step(self, dt: float, velocity_iterations: int, position_iterations: int) -> None:
         """step the simulation, e.g. world.step(1/60, 8, 3)"""
 
-    def destroy(self):
-        """destroy this world."""
-
 	# enum
 	# {
 	# 	e_shapeBit				= 0x0001,	///< draw shapes