From 4a624cfe70ce7e373e92ba3d3233970fe2a9e4ed Mon Sep 17 00:00:00 2001 From: Erris Date: Tue, 3 Mar 2026 08:51:02 +0100 Subject: [PATCH 1/8] adding materials, adding serialization for meshes and materials, random fixes --- editor/include/editor.hpp | 8 ++- editor/include/editor_component.hpp | 1 + editor/include/panels/content_browser.hpp | 1 + editor/src/editor_component.cpp | 65 +++++++++++++++++- editor/src/panels/content_browser.cpp | 28 +++++--- editor/src/panels/scene_hierarchy.cpp | 6 ++ .../open_engine/renderer/renderer3d.hpp | 20 +++++- .../include/open_engine/scene/components.hpp | 15 +++- .../include/open_engine/scene/scene.hpp | 2 +- .../src/open_engine/renderer/renderer3d.cpp | 10 ++- open_engine/src/open_engine/scene/scene.cpp | 26 +++++-- .../open_engine/scene/scene_serializer.cpp | 62 +++++++++++++++++ resources/textures/icons/file.png | Bin 0 -> 2153 bytes resources/textures/icons/folder2.png | Bin 0 -> 2212 bytes resources/textures/icons/play.png | Bin 320 -> 2784 bytes resources/textures/icons/stop.png | Bin 156 -> 1727 bytes 16 files changed, 222 insertions(+), 22 deletions(-) mode change 100644 => 100755 editor/src/panels/content_browser.cpp create mode 100644 resources/textures/icons/file.png create mode 100644 resources/textures/icons/folder2.png diff --git a/editor/include/editor.hpp b/editor/include/editor.hpp index 0820057..982ce97 100755 --- a/editor/include/editor.hpp +++ b/editor/include/editor.hpp @@ -1,7 +1,6 @@ #ifndef EDITOR_HPP #define EDITOR_HPP -#include #include #include "open_engine/renderer/renderer3d.hpp" @@ -92,9 +91,11 @@ namespace OpenEngine { editor_camera = EditorCamera(30.0f, 1920.0f/1080.0f, 0.1f, 1000.0f); + // TODO: Add license icons["play"] = Texture2D::Create("resources/textures/icons/play.png"); icons["stop"] = Texture2D::Create("resources/textures/icons/stop.png"); + // ============================================= Entity cube = scene->CreateEntity("cube"); @@ -104,6 +105,7 @@ namespace OpenEngine { cube.AddComponent(mesh); + // ============================================= Entity quad = scene->CreateEntity("quad"); quad.AddComponent(); quad.GetComponents().translation = {0, 0, 0}; @@ -112,6 +114,7 @@ namespace OpenEngine { quad.AddComponent(quad_mesh); + // ============================================= Entity cube2 = scene->CreateEntity("cube2"); cube2.AddComponent(); cube2.GetComponents().translation = {2, 0, 0}; @@ -129,7 +132,6 @@ namespace OpenEngine { } */ - // TODO: Add file texture. Get free icons and add license //icons["folder"] = Texture2D::Create("resources/textures/icons/folder.png"); /* for (float i = 0; i < 200; i++) { @@ -352,7 +354,7 @@ namespace OpenEngine { bool was_focused = viewport_focused; viewport_focused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow); viewport_hovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow); - Application::Get().GetImGuiLayer()->SetBlockEvents((!viewport_focused && !viewport_hovered) || ImGui::IsAnyItemActive()); + Application::Get().GetImGuiLayer()->SetBlockEvents(ImGui::IsAnyItemActive()); if (viewport_focused && !was_focused) editor_camera.ResetMousePosition(); diff --git a/editor/include/editor_component.hpp b/editor/include/editor_component.hpp index bc5623e..c9fd455 100644 --- a/editor/include/editor_component.hpp +++ b/editor/include/editor_component.hpp @@ -17,6 +17,7 @@ namespace OpenEngine { void SpriteOnImGuiRender(entt::registry& registry, entt::entity entity); void CameraOnImGuiRender(entt::registry& registry, entt::entity entity); void MeshOnImGuiRender(entt::registry®istry, entt::entity entity); + void MaterialOnImGuiRender(entt::registry& registry, entt::entity entity); } #endif // EDITOR_COMPONENT_HPP diff --git a/editor/include/panels/content_browser.hpp b/editor/include/panels/content_browser.hpp index f68ca4d..72a9fc6 100644 --- a/editor/include/panels/content_browser.hpp +++ b/editor/include/panels/content_browser.hpp @@ -18,6 +18,7 @@ namespace OpenEngine { private: std::filesystem::path current_directory; Ref folder_icon; + Ref file_icon; }; } diff --git a/editor/src/editor_component.cpp b/editor/src/editor_component.cpp index 051f377..68de901 100644 --- a/editor/src/editor_component.cpp +++ b/editor/src/editor_component.cpp @@ -1,5 +1,9 @@ #include "imgui.h" +#include "open_engine/renderer/renderer3d.hpp" +#include "open_engine/scene/components.hpp" #include +#include +#include #include namespace OpenEngine { @@ -101,6 +105,7 @@ namespace OpenEngine { DrawVec3Control("Rotation", rotation_comp); transform.rotation = glm::radians(rotation_comp); DrawVec3Control("Scale", transform.scale); + ImGui::Spacing(); }; void SpriteOnImGuiRender(entt::registry& registry, entt::entity entity) @@ -171,8 +176,66 @@ namespace OpenEngine { }; - void MeshOnImGuiRender(entt::registry®istry, entt::entity entity) + void MeshOnImGuiRender(entt::registry& registry, entt::entity entity) { + auto& mesh_component = registry.get(entity); + const char* items[] = { "Quad", "Cube" }; + static int item_selected_idx = 0; + + if (ImGui::BeginCombo("Mesh", items[item_selected_idx])) { + for (int n = 0; n < 2; n++) + { + const bool is_selected = (item_selected_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_selected_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + + if ((int)mesh_component.primitive_type == (item_selected_idx + 1)) + return; + + mesh_component.primitive_type = (PrimitiveType)(item_selected_idx + 1); + switch (mesh_component.primitive_type) { + case OpenEngine::PrimitiveType::Quad: + { + mesh_component.mesh = CreateQuad((uint32_t)entity); + break; + } + case OpenEngine::PrimitiveType::Cube: + { + mesh_component.mesh = CreateCube((uint32_t)entity); + break; + } + default: + break; + } + } + } + + void MaterialOnImGuiRender(entt::registry& registry, entt::entity entity) + { + auto& material = registry.get(entity).material; + + auto& albedo = material.albedo; + auto& roughness = material.roughness; + auto& metallic = material.metallic; + auto& ambient = material.ambient_strength; + auto& specular = material.specular_strength; + + if (ImGui::SliderFloat4("Albedo", glm::value_ptr(albedo), 0, 1)) + material.albedo = albedo; + if (ImGui::SliderFloat("Roughness", &roughness, 0, 1)) + material.roughness = roughness; + if (ImGui::SliderFloat("Metallic", &metallic, 0, 1)) + material.metallic = metallic; + if (ImGui::SliderFloat("Ambient strength", &ambient, 0, 1)) + material.ambient_strength = ambient; + if (ImGui::SliderFloat("Specular strength", &specular, 0, 10)) + material.specular_strength = specular; } } diff --git a/editor/src/panels/content_browser.cpp b/editor/src/panels/content_browser.cpp old mode 100644 new mode 100755 index acb26cd..7d7c056 --- a/editor/src/panels/content_browser.cpp +++ b/editor/src/panels/content_browser.cpp @@ -15,8 +15,9 @@ namespace OpenEngine { ContentBrowserPanel::ContentBrowserPanel() : current_directory(assets_directory) { - // TODO: Add file texture. Get free icons and add license - folder_icon = Texture2D::Create("resources/textures/icons/folder.png"); + // TODO: Add license + folder_icon = Texture2D::Create("resources/textures/icons/folder2.png"); + file_icon = Texture2D::Create("resources/textures/icons/file.png"); } void ContentBrowserPanel::OnImGuiRender() @@ -30,6 +31,16 @@ namespace OpenEngine { current_directory = current_directory.parent_path(); auto directory_it = std::filesystem::directory_iterator(current_directory); + std::vector entries; + + for (auto entry : directory_it) + entries.emplace_back(entry); + + std::sort(entries.begin(), entries.end(), + [](const std::filesystem::directory_entry& a, + const std::filesystem::directory_entry& b) { + return (a.is_directory() && !b.is_directory()); + }); ImVec2 button_size = { 100, 100 }; auto panel_width = ImGui::GetContentRegionAvail().x; @@ -42,9 +53,12 @@ namespace OpenEngine { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, padding); + float margin = 20.0f; + ImGui::Indent(margin); + if (ImGui::BeginTable("table1", table_columns, ImGuiTableFlags_SizingFixedSame)) { - for (auto& entry : directory_it) { + for (auto& entry : entries) { auto file_name = entry.path().filename().string(); ImGui::PushID(file_name.c_str()); @@ -56,17 +70,14 @@ namespace OpenEngine { ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.270f, 0.278f, 0.352f, 1.0f }); ImGui::BeginGroup(); - ImGui::ImageButton("##X", (ImTextureID)folder_icon->GetID(), button_size, { 0, 1 }, { 1, 0 }); + Ref icon = entry.is_directory() ? folder_icon : file_icon; + ImGui::ImageButton("##X", (ImTextureID)icon->GetID(), button_size, { 0, 1 }, { 1, 0 }); if (entry.is_regular_file() && ImGui::BeginDragDropSource()) { const char* source = entry.path().c_str(); ImGui::SetDragDropPayload("CONTENT_BROWSER_PAYLOAD", source, (strlen(source) + 1) * sizeof(char), ImGuiCond_Once); ImGui::EndDragDropSource(); } - - float columnWidth = ImGui::GetColumnWidth(); - float textWidth = ImGui::CalcTextSize(file_name.c_str()).x; - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (columnWidth - textWidth) * 0.5f); ImGui::TextWrapped("%s", file_name.c_str()); ImGui::EndGroup(); @@ -81,6 +92,7 @@ namespace OpenEngine { } ImGui::EndTable(); } + ImGui::Unindent(); ImGui::PopStyleVar(); ImGui::End(); diff --git a/editor/src/panels/scene_hierarchy.cpp b/editor/src/panels/scene_hierarchy.cpp index f00d60e..0c716ad 100644 --- a/editor/src/panels/scene_hierarchy.cpp +++ b/editor/src/panels/scene_hierarchy.cpp @@ -23,6 +23,7 @@ namespace OpenEngine { RegisterDrawer("Sprite Renderer", &SpriteOnImGuiRender); RegisterDrawer("Camera", &CameraOnImGuiRender); RegisterDrawer("Mesh", &MeshOnImGuiRender); + RegisterDrawer("Material", &MaterialOnImGuiRender); scene = context; selected_context = {}; @@ -51,6 +52,11 @@ namespace OpenEngine { selected_context.AddComponent(); ImGui::CloseCurrentPopup(); } + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Material")) { + selected_context.AddComponent(); + ImGui::CloseCurrentPopup(); + } } void EntityPopup(Ref& scene) diff --git a/open_engine/include/open_engine/renderer/renderer3d.hpp b/open_engine/include/open_engine/renderer/renderer3d.hpp index c79cd39..2ee90df 100644 --- a/open_engine/include/open_engine/renderer/renderer3d.hpp +++ b/open_engine/include/open_engine/renderer/renderer3d.hpp @@ -10,6 +10,14 @@ namespace OpenEngine { // SHOULD BE MOVED ================================== + + enum class PrimitiveType + { + None = 0, + Quad, + Cube + }; + struct MeshVertex { glm::vec3 position; @@ -19,6 +27,15 @@ namespace OpenEngine { uint32_t id = -1; }; + struct Material + { + glm::vec4 albedo = { 1.0f, 1.0f, 1.0f, 1.0f }; + float roughness = 1.0f; + float metallic = 1.0f; + float ambient_strength = 1.0f; + float specular_strength = 1.0f; + }; + struct Mesh { Ref vertex_array; @@ -46,7 +63,8 @@ namespace OpenEngine { static void BeginScene(const EditorCamera& camera); static void EndScene(); - static void DrawMesh(const Ref& mesh, const glm::mat4& transform); + static void DrawMesh(const Ref& mesh, Material& material, + const glm::mat4& transform); }; } diff --git a/open_engine/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index b1e55f1..aae8457 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -86,17 +86,28 @@ namespace OpenEngine { (delete nsc->instance); nsc->instance = nullptr; }; - } + }; }; struct MeshComponent { Ref mesh; + PrimitiveType primitive_type = PrimitiveType::None; MeshComponent() = default; MeshComponent(const MeshComponent&) = default; MeshComponent(const Ref& mesh) - : mesh(mesh) {} + : mesh(mesh) {}; + }; + + struct MaterialComponent + { + Material material; + + MaterialComponent() = default; + MaterialComponent(const MaterialComponent&) = default; + MaterialComponent(const Material& material) + : material(material) {}; }; } diff --git a/open_engine/include/open_engine/scene/scene.hpp b/open_engine/include/open_engine/scene/scene.hpp index cf299a8..a4cb2cc 100644 --- a/open_engine/include/open_engine/scene/scene.hpp +++ b/open_engine/include/open_engine/scene/scene.hpp @@ -40,7 +40,7 @@ namespace OpenEngine { uint32_t viewport_width = 0, viewport_height = 0; - std::vector entities_to_be_deleted; + std::vector pending_deletion; friend class SceneSerializer; friend class Entity; diff --git a/open_engine/src/open_engine/renderer/renderer3d.cpp b/open_engine/src/open_engine/renderer/renderer3d.cpp index cc14723..58120ba 100644 --- a/open_engine/src/open_engine/renderer/renderer3d.cpp +++ b/open_engine/src/open_engine/renderer/renderer3d.cpp @@ -176,6 +176,9 @@ namespace OpenEngine { }; TransformData transform_buffer; Ref transform_uniform_buffer; + + Material material_buffer; + Ref material_uniform_buffer; }; static Renderer3DData renderer_data; @@ -190,6 +193,7 @@ namespace OpenEngine { renderer_data.color_shader_3d = Shader::Create("assets/shaders/color3d.glsl"); renderer_data.camera_uniform_buffer = UniformBuffer::Create(sizeof(Renderer3DData::CameraData), 0); renderer_data.transform_uniform_buffer = UniformBuffer::Create(sizeof(Renderer3DData::TransformData), 1); + renderer_data.material_uniform_buffer = UniformBuffer::Create(sizeof(Material), 2); glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); @@ -230,7 +234,8 @@ namespace OpenEngine { } - void Renderer3D::DrawMesh(const Ref& mesh, const glm::mat4& transform) + void Renderer3D::DrawMesh(const Ref& mesh, Material& material, + const glm::mat4& transform) { OE_PROFILE_FUNCTION(); @@ -239,6 +244,9 @@ namespace OpenEngine { renderer_data.transform_buffer.transform = transform; renderer_data.transform_uniform_buffer->SetData(&renderer_data.transform_buffer, sizeof(Renderer3DData::TransformData)); + renderer_data.material_buffer = material; + renderer_data.material_uniform_buffer->SetData(&renderer_data.material_buffer, sizeof(Material)); + mesh->vertex_array->Bind(); RenderCommand::DrawIndexed(mesh->vertex_array, mesh->indices.size()); diff --git a/open_engine/src/open_engine/scene/scene.cpp b/open_engine/src/open_engine/scene/scene.cpp index d6a114e..5fe217d 100644 --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -26,15 +26,15 @@ namespace OpenEngine { void Scene::MarkEntityForDeletion(Entity entity) { - entities_to_be_deleted.emplace_back(entity); + pending_deletion.emplace_back(entity); } void Scene::UpdateEntities() { - for (auto& entity : entities_to_be_deleted) + for (auto& entity : pending_deletion) DeleteEntity(entity); - entities_to_be_deleted.clear(); + pending_deletion.clear(); } void Scene::OnUpdateRuntime() @@ -75,8 +75,13 @@ namespace OpenEngine { for (const auto& entity : view) { auto [transform, mesh] = view.get(entity); + Material material; - Renderer3D::DrawMesh(mesh.mesh, GetTransformFromComp(transform)); + Entity _entity(entity, this); + if (_entity.HasComponent()) + material = _entity.GetComponents().material; + + Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); /* if (sprite.texture) Renderer2D::DrawQuad(GetTransformFromComp(transform), @@ -101,7 +106,13 @@ namespace OpenEngine { for (const auto& entity : view) { auto [transform, mesh] = view.get(entity); - Renderer3D::DrawMesh(mesh.mesh, GetTransformFromComp(transform)); + Material material; + + Entity _entity(entity, this); + if (_entity.HasComponent()) + material = _entity.GetComponents().material; + + Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); } Renderer3D::EndScene(); @@ -170,4 +181,9 @@ namespace OpenEngine { void Scene::OnComponentAdded(Entity entity, MeshComponent& component) { } + + template<> + void Scene::OnComponentAdded(Entity entity, MaterialComponent& component) + { + } } diff --git a/open_engine/src/open_engine/scene/scene_serializer.cpp b/open_engine/src/open_engine/scene/scene_serializer.cpp index 270273e..26600b5 100644 --- a/open_engine/src/open_engine/scene/scene_serializer.cpp +++ b/open_engine/src/open_engine/scene/scene_serializer.cpp @@ -1,7 +1,9 @@ +#include #include #include "core.hpp" #include +#include "renderer/renderer3d.hpp" #include "scene/components.hpp" #include "scene/entity.hpp" @@ -149,6 +151,32 @@ namespace OpenEngine { out << YAML::EndMap; // SpriteRendererComponent } + if (entity.HasComponent()) + { + out << YAML::Key << "MeshComponent"; + out << YAML::BeginMap; // MeshComponent + + auto& mesh_component = entity.GetComponents(); + out << YAML::Key << "MeshType" << YAML::Value << (int)mesh_component.primitive_type; + + out << YAML::EndMap; // MeshComponent + } + + if (entity.HasComponent()) + { + out << YAML::Key << "MaterialComponent"; + out << YAML::BeginMap; // MaterialComponent + + auto& material = entity.GetComponents().material; + out << YAML::Key << "Albedo" << YAML::Value << material.albedo; + out << YAML::Key << "Roughness" << YAML::Value << material.roughness; + out << YAML::Key << "Metalic" << YAML::Value << material.metallic; + out << YAML::Key << "AmbiantStrength" << YAML::Value << material.ambient_strength; + out << YAML::Key << "SpecularStrength" << YAML::Value << material.specular_strength; + + out << YAML::EndMap; // MaterialComponent + } + out << YAML::EndMap; } @@ -241,6 +269,40 @@ namespace OpenEngine { auto& src = deserializedEntity.AddComponent(); src.color = spriteRendererComponent["Color"].as(); } + + auto mesh_component = entity["MeshComponent"]; + if (mesh_component) + { + auto& mesh = deserializedEntity.AddComponent(); + switch (mesh.primitive_type) { + case OpenEngine::PrimitiveType::Quad: + { + mesh.mesh = CreateQuad((uint32_t)deserializedEntity); + break; + } + case OpenEngine::PrimitiveType::Cube: + { + mesh.mesh = CreateCube((uint32_t)deserializedEntity); + break; + } + default: + break; + } + } + + auto material_component = entity["MaterialComponent"]; + if (material_component) + { + auto& material = deserializedEntity.AddComponent(); + material.material.albedo = material_component["Albedo"].as(); + material.material.roughness = material_component["Roughness"].as(); + material.material.metallic = material_component["Metalic"].as(); + material.material.ambient_strength = material_component["AmbiantStrength"].as(); + material.material.specular_strength = material_component["SpecularStrength"].as(); + } + + auto mesh = CreateCube((uint32_t)deserializedEntity); + deserializedEntity.AddComponent(mesh); } } diff --git a/resources/textures/icons/file.png b/resources/textures/icons/file.png new file mode 100644 index 0000000000000000000000000000000000000000..4c885f7c11be50e741f31ba58becf8dc59b822da GIT binary patch literal 2153 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 literal 0 HcmV?d00001 diff --git a/resources/textures/icons/play.png b/resources/textures/icons/play.png index 274b12ad7df072565455f6728fe37f60d1034c9a..f9058d9c363453afbfb247d9ad6f2426dacde475 100644 GIT binary patch literal 2784 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 Ar~m)} From 282eeeabda29d062d0c51f0e1e3eb5d254b8e014 Mon Sep 17 00:00:00 2001 From: Erris Date: Tue, 3 Mar 2026 09:38:52 +0100 Subject: [PATCH 2/8] fixed unselecting entity when cursor goes from ImGui to viewport while click is held --- editor/include/editor.hpp | 5 +---- editor/src/editor_component.cpp | 15 +++++---------- .../include/open_engine/imgui/imgui_layer.hpp | 1 + .../include/open_engine/input/input_system.hpp | 1 - 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/editor/include/editor.hpp b/editor/include/editor.hpp index 982ce97..fc809c8 100755 --- a/editor/include/editor.hpp +++ b/editor/include/editor.hpp @@ -3,9 +3,6 @@ #include -#include "open_engine/renderer/renderer3d.hpp" -#include "open_engine/scene/components.hpp" -#include "open_engine/scene/scene_serializer.hpp" #include "panels/content_browser.hpp" #include "panels/scene_hierarchy.hpp" @@ -181,7 +178,6 @@ namespace OpenEngine { RenderCommand::Clear(); framebuffer->ClearBufferI(1, -1); - switch (state) { case PlayState::Play: { scene->OnUpdateRuntime(); @@ -208,6 +204,7 @@ namespace OpenEngine { static bool clicked = false; // Mouse Picking if (Input::IsMouseButtonPressed(MouseCode::ButtonLeft) + && !Application::Get().GetImGuiLayer()->GetBlockEvents() && mouse_x >= 0 && mouse_y >= 0 && mouse_x < (int)viewport_size.x && mouse_y < (int)viewport_size.y diff --git a/editor/src/editor_component.cpp b/editor/src/editor_component.cpp index 68de901..0c33a67 100644 --- a/editor/src/editor_component.cpp +++ b/editor/src/editor_component.cpp @@ -227,15 +227,10 @@ namespace OpenEngine { auto& ambient = material.ambient_strength; auto& specular = material.specular_strength; - if (ImGui::SliderFloat4("Albedo", glm::value_ptr(albedo), 0, 1)) - material.albedo = albedo; - if (ImGui::SliderFloat("Roughness", &roughness, 0, 1)) - material.roughness = roughness; - if (ImGui::SliderFloat("Metallic", &metallic, 0, 1)) - material.metallic = metallic; - if (ImGui::SliderFloat("Ambient strength", &ambient, 0, 1)) - material.ambient_strength = ambient; - if (ImGui::SliderFloat("Specular strength", &specular, 0, 10)) - material.specular_strength = specular; + ImGui::SliderFloat4("Albedo", glm::value_ptr(albedo), 0, 1); + ImGui::SliderFloat("Roughness", &roughness, 0, 1); + ImGui::SliderFloat("Metallic", &metallic, 0, 1); + ImGui::SliderFloat("Ambient strength", &ambient, 0, 1); + ImGui::SliderFloat("Specular strength", &specular, 0, 10); } } diff --git a/open_engine/include/open_engine/imgui/imgui_layer.hpp b/open_engine/include/open_engine/imgui/imgui_layer.hpp index 176c5b1..4cab138 100644 --- a/open_engine/include/open_engine/imgui/imgui_layer.hpp +++ b/open_engine/include/open_engine/imgui/imgui_layer.hpp @@ -19,6 +19,7 @@ namespace OpenEngine { bool CloseWindow(OpenEngine::KeyPressedEvent& event); void SetBlockEvents(bool block) { block_events = block; }; + bool GetBlockEvents() { return block_events; }; void Begin(); void End(); diff --git a/open_engine/include/open_engine/input/input_system.hpp b/open_engine/include/open_engine/input/input_system.hpp index 8adcb45..65d5b33 100644 --- a/open_engine/include/open_engine/input/input_system.hpp +++ b/open_engine/include/open_engine/input/input_system.hpp @@ -2,7 +2,6 @@ #define INPUT_HPP #include "open_engine/input/mouse_codes.hpp" -#include "open_engine/ref_scope.hpp" #include "open_engine/input/keycodes.hpp" #include From eaef554b10399e56ed698b46b18be24de83d2634 Mon Sep 17 00:00:00 2001 From: Erris Date: Wed, 4 Mar 2026 10:19:46 +0100 Subject: [PATCH 3/8] Adding basic impl of Jolt Update positions on 60tps, position of objects can be modified while physic simulation is running. Position is owned by transform comps but the truth is held by the physics engine for affected entities --- editor/include/editor.hpp | 20 +- editor/include/editor_component.hpp | 2 + editor/src/editor_component.cpp | 32 ++- editor/src/panels/scene_hierarchy.cpp | 29 ++- imgui.ini | 20 +- open_engine/include/open_engine/physics.hpp | 188 ++++++++++++++++++ .../include/open_engine/scene/components.hpp | 33 +++ .../include/open_engine/scene/scene.hpp | 14 +- open_engine/src/open_engine/physics.cpp | 71 +++++++ open_engine/src/open_engine/scene/scene.cpp | 136 ++++++++++++- .../open_engine/scene/scene_serializer.cpp | 16 +- untitled_persp.oes | 47 ----- 12 files changed, 518 insertions(+), 90 deletions(-) create mode 100644 open_engine/include/open_engine/physics.hpp create mode 100644 open_engine/src/open_engine/physics.cpp mode change 100644 => 100755 open_engine/src/open_engine/scene/scene.cpp delete mode 100644 untitled_persp.oes diff --git a/editor/include/editor.hpp b/editor/include/editor.hpp index fc809c8..e054478 100755 --- a/editor/include/editor.hpp +++ b/editor/include/editor.hpp @@ -3,9 +3,15 @@ #include +#include "open_engine/renderer/renderer3d.hpp" +#include "open_engine/scene/components.hpp" #include "panels/content_browser.hpp" #include "panels/scene_hierarchy.hpp" +#include +#include +#include +#include #include #include #include @@ -95,12 +101,12 @@ namespace OpenEngine { // ============================================= Entity cube = scene->CreateEntity("cube"); - - cube.AddComponent(); + auto& tc = cube.AddComponent(); Ref mesh = CreateCube(cube); - cube.AddComponent(mesh); + auto& mc = cube.AddComponent(mesh); + mc.primitive_type = PrimitiveType::Cube; // ============================================= Entity quad = scene->CreateEntity("quad"); @@ -109,7 +115,8 @@ namespace OpenEngine { Ref quad_mesh = CreateQuad(quad, true); - quad.AddComponent(quad_mesh); + auto& mc3 = quad.AddComponent(quad_mesh); + mc3.primitive_type = PrimitiveType::Quad; // ============================================= Entity cube2 = scene->CreateEntity("cube2"); @@ -118,7 +125,8 @@ namespace OpenEngine { Ref mesh2 = CreateCube(cube2); - cube2.AddComponent(mesh2); + auto& mc2 = cube2.AddComponent(mesh2); + mc2.primitive_type = PrimitiveType::Cube; /* auto view = scene->GetRegistry().view(); @@ -562,10 +570,12 @@ namespace OpenEngine { void OnScenePlay() { state = PlayState::Play; + scene->OnRuntimeStart(); } void OnSceneStop() { state = PlayState::Edit; + scene->OnRuntimeStop(); } private: diff --git a/editor/include/editor_component.hpp b/editor/include/editor_component.hpp index c9fd455..5630dfc 100644 --- a/editor/include/editor_component.hpp +++ b/editor/include/editor_component.hpp @@ -18,6 +18,8 @@ namespace OpenEngine { void CameraOnImGuiRender(entt::registry& registry, entt::entity entity); void MeshOnImGuiRender(entt::registry®istry, entt::entity entity); void MaterialOnImGuiRender(entt::registry& registry, entt::entity entity); + void BodyOnImGuiRender(entt::registry& registry, entt::entity entity); + void ShapeOnImGuiRender(entt::registry& registry, entt::entity entity); } #endif // EDITOR_COMPONENT_HPP diff --git a/editor/src/editor_component.cpp b/editor/src/editor_component.cpp index 0c33a67..6b1d445 100644 --- a/editor/src/editor_component.cpp +++ b/editor/src/editor_component.cpp @@ -95,6 +95,7 @@ namespace OpenEngine { if (ImGui::InputText("##tagEditor", buffer, sizeof(buffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll) || (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0))) tag = buffer; + ImGui::Spacing(); }; void TransformOnImGuiRender(entt::registry& registry, entt::entity entity) @@ -221,16 +222,27 @@ namespace OpenEngine { { auto& material = registry.get(entity).material; - auto& albedo = material.albedo; - auto& roughness = material.roughness; - auto& metallic = material.metallic; - auto& ambient = material.ambient_strength; - auto& specular = material.specular_strength; + ImGui::SliderFloat4("Albedo", glm::value_ptr(material.albedo), 0, 1); + ImGui::SliderFloat("Roughness", &material.roughness, 0, 1); + ImGui::SliderFloat("Metallic", &material.metallic, 0, 1); + ImGui::SliderFloat("Ambient strength", &material.ambient_strength, 0, 1); + ImGui::SliderFloat("Specular strength", &material.specular_strength, 0, 10); + } - ImGui::SliderFloat4("Albedo", glm::value_ptr(albedo), 0, 1); - ImGui::SliderFloat("Roughness", &roughness, 0, 1); - ImGui::SliderFloat("Metallic", &metallic, 0, 1); - ImGui::SliderFloat("Ambient strength", &ambient, 0, 1); - ImGui::SliderFloat("Specular strength", &specular, 0, 10); + void BodyOnImGuiRender(entt::registry ®istry, entt::entity entity) + { + auto& body_comp = registry.get(entity); + + ImGui::SliderFloat("Linear damping", &body_comp.linear_damping, 0, 1); + ImGui::SliderFloat("Angular damping", &body_comp.angular_damping, 0, 1); + ImGui::SliderFloat("Gravity factor", &body_comp.gravity_factor, 0, 1); + } + + void ShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) + { + auto& shape_comp = registry.get(entity); + + ImGui::SliderFloat("Bounciness", &shape_comp.restitution, 0, 1); + ImGui::SliderFloat("Friction", &shape_comp.friction, 0, 1); } } diff --git a/editor/src/panels/scene_hierarchy.cpp b/editor/src/panels/scene_hierarchy.cpp index 0c716ad..8b7e41c 100644 --- a/editor/src/panels/scene_hierarchy.cpp +++ b/editor/src/panels/scene_hierarchy.cpp @@ -24,6 +24,8 @@ namespace OpenEngine { RegisterDrawer("Camera", &CameraOnImGuiRender); RegisterDrawer("Mesh", &MeshOnImGuiRender); RegisterDrawer("Material", &MaterialOnImGuiRender); + RegisterDrawer("Physics Body", &BodyOnImGuiRender); + RegisterDrawer("Physics Shape", &ShapeOnImGuiRender); scene = context; selected_context = {}; @@ -57,6 +59,16 @@ namespace OpenEngine { selected_context.AddComponent(); ImGui::CloseCurrentPopup(); } + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Physics body")) { + selected_context.AddComponent(); + ImGui::CloseCurrentPopup(); + } + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Physics shape")) { + selected_context.AddComponent(); + ImGui::CloseCurrentPopup(); + } } void EntityPopup(Ref& scene) @@ -201,17 +213,18 @@ namespace OpenEngine { void SceneHierarchy::DrawComponents(Entity& entity) { auto& reg = scene->GetRegistry(); - entt::entity handle = selected_context; + entt::entity handle = entity; - if (!selected_context || !entity) + if (!entity) return; entity.GetComponents(); TagOnImGuiRender(reg, entity); + // TODO: Defer deletion like the entities? + std::vector pending_deletion; // 0 is null/invalid in entt usually - std::vector component_to_delete; // 0 is null/invalid in entt usually - // Iterate through every component type entt knows about + // Iterate through every component type entt knows about for (auto [id, storage] : reg.storage()) { if (storage.contains(handle)) { if (drawers.contains(id)) { @@ -234,20 +247,24 @@ namespace OpenEngine { if (ImGui::BeginPopup("component_settings")) { if (ImGui::MenuItem("Remove component")) - component_to_delete.emplace_back(id); + pending_deletion.emplace_back(id); ImGui::EndPopup(); } if (opened) { + ImGui::Spacing(); drawers[id].draw_func(reg, handle); + ImGui::Spacing(); ImGui::TreePop(); } } } } - for (auto& id : component_to_delete) + for (auto& id : pending_deletion) { drawers[id].remove_func(reg, entity); + pending_deletion.clear(); + } } } diff --git a/imgui.ini b/imgui.ini index 7fa393d..1e264a3 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][WindowOverViewport_11111111] Pos=0,24 -Size=1272,1363 +Size=2552,1363 Collapsed=0 [Window][Debug##Default] @@ -15,19 +15,19 @@ Collapsed=0 DockId=0x00000003,0 [Window][Properties] -Pos=822,24 +Pos=2102,24 Size=450,805 Collapsed=0 DockId=0x00000007,0 [Window][Viewport] Pos=226,61 -Size=594,956 +Size=1874,956 Collapsed=0 DockId=0x00000012,0 [Window][Dear ImGui Demo] -Pos=822,831 +Pos=2102,831 Size=450,556 Collapsed=0 DockId=0x00000008,0 @@ -144,7 +144,7 @@ DockId=0x00000012,1 [Window][Assets] Pos=226,1019 -Size=594,368 +Size=1874,368 Collapsed=0 DockId=0x0000000C,0 @@ -156,12 +156,12 @@ DockId=0x0000000F,0 [Window][##play_state_bar] Pos=226,24 -Size=594,35 +Size=1874,35 Collapsed=0 DockId=0x00000011,0 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=1272,1363 Split=X +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=2552,1363 Split=X DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=820,1386 Split=X DockNode ID=0x00000001 Parent=0x00000005 SizeRef=224,1386 Split=Y Selected=0xE601B12F DockNode ID=0x00000003 Parent=0x00000001 SizeRef=255,417 Selected=0x553E127E @@ -173,11 +173,11 @@ DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=1272,1363 DockNode ID=0x0000000F Parent=0x0000000D SizeRef=594,60 Selected=0x8325EBDA DockNode ID=0x00000010 Parent=0x0000000D SizeRef=594,931 Split=Y Selected=0xC450F867 DockNode ID=0x00000011 Parent=0x00000010 SizeRef=594,35 HiddenTabBar=1 Selected=0xAB37695D - DockNode ID=0x00000012 Parent=0x00000010 SizeRef=594,956 CentralNode=1 Selected=0xC450F867 + DockNode ID=0x00000012 Parent=0x00000010 SizeRef=594,964 CentralNode=1 Selected=0xC450F867 DockNode ID=0x0000000E Parent=0x0000000B SizeRef=800,993 Selected=0x3EEA4247 DockNode ID=0x0000000C Parent=0x00000009 SizeRef=409,368 Selected=0x42C24103 DockNode ID=0x0000000A Parent=0x00000002 SizeRef=483,600 Selected=0x1BCA3180 DockNode ID=0x00000006 Parent=0x08BD597D SizeRef=450,1386 Split=Y Selected=0x8C72BEA8 - DockNode ID=0x00000007 Parent=0x00000006 SizeRef=444,769 Selected=0x8C72BEA8 - DockNode ID=0x00000008 Parent=0x00000006 SizeRef=444,531 Selected=0x5E5F7166 + DockNode ID=0x00000007 Parent=0x00000006 SizeRef=444,810 Selected=0x8C72BEA8 + DockNode ID=0x00000008 Parent=0x00000006 SizeRef=444,559 Selected=0x5E5F7166 diff --git a/open_engine/include/open_engine/physics.hpp b/open_engine/include/open_engine/physics.hpp new file mode 100644 index 0000000..317d918 --- /dev/null +++ b/open_engine/include/open_engine/physics.hpp @@ -0,0 +1,188 @@ +#ifndef PHYSICS_HPP +#define PHYSICS_HPP + +#include "logging.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace JPH; +using namespace JPH::literals; + +// Callback for traces, connect this to your own trace function if you have one +static void TraceImpl(const char *in_fmt, ...) +{ + // Format the message + va_list list; + va_start(list, in_fmt); + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), in_fmt, list); + va_end(list); + + OE_CORE_TRACE("Jolt: {}", buffer); +} + +#ifdef JPH_ENABLE_ASSERTS +// Callback for asserts, connect this to your own assert handler if you have one +static bool AssertFailedImpl(const char *in_expression, const char *in_message, const char *in_file, uint in_line) +{ + OE_CORE_ERROR("Jolt: Assert in file: {}:{} :({}) {}", in_file, in_line, in_expression, (in_message != nullptr? in_message : "")); + + // Breakpoint + return true; +}; +#endif // JPH_ENABLE_ASSERTS + +// Layer that objects can be in, determines which other objects it can collide with +// Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more +// layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation +// but only if you do collision testing). +namespace Layers { + static constexpr ObjectLayer NON_MOVING = 0; + static constexpr ObjectLayer MOVING = 1; + static constexpr ObjectLayer NUM_LAYERS = 2; +}; + +class ObjectLayerPairFilterImpl : public ObjectLayerPairFilter +{ + public: + virtual bool ShouldCollide(ObjectLayer object1, ObjectLayer object2) const override; +}; + +// Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have +// a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame. +// You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have +// many object layers you'll be creating many broad phase trees, which is not efficient. If you want to fine tune +// your broadphase layers define JPH_TRACK_BROADPHASE_STATS and look at the stats reported on the TTY. +namespace BroadPhaseLayers +{ + static constexpr BroadPhaseLayer NON_MOVING(0); + static constexpr BroadPhaseLayer MOVING(1); + static constexpr uint NUM_LAYERS(2); +}; + +class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface +{ + public: + BPLayerInterfaceImpl() + { + object_to_broad_phase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING; + object_to_broad_phase[Layers::MOVING] = BroadPhaseLayers::MOVING; + } + + virtual uint GetNumBroadPhaseLayers() const override { return BroadPhaseLayers::NUM_LAYERS; }; + + virtual BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer layer) const override + { + JPH_ASSERT(layer < Layers::NUM_LAYERS); + return object_to_broad_phase[layer]; + } + + private: + BroadPhaseLayer object_to_broad_phase[Layers::NUM_LAYERS]; +}; + +class ObjectVsBroadPhaseLayerFilterImpl : public ObjectVsBroadPhaseLayerFilter +{ + public: + virtual bool ShouldCollide(ObjectLayer layer1, BroadPhaseLayer layer2) const override + { + switch (layer1) + { + case Layers::NON_MOVING: + return layer2 == BroadPhaseLayers::MOVING; + case Layers::MOVING: + return true; + default: + JPH_ASSERT(false); + return false; + } + } +}; + +// An example contact listener +class MyContactListener : public ContactListener +{ +public: + // See: ContactListener + virtual ValidateResult OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override + { + OE_CORE_TRACE("Jolt: Contact validate callback"); + + // Allows you to ignore a contact before it is created (using layers to not make objects collide is cheaper!) + return ValidateResult::AcceptAllContactsForThisBodyPair; + } + + virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override + { + OE_CORE_TRACE("Jolt: A contact was added"); + } + + virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override + { + OE_CORE_TRACE("Jolt: A contact was persisted"); + } + + virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override + { + OE_CORE_TRACE("Jolt: A contact was removed"); + } +}; + +// An example activation listener +class MyBodyActivationListener : public BodyActivationListener +{ +public: + virtual void OnBodyActivated(const BodyID &inBodyID, uint64 inBodyUserData) override + { + OE_CORE_TRACE("Jolt: A body got activated"); + } + + virtual void OnBodyDeactivated(const BodyID &inBodyID, uint64 inBodyUserData) override + { + OE_CORE_TRACE("Jolt: A body went to sleep"); + } +}; + +namespace OpenEngine { + + // Consider making this static like the renderer + class PhysicsEngine + { + public: + PhysicsEngine(); + ~PhysicsEngine(); + + // TODO: Temp, make abstract function to create a body + BodyInterface& GetBodyInterface() { return physics_system.GetBodyInterface(); }; + void Update( float delta_time, int collision_steps); + + private: + PhysicsSystem physics_system; + + Ref tmp_allocator; + Ref job_system; + + MyBodyActivationListener body_activation_listener; + MyContactListener contact_listener; + + BPLayerInterfaceImpl broad_phase_layer_interface; + ObjectVsBroadPhaseLayerFilterImpl object_vs_broadphase_layer_filter; + ObjectLayerPairFilterImpl object_vs_object_layer_filter; + + }; +} + +#endif // PHYSICS_HPP diff --git a/open_engine/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index aae8457..a896b12 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -6,7 +6,14 @@ #include "open_engine/scene/scene_camera.hpp" #include "open_engine/renderer/texture.hpp" #include "open_engine/renderer/renderer3d.hpp" +#include "open_engine/physics.hpp" +#include +#include +#include +#include +#include +#include #include #include #include @@ -110,6 +117,32 @@ namespace OpenEngine { : material(material) {}; }; + struct PhysicsBodyComponent + { + enum class BodyType { Static = 0, Kinematic, Dynamic }; + + BodyID body; + + BodyType type = BodyType::Dynamic; + + float linear_damping = 0.05f; + float angular_damping = 0.05f; + float gravity_factor = 1.0f; + + EActivation initial_activation_state = EActivation::Activate; + + PhysicsBodyComponent() = default; + PhysicsBodyComponent(const PhysicsBodyComponent&) = default; + }; + + struct PhysicsShapeComponent + { + ShapeRefC shape; + + float restitution = 0.8f; + float friction = 0.5f; + }; + } #endif // COMPONENTS_HPP diff --git a/open_engine/include/open_engine/scene/scene.hpp b/open_engine/include/open_engine/scene/scene.hpp index a4cb2cc..91dd480 100644 --- a/open_engine/include/open_engine/scene/scene.hpp +++ b/open_engine/include/open_engine/scene/scene.hpp @@ -2,7 +2,9 @@ #define SCENE_HPP #include "open_engine/renderer/editor_camera.hpp" +#include "open_engine/physics.hpp" +#include #include #include #include @@ -17,6 +19,9 @@ namespace OpenEngine { Scene() = default; ~Scene() = default; + void OnRuntimeStart(); + void OnRuntimeStop(); + Entity CreateEntity(const std::string& name = std::string()); void DeleteEntity(entt::entity entity); void MarkEntityForDeletion(Entity entity); @@ -28,20 +33,27 @@ namespace OpenEngine { void OnViewportResize(uint32_t width, uint32_t height); entt::registry& GetRegistry() { return registry; }; - + PhysicsEngine& GetPhysicsEngine() { return physics_engine; }; Entity GetPrimaryCamera(); private: + void OnUpdatePhysics(); + template void OnComponentAdded(Entity entity, T& component); private: entt::registry registry; + PhysicsEngine physics_engine; + + BodyInterface* body_interface; uint32_t viewport_width = 0, viewport_height = 0; std::vector pending_deletion; + //BodyID sphere_id; + friend class SceneSerializer; friend class Entity; }; diff --git a/open_engine/src/open_engine/physics.cpp b/open_engine/src/open_engine/physics.cpp new file mode 100644 index 0000000..7fde043 --- /dev/null +++ b/open_engine/src/open_engine/physics.cpp @@ -0,0 +1,71 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include + +bool ObjectLayerPairFilterImpl::ShouldCollide(ObjectLayer object1, ObjectLayer object2) const +{ + switch (object1) + { + case Layers::NON_MOVING: + return object2 == Layers::MOVING; // Non moving only collides with moving + case Layers::MOVING: + return true; // Moving collides with everything + default: + JPH_ASSERT(false); + return false; + } +} + +namespace OpenEngine { + + PhysicsEngine::PhysicsEngine() + { + RegisterDefaultAllocator(); + + Trace = TraceImpl; + JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl); + + Factory::sInstance = new Factory(); + + RegisterTypes(); + + tmp_allocator = CreateRef(10 * 1024 * 1024); + + job_system = CreateRef(cMaxPhysicsJobs, cMaxPhysicsBarriers, thread::hardware_concurrency() - 1); + + physics_system.Init( + 1024, + 0, + 1024, + 1024, + broad_phase_layer_interface, + object_vs_broadphase_layer_filter, + object_vs_object_layer_filter); + + physics_system.SetBodyActivationListener(&body_activation_listener); + physics_system.SetContactListener(&contact_listener); + + // TODO: Move out of here and check the comment on Jolt's example + physics_system.OptimizeBroadPhase(); + } + + PhysicsEngine::~PhysicsEngine() { + UnregisterTypes(); + + // Destroy the factory + delete Factory::sInstance; + Factory::sInstance = nullptr; + }; + + void PhysicsEngine::Update(float delta_time, int collision_steps) + { + physics_system.Update(delta_time, collision_steps, &*tmp_allocator, &*job_system); + } +} diff --git a/open_engine/src/open_engine/scene/scene.cpp b/open_engine/src/open_engine/scene/scene.cpp old mode 100644 new mode 100755 index 5fe217d..626b18d --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -1,14 +1,85 @@ -#include -#include +#include "logging.hpp" #include #include #include #include #include +#include + +#include +#include +#include +#include +#include +#include namespace OpenEngine { + void Scene::OnRuntimeStart() + { + body_interface = &physics_engine.GetBodyInterface(); + + BoxShapeSettings floor_shape_settings(Vec3(100.0f, 1.0f, 100.0f)); + floor_shape_settings.SetEmbedded(); // A ref counted object on the stack (base class RefTarget) should be marked as such to prevent it from being freed when its reference count goes to 0. + + // Create the shape + ShapeSettings::ShapeResult floor_shape_result = floor_shape_settings.Create(); + ShapeRefC floor_shape = floor_shape_result.Get(); // We don't expect an error here, but you can check floor_shape_result for HasError() / GetError() + + // Create the settings for the body itself. Note that here you can also set other properties like the restitution / friction. + BodyCreationSettings floor_settings(floor_shape, RVec3(0.0_r, -1.0_r, 0.0_r), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING); + + // Create the actual rigid body + Body *floor = body_interface->CreateBody(floor_settings); // Note that if we run out of bodies this can return nullptr + + // Add it to the world + body_interface->AddBody(floor->GetID(), EActivation::DontActivate); + + auto view = registry.view(); + for (auto e : view) { + Entity entity = { e, this }; + + TransformComponent* tc; + if (entity.HasComponent()) + tc = &entity.GetComponents(); + auto& pbc = entity.GetComponents(); + + PhysicsShapeComponent* psc; + if (entity.HasComponent()) + psc = &entity.GetComponents(); + + glm::vec3& pos = tc->translation; + BodyCreationSettings settings( + new BoxShape(Vec3(0.5f, 0.5f, 0.5f)), + Vec3(pos.x, pos.y, pos.z), + Quat::sIdentity(), + EMotionType::Dynamic, + Layers::MOVING); + settings.mLinearDamping = pbc.linear_damping; + settings.mAngularDamping = pbc.angular_damping; + settings.mGravityFactor = pbc.gravity_factor; + + settings.mRestitution = psc->restitution; + settings.mFriction = psc->friction; + + pbc.body = body_interface->CreateAndAddBody(settings, EActivation::Activate); + } + } + + void Scene::OnRuntimeStop() + { + auto view = registry.view(); + for (auto e : view) { + Entity entity = { e, this }; + + auto& pbc = entity.GetComponents(); + + physics_engine.GetBodyInterface().RemoveBody(pbc.body); + physics_engine.GetBodyInterface().DestroyBody(pbc.body); + } + } + Entity Scene::CreateEntity(const std::string& name) { Entity entity = { registry.create(), this }; @@ -37,6 +108,22 @@ namespace OpenEngine { pending_deletion.clear(); } + void Scene::OnUpdatePhysics() + { + static int step = 0; + static float accumulator = 0.0f; + static const float fixedDT = 1.0f / 60.0f; + + float real_delta_time = Time::DeltaTime(); // e.g. from a timer + accumulator += real_delta_time; + + if (accumulator >= fixedDT) { + step++; + physics_engine.Update(fixedDT, 1); + accumulator -= fixedDT; + } + } + void Scene::OnUpdateRuntime() { { @@ -54,6 +141,40 @@ namespace OpenEngine { }); } + auto view = registry.view(); + for (auto e : view) { + Entity entity = { e, this }; + + auto& pos = entity.GetComponents().translation; + auto& body = entity.GetComponents(); + + body_interface->SetPosition(body.body, { pos.x, pos.y, pos.z }, EActivation::Activate); + + PhysicsShapeComponent* shape; + if (entity.HasComponent()) { + shape = &entity.GetComponents(); + + body_interface->SetRestitution(body.body, shape->restitution); + body_interface->SetFriction(body.body, shape->friction); + body_interface->SetGravityFactor(body.body, body.gravity_factor); + } + + } + + OnUpdatePhysics(); + + for (auto e : view) { + Entity entity = { e, this }; + + auto& transform = entity.GetComponents(); + auto& body = entity.GetComponents(); + + auto position = physics_engine.GetBodyInterface().GetPosition(body.body); + transform.translation.x = position.GetX(); + transform.translation.y = position.GetY(); + transform.translation.z = position.GetZ(); + } + SceneCamera* main_camera = nullptr; glm::mat4 main_transform{ 1.0f }; { @@ -75,6 +196,7 @@ namespace OpenEngine { for (const auto& entity : view) { auto [transform, mesh] = view.get(entity); + Material material; Entity _entity(entity, this); @@ -186,4 +308,14 @@ namespace OpenEngine { void Scene::OnComponentAdded(Entity entity, MaterialComponent& component) { } + + template<> + void Scene::OnComponentAdded(Entity entity, PhysicsBodyComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, PhysicsShapeComponent& component) + { + } } diff --git a/open_engine/src/open_engine/scene/scene_serializer.cpp b/open_engine/src/open_engine/scene/scene_serializer.cpp index 26600b5..c217544 100644 --- a/open_engine/src/open_engine/scene/scene_serializer.cpp +++ b/open_engine/src/open_engine/scene/scene_serializer.cpp @@ -274,19 +274,20 @@ namespace OpenEngine { if (mesh_component) { auto& mesh = deserializedEntity.AddComponent(); + mesh.primitive_type = (PrimitiveType)mesh_component["MeshType"].as(); switch (mesh.primitive_type) { - case OpenEngine::PrimitiveType::Quad: - { + case OpenEngine::PrimitiveType::Quad: { mesh.mesh = CreateQuad((uint32_t)deserializedEntity); break; } - case OpenEngine::PrimitiveType::Cube: - { + case OpenEngine::PrimitiveType::Cube: { mesh.mesh = CreateCube((uint32_t)deserializedEntity); break; } - default: - break; + default: { + OE_CORE_ASSERT(false, "No mesh"); + break; + } } } @@ -300,9 +301,6 @@ namespace OpenEngine { material.material.ambient_strength = material_component["AmbiantStrength"].as(); material.material.specular_strength = material_component["SpecularStrength"].as(); } - - auto mesh = CreateCube((uint32_t)deserializedEntity); - deserializedEntity.AddComponent(mesh); } } diff --git a/untitled_persp.oes b/untitled_persp.oes deleted file mode 100644 index 9532713..0000000 --- a/untitled_persp.oes +++ /dev/null @@ -1,47 +0,0 @@ -Scene: N/A -Entities: - - Entity: 412741205 - TagComponent: - Tag: square 3 - TransformComponent: - Translation: [-1.49011612e-08, 0.299999774, -0.499999911] - Rotation: [-1.57079685, 0, 0] - Scale: [0.605000019, 0.60496217, 0.60496217] - SpriteRendererComponent: - Color: [1, 1, 1, 1] - - Entity: 412741205 - TagComponent: - Tag: "square 2 " - TransformComponent: - Translation: [0, 0, -0.200000003] - Rotation: [0, 0, 0] - Scale: [0.600000024, 0.600000083, 0.600000024] - SpriteRendererComponent: - Color: [0.882352948, 0.745098054, 0.376470596, 1] - - Entity: 412741205 - TagComponent: - Tag: square - TransformComponent: - Translation: [0.299827427, -9.68575478e-08, -0.499896437] - Rotation: [0, 1.57079637, 0] - Scale: [0.6049999, 0.604999959, 0.6049999] - SpriteRendererComponent: - Color: [0.517647088, 0.0901960805, 1, 1] - - Entity: 412741205 - TagComponent: - Tag: camera - TransformComponent: - Translation: [0, 0, 20.8999996] - Rotation: [0, 0, 0] - Scale: [1, 1, 1] - CameraComponent: - Camera: - ProjectionType: 0 - PerspectiveFOV: 45 - PerspectiveNear: 0.00999999978 - PerspectiveFar: 1000 - OrthographicSize: 10 - OrthographicNear: -1 - OrthographicFar: 1 - Primary: true - FixedAspectRatio: false \ No newline at end of file From f45091349e9a2a83bd80a3587bcf51d563570fc5 Mon Sep 17 00:00:00 2001 From: Erris Date: Wed, 4 Mar 2026 11:18:16 +0100 Subject: [PATCH 4/8] added rotation --- imgui.ini | 26 ++++---- .../include/open_engine/scene/components.hpp | 6 +- open_engine/src/open_engine/physics.cpp | 10 +-- open_engine/src/open_engine/scene/scene.cpp | 61 +++++++++++-------- 4 files changed, 58 insertions(+), 45 deletions(-) diff --git a/imgui.ini b/imgui.ini index 1e264a3..a2c5d73 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][WindowOverViewport_11111111] Pos=0,24 -Size=2552,1363 +Size=2560,1371 Collapsed=0 [Window][Debug##Default] @@ -10,31 +10,31 @@ Collapsed=0 [Window][Statistics] Pos=0,24 -Size=224,437 +Size=224,439 Collapsed=0 DockId=0x00000003,0 [Window][Properties] -Pos=2102,24 -Size=450,805 +Pos=2110,24 +Size=450,810 Collapsed=0 DockId=0x00000007,0 [Window][Viewport] Pos=226,61 -Size=1874,956 +Size=1882,964 Collapsed=0 DockId=0x00000012,0 [Window][Dear ImGui Demo] -Pos=2102,831 -Size=450,556 +Pos=2110,836 +Size=450,559 Collapsed=0 DockId=0x00000008,0 [Window][Scene] -Pos=0,463 -Size=224,924 +Pos=0,465 +Size=224,930 Collapsed=0 DockId=0x00000004,0 @@ -143,8 +143,8 @@ Collapsed=0 DockId=0x00000012,1 [Window][Assets] -Pos=226,1019 -Size=1874,368 +Pos=226,1027 +Size=1882,368 Collapsed=0 DockId=0x0000000C,0 @@ -156,12 +156,12 @@ DockId=0x0000000F,0 [Window][##play_state_bar] Pos=226,24 -Size=1874,35 +Size=1882,35 Collapsed=0 DockId=0x00000011,0 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=2552,1363 Split=X +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=2560,1371 Split=X DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=820,1386 Split=X DockNode ID=0x00000001 Parent=0x00000005 SizeRef=224,1386 Split=Y Selected=0xE601B12F DockNode ID=0x00000003 Parent=0x00000001 SizeRef=255,417 Selected=0x553E127E diff --git a/open_engine/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index a896b12..c99dbe9 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -119,17 +119,15 @@ namespace OpenEngine { struct PhysicsBodyComponent { - enum class BodyType { Static = 0, Kinematic, Dynamic }; - BodyID body; - BodyType type = BodyType::Dynamic; - float linear_damping = 0.05f; float angular_damping = 0.05f; float gravity_factor = 1.0f; + EMotionType type = EMotionType::Dynamic; EActivation initial_activation_state = EActivation::Activate; + ObjectLayer layer = Layers::MOVING; PhysicsBodyComponent() = default; PhysicsBodyComponent(const PhysicsBodyComponent&) = default; diff --git a/open_engine/src/open_engine/physics.cpp b/open_engine/src/open_engine/physics.cpp index 7fde043..c3de441 100644 --- a/open_engine/src/open_engine/physics.cpp +++ b/open_engine/src/open_engine/physics.cpp @@ -38,7 +38,9 @@ namespace OpenEngine { tmp_allocator = CreateRef(10 * 1024 * 1024); - job_system = CreateRef(cMaxPhysicsJobs, cMaxPhysicsBarriers, thread::hardware_concurrency() - 1); + job_system = CreateRef(cMaxPhysicsJobs, + cMaxPhysicsBarriers, + thread::hardware_concurrency() - 1); physics_system.Init( 1024, @@ -49,10 +51,10 @@ namespace OpenEngine { object_vs_broadphase_layer_filter, object_vs_object_layer_filter); - physics_system.SetBodyActivationListener(&body_activation_listener); - physics_system.SetContactListener(&contact_listener); + //physics_system.SetBodyActivationListener(&body_activation_listener); + //physics_system.SetContactListener(&contact_listener); - // TODO: Move out of here and check the comment on Jolt's example + // TODO: Check the comment on Jolt's example physics_system.OptimizeBroadPhase(); } diff --git a/open_engine/src/open_engine/scene/scene.cpp b/open_engine/src/open_engine/scene/scene.cpp index 626b18d..07d26d0 100755 --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -36,34 +37,40 @@ namespace OpenEngine { // Add it to the world body_interface->AddBody(floor->GetID(), EActivation::DontActivate); - auto view = registry.view(); + // TODO: Cleanup components aquisition + auto view = registry.view(); for (auto e : view) { Entity entity = { e, this }; - TransformComponent* tc; - if (entity.HasComponent()) - tc = &entity.GetComponents(); auto& pbc = entity.GetComponents(); + auto& tc = entity.GetComponents(); - PhysicsShapeComponent* psc; + PhysicsShapeComponent* psc = nullptr; if (entity.HasComponent()) psc = &entity.GetComponents(); + + glm::vec3& pos = tc.translation; + glm::vec3& scale = tc.scale; + glm::vec3& rot = tc.rotation; - glm::vec3& pos = tc->translation; + Quat quat = Quat::sEulerAngles(Vec3(rot.x, rot.y, rot.z)); BodyCreationSettings settings( - new BoxShape(Vec3(0.5f, 0.5f, 0.5f)), + new BoxShape(Vec3(scale.x * 0.5, scale.y * 0.5f, scale.z * 0.5f)), Vec3(pos.x, pos.y, pos.z), - Quat::sIdentity(), - EMotionType::Dynamic, - Layers::MOVING); + quat, + pbc.type, + pbc.layer); + settings.mLinearDamping = pbc.linear_damping; settings.mAngularDamping = pbc.angular_damping; settings.mGravityFactor = pbc.gravity_factor; - settings.mRestitution = psc->restitution; - settings.mFriction = psc->friction; + if (psc != nullptr) { + settings.mRestitution = psc->restitution; + settings.mFriction = psc->friction; + } - pbc.body = body_interface->CreateAndAddBody(settings, EActivation::Activate); + pbc.body = body_interface->CreateAndAddBody(settings, pbc.initial_activation_state); } } @@ -75,8 +82,8 @@ namespace OpenEngine { auto& pbc = entity.GetComponents(); - physics_engine.GetBodyInterface().RemoveBody(pbc.body); - physics_engine.GetBodyInterface().DestroyBody(pbc.body); + body_interface->RemoveBody(pbc.body); + body_interface->DestroyBody(pbc.body); } } @@ -156,7 +163,6 @@ namespace OpenEngine { body_interface->SetRestitution(body.body, shape->restitution); body_interface->SetFriction(body.body, shape->friction); - body_interface->SetGravityFactor(body.body, body.gravity_factor); } } @@ -169,10 +175,17 @@ namespace OpenEngine { auto& transform = entity.GetComponents(); auto& body = entity.GetComponents(); - auto position = physics_engine.GetBodyInterface().GetPosition(body.body); + auto position = body_interface->GetPosition(body.body); + auto rotation = body_interface->GetRotation(body.body).GetEulerAngles(); transform.translation.x = position.GetX(); transform.translation.y = position.GetY(); transform.translation.z = position.GetZ(); + + transform.rotation.x = rotation.GetX(); + transform.rotation.y = rotation.GetY(); + transform.rotation.z = rotation.GetZ(); + + body_interface->SetGravityFactor(body.body, body.gravity_factor); } SceneCamera* main_camera = nullptr; @@ -194,16 +207,16 @@ namespace OpenEngine { auto view = registry.view(); - for (const auto& entity : view) { - auto [transform, mesh] = view.get(entity); + for (const auto& e : view) { + auto [transform, mesh] = view.get(e); - Material material; + Material* material; - Entity _entity(entity, this); - if (_entity.HasComponent()) - material = _entity.GetComponents().material; + Entity entity(e, this); + if (entity.HasComponent()) + material = &entity.GetComponents().material; - Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); + Renderer3D::DrawMesh(mesh.mesh, *material, GetTransformFromComp(transform)); /* if (sprite.texture) Renderer2D::DrawQuad(GetTransformFromComp(transform), From ecf27eae7367c532e25c1e08e7fcbb654a34178d Mon Sep 17 00:00:00 2001 From: Erris Date: Thu, 5 Mar 2026 01:22:41 +0100 Subject: [PATCH 5/8] various bug fix, serialization, adding shapes --- editor/include/editor_component.hpp | 3 +- editor/src/editor_component.cpp | 86 +++++++++++----- editor/src/panels/scene_hierarchy.cpp | 14 ++- open_engine/include/open_engine/physics.hpp | 3 + .../include/open_engine/scene/components.hpp | 20 ++-- .../include/open_engine/scene/scene.hpp | 3 +- open_engine/src/open_engine/scene/scene.cpp | 99 ++++++++++--------- .../open_engine/scene/scene_serializer.cpp | 79 +++++++++++++-- 8 files changed, 215 insertions(+), 92 deletions(-) diff --git a/editor/include/editor_component.hpp b/editor/include/editor_component.hpp index 5630dfc..7a3ecc7 100644 --- a/editor/include/editor_component.hpp +++ b/editor/include/editor_component.hpp @@ -19,7 +19,8 @@ namespace OpenEngine { void MeshOnImGuiRender(entt::registry®istry, entt::entity entity); void MaterialOnImGuiRender(entt::registry& registry, entt::entity entity); void BodyOnImGuiRender(entt::registry& registry, entt::entity entity); - void ShapeOnImGuiRender(entt::registry& registry, entt::entity entity); + void SphereShapeOnImGuiRender(entt::registry& registry, entt::entity entity); + void BoxShapeOnImGuiRender(entt::registry& registry, entt::entity entity); } #endif // EDITOR_COMPONENT_HPP diff --git a/editor/src/editor_component.cpp b/editor/src/editor_component.cpp index 6b1d445..855ee08 100644 --- a/editor/src/editor_component.cpp +++ b/editor/src/editor_component.cpp @@ -1,6 +1,7 @@ #include "imgui.h" #include "open_engine/renderer/renderer3d.hpp" #include "open_engine/scene/components.hpp" +#include #include #include #include @@ -181,12 +182,11 @@ namespace OpenEngine { { auto& mesh_component = registry.get(entity); - const char* items[] = { "Quad", "Cube" }; - static int item_selected_idx = 0; + const char* items[] = { "None", "Quad", "Cube" }; + int item_selected_idx = (int)mesh_component.primitive_type; if (ImGui::BeginCombo("Mesh", items[item_selected_idx])) { - for (int n = 0; n < 2; n++) - { + for (int n = 0; n < 3; n++) { const bool is_selected = (item_selected_idx == n); if (ImGui::Selectable(items[n], is_selected)) item_selected_idx = n; @@ -196,25 +196,26 @@ namespace OpenEngine { ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); + } - if ((int)mesh_component.primitive_type == (item_selected_idx + 1)) - return; + if ((int)mesh_component.primitive_type == (item_selected_idx)) + return; - mesh_component.primitive_type = (PrimitiveType)(item_selected_idx + 1); - switch (mesh_component.primitive_type) { - case OpenEngine::PrimitiveType::Quad: - { - mesh_component.mesh = CreateQuad((uint32_t)entity); - break; - } - case OpenEngine::PrimitiveType::Cube: - { - mesh_component.mesh = CreateCube((uint32_t)entity); - break; - } - default: + mesh_component.primitive_type = (PrimitiveType)(item_selected_idx); + switch (mesh_component.primitive_type) { + case OpenEngine::PrimitiveType::Quad: + { + mesh_component.mesh = CreateQuad((uint32_t)entity); break; - } + } + case OpenEngine::PrimitiveType::Cube: + { + mesh_component.mesh = CreateCube((uint32_t)entity); + break; + } + default: + mesh_component.mesh = nullptr; + break; } } @@ -233,16 +234,53 @@ namespace OpenEngine { { auto& body_comp = registry.get(entity); + const char* items[] = { "Static", "Kinematic", "Dynamic" }; + int item_selected_idx = body_comp.type; + + if (ImGui::BeginCombo("Body type", items[item_selected_idx])) { + for (int n = 0; n < 3; n++) + { + const bool is_selected = (item_selected_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_selected_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + body_comp.type = item_selected_idx; + ImGui::SliderFloat("Linear damping", &body_comp.linear_damping, 0, 1); ImGui::SliderFloat("Angular damping", &body_comp.angular_damping, 0, 1); ImGui::SliderFloat("Gravity factor", &body_comp.gravity_factor, 0, 1); + ImGui::SliderFloat("Bounciness", &body_comp.restitution, 0, 1); + ImGui::SliderFloat("Friction", &body_comp.friction, 0, 1); } - void ShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) + void SphereShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) { - auto& shape_comp = registry.get(entity); + auto& sphere_comp = registry.get(entity); + + ImGui::DragFloat("Radius", + &sphere_comp.radius, + 0.1f, + 0.11f, FLT_MAX, + "%.2f", + ImGuiSliderFlags_AlwaysClamp); + } - ImGui::SliderFloat("Bounciness", &shape_comp.restitution, 0, 1); - ImGui::SliderFloat("Friction", &shape_comp.friction, 0, 1); + void BoxShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) + { + auto& box_comp = registry.get(entity); + + ImGui::DragFloat3("Size", + glm::value_ptr(box_comp.size), + 0.1f, + 0.11f, FLT_MAX, + "%.2f", + ImGuiSliderFlags_AlwaysClamp); } } diff --git a/editor/src/panels/scene_hierarchy.cpp b/editor/src/panels/scene_hierarchy.cpp index 8b7e41c..bdcfdc6 100644 --- a/editor/src/panels/scene_hierarchy.cpp +++ b/editor/src/panels/scene_hierarchy.cpp @@ -25,7 +25,8 @@ namespace OpenEngine { RegisterDrawer("Mesh", &MeshOnImGuiRender); RegisterDrawer("Material", &MaterialOnImGuiRender); RegisterDrawer("Physics Body", &BodyOnImGuiRender); - RegisterDrawer("Physics Shape", &ShapeOnImGuiRender); + RegisterDrawer("Sphere Shape", &SphereShapeOnImGuiRender); + RegisterDrawer("Box Shape", &BoxShapeOnImGuiRender); scene = context; selected_context = {}; @@ -64,9 +65,14 @@ namespace OpenEngine { selected_context.AddComponent(); ImGui::CloseCurrentPopup(); } - if (!selected_context.HasComponent()) - if (ImGui::MenuItem("Physics shape")) { - selected_context.AddComponent(); + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Sphere shape")) { + selected_context.AddComponent(); + ImGui::CloseCurrentPopup(); + } + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Box shape")) { + selected_context.AddComponent(); ImGui::CloseCurrentPopup(); } } diff --git a/open_engine/include/open_engine/physics.hpp b/open_engine/include/open_engine/physics.hpp index 317d918..673a5d4 100644 --- a/open_engine/include/open_engine/physics.hpp +++ b/open_engine/include/open_engine/physics.hpp @@ -17,6 +17,7 @@ #include #include +#include using namespace JPH; using namespace JPH::literals; @@ -73,6 +74,8 @@ namespace BroadPhaseLayers static constexpr uint NUM_LAYERS(2); }; +inline JPH::Vec3 ToJolt(const glm::vec3& v) { return JPH::Vec3(v.x, v.y, v.z); }; + class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface { public: diff --git a/open_engine/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index c99dbe9..9375e32 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -124,23 +124,27 @@ namespace OpenEngine { float linear_damping = 0.05f; float angular_damping = 0.05f; float gravity_factor = 1.0f; + float restitution = 0.8f; + float friction = 0.5f; - EMotionType type = EMotionType::Dynamic; - EActivation initial_activation_state = EActivation::Activate; - ObjectLayer layer = Layers::MOVING; + int type = (int)EMotionType::Static; + int initial_activation_state = (int)EActivation::Activate; + int layer = (int)Layers::MOVING; PhysicsBodyComponent() = default; PhysicsBodyComponent(const PhysicsBodyComponent&) = default; }; - struct PhysicsShapeComponent + // TODO: Let's add more shapes + struct BoxShapeComponent { - ShapeRefC shape; - - float restitution = 0.8f; - float friction = 0.5f; + glm::vec3 size = { 1.0f, 1.0f, 1.0f }; }; + struct SphereShapeComponent + { + float radius = 1.0f; + }; } #endif // COMPONENTS_HPP diff --git a/open_engine/include/open_engine/scene/scene.hpp b/open_engine/include/open_engine/scene/scene.hpp index 91dd480..c475590 100644 --- a/open_engine/include/open_engine/scene/scene.hpp +++ b/open_engine/include/open_engine/scene/scene.hpp @@ -18,6 +18,7 @@ namespace OpenEngine { public: Scene() = default; ~Scene() = default; + Scene(Scene& other) {}; void OnRuntimeStart(); void OnRuntimeStop(); @@ -52,8 +53,6 @@ namespace OpenEngine { std::vector pending_deletion; - //BodyID sphere_id; - friend class SceneSerializer; friend class Entity; }; diff --git a/open_engine/src/open_engine/scene/scene.cpp b/open_engine/src/open_engine/scene/scene.cpp index 07d26d0..dfc26fb 100755 --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -1,4 +1,9 @@ #include "logging.hpp" +#include "physics.hpp" +#include "ref_scope.hpp" +#include +#include +#include #include #include @@ -8,6 +13,7 @@ #include #include +#include #include #include #include @@ -17,37 +23,42 @@ namespace OpenEngine { + static Ref CreateShape(entt::registry& reg, entt::entity e) + { + if (reg.any_of(e)) { + auto& c = reg.get(e); + return CreateRef(ToJolt(c.size * 0.5f)); + } + if (reg.any_of(e)) { + auto& c = reg.get(e); + return CreateRef(c.radius); + } + + OE_CORE_ERROR("Entity has no shape component!"); + return nullptr; + }; + void Scene::OnRuntimeStart() { body_interface = &physics_engine.GetBodyInterface(); - - BoxShapeSettings floor_shape_settings(Vec3(100.0f, 1.0f, 100.0f)); - floor_shape_settings.SetEmbedded(); // A ref counted object on the stack (base class RefTarget) should be marked as such to prevent it from being freed when its reference count goes to 0. - - // Create the shape - ShapeSettings::ShapeResult floor_shape_result = floor_shape_settings.Create(); - ShapeRefC floor_shape = floor_shape_result.Get(); // We don't expect an error here, but you can check floor_shape_result for HasError() / GetError() - - // Create the settings for the body itself. Note that here you can also set other properties like the restitution / friction. - BodyCreationSettings floor_settings(floor_shape, RVec3(0.0_r, -1.0_r, 0.0_r), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING); - - // Create the actual rigid body - Body *floor = body_interface->CreateBody(floor_settings); // Note that if we run out of bodies this can return nullptr - - // Add it to the world - body_interface->AddBody(floor->GetID(), EActivation::DontActivate); - // TODO: Cleanup components aquisition auto view = registry.view(); for (auto e : view) { Entity entity = { e, this }; + + auto shape_settings = CreateShape(registry, e); + if (!shape_settings) + shape_settings = CreateRef(Vec3(0.5f, 0.5f, 0.5f)); + + auto shape_result = shape_settings->Create(); + if (shape_result.HasError()) { + OE_CORE_ERROR("Shape creation failed: {}", shape_result.GetError().c_str()); + continue; + } + ShapeRefC shape = shape_result.Get(); auto& pbc = entity.GetComponents(); auto& tc = entity.GetComponents(); - - PhysicsShapeComponent* psc = nullptr; - if (entity.HasComponent()) - psc = &entity.GetComponents(); glm::vec3& pos = tc.translation; glm::vec3& scale = tc.scale; @@ -55,22 +66,21 @@ namespace OpenEngine { Quat quat = Quat::sEulerAngles(Vec3(rot.x, rot.y, rot.z)); BodyCreationSettings settings( - new BoxShape(Vec3(scale.x * 0.5, scale.y * 0.5f, scale.z * 0.5f)), + shape, + //new BoxShape(Vec3(scale.x * 0.5, scale.y * 0.5f, scale.z * 0.5f)), Vec3(pos.x, pos.y, pos.z), quat, - pbc.type, + (EMotionType)pbc.type, pbc.layer); settings.mLinearDamping = pbc.linear_damping; settings.mAngularDamping = pbc.angular_damping; settings.mGravityFactor = pbc.gravity_factor; + settings.mRestitution = pbc.restitution; + settings.mFriction = pbc.friction; + settings.mObjectLayer = (ObjectLayer)pbc.layer; - if (psc != nullptr) { - settings.mRestitution = psc->restitution; - settings.mFriction = psc->friction; - } - - pbc.body = body_interface->CreateAndAddBody(settings, pbc.initial_activation_state); + pbc.body = body_interface->CreateAndAddBody(settings, (EActivation)pbc.initial_activation_state); } } @@ -157,14 +167,8 @@ namespace OpenEngine { body_interface->SetPosition(body.body, { pos.x, pos.y, pos.z }, EActivation::Activate); - PhysicsShapeComponent* shape; - if (entity.HasComponent()) { - shape = &entity.GetComponents(); - - body_interface->SetRestitution(body.body, shape->restitution); - body_interface->SetFriction(body.body, shape->friction); - } - + body_interface->SetRestitution(body.body, body.restitution); + body_interface->SetFriction(body.body, body.friction); } OnUpdatePhysics(); @@ -209,14 +213,13 @@ namespace OpenEngine { for (const auto& e : view) { auto [transform, mesh] = view.get(e); - - Material* material; - Entity entity(e, this); - if (entity.HasComponent()) - material = &entity.GetComponents().material; - Renderer3D::DrawMesh(mesh.mesh, *material, GetTransformFromComp(transform)); + Material material; + if (entity.HasComponent()) + material = entity.GetComponents().material; + + Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); /* if (sprite.texture) Renderer2D::DrawQuad(GetTransformFromComp(transform), @@ -247,7 +250,8 @@ namespace OpenEngine { if (_entity.HasComponent()) material = _entity.GetComponents().material; - Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); + if (mesh.mesh) + Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); } Renderer3D::EndScene(); @@ -328,7 +332,12 @@ namespace OpenEngine { } template<> - void Scene::OnComponentAdded(Entity entity, PhysicsShapeComponent& component) + void Scene::OnComponentAdded(Entity entity, SphereShapeComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, BoxShapeComponent& component) { } } diff --git a/open_engine/src/open_engine/scene/scene_serializer.cpp b/open_engine/src/open_engine/scene/scene_serializer.cpp index c217544..818e3d1 100644 --- a/open_engine/src/open_engine/scene/scene_serializer.cpp +++ b/open_engine/src/open_engine/scene/scene_serializer.cpp @@ -115,8 +115,7 @@ namespace OpenEngine { out << YAML::EndMap; // TransformComponent } - if (entity.HasComponent()) - { + if (entity.HasComponent()) { out << YAML::Key << "CameraComponent"; out << YAML::BeginMap; // CameraComponent @@ -151,8 +150,7 @@ namespace OpenEngine { out << YAML::EndMap; // SpriteRendererComponent } - if (entity.HasComponent()) - { + if (entity.HasComponent()) { out << YAML::Key << "MeshComponent"; out << YAML::BeginMap; // MeshComponent @@ -162,8 +160,7 @@ namespace OpenEngine { out << YAML::EndMap; // MeshComponent } - if (entity.HasComponent()) - { + if (entity.HasComponent()) { out << YAML::Key << "MaterialComponent"; out << YAML::BeginMap; // MaterialComponent @@ -177,6 +174,44 @@ namespace OpenEngine { out << YAML::EndMap; // MaterialComponent } + if (entity.HasComponent()) { + out << YAML::Key << "PhysicsBodyComponent"; + out << YAML::BeginMap; // PhysicsBodyComponent + + auto& pbc = entity.GetComponents(); + out << YAML::Key << "LinearDamping" << YAML::Value << pbc.linear_damping; + out << YAML::Key << "AngularDamping" << YAML::Value << pbc.angular_damping; + out << YAML::Key << "GravityFactor" << YAML::Value << pbc.gravity_factor; + out << YAML::Key << "Restitution" << YAML::Value << pbc.restitution; + out << YAML::Key << "Friction" << YAML::Value << pbc.friction; + + out << YAML::Key << "Type" << YAML::Value << pbc.type; + out << YAML::Key << "ActivationState" << YAML::Value << pbc.initial_activation_state; + out << YAML::Key << "Layer" << YAML::Value << pbc.layer; + + out << YAML::EndMap; // PhysicsBodyComponent + } + + if (entity.HasComponent()) { + out << YAML::Key << "BoxShapeComponent"; + out << YAML::BeginMap; //BoxShapeComponent + + auto& bsc = entity.GetComponents(); + out << YAML::Key << "Size" << YAML::Value << bsc.size; + + out << YAML::EndMap; //BoxShapeComponent + } + + if (entity.HasComponent()) { + out << YAML::Key << "SphereShapeComponent"; + out << YAML::BeginMap; //SphereShapeComponent + + auto& ssc = entity.GetComponents(); + out << YAML::Key << "Radius" << YAML::Value << ssc.radius; + + out << YAML::EndMap; //SphereShapeComponent + } + out << YAML::EndMap; } @@ -292,8 +327,7 @@ namespace OpenEngine { } auto material_component = entity["MaterialComponent"]; - if (material_component) - { + if (material_component) { auto& material = deserializedEntity.AddComponent(); material.material.albedo = material_component["Albedo"].as(); material.material.roughness = material_component["Roughness"].as(); @@ -301,6 +335,35 @@ namespace OpenEngine { material.material.ambient_strength = material_component["AmbiantStrength"].as(); material.material.specular_strength = material_component["SpecularStrength"].as(); } + + auto physics_body_component = entity["PhysicsBodyComponent"]; + if (physics_body_component) { + auto& pbc = deserializedEntity.AddComponent(); + + pbc.linear_damping = physics_body_component["LinearDamping"].as(); + pbc.angular_damping = physics_body_component["AngularDamping"].as(); + pbc.gravity_factor = physics_body_component["GravityFactor"].as(); + pbc.restitution = physics_body_component["Restitution"].as(); + pbc.friction = physics_body_component["Friction"].as(); + + pbc.type = physics_body_component["Type"].as(); + pbc.initial_activation_state = physics_body_component["ActivationState"].as(); + pbc.layer = physics_body_component["Layer"].as(); + } + + auto box_shape_component = entity["BoxShapeComponent"]; + if (box_shape_component) { + auto& bsc = deserializedEntity.AddComponent(); + + bsc.size = box_shape_component["Size"].as(); + } + + auto sphere_shape_component = entity["SphereShapeComponent"]; + if (sphere_shape_component) { + auto& ssc = deserializedEntity.AddComponent(); + + ssc.radius = sphere_shape_component["Radius"].as(); + } } } From a187bd2894f9af5fa96b051b135b96b632cf5dcb Mon Sep 17 00:00:00 2001 From: Erris Date: Thu, 5 Mar 2026 01:23:26 +0100 Subject: [PATCH 6/8] needed for jolt --- open_engine/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/open_engine/CMakeLists.txt b/open_engine/CMakeLists.txt index 808c01d..736726e 100644 --- a/open_engine/CMakeLists.txt +++ b/open_engine/CMakeLists.txt @@ -74,3 +74,5 @@ add_subdirectory(vendor/glad ) add_subdirectory("vendor/nativefiledialog-extended") + +target_compile_options(open_engine PRIVATE -msse4.1 -msse4.2 -mavx -mavx2) From 5be3c6185959a5677a8264b520f7fe6c78063ab5 Mon Sep 17 00:00:00 2001 From: Erris Date: Thu, 5 Mar 2026 22:30:48 +0100 Subject: [PATCH 7/8] fixing segv when closing the program --- open_engine/include/open_engine/renderer/uniform_buffer.hpp | 2 +- open_engine/src/open_engine/renderer/renderer3d.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/open_engine/include/open_engine/renderer/uniform_buffer.hpp b/open_engine/include/open_engine/renderer/uniform_buffer.hpp index c6ccf6f..d38afe8 100644 --- a/open_engine/include/open_engine/renderer/uniform_buffer.hpp +++ b/open_engine/include/open_engine/renderer/uniform_buffer.hpp @@ -8,7 +8,7 @@ namespace OpenEngine { class UniformBuffer { public: - virtual ~UniformBuffer() {} + virtual ~UniformBuffer() = default; virtual void SetData(const void* data, uint32_t size, uint32_t offset = 0) = 0; diff --git a/open_engine/src/open_engine/renderer/renderer3d.cpp b/open_engine/src/open_engine/renderer/renderer3d.cpp index 58120ba..291bfb7 100644 --- a/open_engine/src/open_engine/renderer/renderer3d.cpp +++ b/open_engine/src/open_engine/renderer/renderer3d.cpp @@ -205,8 +205,10 @@ namespace OpenEngine { void Renderer3D::Shutdown() { - renderer_data.camera_uniform_buffer.reset(); renderer_data.color_shader_3d.reset(); + renderer_data.camera_uniform_buffer.reset(); + renderer_data.transform_uniform_buffer.reset(); + renderer_data.material_uniform_buffer.reset(); } void Renderer3D::BeginScene(const SceneCamera& camera, const glm::mat4& transform) From 2d3fe57d5a80791e0c05cad31538230637f71b69 Mon Sep 17 00:00:00 2001 From: Erris Date: Fri, 6 Mar 2026 18:07:51 +0100 Subject: [PATCH 8/8] added UUID --- editor/src/panels/scene_hierarchy.cpp | 1 - imgui.ini | 30 ++++++++-------- open_engine/include/open_engine/core/uuid.hpp | 36 +++++++++++++++++++ .../include/open_engine/scene/components.hpp | 16 ++++++--- .../include/open_engine/scene/entity.hpp | 4 +++ .../scene/native_scriptable_entity.hpp | 1 + .../include/open_engine/scene/scene.hpp | 2 ++ open_engine/src/open_engine/core/uuid.cpp | 24 +++++++++++++ open_engine/src/open_engine/scene/scene.cpp | 12 +++++++ .../open_engine/scene/scene_serializer.cpp | 8 +++-- 10 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 open_engine/include/open_engine/core/uuid.hpp create mode 100644 open_engine/src/open_engine/core/uuid.cpp diff --git a/editor/src/panels/scene_hierarchy.cpp b/editor/src/panels/scene_hierarchy.cpp index bdcfdc6..652febf 100644 --- a/editor/src/panels/scene_hierarchy.cpp +++ b/editor/src/panels/scene_hierarchy.cpp @@ -1,4 +1,3 @@ -#include "open_engine/scene/components.hpp" #include "open_engine/scene/entity.hpp" #include "editor_component.hpp" diff --git a/imgui.ini b/imgui.ini index a2c5d73..9bfba42 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][WindowOverViewport_11111111] Pos=0,24 -Size=2560,1371 +Size=1272,1363 Collapsed=0 [Window][Debug##Default] @@ -10,31 +10,31 @@ Collapsed=0 [Window][Statistics] Pos=0,24 -Size=224,439 +Size=224,437 Collapsed=0 DockId=0x00000003,0 [Window][Properties] -Pos=2110,24 -Size=450,810 +Pos=822,24 +Size=450,805 Collapsed=0 DockId=0x00000007,0 [Window][Viewport] Pos=226,61 -Size=1882,964 +Size=594,956 Collapsed=0 DockId=0x00000012,0 [Window][Dear ImGui Demo] -Pos=2110,836 -Size=450,559 +Pos=822,831 +Size=450,556 Collapsed=0 DockId=0x00000008,0 [Window][Scene] -Pos=0,465 -Size=224,930 +Pos=0,463 +Size=224,924 Collapsed=0 DockId=0x00000004,0 @@ -143,8 +143,8 @@ Collapsed=0 DockId=0x00000012,1 [Window][Assets] -Pos=226,1027 -Size=1882,368 +Pos=226,1019 +Size=594,368 Collapsed=0 DockId=0x0000000C,0 @@ -156,12 +156,12 @@ DockId=0x0000000F,0 [Window][##play_state_bar] Pos=226,24 -Size=1882,35 +Size=594,35 Collapsed=0 DockId=0x00000011,0 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=2560,1371 Split=X +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=1272,1363 Split=X DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=820,1386 Split=X DockNode ID=0x00000001 Parent=0x00000005 SizeRef=224,1386 Split=Y Selected=0xE601B12F DockNode ID=0x00000003 Parent=0x00000001 SizeRef=255,417 Selected=0x553E127E @@ -178,6 +178,6 @@ DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,24 Size=2560,1371 DockNode ID=0x0000000C Parent=0x00000009 SizeRef=409,368 Selected=0x42C24103 DockNode ID=0x0000000A Parent=0x00000002 SizeRef=483,600 Selected=0x1BCA3180 DockNode ID=0x00000006 Parent=0x08BD597D SizeRef=450,1386 Split=Y Selected=0x8C72BEA8 - DockNode ID=0x00000007 Parent=0x00000006 SizeRef=444,810 Selected=0x8C72BEA8 - DockNode ID=0x00000008 Parent=0x00000006 SizeRef=444,559 Selected=0x5E5F7166 + DockNode ID=0x00000007 Parent=0x00000006 SizeRef=444,805 Selected=0x8C72BEA8 + DockNode ID=0x00000008 Parent=0x00000006 SizeRef=444,556 Selected=0x5E5F7166 diff --git a/open_engine/include/open_engine/core/uuid.hpp b/open_engine/include/open_engine/core/uuid.hpp new file mode 100644 index 0000000..3ab6d36 --- /dev/null +++ b/open_engine/include/open_engine/core/uuid.hpp @@ -0,0 +1,36 @@ +#ifndef UUID_HPP +#define UUID_HPP + +#include + +namespace OpenEngine { + + class UUID + { + public: + UUID(); + UUID(uint64_t uuid); + UUID(const UUID&) = default; + + operator uint64_t() const { return uuid; }; + + private: + uint64_t uuid; + }; + +} + +namespace std { + + template<> + struct hash + { + std::size_t operator()(const OpenEngine::UUID& uuid) const + { + return hash()((uint64_t)uuid); + } + }; + +} + +#endif // UUID_HPP diff --git a/open_engine/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index 9375e32..d5fe5cb 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -1,12 +1,12 @@ #ifndef COMPONENTS_HPP #define COMPONENTS_HPP -#include "open_engine/scene/native_scriptable_entity.hpp" #include "open_engine/renderer/renderer3d.hpp" #include "open_engine/scene/scene_camera.hpp" #include "open_engine/renderer/texture.hpp" #include "open_engine/renderer/renderer3d.hpp" #include "open_engine/physics.hpp" +#include "open_engine/core/uuid.hpp" #include #include @@ -28,6 +28,15 @@ namespace OpenEngine { + struct IDComponent + { + UUID id; + + IDComponent() = default; + IDComponent(const IDComponent&) = default; + IDComponent(const UUID& uuid) : id(uuid) {}; + }; + struct TagComponent { std::string tag; @@ -74,6 +83,8 @@ namespace OpenEngine { CameraComponent(const CameraComponent&) = default; }; + class NativeScriptableEntity; + struct NativeScriptComponent { NativeScriptableEntity* instance = nullptr; @@ -81,9 +92,6 @@ namespace OpenEngine { NativeScriptableEntity* (*InstanciateScript)(); void (*DestroyInstanceScript)(NativeScriptComponent*); - void OnImGuiRender(Entity& entity) - {}; - template void Bind() { diff --git a/open_engine/include/open_engine/scene/entity.hpp b/open_engine/include/open_engine/scene/entity.hpp index bfe1e30..50d375a 100644 --- a/open_engine/include/open_engine/scene/entity.hpp +++ b/open_engine/include/open_engine/scene/entity.hpp @@ -3,6 +3,8 @@ #include "open_engine/core.hpp" +#include "open_engine/core/uuid.hpp" +#include "open_engine/scene/components.hpp" #include "open_engine/scene/scene.hpp" #include @@ -48,6 +50,8 @@ namespace OpenEngine { return scene->registry.all_of(handle); }; + UUID GetUUID() { return GetComponents().id; }; + operator bool() const { return handle != entt::null; }; operator entt::entity() const { return handle; }; operator uint32_t() const { return (uint32_t)handle; }; diff --git a/open_engine/include/open_engine/scene/native_scriptable_entity.hpp b/open_engine/include/open_engine/scene/native_scriptable_entity.hpp index dceb611..65ae6c2 100644 --- a/open_engine/include/open_engine/scene/native_scriptable_entity.hpp +++ b/open_engine/include/open_engine/scene/native_scriptable_entity.hpp @@ -1,6 +1,7 @@ #ifndef NATIVE_SCRIPTABLE_ENTITY_HPP #define NATIVE_SCRIPTABLE_ENTITY_HPP +#include "open_engine/scene/native_scriptable_entity.hpp" #include "open_engine/scene/entity.hpp" namespace OpenEngine { diff --git a/open_engine/include/open_engine/scene/scene.hpp b/open_engine/include/open_engine/scene/scene.hpp index c475590..24d405a 100644 --- a/open_engine/include/open_engine/scene/scene.hpp +++ b/open_engine/include/open_engine/scene/scene.hpp @@ -1,6 +1,7 @@ #ifndef SCENE_HPP #define SCENE_HPP +#include "open_engine/core/uuid.hpp" #include "open_engine/renderer/editor_camera.hpp" #include "open_engine/physics.hpp" @@ -24,6 +25,7 @@ namespace OpenEngine { void OnRuntimeStop(); Entity CreateEntity(const std::string& name = std::string()); + Entity CreateEntityWithUUID(UUID uuid, const std::string& name = std::string()); void DeleteEntity(entt::entity entity); void MarkEntityForDeletion(Entity entity); diff --git a/open_engine/src/open_engine/core/uuid.cpp b/open_engine/src/open_engine/core/uuid.cpp new file mode 100644 index 0000000..5e08f75 --- /dev/null +++ b/open_engine/src/open_engine/core/uuid.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include + +#include + +namespace OpenEngine { + + static std::random_device s_random_device; + static std::mt19937_64 s_engine(s_random_device()); + static std::uniform_int_distribution s_uniform_distribution; + + UUID::UUID() + : uuid(s_uniform_distribution(s_engine)) + { + } + + UUID::UUID(uint64_t uuid) + : uuid(uuid) + { + } + +} diff --git a/open_engine/src/open_engine/scene/scene.cpp b/open_engine/src/open_engine/scene/scene.cpp index dfc26fb..75297ad 100755 --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -98,9 +99,15 @@ namespace OpenEngine { } Entity Scene::CreateEntity(const std::string& name) + { + return CreateEntityWithUUID(UUID(), name); + } + + Entity Scene::CreateEntityWithUUID(UUID uuid, const std::string& name) { Entity entity = { registry.create(), this }; + entity.AddComponent(uuid); auto& tag = entity.AddComponent(); tag.tag = name.empty() ? "Entity" : name; @@ -340,4 +347,9 @@ namespace OpenEngine { void Scene::OnComponentAdded(Entity entity, BoxShapeComponent& component) { } + + template<> + void Scene::OnComponentAdded(Entity entity, IDComponent& component) + { + } } diff --git a/open_engine/src/open_engine/scene/scene_serializer.cpp b/open_engine/src/open_engine/scene/scene_serializer.cpp index 818e3d1..9733ea6 100644 --- a/open_engine/src/open_engine/scene/scene_serializer.cpp +++ b/open_engine/src/open_engine/scene/scene_serializer.cpp @@ -88,8 +88,10 @@ namespace OpenEngine { static void SerializeEntity(YAML::Emitter& out, Entity entity) { + OE_CORE_ASSERT(entity.HasComponent(), "Entity is missing UUID."); + out << YAML::BeginMap; - out << YAML::Key << "Entity" << YAML::Value << "412741205"; // Needs random + out << YAML::Key << "Entity" << YAML::Value << entity.GetUUID(); // Needs random if (entity.HasComponent()) { @@ -258,7 +260,7 @@ namespace OpenEngine { { for (auto entity : entities) { - uint64_t uuid = entity["Entity"].as(); // TODO + uint64_t uuid = entity["Entity"].as(); std::string name; auto tagComponent = entity["TagComponent"]; @@ -267,7 +269,7 @@ namespace OpenEngine { OE_CORE_TRACE("Deserialized entity with ID = {0}, name = {1}", uuid, name); - Entity deserializedEntity = context->CreateEntity(name); + Entity deserializedEntity = context->CreateEntityWithUUID(uuid, name); auto transformComponent = entity["TransformComponent"]; if (transformComponent)