Editor entity reparenting.

This commit is contained in:
2016-01-18 21:18:23 +01:00
parent 1760f9dfb1
commit 3fc44e944c
7 changed files with 140 additions and 55 deletions
+1 -1
Submodule assets updated: a3c92ac876...a1bb17dbe0
+12 -4
View File
@@ -13,13 +13,13 @@
#include "../Core/EventBroker.h"
#include "../Core/World.h"
#include "../Core/EntityWrapper.h"
#include "../Core/ResourceManager.h"
#include "../Rendering/Texture.h"
class EditorGUI
{
public:
EditorGUI(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
EditorGUI(EventBroker* eventBroker);
void Draw(World* world);
@@ -46,6 +46,9 @@ public:
// Called when the user means to delete an entity.
typedef std::function<void(EntityWrapper)> OnEntityDelete_t;
void SetEntityDeleteCallback(OnEntityDelete_t f) { m_OnEntityDelete = f; }
// Called when the user means to change the parent of an entity.
typedef std::function<void(EntityWrapper, EntityWrapper)> OnEntityChangeParent_t;
void SetEntityChangeParentCallback(OnEntityChangeParent_t f) { m_OnEntityChangeParent = f; }
// Called when the user means to attach a new component to an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnComponentAttach_t;
void SetComponentAttachCallback(OnComponentAttach_t f) { m_OnComponentAttach = f; }
@@ -62,6 +65,7 @@ private:
// State variables
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
std::unordered_map<EntityWrapper, boost::filesystem::path> m_EntityFiles;
EntityWrapper m_CurrentlyDragging = EntityWrapper::Invalid;
std::string m_LastErrorMessage;
// Callbacks
@@ -70,21 +74,25 @@ private:
OnEntitySave_t m_OnEntitySave = nullptr;
OnEntityCreate_t m_OnEntityCreate = nullptr;
OnEntityDelete_t m_OnEntityDelete = nullptr;
OnEntityChangeParent_t m_OnEntityChangeParent = nullptr;
OnComponentAttach_t m_OnComponentAttach = nullptr;
OnComponentDelete_t m_OnComponentDelete = nullptr;
// Utility functions
boost::filesystem::path fileOpenDialog();
boost::filesystem::path fileSaveDialog();
const std::string formatEntityName(EntityWrapper entity);
// Entity file handling methods
void entityImport(World* world);
void entitySave(EntityWrapper entity);
void entitySave(EntityWrapper entity, bool saveAs = false);
void entityCreate(World* world, EntityWrapper parent);
void entityDelete(EntityWrapper entity);
void entityChangeParent(EntityWrapper entity, EntityWrapper parent);
// UI drawing methods
void drawMenu();
void drawTools();
void drawEntities(World* world);
void drawEntitiesRecursive(World* world, EntityID parent);
bool drawEntityNode(EntityWrapper entity);
+1
View File
@@ -40,6 +40,7 @@ private:
void OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath);
EntityWrapper OnEntityCreate(EntityWrapper parent);
void OnEntityDelete(EntityWrapper entity);
void OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent);
void OnComponentAttach(EntityWrapper entity, const std::string& componentType);
void OnComponentDelete(EntityWrapper entity, const std::string& componentType);
};
-1
View File
@@ -50,7 +50,6 @@ ComponentWrapper ComponentPool::GetByEntity(EntityID ent)
return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent));
}
bool ComponentPool::KnowsEntity(EntityID ent)
{
return m_EntityToComponent.find(ent) != m_EntityToComponent.end();
+113 -42
View File
@@ -1,9 +1,16 @@
#include "Editor/EditorGUI.h"
EditorGUI::EditorGUI(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{
}
void EditorGUI::Draw(World* world)
{
ImGui::ShowTestWindow();
drawMenu();
drawTools();
drawEntities(world);
drawComponents(m_CurrentSelection);
}
@@ -21,6 +28,34 @@ void EditorGUI::drawMenu()
}
void EditorGUI::drawTools()
{
if (!ImGui::Begin("Tools", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) {
return;
}
GLuint translateIcon = 0;
try {
translateIcon = ResourceManager::Load<Texture>("Textures/Icons/shaft.png")->m_Texture;
} catch (const std::exception&) { }
GLuint rotateIcon = 0;
try {
rotateIcon = ResourceManager::Load<Texture>("Textures/Icons/circulararrows3.png")->m_Texture;
} catch (const std::exception&) { }
GLuint scaleIcon = 0;
try {
scaleIcon = ResourceManager::Load<Texture>("Textures/Icons/increase10.png")->m_Texture;
} catch (const std::exception&) { }
ImGui::ImageButton((void*)translateIcon, ImVec2(24, 24));
ImGui::SameLine();
ImGui::ImageButton((void*)rotateIcon, ImVec2(24, 24));
ImGui::SameLine();
ImGui::ImageButton((void*)scaleIcon, ImVec2(24, 24));
ImGui::End();
}
void EditorGUI::drawEntities(World* world)
{
if (!ImGui::Begin("Entities")) {
@@ -61,6 +96,7 @@ void EditorGUI::drawEntitiesRecursive(World* world, EntityID parent)
bool EditorGUI::drawEntityNode(EntityWrapper entity)
{
// Custom button hitbox to select entities on top of tree node
ImVec2 pos = ImGui::GetCursorScreenPos();
float width = ImGui::GetContentRegionAvailWidth();
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 14));
@@ -75,53 +111,53 @@ bool EditorGUI::drawEntityNode(EntityWrapper entity)
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
SelectEntity(entity);
}
//if (held) {
// ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
// if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
// if (m_UIDraggingEntity == EntityID_Invalid) {
// m_UIDraggingEntity = entity;
// LOG_DEBUG("Started drag of entity %i", m_UIDraggingEntity);
// }
// ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
// ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
// ImGui::Text("#%i", m_UIDraggingEntity);
// ImGui::End();
// }
//}
// Compose title
std::stringstream nodeTitle;
const std::string& entityName = entity.World->GetName(entity);
if (!entityName.empty()) {
nodeTitle << entityName;
} else {
nodeTitle << "#" << entity.ID;
// Handle entity dragging
if (held) {
ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
if (m_CurrentlyDragging == EntityWrapper::Invalid) {
m_CurrentlyDragging = entity;
LOG_DEBUG("Started dragging %i", entity.ID);
}
if (m_EntityFiles.count(entity) == 1) {
nodeTitle << " (" << m_EntityFiles.at(entity).filename().string() << ")";
ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
ImGui::Text(formatEntityName(entity).c_str());
ImGui::End();
}
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
if (ImGui::TreeNode(nodeTitle.str().c_str())) {
//if (m_UIDraggingEntity != EntityID_Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
// LOG_DEBUG("Changed parent of %i to %i", m_UIDraggingEntity, entity);
// changeParent(m_UIDraggingEntity, entity);
// m_UIDraggingEntity = EntityID_Invalid;
//}
if (ImGui::BeginPopupContextItem("entity context menu")) {
if (ImGui::Button("Save")) {
} else if (m_CurrentlyDragging == entity) {
LOG_DEBUG("Stopped dragging %i", entity.ID);
m_CurrentlyDragging = EntityWrapper::Invalid;
}
// Entity context menu
std::string contextMenuUniqueID = std::string("EntityContextMenu") + std::to_string(entity.ID);
if (hovered && ImGui::IsMouseClicked(1)) {
ImGui::OpenPopup(contextMenuUniqueID.c_str());
}
if (ImGui::BeginPopup(contextMenuUniqueID.c_str())) {
ImGui::TextDisabled(formatEntityName(entity).c_str());
if (ImGui::MenuItem("Save", "Ctrl+S")) {
entitySave(entity);
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Delete")) {
} else
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) {
entitySave(entity, true);
} else
if (ImGui::MenuItem("Delete", "Del")) {
entityDelete(entity);
ImGui::CloseCurrentPopup();
} else
if (ImGui::MenuItem("Move to root")) {
entityChangeParent(entity, EntityWrapper::Invalid);
}
drawModals();
ImGui::EndPopup();
}
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
if (ImGui::TreeNode(formatEntityName(entity).c_str())) {
// Handle drop events for reparenting
if (m_CurrentlyDragging != EntityWrapper::Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
entityChangeParent(m_CurrentlyDragging, entity);
m_CurrentlyDragging = EntityWrapper::Invalid;
}
return true;
} else {
return false;
@@ -133,7 +169,7 @@ void EditorGUI::drawComponents(EntityWrapper entity)
std::stringstream title;
title << "Components";
if (entity.Valid()) {
title << " #" << entity.ID << "###Components";
title << formatEntityName(entity) << "###Components";
}
if (!ImGui::Begin(title.str().c_str())) {
ImGui::End();
@@ -380,6 +416,7 @@ bool EditorGUI::createDeleteButton(const std::string& componentType)
return pressed;
}
boost::filesystem::path EditorGUI::fileOpenDialog()
{
namespace bfs = boost::filesystem;
@@ -412,6 +449,28 @@ boost::filesystem::path EditorGUI::fileSaveDialog()
}
}
const std::string EditorGUI::formatEntityName(EntityWrapper entity)
{
if (!entity.Valid()) {
return "EntityID_Invalid";
}
std::stringstream name;
const std::string& entityName = entity.World->GetName(entity);
if (!entityName.empty()) {
name << entityName;
} else {
name << "#" << entity.ID;
}
if (m_EntityFiles.count(entity) == 1) {
name << " (" << m_EntityFiles.at(entity).filename().string() << ")";
}
return name.str();
}
void EditorGUI::entityImport(World* world)
{
boost::filesystem::path filePath = fileOpenDialog();
@@ -428,10 +487,10 @@ void EditorGUI::entityImport(World* world)
}
}
void EditorGUI::entitySave(EntityWrapper entity)
void EditorGUI::entitySave(EntityWrapper entity, bool saveAs /* = false */)
{
boost::filesystem::path filePath;
if (m_EntityFiles.count(entity) == 1) {
if (!saveAs && m_EntityFiles.count(entity) == 1) {
filePath = m_EntityFiles.at(entity);
} else {
filePath = fileSaveDialog();
@@ -472,3 +531,15 @@ void EditorGUI::entityDelete(EntityWrapper entity)
SelectEntity(EntityWrapper::Invalid);
}
}
void EditorGUI::entityChangeParent(EntityWrapper entity, EntityWrapper parent)
{
if (entity == parent) {
return;
}
if (m_OnEntityChangeParent != nullptr) {
m_OnEntityChangeParent(entity, parent);
LOG_DEBUG("Changed parent of %i to %i", entity.ID, parent.ID);
}
}
+6
View File
@@ -25,6 +25,7 @@ EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer, Render
m_EditorGUI->SetEntitySaveCallback(std::bind(&EditorSystem::OnEntitySave, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetEntityCreateCallback(std::bind(&EditorSystem::OnEntityCreate, this, std::placeholders::_1));
m_EditorGUI->SetEntityDeleteCallback(std::bind(&EditorSystem::OnEntityDelete, this, std::placeholders::_1));
m_EditorGUI->SetEntityChangeParentCallback(std::bind(&EditorSystem::OnEntityChangeParent, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetComponentAttachCallback(std::bind(&EditorSystem::OnComponentAttach, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetComponentDeleteCallback(std::bind(&EditorSystem::OnComponentDelete, this, std::placeholders::_1, std::placeholders::_2));
@@ -79,6 +80,11 @@ void EditorSystem::OnEntityDelete(EntityWrapper entity)
entity.World->DeleteEntity(entity.ID);
}
void EditorSystem::OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent)
{
entity.World->SetParent(entity.ID, parent.ID);
}
void EditorSystem::OnComponentAttach(EntityWrapper entity, const std::string& componentType)
{
entity.World->AttachComponent(entity.ID, componentType);
+2 -2
View File
@@ -105,7 +105,7 @@ void ImGuiRenderPass::Draw()
if (pcmd->UserCallback) {
pcmd->UserCallback(cmd_list, pcmd);
} else {
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glBindTexture(GL_TEXTURE_2D, (GLuint)pcmd->TextureId);
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
}
@@ -271,7 +271,7 @@ bool ImGuiRenderPass::createFontsTexture()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
io.Fonts->TexID = (void*)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);