From e48d3e2840b65b9db9e46d98b1196c5a2d8da4ed Mon Sep 17 00:00:00 2001
From: Joseph Walton-Rivers <joseph@walton-rivers.uk>
Date: Mon, 1 Aug 2022 15:05:52 +0100
Subject: [PATCH] add service-based physics

---
 demo/data/rollball.yml                        |   4 +-
 demo/demo/rollball.cpp                        |  20 +++-
 demo/include/rollball.hpp                     |   3 +
 fggl/entity/loader/loader.cpp                 |   7 +-
 fggl/entity/module.cpp                        |   2 +
 include/fggl/entity/entity.hpp                |   7 ++
 include/fggl/entity/loader/loader.hpp         |   8 +-
 include/fggl/entity/loader/spec.hpp           |   1 +
 include/fggl/phys/service.hpp                 |  37 +++++++
 integrations/bullet/CMakeLists.txt            |   1 +
 .../include/fggl/phys/bullet/module.hpp       |   5 +-
 .../include/fggl/phys/bullet/motion.hpp       |  12 +-
 .../include/fggl/phys/bullet/service.hpp      |  33 ++++++
 .../bullet/include/fggl/phys/bullet/types.hpp |   2 +
 integrations/bullet/src/module.cpp            |  69 +-----------
 integrations/bullet/src/service.cpp           | 103 ++++++++++++++++++
 integrations/bullet/src/simulation.cpp        |  11 +-
 17 files changed, 241 insertions(+), 84 deletions(-)
 create mode 100644 include/fggl/phys/service.hpp
 create mode 100644 integrations/bullet/include/fggl/phys/bullet/service.hpp
 create mode 100644 integrations/bullet/src/service.cpp

diff --git a/demo/data/rollball.yml b/demo/data/rollball.yml
index df682f1..ea445d5 100644
--- a/demo/data/rollball.yml
+++ b/demo/data/rollball.yml
@@ -86,6 +86,4 @@ prefabs:
       phys::Body:
         type: kinematic
         shape:
