add basic core

This commit is contained in:
SweetId 2023-09-23 19:20:32 -04:00
parent 5c4c23b971
commit d1f132b07e
22 changed files with 824 additions and 0 deletions

View File

@ -0,0 +1,23 @@
#pragma once
#include <Nazara/Core/ResourceManager.hpp>
#include <string>
namespace Nz
{
class Asset
{
public:
virtual bool IsExtensionSupported(std::string_view ext) = 0;
};
template<typename TResourceManager>
class TAsset
{
public:
virtual bool IsExtensionSupported(std::string_view ext) { return m_resourceManager. }
protected:
TResourceManager m_resourceManager;
};
}

View File

@ -0,0 +1,16 @@
#pragma once
#ifndef NAZARAEDITOR_CORE_CONFIG_HPP
#define NAZARAEDITOR_CORE_CONFIG_HPP
#if !defined(NAZARAEDITOR_STATIC)
#ifdef NAZARAEDITOR_CORE_BUILD
#define NAZARAEDITOR_CORE_API NAZARA_EXPORT
#else
#define NAZARAEDITOR_CORE_API NAZARA_IMPORT
#endif
#else
#define NAZARAEDITOR_CORE_API
#endif
#endif // NAZARAEDITOR_CORE_CONFIG_HPP

View File

@ -0,0 +1,25 @@
#pragma once
#include <NazaraEditor/Core/Config.hpp>
#include <Nazara/Core/ModuleBase.hpp>
#include <NazaraImgui/NazaraImgui.hpp>
namespace Nz
{
class NAZARAEDITOR_CORE_API EditorCore : public Nz::ModuleBase<EditorCore>
{
friend ModuleBase;
public:
using Dependencies = TypeList<Imgui>;
struct Config {};
EditorCore(Config config);
~EditorCore();
private:
static EditorCore* s_instance;
};
}

View File

