Editor version 1
This commit is contained in:
+1
-1
Submodule assets updated: b37468222e...5874ddf376
@@ -21,10 +21,14 @@ public:
|
|||||||
ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
|
ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
|
||||||
// Get a component of an entity
|
// Get a component of an entity
|
||||||
ComponentWrapper GetComponent(EntityID entity, std::string componentType);
|
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
|
// Get all components of the specified type
|
||||||
const ComponentPool* GetComponents(std::string componentType);
|
const ComponentPool* GetComponents(std::string componentType);
|
||||||
// Get entity parent
|
// Get entity parent
|
||||||
EntityID GetParent(EntityID entity);
|
EntityID GetParent(EntityID entity);
|
||||||
|
// Get all component pools
|
||||||
|
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntityID m_CurrentEntityID = 1;
|
EntityID m_CurrentEntityID = 1;
|
||||||
|
|||||||
@@ -1,11 +1,26 @@
|
|||||||
|
#include <imgui/imgui.h>
|
||||||
#include "../Core/System.h"
|
#include "../Core/System.h"
|
||||||
|
#include "../Core/EMousePress.h"
|
||||||
|
#include "../Rendering/EPicking.h"
|
||||||
|
|
||||||
class EditorSystem : public ImpureSystem
|
class EditorSystem : public ImpureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EditorSystem(EventBroker* eventBroker)
|
EditorSystem(EventBroker* eventBroker);
|
||||||
: ImpureSystem(eventBroker)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual void Update(World* world, double dt) override;
|
virtual void Update(World* world, double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<glm::vec2> m_PickingQueue;
|
||||||
|
EntityID m_Widget = 0;
|
||||||
|
EntityID m_Selection = 0;
|
||||||
|
EntityID m_LastSelection = 0;
|
||||||
|
|
||||||
|
EventRelay<EditorSystem, Events::MousePress> m_EMousePress;
|
||||||
|
bool OnMousePress(const Events::MousePress& e);
|
||||||
|
EventRelay<EditorSystem, Events::Picking> m_EPicking;
|
||||||
|
bool OnPicking(const Events::Picking& e);
|
||||||
|
|
||||||
|
void drawUI(World* world, double dt);
|
||||||
|
bool createDeleteButton(std::string componentType);
|
||||||
};
|
};
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <imgui/imgui.h>
|
||||||
#include "../Input/FirstPersonInputController.h"
|
#include "../Input/FirstPersonInputController.h"
|
||||||
|
|
||||||
template <typename EventContext>
|
template <typename EventContext>
|
||||||
@@ -15,20 +16,31 @@ public:
|
|||||||
{
|
{
|
||||||
if (e.Command == "PrimaryFire") {
|
if (e.Command == "PrimaryFire") {
|
||||||
if (e.Value > 0) {
|
if (e.Value > 0) {
|
||||||
LockMouse();
|
if (!ImGui::IsMouseHoveringAnyWindow()) {
|
||||||
|
LockMouse();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
UnlockMouse();
|
UnlockMouse();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.Command == "Right") {
|
if (m_MouseLocked || e.Value == 0) {
|
||||||
float value = std::max(-1.f, std::min(e.Value, 1.f));
|
if (e.Command == "Right") {
|
||||||
m_Velocity.x = value;
|
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));
|
if (e.Command == "Forward") {
|
||||||
m_Velocity.z = -value;
|
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);
|
return FirstPersonInputController::OnCommand(e);
|
||||||
@@ -37,12 +49,13 @@ public:
|
|||||||
void Update(double dt)
|
void Update(double dt)
|
||||||
{
|
{
|
||||||
if (glm::length2(m_Velocity) > 0) {
|
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:
|
protected:
|
||||||
glm::vec3 m_Position = glm::vec3(0, 0, 0);
|
glm::vec3 m_Position = glm::vec3(0, 0, 0);
|
||||||
glm::vec3 m_Velocity = 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;
|
||||||
};
|
};
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
if (it != PickingColorsToEntity->end()) {
|
if (it != PickingColorsToEntity->end()) {
|
||||||
pickData.Entity = it->second;
|
pickData.Entity = it->second;
|
||||||
} else {
|
} else {
|
||||||
pickData.Entity = -1;
|
pickData.Entity = 0;
|
||||||
}
|
}
|
||||||
pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, Resolution.Width - screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix);
|
pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, Resolution.Width - screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix);
|
||||||
|
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components">
|
||||||
|
<Components>
|
||||||
|
<c:Transform></c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="0"/>
|
||||||
|
<Scale X="100" Y="1" Z="100"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitPlane.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="1" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>An error</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
@@ -1,6 +1,187 @@
|
|||||||
#include "Editor/EditorSystem.h"
|
#include "Editor/EditorSystem.h"
|
||||||
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
|
#include <imgui/imgui_internal.h>
|
||||||
|
|
||||||
|
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)
|
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<const char*> 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<glm::vec3>(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<float>());
|
||||||
|
} else {
|
||||||
|
ImGui::InputFloat3(field.c_str(), glm::value_ptr(val));
|
||||||
|
}
|
||||||
|
} else if (type == "Color") {
|
||||||
|
auto& val = component.Property<glm::vec4>(field);
|
||||||
|
ImGui::ColorEdit4(field.c_str(), glm::value_ptr(val), true);
|
||||||
|
} else if (type == "string") {
|
||||||
|
std::string& val = component.Property<std::string>(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<float>(component.Property<double>(field));
|
||||||
|
if (ImGui::InputFloat(field.c_str(), &tempVal, 0.01f, 1.f)) {
|
||||||
|
component.SetProperty(field, static_cast<double>(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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,21 @@ ImGuiRenderPass::ImGuiRenderPass(IRenderer* renderer, EventBroker* eventBroker)
|
|||||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
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();
|
createDeviceObjects();
|
||||||
|
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &ImGuiRenderPass::OnMousePress);
|
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &ImGuiRenderPass::OnMousePress);
|
||||||
@@ -320,6 +335,8 @@ void ImGuiRenderPass::newFrame()
|
|||||||
io.MouseWheel = g_MouseWheel;
|
io.MouseWheel = g_MouseWheel;
|
||||||
g_MouseWheel = 0;
|
g_MouseWheel = 0;
|
||||||
|
|
||||||
|
m_EventBroker->Process<ImGuiRenderPass>();
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ void Renderer::Update(double dt)
|
|||||||
{
|
{
|
||||||
m_EventBroker->Process<Renderer>();
|
m_EventBroker->Process<Renderer>();
|
||||||
InputUpdate(dt);
|
InputUpdate(dt);
|
||||||
m_EventBroker->Process<ImGuiRenderPass>();
|
|
||||||
m_ImGuiRenderPass->Update(dt);
|
m_ImGuiRenderPass->Update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user