MAJOR BREAKING CHANGE: EntityID 0 is now a valid entity. Use EntityID_Invalid as sentry for checks!

Also contains inseparable editor changes.
This commit is contained in:
2016-01-11 10:26:45 +01:00
parent 6adc98eea5
commit 39dd27726d
9 changed files with 238 additions and 118 deletions
+177 -85
View File
@@ -9,6 +9,7 @@ EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
m_Enabled = config->Get<bool>("Debug.EditorEnabled", false);
m_Visible = m_Enabled;
m_DefaultEntityDir = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
if (!m_Enabled) {
return;
@@ -44,6 +45,35 @@ void EditorSystem::Update(World* world, double dt)
}
}
boost::filesystem::path EditorSystem::openDialog(boost::filesystem::path defaultPath)
{
namespace bfs = boost::filesystem;
auto absolutePath = bfs::absolute(defaultPath);
nfdchar_t* outPath = nullptr;
nfdresult_t result = NFD_OpenDialog(NULL, absolutePath.string().c_str(), &outPath);
if (result == NFD_ERROR) {
LOG_ERROR("NFD Error: %s", NFD_GetError());
return bfs::path();
}
return bfs::absolute(outPath);
}
boost::filesystem::path EditorSystem::saveDialog(boost::filesystem::path defaultPath)
{
namespace bfs = boost::filesystem;
auto absolutePath = bfs::absolute(defaultPath);
nfdchar_t* outPath = nullptr;
nfdresult_t result = NFD_SaveDialog(NULL, absolutePath.string().c_str(), &outPath);
if (result == NFD_ERROR) {
LOG_ERROR("NFD Error: %s", NFD_GetError());
return bfs::path();
}
return bfs::absolute(outPath);
}
bool EditorSystem::OnInputCommand(const Events::InputCommand& e)
{
if (e.Command == "ToggleEditor" && e.Value > 0) {
@@ -81,17 +111,24 @@ bool EditorSystem::OnMousePress(const Events::MousePress& e)
bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
{
if (m_Widget == 0) {
if (m_Widget == EntityID_Invalid) {
return false;
}
if (m_Selection == EntityID_Invalid) {
return false;
}
if (m_Selection == m_Widget) {
return false;
}
// TODO: No widgets for root entity until widgets reside in thier own world,
// or the widgets will move relative to the root entity being moved, which is WEEEIRD.
if (m_Selection == 0) {
return false;
}
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
glm::vec3 widgetOrientation = widgetTransform["Orientation"];
glm::quat totalOrientation = m_Renderer->Camera()->Orientation() * glm::inverse(glm::quat(widgetOrientation));
glm::quat totalOrientation = m_Renderer->Camera()->Orientation() * glm::inverse(glm::quat(widgetOrientation));
int width;
int height;
@@ -122,9 +159,9 @@ bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
if (m_WidgetSpace == WidgetSpace::Global) {
EntityID parent = m_World->GetParent(m_Selection);
glm::quat inverseParentOrientation;
if (parent != 0) {
//if (parent != 0) {
inverseParentOrientation = glm::inverse(RenderQueueFactory::AbsoluteOrientation(m_World, parent));
}
//}
(glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Position"] += inverseParentOrientation * movement;
} else if (m_WidgetSpace == WidgetSpace::Local) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
@@ -138,12 +175,12 @@ bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
if (m_WidgetSpace == WidgetSpace::Global) {
EntityID parent = m_World->GetParent(m_Selection);
glm::quat parentOrientation;
if (parent != 0) {
parentOrientation = RenderQueueFactory::AbsoluteOrientation(m_World, parent);
}
//if (parent != 0) {
// parentOrientation = RenderQueueFactory::AbsoluteOrientation(m_World, parent);
//}
glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"];
//glm::quat currentOrientation = RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection);
glm::quat currentOrientation = parentOrientation * glm::quat(selectionOrientation);
glm::quat currentOrientation = RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection);
//glm::quat currentOrientation = parentOrientation * glm::quat(selectionOrientation);
glm::quat deltaOrientation(finalMovement);
selectionOrientation = glm::eulerAngles(glm::inverse(parentOrientation) * (deltaOrientation * currentOrientation));
} else if (m_WidgetSpace == WidgetSpace::Local) {
@@ -204,9 +241,10 @@ bool EditorSystem::OnPicking(const Events::Picking& e)
auto result = e.Pick(pos);
EntityID entity = result.Entity;
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
// ???
} else {
LOG_INFO("Selected %i", entity);
if (entity != 0) {
if (entity != EntityID_Invalid) {
EntityID parent = m_World->GetParent(entity);
if (parent == m_Widget) {
m_WidgetCurrentAxis = glm::vec3(
@@ -221,11 +259,12 @@ bool EditorSystem::OnPicking(const Events::Picking& e)
//widgetTransform["Position"] = (glm::vec3)selectionTransform["Position"];
} else {
ImGui::SetActiveID(0, nullptr);
m_Selection = entity;
if (m_WidgetMode == WidgetMode::None) {
m_WidgetMode = WidgetMode::Translate;
}
setWidgetMode(m_WidgetMode);
m_Selection = entity;
}
} else {
m_Selection = 0;
}
}
}
@@ -240,9 +279,10 @@ bool EditorSystem::OnFileDropped(const Events::FileDropped& e)
return true;
}
void EditorSystem::updateWidget()
void EditorSystem::createWidget()
{
if (m_Widget == 0) {
if (m_Widget == EntityID_Invalid) {
m_Widget = m_World->CreateEntity();
m_World->AttachComponent(m_Widget, "Transform");
m_WidgetX = m_World->CreateEntity(m_Widget);
@@ -269,10 +309,20 @@ void EditorSystem::updateWidget()
m_WidgetOrigin = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetOrigin, "Transform");
m_World->AttachComponent(m_WidgetOrigin, "Model");
setWidgetMode(WidgetMode::Translate);
setWidgetMode(WidgetMode::None);
}
}
void EditorSystem::updateWidget()
{
if (m_Widget == EntityID_Invalid) {
return;
}
if (m_Selection == m_Widget) {
return;
}
if (m_Selection != 0) {
if (m_Selection != EntityID_Invalid) {
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
glm::vec3 selectionPosition = RenderQueueFactory::AbsolutePosition(m_World, m_Selection);
widgetTransform["Position"] = selectionPosition;
@@ -284,7 +334,7 @@ void EditorSystem::updateWidget()
void EditorSystem::setWidgetMode(WidgetMode newMode)
{
if (m_Widget == 0) {
if (m_Widget == EntityID_Invalid) {
return;
}
@@ -309,7 +359,7 @@ void EditorSystem::setWidgetMode(WidgetMode newMode)
m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = true;
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = true;
}
if (m_Selection != 0) {
if (m_Selection != EntityID_Invalid) {
if (m_WidgetSpace == WidgetSpace::Local) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
@@ -321,7 +371,7 @@ void EditorSystem::setWidgetMode(WidgetMode newMode)
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/ScaleWidgetZ.obj";
m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = true;
m_World->GetComponent(m_WidgetOrigin, "Model")["Resource"] = "Models/ScaleWidgetOrigin.obj";
if (m_Selection != 0) {
if (m_Selection != EntityID_Invalid) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
}
@@ -329,7 +379,7 @@ void EditorSystem::setWidgetMode(WidgetMode newMode)
m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/RotationWidgetX.obj";
m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/RotationWidgetY.obj";
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/RotationWidgetZ.obj";
if (m_Selection != 0) {
if (m_Selection != EntityID_Invalid) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
if (m_WidgetSpace == WidgetSpace::Local) {
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
@@ -339,7 +389,6 @@ void EditorSystem::setWidgetMode(WidgetMode newMode)
m_WidgetMode = newMode;
}
void EditorSystem::setWidgetSpace(WidgetSpace space)
{
m_WidgetSpace = space;
@@ -348,16 +397,23 @@ void EditorSystem::setWidgetSpace(WidgetSpace space)
void EditorSystem::drawUI(World* world, double dt)
{
namespace bfs = boost::filesystem;
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")) { }
//if (ImGui::MenuItem("New")) { }
if (ImGui::MenuItem("Import", "Ctrl+O")) {
fileImport(world);
}
if (ImGui::MenuItem("Save", "Ctrl+S")) {
fileSave(world);
}
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) {
fileSaveAs(world);
}
ImGui::Separator();
if (ImGui::MenuItem("Close Editor", "F1")) { }
@@ -392,7 +448,7 @@ void EditorSystem::drawUI(World* world, double dt)
std::string title = std::string("Components #") + std::to_string(m_Selection) + std::string("###Components");
if (ImGui::Begin(title.c_str())) {
if (m_Selection != 0) {
if (m_Selection != EntityID_Invalid) {
auto& pools = world->GetComponentPools();
std::vector<const char*> componentTypes;
@@ -492,74 +548,81 @@ void EditorSystem::drawUI(World* world, double dt)
}
ImGui::End();
if (ImGui::Begin("Entitites")) {
static EntityID draggingEntity = 0;
if (ImGui::Begin("Entities")) {
auto entityChildren = world->GetEntityChildren();
std::function<void(EntityID)> recurse = [&](EntityID parent) {
auto range = entityChildren.equal_range(parent);
for (auto it = range.first; it != range.second; it++) {
ImVec2 pos = ImGui::GetCursorScreenPos();
float width = ImGui::GetContentRegionAvailWidth();
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13));
auto window = ImGui::GetCurrentWindow();
if (m_Selection == it->second) {
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
}
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(it->second)).c_str());
bool hovered = false;
bool held = false;
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
m_Selection = it->second;
}
if (held) {
ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
if (draggingEntity == 0) {
draggingEntity = it->second;
LOG_DEBUG("Started drag of entity %i", draggingEntity);
}
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", draggingEntity);
ImGui::End();
}
}
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
if (ImGui::TreeNode((std::string("#") + std::to_string(it->second)).c_str())) {
if (draggingEntity != 0 && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
LOG_DEBUG("Changed parent of %i to %i", draggingEntity, it->second);
changeParent(draggingEntity, it->second);
draggingEntity = 0;
}
if (ImGui::BeginPopupContextItem("item context menu")) {
if (ImGui::Button("Add")) {
EntityID entity = world->CreateEntity(it->second);
world->AttachComponent(entity, "Transform");
}
ImGui::SameLine();
if (ImGui::Button("Delete")) {
world->DeleteEntity(it->second);
ImGui::CloseCurrentPopup();
if (m_Selection == it->second) {
m_Selection = 0;
}
}
ImGui::EndPopup();
}
if (createEntityNode(world, it->second)) {
recurse(it->second);
ImGui::TreePop();
}
}
};
recurse(0);
recurse(EntityID_Invalid);
}
ImGui::End();
}
bool EditorSystem::createEntityNode(World* world, EntityID entity)
{
ImVec2 pos = ImGui::GetCursorScreenPos();
float width = ImGui::GetContentRegionAvailWidth();
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13));
auto window = ImGui::GetCurrentWindow();
if (m_Selection == entity) {
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
}
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity)).c_str());
bool hovered = false;
bool held = false;
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
m_Selection = 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();
}
}
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
if (ImGui::TreeNode((std::string("#") + std::to_string(entity)).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("item context menu")) {
if (ImGui::Button("Add")) {
EntityID entity = world->CreateEntity(entity);
world->AttachComponent(entity, "Transform");
}
ImGui::SameLine();
if (ImGui::Button("Delete")) {
world->DeleteEntity(entity);
ImGui::CloseCurrentPopup();
if (m_Selection == entity) {
m_Selection = EntityID_Invalid;
}
}
ImGui::EndPopup();
}
return true;
} else {
return false;
}
}
bool EditorSystem::createDeleteButton(std::string componentType)
{
float width = ImGui::GetContentRegionAvailWidth();
@@ -594,3 +657,32 @@ void EditorSystem::changeParent(EntityID entity, EntityID newParent)
m_World->SetParent(entity, newParent);
}
void EditorSystem::fileImport(World* world)
{
m_CurrentFile = openDialog(m_DefaultEntityDir);
auto file = ResourceManager::Load<EntityFile>(m_CurrentFile.string());
//EntityFilePreprocessor fpp(file);
//fpp.RegisterComponents(world);
EntityFileParser fp(file);
fp.MergeEntities(world);
createWidget();
updateWidget();
}
void EditorSystem::fileSave(World* world)
{
if (boost::filesystem::exists(m_CurrentFile)) {
EntityFileWriter writer(m_CurrentFile.string());
writer.WriteWorld(world);
} else {
fileSaveAs(world);
}
}
void EditorSystem::fileSaveAs(World* world)
{
auto filePath = saveDialog(m_DefaultEntityDir);
EntityFileWriter writer(filePath.string());
writer.WriteWorld(world);
}