add basic editor

This commit is contained in:
SweetId 2023-09-23 19:20:41 -04:00
parent d1f132b07e
commit a30e94dee9
13 changed files with 438 additions and 0 deletions

View File

@ -0,0 +1,9 @@
#pragma once
#include <NazaraEditor/Core/Core.hpp>
#include <NazaraEditor/Core/UI/Window.hpp>
#include <NazaraEditor/Core/Reflection/Math.hpp>
#include <NazaraEditor/Core/Reflection/Core.hpp>
#include <NazaraEditor/Core/Reflection/Utility.hpp>
#include <NazaraEditor/Core/Reflection/Graphics.hpp>
#include <NazaraEditor/Core/Reflection/Editor.hpp>

View File

@ -0,0 +1,51 @@
#pragma once
#include <Nazara/Core.hpp>
#include <Nazara/Graphics.hpp>
#include <Nazara/Platform.hpp>
#include <Nazara/Renderer.hpp>
#include <Nazara/Utility.hpp>
#include <NazaraEditor/Core.hpp>
#include <NazaraImgui/NazaraImgui.hpp>
namespace Nz
{
class EditorApplication
: public Nz::Application<Nz::Graphics, Nz::Imgui, Nz::EditorCore>
{
public:
NazaraSignal(OnWorldChanged, Nz::EnttWorld*);
// Entity lifetime events
NazaraSignal(OnEntityCreated, entt::handle);
NazaraSignal(OnEntityDestroyed, entt::handle);
NazaraSignal(OnEntityParentChanged, entt::handle);
// Entity selection events
NazaraSignal(OnEntitySelected, entt::handle);
NazaraSignal(OnEntityDeselected, entt::handle);
static EditorApplication& Instance();
void NewWorld();
Nz::EnttWorld* GetCurrentWorld();
entt::handle CreateEntity();
template<typename T>
void RegisterWindow()
{
static_assert(std::is_base_of<Nz::EditorWindow, T>::value, "Register Window should be called with a subclass of Nz::EditorWindow");
m_windows.push_back(std::make_unique<T>());
}
private:
EditorApplication();
std::unique_ptr<Nz::WindowSwapchain> m_windowSwapchain;
Nz::EnttWorld* m_world;
std::vector<std::unique_ptr<Nz::EditorWindow>> m_windows;
};
}

View File

@ -0,0 +1,16 @@
#include <NazaraEditor/Core/UI/Window.hpp>
namespace Nz
{
class EditorAssetsWindow
: public Nz::EditorWindow
{
public:
EditorAssetsWindow();
void ImportAsset();
protected:
void BuildMenuBar();
};
}

View File

@ -0,0 +1,21 @@
#include <NazaraEditor/Core/UI/Window.hpp>
#include <entt/entt.hpp>
namespace Nz
{
class EditorInspectorWindow
: public Nz::EditorWindow
{
public:
EditorInspectorWindow();
virtual void OnEditorGUI() override;
protected:
void OnEntitySelected(entt::handle entity);
void OnEntityDeselected(entt::handle);
entt::handle m_currentEntity;
};
}

View File

@ -0,0 +1,25 @@
#include <NazaraEditor/Core/UI/Window.hpp>
#include <Nazara/Core.hpp>
#include <Nazara/Utility.hpp>
namespace Nz
{
class EditorLevelWindow
: public Nz::EditorWindow
{
public:
EditorLevelWindow();
virtual void OnEditorGUI() override;
protected:
void RefreshEntities();
Nz::EnttWorld* m_currentWorld;
bool m_dirty;
std::vector<Nz::Node*> m_rootNodes;
std::map<Nz::Node*, entt::handle> m_nodeToEntity;
};
}

View File

@ -0,0 +1,24 @@
#include <NazaraEditor/Core/UI/Window.hpp>
namespace Nz
{
class EditorMainWindow
: public Nz::EditorWindow
{
public:
EditorMainWindow();
bool Quit();
bool NewLevel();
bool OpenLevel();
bool SaveLevel();
bool NewProject();
bool OpenProject();
bool SaveProject();
protected:
void BuildMenuBar();
};
}

View File

