diff --git a/assets b/assets index b3746822..5874ddf3 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit b37468222e45ec0b2116f1543c578cb9784d43f2 +Subproject commit 5874ddf376e234d0c7de0878c940d3da439a19dd diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 65dc3be7..39d27ca6 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -21,10 +21,14 @@ public: ComponentWrapper AttachComponent(EntityID entity, std::string componentType); // Get a component of an entity ComponentWrapper GetComponent(EntityID entity, std::string componentType); + // Delete a component off an entity + void DeleteComponent(EntityID entity, std::string componentType); // Get all components of the specified type const ComponentPool* GetComponents(std::string componentType); // Get entity parent EntityID GetParent(EntityID entity); + // Get all component pools + const std::unordered_map& GetComponentPools() const { return m_ComponentPools; } private: EntityID m_CurrentEntityID = 1; diff --git a/include/Engine/Editor/EditorSystem.h b/include/Engine/Editor/EditorSystem.h index 9520d2a6..da076942 100644 --- a/include/Engine/Editor/EditorSystem.h +++ b/include/Engine/Editor/EditorSystem.h @@ -1,11 +1,26 @@ +#include #include "../Core/System.h" +#include "../Core/EMousePress.h" +#include "../Rendering/EPicking.h" class EditorSystem : public ImpureSystem { public: - EditorSystem(EventBroker* eventBroker) - : ImpureSystem(eventBroker) - { } + EditorSystem(EventBroker* eventBroker); virtual void Update(World* world, double dt) override; + +private: + std::vector m_PickingQueue; + EntityID m_Widget = 0; + EntityID m_Selection = 0; + EntityID m_LastSelection = 0; + + EventRelay m_EMousePress; + bool OnMousePress(const Events::MousePress& e); + EventRelay m_EPicking; + bool OnPicking(const Events::Picking& e); + + void drawUI(World* world, double dt); + bool createDeleteButton(std::string componentType); }; \ No newline at end of file diff --git a/include/Engine/Rendering/DebugCameraInputController.h b/include/Engine/Rendering/DebugCameraInputController.h index 551ae0f2..6d5908ef 100644 --- a/include/Engine/Rendering/DebugCameraInputController.h +++ b/include/Engine/Rendering/DebugCameraInputController.h @@ -1,3 +1,4 @@ +#include #include "../Input/FirstPersonInputController.h" template @@ -15,20 +16,31 @@ public: { if (e.Command == "PrimaryFire") { if (e.Value > 0) { - LockMouse(); + if (!ImGui::IsMouseHoveringAnyWindow()) { + LockMouse(); + } } else { UnlockMouse(); } return false; } - if (e.Command == "Right") { - float value = std::max(-1.f, std::min(e.Value, 1.f)); - m_Velocity.x = value; - } - if (e.Command == "Forward") { - float value = std::max(-1.f, std::min(e.Value, 1.f)); - m_Velocity.z = -value; + if (m_MouseLocked || e.Value == 0) { + if (e.Command == "Right") { + float value = std::max(-1.f, std::min(e.Value, 1.f)); + m_Velocity.x = value; + } + if (e.Command == "Forward") { + float value = std::max(-1.f, std::min(e.Value, 1.f)); + m_Velocity.z = -value; + } + if (e.Command == "Sprint") { + if (e.Value > 0.f) { + m_Speed = m_BaseSpeed * 2.f * (e.Value); + } else { + m_Speed = m_BaseSpeed; + } + } } return FirstPersonInputController::OnCommand(e); @@ -37,12 +49,13 @@ public: void Update(double dt) { if (glm::length2(m_Velocity) > 0) { - m_Position += m_Orientation * (glm::normalize(m_Velocity) * m_BaseSpeed); + m_Position += m_Orientation * (glm::normalize(m_Velocity) * m_Speed * (float)dt); } } protected: glm::vec3 m_Position = glm::vec3(0, 0, 0); glm::vec3 m_Velocity = glm::vec3(0, 0, 0); - float m_BaseSpeed = 0.1f; + float m_BaseSpeed = 2.0f; + float m_Speed = m_BaseSpeed; }; \ No newline at end of file diff --git a/include/Engine/Rendering/EPicking.h b/include/Engine/Rendering/EPicking.h index df75854a..66530a01 100644 --- a/include/Engine/Rendering/EPicking.h +++ b/include/Engine/Rendering/EPicking.h @@ -46,7 +46,7 @@ public: if (it != PickingColorsToEntity->end()) { pickData.Entity = it->second; } else { - pickData.Entity = -1; + pickData.Entity = 0; } pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, Resolution.Width - screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix); diff --git a/resources/Schema/Entities/EditorTestWorld.xml b/resources/Schema/Entities/EditorTestWorld.xml new file mode 100755 index 00000000..6e1c0be5 --- /dev/null +++ b/resources/Schema/Entities/EditorTestWorld.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + Models/Core/UnitPlane.obj + + + + + + + + + + An error + + + + + \ No newline at end of file diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index c1e359af..b687fb6a 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -1,6 +1,187 @@ #include "Editor/EditorSystem.h" +#define IMGUI_DEFINE_MATH_OPERATORS +#include + +EditorSystem::EditorSystem(EventBroker* eventBroker) + : ImpureSystem(eventBroker) +{ + EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress); + EVENT_SUBSCRIBE_MEMBER(m_EPicking, &EditorSystem::OnPicking); +} void EditorSystem::Update(World* world, double dt) { + if (m_Widget == 0) { + m_Widget = world->CreateEntity(); + world->AttachComponent(m_Widget, "Transform"); + auto& model = world->AttachComponent(m_Widget, "Model"); + model["Resource"] = "Models/TranslationWidget.obj"; + } + if (m_Selection != m_LastSelection) { + + } + + if (m_Selection != 0) { + auto selectionTransform = world->GetComponent(m_Selection, "Transform"); + auto widgetTransform = world->GetComponent(m_Widget, "Transform"); + + widgetTransform["Position"] = (glm::vec3)selectionTransform["Position"]; + } + + drawUI(world, dt); +} + +bool EditorSystem::OnMousePress(const Events::MousePress& e) +{ + if (e.Button == GLFW_MOUSE_BUTTON_RIGHT) { + m_PickingQueue.push_back(glm::vec2(e.X, e.Y)); + } + return true; +} + +bool EditorSystem::OnPicking(const Events::Picking& e) +{ + for (auto& pos : m_PickingQueue) { + auto result = e.Pick(pos); + LOG_INFO("Selected %i", result.Entity); + m_Selection = result.Entity; + } + m_PickingQueue.clear(); + return true; +}; + +void EditorSystem::drawUI(World* world, double dt) +{ + //ImGui::ShowTestWindow(); + //ImGui::ShowStyleEditor(); + + if (ImGui::BeginMainMenuBar()) { + if (ImGui::BeginMenu("File")) { + + if (ImGui::MenuItem("New")) { } + if (ImGui::MenuItem("Open", "Ctrl+O")) { } + if (ImGui::MenuItem("Save", "Ctrl+S")) { } + if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) { } + ImGui::Separator(); + if (ImGui::MenuItem("Close Editor", "F1")) { } + + ImGui::EndMenu(); + } + + ImGui::SameLine(); + if (ImGui::Button("Move")) { + auto& model = world->GetComponent(m_Widget, "Model"); + model["Resource"] = "Models/TranslationWidget.obj"; + } + ImGui::SameLine(); + if (ImGui::Button("Rotate")) { + auto& model = world->GetComponent(m_Widget, "Model"); + model["Resource"] = "Models/RotationWidget.obj"; + } + ImGui::SameLine(); + if (ImGui::Button("Scale")) { + auto& model = world->GetComponent(m_Widget, "Model"); + model["Resource"] = "Models/ScaleWidget.obj"; + } + + ImGui::EndMainMenuBar(); + } + + if (ImGui::Begin("Properties")) { + if (m_Selection != 0) { + auto& pools = world->GetComponentPools(); + + std::vector componentTypes; + for (auto& pair : pools) { + // Only add components the entity doesn't already have + if (!pair.second->KnowsEntity(m_Selection)) { + componentTypes.push_back(pair.first.c_str()); + } + } + int item = -1; + ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth() - 5.f); + if (ImGui::Combo("", &item, componentTypes.data(), componentTypes.size())) { + if (item != -1) { + std::string chosenType = std::string(componentTypes.at(item)); + world->AttachComponent(m_Selection, chosenType); + } + } + ImGui::PopItemWidth(); + + for (auto& pair : pools) { + const std::string& componentType = pair.first; + auto pool = pair.second; + if (!pool->KnowsEntity(m_Selection)) { + continue; + } + auto& ci = pool->ComponentInfo(); + + bool deletePressed = createDeleteButton(componentType); + if (deletePressed) { + world->DeleteComponent(m_Selection, componentType); + continue; + } + + if (ImGui::CollapsingHeader(componentType.c_str())) { + if (!ci.Meta.Annotation.empty()) { + ImGui::Text(ci.Meta.Annotation.c_str()); + } + + auto& component = world->GetComponent(m_Selection, componentType); + for (auto& pair : ci.FieldTypes) { + const std::string& field = pair.first; + const std::string& type = pair.second; + + if (type == "Vector") { + auto& val = component.Property(field); + if (field == "Scale") { + ImGui::DragFloat3(field.c_str(), glm::value_ptr(val), 0.1f, 0.f, 9999.f); + } else if (field == "Orientation") { + ImGui::SliderFloat3(field.c_str(), glm::value_ptr(val), 0.f, glm::pi()); + } else { + ImGui::InputFloat3(field.c_str(), glm::value_ptr(val)); + } + } else if (type == "Color") { + auto& val = component.Property(field); + ImGui::ColorEdit4(field.c_str(), glm::value_ptr(val), true); + } else if (type == "string") { + std::string& val = component.Property(field); + char tempString[1024]; + memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString))); + if (ImGui::InputText(field.c_str(), tempString, sizeof(tempString))) { + val = std::string(tempString); + LOG_DEBUG("%s::%s changed!", componentType.c_str(), field.c_str()); + } + } else if (type == "double") { + float tempVal = static_cast(component.Property(field)); + if (ImGui::InputFloat(field.c_str(), &tempVal, 0.01f, 1.f)) { + component.SetProperty(field, static_cast(tempVal)); + } + } + } + } + } + } + + } + ImGui::End(); +} + +bool EditorSystem::createDeleteButton(std::string componentType) +{ + float width = ImGui::GetContentRegionAvailWidth(); + ImGuiWindow* window = ImGui::GetCurrentWindow(); + auto pos = ImGui::GetCursorScreenPos() + ImVec2(width - 14.f, 1); + ImRect bb = ImRect(pos, pos + ImVec2(14.f, 14.f)); + std::string idString = "#DELETE"; + idString += componentType; + ImGuiID id = window->GetID(idString.c_str()); + bool hovered; + bool held; + bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held); + //ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton); + ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); + window->DrawList->AddCircleFilled(bb.GetCenter(), 7.f, col, 16); + return pressed; } diff --git a/src/Engine/Rendering/ImGuiRenderPass.cpp b/src/Engine/Rendering/ImGuiRenderPass.cpp index f47438fd..1cb3ed8c 100644 --- a/src/Engine/Rendering/ImGuiRenderPass.cpp +++ b/src/Engine/Rendering/ImGuiRenderPass.cpp @@ -27,6 +27,21 @@ ImGuiRenderPass::ImGuiRenderPass(IRenderer* renderer, EventBroker* eventBroker) io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; + ImGuiStyle& style = ImGui::GetStyle(); + style.Alpha = 1.f; + style.WindowPadding = ImVec2(8.f, 7.f); + style.WindowRounding = 4.f; + style.ChildWindowRounding = 0.f; + style.FramePadding = ImVec2(4.f, 2.f); + style.FrameRounding = 2.f; + style.ItemSpacing = ImVec2(6.f, 2.f); + style.ItemInnerSpacing = ImVec2(3.f, 4.f); + style.IndentSpacing = 16.f; + style.ScrollbarSize = 12; + style.ScrollbarRounding = 2.f; + style.GrabMinSize = 13.f; + style.GrabRounding = 3.f; + createDeviceObjects(); EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &ImGuiRenderPass::OnMousePress); @@ -320,6 +335,8 @@ void ImGuiRenderPass::newFrame() io.MouseWheel = g_MouseWheel; g_MouseWheel = 0; + m_EventBroker->Process(); + ImGui::NewFrame(); } diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index 76e687ee..81926f4e 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -129,7 +129,6 @@ void Renderer::Update(double dt) { m_EventBroker->Process(); InputUpdate(dt); - m_EventBroker->Process(); m_ImGuiRenderPass->Update(dt); }