Merge pull request #9 from SeanOMik/feature/physics

Create simple physics system
This commit is contained in:
SeanOMik 2022-11-20 13:27:44 -05:00 committed by GitHub
commit 181cb15599
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 891 additions and 91 deletions

View File

@ -24,6 +24,7 @@ find_package(OpenGL REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
find_package(assimp CONFIG REQUIRED)
find_package(Bullet REQUIRED)
# Link sources
file(GLOB_RECURSE source_list src/*.cpp)
@ -49,6 +50,7 @@ target_link_libraries(simpleengine PUBLIC GLEW::GLEW)
target_link_libraries(simpleengine PUBLIC glfw)
target_link_libraries(simpleengine PUBLIC ${GLM_LIBRARIES})
target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES})
target_link_libraries(simpleengine PUBLIC ${BULLET_LIBRARIES})
if(WIN32)
target_link_libraries(simpleengine PUBLIC assimp::assimp)
target_link_libraries(simpleengine PUBLIC fmt::fmt)
@ -68,6 +70,7 @@ target_include_directories(simpleengine PUBLIC ${OPENGL_INCLUDE_DIR})
target_include_directories(simpleengine PUBLIC ${GLM_INCLUDE_DIRS})
target_include_directories(simpleengine PUBLIC ${STB_INCLUDE_DIR})
target_include_directories(simpleengine PUBLIC ${ENTT_INCLUDE_DIR})
target_include_directories(simpleengine PUBLIC ${BULLET_INCLUDE_DIRS})
# Add examples as a target if the user has them enabled
if (SIMPLE_ENGINE_BUILD_EXAMPLES)

View File

@ -1,7 +1,10 @@
#include "simpleengine/camera.h"
#include "simpleengine/ecs/component/box_collider_component.h"
#include "simpleengine/ecs/component/mesh_component.h"
#include "simpleengine/ecs/component/rigid_body_component.h"
#include "simpleengine/ecs/component/transform_component.h"
#include "simpleengine/ecs/entity.h"
#include "simpleengine/ecs/registry.h"
#include "simpleengine/gfx/light.h"
#include "simpleengine/gfx/material.h"
#include "simpleengine/gfx/mesh.h"
@ -9,7 +12,7 @@
#include "simpleengine/gfx/renderer.h"
#include "simpleengine/gfx/texture.h"
#include "simpleengine/vector.h"
#include <GLFW/glfw3.h>
#include <semaphore.h>
#include <simpleengine/ecs/component/model_component.h>
#include <simpleengine/ecs/component/rotating_component.h>
#include <simpleengine/event/event.h>
@ -18,15 +21,20 @@
#include <simpleengine/gfx/shader.h>
#include <simpleengine/gfx/shaders/core_3d_shader.h>
#include <simpleengine/renderable.h>
#include <simpleengine/scene.h>
#include <simpleengine/shader_program.h>
#include <simpleengine/ecs/system/scene_system.h>
#include <simpleengine/vertex.h>
#include <simpleengine/log/logger.h>
#include <simpleengine/physics/physics_system.h>
#include "entt/entity/fwd.hpp"
#include <assimp/material.h>
#include <glm/ext/matrix_clip_space.hpp>
#include <glm/fwd.hpp>
#include <GLFW/glfw3.h>
#include <chrono>
#include <iostream>
#include <memory>
@ -34,6 +42,8 @@
#include <sstream>
#include <stdint.h>
#include <BulletCollision/CollisionShapes/btStaticPlaneShape.h>
namespace se = simpleengine;
class FPSCounterEvent : public se::Renderable {
@ -91,7 +101,7 @@ public:
if (current_time - last_frame_time_render >= 1.0) {
double ms_per_frame = 1000 / (double)frame_count_render;
SE_DEBUG("performance", "Render: {}fps, {}ms/frame", frame_count_render, ms_per_frame);
SE_DEBUG("performance", "Render: {}fps, {:.2f}ms/frame", frame_count_render, ms_per_frame);
SE_DEBUG("performance", "-------------------------------");
frame_count_render = 0;
last_frame_time_render += 1.0;
@ -107,17 +117,24 @@ int main(int argc, char *argv[]) {
// Load core shaders from SimpleEngine resources
se::gfx::shaders::Core3dShader core_shader;
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0));
// Create an entity registry
auto registry = std::make_shared<se::ecs::Registry>();
auto camera = std::make_shared<se::Camera>(game.get_window(), core_shader, 70, glm::vec3(-6, 0, 0));
//game.add_event(camera);
// Create a renderer
auto renderer = std::make_shared<se::gfx::Renderer>(game.get_window(), core_shader, camera);
renderer->initialize();
// Create a Scene and give it the renderer
auto scene = std::make_shared<se::Scene>(renderer, camera);
//game.add_event(scene);
auto scene = std::make_shared<se::ecs::system::SceneSystem>(registry, renderer, camera);
game.add_renderable(scene);
// Create a Physics System for handling the physics
auto physics_sys = std::make_shared<se::physics::PhysicsSystem>(registry);
game.add_event(physics_sys);
/* se::ecs::Entity other_e = scene->create_entity();
other_e.add_component<se::ModelComponent>("examples/dev_testing/resources/transparent_window.fbx",
se::gfx::ModelProcessingFlags::MdlProcFlag_TRANSPARENT);
@ -134,11 +151,16 @@ int main(int argc, char *argv[]) {
transform_comp.translate(4.f, 0.f, 0.f); */
se::ecs::Entity brick_e = scene->create_entity();
brick_e.add_component<se::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx");
brick_e.add_component<se::RotatingComponent>();
auto &brick_transf = brick_e.add_component<se::TransformComponent>();
brick_transf.translate(6.f, 0.f, 0.f);
//brick_transf.translate(6.f, -0.5f, 1.f);
brick_e.add_component<se::ecs::ModelComponent>("examples/dev_testing/resources/bricks/bricks.fbx");
brick_e.add_component<se::ecs::TransformComponent>(glm::vec3(6.f, 6.f, 0.f));
brick_e.add_component<se::ecs::BoxColliderComponent>(1.f, 1.f, 1.f);
brick_e.add_component<se::ecs::RigidBodyComponent>(1.f, se::Vectorf(6.f, 6.f, 0.1f));
se::ecs::Entity floor = scene->create_entity();
floor.add_component<se::ecs::ModelComponent>("examples/dev_testing/resources/ground/ground.fbx");
floor.add_component<se::ecs::TransformComponent>(glm::vec3(6.f, -6.f, 0.f), glm::vec3(0.f), glm::vec3(1.f, 1.f, 1.f));
floor.add_component<se::ecs::BoxColliderComponent>(1.f, 1.f, 1.f);
floor.add_component<se::ecs::RigidBodyComponent>(0.f, se::Vectorf(6.f, -6.f, 0.f));
auto light = std::make_shared<se::gfx::Light>(core_shader, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f));
game.add_event(light);

View File

@ -0,0 +1,44 @@
#pragma once
#include "../../physics/collision/box_shape.h"
namespace simpleengine::ecs {
/**
* @brief A component that contains a Box collision shape.
*
*/
class BoxColliderComponent {
public:
physics::collision::BoxShape box_shape;
BoxColliderComponent(physics::collision::BoxShape box) : box_shape(box) {
}
/**
* @brief Create a BoxShape with the extent of the box.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param x_extent The extent of the box in the x direction.
* @param y_extent The extent of the box in the y direction.
* @param z_extent The extent of the box in the z direction.
*
*/
BoxColliderComponent(const float& x_extent, const float& y_extent, const float& z_extent) : box_shape(x_extent, y_extent, z_extent) {
}
/**
* @brief Create a BoxShape with the extent of the box.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param extent The extent of the box.
*
*/
BoxColliderComponent(const simpleengine::Vectorf& extent) : box_shape(extent) {
}
};
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "../../physics/collision/capsule_shape.h"
#include "../../vector.h"
namespace simpleengine::ecs {
/**
* @brief A component that contains a capsule collision shape.
*
*/
class CapsuleColliderComponent {
public:
physics::collision::CapsuleShape capsule_shape;
CapsuleColliderComponent(physics::collision::CapsuleShape capsule) : capsule_shape(capsule) {
}
CapsuleColliderComponent(const float& radius, const float& height) : capsule_shape(radius, height) {
}
};
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "../../physics/collision/collision_shape.h"
namespace simpleengine::ecs {
/**
* @brief A component that contains a collision shape.
*
*/
class CollisionShapeComponent {
public:
physics::collision::CollisionShape* collision_shape;
CollisionShapeComponent(physics::collision::CollisionShape* shape) : collision_shape(shape) {
}
};
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "../../physics/collision/cone_shape.h"
#include "../../vector.h"
namespace simpleengine::ecs {
/**
* @brief A component that contains a cone collision shape.
*
*/
class ConeColliderComponent {
public:
physics::collision::ConeShape cone_shape;
ConeColliderComponent(physics::collision::ConeShape cone) : cone_shape(cone) {
}
ConeColliderComponent(float radius, float height) : cone_shape(radius, height) {
}
};
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "../../physics/collision/cylinder_shape.h"
#include "../../vector.h"
namespace simpleengine::ecs {
/**
* @brief A component that contains a cylinder collision shape.
*
*/
class CylinderColliderComponent {
public:
physics::collision::CylinderShape cylinder_shape;
CylinderColliderComponent(physics::collision::CylinderShape cylinder) : cylinder_shape(cylinder) {
}
/**
* @brief Create a cylinder collider with the extent of the cylinder shape.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param x_extent The extent of the cylinder shape in the x direction.
* @param y_extent The extent of the cylinder shape in the y direction.
* @param z_extent The extent of the cylinder shape in the z direction.
*
*/
CylinderColliderComponent(const float& x_extent, const float& y_extent, const float& z_extent) : cylinder_shape(x_extent, y_extent, z_extent) {
}
/**
* @brief Create a CylinderShape with the extent of the cylinder shape.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param extent The extent of the cylinder.
*
*/
CylinderColliderComponent(const simpleengine::Vectorf& extent) : cylinder_shape(extent) {
}
};
}

View File

@ -6,7 +6,7 @@
#include <iostream>
#include <vector>
namespace simpleengine {
namespace simpleengine::ecs {
/**
* @brief A component that contains a Mesh that will be rendered.
*

View File

@ -5,7 +5,7 @@
#include <iostream>
#include <vector>
namespace simpleengine {
namespace simpleengine::ecs {
/**
* @brief A component that contains a Model that will be rendered.
*

View File

@ -0,0 +1,41 @@
#pragma once
#include "../../gfx/model.h"
#include "simpleengine/vector.h"
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <BulletDynamics/Dynamics/btRigidBody.h>
#include <LinearMath/btDefaultMotionState.h>
#include <LinearMath/btScalar.h>
#include <LinearMath/btTransform.h>
#include <LinearMath/btVector3.h>
#include <btBulletDynamicsCommon.h>
namespace simpleengine::physics {
class PhysicsSystem;
}
namespace simpleengine::ecs {
/**
* @brief A component that contains a Model that will be rendered.
*
*/
class RigidBodyComponent {
friend simpleengine::physics::PhysicsSystem;
private:
float mass;
bool is_dynamic;
// TODO: Free
btDefaultMotionState* motion_state;
btCollisionShape* col_shape;
public:
//bool initialized = false;
btRigidBody* rigid_body;
RigidBodyComponent(float mass, simpleengine::Vectorf start_origin) : mass(mass), is_dynamic(mass != 0.f), rigid_body(nullptr) {
}
};
}

View File

@ -2,7 +2,7 @@
#include <glm/glm.hpp>
namespace simpleengine {
namespace simpleengine::ecs {
/**
* @brief A component that will rotate the transform every frame.
*

View File

@ -0,0 +1,22 @@
#pragma once
#include "../../physics/collision/sphere_shape.h"
namespace simpleengine::ecs {
/**
* @brief A component that contains a Sphere collision shape.
*
*/
class SphereColliderComponent {
public:
physics::collision::SphereShape sphere_shape;
SphereColliderComponent(physics::collision::SphereShape sphere) : sphere_shape(sphere) {
}
SphereColliderComponent(const float& radius) : sphere_shape(radius) {
}
};
}

View File

@ -1,26 +1,42 @@
#pragma once
//#include "simpleengine/scene.h"
#include <glm/gtx/euler_angles.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/fwd.hpp>
#include <glm/glm.hpp>
namespace simpleengine {
namespace simpleengine::ecs {
namespace system {
class SceneSystem;
}
/**
* @brief A component that contains a Mesh that will be rendered.
*
*/
class TransformComponent {
friend class Scene;
private:
friend simpleengine::ecs::system::SceneSystem;
public:
// This is the transform from the last render loop. The renderer uses this for frame interprelation
glm::mat4 last_transform_matrix;
public:
glm::mat4 transform_matrix;
TransformComponent() : transform_matrix(1.f), last_transform_matrix(1.f) {
}
TransformComponent(glm::vec3 initial_position, glm::vec3 initial_rotation = glm::vec3(0.f), glm::vec3 initial_scale = glm::vec3(1.f))
: transform_matrix(1.f), last_transform_matrix(1.f) {
translate(initial_position);
rotate_x(initial_rotation.x);
rotate_y(initial_rotation.y);
rotate_z(initial_rotation.z);
scale(initial_scale);
}
TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix), last_transform_matrix(1.f) {
}
@ -45,6 +61,38 @@ namespace simpleengine {
return lhs;
}
virtual void decompose_matrix(glm::vec3& pos, glm::quat& rot, glm::vec3& scale) const {
pos = transform_matrix[3];
for(int i = 0; i < 3; i++) {
scale[i] = glm::length(glm::vec3(transform_matrix[i]));
}
const glm::mat3 rotMtx(glm::vec3(transform_matrix[0]) / scale[0],
glm::vec3(transform_matrix[1]) / scale[1], glm::vec3(transform_matrix[2]) / scale[2]);
rot = glm::quat_cast(rotMtx);
}
virtual glm::vec3 get_pos() const {
return transform_matrix[3];
}
virtual glm::vec3 get_scale() const {
glm::vec3 scale;
for(int i = 0; i < 3; i++) {
scale[i] = glm::length(glm::vec3(transform_matrix[i]));
}
return scale;
}
virtual glm::quat get_rotation_quat() const {
glm::vec3 scale = get_scale();
const glm::mat3 rot_mtx(glm::vec3(transform_matrix[0]) / scale[0],
glm::vec3(transform_matrix[1]) / scale[1], glm::vec3(transform_matrix[2]) / scale[2]);
return glm::quat_cast(rot_mtx);
}
virtual void combine_transform(const glm::mat4& transform_matrix) {
this->transform_matrix *= transform_matrix;
}
@ -57,9 +105,9 @@ namespace simpleengine {
transform_matrix = glm::translate(transform_matrix, glm::vec3(x, y, z));
}
/* virtual void translate(const glm::vec3& vec) {
virtual void translate(const glm::vec3& vec) {
transform_matrix = glm::translate(transform_matrix, vec);
} */
}
virtual glm::mat4 rotation_matrix(float degrees, glm::vec3 rotation_axis) const {
return glm::rotate(transform_matrix, glm::radians(degrees), rotation_axis);

View File

@ -0,0 +1,22 @@
#pragma once
#include "entt/signal/fwd.hpp"
#include <entt/entt.hpp>
namespace simpleengine::ecs {
class Entity;
class Registry {
entt::registry inner;
//entt::dispatcher dispatcher;
public:
Registry();
entt::registry& get_inner();
Entity create_entity();
};
/* struct NewEntityEvent {
Entity& entity;
}; */
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "system.h"
namespace simpleengine {
// fwd decl
class Camera;
namespace gfx {
class Renderer;
}
namespace ecs {
class Entity;
class Registry;
namespace system {
class SceneSystem : public System {
protected:
std::shared_ptr<gfx::Renderer> renderer;
std::shared_ptr<Camera> camera;
public:
SceneSystem(std::shared_ptr<Registry> entity_registry, std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> camera);
ecs::Entity create_entity();
virtual void update(const float& delta_time) override;
virtual void input_update(const float& delta_time) override;
virtual void render(const float& interpolate_alpha, const float& frame_time) override;
virtual void destroy() override;
};
}
}
}

View File

@ -0,0 +1,24 @@
#pragma once
#include "../../renderable.h"
namespace simpleengine::ecs {
class Entity;
class Registry;
namespace system {
class System : public simpleengine::Renderable {
protected:
std::shared_ptr<Registry> entity_registry;
public:
System(std::shared_ptr<Registry> entity_registry);
ecs::Entity create_entity();
virtual void update(const float& delta_time) = 0;
virtual void input_update(const float& delta_time) = 0;
virtual void render(const float& interpolate_alpha, const float& frame_time) = 0;
virtual void destroy() = 0;
};
}
}

View File

@ -7,9 +7,6 @@
namespace simpleengine {
class Event : public simpleengine::Destructable {
public:
Event() = default;
virtual ~Event() = default;
/**
* @brief The update function with fixed-timestep.
*

View File

@ -0,0 +1,58 @@
#pragma once
#include "../../vector.h"
#include <BulletCollision/CollisionShapes/btBoxShape.h>
namespace simpleengine::physics::collision {
class BoxShape {
btBoxShape inner;
public:
BoxShape(btBoxShape inner) : inner(inner) {
}
/**
* @brief Create a BoxShape with the extent of the box.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param x_extent The extent of the box in the x direction.
* @param y_extent The extent of the box in the y direction.
* @param z_extent The extent of the box in the z direction.
*
*/
BoxShape(const float& x_extent, const float& y_extent, const float& z_extent) : inner(btVector3(btScalar(x_extent), btScalar(y_extent), btScalar(z_extent))) {
}
/**
* @brief Create a BoxShape with the extent of the box.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param extent The extent of the box.
*
*/
BoxShape(const simpleengine::Vectorf& extent) : BoxShape(extent.x(), extent.y(), extent.z()) {
}
/**
* @brief Get the inner bullet box shape object as a pointer.
*
* @return btBoxShape*
*/
btBoxShape* get_inner_ptr() {
return &inner;
}
/**
* @brief Get the inner bullet box shape object as a reference.
*
* @return btBoxShape&
*/
btBoxShape& get_inner() {
return inner;
}
};
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
namespace simpleengine::physics::collision {
class CapsuleShape {
btCapsuleShape inner;
public:
CapsuleShape(btCapsuleShape inner) : inner(inner) {
}
CapsuleShape(const float& radius, const float& height) : inner(radius, height) {
}
/**
* @brief Get the inner bullet capsule shape object as a pointer.
*
* @return btCapsuleShape*
*/
btCapsuleShape* get_inner_ptr() {
return &inner;
}
/**
* @brief Get the inner bullet capsule shape object as a reference.
*
* @return btCapsuleShape&
*/
btCapsuleShape& get_inner() {
return inner;
}
};
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
namespace simpleengine::physics::collision {
class CollisionShape {
btCollisionShape* inner;
public:
CollisionShape() = default;
CollisionShape(btCollisionShape* inner) : inner(inner) {
}
btCollisionShape* get_inner() {
return inner;
}
};
}

View File

@ -0,0 +1,37 @@
#pragma once
#include <utility>
#include <BulletCollision/CollisionShapes/btConeShape.h>
namespace simpleengine::physics::collision {
class ConeShape {
btConeShape inner;
public:
ConeShape(btConeShape inner) : inner(std::move(inner)) {
}
ConeShape(float radius, float height) : inner(radius, height) {
}
/**
* @brief Get the inner bullet cone shape object as a pointer.
*
* @return btConeShape*
*/
btConeShape* get_inner_ptr() {
return &inner;
}
/**
* @brief Get the inner bullet cone shape object as a reference.
*
* @return btConeShape&
*/
btConeShape& get_inner() {
return inner;
}
};
}

View File

@ -0,0 +1,58 @@
#pragma once
#include <BulletCollision/CollisionShapes/btCylinderShape.h>
#include "vector.h"
namespace simpleengine::physics::collision {
class CylinderShape {
btCylinderShape inner;
public:
CylinderShape(btCylinderShape inner) : inner(inner) {
}
/**
* @brief Create a CylinderShape with the extent of the cylinder shape.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param x_extent The extent of the cylinder shape in the x direction.
* @param y_extent The extent of the cylinder shape in the y direction.
* @param z_extent The extent of the cylinder shape in the z direction.
*
*/
CylinderShape(const float& x_extent, const float& y_extent, const float& z_extent) : inner(btVector3(btScalar(x_extent), btScalar(y_extent), btScalar(z_extent))) {
}
/**
* @brief Create a CylinderShape with the extent of the cylinder shape.
*
* @note These extents are in half-extents since that's what the underlying Physics engine uses (Bullet).
*
* @param extent The extent of the cylinder.
*
*/
CylinderShape(const simpleengine::Vectorf& extent) : CylinderShape(extent.x(), extent.y(), extent.z()) {
}
/**
* @brief Get the inner bullet cylinder shape object as a pointer.
*
* @return btCylinderShape*
*/
btCylinderShape* get_inner_ptr() {
return &inner;
}
/**
* @brief Get the inner bullet cylinder shape object as a reference.
*
* @return btCylinderShape&
*/
btCylinderShape& get_inner() {
return inner;
}
};
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <BulletCollision/CollisionShapes/btSphereShape.h>
namespace simpleengine::physics::collision {
class SphereShape {
btSphereShape inner;
public:
SphereShape(btSphereShape inner) : inner(inner) {
}
SphereShape(const float& radius) : inner(btScalar(radius)) {
}
/**
* @brief Get the inner bullet sphere shape object as a pointer.
*
* @return btSphereShape*
*/
btSphereShape* get_inner_ptr() {
return &inner;
}
/**
* @brief Get the inner bullet sphere shape object as a reference.
*
* @return btSphereShape&
*/
btSphereShape& get_inner() {
return inner;
}
};
}

View File

@ -0,0 +1,69 @@
#pragma once
#include "../vector.h"
#include "../ecs/entity.h"
#include "../log/logger.h"
#include "../ecs/system/system.h"
#include <memory>
#include <entt/entity/fwd.hpp>
#include <entt/entt.hpp>
class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
class btBroadphaseInterface;
class btSequentialImpulseConstraintSolver;
class btDiscreteDynamicsWorld;
class btRigidBody;
class btCollisionShape;
namespace simpleengine {
namespace ecs {
class Registry;
class TransformComponent;
class RigidBodyComponent;
}
namespace physics {
class PhysicsSystem : public simpleengine::ecs::system::System {
protected:
std::unique_ptr<btDefaultCollisionConfiguration> collision_configuration;
std::unique_ptr<btCollisionDispatcher> col_dispatcher;
std::unique_ptr<btBroadphaseInterface> overlapping_pair_cache;
std::unique_ptr<btSequentialImpulseConstraintSolver> solver;
std::unique_ptr<btDiscreteDynamicsWorld> dynamics_world;
simpleengine::log::Logger logger;
public:
simpleengine::Vectorf gravity_vector;
bool should_simulate;
PhysicsSystem(std::shared_ptr<ecs::Registry> entity_registry);
~PhysicsSystem();
void set_y_gravity(const float& gravity);
/**
* @brief Add a *manually* constructed rigid body to the Physics System.
*
* @note Do not add a rigid body from a rigid body component. This will be added automatically by the Physics System.
*
* @param rigid_body The rigid body that *manually* created.
*/
void add_rigid_body(btRigidBody* rigid_body);
virtual void update(const float& delta_time) override;
// Empty implementations
virtual void input_update(const float& delta_time) override {}
virtual void render(const float& interpolate_alpha, const float& frame_time) override {}
virtual void destroy() override {}
protected:
// Try get a collision shape from an entities components.
btCollisionShape* try_get_collision_shape(const entt::entity& entity);
/// Initialize a rigid body component.
inline bool init_rigid_body_component(const entt::entity& entity, simpleengine::ecs::TransformComponent& transform_comp, simpleengine::ecs::RigidBodyComponent& rigid_body_comp);
};
}
}

View File

@ -1,44 +0,0 @@
#pragma once
#include "camera.h"
#include "entt/entity/fwd.hpp"
#include "gfx/mesh.h"
#include "event/event.h"
#include "renderable.h"
#include "simpleengine/gfx/renderer.h"
#include <memory>
#include <GLFW/glfw3.h>
#include <unordered_map>
#include <vector>
#include <entt/entt.hpp>
namespace simpleengine {
namespace ecs {
class Entity;
}
//class Scene : public simpleengine::Event {
class Scene : public simpleengine::Renderable {
protected:
entt::registry registry;
std::shared_ptr<gfx::Renderer> renderer;
// Last transform matrixes for all entities.
std::unordered_map<uint32_t, glm::mat4> last_transforms;
std::shared_ptr<Camera> camera;
public:
Scene(std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> camera);
ecs::Entity create_entity();
virtual void update(const float& delta_time) override;
virtual void input_update(const float& delta_time) override;
virtual void render(const float& interpolate_alpha, const float& frame_time) override;
virtual void destroy() override;
};
}

View File

@ -29,15 +29,15 @@ namespace simpleengine {
return inner_vec;
}
VectorType& x() {
const VectorType& x() const {
return inner_vec.x;
}
VectorType& y() {
const VectorType& y() const {
return inner_vec.y;
}
VectorType& z() {
const VectorType& z() const {
return inner_vec.z;
}

View File

@ -13,5 +13,6 @@ pkgs.mkShell {
glm
assimp
spdlog
bullet
];
}

16
src/ecs/registry.cpp Normal file
View File

@ -0,0 +1,16 @@
#include "ecs/registry.h"
#include "ecs/entity.h"
namespace simpleengine::ecs {
Registry::Registry() {
}
entt::registry& Registry::get_inner() {
return inner;
}
Entity Registry::create_entity() {
return ecs::Entity(inner, inner.create());
}
}

View File

@ -1,44 +1,51 @@
#include "scene.h"
#include "ecs/component/mesh_component.h"
#include "ecs/component/model_component.h"
#include "gfx/renderer.h"
#include "ecs/system/scene_system.h"
#include "ecs/component/transform_component.h"
#include "ecs/component/rotating_component.h"
#include "ecs/entity.h"
#include "gfx/renderer.h"
#include "log/logger.h"
#include "ecs/registry.h"
#include "ecs/component/model_component.h"
#include "ecs/component/mesh_component.h"
#include <glm/gtx/string_cast.hpp>
#include <spdlog/common.h>
#include <stdexcept>
namespace simpleengine {
Scene::Scene(std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> camera) : renderer(renderer), camera(camera) {
#include <entt/entity/fwd.hpp>
#include <entt/entt.hpp>
using namespace simpleengine::ecs;
namespace simpleengine::ecs::system {
SceneSystem::SceneSystem(std::shared_ptr<Registry> entity_registry, std::shared_ptr<gfx::Renderer> renderer, std::shared_ptr<Camera> camera)
: System(entity_registry), renderer(renderer), camera(camera) {
}
ecs::Entity Scene::create_entity() {
return ecs::Entity(registry, registry.create());
ecs::Entity SceneSystem::create_entity() {
return entity_registry->create_entity();
}
void Scene::input_update(const float& delta_time) {
void SceneSystem::input_update(const float& delta_time) {
camera->input_update(delta_time); // Update camera input
}
void Scene::update(const float& delta_time) {
void SceneSystem::update(const float& delta_time) {
// Update the last transform matrix
registry.view<TransformComponent>().each([this, &delta_time](TransformComponent& transform) {
entity_registry->get_inner().view<TransformComponent>().each([this, &delta_time](TransformComponent& transform) {
transform.last_transform_matrix = transform.transform_matrix;
});
// Rotate the model
registry.view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
/* registry->view<TransformComponent, RotatingComponent>().each([this, &delta_time](TransformComponent& transform, RotatingComponent& rotating) {
transform.rotate(rotating.rate * delta_time, rotating.rotation_axis);
});
}); */
}
void Scene::render(const float& interpolate_alpha, const float& frame_time) {
void SceneSystem::render(const float& interpolate_alpha, const float& frame_time) {
// Is there a way these can be grouped?
registry.view<TransformComponent, ModelComponent>().each([this](TransformComponent& transform, ModelComponent& model_component) {
entity_registry->get_inner().view<TransformComponent, ModelComponent>().each([this](TransformComponent& transform, ModelComponent& model_component) {
for (auto& mesh : model_component.model.meshes) {
auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh.material) {
@ -49,7 +56,7 @@ namespace simpleengine {
}
});
registry.view<TransformComponent, MeshComponent>().each([this](TransformComponent& transform, MeshComponent& mesh_component) {
entity_registry->get_inner().view<TransformComponent, MeshComponent>().each([this](TransformComponent& transform, MeshComponent& mesh_component) {
auto rendering_type = gfx::RenderingType::RendType_OPAQUE;
if (mesh_component.mesh.material) {
rendering_type = mesh_component.mesh.material->rendering_type;
@ -61,15 +68,15 @@ namespace simpleengine {
renderer->render(interpolate_alpha, frame_time);
}
void Scene::destroy() {
void SceneSystem::destroy() {
SE_DEBUG("scene", "Destroying Scene...");
registry.view<ModelComponent>().each([this](ModelComponent& model_component) {
entity_registry->get_inner().view<ModelComponent>().each([this](ModelComponent& model_component) {
for (auto& mesh : model_component.model.meshes) {
mesh.destroy();
}
});
registry.view<MeshComponent>().each([this](MeshComponent& mesh_component) {
entity_registry->get_inner().view<MeshComponent>().each([this](MeshComponent& mesh_component) {
mesh_component.mesh.destroy();
});
}

13
src/ecs/system/system.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "ecs/system/system.h"
#include "ecs/entity.h"
#include "ecs/registry.h"
namespace simpleengine::ecs::system {
System::System(std::shared_ptr<Registry> entity_registry) : entity_registry(entity_registry) {
}
ecs::Entity System::create_entity() {
return entity_registry->create_entity();
}
}

View File

@ -2,6 +2,7 @@
#include "gfx/mesh.h"
#include "gfx/vao.h"
#include "renderable.h"
#include "gfx/shader.h"
#include "ecs/component/mesh_component.h"
#include "ecs/component/model_component.h"

View File

@ -0,0 +1,130 @@
#include "ecs/component/box_collider_component.h"
#include "ecs/component/sphere_collider_component.h"
#include "ecs/component/cylinder_collider_component.h"
#include "ecs/component/cone_collider_component.h"
#include "ecs/component/capsule_collider_component.h"
#include "ecs/component/rigid_body_component.h"
#include "ecs/system/system.h"
#include "entt/entity/fwd.hpp"
#include "physics/physics_system.h"
#include "ecs/component/transform_component.h"
#include "ecs/entity.h"
#include "ecs/registry.h"
#include "game.h"
#include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionDispatch/btCollisionDispatcher.h>
#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
#include <BulletCollision/BroadphaseCollision/btBroadphaseInterface.h>
#include <BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h>
#include <BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h>
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
#include <BulletDynamics/Dynamics/btRigidBody.h>
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
#include <memory>
namespace simpleengine::physics {
PhysicsSystem::PhysicsSystem(std::shared_ptr<ecs::Registry> entity_registry) : simpleengine::ecs::system::System(entity_registry),
logger(log::LoggerManager::create_logger("physics")), should_simulate(true), gravity_vector(0, -8, 0) {
collision_configuration = std::make_unique<btDefaultCollisionConfiguration>();
col_dispatcher = std::make_unique<btCollisionDispatcher>(collision_configuration.get());
overlapping_pair_cache = std::make_unique<btDbvtBroadphase>();
solver = std::make_unique<btSequentialImpulseConstraintSolver>();
dynamics_world = std::make_unique<btDiscreteDynamicsWorld>(col_dispatcher.get(), overlapping_pair_cache.get(), solver.get(), collision_configuration.get());
dynamics_world->setGravity(btVector3(gravity_vector.x(), gravity_vector.y(), gravity_vector.z()));
}
PhysicsSystem::~PhysicsSystem() {
}
void PhysicsSystem::set_y_gravity(const float& gravity) {
this->gravity_vector.set_y(gravity);
}
void PhysicsSystem::add_rigid_body(btRigidBody* rigid_body) {
dynamics_world->addRigidBody(rigid_body);
}
void PhysicsSystem::update(const float& delta_time) {
if (should_simulate) {
dynamics_world->stepSimulation(delta_time, 10);
entity_registry->get_inner().view<simpleengine::ecs::TransformComponent, simpleengine::ecs::RigidBodyComponent>()
.each([this](const entt::entity& entity, simpleengine::ecs::TransformComponent& transform_comp, simpleengine::ecs::RigidBodyComponent& rigid_body_comp) {
// Initialize the rigid body component if it hasn't already been initialized.
init_rigid_body_component(entity, transform_comp, rigid_body_comp);
btRigidBody* rigid_body = rigid_body_comp.rigid_body;
btTransform trans;
if (rigid_body_comp.rigid_body->getMotionState()) {
rigid_body->getMotionState()->getWorldTransform(trans);
trans.getOpenGLMatrix(glm::value_ptr(transform_comp.transform_matrix));
}
});
}
}
btCollisionShape* PhysicsSystem::try_get_collision_shape(const entt::entity& entity) {
if (auto box_col = entity_registry->get_inner().try_get<simpleengine::ecs::BoxColliderComponent>(entity)) {
return box_col->box_shape.get_inner_ptr();
} else if (auto sphere_col = entity_registry->get_inner().try_get<simpleengine::ecs::SphereColliderComponent>(entity)) {
return sphere_col->sphere_shape.get_inner_ptr();
} else if (auto cylinder_col = entity_registry->get_inner().try_get<simpleengine::ecs::CylinderColliderComponent>(entity)) {
return cylinder_col->cylinder_shape.get_inner_ptr();
} else if (auto cone_col = entity_registry->get_inner().try_get<simpleengine::ecs::ConeColliderComponent>(entity)) {
return cone_col->cone_shape.get_inner_ptr();
} else if (auto capsule_col = entity_registry->get_inner().try_get<simpleengine::ecs::CapsuleColliderComponent>(entity)) {
return capsule_col->capsule_shape.get_inner_ptr();
}
return nullptr;
}
bool PhysicsSystem::init_rigid_body_component(const entt::entity& entity, simpleengine::ecs::TransformComponent& transform_comp, simpleengine::ecs::RigidBodyComponent& rigid_body_comp) {
if (!rigid_body_comp.rigid_body) {
// Try to get the collision shape
btCollisionShape* collision_shape = try_get_collision_shape(entity);
if (!collision_shape) {
logger.warn("Entity with a rigid body component is missing a collider! The entities rigid body component will be removed!");
if (entity_registry->get_inner().remove<simpleengine::ecs::RigidBodyComponent>(entity) == 0) {
logger.warn("Failed to remove rigid body component from the entity!");
}
return true;
}
btTransform start_transform;
start_transform.setIdentity();
glm::vec3 origin = transform_comp.get_pos();
start_transform.setOrigin(btVector3(origin.x, origin.y, origin.z));
glm::quat rot = transform_comp.get_rotation_quat();
start_transform.setRotation(btQuaternion(rot.x, rot.y, rot.z, rot.w));
rigid_body_comp.col_shape = collision_shape;
btVector3 local_inertia;
if (rigid_body_comp.is_dynamic) {
// update collision shape
rigid_body_comp.col_shape->calculateLocalInertia(rigid_body_comp.mass, local_inertia);
}
rigid_body_comp.motion_state = new btDefaultMotionState(start_transform);
btRigidBody::btRigidBodyConstructionInfo rb_info(rigid_body_comp.mass, rigid_body_comp.motion_state, rigid_body_comp.col_shape, local_inertia);
rigid_body_comp.rigid_body = new btRigidBody(rb_info);
this->add_rigid_body(rigid_body_comp.rigid_body);
logger.debug("Initialized rigid body component");
return true;
}
return false;
}
}