@ -0,0 +1,76 @@
#include <NazaraEditor/Editor/Application.hpp>
namespace Nz
{
EditorApplication::EditorApplication()
: m_world(nullptr)
{
auto& windowing = AddComponent<Nz::AppWindowingComponent>();
std::shared_ptr<Nz::RenderDevice> device = Nz::Graphics::Instance()->GetRenderDevice();
std::string windowTitle = "Nazara Editor";
Nz::Window& window = windowing.CreateWindow(Nz::VideoMode(1280, 720, 32), windowTitle);
m_windowSwapchain = std::make_unique<Nz::WindowSwapchain>(device, window);
// connect basic handler
window.GetEventHandler().OnQuit.Connect([&window](const auto* handler) {
NazaraUnused(handler);
window.Close();
});
AddComponent<Nz::AppEntitySystemComponent>();
Nz::Imgui::Instance()->Init(window);
ImGui::EnsureContextOnThisThread();
NewWorld();
AddUpdaterFunc(Interval{ Nz::Time::Milliseconds(16) }, [&](Nz::Time elapsed) {
if (!window.IsOpen())
return;
window.ProcessEvents();
Nz::RenderFrame frame = m_windowSwapchain->AcquireFrame();
if (!frame)
return;
Nz::Imgui::Instance()->Update(window, elapsed.AsSeconds());
Nz::Imgui::Instance()->Render(m_windowSwapchain.get(), frame);
frame.Present();
});
}
EditorApplication& EditorApplication::Instance()
{
static EditorApplication e;
return e;
}
Nz::EnttWorld* EditorApplication::GetCurrentWorld()
{
return m_world;
}
entt::handle EditorApplication::CreateEntity()
{
if (m_world == nullptr)
return {};
entt::handle entity = m_world->CreateEntity();
entity.emplace<Nz::NodeComponent>();
OnEntityCreated(entity);
OnEntitySelected(entity);
return entity;
}
void EditorApplication::NewWorld()
{
auto& ecs = GetComponent<Nz::AppEntitySystemComponent>();
m_world = &ecs.AddWorld<Nz::EnttWorld>();
}
}

View File

@ -0,0 +1,20 @@
#include <NazaraEditor/Editor/UI/AssetsWindow.hpp>
namespace Nz
{
EditorAssetsWindow::EditorAssetsWindow()
: Nz::EditorWindow("Assets Browser")
{
BuildMenuBar();
}
void EditorAssetsWindow::ImportAsset()
{
}
void EditorAssetsWindow::BuildMenuBar()
{
AddMenuAction("Import", "Ctrl+I", [this]() { ImportAsset(); });
}
}

View File

@ -0,0 +1,32 @@
#include <NazaraEditor/Editor/UI/InspectorWindow.hpp>
#include <NazaraEditor/Editor/Application.hpp>
namespace Nz
{
EditorInspectorWindow::EditorInspectorWindow()
: Nz::EditorWindow("Inspector")
{
EditorApplication::Instance().OnEntitySelected.Connect(this, &EditorInspectorWindow::OnEntitySelected);
}
void EditorInspectorWindow::OnEditorGUI()
{
if (!m_currentEntity)
return;
Nz::EditorPropertyInspector<Nz::EditorRenderer> enumerator;
enumerator.AddProperty(m_currentEntity, "", "");
ImGui::End();
}
void EditorInspectorWindow::OnEntitySelected(entt::handle entity)
{
m_currentEntity = entity;
}
void EditorInspectorWindow::OnEntityDeselected(entt::handle)
{
m_currentEntity = {};
}
}

View File

@ -0,0 +1,58 @@
#include <NazaraEditor/Editor/UI/LevelWindow.hpp>
#include <NazaraEditor/Editor/Application.hpp>
namespace Nz
{
EditorLevelWindow::EditorLevelWindow()
: Nz::EditorWindow("Level")
, m_currentWorld(EditorApplication::Instance().GetCurrentWorld())
, m_dirty(true)
{
EditorApplication::Instance().OnWorldChanged.Connect([this](Nz::EnttWorld* world) { m_currentWorld = world; m_dirty = true; });
EditorApplication::Instance().OnEntityCreated.Connect([this](entt::handle) { m_dirty = true; });
EditorApplication::Instance().OnEntityDestroyed.Connect([this](entt::handle) { m_dirty = true; });
EditorApplication::Instance().OnEntityParentChanged.Connect([this](entt::handle) { m_dirty = true; });
}
void EditorLevelWindow::OnEditorGUI()
{
RefreshEntities();
std::function<void(Nz::Node*)> drawHierarchy = [&](Nz::Node* c)
{
entt::handle entity = m_nodeToEntity[c];
Nz::EditorImgui::Begin(entity, "", "");
for (auto& child : c->GetChilds())
drawHierarchy(child);
Nz::EditorImgui::End(entity);
};
for (auto& node : m_rootNodes)
drawHierarchy(node);
}
void EditorLevelWindow::RefreshEntities()
{
if (!m_dirty)
return;
m_dirty = false;
m_rootNodes.clear();
m_nodeToEntity.clear();
if (m_currentWorld == nullptr)
return;
m_currentWorld->GetRegistry().each([&](const entt::entity entity) {
entt::handle handle(m_currentWorld->GetRegistry(), entity);
Nz::NodeComponent* component = handle.try_get<Nz::NodeComponent>();
if (component != nullptr)
{
m_nodeToEntity[component] = handle;
if (component->GetParent() == nullptr)
m_rootNodes.push_back(component);
}
});
}
}

