Added MVP for prefab editor window and made the whole editor modular to support multi-scene editing
This commit is contained in:
@@ -41,7 +41,6 @@ public:
|
||||
EditorSelection(const Nuake::Entity& entity)
|
||||
{
|
||||
Type = EditorSelectionType::Entity;
|
||||
Nuake::Engine::GetCurrentScene()->m_SceneRenderer->mOutlineEntityID = (uint32_t)entity.GetHandle();
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@ public:
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
Vector3 position = component.GetLocalPosition();
|
||||
ImGuiHelper::DrawVec3("Translation", &position);
|
||||
ImGuiHelper::DrawVec3("Translation##" + entity.GetHandle(), &position);
|
||||
if (position != component.GetLocalPosition())
|
||||
component.SetLocalPosition(position);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0));
|
||||
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetTranslation";
|
||||
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetTranslation" + std::to_string(entity.GetHandle());
|
||||
if (ImGui::Button(resetLabel.c_str()))
|
||||
component.SetLocalPosition(Vector3(0, 0, 0));
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
Vector3 eulerDegreesOld = glm::degrees(glm::eulerAngles(currentRotation));
|
||||
|
||||
// Draw the ImGui widget for rotation
|
||||
ImGuiHelper::DrawVec3("Rotation", &eulerDegreesOld);
|
||||
ImGuiHelper::DrawVec3("Rotation##" + entity.GetHandle(), &eulerDegreesOld);
|
||||
|
||||
// Calculate the delta in Euler angles
|
||||
Vector3 eulerDelta = eulerDegreesOld - glm::degrees(glm::eulerAngles(currentRotation));
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0));
|
||||
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetRotation";
|
||||
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetRotation" + std::to_string(entity.GetHandle());
|
||||
if (ImGui::Button(resetLabel.c_str()))
|
||||
{
|
||||
component.SetLocalRotation(Quat(1, 0, 0, 0));
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
Vector3 localScale = component.GetLocalScale();
|
||||
ImGuiHelper::DrawVec3("Scale", &localScale);
|
||||
ImGuiHelper::DrawVec3("Scale##" + entity.GetHandle(), &localScale);
|
||||
|
||||
if (localScale != component.GetLocalScale())
|
||||
component.SetLocalScale(localScale);
|
||||
@@ -105,7 +105,7 @@ public:
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0));
|
||||
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetScale";
|
||||
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetScale" + std::to_string(entity.GetHandle());
|
||||
if (ImGui::Button(resetLabel.c_str()))
|
||||
component.SetLocalScale(Vector3(1, 1, 1));
|
||||
|
||||
|
||||
2
Editor/src/UIComponents/EntityTree.h
Normal file
2
Editor/src/UIComponents/EntityTree.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
||||
@@ -307,6 +307,11 @@ namespace Nuake {
|
||||
const auto& editorCam = Engine::GetCurrentScene()->GetCurrentCamera();
|
||||
Matrix4 cameraView = editorCam->GetTransform();
|
||||
Matrix4 cameraProjection = editorCam->GetPerspective();
|
||||
static Vector3 camPreviousPos = Engine::GetCurrentScene()->m_EditorCamera->Translation;
|
||||
static Vector3 camNewPos = Vector3(0, 0, 0);
|
||||
|
||||
Vector3 camDelta = camNewPos - camPreviousPos;
|
||||
Vector3 previousGlobalPos = transform[3];
|
||||
|
||||
// Imguizmo calculates the delta from the gizmo,
|
||||
ImGuizmo::Manipulate(
|
||||
@@ -323,6 +328,15 @@ namespace Nuake {
|
||||
// we need to multiply by the inverse of the parent's global transform in order to revert
|
||||
// the changes from the parent transform.
|
||||
Matrix4 localTransform = Matrix4(transform);
|
||||
|
||||
Vector3 newGlobalPos = transform[3];
|
||||
if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
|
||||
{
|
||||
Vector3 positionDelta = newGlobalPos - previousGlobalPos;
|
||||
Engine::GetCurrentScene()->m_EditorCamera->Translation += positionDelta;
|
||||
camNewPos = Engine::GetCurrentScene()->m_EditorCamera->Translation;
|
||||
}
|
||||
|
||||
ParentComponent& parent = Selection.Entity.GetComponent<ParentComponent>();
|
||||
if (parent.HasParent)
|
||||
{
|
||||
@@ -861,7 +875,7 @@ namespace Nuake {
|
||||
|
||||
// Check if entity is already parent.
|
||||
ParentComponent& parentPayload = payload_entity.GetComponent<ParentComponent>();
|
||||
if (!EntityContainsItself(payload_entity, e) && parentPayload.Parent != e && std::count(parent.Children.begin(), parent.Children.end(), payload_entity) == 0)
|
||||
if (!payload_entity.EntityContainsItself(payload_entity, e) && parentPayload.Parent != e && std::count(parent.Children.begin(), parent.Children.end(), payload_entity) == 0)
|
||||
{
|
||||
if (parentPayload.HasParent)
|
||||
{
|
||||
@@ -2287,26 +2301,6 @@ namespace Nuake {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool EditorInterface::EntityContainsItself(Entity source, Entity target)
|
||||
{
|
||||
ParentComponent& targeParentComponent = target.GetComponent<ParentComponent>();
|
||||
if (!targeParentComponent.HasParent)
|
||||
return false;
|
||||
|
||||
Entity currentParent = target.GetComponent<ParentComponent>().Parent;
|
||||
while (currentParent != source)
|
||||
{
|
||||
if (currentParent.GetComponent<ParentComponent>().HasParent)
|
||||
currentParent = currentParent.GetComponent<ParentComponent>().Parent;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (currentParent == source)
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LogErrors = true;
|
||||
bool LogWarnings = true;
|
||||
bool LogDebug = true;
|
||||
@@ -2315,7 +2309,7 @@ namespace Nuake {
|
||||
{
|
||||
if (ImGui::Begin("Logger"))
|
||||
{
|
||||
if (ImGui::Button("Clear"))
|
||||
if (ImGui::Button("Clear", ImVec2(60, 28)))
|
||||
{
|
||||
Logger::ClearLogs();
|
||||
SetStatusMessage("Logs cleared.");
|
||||
@@ -2323,77 +2317,78 @@ namespace Nuake {
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginMenu("Edit"))
|
||||
if (ImGui::Button(ICON_FA_FILTER, ImVec2(30, 28)))
|
||||
{
|
||||
if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
|
||||
if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Project Settings", ""))
|
||||
{
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
ImGui::OpenPopup("filter_popup");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
|
||||
|
||||
bool isEnabled = LogErrors;
|
||||
if (isEnabled)
|
||||
if (ImGui::BeginPopup("filter_popup"))
|
||||
{
|
||||
Color color = Engine::GetProject()->Settings.PrimaryColor;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
|
||||
}
|
||||
ImGui::SeparatorText("Filters");
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
|
||||
|
||||
if (ImGui::Button(ICON_FA_BAN, ImVec2(30, 28)))
|
||||
{
|
||||
LogErrors = !LogErrors;
|
||||
}
|
||||
if (isEnabled)
|
||||
{
|
||||
Color color = Engine::GetProject()->Settings.PrimaryColor;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
|
||||
}
|
||||
|
||||
if (ImGui::Button((std::string(ICON_FA_BAN) + " Error").c_str()))
|
||||
{
|
||||
LogErrors = !LogErrors;
|
||||
}
|
||||
|
||||
UI::Tooltip("Display Errors");
|
||||
if (isEnabled)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
isEnabled = LogWarnings;
|
||||
if (isEnabled)
|
||||
{
|
||||
Color color = Engine::GetProject()->Settings.PrimaryColor;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
|
||||
}
|
||||
|
||||
if (ImGui::Button((std::string(ICON_FA_EXCLAMATION_TRIANGLE) + " Warning").c_str()))
|
||||
{
|
||||
LogWarnings = !LogWarnings;
|
||||
}
|
||||
|
||||
UI::Tooltip("Display Warnings");
|
||||
if (isEnabled)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
isEnabled = LogDebug;
|
||||
if (isEnabled)
|
||||
{
|
||||
Color color = Engine::GetProject()->Settings.PrimaryColor;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
|
||||
}
|
||||
|
||||
if (ImGui::Button((std::string(ICON_FA_INFO) + " Info").c_str()))
|
||||
{
|
||||
LogDebug = !LogDebug;
|
||||
}
|
||||
|
||||
UI::Tooltip("Display Verbose");
|
||||
if (isEnabled)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
UI::Tooltip("Display Errors");
|
||||
if (isEnabled)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
isEnabled = LogWarnings;
|
||||
if (isEnabled)
|
||||
{
|
||||
Color color = Engine::GetProject()->Settings.PrimaryColor;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
|
||||
}
|
||||
|
||||
if (ImGui::Button(ICON_FA_EXCLAMATION_TRIANGLE, ImVec2(30, 28)))
|
||||
{
|
||||
LogWarnings = !LogWarnings;
|
||||
}
|
||||
|
||||
UI::Tooltip("Display Warnings");
|
||||
if (isEnabled)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
isEnabled = LogDebug;
|
||||
if (isEnabled)
|
||||
{
|
||||
Color color = Engine::GetProject()->Settings.PrimaryColor;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
|
||||
}
|
||||
|
||||
if (ImGui::Button(ICON_FA_INFO, ImVec2(30, 28)))
|
||||
{
|
||||
LogDebug = !LogDebug;
|
||||
}
|
||||
|
||||
UI::Tooltip("Display Verbose");
|
||||
if (isEnabled)
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -2416,8 +2411,6 @@ namespace Nuake {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleVar(2);
|
||||
//ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
//if (ImGui::BeginChild("Log window", ImGui::GetContentRegionAvail(), false))
|
||||
//{
|
||||
@@ -2884,6 +2877,19 @@ namespace Nuake {
|
||||
}
|
||||
}
|
||||
|
||||
void EditorInterface::OpenPrefabWindow(const std::string& prefabPath)
|
||||
{
|
||||
if (!FileSystem::FileExists(prefabPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<Prefab> newPrefab = CreateRef<Prefab>();
|
||||
newPrefab->Path = prefabPath;
|
||||
|
||||
prefabEditors.push_back(CreateRef<PrefabEditorWindow>(newPrefab));
|
||||
}
|
||||
|
||||
void NewProject()
|
||||
{
|
||||
if (Engine::GetProject() && Engine::GetProject()->FileExist())
|
||||
@@ -3265,6 +3271,18 @@ namespace Nuake {
|
||||
|
||||
pInterface.m_CurrentProject = Engine::GetProject();
|
||||
|
||||
uint32_t selectedEntityID;
|
||||
if (Selection.Type == EditorSelectionType::Entity && Selection.Entity.IsValid())
|
||||
{
|
||||
selectedEntityID = Selection.Entity.GetHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedEntityID = 0;
|
||||
}
|
||||
|
||||
Nuake::Engine::GetCurrentScene()->m_SceneRenderer->mOutlineEntityID = selectedEntityID;
|
||||
|
||||
m_ProjectSettingsWindow->Draw();
|
||||
|
||||
m_DemoWindow.Draw();
|
||||
@@ -3292,6 +3310,10 @@ namespace Nuake {
|
||||
|
||||
DrawStatusBar();
|
||||
|
||||
for (auto& prefabEditors : prefabEditors)
|
||||
{
|
||||
prefabEditors->Draw();
|
||||
}
|
||||
//pInterface.DrawEntitySettings();
|
||||
DrawViewport();
|
||||
DrawSceneTree();
|
||||
@@ -3301,6 +3323,7 @@ namespace Nuake {
|
||||
filesystem->Draw();
|
||||
filesystem->DrawDirectoryExplorer();
|
||||
|
||||
|
||||
if (isNewProject)
|
||||
{
|
||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||
@@ -3351,7 +3374,7 @@ namespace Nuake {
|
||||
isControllingCamera = editorCam->Update(ts, m_IsHoveringViewport && m_IsViewportFocused);
|
||||
|
||||
const bool entityIsSelected = Selection.Type == EditorSelectionType::Entity && Selection.Entity.IsValid();
|
||||
if (editorCam->IsFlying() && entityIsSelected && Input::IsKeyPressed(Key::F))
|
||||
if (entityIsSelected && Input::IsKeyPressed(Key::F))
|
||||
{
|
||||
editorCam->IsMoving = true;
|
||||
editorCam->TargetPos = Selection.Entity.GetComponent<TransformComponent>().GetGlobalPosition();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <src/Scripting/ScriptingEngineNet.h>
|
||||
#include "ProjectSettings/ProjectSettingsWindow.h"
|
||||
#include "PrefabEditor/PrefabEditorWindow.h"
|
||||
|
||||
|
||||
using namespace NuakeEditor;
|
||||
@@ -31,6 +32,7 @@ namespace Nuake
|
||||
{
|
||||
private:
|
||||
std::vector<CompilationError> errors;
|
||||
std::vector<Ref<PrefabEditorWindow>> prefabEditors;
|
||||
Ref<Scene> SceneSnapshot;
|
||||
static NuakeEditor::CommandBuffer* mCommandBuffer;
|
||||
|
||||
@@ -93,9 +95,9 @@ namespace Nuake
|
||||
void DrawSceneTree();
|
||||
void DrawLogger();
|
||||
void DrawProjectSettings();
|
||||
bool EntityContainsItself(Entity ent1, Entity ent2);
|
||||
void Overlay();
|
||||
|
||||
void OpenPrefabWindow(const std::string& prefabPath);
|
||||
bool ShouldDrawAxis() const { return m_DrawAxis; }
|
||||
bool ShouldDrawCollision() const { return m_DebugCollisions; }
|
||||
bool ShouldDrawNavMesh() const { return m_DrawNavMesh; }
|
||||
|
||||
@@ -66,9 +66,9 @@ void EditorSelectionPanel::ResolveFile(Ref<Nuake::File> file)
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSelectionPanel::Draw(EditorSelection selection)
|
||||
void EditorSelectionPanel::Draw(EditorSelection selection, const std::string& id)
|
||||
{
|
||||
if (ImGui::Begin("Properties"))
|
||||
if (ImGui::Begin(std::string("Properties##" + id).c_str()))
|
||||
{
|
||||
switch (selection.Type)
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ private:
|
||||
public:
|
||||
EditorSelectionPanel();
|
||||
|
||||
void Draw(EditorSelection selection);
|
||||
void Draw(EditorSelection selection, const std::string& id = "");
|
||||
|
||||
void DrawNone();
|
||||
void DrawEntity(Nuake::Entity entity);
|
||||
|
||||
@@ -271,6 +271,9 @@ namespace Nuake
|
||||
case FileType::Solution:
|
||||
OS::OpenIn(file->GetAbsolutePath());
|
||||
break;
|
||||
case FileType::Prefab:
|
||||
this->Editor->OpenPrefabWindow(file->GetRelativePath());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
626
Editor/src/Windows/PrefabEditor/PrefabEditorWindow.cpp
Normal file
626
Editor/src/Windows/PrefabEditor/PrefabEditorWindow.cpp
Normal file
@@ -0,0 +1,626 @@
|
||||
#include "PrefabEditorWindow.h"
|
||||
|
||||
#include <src/Core/Input.h>
|
||||
#include <src/Rendering/Buffers/FrameBuffer.h>
|
||||
#include <src/Rendering/SceneRenderer.h>
|
||||
#include <src/Resource/Prefab.h>
|
||||
#include <src/Scene/Scene.h>
|
||||
#include <src/Scene/EditorCamera.h>
|
||||
#include <src/Scene/Entities/Entity.h>
|
||||
#include <src/Rendering/Textures/Texture.h>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/imgui_internal.h>
|
||||
#include <src/Scene/Components/SpriteComponent.h>
|
||||
#include <src/Scene/Components/ParticleEmitterComponent.h>
|
||||
#include <src/Scene/Components/RigidbodyComponent.h>
|
||||
#include <src/Scene/Components/BoxCollider.h>
|
||||
#include <src/Scene/Components/SphereCollider.h>
|
||||
#include <src/Scene/Components/AudioEmitterComponent.h>
|
||||
#include <src/Scene/Components/PrefabComponent.h>
|
||||
#include <src/Scene/Components/BSPBrushComponent.h>
|
||||
#include <src/Scene/Components/NetScriptComponent.h>
|
||||
#include <src/FileSystem/FileDialog.h>
|
||||
|
||||
|
||||
using namespace Nuake;
|
||||
|
||||
PrefabEditorWindow::PrefabEditorWindow(Ref<Prefab> inPrefab) :
|
||||
prefab(inPrefab)
|
||||
{
|
||||
const Vector2 defaultSize = Vector2{ 640, 360 };
|
||||
viewportFramebuffer = CreateRef<FrameBuffer>(true, defaultSize);
|
||||
viewportFramebuffer->SetTexture(CreateRef<Texture>(defaultSize, GL_RGB, GL_RGB16F, GL_FLOAT));
|
||||
|
||||
virtualScene = CreateRef<Scene>();
|
||||
virtualScene->GetEnvironment()->CurrentSkyType = SkyType::ProceduralSky;
|
||||
virtualScene->GetEnvironment()->ProceduralSkybox->SunDirection = { 0.58f, 0.34f, -0.74f };
|
||||
|
||||
Prefab::InstanceInScene(inPrefab->Path, virtualScene);
|
||||
|
||||
Ref<Texture> outputTexture = CreateRef<Texture>(defaultSize, GL_RGB);
|
||||
outputTexture->SetParameter(GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
outputTexture->SetParameter(GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
auto& previewLight = virtualScene->CreateEntity("_directionalLight").AddComponent<LightComponent>();
|
||||
previewLight.Type = LightType::Directional;
|
||||
previewLight.SetCastShadows(true);
|
||||
previewLight.SyncDirectionWithSky = true;
|
||||
previewLight.Strength = 5.5f;
|
||||
|
||||
}
|
||||
|
||||
void PrefabEditorWindow::Update(float ts)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PrefabEditorWindow::Draw()
|
||||
{
|
||||
RenderScene();
|
||||
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
||||
|
||||
ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
|
||||
ImGuiID dockspace_id = ImGui::GetID(prefab->Path.c_str());
|
||||
ImVec2 dockspace_size;
|
||||
if (!isInitialized)
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(1280, 720));
|
||||
}
|
||||
|
||||
if(ImGui::Begin(prefab->Path.c_str(), 0, window_flags))
|
||||
{
|
||||
dockspace_size = ImGui::GetContentRegionAvail();
|
||||
ImGui::DockSpace(dockspace_id, dockspace_size, dockspace_flags);
|
||||
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("File"))
|
||||
{
|
||||
ImGui::MenuItem("New", "Ctrl+N");
|
||||
ImGui::MenuItem("Open", "Ctrl+O");
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
// Programmatically dock windows using DockBuilder API
|
||||
if (!isInitialized)
|
||||
{
|
||||
isInitialized = true;
|
||||
|
||||
// Create dock layout for the embedded dockspace
|
||||
ImGui::DockBuilderRemoveNode(dockspace_id); // Clear any existing layout
|
||||
ImGui::DockBuilderAddNode(dockspace_id, dockspace_flags | ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(dockspace_id, dockspace_size);
|
||||
|
||||
// Split the dockspace into two areas: left and right
|
||||
ImGuiID dock_left_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Left, 0.25f, nullptr, &dockspace_id);
|
||||
ImGuiID dock_r_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Right, 0.66f, nullptr, &dockspace_id);
|
||||
|
||||
// Dock windows into the created nodes
|
||||
ImGui::DockBuilderDockWindow(std::string("Prefab Hierarchy## " + prefab->Path).c_str(), dock_left_id);
|
||||
ImGui::DockBuilderDockWindow(std::string("Viewport##" + prefab->Path).c_str(), dockspace_id);
|
||||
ImGui::DockBuilderDockWindow(std::string("Properties##" + prefab->Path).c_str(), dock_r_id);
|
||||
// Commit the dock layout
|
||||
ImGui::DockBuilderFinish(dockspace_id);
|
||||
}
|
||||
|
||||
if (ImGui::Begin(std::string("Prefab Hierarchy## " + prefab->Path).c_str()))
|
||||
{
|
||||
Ref<Scene> scene = virtualScene;
|
||||
std::string searchQuery = "";
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 8, 8 });
|
||||
ImGui::InputTextWithHint("##search", "Search entity", &searchQuery, 0, 0, 0);
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (UI::PrimaryButton("Add Entity", { ImGui::GetContentRegionAvail().x, 0 }))
|
||||
{
|
||||
ImGui::OpenPopup("create_entity_popup");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("create_entity_popup"))
|
||||
{
|
||||
Nuake::Entity entity;
|
||||
if (ImGui::MenuItem("Empty"))
|
||||
{
|
||||
entity = scene->CreateEntity("Empty");
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("3D"))
|
||||
{
|
||||
if (ImGui::MenuItem("Camera"))
|
||||
{
|
||||
entity = scene->CreateEntity("Camera");
|
||||
entity.AddComponent<CameraComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Model"))
|
||||
{
|
||||
entity = scene->CreateEntity("Model");
|
||||
entity.AddComponent<ModelComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Skinned Model"))
|
||||
{
|
||||
entity = scene->CreateEntity("Skinned Model");
|
||||
entity.AddComponent<SkinnedModelComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Sprite"))
|
||||
{
|
||||
entity = scene->CreateEntity("Sprite");
|
||||
entity.AddComponent<SpriteComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Particle Emitter"))
|
||||
{
|
||||
entity = scene->CreateEntity("Particle Emitter");
|
||||
entity.AddComponent<ParticleEmitterComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Light"))
|
||||
{
|
||||
entity = scene->CreateEntity("Light");
|
||||
entity.AddComponent<LightComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Quake Map"))
|
||||
{
|
||||
entity = scene->CreateEntity("Quake Map");
|
||||
entity.AddComponent<QuakeMapComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("NavMesh Volume"))
|
||||
{
|
||||
entity = scene->CreateEntity("NavMesh Volume");
|
||||
entity.AddComponent<NavMeshVolumeComponent>();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Physics"))
|
||||
{
|
||||
if (ImGui::MenuItem("Character Controller"))
|
||||
{
|
||||
entity = scene->CreateEntity("Character Controller");
|
||||
entity.AddComponent<CharacterControllerComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Rigid Body"))
|
||||
{
|
||||
entity = scene->CreateEntity("Rigid Body");
|
||||
entity.AddComponent<RigidBodyComponent>();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Colliders"))
|
||||
{
|
||||
if (ImGui::MenuItem("Box Collider"))
|
||||
{
|
||||
entity = scene->CreateEntity("Box Collider");
|
||||
entity.AddComponent<BoxColliderComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Sphere Collider"))
|
||||
{
|
||||
entity = scene->CreateEntity("Sphere Collider");
|
||||
entity.AddComponent<SphereColliderComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Capsule Collider"))
|
||||
{
|
||||
entity = scene->CreateEntity("Capsule Collider");
|
||||
entity.AddComponent<CapsuleColliderComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Cylinder Collider"))
|
||||
{
|
||||
entity = scene->CreateEntity("Cylinder Collider");
|
||||
entity.AddComponent<CylinderColliderComponent>();
|
||||
}
|
||||
if (ImGui::MenuItem("Mesh Collider"))
|
||||
{
|
||||
entity = scene->CreateEntity("Mesh Collider");
|
||||
entity.AddComponent<MeshColliderComponent>();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Audio"))
|
||||
{
|
||||
if (ImGui::MenuItem("Audio Emitter"))
|
||||
{
|
||||
entity = scene->CreateEntity("Audio Emitter");
|
||||
entity.AddComponent<AudioEmitterComponent>();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (entity.IsValid())
|
||||
{
|
||||
if (Selection.Type == EditorSelectionType::Entity && Selection.Entity.IsValid())
|
||||
{
|
||||
Selection.Entity.AddChild(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& camera = Engine::GetCurrentScene()->m_EditorCamera;
|
||||
Vector3 newEntityPos = camera->Translation + camera->Direction;
|
||||
entity.GetComponent<TransformComponent>().SetLocalPosition(newEntityPos);
|
||||
}
|
||||
|
||||
Selection = EditorSelection(entity);
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Draw a tree of entities.
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(26.f / 255.0f, 26.f / 255.0f, 26.f / 255.0f, 1));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 4, 4 });
|
||||
if (ImGui::BeginChild("Scene tree", ImGui::GetContentRegionAvail(), false))
|
||||
{
|
||||
if (ImGui::BeginTable("entity_table", 4, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchProp))
|
||||
{
|
||||
ImGui::TableSetupColumn(" Label", ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Script", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Visibility ", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0));
|
||||
std::vector<Nuake::Entity> entities = scene->GetAllEntities();
|
||||
for (auto& e : entities)
|
||||
{
|
||||
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanFullWidth;
|
||||
std::string name = e.GetComponent<NameComponent>().Name;
|
||||
// If selected add selected flag.
|
||||
if (Selection.Type == EditorSelectionType::Entity && Selection.Entity == e)
|
||||
base_flags |= ImGuiTreeNodeFlags_Selected;
|
||||
|
||||
// Draw all entity without parents.
|
||||
if (!e.GetComponent<ParentComponent>().HasParent)
|
||||
{
|
||||
// Recursively draw childrens.
|
||||
DrawEntityTree(e);
|
||||
}
|
||||
|
||||
// Pop font.
|
||||
//ImGui::PopFont();
|
||||
|
||||
// Right click menu
|
||||
//if (ImGui::BeginPopupContextItem())
|
||||
// ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
SelectionPanel.Draw(Selection, prefab->Path);
|
||||
|
||||
DrawViewportWindow();
|
||||
}
|
||||
|
||||
void PrefabEditorWindow::DrawViewportWindow()
|
||||
{
|
||||
|
||||
//viewportFramebuffer->Bind();
|
||||
////RenderCommand::SetClearColor(Color(1, 0, 0, 1));
|
||||
//viewportFramebuffer->Clear();
|
||||
//viewportFramebuffer->Unbind();
|
||||
|
||||
//RenderScene();
|
||||
|
||||
if (ImGui::Begin(std::string("Viewport##" + prefab->Path).c_str()))
|
||||
{
|
||||
ImVec2 regionAvail = ImGui::GetContentRegionAvail();
|
||||
Vector2 viewportPanelSize = glm::vec2(regionAvail.x, regionAvail.y);
|
||||
|
||||
if (viewportFramebuffer->GetSize() != viewportPanelSize)
|
||||
viewportFramebuffer->QueueResize(viewportPanelSize);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));\
|
||||
viewportFramebuffer->QueueResize(viewportPanelSize);
|
||||
ImGui::Image((void*)viewportFramebuffer->GetTexture(GL_COLOR_ATTACHMENT0)->GetID(), regionAvail, ImVec2(0, 1), ImVec2(1, 0));
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
const Vector2& mousePos = Input::GetMousePosition();
|
||||
|
||||
const ImVec2& windowPos = ImGui::GetWindowPos();
|
||||
const auto windowPosNuake = Vector2(windowPos.x, windowPos.y);
|
||||
const ImVec2& windowSize = ImGui::GetWindowSize();
|
||||
const bool isInsideWidth = mousePos.x > windowPos.x && mousePos.x < windowPos.x + windowSize.x;
|
||||
const bool isInsideHeight = mousePos.y > windowPos.y && mousePos.y < windowPos.y + windowSize.y;
|
||||
isHoveringViewport = isInsideWidth && isInsideHeight;
|
||||
|
||||
auto& editorCam = virtualScene->m_EditorCamera;
|
||||
bool isControllingCamera = editorCam->Update(Engine::GetTimestep(), isHoveringViewport);
|
||||
|
||||
if (ImGui::IsWindowHovered() && isHoveringViewport && !isViewportFocused && ImGui::GetIO().WantCaptureMouse)
|
||||
{
|
||||
ImGui::FocusWindow(ImGui::GetCurrentWindow());
|
||||
}
|
||||
|
||||
isViewportFocused = ImGui::IsWindowFocused();
|
||||
|
||||
|
||||
if (ImGui::GetIO().WantCaptureMouse && isHoveringViewport && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && isViewportFocused)
|
||||
{
|
||||
auto& gbuffer = virtualScene->m_SceneRenderer->GetGBuffer();
|
||||
auto pixelPos = (Input::GetMousePosition() - windowPosNuake);
|
||||
pixelPos.y = gbuffer.GetSize().y - pixelPos.y; // imgui coords are inverted on the Y axi
|
||||
|
||||
gbuffer.Bind();
|
||||
if (const int result = gbuffer.ReadPixel(3, pixelPos); result > 0)
|
||||
{
|
||||
auto ent = Nuake::Entity{ (entt::entity)(result - 1), virtualScene.get() };
|
||||
if (ent.IsValid())
|
||||
{
|
||||
Selection = EditorSelection(ent);
|
||||
virtualScene->m_SceneRenderer->mOutlineEntityID = (uint32_t)ent.GetHandle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Selection = EditorSelection(); // None
|
||||
}
|
||||
|
||||
gbuffer.Unbind();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void PrefabEditorWindow::RenderScene()
|
||||
{
|
||||
virtualScene->Update(Engine::GetTimestep());
|
||||
|
||||
Ref<SceneRenderer> sceneRenderer = virtualScene->m_SceneRenderer;
|
||||
Ref<EditorCamera> editorCam = virtualScene->m_EditorCamera;
|
||||
editorCam->OnWindowResize(viewportFramebuffer->GetSize().x, viewportFramebuffer->GetSize().y);
|
||||
virtualScene->Draw(*viewportFramebuffer.get());
|
||||
|
||||
sceneRenderer->BeginRenderScene(editorCam->GetPerspective(), editorCam->GetTransform(), editorCam->Translation);
|
||||
sceneRenderer->RenderScene(*virtualScene, *viewportFramebuffer.get(), true);
|
||||
|
||||
}
|
||||
|
||||
void PrefabEditorWindow::DrawEntityTree(Nuake::Entity e)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{ 0.0f, 0.0f });
|
||||
|
||||
ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAllColumns;
|
||||
|
||||
NameComponent& nameComponent = e.GetComponent<NameComponent>();
|
||||
std::string name = nameComponent.Name;
|
||||
|
||||
ParentComponent& parent = e.GetComponent<ParentComponent>();
|
||||
|
||||
if (Selection.Type == EditorSelectionType::Entity && Selection.Entity == e)
|
||||
base_flags |= ImGuiTreeNodeFlags_Selected;
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
// Write in normal font.
|
||||
// ImGui::PushFont(normalFont);
|
||||
|
||||
// If has no childrens draw tree node leaf
|
||||
if (parent.Children.size() <= 0)
|
||||
{
|
||||
base_flags |= ImGuiTreeNodeFlags_Leaf;
|
||||
}
|
||||
|
||||
if (nameComponent.IsPrefab && e.HasComponent<PrefabComponent>())
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255));
|
||||
}
|
||||
else if (e.HasComponent<BSPBrushComponent>())
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 120));
|
||||
}
|
||||
|
||||
//if (!m_IsRenaming && m_ShouldUnfoldEntityTree && Selection.Type == EditorSelectionType::Entity && e.GetScene()->EntityIsParent(Selection.Entity, e))
|
||||
//{
|
||||
// ImGui::SetNextItemOpen(true);
|
||||
//}
|
||||
|
||||
auto cursorPos = ImGui::GetCursorPos();
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
bool open = ImGui::TreeNodeEx(name.c_str(), base_flags);
|
||||
|
||||
if (isRenaming)
|
||||
{
|
||||
if (Selection.Type == EditorSelectionType::Entity && Selection.Entity == e)
|
||||
{
|
||||
ImGui::SetCursorPosY(cursorPos.y);
|
||||
ImGui::Indent();
|
||||
ImGui::InputText("##renamingEntity", &name);
|
||||
ImGui::Unindent();
|
||||
if (Input::IsKeyDown(Key::ENTER))
|
||||
{
|
||||
nameComponent.Name = name;
|
||||
isRenaming = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isDragging = false;
|
||||
if (nameComponent.IsPrefab && e.HasComponent<PrefabComponent>() || e.HasComponent<BSPBrushComponent>())
|
||||
{
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
else if (!isRenaming && ImGui::BeginDragDropSource())
|
||||
{
|
||||
ImGui::SetDragDropPayload("ENTITYPrefab", (void*)&e, sizeof(Nuake::Entity));
|
||||
ImGui::Text(name.c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITYPrefab"))
|
||||
{
|
||||
Nuake::Entity payload_entity = *(const Nuake::Entity*)payload->Data;
|
||||
|
||||
// Check if entity is already parent.
|
||||
ParentComponent& parentPayload = payload_entity.GetComponent<ParentComponent>();
|
||||
if (!payload_entity.EntityContainsItself(payload_entity, e) && parentPayload.Parent != e && std::count(parent.Children.begin(), parent.Children.end(), payload_entity) == 0)
|
||||
{
|
||||
if (parentPayload.HasParent)
|
||||
{
|
||||
// Erase remove idiom.
|
||||
ParentComponent& childOfParent = parentPayload.Parent.GetComponent<ParentComponent>();
|
||||
childOfParent.Children.erase(std::remove(childOfParent.Children.begin(), childOfParent.Children.end(), payload_entity), childOfParent.Children.end());
|
||||
}
|
||||
|
||||
parentPayload.Parent = e;
|
||||
parentPayload.HasParent = true;
|
||||
parent.Children.push_back(payload_entity);
|
||||
}
|
||||
}
|
||||
else if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_NetScript"))
|
||||
{
|
||||
char* file = (char*)payload->Data;
|
||||
|
||||
std::string fullPath = std::string(file, 512);
|
||||
std::string path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath));
|
||||
|
||||
if (e.HasComponent<NetScriptComponent>())
|
||||
{
|
||||
e.GetComponent<NetScriptComponent>().ScriptPath = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.AddComponent<NetScriptComponent>().ScriptPath = path;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
|
||||
if (!isDragging && ImGui::IsItemHovered() && ImGui::IsMouseReleased(0))
|
||||
{
|
||||
// We selected another another that we werent renaming
|
||||
if (Selection.Entity != e)
|
||||
{
|
||||
isRenaming = false;
|
||||
}
|
||||
|
||||
Selection = EditorSelection(e);
|
||||
}
|
||||
|
||||
if (!isDragging && (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) || Input::IsKeyPressed(Key::F2))
|
||||
{
|
||||
isRenaming = true;
|
||||
}
|
||||
|
||||
if (!isRenaming && Selection.Type == EditorSelectionType::Entity && Input::IsKeyPressed(Key::DELETE_KEY))
|
||||
{
|
||||
//QueueDeletion = Selection.Entity;
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupContextItem())
|
||||
{
|
||||
Selection = EditorSelection(e);
|
||||
|
||||
Nuake::Entity entity = Selection.Entity;
|
||||
if (entity.HasComponent<CameraComponent>())
|
||||
{
|
||||
// Moves the editor camera to the camera position and direction.
|
||||
if (ImGui::Selectable("Focus camera"))
|
||||
{
|
||||
Ref<EditorCamera> editorCam = Engine::GetCurrentScene()->m_EditorCamera;
|
||||
Vector3 camDirection = entity.GetComponent<CameraComponent>().CameraInstance->GetDirection();
|
||||
camDirection.z *= -1.0f;
|
||||
editorCam->SetTransform(glm::inverse(entity.GetComponent<TransformComponent>().GetGlobalTransform()));
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
if (ImGui::Selectable("Remove"))
|
||||
{
|
||||
//QueueDeletion = e;
|
||||
}
|
||||
|
||||
if (entity.GetComponent<ParentComponent>().HasParent && ImGui::Selectable("Move to root"))
|
||||
{
|
||||
auto& parentComp = Selection.Entity.GetComponent<ParentComponent>();
|
||||
if (parentComp.HasParent)
|
||||
{
|
||||
auto& parentParentComp = parentComp.Parent.GetComponent<ParentComponent>();
|
||||
parentParentComp.RemoveChildren(entity);
|
||||
parentComp.HasParent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Selectable("Save entity as a new prefab"))
|
||||
{
|
||||
Ref<Prefab> newPrefab = Prefab::CreatePrefabFromEntity(Selection.Entity);
|
||||
std::string savePath = Nuake::FileDialog::SaveFile("*.prefab");
|
||||
if (!String::EndsWith(savePath, ".prefab"))
|
||||
{
|
||||
savePath += ".prefab";
|
||||
}
|
||||
|
||||
if (!savePath.empty())
|
||||
{
|
||||
newPrefab->SaveAs(savePath);
|
||||
Selection.Entity.AddComponent<PrefabComponent>().PrefabInstance = newPrefab;
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TextColored(ImVec4(0.5, 0.5, 0.5, 1.0), "");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
bool hasScript = e.HasComponent<NetScriptComponent>();
|
||||
if (hasScript)
|
||||
{
|
||||
std::string scrollIcon = std::string(ICON_FA_SCROLL) + "##" + name;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
|
||||
if (ImGui::Button(scrollIcon.c_str(), { 40, 0 }))
|
||||
{
|
||||
auto& scriptComponent = e.GetComponent<NetScriptComponent>();
|
||||
if (!scriptComponent.ScriptPath.empty() && FileSystem::FileExists(scriptComponent.ScriptPath))
|
||||
{
|
||||
OS::OpenIn(FileSystem::RelativeToAbsolute(scriptComponent.ScriptPath));
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
bool& isVisible = e.GetComponent<VisibilityComponent>().Visible;
|
||||
std::string visibilityIcon = isVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
|
||||
if (ImGui::Button(visibilityIcon.c_str(), { 40, 0 }))
|
||||
{
|
||||
isVisible = !isVisible;
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (open)
|
||||
{
|
||||
// Caching list to prevent deletion while iterating.
|
||||
std::vector<Nuake::Entity> childrens = parent.Children;
|
||||
for (auto& c : childrens)
|
||||
DrawEntityTree(c);
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
//ImGui::PopFont();
|
||||
}
|
||||
44
Editor/src/Windows/PrefabEditor/PrefabEditorWindow.h
Normal file
44
Editor/src/Windows/PrefabEditor/PrefabEditorWindow.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include "src/Core/Core.h"
|
||||
|
||||
#include "../EditorSelectionPanel.h"
|
||||
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
class Prefab;
|
||||
class Scene;
|
||||
class FrameBuffer;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
class PrefabEditorWindow
|
||||
{
|
||||
public:
|
||||
PrefabEditorWindow(Ref<Nuake::Prefab> prefab);
|
||||
~PrefabEditorWindow() {
|
||||
ASSERT(false);
|
||||
};
|
||||
|
||||
void Update(float ts);
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
Ref<Nuake::Prefab> prefab;
|
||||
Ref<Nuake::Scene> virtualScene;
|
||||
Ref<Nuake::FrameBuffer> viewportFramebuffer;
|
||||
Ref<Nuake::Texture> viewportTexture;
|
||||
|
||||
bool isViewportFocused;
|
||||
bool isHoveringViewport;
|
||||
bool isRenaming;
|
||||
bool isInitialized = false;
|
||||
|
||||
EditorSelectionPanel SelectionPanel;
|
||||
EditorSelection Selection;
|
||||
|
||||
private:
|
||||
void DrawViewportWindow();
|
||||
void RenderScene();
|
||||
void DrawEntityTree(Nuake::Entity e);
|
||||
};
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
#define ASSERT(x) if (!(x)) assert(false)
|
||||
|
||||
|
||||
@@ -52,19 +52,14 @@ namespace Nuake
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const bool smoothCamera = Engine::GetProject()->Settings.SmoothCamera;
|
||||
const float smoothCameraSpeed = Engine::GetProject()->Settings.SmoothCameraSpeed;
|
||||
Yaw = glm::mix(Yaw, TargetYaw, smoothCamera ? smoothCameraSpeed : 1.0f);
|
||||
Pitch = glm::mix(Pitch, TargetPitch, smoothCamera ? smoothCameraSpeed : 1.0f);
|
||||
|
||||
if (!controlled)
|
||||
{
|
||||
Input::ShowMouse();
|
||||
}
|
||||
else if(hover)
|
||||
{
|
||||
Input::HideMouse();
|
||||
}
|
||||
|
||||
|
||||
if (Input::IsKeyDown(Key::LEFT_ALT))
|
||||
{
|
||||
@@ -168,6 +163,12 @@ namespace Nuake
|
||||
|
||||
if (controlled)
|
||||
{
|
||||
if (!wasControlled)
|
||||
{
|
||||
Input::HideMouse();
|
||||
wasControlled = true;
|
||||
}
|
||||
|
||||
if (Input::IsMouseButtonDown(2))
|
||||
{
|
||||
Vector3 movement = Vector3(0);
|
||||
@@ -189,6 +190,14 @@ namespace Nuake
|
||||
Input::YScroll = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wasControlled)
|
||||
{
|
||||
Input::ShowMouse();
|
||||
wasControlled = false;
|
||||
}
|
||||
}
|
||||
|
||||
SetDirection(glm::normalize(Direction));
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Nuake
|
||||
{
|
||||
private:
|
||||
bool m_IsFlying = false;
|
||||
|
||||
bool wasControlled = false;
|
||||
public:
|
||||
|
||||
EditorCamera()
|
||||
|
||||
@@ -16,6 +16,26 @@ namespace Nuake
|
||||
}
|
||||
}
|
||||
|
||||
bool Entity::EntityContainsItself(Entity a, Entity b)
|
||||
{
|
||||
ParentComponent& targeParentComponent = b.GetComponent<ParentComponent>();
|
||||
if (!targeParentComponent.HasParent)
|
||||
return false;
|
||||
|
||||
Entity currentParent = b.GetComponent<ParentComponent>().Parent;
|
||||
while (currentParent != a)
|
||||
{
|
||||
if (currentParent.GetComponent<ParentComponent>().HasParent)
|
||||
currentParent = currentParent.GetComponent<ParentComponent>().Parent;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (currentParent == a)
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
json Entity::Serialize()
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace Nuake
|
||||
return m_Scene->m_Registry.all_of<T>(m_EntityHandle);
|
||||
}
|
||||
|
||||
bool EntityContainsItself(Entity a, Entity b);
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return m_EntityHandle != (entt::entity)-1 && m_Scene->m_Registry.valid((entt::entity)GetHandle());
|
||||
|
||||
@@ -91,8 +91,9 @@ public:
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void DrawVec2(const std::string label, glm::vec2* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f)
|
||||
static bool DrawVec2(const std::string label, glm::vec2* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f)
|
||||
{
|
||||
bool changed = false;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
auto boldFont = io.Fonts->Fonts[0];
|
||||
|
||||
@@ -109,13 +110,20 @@ public:
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
|
||||
ImGui::PushFont(boldFont);
|
||||
if (ImGui::Button("###X", buttonSize))
|
||||
{
|
||||
values->x = resetValue;
|
||||
changed = true;
|
||||
}
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(availWidth);
|
||||
ImGui::DragFloat("##X", &values->x, rate, min, 0.0f, "%.2f");
|
||||
if (ImGui::DragFloat("##X", &values->x, rate, min, 0.0f, "%.2f"))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine();
|
||||
|
||||
@@ -124,17 +132,24 @@ public:
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
|
||||
ImGui::PushFont(boldFont);
|
||||
if (ImGui::Button("Y", buttonSize))
|
||||
{
|
||||
values->y = resetValue;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(availWidth);
|
||||
ImGui::DragFloat("##Y", &values->y, rate, 0.0f, 0.0f, "%.2f");
|
||||
if (ImGui::DragFloat("##Y", &values->y, rate, 0.0f, 0.0f, "%.2f"))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::PopID();
|
||||
//ImGui::Text("Hello");
|
||||
return changed;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user