diff --git a/CMake/GetEnTT.cmake b/CMake/GetEnTT.cmake new file mode 100644 index 0000000..0cdeaea --- /dev/null +++ b/CMake/GetEnTT.cmake @@ -0,0 +1,10 @@ +# Get the entt header libraries. +include(FetchContent) +FetchContent_Declare( + entt + GIT_REPOSITORY https://github.com/skypjack/entt.git + GIT_TAG v3.10.3 +) +FetchContent_MakeAvailable(entt) +message("Downloaded entt library to: ${entt_SOURCE_DIR}") +set(ENTT_INCLUDE_DIR ${entt_SOURCE_DIR}/src) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 53cdba1..d30ac6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(SimpleEngine) include(cmrc/CMakeRC.cmake) include(CMake/GetStbLibraries.cmake) +include(CMake/GetEnTT.cmake) # Add some CMake options: option(SIMPLE_ENGINE_BUILD_EXAMPLES "Build example projects" ON) @@ -47,11 +48,11 @@ target_link_libraries(simpleengine PUBLIC ${OPENGL_LIBRARIES}) target_link_libraries(simpleengine PUBLIC assimp) target_link_libraries(simpleengine PRIVATE simpleengine_resources) -target_include_directories(simpleengine PUBLIC ${STB_INCLUDE_DIR}) - # Include some dependencies' include directories 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}) # Add examples as a target if the user has them enabled if (SIMPLE_ENGINE_BUILD_EXAMPLES) diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 632a488..5ff3a3d 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -1,8 +1,9 @@ +#include "entt/entity/fwd.hpp" #include "simpleengine/camera.h" #include "simpleengine/ecs/component/mesh_component.h" #include +#include "simpleengine/ecs/component/transform_component.h" #include "simpleengine/ecs/entity.h" -#include "simpleengine/entity_manager.h" #include "simpleengine/gfx/light.h" #include "simpleengine/gfx/material.h" #include "simpleengine/gfx/mesh.h" @@ -20,6 +21,8 @@ #include #include +#include + //#include #include @@ -170,25 +173,29 @@ int main(int argc, char *argv[]) { textures.emplace(white_texture.type, std::vector{ white_texture }); se::gfx::Material white_material(textures, 1.f, 0.f, 0.f, 0.f, 0.f); + // Create a renderer + auto renderer = std::make_shared(game.get_window(), core_shader); + game.add_renderable(renderer); + + // Create a Scene and give it the renderer + auto scene = std::make_shared(renderer); + game.add_event(scene); + + // Create an Entity in the Scene and add components to it. + se::ecs::Entity entity = scene->create_entity(); + entity.add_component("examples/dev_testing/resources/dragon.obj"); + auto& transform_comp = entity.add_component(); + transform_comp.translate(12.f, -4.f, 0.f); + + // Create the entity and add the model component to it. /* auto entity = std::make_shared(); entity->add_component(cube_vertices, cube_indicies, white_material, true); entity->translate(3.5f, 0.f, 0.f); */ - auto entity = std::make_shared(); + /* auto entity = std::make_shared(); entity->add_component("examples/dev_testing/resources/dragon.obj"); - entity->translate(12.f, -4.f, 0.f); - - // Create a renderer and submit the entity into it. - auto renderer = std::make_shared(game.get_window(), core_shader); - renderer->enable_debug(); - renderer->submit_entity(entity); - game.add_renderable(renderer); - - // Create an EntityManager, and submit the entity into it. - auto ecs_manager = std::make_shared(); - ecs_manager->submit_entity(entity); - game.add_event(ecs_manager); + entity->translate(12.f, -4.f, 0.f); */ auto camera = std::make_shared(game.get_window(), core_shader, 70, glm::vec3(0, 0, 0)); game.add_event(camera); diff --git a/include/simpleengine/ecs/component/component.h b/include/simpleengine/ecs/component/component.h deleted file mode 100644 index d132f27..0000000 --- a/include/simpleengine/ecs/component/component.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "../../gfx/mesh.h" -#include "../../event/event.h" - -#include -#include - -namespace simpleengine { - /** - * @brief A Model is a object that will be shown on the screen by a renderer. - * - */ - class Component : public simpleengine::Event { - private: - static uint32_t incrementing_handle; - uint32_t handle; - public: - Component() { - handle = incrementing_handle++; - } - - uint32_t get_handle() { - return handle; - } - - virtual void update(const float& delta_time) override { - std::cout << "Component update" << std::endl; - } - }; -} \ No newline at end of file diff --git a/include/simpleengine/ecs/component/mesh_component.h b/include/simpleengine/ecs/component/mesh_component.h index 3daff3e..6e2bf15 100644 --- a/include/simpleengine/ecs/component/mesh_component.h +++ b/include/simpleengine/ecs/component/mesh_component.h @@ -1,6 +1,5 @@ #pragma once -#include "component.h" #include "../../gfx/mesh.h" #include "../../gfx/material.h" @@ -9,37 +8,32 @@ namespace simpleengine { /** - * @brief A Model is a object that will be shown on the screen by a renderer. + * @brief A component that contains a Mesh that will be rendered. * */ - class MeshComponent : public simpleengine::Component { + class MeshComponent { public: - gfx::Mesh model; - //gfx::Material material; + gfx::Mesh mesh; - MeshComponent(gfx::Mesh model) : model(model) { + MeshComponent(gfx::Mesh mesh) : mesh(mesh) { } MeshComponent(std::vector vertices, std::vector indicies, gfx::Material material, - bool calculate_normals = false): model(vertices, indicies, material) { + bool calculate_normals = false): mesh(vertices, indicies, material) { if (calculate_normals) { - model.calculate_normals(); + mesh.calculate_normals(); } } MeshComponent(std::vector vertices, std::vector indicies = std::vector(), std::optional material = std::nullopt, bool calculate_normals = false) : - model(vertices, indicies, material) { + mesh(vertices, indicies, material) { if (calculate_normals) { - model.calculate_normals(); + mesh.calculate_normals(); } } - - virtual void update(const float& delta_time) override { - - } }; } \ No newline at end of file diff --git a/include/simpleengine/ecs/component/model_component.h b/include/simpleengine/ecs/component/model_component.h index 9d6dfda..359298e 100644 --- a/include/simpleengine/ecs/component/model_component.h +++ b/include/simpleengine/ecs/component/model_component.h @@ -1,6 +1,5 @@ #pragma once -#include "component.h" #include "../../gfx/model.h" #include @@ -8,10 +7,10 @@ namespace simpleengine { /** - * @brief A Model is a object that will be shown on the screen by a renderer. + * @brief A component that contains a Model that will be rendered. * */ - class ModelComponent : public simpleengine::Component { + class ModelComponent { public: gfx::Model model; @@ -22,9 +21,5 @@ namespace simpleengine { ModelComponent(std::string model_file_path) : model(model_file_path) { } - - virtual void update(const float& delta_time) override { - - } }; } \ No newline at end of file diff --git a/include/simpleengine/ecs/component/transform_component.h b/include/simpleengine/ecs/component/transform_component.h new file mode 100644 index 0000000..f0fa948 --- /dev/null +++ b/include/simpleengine/ecs/component/transform_component.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include + +namespace simpleengine { + /** + * @brief A component that contains a Mesh that will be rendered. + * + */ + class TransformComponent { + public: + glm::mat4 transform_matrix; + + TransformComponent() : transform_matrix(glm::mat4(1.f)) { + + } + + TransformComponent(glm::mat4 transform_matrix) : transform_matrix(transform_matrix) { + + } + + friend TransformComponent operator+(TransformComponent lhs, const TransformComponent& rhs) { + lhs.transform_matrix += rhs.transform_matrix; + return lhs; + } + + friend TransformComponent operator-(TransformComponent lhs, const TransformComponent& rhs) { + lhs.transform_matrix -= rhs.transform_matrix; + return lhs; + } + + friend TransformComponent operator*(TransformComponent lhs, const TransformComponent& rhs) { + lhs.transform_matrix *= rhs.transform_matrix; + return lhs; + } + + friend TransformComponent operator/(TransformComponent lhs, const TransformComponent& rhs) { + lhs.transform_matrix /= rhs.transform_matrix; + return lhs; + } + + virtual void combine_transform(const glm::mat4& transform_matrix) { + this->transform_matrix *= transform_matrix; + } + + virtual void combine_transform(const TransformComponent& transformable) { + transform_matrix = transformable.transform_matrix; + } + + virtual void translate(float x, float y, float z) { + transform_matrix = glm::translate(transform_matrix, glm::vec3(x, y, z)); + } + + /* 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); + } + + virtual glm::mat4 rotation_x_matrix(float degrees) const { + return rotation_matrix(degrees, glm::vec3(1, 0, 0)); + } + + virtual glm::mat4 rotation_y_matrix(float degrees) const { + return rotation_matrix(degrees, glm::vec3(0, 1, 0)); + } + + virtual glm::mat4 rotation_z_matrix(float degrees) const { + return rotation_matrix(degrees, glm::vec3(0, 0, 1)); + } + + virtual void rotate(float degrees, glm::vec3 rotation_axis) { + transform_matrix = rotation_matrix(degrees, rotation_axis); + } + + virtual void rotate_x(float degrees) { + transform_matrix = rotation_x_matrix(degrees); + } + + virtual void rotate_y(float degrees) { + transform_matrix = rotation_y_matrix(degrees); + } + + virtual void rotate_z(float degrees) { + transform_matrix = rotation_z_matrix(degrees); + } + + virtual void scale(glm::vec3 scalar_vec) { + transform_matrix = glm::scale(transform_matrix, scalar_vec); + } + + virtual void scale(float scalar) { + transform_matrix = glm::scale(transform_matrix, glm::vec3(scalar, scalar, scalar)); + } + }; +} \ No newline at end of file diff --git a/include/simpleengine/ecs/entity.h b/include/simpleengine/ecs/entity.h index e1e5bf9..8cc2675 100644 --- a/include/simpleengine/ecs/entity.h +++ b/include/simpleengine/ecs/entity.h @@ -1,116 +1,266 @@ #pragma once -#include "component/component.h" -#include "../transformable.h" -#include "../util.h" +#include "entt/entity/fwd.hpp" +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include - -namespace simpleengine { - /** - * @brief A Model is a object that will be shown on the screen by a renderer. - * - */ - class Entity : public simpleengine::Event, public simpleengine::Transformable { - // TODO: Don't extend from Event, create own destroy function +namespace simpleengine::ecs { + class Entity { private: - static uint32_t incrementing_handle; - uint32_t handle; + entt::registry& registry; + entt::entity inner; public: - std::vector> components; + /* Entity(entt::entity entity) : inner(entity) { - Entity() : components({}) { - handle = incrementing_handle++; - } - - /* Entity() : components({}) { - std::random_device rd; // obtain a random number from hardware - std::mt19937 gen(rd()); // seed the generator - std::uniform_int_distribution distr(1, std::numeric_limits::max()); - - uint16_t num = distr(gen); - uint32_t pid = simpleengine::util::get_current_pid(); - - handle |= num; - handle |= (pid << 16); - - std::string binary = std::bitset<16>(num).to_string(); - std::cout << "Entity handle: " << binary << std::endl; - } */ - Entity(std::vector> components) : Entity() { - this->components = components; + Entity(entt::registry& registry, entt::entity entity) : registry(registry), inner(entity) { + } - uint32_t get_handle() { - return handle; + /** + * @brief Checks if an identifier refers to a valid entity. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a1795b1221d728f806319a685930f520d + * + * @return true if the identifier is valid + * @return false otherwise + */ + bool is_valid() const { + return registry.valid(inner); } - virtual void update(const float& delta_time) override { - for (auto& component : components) { - component->update(delta_time); - } - - rotate_y(delta_time * 10); // TODO: Remove + /** + * @brief Returns the actual version for an identifier. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a199babc787d6baa6f7ccce761228a5f6 + * + * @return entt::registry::version_type The version for the given identifier if valid, the tombstone version otherwise. + */ + entt::registry::version_type current_version() const { + return registry.current(inner); } - template - bool has_component() const { - for (const auto& comp : components) { - if (std::dynamic_pointer_cast(comp)) { - return true; - } - } - - return false; + /** + * @brief Releases an identifier. + * + * The version is updated and the identifier can be recycled at any time. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a3d9cb2368384b0952cb54848e777359e + * + * @return entt::registry::version_type The version of the recycled entity. + */ + entt::registry::version_type release() { + return registry.release(inner); } - template - std::shared_ptr get_component() const { - for (const auto& comp : components) { - if (std::shared_ptr dyn_comp = std::dynamic_pointer_cast(comp); dyn_comp) { - return dyn_comp; - } - } - - return nullptr; + /** + * @brief Releases an identifier. + * + * The suggested version or the valid version closest to the suggested one is used instead of the implicitly generated version. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#af9c919867fc93a7e1a2d0762ac3a9877 + * + * @param version A desired version upon destruction. + * @return entt::registry::version_type The version actually assigned to the entity. + */ + entt::registry::version_type release(entt::registry::version_type version) { + return registry.release(inner, version); } - template - void add_component(std::shared_ptr component) { - static_assert(std::is_base_of_v, "Component class must derive from simpleengine::Component"); - - // Only allow one type of the same component - assert(!has_component()); // TODO: Don't assert, give an error - components.push_back(component); + /** + * @brief Destroys an entity and releases its identifier. + * + * @warning Adding or removing components to an entity that is being destroyed can result in undefined behavior. Attempting to use an invalid entity results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a7b2c0368d508a6af2d094a9fc592a4a0 + * + * @return entt::registry::version_type The version of the recycled entity. + */ + entt::registry::version_type destroy() { + return registry.destroy(inner); } - template - void add_component(T component) { - static_assert(std::is_base_of_v, "Component class must derive from simpleengine::Component"); - - // Only allow one type of the same component - assert(!has_component()); // TODO: Don't assert, give an error - components.push_back(std::make_shared(component)); + /** + * @brief Destroys an entity and releases its identifier. + * + * The suggested version or the valid version closest to the suggested one is used instead of the implicitly generated version. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#adc175a0d3bcf83a133c63890c674ceb3 + * + * @param version A desired version upon destruction. + * @return entt::registry::version_type The version actually assigned to the entity. + */ + entt::registry::version_type destroy(entt::registry::version_type version) { + return registry.destroy(inner, version); } - template - std::shared_ptr add_component(Args&&... args) { - static_assert(std::is_base_of_v, "Component class must derive from simpleengine::Component"); + /** + * @brief Assigns the given component to an entity. + * + * The component must have a proper constructor or be of aggregate type. + * + * @warning Attempting to use an invalid entity or to assign a component to an entity that already owns it results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a4c9c0532972adc7a930a50888a97efdf + * + * @tparam Component Type of component to create. + * @tparam Args Types of arguments to use to construct the component. + * + * @param args Parameters to use to initialize the component. + * + * @return decltype(auto) A reference to the newly created component. + */ + template + decltype(auto) add_component(Args&&... args) { + return registry.emplace(inner, std::forward(args)...); + } - // Only allow one type of the same component - assert(!has_component()); // TODO: Don't assert, give an error - auto comp = std::make_shared(std::forward(args)...); - components.push_back(comp); + /** + * @brief Assigns or replaces the given component for an entity. + * + * The component must have a proper constructor or be of aggregate type. + * + * @warning Attempting to use an invalid entity or to assign a component to an entity that already owns it results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a3bbaebbb9365eef262453e42a8f7dc4b + * + * @tparam Component Type of component to assign or replace. + * @tparam Args Types of arguments to use to construct the component. + * + * @param args Parameters to use to initialize the component. + * + * @return decltype(auto) A reference to the newly created component. + */ + template + decltype(auto) add_or_replace_component(Args&&... args) { + return registry.emplace_or_replace(inner, std::forward(args)...); + } - return comp; + /** + * @brief Replaces the given component for an entity. + * + * The component must have a proper constructor or be of aggregate type. + * + * @warning Attempting to use an invalid entity or to replace a component of an entity that doesn't own it results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a0501ff5a96a3421f3eec427bf5d62380 + * + * @tparam Component Type of component to replace. + * @tparam Args Types of arguments to use to construct the component. + * + * @param args Parameters to use to initialize the component. + * + * @return decltype(auto) A reference to the component being replaced. + */ + template + decltype(auto) replace_component(Args&&... args) { + return registry.replace(inner, std::forward(args)...); + } + + /** + * @brief Patches the given component for an entity. + * + * The signature of the function should be equivalent to the following: + * \code{.cpp} + * void(Component &); + * \endcode + * + * @note Empty types aren't explicitly instantiated and therefore they are never returned. However, this function can be used to trigger an update signal for them. + * + * @warning Attempting to use an invalid entity or to patch a component of an entity that doesn't own it results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a22454253689ff77e41326f849bfea976 + * + * @tparam Component Type of component to patch. + * @tparam Func Types of the function objects to invoke. + * + * @param func Valid function objects. + * + * @return decltype(auto) A reference to the patched component. + */ + template + decltype(auto) patch(Func&&... func) { + return registry.patch(inner, std::forward(func)...); + } + + /** + * @brief Removes the given components from an entity. + * + * @warning Attempting to use an invalid entity results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#aa66ca71c5eb6c2e1b3bde6ff86a268c7 + * + * @tparam Component Type of component to remove. + * @tparam Other Other types of components to remove. + * + * @return size_t The number of components actually removed. + */ + template + size_t remove_components() { + return registry.remove(inner); + } + + /** + * @brief Erases the given components from an entity. + * + * @warning Attempting to use an invalid entity or to erase a component from an entity that doesn't own it results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#ad7a51ade7ff181d7aa0b35915d0a4f2b + * + * @tparam Component Types of components to erase. + * @tparam Other Other types of components to erase. + */ + template + void erase() { + return registry.remove(inner); + } + + /** + * @brief Checks if an entity has all the given components. + * + * @warning Attempting to use an invalid entity results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a40072eca607846f43f47d0e3f11dd196 + * + * @tparam Component Components for which to perform the check. + * + * @return true if the entity has all the components + * @return false otherwise + */ + template + bool has_all_of() const { + return registry.all_of(inner); + } + + /** + * @brief Checks if an entity has at least one of the given components. + * + * @warning Attempting to use an invalid entity results in undefined behavior. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a08f819276fd2d8b2b2b6d01357f61a42 + * + * @tparam Component Components for which to perform the check. + * + * @return true if the entity has at least one of the given components + * @return false otherwise + */ + template + bool has_any_of() const { + return registry.any_of(inner); + } + + /** + * @brief Checks if an entity has components assigned. + * + * @link https://skypjack.github.io/entt/classentt_1_1basic__registry.html#a10f5e61d4cabab9e9c1e87edc30de551 + * + * @return true if the entity has no components assigned + * @return false otherwise + */ + bool has_any_components() const { + return registry.orphan(inner); } }; } \ No newline at end of file diff --git a/include/simpleengine/entity_manager.h b/include/simpleengine/entity_manager.h deleted file mode 100644 index de7fe2d..0000000 --- a/include/simpleengine/entity_manager.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "ecs/entity.h" -#include "event/event.h" - -#include -#include -#include - -namespace simpleengine { - class EntityManager : public simpleengine::Event { - public: - std::unordered_map> entities; - - EntityManager(); - - virtual void submit_entity(std::shared_ptr entity); - virtual bool withdraw_entity(std::shared_ptr entity); - - virtual void initialize(); - virtual void destroy() override; - - virtual void update(const float& delta_time) override; - }; -} \ No newline at end of file diff --git a/include/simpleengine/gfx/mesh.h b/include/simpleengine/gfx/mesh.h index 45a82ba..e696053 100644 --- a/include/simpleengine/gfx/mesh.h +++ b/include/simpleengine/gfx/mesh.h @@ -23,6 +23,7 @@ namespace simpleengine::gfx { std::vector vertices; std::vector indicies; + bool are_buffers_created = false; gfx::VBO ebo; gfx::VBO vbo; gfx::VAO vao; diff --git a/include/simpleengine/gfx/renderer.h b/include/simpleengine/gfx/renderer.h index 8ee23d7..3cb5cce 100644 --- a/include/simpleengine/gfx/renderer.h +++ b/include/simpleengine/gfx/renderer.h @@ -1,45 +1,29 @@ #pragma once -#include "../ecs/entity.h" -#include "material.h" -#include "texture.h" #include "shader.h" -//#include "renderable.h" -#include "mesh.h" -#include "model.h" +#include "simpleengine/gfx/mesh.h" #include #include +#include namespace simpleengine::gfx { + class RenderingJob { + public: + gfx::Mesh& rendering_mesh; + glm::mat4 transform_mat; + + RenderingJob(gfx::Mesh& mesh, glm::mat4 position) : rendering_mesh(mesh), transform_mat(position) { + + } + }; + class Renderer : public simpleengine::Renderable { private: GLFWwindow* window; public: - class RenderingModel { - public: - std::shared_ptr entity; - std::unordered_map component_models; - - RenderingModel(std::shared_ptr entity) : entity(entity) { - - } - - /** - * @brief Create and delete buffers for new and old components in entity. - * - */ - void update_buffers(); - - /** - * @brief Destroy the buffers - * - */ - void destroy_buffers(); - }; - - std::unordered_map rendering_models; + std::queue rendering_queue; gfx::Shader shader; Renderer(GLFWwindow* window, gfx::Shader shader); @@ -47,8 +31,8 @@ namespace simpleengine::gfx { void enable_debug(); - virtual void submit_entity(std::shared_ptr entity); - virtual bool withdraw_entity(std::shared_ptr entity); + virtual void queue_job(RenderingJob job); + virtual void create_job_buffers(RenderingJob& job); virtual void initialize(); virtual void destroy() override; diff --git a/include/simpleengine/scene.h b/include/simpleengine/scene.h index ab24895..87f8318 100644 --- a/include/simpleengine/scene.h +++ b/include/simpleengine/scene.h @@ -1,44 +1,32 @@ #pragma once +#include "entt/entity/fwd.hpp" #include "gfx/mesh.h" -#include "entity.h" #include "event/event.h" #include "renderable.h" +#include "simpleengine/gfx/renderer.h" #include #include #include +#include + namespace simpleengine { + namespace ecs { + class Entity; + } + class Scene : public simpleengine::Event { + protected: + entt::registry registry; + std::shared_ptr renderer; public: - /** - * @brief A list of entities in this scene. - * - */ - std::vector> entities; + Scene(std::shared_ptr renderer); - /** - * @brief Models that don't belong to an entity. - * - */ - std::vector> stray_models; + ecs::Entity create_entity(); - Scene() = default; - - void add_entity(std::shared_ptr entity) { - entities.push_back(entity); - } - - void add_stray_model(std::shared_ptr stray) { - stray_models.push_back(stray); - } - - virtual void update(const float& delta_time) override { - for (auto& entity : entities) { - entity->update(delta_time); - } - } + virtual void update(const float& delta_time) override; }; } \ No newline at end of file diff --git a/src/ecs/component/component.cpp b/src/ecs/component/component.cpp deleted file mode 100644 index 02f50b5..0000000 --- a/src/ecs/component/component.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "ecs/component/component.h" - -uint32_t simpleengine::Component::incrementing_handle = 0; \ No newline at end of file diff --git a/src/ecs/entity.cpp b/src/ecs/entity.cpp deleted file mode 100644 index 01c1846..0000000 --- a/src/ecs/entity.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "ecs/entity.h" - -uint32_t simpleengine::Entity::incrementing_handle = 0; \ No newline at end of file diff --git a/src/entity_manager.cpp b/src/entity_manager.cpp deleted file mode 100644 index 53e4c8e..0000000 --- a/src/entity_manager.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "entity_manager.h" - -simpleengine::EntityManager::EntityManager() { - -} - -void simpleengine::EntityManager::submit_entity(std::shared_ptr entity) { - entities.emplace(entity->get_handle(), entity); -} - -bool simpleengine::EntityManager::withdraw_entity(std::shared_ptr entity) { - auto it = entities.find(entity->get_handle()); - - if (it != entities.end()) { - it->second->destroy(); - entities.erase(it); - - return true; - } - - return false; -} - -void simpleengine::EntityManager::initialize() { - -} - -void simpleengine::EntityManager::destroy() { - std::cout << "Destroy entity manager!" << std::endl; - - for (auto& [handle, entity] : entities) { - entity->destroy(); - } -} - -void simpleengine::EntityManager::update(const float& delta_time) { - for (auto& [handle, entity] : entities) { - entity->update(delta_time); - } -} \ No newline at end of file diff --git a/src/gfx/model.cpp b/src/gfx/model.cpp index c749bb5..8f1d531 100644 --- a/src/gfx/model.cpp +++ b/src/gfx/model.cpp @@ -38,7 +38,7 @@ namespace simpleengine::gfx { // process all the node's meshes (if any) for (int i = 0; i < node->mNumMeshes; i++) { aiMesh *mesh = scene->mMeshes[node->mMeshes[i]]; - meshes.push_back(process_mesh(mesh, scene)); + meshes.push_back(process_mesh(mesh, scene)); } // then do the same for each of its children diff --git a/src/gfx/renderer.cpp b/src/gfx/renderer.cpp index 6ad4644..6e4e058 100644 --- a/src/gfx/renderer.cpp +++ b/src/gfx/renderer.cpp @@ -1,6 +1,4 @@ #include "gfx/renderer.h" -#include "ecs/component/component.h" -#include "ecs/entity.h" #include "gfx/mesh.h" #include "gfx/vao.h" #include "renderable.h" @@ -12,16 +10,7 @@ #include namespace simpleengine::gfx { - void create_mesh_buffers(std::shared_ptr comp, simpleengine::gfx::Mesh& mesh); - - void Renderer::RenderingModel::destroy_buffers() { - std::cout << "Destroying entity models..." << std::endl; - - // Iterate through all buffer lists and destroy each inner buffer. - for (auto& pair : component_models) { - pair.second.destroy(); - } - } + void create_mesh_buffers(simpleengine::gfx::Mesh& mesh); Renderer::Renderer(GLFWwindow* window, gfx::Shader shader): window(window), shader(shader) { @@ -45,24 +34,40 @@ namespace simpleengine::gfx { glDebugMessageCallback(debug_message_callback, 0); } - void Renderer::submit_entity(std::shared_ptr entity) { - std::cout << "Submitting entity (" << entity->get_handle() << ")..." << std::endl; - auto it = rendering_models.emplace(entity->get_handle(), entity); - it.first->second.update_buffers(); + void Renderer::queue_job(RenderingJob job) { + RenderingJob& emplace = rendering_queue.emplace(job); + create_job_buffers(emplace); } - bool Renderer::withdraw_entity(std::shared_ptr entity) { - std::cout << "Withdrawing entity (" << entity->get_handle() << ")..."; - auto it = rendering_models.find(entity->get_handle()); + void Renderer::create_job_buffers(RenderingJob& job) { + Mesh& rendering_mesh = job.rendering_mesh; - if (it != rendering_models.end()) { - it->second.destroy_buffers(); - rendering_models.erase(it); + if (!rendering_mesh.are_buffers_created) { + gfx::VBO& vbo = rendering_mesh.vbo; + gfx::VBO& ebo = rendering_mesh.ebo; + gfx::VAO& vao = rendering_mesh.vao; - return true; + vao.bind(); + vbo.buffer(rendering_mesh.vertices.data(), 0, sizeof(LitVertex) * rendering_mesh.vertices.size()); + + if (!rendering_mesh.indicies.empty()) { + ebo.buffer(rendering_mesh.indicies.data(), 0, rendering_mesh.indicies.size() * sizeof(GLuint)); + } + + // Enable VAO attributes + vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position), false); + vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false); + vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false); + vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false); + vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + rendering_mesh.are_buffers_created = true; + + std::cout << "Created render job buffers" << std::endl; } - - return false; } void Renderer::update(const float& delta_time) { @@ -76,113 +81,53 @@ namespace simpleengine::gfx { void Renderer::destroy() { std::cout << "Destroying renderer..." << std::endl; - for (auto& [handle, rendering] : rendering_models) { + /* for (auto& [handle, rendering] : rendering_models) { rendering.destroy_buffers(); - } + } */ } void Renderer::render() { shader.use(); - for (auto& [handle, rendering] : rendering_models) { - if (rendering.component_models.size() >= 0) { - std::shared_ptr& entity = rendering.entity; + while (!rendering_queue.empty()) { + // Get the job from the queue, we'll remove it after we render. + RenderingJob& job = rendering_queue.front(); + Mesh& mesh = job.rendering_mesh; - shader.set_uniform_matrix_4f("transform_matrix", entity->transform_matrix, false); + shader.set_uniform_matrix_4f("transform_matrix", job.transform_mat, false); - for (const auto& pair : rendering.component_models) { - Mesh& model = pair.second; - std::optional& material = model.material; + std::optional& material = mesh.material; - shader.set_uniform_int("u_textures", 0, false); + shader.set_uniform_int("u_textures", 0, false); - if (material.has_value()) { - shader.set_uniform_float("u_texture_shine", material->shine, false); - shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false); + if (material.has_value()) { + shader.set_uniform_float("u_texture_shine", material->shine, false); + shader.set_uniform_float("u_texture_reflectivity", material->reflectivity, false); - int texture_count = 0; - auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE); - for (const auto& texture : diffuse_maps->second) { - // We can only bind to 16 textures at a time (indexes are 0-15) - if (texture_count >= 16) break; + int texture_count = 0; + auto diffuse_maps = material->textures.find(aiTextureType_DIFFUSE); + for (const auto& texture : diffuse_maps->second) { + // We can only bind to 16 textures at a time (indexes are 0-15) + if (texture_count >= 16) break; - glActiveTexture(GL_TEXTURE0 + texture_count); - glBindTextureUnit(texture_count, texture.get_texture_id()); + glActiveTexture(GL_TEXTURE0 + texture_count); + glBindTextureUnit(texture_count, texture.get_texture_id()); - texture_count++; - } - } - - model.vao.bind(); - if (model.indicies.empty()) { - glDrawArrays(GL_TRIANGLES, 0, model.vertices.size()); - } else { - glDrawElements(GL_TRIANGLES, model.indicies.size(), GL_UNSIGNED_INT, 0); - } + texture_count++; } } + + mesh.vao.bind(); + if (mesh.indicies.empty()) { + glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size()); + } else { + glDrawElements(GL_TRIANGLES, mesh.indicies.size(), GL_UNSIGNED_INT, 0); + } + + // Now we'll remove the job from the queue. + rendering_queue.pop(); } shader.unuse(); } - - void Renderer::RenderingModel::update_buffers() { - if (entity->has_component()) { - std::shared_ptr comp = entity->get_component(); - auto iter = component_models.find(comp->get_handle()); - if (iter == component_models.end()) { - std::cout << "Enabling buffer attributes for MeshComponent (" << comp->get_handle() << ")..." << std::endl; - - //iter->second = comp->model; - gfx::Mesh& mesh = comp->model; - create_mesh_buffers(comp, mesh); - component_models.emplace(comp->get_handle(), mesh); - - std::cout << "Enabled all buffer attributes for MeshComponent" << std::endl; - } else { - std::cout << "Already exists" << std::endl; - } - } else if (entity->has_component()) { - std::shared_ptr comp = entity->get_component(); - - auto iter = component_models.find(comp->get_handle()); - if (iter == component_models.end()) { - std::cout << "Enabling buffer attributes for ModelComponent (" << comp->get_handle() << ")..." << std::endl; - - // Store all the model's meshes - for (auto& mesh : comp->model.meshes) { - create_mesh_buffers(comp, mesh); - - component_models.emplace(comp->get_handle(), mesh); - } - - std::cout << "Enabled all buffer attributes for ModelComponent" << std::endl; - } else { - std::cout << "Already exists" << std::endl; - } - } - } - - void create_mesh_buffers(std::shared_ptr comp, gfx::Mesh& mesh) { - gfx::VBO& vbo = mesh.vbo; - gfx::VBO& ebo = mesh.ebo; - gfx::VAO& vao = mesh.vao; - - vao.bind(); - vbo.buffer(mesh.vertices.data(), 0, sizeof(LitVertex) * mesh.vertices.size()); - - if (!mesh.indicies.empty()) { - ebo.buffer(mesh.indicies.data(), 0, mesh.indicies.size() * sizeof(GLuint)); - } - - // Enable VAO attributes - vao.enable_attrib(vbo, 0, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, position), false); - vao.enable_attrib(vbo, 1, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, color), false); - vao.enable_attrib(vbo, 2, 3, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, normal), false); - vao.enable_attrib(vbo, 3, 2, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, tex_coord), false); - vao.enable_attrib(vbo, 4, 1, GL_FLOAT, sizeof(LitVertex), offsetof(LitVertex, texture_id), false); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } } \ No newline at end of file diff --git a/src/scene.cpp b/src/scene.cpp new file mode 100644 index 0000000..00bdb9e --- /dev/null +++ b/src/scene.cpp @@ -0,0 +1,29 @@ +#include "scene.h" +#include "ecs/component/mesh_component.h" +#include "ecs/component/model_component.h" +#include "ecs/component/transform_component.h" +#include "ecs/entity.h" +#include "gfx/renderer.h" + +namespace simpleengine { + Scene::Scene(std::shared_ptr renderer) : renderer(renderer) { + + } + + ecs::Entity Scene::create_entity() { + return ecs::Entity(registry, registry.create()); + } + + void Scene::update(const float& delta_time) { + // Is there a way these can be grouped? + registry.view().each([this](const TransformComponent& transform, ModelComponent& model_component) { + for (auto& mesh : model_component.model.meshes) { + renderer->queue_job(gfx::RenderingJob(mesh, transform.transform_matrix)); + } + }); + + registry.view().each([this](const TransformComponent& transform, MeshComponent& mesh_component) { + renderer->queue_job(gfx::RenderingJob(mesh_component.mesh, transform.transform_matrix)); + }); + } +} \ No newline at end of file