View File

@ -0,0 +1,62 @@
#include <NazaraEditor/Editor/UI/MainWindow.hpp>
namespace Nz
{
EditorMainWindow::EditorMainWindow()
: Nz::EditorWindow("MainWindow")
{
BuildMenuBar();
}
void EditorMainWindow::BuildMenuBar()
{
AddMenuAction("File|Project|New", "Ctrl+Shift+N", [this]() { NewProject(); });
AddMenuAction("File|Project|Open", "Ctrl+Shift+O", [this]() { OpenProject(); });
AddMenuAction("File|Project|Save", "Ctrl+Shift+S", [this]() { SaveProject(); });
AddMenuAction("File|Level|New", "Ctrl+N", [this]() { NewLevel(); });
AddMenuAction("File|Level|Open", "Ctrl+O", [this]() { OpenLevel(); });
AddMenuAction("File|Level|Save", "Ctrl+S", [this]() { SaveLevel(); });
AddMenuSeparator("File");
AddMenuAction("File|Quit", "Ctrl+W", [this]() { Quit(); });
}
void EditorMainWindow::OnEditorGUI()
{
}
bool EditorMainWindow::Quit()
{
return true;
}
bool EditorMainWindow::NewLevel()
{
return true;
}
bool EditorMainWindow::OpenLevel()
{
return true;
}
bool EditorMainWindow::SaveLevel()
{
return true;
}
bool EditorMainWindow::NewProject()
{
return true;
}
bool EditorMainWindow::OpenProject()
{
return true;
}
bool EditorMainWindow::SaveProject()
{
return true;
}
}

View File

@ -0,0 +1,44 @@
#include <Nazara/Core.hpp>
#include <Nazara/Graphics.hpp>
#include <Nazara/Platform.hpp>
#include <Nazara/Renderer.hpp>
#include <Nazara/Utility.hpp>
#include <NazaraImgui/NazaraImgui.hpp>
#include <NazaraEditor/Core.hpp>
#include <NazaraEditor/Editor/Application.hpp>
#include <NazaraEditor/Editor/UI/AssetsWindow.hpp>
#include <NazaraEditor/Editor/UI/InspectorWindow.hpp>
#include <NazaraEditor/Editor/UI/LevelWindow.hpp>
#include <NazaraEditor/Editor/UI/MainWindow.hpp>
NAZARA_REQUEST_DEDICATED_GPU()
#if 1
int main(int argc, char* argv[])
#else
int WinMain(int argc, char* argv[])
#endif
{
NazaraUnused(argc);
NazaraUnused(argv);
Nz::EditorApplication& app = Nz::EditorApplication::Instance();
app.RegisterWindow<Nz::EditorMainWindow>();
app.RegisterWindow<Nz::EditorAssetsWindow>();
app.RegisterWindow<Nz::EditorLevelWindow>();
app.RegisterWindow<Nz::EditorInspectorWindow>();
entt::meta<Nz::NodeComponent>()
.type(entt::type_hash<Nz::NodeComponent>::value())
.func<&Nz::ReflectComponent<Nz::EditorPropertyInspector<Nz::EditorRenderer>, Nz::NodeComponent>>(entt::hashed_string("Reflect"));
entt::meta<Nz::LightComponent>()
.type(entt::type_hash<Nz::LightComponent>::value())
.func<&Nz::ReflectComponent<Nz::EditorPropertyInspector<Nz::EditorRenderer>, Nz::LightComponent>>(entt::hashed_string("Reflect"));
entt::handle entity = app.CreateEntity();
return app.Run();
}