-          type: box
-      phys::Callbacks:
-      phys::Cache:
\ No newline at end of file
+          type: box
\ No newline at end of file
diff --git a/demo/demo/rollball.cpp b/demo/demo/rollball.cpp
index 88cc926..d3661ca 100644
--- a/demo/demo/rollball.cpp
+++ b/demo/demo/rollball.cpp
@@ -120,14 +120,18 @@ namespace demo {
 	constexpr fggl::math::vec3 COLOUR_BLUE{0.0F, 0.0F, 1.0F};
 	constexpr float MOVE_FORCE{3.0F};
 
-	RollBall::RollBall(fggl::App &app) : Game(app) {
+	RollBall::RollBall(fggl::App &app) : Game(app), m_phys(nullptr) {
 	}
 
 	void RollBall::activate() {
 		Game::activate();
-
 		fggl::debug::log(fggl::debug::Level::info, "RollBall::activate()");
 
+		// attach physics
+		auto* physService = m_owner.service<fggl::phys::PhysicsProvider>();
+		auto* entFactory = m_owner.service<fggl::entity::EntityFactory>();
+		m_phys = physService->create(&world(), entFactory);
+
 		auto* assetLoader = m_owner.service<fggl::assets::Loader>();
 		assetLoader->load("rollball.yml", fggl::entity::PROTOTYPE_ASSET);
 
@@ -150,6 +154,17 @@ namespace demo {
 		setup_environment(world(), m_owner.service<fggl::entity::EntityFactory>(), WORLD_SIZE, state);
 	}
 
+	void RollBall::deactivate() {
+		// we need to clean up physics
+		if ( m_phys != nullptr ) {
+			delete m_phys;
+			m_phys = nullptr;
+		}
+
+		// now let the rest of the scene do its bit
+		Game::deactivate();
+	}
+
 	fggl::math::vec3 calc_move_vector(const fggl::input::Input& input) {
 		constexpr fggl::math::vec3 forward = fggl::math::FORWARD;
 		constexpr fggl::math::vec3 right = fggl::math::RIGHT;
@@ -176,6 +191,7 @@ namespace demo {
 
 	void RollBall::update() {
 		Game::update();
+		m_phys->step();
 
 		const float deltaTime = 1 / 60.0F;
 
diff --git a/demo/include/rollball.hpp b/demo/include/rollball.hpp
index d18bb4b..1b39f03 100644
--- a/demo/include/rollball.hpp
+++ b/demo/include/rollball.hpp
@@ -26,6 +26,7 @@
 #define DEMO_ROLLBALL_HPP
 
 #include "fggl/scenes/game.hpp"
+#include "fggl/phys/service.hpp"
 
 namespace demo {
 
@@ -54,6 +55,7 @@ namespace demo {
 			explicit RollBall(fggl::App& app);
 
 			void activate() override;
+			void deactivate() override;
 
 			void update() override;
 			void render(fggl::gfx::Graphics& gfx) override;
@@ -61,6 +63,7 @@ namespace demo {
 		private:
 			constexpr static fggl::math::vec3 HINT_COLOUR{0.5f, 0.0f, 0.0f};
 			RollState state;
+			fggl::phys::PhysicsEngine* m_phys;
 			fggl::math::vec3 cameraOffset = {-15.0F, 15.0F, 0.0F};
 
 			void closestPickup(fggl::entity::EntityManager& world);
diff --git a/fggl/entity/loader/loader.cpp b/fggl/entity/loader/loader.cpp
index 62750d2..fb29fa8 100644
--- a/fggl/entity/loader/loader.cpp
+++ b/fggl/entity/loader/loader.cpp
@@ -32,7 +32,7 @@ namespace fggl::entity {
 				auto name = prefab["name"].as<fggl::util::GUID>();
 
 				#ifndef NDEBUG
-					debug::log(debug::Level::info, "found prefab: {}", fggl::util::guidToString(name) );
+					debug::info("found prefab: {}", fggl::util::guidToString(name) );
 				#endif
 
 				// setup the components
@@ -43,6 +43,11 @@ namespace fggl::entity {
 					ComponentSpec compSpec{};
 					compSpec.config = compEntry.second;
 					entity.components[compId] = compSpec;
+					entity.ordering.push_back(compId);
+
+					#ifndef NDEBUG
+						debug::trace("{} has component {}", fggl::util::guidToString(name), fggl::util::guidToString(compId));
+					#endif
 				}
 
 				factory->define( name, entity );
diff --git a/fggl/entity/module.cpp b/fggl/entity/module.cpp
index ee6b1c0..7efd1ec 100644
--- a/fggl/entity/module.cpp
+++ b/fggl/entity/module.cpp
@@ -26,6 +26,8 @@ namespace fggl::entity {
 		transform.origin( spec.get<math::vec3>( "origin", math::VEC3_ZERO ) );
 		transform.euler( spec.get<math::vec3>( "rotation", math::VEC3_ZERO ) );
 		transform.scale( spec.get<math::vec3>( "scale", math::VEC3_ONES ) );
+
+		debug::trace("created transform for entity {}", (uint64_t)entity);
 	}
 
 	void install_component_factories(entity::EntityFactory* factory) {
diff --git a/include/fggl/entity/entity.hpp b/include/fggl/entity/entity.hpp
index 05c3ba5..72d2d4a 100644
--- a/include/fggl/entity/entity.hpp
+++ b/include/fggl/entity/entity.hpp
@@ -20,6 +20,8 @@
 #define FGGL_ENTITY_ENTITY_HPP
 
 #include <cstdint>
+
+#include "fggl/debug/logging.hpp"
 #include "fggl/vendor/entt.hpp"
 
 namespace fggl::entity {
@@ -43,6 +45,11 @@ namespace fggl::entity {
 
 			template<typename Component>
 			Component& get(EntityID entity) {
+				#ifndef NDEBUG
+					if ( !has<Component>(entity) ) {
+						debug::error("Entity {} has no component of type {}", (uint64_t)entity, typeid(Component).name());
+					}
+				#endif
 				return m_registry.get<Component>(entity);
 			}
 
diff --git a/include/fggl/entity/loader/loader.hpp b/include/fggl/entity/loader/loader.hpp
index 8da4709..47381dd 100644
--- a/include/fggl/entity/loader/loader.hpp
+++ b/include/fggl/entity/loader/loader.hpp
@@ -47,17 +47,19 @@ namespace fggl::entity {
 
 					// invoke each component factory as required
 					auto entity = manager.create();
-					for (auto &[name, data] : prototype.components) {
+					for ( auto& component : prototype.ordering ) {
 						try {
-							m_factories.at(name)(data, manager, entity);
+							auto& data = prototype.components.at(component);
+							m_factories.at(component)(data, manager, entity);
 						} catch (std::out_of_range& ex) {
 							#ifndef NDEBUG
-								debug::log(debug::Level::error, "EntityFactory: Unknown component factory type '{}'", fggl::util::guidToString(name));
+							debug::log(debug::Level::error, "EntityFactory: Unknown component factory type '{}'", fggl::util::guidToString(component));
 							#endif
 							manager.destroy(entity);
 							return fggl::entity::INVALID;
 						}
 					}
+
 					return entity;
 				} catch (std::out_of_range& ex) {
 					#ifndef NDEBUG
diff --git a/include/fggl/entity/loader/spec.hpp b/include/fggl/entity/loader/spec.hpp
index 4dd926c..c9ef555 100644
--- a/include/fggl/entity/loader/spec.hpp
+++ b/include/fggl/entity/loader/spec.hpp
@@ -46,6 +46,7 @@ namespace fggl::entity {
 	};
 
 	struct EntitySpec {
+		std::vector<util::GUID> ordering;
 		std::map<util::GUID, ComponentSpec> components;
 	};
 
diff --git a/include/fggl/phys/service.hpp b/include/fggl/phys/service.hpp
new file mode 100644
index 0000000..54b84f9
--- /dev/null
+++ b/include/fggl/phys/service.hpp
@@ -0,0 +1,37 @@
+/*
+ * This file is part of FGGL.
+ *
+ * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with FGGL.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//
+// Created by webpigeon on 01/08/22.
+//
+
+#ifndef FGGL_PHYS_SERVICE_HPP
+#define FGGL_PHYS_SERVICE_HPP
+
+#include "fggl/modules/module.hpp"
+#include "fggl/entity/module.hpp"
+#include "fggl/phys/types.hpp"
+
+namespace fggl::phys {
+
+	class PhysicsProvider {
+		public:
+			constexpr static const modules::ModuleService service = modules::make_service("fggl::phys::service");
+
+			virtual PhysicsEngine* create(entity::EntityManager* entityManager, entity::EntityFactory* factory) = 0;
+	};
+
+}
+
+#endif //FGGL_PHYS_SERVICE_HPP
diff --git a/integrations/bullet/CMakeLists.txt b/integrations/bullet/CMakeLists.txt
index f128ed8..28134aa 100644
--- a/integrations/bullet/CMakeLists.txt
+++ b/integrations/bullet/CMakeLists.txt
@@ -35,5 +35,6 @@ else()
             src/module.cpp
             src/simulation.cpp
             src/phys_draw.cpp
+            src/service.cpp
     )
 endif()
diff --git a/integrations/bullet/include/fggl/phys/bullet/module.hpp b/integrations/bullet/include/fggl/phys/bullet/module.hpp
index 6950919..2f81006 100644
--- a/integrations/bullet/include/fggl/phys/bullet/module.hpp
+++ b/integrations/bullet/include/fggl/phys/bullet/module.hpp
@@ -23,22 +23,21 @@
 #include "fggl/entity/module.hpp"
 
 #include "fggl/phys/types.hpp"
+#include "fggl/phys/service.hpp"
 #include "fggl/phys/bullet/types.hpp"
 
 namespace fggl::phys::bullet {
 
-	constexpr modules::ModuleService BIND_BULLET = modules::make_service("bind_bullet");
 	constexpr util::GUID CONFIG_PHYS_BODY = util::make_guid("phys::body");
 
 	struct Bullet {
 		constexpr static const char* name = "fggl::phys::bullet";
 		constexpr static const std::array<modules::ModuleService, 1> provides = {
-			BIND_BULLET
+			phys::PhysicsProvider::service
 		};
 		constexpr static const std::array<modules::ModuleService, 1> depends = {
 			entity::EntityFactory::service
 		};
-
 		static bool factory(modules::ModuleService name, modules::Services& serviceManager);
 	};
 
diff --git a/integrations/bullet/include/fggl/phys/bullet/motion.hpp b/integrations/bullet/include/fggl/phys/bullet/motion.hpp
index 7a38a22..07c1a25 100644
--- a/integrations/bullet/include/fggl/phys/bullet/motion.hpp
+++ b/integrations/bullet/include/fggl/phys/bullet/motion.hpp
@@ -34,6 +34,7 @@
 #define FGGL_PHYS_BULLET_MOTION_HPP
 
 #include "types.hpp"
+#include "fggl/debug/logging.hpp"
 
 namespace fggl::phys::bullet {
 
@@ -41,11 +42,16 @@ namespace fggl::phys::bullet {
 		public:
 			FgglMotionState(entity::EntityManager* world, entity::EntityID entity) : m_world(world), m_entity(entity) {
 			}
-			virtual ~FgglMotionState() = default;
+			~FgglMotionState() override = default;
 
 			void getWorldTransform(btTransform& worldTrans) const override {
-				const auto& transform = m_world->get<fggl::math::Transform>(m_entity);
-				worldTrans.setFromOpenGLMatrix( glm::value_ptr(transform.model()) );
+				const auto* transform = m_world->tryGet<fggl::math::Transform>(m_entity);
+				if ( transform == nullptr ) {
+					debug::warning("BT: attempted to get transform of entity without transform component.");
+					return;
+				}
+
+				worldTrans.setFromOpenGLMatrix(glm::value_ptr(transform->model()));
 			}
 
 			void setWorldTransform(const btTransform& worldTrans) override {
diff --git a/integrations/bullet/include/fggl/phys/bullet/service.hpp b/integrations/bullet/include/fggl/phys/bullet/service.hpp
new file mode 100644
index 0000000..77adc64
--- /dev/null
+++ b/integrations/bullet/include/fggl/phys/bullet/service.hpp
@@ -0,0 +1,33 @@
+/*
+ * This file is part of FGGL.
+ *
+ * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with FGGL.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//
+// Created by webpigeon on 01/08/22.
+//
+
+#ifndef FGGL_INTEGRATIONS_BULLET_PHYS_BULLET_BULLETSERVICE_H
+#define FGGL_INTEGRATIONS_BULLET_PHYS_BULLET_BULLETSERVICE_H
+
+#include "fggl/phys/service.hpp"
+
+namespace fggl::phys::bullet {
+
+	class BulletProvider : public phys::PhysicsProvider {
+		public:
+			PhysicsEngine* create(entity::EntityManager* entityManager, entity::EntityFactory* factory) override;
+	};
+
+}
+
+#endif //FGGL_INTEGRATIONS_BULLET_PHYS_BULLET_BULLETSERVICE_H
diff --git a/integrations/bullet/include/fggl/phys/bullet/types.hpp b/integrations/bullet/include/fggl/phys/bullet/types.hpp
index 4d6857d..b692413 100644
--- a/integrations/bullet/include/fggl/phys/bullet/types.hpp
+++ b/integrations/bullet/include/fggl/phys/bullet/types.hpp
@@ -83,6 +83,8 @@ namespace fggl::phys::bullet {
 			std::vector<entity::EntityID> raycastAll(math::vec3 from, math::vec3 to) override;
 			std::vector<entity::EntityID> sweep(PhyShape& shape, math::Transform& from, math::Transform& to) override;
 
+			void addBody(entity::EntityID entity, BulletBody& body);
+
 			bool debugDraw = false;
 		private:
 			entity::EntityManager* m_ecs;
diff --git a/integrations/bullet/src/module.cpp b/integrations/bullet/src/module.cpp
index 7703f1d..e880506 100644
--- a/integrations/bullet/src/module.cpp
+++ b/integrations/bullet/src/module.cpp
@@ -17,76 +17,13 @@
 //
 
 #include "fggl/phys/bullet/module.hpp"
-#include "fggl/phys/bullet/motion.hpp"
+#include "fggl/phys/bullet/service.hpp"
 
 namespace fggl::phys::bullet {
 
-	constexpr float UNIT_EXTENT = 0.5F;
-
-	btCollisionShape* create_bullet_shape(const YAML::Node& node) {
-		auto type = node["type"].as<std::string>("MISSING");
-		if ( type == "sphere" ) {
-			auto radius = node["radius"].as<float>(UNIT_EXTENT);
-			return new btSphereShape(radius);
-		} else if ( type == "box" ) {
-			auto extents = node["extents"].as<math::vec3>(math::vec3(UNIT_EXTENT));
-			return new btBoxShape(btVector3(extents.x, extents.y, extents.z));
-		} else {
-			debug::warning("unknown shape type: {}, assuming unit sphere", type);
-			return new btSphereShape(0.5F);
-		}
-	}
-
-	void setup_body(BodyType type, btRigidBody& body) {
-		if ( type != BodyType::STATIC ) {
-			body.setRestitution(0.5F);
-			body.setRollingFriction(0.0F);
-
-			// kinematic bodies cannot sleep
-			if (type == BodyType::KINEMATIC) {
-				auto flags = (body.getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
-				body.setCollisionFlags(flags);
-				body.setActivationState(DISABLE_DEACTIVATION);
-			}
-		}
-	}
-
-	void add_bt_body(const entity::ComponentSpec& spec, entity::EntityManager& manager, const entity::EntityID& id) {
-		auto& body = manager.add<BulletBody>(id);
-		body.motion = new FgglMotionState(&manager, id);
-
-		auto type = spec.get<BodyType>("type", BodyType::DYNAMIC);
-		auto mass = 0.0F;
-
-		// non-static objects can have mass
-		if ( type != BodyType::STATIC ) {
-			mass = spec.get<float>("mass", 1.0F);
-		}
-
-		// calculate inertia
-		btCollisionShape* shape = create_bullet_shape(spec.config["shape"]);
-		btVector3 inertia(0, 0, 0);
-		if ( type != BodyType::STATIC ) {
-			shape->calculateLocalInertia(mass, inertia);
-		}
-
-		// construction information for the simulation
-		btRigidBody::btRigidBodyConstructionInfo constructionInfo {
-			mass,
-			body.motion,
-			shape,
-			inertia
-		};
-		body.body = new btRigidBody(constructionInfo);
-		setup_body(type, *body.body);
-
-		// add the body to the simulation
-	}
-
 	bool Bullet::factory(modules::ModuleService service, modules::Services& services) {
-		if ( service == BIND_BULLET ) {
-			auto* entityFactory = services.get<entity::EntityFactory>();
-			entityFactory->bind(CONFIG_PHYS_BODY, add_bt_body);
+		if ( service == phys::PhysicsProvider::service ) {
+			services.bind<phys::PhysicsProvider, BulletProvider>();
 		}
 		return false;
 	}
diff --git a/integrations/bullet/src/service.cpp b/integrations/bullet/src/service.cpp
new file mode 100644
index 0000000..a91c777
--- /dev/null
+++ b/integrations/bullet/src/service.cpp
@@ -0,0 +1,103 @@
+/*
+ * This file is part of FGGL.
+ *
+ * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with FGGL.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//
+// Created by webpigeon on 01/08/22.
+//
+
+#include "fggl/phys/bullet/service.hpp"
+#include "fggl/phys/bullet/types.hpp"
+#include "fggl/phys/bullet/motion.hpp"
+
+namespace fggl::phys::bullet {
+
+	constexpr float UNIT_EXTENT = 0.5F;
+
+	btCollisionShape* create_bullet_shape(const YAML::Node& node) {
+		auto type = node["type"].as<std::string>("MISSING");
+		if ( type == "sphere" ) {
+			auto radius = node["radius"].as<float>(UNIT_EXTENT);
+			return new btSphereShape(radius);
+		} else if ( type == "box" ) {
+			auto extents = node["extents"].as<math::vec3>(math::vec3(UNIT_EXTENT));
+			return new btBoxShape(btVector3(extents.x, extents.y, extents.z));
+		} else {
+			debug::warning("unknown shape type: {}, assuming unit sphere", type);
+			return new btSphereShape(0.5F);
+		}
+	}
+
+	void setup_body(BodyType type, btRigidBody& body) {
+		if ( type != BodyType::STATIC ) {
+			body.setRestitution(0.5F);
+			body.setRollingFriction(0.0F);
+
+			// kinematic bodies cannot sleep
+			if (type == BodyType::KINEMATIC) {
+				auto flags = (body.getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
+				body.setCollisionFlags(flags);
+				body.setActivationState(DISABLE_DEACTIVATION);
+			}
+		}
+	}
+
+	void add_bt_body(BulletPhysicsEngine* engine, const entity::ComponentSpec& spec, entity::EntityManager& manager, const entity::EntityID& id) {
+		auto& body = manager.add<BulletBody>(id);
+		body.motion = new FgglMotionState(&manager, id);
+
+		auto type = spec.get<BodyType>("type", BodyType::DYNAMIC);
+		auto mass = 0.0F;
+
+		// non-static objects can have mass
+		if ( type != BodyType::STATIC ) {
+			mass = spec.get<float>("mass", 1.0F);
+		}
+
+		// calculate inertia
+		btCollisionShape* shape = create_bullet_shape(spec.config["shape"]);
+		btVector3 inertia(0, 0, 0);
+		if ( type != BodyType::STATIC ) {
+			shape->calculateLocalInertia(mass, inertia);
+		}
+
+		// construction information for the simulation
+		btRigidBody::btRigidBodyConstructionInfo constructionInfo {
+			mass,
+			body.motion,
+			shape,
+			inertia
+		};
+		body.body = new btRigidBody(constructionInfo);
+		setup_body(type, *body.body);
+
+		// add the body to the simulation
+		engine->addBody(id, body);
+		if ( type == BodyType::DYNAMIC ) {
+			manager.add<phys::Dynamics>(id);
+		}
+	}
+
+	PhysicsEngine* BulletProvider::create(entity::EntityManager* entityManager, entity::EntityFactory* factory) {
+		auto* engine = new BulletPhysicsEngine(entityManager);
+
+		// FIXME: this won't work across multiple scenes - reactive approach might be better...
+		factory->bind(util::make_guid("phys::Body"), [engine](const entity::ComponentSpec& config, entity::EntityManager& manager, const entity::EntityID& id) {
+			add_bt_body(engine, config, manager, id);
+		});
+		engine->debugDraw = true;
+
+		return engine;
+	}
+
+} // namespace fggl::phys::bullet
\ No newline at end of file
diff --git a/integrations/bullet/src/simulation.cpp b/integrations/bullet/src/simulation.cpp
index 4ee06d6..df589cb 100644
--- a/integrations/bullet/src/simulation.cpp
+++ b/integrations/bullet/src/simulation.cpp
@@ -49,7 +49,7 @@ namespace fggl::phys::bullet {
 
 		m_debug = std::make_unique<debug::BulletDebugDrawList>();
 		m_world->setDebugDrawer( m_debug.get() );
-		m_debug->setDebugMode(1);
+		m_debug->setDebugMode(btIDebugDraw::DBG_DrawWireframe);
 
 		// callbacks (for handling bullet -> ecs)
 
@@ -58,7 +58,8 @@ namespace fggl::phys::bullet {
 	}
 
 	void BulletPhysicsEngine::step() {
-		checkForPhys();
+		// this is now handled on creation
+		//checkForPhys();
 
 		auto dynamicEnts = m_ecs->find<phys::Dynamics, phys::bullet::BulletBody>();
 		for (auto& ent : dynamicEnts) {
@@ -82,10 +83,14 @@ namespace fggl::phys::bullet {
 		}
 	}
 
+	void BulletPhysicsEngine::addBody(entity::EntityID /*entity*/, BulletBody &body) {
+		m_world->addRigidBody(body.body);
+	}
+
 	inline btCollisionShape* shape_to_bullet(const phys::RigidBody& fgglBody) {
 		if ( fgglBody.shape == nullptr ) {
 			// they forgot to put a shape, we'll assume a unit sphere to avoid crashes...
-			return new btSphereShape(0.5f);
+			return new btSphereShape(0.5F);
 		}
 
 		switch (fgglBody.shape->type) {
-- 
GitLab