@ -0,0 +1,144 @@
#pragma once
#include <NazaraEditor/Core/Reflection/Reflection.hpp>
#include <NazaraEditor/Core/Reflection/Math.hpp>
#include <Nazara/Core.hpp>
#include <Nazara/Utility.hpp>
#include <array>
#include <vector>
#include <string>
#include <imgui.h>
namespace Nz
{
template <>
class TypeReflect<Color>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, Color& obj)
{
p.AddProperty(obj.r, "R", "Red (0-255)");
p.AddProperty(obj.g, "G", "Green (0-255)");
p.AddProperty(obj.b, "B", "Blue (0-255)");
p.AddProperty(obj.a, "A", "Alpha (0-255)");
}
};
namespace EditorImgui
{
inline bool Begin(Color& obj, const std::string& name, const std::string& tooltip)
{
// your IMGUI Code
float values[] = { obj.r, obj.g, obj.b, obj.a };
if (ImGui::ColorEdit4(name.c_str(), values, ImGuiColorEditFlags_PickerHueWheel))
{
obj = Color(values[0], values[1], values[2], values[3]);
}
return false;
}
inline void End(Color&) {}
}
// Wrapper for array values
template <typename T>
struct ArrayEntry
{
T& value;
};
template <typename T>
class TypeReflect<ArrayEntry<T>>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, ArrayEntry<T>& obj)
{
p.AddProperty(p.value, "", "");
}
};
template <typename T, size_t Size>
class TypeReflect<std::array<T, Size>>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, std::array<T, Size>& obj)
{
for (size_t i = 0; i < Size; ++i)
{
p.AddProperty(ArrayEntry{ obj[i] }, "", "");
}
}
};
namespace EditorImgui
{
template <typename T, size_t Size>
static bool Begin(ArrayEntry<T>& obj, const std::string& name, const std::string& tooltip)
{
ImGui::BeginGroup();
}
template <typename T, size_t Size>
static void End(ArrayEntry<T>&) {
ImGui::EndGroup();
}
template <typename T, size_t Size>
static bool Begin(std::array<T, Size>& obj, const std::string& name, const std::string& tooltip)
{
return ImGui::TreeNode(name.c_str());
}
template <typename T, size_t Size>
static void End(std::array<T, Size>&) {
ImGui::TreePop();
}
}
template <>
class TypeReflect<entt::handle>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, entt::handle& obj)
{
for (auto&& curr : obj.storage())
{
if (auto& storage = curr.second; storage.contains(obj))
{
entt::id_type id = curr.first;
if (auto reflect = entt::resolve(id).func(entt::hashed_string("Reflect")); reflect)
reflect.invoke({}, p, obj);
}
}
}
};
namespace EditorImgui
{
static bool Begin(entt::handle& obj, const std::string& name, const std::string& tooltip)
{
std::string n = "Entity " + name;
return ImGui::TreeNode(n.c_str());
}
static void End(entt::handle&) {
ImGui::TreePop();
}
}
template <typename TPropertyEnumerator, typename TComponent>
inline void ReflectComponent(TPropertyEnumerator& p, entt::handle& obj)
{
TComponent* component = obj.try_get<TComponent>();
if (component != nullptr)
p.AddProperty(*component, "", "");
}
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <functional>
#include <string>
namespace Nz
{
template <typename TPropertyDetail>
struct EditorPropertyInspector
{
template <typename T>
void AddProperty(T& prop, const std::string& name, const std::string& tooltip);
/*template <typename T, typename U, typename V>
void AddProperty(T& parent, V(U::* Getter)() const, void(U::*Setter(const V&))(), const std::string& name, const std::string& tooltip)
{
U val = parent->Getter();
AddProperty(val, name, tooltip);
parent->Setter(val);
}*/
template <typename TGetter, typename TSetter>
void AddProperty(TGetter Getter, TSetter Setter, const std::string& name, const std::string& tooltip)
{
auto val = Getter();
AddProperty(val, name, tooltip);
Setter(val);
}
};
struct EditorRenderer
{
template <typename T>
static bool Begin(T& prop, const std::string& name, const std::string& tooltip)
{
return EditorImgui::Begin(prop, name, tooltip);
}
template <typename T>
static void End(T& prop)
{
EditorImgui::End(prop);
}
};
}
#include <NazaraEditor/Core/Reflection/Editor.inl>

View File

