diff --git a/editor/include/editor.hpp b/editor/include/editor.hpp index 0820057..e054478 100755 --- a/editor/include/editor.hpp +++ b/editor/include/editor.hpp @@ -1,15 +1,17 @@ #ifndef EDITOR_HPP #define EDITOR_HPP -#include #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" +#include +#include +#include +#include #include #include #include @@ -92,33 +94,39 @@ 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"); - - 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"); quad.AddComponent(); quad.GetComponents().translation = {0, 0, 0}; 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"); cube2.AddComponent(); cube2.GetComponents().translation = {2, 0, 0}; Ref mesh2 = CreateCube(cube2); - cube2.AddComponent(mesh2); + auto& mc2 = cube2.AddComponent(mesh2); + mc2.primitive_type = PrimitiveType::Cube; /* auto view = scene->GetRegistry().view(); @@ -129,7 +137,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++) { @@ -179,7 +186,6 @@ namespace OpenEngine { RenderCommand::Clear(); framebuffer->ClearBufferI(1, -1); - switch (state) { case PlayState::Play: { scene->OnUpdateRuntime(); @@ -206,6 +212,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 @@ -352,7 +359,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(); @@ -563,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 bc5623e..7a3ecc7 100644 --- a/editor/include/editor_component.hpp +++ b/editor/include/editor_component.hpp @@ -17,6 +17,10 @@ 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); + void BodyOnImGuiRender(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/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..855ee08 100644 --- a/editor/src/editor_component.cpp +++ b/editor/src/editor_component.cpp @@ -1,5 +1,10 @@ #include "imgui.h" +#include "open_engine/renderer/renderer3d.hpp" +#include "open_engine/scene/components.hpp" +#include #include +#include +#include #include namespace OpenEngine { @@ -91,6 +96,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) @@ -101,6 +107,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 +178,109 @@ 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[] = { "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 < 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(); + } + + if ((int)mesh_component.primitive_type == (item_selected_idx)) + return; + + 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; + } + } + + void MaterialOnImGuiRender(entt::registry& registry, entt::entity entity) + { + auto& material = registry.get(entity).material; + + 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); + } + + void BodyOnImGuiRender(entt::registry ®istry, entt::entity entity) + { + 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 SphereShapeOnImGuiRender(entt::registry ®istry, entt::entity entity) + { + auto& sphere_comp = registry.get(entity); + + ImGui::DragFloat("Radius", + &sphere_comp.radius, + 0.1f, + 0.11f, FLT_MAX, + "%.2f", + ImGuiSliderFlags_AlwaysClamp); + } + + 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/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..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" @@ -23,6 +22,10 @@ namespace OpenEngine { RegisterDrawer("Sprite Renderer", &SpriteOnImGuiRender); RegisterDrawer("Camera", &CameraOnImGuiRender); RegisterDrawer("Mesh", &MeshOnImGuiRender); + RegisterDrawer("Material", &MaterialOnImGuiRender); + RegisterDrawer("Physics Body", &BodyOnImGuiRender); + RegisterDrawer("Sphere Shape", &SphereShapeOnImGuiRender); + RegisterDrawer("Box Shape", &BoxShapeOnImGuiRender); scene = context; selected_context = {}; @@ -51,6 +54,26 @@ namespace OpenEngine { selected_context.AddComponent(); ImGui::CloseCurrentPopup(); } + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Material")) { + 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("Sphere shape")) { + selected_context.AddComponent(); + ImGui::CloseCurrentPopup(); + } + if (!selected_context.HasComponent()) + if (ImGui::MenuItem("Box shape")) { + selected_context.AddComponent(); + ImGui::CloseCurrentPopup(); + } } void EntityPopup(Ref& scene) @@ -195,17 +218,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)) { @@ -228,20 +252,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..9bfba42 100644 --- a/imgui.ini +++ b/imgui.ini @@ -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,805 Selected=0x8C72BEA8 + DockNode ID=0x00000008 Parent=0x00000006 SizeRef=444,556 Selected=0x5E5F7166 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) 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/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 diff --git a/open_engine/include/open_engine/physics.hpp b/open_engine/include/open_engine/physics.hpp new file mode 100644 index 0000000..673a5d4 --- /dev/null +++ b/open_engine/include/open_engine/physics.hpp @@ -0,0 +1,191 @@ +#ifndef PHYSICS_HPP +#define PHYSICS_HPP + +#include "logging.hpp" + +#include +#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); +}; + +inline JPH::Vec3 ToJolt(const glm::vec3& v) { return JPH::Vec3(v.x, v.y, v.z); }; + +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/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/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/include/open_engine/scene/components.hpp b/open_engine/include/open_engine/scene/components.hpp index b1e55f1..d5fe5cb 100644 --- a/open_engine/include/open_engine/scene/components.hpp +++ b/open_engine/include/open_engine/scene/components.hpp @@ -1,12 +1,19 @@ #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 +#include +#include +#include +#include #include #include #include @@ -21,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; @@ -67,6 +83,8 @@ namespace OpenEngine { CameraComponent(const CameraComponent&) = default; }; + class NativeScriptableEntity; + struct NativeScriptComponent { NativeScriptableEntity* instance = nullptr; @@ -74,9 +92,6 @@ namespace OpenEngine { NativeScriptableEntity* (*InstanciateScript)(); void (*DestroyInstanceScript)(NativeScriptComponent*); - void OnImGuiRender(Entity& entity) - {}; - template void Bind() { @@ -86,19 +101,58 @@ 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) {}; + }; + + struct PhysicsBodyComponent + { + BodyID body; + + float linear_damping = 0.05f; + float angular_damping = 0.05f; + float gravity_factor = 1.0f; + float restitution = 0.8f; + float friction = 0.5f; + + int type = (int)EMotionType::Static; + int initial_activation_state = (int)EActivation::Activate; + int layer = (int)Layers::MOVING; + + PhysicsBodyComponent() = default; + PhysicsBodyComponent(const PhysicsBodyComponent&) = default; + }; + + // TODO: Let's add more shapes + struct BoxShapeComponent + { + 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/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 cf299a8..24d405a 100644 --- a/open_engine/include/open_engine/scene/scene.hpp +++ b/open_engine/include/open_engine/scene/scene.hpp @@ -1,8 +1,11 @@ #ifndef SCENE_HPP #define SCENE_HPP +#include "open_engine/core/uuid.hpp" #include "open_engine/renderer/editor_camera.hpp" +#include "open_engine/physics.hpp" +#include #include #include #include @@ -16,8 +19,13 @@ namespace OpenEngine { public: Scene() = default; ~Scene() = default; + Scene(Scene& other) {}; + + void OnRuntimeStart(); + 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); @@ -28,19 +36,24 @@ 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 entities_to_be_deleted; + std::vector pending_deletion; friend class SceneSerializer; friend class 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/physics.cpp b/open_engine/src/open_engine/physics.cpp new file mode 100644 index 0000000..c3de441 --- /dev/null +++ b/open_engine/src/open_engine/physics.cpp @@ -0,0 +1,73 @@ +#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: 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/renderer/renderer3d.cpp b/open_engine/src/open_engine/renderer/renderer3d.cpp index cc14723..291bfb7 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); @@ -201,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) @@ -230,7 +236,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 +246,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 old mode 100644 new mode 100755 index d6a114e..75297ad --- a/open_engine/src/open_engine/scene/scene.cpp +++ b/open_engine/src/open_engine/scene/scene.cpp @@ -1,18 +1,113 @@ -#include -#include +#include "logging.hpp" +#include "physics.hpp" +#include "ref_scope.hpp" +#include +#include +#include #include #include #include +#include #include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include 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(); + // 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(); + + glm::vec3& pos = tc.translation; + glm::vec3& scale = tc.scale; + glm::vec3& rot = tc.rotation; + + Quat quat = Quat::sEulerAngles(Vec3(rot.x, rot.y, rot.z)); + BodyCreationSettings settings( + shape, + //new BoxShape(Vec3(scale.x * 0.5, scale.y * 0.5f, scale.z * 0.5f)), + Vec3(pos.x, pos.y, pos.z), + quat, + (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; + + pbc.body = body_interface->CreateAndAddBody(settings, (EActivation)pbc.initial_activation_state); + } + } + + void Scene::OnRuntimeStop() + { + auto view = registry.view(); + for (auto e : view) { + Entity entity = { e, this }; + + auto& pbc = entity.GetComponents(); + + body_interface->RemoveBody(pbc.body); + body_interface->DestroyBody(pbc.body); + } + } + 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; @@ -26,15 +121,31 @@ 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::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 +165,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); + + body_interface->SetRestitution(body.body, body.restitution); + body_interface->SetFriction(body.body, body.friction); + } + + OnUpdatePhysics(); + + for (auto e : view) { + Entity entity = { e, this }; + + auto& transform = entity.GetComponents(); + auto& body = entity.GetComponents(); + + 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; glm::mat4 main_transform{ 1.0f }; { @@ -73,10 +218,15 @@ 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); + Entity entity(e, this); - Renderer3D::DrawMesh(mesh.mesh, 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), @@ -101,7 +251,14 @@ 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; + + if (mesh.mesh) + Renderer3D::DrawMesh(mesh.mesh, material, GetTransformFromComp(transform)); } Renderer3D::EndScene(); @@ -170,4 +327,29 @@ namespace OpenEngine { void Scene::OnComponentAdded(Entity entity, MeshComponent& component) { } + + template<> + void Scene::OnComponentAdded(Entity entity, MaterialComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, PhysicsBodyComponent& component) + { + } + + template<> + void Scene::OnComponentAdded(Entity entity, SphereShapeComponent& component) + { + } + + template<> + 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 270273e..9733ea6 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" @@ -86,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()) { @@ -113,8 +117,7 @@ namespace OpenEngine { out << YAML::EndMap; // TransformComponent } - if (entity.HasComponent()) - { + if (entity.HasComponent()) { out << YAML::Key << "CameraComponent"; out << YAML::BeginMap; // CameraComponent @@ -149,6 +152,68 @@ 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 + } + + 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; } @@ -195,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"]; @@ -204,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) @@ -241,6 +306,66 @@ namespace OpenEngine { auto& src = deserializedEntity.AddComponent(); src.color = spriteRendererComponent["Color"].as(); } + + auto mesh_component = entity["MeshComponent"]; + if (mesh_component) + { + auto& mesh = deserializedEntity.AddComponent(); + mesh.primitive_type = (PrimitiveType)mesh_component["MeshType"].as(); + 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: { + OE_CORE_ASSERT(false, "No mesh"); + 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 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(); + } } } diff --git a/resources/textures/icons/file.png b/resources/textures/icons/file.png new file mode 100644 index 0000000..4c885f7 Binary files /dev/null and b/resources/textures/icons/file.png differ diff --git a/resources/textures/icons/folder2.png b/resources/textures/icons/folder2.png new file mode 100644 index 0000000..5bfd08a Binary files /dev/null and b/resources/textures/icons/folder2.png differ diff --git a/resources/textures/icons/play.png b/resources/textures/icons/play.png index 274b12a..f9058d9 100644 Binary files a/resources/textures/icons/play.png and b/resources/textures/icons/play.png differ diff --git a/resources/textures/icons/stop.png b/resources/textures/icons/stop.png index f8b14b5..ce54396 100644 Binary files a/resources/textures/icons/stop.png and b/resources/textures/icons/stop.png differ 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