diff --git a/CMakeLists.txt b/CMakeLists.txt index 7059121..1b438ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,10 @@ find_package(glfw3 3.3 REQUIRED) ## Find SWIG find_package(SWIG REQUIRED) +## Find Bullet +find_package(Bullet REQUIRED) +include_directories(${BULLET_INCLUDE_DIRS}) + ## Find Lua find_package(Lua REQUIRED) @@ -24,6 +28,7 @@ endif() target_link_libraries(couch OpenGL::GL) target_link_libraries(couch GLEW::GLEW) target_link_libraries(couch ${LUA_LIBRARIES}) +target_link_libraries(couch ${BULLET_LIBRARIES}) include(UseSWIG) set_property(SOURCE scripting/couch.i PROPERTY CPLUSPLUS ON) diff --git a/core/Rigidbody.cpp b/core/Rigidbody.cpp new file mode 100644 index 0000000..d33c011 --- /dev/null +++ b/core/Rigidbody.cpp @@ -0,0 +1,56 @@ +#include "Rigidbody.h" +#include "World.h" + +Rigidbody::Rigidbody() {} + +Rigidbody *Rigidbody::Create() { + return new Rigidbody; +} + +Rigidbody *Rigidbody::Duplicate() { + Rigidbody *rigidbody = static_cast(Spatial::Duplicate()); + + rigidbody->collisionShape = collisionShape; + rigidbody->btBody = btBody; + rigidbody->mass = mass; + return rigidbody; +} + +Rigidbody *Rigidbody::Instance() { + Rigidbody *rigidbody = static_cast(Node::Instance()); + + rigidbody->collisionShape = new btSphereShape(1.0f); + rigidbody->btBody = new btRigidBody(rigidbody->mass, new RigidbodyMotionState(rigidbody), rigidbody->collisionShape); + assert(rigidbody); + + World *world = World::GetWorld(); + world->AddRigidbody(rigidbody); + + return rigidbody; +} + +RigidbodyMotionState::RigidbodyMotionState(Rigidbody *rigidbody) { + this->rigidbody = rigidbody; +} + +void RigidbodyMotionState::getWorldTransform(btTransform &worldTrans) const { + worldTrans.setOrigin(btVector3( + rigidbody->transform.position.x, + rigidbody->transform.position.y, + rigidbody->transform.position.z)); + btQuaternion quat; + quat.setEuler(rigidbody->transform.rotation.z, + rigidbody->transform.rotation.y, + rigidbody->transform.rotation.x); + worldTrans.setRotation(quat); +} + +void RigidbodyMotionState::setWorldTransform(const btTransform &worldTrans) { + rigidbody->transform.position = Vector3(worldTrans.getOrigin().getX(), + worldTrans.getOrigin().getY(), + worldTrans.getOrigin().getZ()); + + worldTrans.getRotation().getEulerZYX(rigidbody->transform.rotation.z, + rigidbody->transform.rotation.y, + rigidbody->transform.rotation.x); +} diff --git a/core/Rigidbody.h b/core/Rigidbody.h new file mode 100644 index 0000000..34f6b17 --- /dev/null +++ b/core/Rigidbody.h @@ -0,0 +1,31 @@ +#ifndef RIGIDBODY_H +#define RIGIDBODY_H + +#include + +#include "types.h" +#include "Spatial.h" + +class Rigidbody : public Spatial { +public: + Rigidbody(); + virtual Rigidbody *Create(); + virtual Rigidbody *Duplicate(); + virtual Rigidbody *Instance(); + cfloat mass = 1.0f; +private: + btRigidBody *btBody; + btCollisionShape *collisionShape; + friend class World; +}; + +class RigidbodyMotionState : public btMotionState { +public: + RigidbodyMotionState(Rigidbody *rigidbody); + virtual void getWorldTransform(btTransform &worldTrans) const; + virtual void setWorldTransform(const btTransform &worldTrans); +private: + Rigidbody *rigidbody; +}; + +#endif /* RIGIDBODY_H */ diff --git a/core/World.cpp b/core/World.cpp new file mode 100644 index 0000000..4f4921d --- /dev/null +++ b/core/World.cpp @@ -0,0 +1,37 @@ +#include "World.h" + +World* World::GetWorld() { + if (!world) { + world = new World(); + } + + return world; +} + +void World::AddRigidbody(Rigidbody *rigidbody) { + btWorld->addRigidBody(rigidbody->btBody); +} + +void World::Step(cfloat delta) { + btWorld->stepSimulation(delta); +} + +World* World::world { new World() }; + +World::World() { + // Some Java-ass code to follow + collisionConfiguration = new btDefaultCollisionConfiguration(); + dispatcher = new btCollisionDispatcher(collisionConfiguration); + overlappingPairCache = new btDbvtBroadphase(); + solver = new btSequentialImpulseConstraintSolver(); + btWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration); + btWorld->setGravity(btVector3(0, -10, 0)); +} + +World::~World() { + delete btWorld; + delete solver; + delete overlappingPairCache; + delete dispatcher; + delete collisionConfiguration; +} diff --git a/core/World.h b/core/World.h new file mode 100644 index 0000000..b7a2640 --- /dev/null +++ b/core/World.h @@ -0,0 +1,24 @@ +#ifndef WORLD_H +#define WORLD_H + +#include + +#include "Rigidbody.h" + +class World { +public: + static World* GetWorld(); + void AddRigidbody(Rigidbody *rigidbody); + void Step(cfloat delta); +private: + static World* world; + btDiscreteDynamicsWorld *btWorld; + btDefaultCollisionConfiguration *collisionConfiguration; + btCollisionDispatcher *dispatcher; + btBroadphaseInterface *overlappingPairCache; + btSequentialImpulseConstraintSolver *solver; + World(); + ~World(); +}; + +#endif /* WORLD_H */ diff --git a/core/couch.cpp b/core/couch.cpp index 98ebc36..06b011b 100644 --- a/core/couch.cpp +++ b/core/couch.cpp @@ -23,6 +23,10 @@ #include "Light.h" #include "Skybox.h" +#include "Rigidbody.h" +#include "World.h" + + #include "Scripting/Lua.h" // Thirdparty Includes @@ -37,22 +41,22 @@ const int height = 600; Node *root; void render(Node *curr, Shader *shader, Matrix model) { + if (curr->IsTransformable()) { + Spatial *spatial = dynamic_cast(curr); + model = glm::rotate(model, spatial->transform.rotation.x, Vector3(1.0f, 0.0f, 0.0f)); + model = glm::rotate(model, spatial->transform.rotation.y, Vector3(0.0f, 1.0f, 0.0f)); + model = glm::rotate(model, spatial->transform.rotation.z, Vector3(0.0f, 0.0f, 1.0f)); + model = glm::translate(model, spatial->transform.position); + model = glm::scale(model, spatial->transform.scale); + shader->UpdateModel(model); + shader->UpdateNormal(glm::mat3(glm::transpose(glm::inverse(model)))); + } if (curr->IsDrawable()) { - if (curr->IsTransformable()) { - Spatial *spatial = dynamic_cast(curr); - model = glm::rotate(model, spatial->transform.rotation.x, Vector3(1.0f, 0.0f, 0.0f)); - model = glm::rotate(model, spatial->transform.rotation.y, Vector3(0.0f, 1.0f, 0.0f)); - model = glm::rotate(model, spatial->transform.rotation.z, Vector3(0.0f, 0.0f, 1.0f)); - model = glm::translate(model, spatial->transform.position); - model = glm::scale(model, spatial->transform.scale); - shader->UpdateModel(model); - shader->UpdateNormal(glm::mat3(glm::transpose(glm::inverse(model)))); - } Mesh *mesh = dynamic_cast(curr); mesh->Draw(shader); } for (Node *child : curr->children) { - render(child, shader, model); + render(child, shader, model); } } @@ -89,6 +93,8 @@ int main() { Camera defaultCamera; + World *world = World::GetWorld(); + Screen screen; ScreenShader *screenShader = new ScreenShader(); @@ -106,6 +112,10 @@ int main() { double delta = 0.0; while(!glfwWindowShouldClose(window)) { + + // Physics update() + world->Step(delta); + // Start rendering to texture; screen.Enable(); diff --git a/demo/main.lua b/demo/main.lua index 2d487b7..1e30618 100644 --- a/demo/main.lua +++ b/demo/main.lua @@ -46,6 +46,17 @@ function init() ) couch.Node.GetRoot().children:Append(skybox:Instance()) + local physics_ball_prefab = couch.Rigidbody() + local physics_ball_mesh = couch.Mesh.FromFile("ball.obj") + material = physics_ball_mesh:GetMaterial(0) + material.ambient = BLUE + material.diffuse = BLUE + physics_ball_mesh:SetMaterial(0, material) + physics_ball_prefab.children:Append(physics_ball_mesh); + physics_ball_prefab.transform.position = couch.Vector3(0.0, 30.0, -10.0) + local physics_ball = physics_ball_prefab:Instance() + couch.Node.GetRoot().children:Append(physics_ball) + make_ground() local cube_prefab = couch.Mesh.FromFile("cube.obj") diff --git a/scripting/couch.i b/scripting/couch.i index 79a43c0..4cc6d93 100644 --- a/scripting/couch.i +++ b/scripting/couch.i @@ -16,6 +16,7 @@ #include "Camera.h" #include "Light.h" #include "Skybox.h" +#include "Rigidbody.h" %} typedef float cfloat; @@ -48,3 +49,4 @@ public: %include "Camera.h" %include "Light.h" %include "Skybox.h" +%include "Rigidbody.h"