@ -0,0 +1,15 @@
namespace Nz
{
template <typename TPropertyDetail>
template <typename T> void EditorPropertyInspector<TPropertyDetail>::AddProperty(T& prop, const std::string& name, const std::string& tooltip)
{
if (TPropertyDetail::Begin(prop, name, tooltip))
{
TypeReflect<T>::Reflect(*this, prop);
TPropertyDetail::End(prop);
}
}
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <NazaraEditor/Core/Reflection/Reflection.hpp>
#include <Nazara/Graphics.hpp>
#include <imgui.h>
namespace Nz
{
template <>
class TypeReflect<LightComponent::LightEntry>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, LightComponent::LightEntry& obj)
{
}
};
template <>
class TypeReflect<LightComponent>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, LightComponent& obj)
{
p.AddProperty([&obj]() { return obj.IsVisible(); }, [&obj](bool v) { obj.Show(v); }, "Is Visible", "Toggles lights visibility");
//p.AddProperty(obj.GetLights(), "Lights", "");
}
};
namespace EditorImgui
{
inline bool Begin(Nz::LightComponent::LightEntry& obj, const std::string& name, const std::string& tooltip)
{
return false;
}
inline void End(Nz::LightComponent::LightEntry&) {
}
inline bool Begin(Nz::LightComponent& obj, const std::string& name, const std::string& tooltip)
{
return ImGui::TreeNode("LightComponent");
}
inline void End(Nz::LightComponent&) {
ImGui::TreePop();
}
}
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <NazaraEditor/Core/Reflection/Reflection.hpp>
#include <Nazara/Math.hpp>
#include <imgui.h>
namespace Nz
{
namespace EditorImgui
{
inline bool Begin(bool& obj, const std::string& name, const std::string& /*tooltip*/)
{
ImGui::Checkbox(name.c_str(), &obj);
return false;
}
inline void End(bool&) {}
#define IMGUI_BASIC_INTEGER(Type) \
inline bool Begin(Type& obj, const std::string& name, const std::string& /*tooltip*/) \
{ \
int value = static_cast<int>(obj); \
if (ImGui::DragInt(name.c_str(), &value, 1.f, std::numeric_limits<Type>::min(), std::numeric_limits<Type>::max())) \
obj = static_cast<Type>(value); \
return false; \
} \
inline void End(Type&) {}
IMGUI_BASIC_INTEGER(Nz::Int8);
IMGUI_BASIC_INTEGER(Nz::Int16)
IMGUI_BASIC_INTEGER(Nz::Int32);
IMGUI_BASIC_INTEGER(Nz::Int64);
IMGUI_BASIC_INTEGER(Nz::UInt8);
IMGUI_BASIC_INTEGER(Nz::UInt16);
IMGUI_BASIC_INTEGER(Nz::UInt32);
IMGUI_BASIC_INTEGER(Nz::UInt64);
#define IMGUI_BASIC_FLOAT(Type) \
inline bool Begin(Type& obj, const std::string& name, const std::string& /*tooltip*/) \
{ \
float value = (float)obj; \
if (ImGui::DragFloat(name.c_str(), &value, 1.f, std::numeric_limits<Type>::min(), std::numeric_limits<Type>::max())) \
obj = (Type)value; \
return false; \
} \
inline void End(Type&) {}
IMGUI_BASIC_FLOAT(float);
IMGUI_BASIC_FLOAT(double);
inline bool Begin(Nz::Vector3f& obj, const std::string& name, const std::string& /*tooltip*/)
{
float value[] = { obj.x, obj.y, obj.z };
if (ImGui::DragFloat3(name.c_str(), value, 1.f, std::numeric_limits<float>::min(), std::numeric_limits<float>::max()))
obj = Nz::Vector3f(value[0], value[1], value[2]);
return false;
}
inline void End(Nz::Vector3f&) {}
inline bool Begin(Nz::Quaternionf& obj, const std::string& name, const std::string& /*tooltip*/)
{
auto euler = obj.ToEulerAngles();
float value[] = { euler.pitch.ToDegrees(), euler.yaw.ToDegrees(), euler.roll.ToDegrees() };
if (ImGui::DragFloat3(name.c_str(), value, 1.f, std::numeric_limits<float>::min(), std::numeric_limits<float>::max()))
{
obj = EulerAnglesf(value[0], value[1], value[2]).ToQuaternion();
}
return false;
}
inline void End(Nz::Quaternionf&) {}
}
}

View File

@ -0,0 +1,12 @@
#pragma once
namespace Nz
{
template <typename T>
class TypeReflect
{
public:
template <typename TEnumerator>
static void Reflect(TEnumerator&, T&) { } // default specialization
};
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <NazaraEditor/Core/Reflection/Reflection.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>
#include <imgui.h>
namespace Nz
{
template <>
class TypeReflect<NodeComponent>
{
public:
template <typename TPropertyEnumerator>
static void Reflect(TPropertyEnumerator& p, NodeComponent& obj)
{
p.AddProperty([&obj]() { return obj.GetPosition(); }, [&obj](const Nz::Vector3f& v) { return obj.SetPosition(v); }, "Position", "Position of the node");
p.AddProperty([&obj]() { return obj.GetRotation(); }, [&obj](const Nz::Quaternionf& v) { return obj.SetRotation(v); }, "Rotation", "Rotation of the node");
p.AddProperty([&obj]() { return obj.GetScale(); }, [&obj](const Nz::Vector3f& v) { return obj.SetScale(v); }, "Scale", "Scale of the node");
}
};
namespace EditorImgui
{
inline bool Begin(Nz::NodeComponent& obj, const std::string& name, const std::string& tooltip)
{
return ImGui::TreeNode("NodeComponent");
}
inline void End(Nz::NodeComponent&) {
ImGui::TreePop();
}
}
}

View File

View File

View File

@ -0,0 +1,54 @@
#pragma once
#include <NazaraUtils/Prerequisites.hpp>
#include <NazaraEditor/Core/Config.hpp>
#include <NazaraImgui/NazaraImgui.hpp>
namespace Nz
{
using ActionCallback = std::function<void(void)>;
class NAZARAEDITOR_CORE_API EditorWindow
: private Nz::ImguiHandler
{
public:
EditorWindow(const std::string& name = "");
~EditorWindow();
EditorWindow(const EditorWindow&) = delete;
EditorWindow& operator=(const EditorWindow&) = delete;
virtual void OnRenderImgui() override;
void AddMenuAction(const std::string& path, const std::string& shortcut, ActionCallback callback);
void AddMenuSeparator(const std::string& path);
protected:
virtual void OnEditorGUI() {};
private:
void DrawMenus();
std::string m_windowName;
struct MenuAction
{
std::string label;
std::string shortcut;
ActionCallback callback;
};
struct MenuSeparator
{};
struct MenuList
{
std::string label;
std::vector<std::variant<MenuAction, MenuSeparator, MenuList>> entries;
};
MenuList m_root;
MenuList& GetOrCreateMenuHierarchy(const std::vector<std::string_view>& hierarchy);
};
}

View File

View File

@ -0,0 +1,14 @@
#include <NazaraEditor/Core/Core.hpp>
namespace Nz
{
EditorCore* EditorCore::s_instance = nullptr;
EditorCore::EditorCore(Config /*config*/)
: ModuleBase("EditorCore", this)
{
ImGui::EnsureContextOnThisThread();
}
EditorCore::~EditorCore() {}
}

View File

View File

View File

@ -0,0 +1,119 @@
#include <NazaraEditor/Core/UI/Window.hpp>
#include <Nazara/Core/StringExt.hpp>
namespace Nz
{
EditorWindow::EditorWindow(const std::string& name)
: m_windowName(name)
{
Nz::Imgui::Instance()->AddHandler(this);
}
EditorWindow::~EditorWindow()
{
Nz::Imgui::Instance()->RemoveHandler(this);
}
void EditorWindow::OnRenderImgui()
{
bool bNeedsMenu = !m_root.entries.empty();
ImGuiWindowFlags flags = (bNeedsMenu ? ImGuiWindowFlags_MenuBar : 0);
if (ImGui::Begin(m_windowName.c_str(), nullptr, flags))
{
DrawMenus();
OnEditorGUI();
ImGui::End();
}
}
void EditorWindow::AddMenuAction(const std::string& path, const std::string& shortcut, ActionCallback callback)
{
std::vector<std::string_view> v;
Nz::SplitString(path, "|", [&](std::string_view str) { v.push_back(str); return true; });
std::string leaf = std::string(v.back());
v.pop_back(); // remove action name from hierarchy
MenuList& parent = GetOrCreateMenuHierarchy(v);
parent.entries.push_back(MenuAction{ leaf, shortcut, callback});
}
void EditorWindow::AddMenuSeparator(const std::string& path)
{
std::vector<std::string_view> v;
Nz::SplitString(path, "|", [&](std::string_view str) { v.push_back(str); return true; });
MenuList& parent = GetOrCreateMenuHierarchy(v);
parent.entries.push_back(MenuSeparator{});
}
void EditorWindow::DrawMenus()
{
if (m_root.entries.empty())
return;
std::function<void(const std::variant<MenuAction, MenuSeparator, MenuList>&)> visitor;
visitor = [&visitor](auto& menu) {
std::visit(Overloaded{
[&visitor](const MenuList& arg) {
if (ImGui::BeginMenu(arg.label.c_str()))
{
for (auto& child : arg.entries)
visitor(child);
ImGui::EndMenu();
}
},
[](const MenuSeparator&) {
ImGui::Separator();
},
[](const MenuAction& arg) {
if (ImGui::MenuItem(arg.label.c_str(), arg.shortcut.c_str()))
arg.callback();
},
}, menu);
};
if (ImGui::BeginMenuBar())
{
for (auto& menu : m_root.entries)
visitor(menu);
ImGui::EndMenuBar();
}
}
EditorWindow::MenuList& EditorWindow::GetOrCreateMenuHierarchy(const std::vector<std::string_view>& hierarchy)
{
auto getOrCreate_submenu = [](MenuList* menu, std::string_view v) -> MenuList*
{
for (auto& e : menu->entries)
{
MenuList* ptr = nullptr;
std::visit(Overloaded{
[&ptr, v](MenuList& arg) {
if (arg.label == v)
ptr = &arg;
},
[](MenuSeparator&) { },
[](MenuAction&) { },
}, e);
if (nullptr != ptr)
return ptr;
}
menu->entries.push_back(MenuList{ std::string(v) });
return &std::get<MenuList>(menu->entries.back());
};
MenuList* currentMenu = &m_root;
for (auto& entry : hierarchy)
currentMenu = getOrCreate_submenu(currentMenu, entry);
return *currentMenu;
}
}

189
xmake.lua Normal file
View File

@ -0,0 +1,189 @@
set_project("NazaraEditor")
add_rules("mode.asan", "mode.tsan", "mode.coverage", "mode.debug", "mode.releasedbg", "mode.release")
add_rules("plugin.vsxmake.autoupdate")
includes("xmake/**.lua")
add_repositories("nazara-engine-repo https://github.com/NazaraEngine/xmake-repo")
add_repositories("nazara-imgui-repo https://github.com/SweetId/NazaraImgui-xmake-repo")
add_requires("nazaraengine", { alias = "nazara", debug = is_mode("debug") })
add_requires("nazaraimgui", { alias = "nzimgui", debug = is_mode("debug") })
add_includedirs("include", "src")
set_languages("c89", "c++17")
set_rundir("./bin/$(plat)_$(arch)_$(mode)")
set_targetdir("./bin/$(plat)_$(arch)_$(mode)")
if has_config("erronwarn") then
set_warnings("allextra", "error")
else
set_warnings("allextra")
end
if is_plat("mingw", "linux") then
add_cxflags("-Wno-subobject-linkage")
end
if is_plat("windows") then
add_defines("_CRT_SECURE_NO_WARNINGS")
add_cxxflags("/bigobj", "/permissive-", "/Zc:__cplusplus", "/Zc:externConstexpr", "/Zc:inline", "/Zc:lambda", "/Zc:preprocessor", "/Zc:referenceBinding", "/Zc:strictStrings", "/Zc:throwingNew")
add_cxflags("/w44062") -- Enable warning: switch case not handled
add_cxflags("/wd4251") -- Disable warning: class needs to have dll-interface to be used by clients of class blah blah blah
add_cxflags("/wd4275") -- Disable warning: DLL-interface class 'class_1' used as base for DLL-interface blah
elseif is_plat("mingw") then
add_cxflags("-Og", "-Wa,-mbig-obj")
add_ldflags("-Wa,-mbig-obj")
end
if is_mode("debug") then
set_runtimes("MDd")
elseif is_mode("asan", "tsan", "ubsan") then
set_optimize("none") -- by default xmake will optimize asan builds
elseif is_mode("coverage") then
if not is_plat("windows") then
add_links("gcov")
end
elseif is_mode("releasedbg") then
set_runtimes("MD")
set_fpmodels("fast")
add_vectorexts("sse", "sse2", "sse3", "ssse3")
end
local modules = {
Core = {
Packages = { "nazara", "nzimgui" },
}
}
function ModuleTargetConfig(name, module)
add_defines("NAZARAEDITOR_" .. name:upper() .. "_BUILD")
if is_mode("debug") then
add_defines("NAZARAEDITOR_" .. name:upper() .. "_DEBUG")
end
-- Add header and source files
local headerExts = {".h", ".hpp", ".inl", ".natvis"}
for _, ext in ipairs(headerExts) do
add_headerfiles("include/(NazaraEditor/" .. name .. "/**" .. ext .. ")")
add_headerfiles("src/NazaraEditor/" .. name .. "/**" .. ext, { prefixdir = "private", install = false })
add_headerfiles("src/NazaraEditor/" .. name .. "/Resources/**.nzsl", { prefixdir = "private", install = false })
end
remove_headerfiles("src/NazaraEditor/" .. name .. "/Resources/**.h")
add_files("src/NazaraEditor/" .. name .. "/**.cpp")
if has_config("embed_resources") then
local embedResourceRule = false
for _, filepath in pairs(os.files("src/NazaraEditor/" .. name .. "/Resources/**|**.h|**.nzsl|**.nzslb")) do
if not embedResourceRule then
add_rules("embed.resources")
embedResourceRule = true
end
add_files(filepath, {rule = "embed.resources"})
end
end
if has_config("compile_shaders") then
local compileShaderRule = false
for _, filepath in pairs(os.files("src/NazaraEditor/" .. name .. "/Resources/**.nzsl")) do
if not compileShaderRule then
add_rules("nzsl.compile.shaders")
compileShaderRule = true
end
add_files(filepath, {rule = "nzsl.compile.shaders"})
end
end
-- Remove platform-specific files
if not is_plat("windows", "mingw") then
remove_headerfiles("src/NazaraEditor/" .. name .. "/Win32/**")
remove_files("src/NazaraEditor/" .. name .. "/Win32/**")
end
if not is_plat("linux", "android", "cross") then
remove_headerfiles("src/NazaraEditor/" .. name .. "/Linux/**")
remove_files("src/NazaraEditor/" .. name .. "/Linux/**")
end
if not is_plat("macosx", "iphoneos") then
remove_headerfiles("src/NazaraEditor/" .. name .. "/Darwin/**")
remove_files("src/NazaraEditor/" .. name .. "/Darwin/**")
end
if not is_plat("linux", "macosx", "iphoneos", "android", "wasm", "cross") then
remove_headerfiles("src/NazaraEditor/" .. name .. "/Posix/**")
remove_files("src/NazaraEditor/" .. name .. "/Posix/**")
end
if module.Custom then
module.Custom()
end
end
for name, module in pairs(modules) do
if module.Option and not has_config(module.Option) then
goto continue
end
target("NazaraEditor-" .. name, function ()
set_group("Modules")
-- for now only shared compilation is supported (except on platforms like wasm)
if not is_plat("wasm") then
set_kind("shared")
else
set_kind("static")
add_defines("NAZARAEDITOR_STATIC", { public = true })
end
add_rpathdirs("$ORIGIN")
if module.Deps then
add_deps(table.unpack(module.Deps))
end
if module.Packages then
add_packages(table.unpack(module.Packages))
end
if module.PublicPackages then
for _, pkg in ipairs(module.PublicPackages) do
add_packages(pkg, { public = true })
end
end
if has_config("usepch") then
set_pcxxheader("include/NazaraEditor/" .. name .. ".hpp")
end
if has_config("unitybuild") then
add_rules("c++.unity_build", {uniqueid = "NAZARA_UNITY_ID", batchsize = 12})
end
if is_plat("windows", "mingw") then
add_defines("NAZARA_UTILS_WINDOWS_NT6=1")
end
add_includedirs("src")
ModuleTargetConfig(name, module)
end)
::continue::
end
target("NazaraEditor")
set_group("Applications")
add_headerfiles("include/NazaraEditor/Editor/**.h")
add_headerfiles("include/NazaraEditor/Editor/**.hpp")
add_headerfiles("include/NazaraEditor/Editor/**.inl")
add_files("src/NazaraEditor/Editor/**.cpp")
for name, module in pairs(modules) do
add_deps("NazaraEditor-" .. name)
end
add_packages("nazara", "nzimgui")
set_rundir(".")