diff --git a/.vscode/settings.json b/.vscode/settings.json index 4114250..5081ccf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "bitmap.c": "cpp", "heap.c": "cpp", "init.c": "cpp", - "random.c": "cpp" + "random.c": "cpp", + "type_traits": "cpp" } } \ No newline at end of file diff --git a/README.md b/README.md index 235870f..e59a55d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ +![Logo](engine/assets/logo.png) # 个人游戏引擎 +原始项目: http://175.24.226.114:3000/ouczbs/zengine.git + 这是一个模块化的 C++ 游戏引擎,旨在帮助学习和实现基本的游戏引擎系统。它包括多个模块,如渲染、资源管理、UI 等,并使用 Vulkan 作为主要的渲染 API。该引擎的结构被拆分为多个静态库和动态链接库(DLL),通过 `xmake` 管理。 ## 功能 - **模块化架构**:将引擎拆分成多个独立模块,提高了可维护性和可扩展性。 - **渲染**:使用 Vulkan 实现,且有抽象层支持未来扩展到 OpenGL、DirectX 和 Metal 等其他渲染 API。 - **资源管理**:包括基础的资源管理、加载和序列化功能。 -- **UI**:集成了 NoesisGUI 进行 XAML UI 元素的渲染。 -- **全局变量管理**:通过 `engine.dll` 集中管理全局状态,避免模块间不一致。 +- **UI**:初步集成了 NoesisGUI 和 ImGui 进行 XAML UI 元素的渲染。 +- **接口导出**:通过 `engine.dll` 集中管理全局状态,避免模块间不一致。 - **高效内存管理**:通过 `pmr` 内存资源和模板元编程优化内存分配。 - **编辑器支持**:为编辑器功能提供基本的集成,未来计划使用 ImGui 和 NoesisGUI 开发完整的编辑器工具。 diff --git a/engine/assets/logo.png b/engine/assets/logo.png new file mode 100644 index 0000000..956cea2 Binary files /dev/null and b/engine/assets/logo.png differ diff --git a/engine/assets/scene/entry.scene b/engine/assets/scene/entry.scene new file mode 100644 index 0000000..761d520 --- /dev/null +++ b/engine/assets/scene/entry.scene @@ -0,0 +1,12 @@ +__parent__: + mName: entry + mLevelBlueprint: + __class__: api::LevelBlueprint + __data__: ~ + mLevelInfos: + - mName: main + mPath: /scene/entry/main.level + mOffset: + x: 0 + y: 255 + z: 0 \ No newline at end of file diff --git a/engine/assets/scene/entry/main.level b/engine/assets/scene/entry/main.level new file mode 100644 index 0000000..3590a82 --- /dev/null +++ b/engine/assets/scene/entry/main.level @@ -0,0 +1,13 @@ +__parent__: + mName: main + mPath: /scene/entry/main.level + mOffset: + x: 0 + y: 255 + z: 0 +mObjects: + - __class__: api::GameObject + __data__: + mName: "" + mChildrens: ~ + mComponents: ~ \ No newline at end of file diff --git a/engine/include/engine/app.h b/engine/include/engine/app.h new file mode 100644 index 0000000..9e2d71f --- /dev/null +++ b/engine/include/engine/app.h @@ -0,0 +1,12 @@ +#pragma once +#include "data/global.h" +namespace api{ + class ENGINE_API App { + public: + void* operator new(size_t size) { + return ::operator new(size, GlobalPool()); + } + virtual bool Launch(); + virtual void Update(); + }; +} \ No newline at end of file diff --git a/engine/modules/engine/app/impl/app_impl.inl b/engine/modules/engine/app/impl/app_impl.inl index 77fb44d..73cbf5f 100644 --- a/engine/modules/engine/app/impl/app_impl.inl +++ b/engine/modules/engine/app/impl/app_impl.inl @@ -1,5 +1,8 @@ -#include "app.h" #include "data/global.h" namespace api { - APP_API EngineConfig gEngineConfig{}; + APP_API EngineConfig gEngineConfig{}; + APP_API ProjectConfig gProjectConfig{}; +#ifdef WITH_EDITOR + APP_API EditorConfig gEditorConfig{}; +#endif } \ No newline at end of file diff --git a/engine/modules/engine/app/impl/scene_system_impl.inl b/engine/modules/engine/app/impl/scene_system_impl.inl new file mode 100644 index 0000000..d77e125 --- /dev/null +++ b/engine/modules/engine/app/impl/scene_system_impl.inl @@ -0,0 +1,163 @@ +#include "scene/scene_system.h" +#include "scene/scene.h" +namespace api { + class SceneSystemImpl + { + public: + Scene* curScene = nullptr; + table scenes; + table pathTable; + public: + void LoadScene(PackagePath path, bool switchNow = true); + void SwitchScene(Name name); + void DeleteScene(Name name); + void DeleteAllScene(); + void ReloadScene(); + void Render(); + void Update(); + Scene* GetCurScene(); + Scene* GetScene(Name name); + Scene* FindScene(PackagePath path); + }; + Scene* SceneSystemImpl::GetScene(Name name) + { + auto iter = scenes.find(name); + if (iter != scenes.end()) + return iter->second; + return nullptr; + } + Scene* SceneSystemImpl::FindScene(PackagePath path) + { + Name name = Name::Find(path.path); + auto it = pathTable.find(name); + if (it != pathTable.end()) { + return GetScene(it->second); + } + return nullptr; + } + void SceneSystemImpl::LoadScene(PackagePath path, bool switchNow) + { + Scene* pScene = FindScene(path); + if (pScene) { + curScene = pScene; + return; + } + FileHandle handle(path); + if (!handle.Open(FILE_OP::READ)) { + return; + } + pmr::string text = handle.ReadAll(); + pScene = new Scene(); + if (!TextDeserialize(text, pScene)) _UNLIKELY{ + delete pScene; + return; + }; + pScene->mPath = path(); + pathTable.emplace(pScene->mPath, pScene->mName); + scenes.emplace(pScene->mName, pScene); + curScene = pScene; + curScene->OnLoad(); + } + void SceneSystemImpl::SwitchScene(Name name) + { + auto scene = GetScene(name); + if (scene == nullptr) _UNLIKELY + { + zlog::error("Switch to invalid scene: {}", name.data()); + return; + } + curScene = scene; + } + void SceneSystemImpl::DeleteScene(Name name) + { + auto iter = scenes.find(name); + if (iter == scenes.end()) _UNLIKELY + { + zlog::info("Attempt to delete a nonexistent scene: {}", name.ToStringView()); + return; + } + delete iter->second; + scenes.erase(iter); + } + void SceneSystemImpl::DeleteAllScene() + { + for (auto& iter : scenes) + { + delete iter.second; + } + scenes.clear(); + } + void SceneSystemImpl::ReloadScene() + { + if (!curScene)_UNLIKELY{ + return; + } + Name path = curScene->mPath; + DeleteScene(curScene->mName); + LoadScene(path, true); + } + void SceneSystemImpl::Render() + { + if(curScene) _LIKELY + curScene->Render(); + } + void SceneSystemImpl::Update() + { + if(curScene) _LIKELY + curScene->Update(); + } + Scene* SceneSystemImpl::GetCurScene() + { + return curScene; + } + SINGLETON_DEFINE(SceneSystem) + SceneSystem::SceneSystem() + { + SINGLETON_PTR(); + impl = new (GlobalPool())SceneSystemImpl(); + } + void SceneSystem::Initialize() + { + + } + void SceneSystem::Finalize() + { + + } + void SceneSystem::LoadScene(PackagePath path, bool switchNow) + { + impl->LoadScene(path, switchNow); + } + void SceneSystem::SwitchScene(Name name) + { + impl->SwitchScene(name); + } + void SceneSystem::DeleteScene(Name name) + { + impl->DeleteScene(name); + } + void SceneSystem::DeleteAllScene() + { + impl->DeleteAllScene(); + } + void SceneSystem::ReloadScene() + { + impl->ReloadScene(); + } + void SceneSystem::Render() + { + impl->Render(); + } + void SceneSystem::Update() + { + impl->Update(); + } + Scene* SceneSystem::GetCurScene() + { + return impl->GetCurScene(); + } + Scene* SceneSystem::GetScene(Name name) + { + return impl->GetScene(name); + } +} \ No newline at end of file diff --git a/engine/modules/engine/app/include/app.inl b/engine/modules/engine/app/include/app.inl deleted file mode 100644 index c9c6410..0000000 --- a/engine/modules/engine/app/include/app.inl +++ /dev/null @@ -1,25 +0,0 @@ -namespace api { - template - class AppImpl { - void Setup() { - static_cast(this)->Setup(); - } - void CleanUp() { - static_cast(this)->CleanUp(); - } - void ImGui() { - static_cast(this)->ImGui(); - } - void PreRender() { - static_cast(this)->PreRender(); - } - void PostRender() { - static_cast(this)->PostRender(); - } - }; - template - inline void App::Run(EngineConfig config, AppImpl& impl) - { - impl.Setup(); - } -} \ No newline at end of file diff --git a/engine/modules/engine/app/include/app.h b/engine/modules/engine/app/include/app_module.h similarity index 55% rename from engine/modules/engine/app/include/app.h rename to engine/modules/engine/app/include/app_module.h index ff1281d..20c1bfc 100644 --- a/engine/modules/engine/app/include/app.h +++ b/engine/modules/engine/app/include/app_module.h @@ -1,6 +1,5 @@ #pragma once #include "module/module.h" -#include "data/engine_config.h" namespace api{ class APP_API AppModule : public IStaticModule { @@ -9,12 +8,4 @@ namespace api{ void OnUnload() override; void InitMetaData(void) override {}; }; - template - class AppImpl; - class App { - public: - template - void Run(EngineConfig config, AppImpl& impl); - }; -} -#include "app.inl" \ No newline at end of file +} \ No newline at end of file diff --git a/engine/modules/engine/app/include/data/editor_config.h b/engine/modules/engine/app/include/data/editor_config.h new file mode 100644 index 0000000..4738a53 --- /dev/null +++ b/engine/modules/engine/app/include/data/editor_config.h @@ -0,0 +1,9 @@ +#pragma once +#include "render/type.h" +namespace api{ + struct EditorConfig { + bool IsRenderEditorSurface = false; + bool IsGameStart = false; + bool isGamePause = false; + }; +} \ No newline at end of file diff --git a/engine/modules/engine/app/include/data/engine_config.h b/engine/modules/engine/app/include/data/engine_config.h index e590e22..84da196 100644 --- a/engine/modules/engine/app/include/data/engine_config.h +++ b/engine/modules/engine/app/include/data/engine_config.h @@ -3,9 +3,5 @@ namespace api{ struct EngineConfig { GraphicsAPI API = GraphicsAPI::Vulkan; -#ifdef WITH_EDITOR - bool IsRenderEditorSurface = false; -#endif // WITH_EDITOR - }; } \ No newline at end of file diff --git a/engine/modules/engine/app/include/data/global.h b/engine/modules/engine/app/include/data/global.h index 7a8a3a2..d8f6ab8 100644 --- a/engine/modules/engine/app/include/data/global.h +++ b/engine/modules/engine/app/include/data/global.h @@ -8,4 +8,11 @@ namespace api { constexpr const char* CFileMountName = "/work/assets/file_mount.meta"; extern APP_API EngineConfig gEngineConfig; -} \ No newline at end of file + extern APP_API ProjectConfig gProjectConfig; +} +#ifdef WITH_EDITOR +#include "editor_config.h" +namespace api{ + extern APP_API EditorConfig gEditorConfig; +} +#endif \ No newline at end of file diff --git a/engine/modules/engine/app/include/data/project_config.h b/engine/modules/engine/app/include/data/project_config.h index a92349d..5f2160d 100644 --- a/engine/modules/engine/app/include/data/project_config.h +++ b/engine/modules/engine/app/include/data/project_config.h @@ -1,5 +1,8 @@ #pragma once +#include "pmr/name.h" namespace api{ + using pmr::Name; struct ProjectConfig { + Name EntryScene; }; } \ No newline at end of file diff --git a/engine/modules/engine/app/include/object/component/transform.h b/engine/modules/engine/app/include/object/component/transform.h new file mode 100644 index 0000000..11614af --- /dev/null +++ b/engine/modules/engine/app/include/object/component/transform.h @@ -0,0 +1,7 @@ +#pragma once +#include "object/game_object.h" +namespace api { + class Transform : public Component { + + }; +} \ No newline at end of file diff --git a/engine/modules/engine/app/include/object/game_object.h b/engine/modules/engine/app/include/object/game_object.h new file mode 100644 index 0000000..54d5127 --- /dev/null +++ b/engine/modules/engine/app/include/object/game_object.h @@ -0,0 +1,31 @@ +#pragma once +#include "archive/reflect.h" +namespace api { + using pmr::Name; + using refl::TAny; + using std::vector; + class Component; + class GameObject { + private: + GENERATED_BODY() + UPROPERTY() + Name mName; + UPROPERTY() + vector> mChildrens; + UPROPERTY() + vector> mComponents; + public: + + }; + class Component { + private: + GENERATED_BODY() + UPROPERTY() + Name mName; + GameObject* mOwner; + + public: + + }; +} +#include ".app/game_object_gen.inl" \ No newline at end of file diff --git a/engine/modules/engine/app/include/scene/level.h b/engine/modules/engine/app/include/scene/level.h new file mode 100644 index 0000000..0228a7c --- /dev/null +++ b/engine/modules/engine/app/include/scene/level.h @@ -0,0 +1,26 @@ +#pragma once +#include "object/game_object.h" +#include "math/vector3.h" +namespace api { + using refl::TAny; + struct LevelInfo { + UPROPERTY() + Name mName; + UPROPERTY() + Name mPath; + UPROPERTY() + Vector3 mOffset; + }; + class Level : public LevelInfo{ + protected: + GENERATED_BODY() + UPROPERTY() + vector> mObjects; + public: + Level(const LevelInfo& info) : LevelInfo(info) {}; + Level(); + ~Level(); + void AddObject(TAny object); + }; +} +#include ".app/level_gen.inl" \ No newline at end of file diff --git a/engine/modules/engine/app/include/scene/level_blueprint.h b/engine/modules/engine/app/include/scene/level_blueprint.h new file mode 100644 index 0000000..8af3b41 --- /dev/null +++ b/engine/modules/engine/app/include/scene/level_blueprint.h @@ -0,0 +1,11 @@ +#pragma once +#include "object/game_object.h" +namespace api { + class Scene; + class LevelBlueprint { + public: + LevelBlueprint(); + ~LevelBlueprint(); + void LoadScene(Scene* scene); + }; +} \ No newline at end of file diff --git a/engine/modules/engine/app/include/scene/scene.h b/engine/modules/engine/app/include/scene/scene.h new file mode 100644 index 0000000..341467c --- /dev/null +++ b/engine/modules/engine/app/include/scene/scene.h @@ -0,0 +1,31 @@ +#pragma once +#include "level.h" +namespace api { + class LevelBlueprint; + struct SceneInfo { + UPROPERTY() + Name mName; + Name mPath; + UPROPERTY() + TAny mLevelBlueprint; + UPROPERTY() + vector mLevelInfos; + }; + class Scene : public SceneInfo{ + protected: + GENERATED_BODY() + + vector mLevels; + vector mObjects; + public: + Scene(const SceneInfo& info) : SceneInfo(info) {}; + Scene(); + ~Scene(); + void OnLoad(); + void Update(); + void Render(); + void AddLevel(Level* level); + void AddGameObject(GameObject* object); + }; +} +#include ".app/scene_gen.inl" \ No newline at end of file diff --git a/engine/modules/engine/app/include/scene/scene_system.h b/engine/modules/engine/app/include/scene/scene_system.h new file mode 100644 index 0000000..6316198 --- /dev/null +++ b/engine/modules/engine/app/include/scene/scene_system.h @@ -0,0 +1,25 @@ +#pragma once +#include "module/module.h" +namespace api { + class Scene; + class SceneSystemImpl; + class APP_API SceneSystem : public ISystem { + SINGLETON_IMPL(SceneSystem) + private: + SceneSystemImpl* impl; + public: + SceneSystem(); + void Initialize() override; + void Finalize() override; + public: + void LoadScene(PackagePath path, bool switchNow = true); + void SwitchScene(Name name); + void DeleteScene(Name name); + void DeleteAllScene(); + void ReloadScene(); + void Render(); + void Update(); + Scene* GetCurScene(); + Scene* GetScene(Name name); + }; +} \ No newline at end of file diff --git a/engine/modules/engine/app/src/app.cpp b/engine/modules/engine/app/src/app_module.cpp similarity index 66% rename from engine/modules/engine/app/src/app.cpp rename to engine/modules/engine/app/src/app_module.cpp index 89f8e39..16f1366 100644 --- a/engine/modules/engine/app/src/app.cpp +++ b/engine/modules/engine/app/src/app_module.cpp @@ -1,10 +1,11 @@ -#include "data/engine_config.h" #include "event/event_system.h" -#include "app.h" +#include "scene/scene_system.h" +#include "app_module.h" namespace api { void AppModule::OnLoad(int argc, char** argv) { AddSystem(); + AddSystem(); } void AppModule::OnUnload() { diff --git a/engine/modules/engine/app/src/object/component/transform.cpp b/engine/modules/engine/app/src/object/component/transform.cpp new file mode 100644 index 0000000..e69de29 diff --git a/engine/modules/engine/app/src/object/game_object.cpp b/engine/modules/engine/app/src/object/game_object.cpp new file mode 100644 index 0000000..e69de29 diff --git a/engine/modules/engine/app/src/scene/level.cpp b/engine/modules/engine/app/src/scene/level.cpp new file mode 100644 index 0000000..f4d8802 --- /dev/null +++ b/engine/modules/engine/app/src/scene/level.cpp @@ -0,0 +1,16 @@ +#include "scene/level.h" + +namespace api { + Level::Level() + { + + } + Level::~Level() + { + + } + void Level::AddObject(TAny object) + { + mObjects.push_back(object); + } +} diff --git a/engine/modules/engine/app/src/scene/level_blueprint.cpp b/engine/modules/engine/app/src/scene/level_blueprint.cpp new file mode 100644 index 0000000..9418371 --- /dev/null +++ b/engine/modules/engine/app/src/scene/level_blueprint.cpp @@ -0,0 +1,28 @@ +#include "scene/level_blueprint.h" +#include "scene/scene.h" +#include "os/file_handle.h" +#include "archive/pch.h" +namespace api { + LevelBlueprint::LevelBlueprint() + { + } + LevelBlueprint::~LevelBlueprint() + { + } + void LevelBlueprint::LoadScene(Scene* scene) + { + for (auto& levelInfo : scene->mLevelInfos) { + FileHandle handle(levelInfo.mPath); + if (!handle.Open(FILE_OP::READ)) { + continue; + } + Level* pLevel = new Level(levelInfo); + pmr::string text = handle.ReadAll(); + if (!TextDeserialize(text, pLevel)) { + delete pLevel; + continue; + } + scene->AddLevel(pLevel); + } + } +} diff --git a/engine/modules/engine/app/src/scene/scene.cpp b/engine/modules/engine/app/src/scene/scene.cpp new file mode 100644 index 0000000..d5b5bf7 --- /dev/null +++ b/engine/modules/engine/app/src/scene/scene.cpp @@ -0,0 +1,31 @@ +#include "scene/scene.h" +#include "scene/level_blueprint.h" +namespace api { + Scene::Scene() + { + + } + Scene::~Scene() + { + } + void Scene::OnLoad() + { + if (mLevelBlueprint) { + mLevelBlueprint->LoadScene(this); + } + } + void Scene::Update() + { + } + void Scene::Render() + { + } + void Scene::AddLevel(Level* level) + { + mLevels.push_back(level); + } + void Scene::AddGameObject(GameObject* object) + { + mObjects.push_back(object); + } +} diff --git a/engine/modules/engine/app/xmake.lua b/engine/modules/engine/app/xmake.lua index 81c3785..a15c5a9 100644 --- a/engine/modules/engine/app/xmake.lua +++ b/engine/modules/engine/app/xmake.lua @@ -1,4 +1,7 @@ static_component("app","engine") - add_headerfiles("include/**.h", "include/**.inl") + add_rules("c++.codegen",{ + files = {"include/object/**.h", "include/scene/*.h"} + }) + add_headerfiles("include/**.h") add_files("src/**.cpp") add_deps("core", "asset", "zlib", "render") \ No newline at end of file diff --git a/engine/modules/engine/core/include/archive/json.h b/engine/modules/engine/core/include/archive/json.h index 8d591a9..1c189c4 100644 --- a/engine/modules/engine/core/include/archive/json.h +++ b/engine/modules/engine/core/include/archive/json.h @@ -7,15 +7,15 @@ #define JSON_WRITE_FLAGS YYJSON_WRITE_NOFLAG #endif namespace gen { - template<> - inline bool JsonRead(yyjson_val* node, const refl::Any& t) { - if (!node) return false; - return api::JsonArchive::Deserialize(node, t); - } - template<> - inline yyjson_mut_val* JsonWrite(yyjson_mut_doc* doc, const refl::Any& t) { - return api::JsonArchive::Serialize(doc, t); - } + template + struct JsonSerde { + inline static bool Read(yyjson_val* val, const void* ptr) { + return api::JsonArchive::Deserialize(val, refl::Any{ ptr, refl::meta_info() }); + } + inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, const void* ptr) { + return api::JsonArchive::Serialize(doc, refl::Any{ ptr, refl::meta_info() }); + } + }; } namespace api { namespace detail { diff --git a/engine/modules/engine/core/include/archive/json/serde.inl b/engine/modules/engine/core/include/archive/json/serde.inl index c0efb3e..1e23dde 100644 --- a/engine/modules/engine/core/include/archive/json/serde.inl +++ b/engine/modules/engine/core/include/archive/json/serde.inl @@ -37,8 +37,8 @@ namespace gen { for (size_t i = 0; i < length; ++i) { yyjson_val* obj_i = yyjson_arr_get(val, i); if constexpr (refl::is_map_v) { - JsonRead(yyjson_obj_get(obj_i, "#k"), it.first); - JsonRead(yyjson_obj_get(obj_i, "#v"), it.second); + JsonRead(yyjson_obj_get(obj_i, MAP_KEY_NAME), it.first); + JsonRead(yyjson_obj_get(obj_i, MAP_VALUE_NAME), it.second); docker[it.first] = it.second; } else { @@ -54,8 +54,8 @@ namespace gen { if constexpr (refl::is_map_v) { for (auto& it : docker) { yyjson_mut_val* obj = yyjson_mut_obj(doc); - yyjson_mut_obj_add_val(doc, obj, "#k", JsonWrite(doc, it.first)); - yyjson_mut_obj_add_val(doc, obj, "#v", JsonWrite(doc, it.second)); + yyjson_mut_obj_add_val(doc, obj, MAP_KEY_NAME, JsonWrite(doc, it.first)); + yyjson_mut_obj_add_val(doc, obj, MAP_VALUE_NAME, JsonWrite(doc, it.second)); yyjson_mut_arr_add_val(arr, obj); } } diff --git a/engine/modules/engine/core/include/archive/json/serialize.inl b/engine/modules/engine/core/include/archive/json/serialize.inl index 6efc93b..3bad3be 100644 --- a/engine/modules/engine/core/include/archive/json/serialize.inl +++ b/engine/modules/engine/core/include/archive/json/serialize.inl @@ -66,7 +66,7 @@ namespace api { } yyjson_mut_val* obj = yyjson_mut_obj(doc); if (auto p = any.Parent()) { - yyjson_mut_obj_add_val(doc, obj, "__parent__", Serialize(doc, p)); + yyjson_mut_obj_add_val(doc, obj, PARENT_KEY_NAME, Serialize(doc, p)); } auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, pmr::Name("")); for (auto& field : fieldList) { diff --git a/engine/modules/engine/core/include/archive/reflect.h b/engine/modules/engine/core/include/archive/reflect.h new file mode 100644 index 0000000..66534ee --- /dev/null +++ b/engine/modules/engine/core/include/archive/reflect.h @@ -0,0 +1,77 @@ +#pragma once +#include "refl/pch.h" +#include "math/vector2.h" +#include "math/vector3.h" +#include "math/vector4.h" +namespace refl { + template<> struct Meta { + using T = api::Vector2; + using Impl = gen::MetaImpl; + }; +} +namespace refl { + template<> struct Meta { + using T = api::Vector3; + using Impl = gen::MetaImpl; + }; +} +namespace refl { + template<> struct Meta { + using T = api::Vector4; + using Impl = gen::MetaImpl; + }; +} +namespace gen { + template<> struct MetaImpl : public refl::MetaHelp { + using T = api::Vector2; + consteval static int MemberCount() { return 2; }; + consteval static int StaticMemberCount() { return 0; }; + consteval static int CtorCount() { return 0; }; + consteval static auto Fields() { + return std::make_tuple(FProperty(&T::x, "x"), FProperty(&T::y, "y")); + } + static auto MakeFields() { + return std::array{ + MemberField(&T::x, "x", {}), + MemberField(&T::y, "y", {}), + }; + }; + }; +} +namespace gen { + template<> struct MetaImpl : public refl::MetaHelp { + using T = api::Vector3; + consteval static int MemberCount() { return 3; }; + consteval static int StaticMemberCount() { return 0; }; + consteval static int CtorCount() { return 0; }; + consteval static auto Fields() { + return std::make_tuple(FProperty(&T::x, "x"), FProperty(&T::y, "y"), FProperty(&T::z, "z")); + } + static auto MakeFields() { + return std::array{ + MemberField(&T::x, "x", {}), + MemberField(&T::y, "y", {}), + MemberField(&T::z, "z", {}), + }; + }; + }; +} +namespace gen { + template<> struct MetaImpl : public refl::MetaHelp { + using T = api::Vector4; + consteval static int MemberCount() { return 4; }; + consteval static int StaticMemberCount() { return 0; }; + consteval static int CtorCount() { return 0; }; + consteval static auto Fields() { + return std::make_tuple(FProperty(&T::x, "x"), FProperty(&T::y, "y"), FProperty(&T::z, "z"), FProperty(&T::w, "w")); + } + static auto MakeFields() { + return std::array{ + MemberField(&T::x, "x", {}), + MemberField(&T::y, "y", {}), + MemberField(&T::z, "z", {}), + MemberField(&T::w, "w", {}), + }; + }; + }; +} \ No newline at end of file diff --git a/engine/modules/engine/core/include/archive/type.h b/engine/modules/engine/core/include/archive/type.h index 132144c..53912c4 100644 --- a/engine/modules/engine/core/include/archive/type.h +++ b/engine/modules/engine/core/include/archive/type.h @@ -1,6 +1,12 @@ #pragma once #include "meta/result.h" #include "refl/pch.h" +#define PARENT_KEY_NAME "__parent__" +#define CLASS_KEY_NAME "__class__" +#define DATA_KEY_NAME "__data__" +#define MAP_KEY_NAME "#k" +#define MAP_VALUE_NAME "#v" + namespace gen { template struct Meta {}; @@ -15,6 +21,9 @@ namespace gen { template concept is_serde_v = std::is_same_v || std::is_integral_v || std::is_floating_point_v || is_string_v || std::is_enum_v || is_string_view_v; + + template + concept is_any_v = std::is_base_of_v; } namespace api { using meta::result; diff --git a/engine/modules/engine/core/include/archive/yaml.h b/engine/modules/engine/core/include/archive/yaml.h index c55c568..1ad6732 100644 --- a/engine/modules/engine/core/include/archive/yaml.h +++ b/engine/modules/engine/core/include/archive/yaml.h @@ -1,15 +1,15 @@ #include "yaml/serde.inl" #include "yaml/serialize.inl" namespace gen { - template<> - inline bool YamlRead(const YAML::Node& node, const refl::Any& t) { - if (!node) return false; - return api::YamlArchive::Deserialize(node, refl::Any{ &t, refl::meta_info() }); - } - template<> - inline YAML::Node YamlWrite(const refl::Any& t) { - return api::YamlArchive::Serialize(refl::Any{&t, refl::meta_info()}); - } + template + struct YamlSerde { + inline static bool Read(const YAML::Node& node, const void* ptr) { + return api::YamlArchive::Deserialize(node, refl::Any{ ptr, refl::meta_info() }); + } + inline static YAML::Node Write(const void* ptr) { + return api::YamlArchive::Serialize(refl::Any{ ptr, refl::meta_info() }); + } + }; } namespace YAML { inline Node APILoad(std::string_view text) { diff --git a/engine/modules/engine/core/include/archive/yaml/serde.inl b/engine/modules/engine/core/include/archive/yaml/serde.inl index 299d533..cba7aa9 100644 --- a/engine/modules/engine/core/include/archive/yaml/serde.inl +++ b/engine/modules/engine/core/include/archive/yaml/serde.inl @@ -13,6 +13,10 @@ namespace gen { struct YamlSerde>> { inline static bool Read(const YAML::Node& node, const void* ptr) { T& v = *(T*)ptr; + if constexpr (refl::has_parent_v) { + using P = refl::parent_t; + YamlRead>(node[PARENT_KEY_NAME], *(P*)ptr); + } for_each_field([&](std::string_view name, auto&& value) { YamlRead(node[name], value); }, v); @@ -21,6 +25,10 @@ namespace gen { inline static YAML::Node Write(const void* ptr) { T& v = *(T*)ptr; YAML::Node node; + if constexpr (refl::has_parent_v) { + using P = refl::parent_t; + node[PARENT_KEY_NAME] = YamlWrite

(*(P*)ptr); + } for_each_field([&](std::string_view name, auto&& value) { node[name] = YamlWrite(value); }, v); @@ -35,8 +43,8 @@ namespace gen { value_type_t it;//构造失败怎么办? for (auto node_i : node) { if constexpr (refl::is_map_v) { - YamlRead(node_i["#k"], it.first); - YamlRead(node_i["#v"], it.second); + YamlRead(node_i[MAP_KEY_NAME], it.first); + YamlRead(node_i[MAP_VALUE_NAME], it.second); docker[it.first] = it.second; } else { @@ -52,8 +60,8 @@ namespace gen { if constexpr (refl::is_map_v) { for (auto& it : docker) { YAML::Node node_i; - node_i["#k"] = YamlWrite(it.first); - node_i["#v"] = YamlWrite(it.second); + node_i[MAP_KEY_NAME] = YamlWrite(it.first); + node_i[MAP_VALUE_NAME] = YamlWrite(it.second); node.push_back(node_i); } } diff --git a/engine/modules/engine/core/include/archive/yaml/serialize.inl b/engine/modules/engine/core/include/archive/yaml/serialize.inl index 88ef307..40a96d8 100644 --- a/engine/modules/engine/core/include/archive/yaml/serialize.inl +++ b/engine/modules/engine/core/include/archive/yaml/serialize.inl @@ -36,11 +36,11 @@ namespace api { return Serialize(any.Parent()); } YAML::Node result; - if (any.cls == meta_info()) { + if (any.Check(meta_info())) { Any obj = any.CastTo(); if (obj) { - result["__class__"] = obj.cls->name.ToStringView(); - result["__data__"] = Serialize(obj); + result[CLASS_KEY_NAME] = obj.cls->name.ToStringView(); + result[DATA_KEY_NAME] = Serialize(obj); } return result; } @@ -68,7 +68,7 @@ namespace api { return result; } if (Any p = any.Parent()) { - result["__parent__"] = Serialize(p); + result[PARENT_KEY_NAME] = Serialize(p); } auto fieldList = any.cls->GetFields(refl::FIND_ALL_MEMBER, Name("")); for (auto& field : fieldList) { @@ -89,8 +89,8 @@ namespace api { if (any.IsEnum()) { return Deserialize(res, any.Parent()); } - if (any.cls == meta_info() && res) { - auto __class = res["__class__"]; + if (any.Check(meta_info()) && res) { + auto __class = res[CLASS_KEY_NAME]; if (!__class) { return false; } @@ -99,7 +99,7 @@ namespace api { if (cls) { Any obj = cls->New(FramePool()); *any.CastTo() = obj; - return Deserialize(res["__data__"], obj); + return Deserialize(res[DATA_KEY_NAME], obj); } *any.CastTo() = {}; return false; diff --git a/engine/modules/engine/core/include/os/file_system.h b/engine/modules/engine/core/include/os/file_system.h index a25dac0..54ba337 100644 --- a/engine/modules/engine/core/include/os/file_system.h +++ b/engine/modules/engine/core/include/os/file_system.h @@ -2,4 +2,5 @@ namespace fs { std::string GetExecutablePath(); std::string GetWorkPath(); + void EnsurePathExists(std::string_view path); } \ No newline at end of file diff --git a/engine/modules/engine/core/src/module/module.cpp b/engine/modules/engine/core/src/module/module.cpp index e983582..4fdcf24 100644 --- a/engine/modules/engine/core/src/module/module.cpp +++ b/engine/modules/engine/core/src/module/module.cpp @@ -1,10 +1,14 @@ #include "module/module_manager.h" #include "os/file_manager.h" #include "archive/pch.h" +#include "archive/reflect.h" namespace api { void CoreModule::OnLoad(int argc, char** argv) { TextArchive::InitSerde(); + TextArchive::Register(); + TextArchive::Register(); + TextArchive::Register(); } void CoreModule::OnUnload() { diff --git a/engine/modules/engine/core/src/os/file_handle.cpp b/engine/modules/engine/core/src/os/file_handle.cpp index 574651b..d0565d8 100644 --- a/engine/modules/engine/core/src/os/file_handle.cpp +++ b/engine/modules/engine/core/src/os/file_handle.cpp @@ -1,4 +1,5 @@ #include "os/file_handle.h" +#include "os/file_system.h" #include #define READ_DATA_SIZE 100 #define TOKEN_SIZE 100 @@ -24,6 +25,7 @@ namespace api { break; } case api::FILE_OP::WRITE: + fs::EnsurePathExists(file_path); vfile = std::ofstream(file_path.c_str(), is_binarry ? std::ios::binary : 0); break; case api::FILE_OP::APPEND: diff --git a/engine/modules/engine/core/src/os/file_system.cpp b/engine/modules/engine/core/src/os/file_system.cpp index 6b811be..efbeb7e 100644 --- a/engine/modules/engine/core/src/os/file_system.cpp +++ b/engine/modules/engine/core/src/os/file_system.cpp @@ -44,4 +44,15 @@ namespace fs { return path.string(); } + void EnsurePathExists(std::string_view path) + { + size_t pos = path.find_last_of("\\/"); + if (std::string::npos != pos){ + std::string_view dir = path.substr(0, pos); + if (!std::filesystem::exists(dir)) { + std::filesystem::create_directories(dir); // Ŀ¼ڣ򴴽 + } + } + } + } \ No newline at end of file diff --git a/engine/modules/engine/zlib/include/pmr/name.h b/engine/modules/engine/zlib/include/pmr/name.h index 85fb623..2812982 100644 --- a/engine/modules/engine/zlib/include/pmr/name.h +++ b/engine/modules/engine/zlib/include/pmr/name.h @@ -209,6 +209,7 @@ namespace pmr { const StringEntry* stringEntry = UNIQUER_VAL(stringEntryMemoryManager).GetStringEntry(StringEntryHandle(flag3_memory29)); return std::string(stringEntry->GetData(), stringEntry->GetSize()); } + static Name Find(std::string_view view); }; class Tag { diff --git a/engine/modules/engine/zlib/include/pmr/name.inl b/engine/modules/engine/zlib/include/pmr/name.inl index 873b751..97eddf5 100644 --- a/engine/modules/engine/zlib/include/pmr/name.inl +++ b/engine/modules/engine/zlib/include/pmr/name.inl @@ -152,4 +152,23 @@ namespace pmr { } return slotValue; } + inline Name Name::Find(std::string_view view) { + Name result{}; + if (!view.empty()) { + HashInfo hashInfo(view); + auto& stringEntryMemoryManager = UNIQUER_VAL(stringEntryMemoryManager); + auto& slotPool = stringEntryMemoryManager.slotPoolArray[hashInfo.GetSlotPoolIndex()]; + uint32_t slotValue = 0u; + { + std::unique_lock lock(slotPool.mutex); + Name::Slot& slot = slotPool.FindUnusedOrTargetSlot(hashInfo); + if (slot.IsUsed()) + { + result.flag3_memory29 = slot.GetSlotValue(); + return result; + } + } + } + return result; + } } \ No newline at end of file diff --git a/engine/modules/engine/zlib/include/refl/detail/any.h b/engine/modules/engine/zlib/include/refl/detail/any.h index 1d8faf7..d00bb42 100644 --- a/engine/modules/engine/zlib/include/refl/detail/any.h +++ b/engine/modules/engine/zlib/include/refl/detail/any.h @@ -15,7 +15,7 @@ namespace refl { constexpr Any() noexcept: ptr(nullptr), cls(nullptr) {} constexpr Any(const void* ptr, const UClass* cls) noexcept : ptr(ptr), cls(cls) {} template - constexpr Any(T&& v) noexcept : ptr(&v), cls(meta_info()) {} + constexpr Any(T&& v) noexcept : ptr(&v), cls(meta_info>()) {} template constexpr Any(T* v) noexcept : ptr(v), cls(meta_info()) {} template//参数 T* => T* @@ -63,4 +63,16 @@ namespace refl { Destruct(); } }; + template + class TAny : public Any{ + public: + TAny() : Any(){} + TAny(T* t) : Any(t){} + T* operator->() { + return (T*)ptr; + } + }; + template struct Meta> { + using Parent = Any; + }; } \ No newline at end of file diff --git a/engine/modules/engine/zlib/include/refl/detail/container.inl b/engine/modules/engine/zlib/include/refl/detail/container.inl index a26b627..f717799 100644 --- a/engine/modules/engine/zlib/include/refl/detail/container.inl +++ b/engine/modules/engine/zlib/include/refl/detail/container.inl @@ -15,7 +15,7 @@ namespace refl { Any malloc(pmr::memory_resource* alloc)const { void* it = alloc->allocate(cls->parent->size); cls->Construct(it); - return Any{ it, cls }; + return Any{ it, cls->parent }; } span GetFields() { return cls->parent->GetFields(EFieldFind::FIND_ALL_MEMBER, Name("")); diff --git a/engine/modules/engine/zlib/include/refl/detail/uclass.inl b/engine/modules/engine/zlib/include/refl/detail/uclass.inl index 427e0f5..614def9 100644 --- a/engine/modules/engine/zlib/include/refl/detail/uclass.inl +++ b/engine/modules/engine/zlib/include/refl/detail/uclass.inl @@ -26,6 +26,10 @@ namespace refl { flag = CLASS_ENUM_FLAG; parent = meta_info>(); } + else if constexpr (has_parent_v) { + flag |= CLASS_PARENT_FLAG; + parent = meta_info>(); + } vtable.AddConstruct(&UClass::Construct); vtable.AddDestruct(&UClass::Destruct); } @@ -170,6 +174,7 @@ namespace refl { FieldsType Fields{ MetaImpl::MakeFields() }; UClass_Meta() : UClass(meta_name(), sizeof(T)) { if constexpr (has_parent_v) { + flag |= CLASS_PARENT_FLAG; parent = meta_info>(); } vtable.AddGetFields(&UClass_Meta::GetFields); diff --git a/engine/modules/render/vulkan/src/vulkan_ui_system.cpp b/engine/modules/render/vulkan/src/vulkan_ui_system.cpp index 42da507..fa1099b 100644 --- a/engine/modules/render/vulkan/src/vulkan_ui_system.cpp +++ b/engine/modules/render/vulkan/src/vulkan_ui_system.cpp @@ -16,8 +16,8 @@ namespace vkn { void vkn::VulkanUISystem::OnBeginRenderFrame(FrameGraph& graph, uint32_t frame) { #ifdef WITH_EDITOR - graph.mIsRenderEditorSurface = gEngineConfig.IsRenderEditorSurface; - if (gEngineConfig.IsRenderEditorSurface) { + graph.mIsRenderEditorSurface = gEditorConfig.IsRenderEditorSurface; + if (gEditorConfig.IsRenderEditorSurface) { graph.mEditorSurfaceID = graph.mSurfaceID; graph.mSurfaceID = graph.GetTextureID(FrameGraph::NameEditorSurface, frame); } @@ -38,7 +38,7 @@ namespace vkn { .Type(RenderPassNodeType::Imgui, RenderPassNodeFlag::Output) .Write(graph.GetRenderSurface(), ResourceState::COLOR_ATTACHMENT) .Write(stencil, ResourceState::DEPTH_ATTACHMENT); - if (gEngineConfig.IsRenderEditorSurface) { + if (gEditorConfig.IsRenderEditorSurface) { builder.Read(graph.GetSurface(), ResourceState::READ_ONLY); } } diff --git a/engine/src/editor/window/editor_main_window.cpp b/engine/src/editor/window/editor_main_window.cpp index c895920..4fddbad 100644 --- a/engine/src/editor/window/editor_main_window.cpp +++ b/engine/src/editor/window/editor_main_window.cpp @@ -75,7 +75,7 @@ namespace api { ImGui::Begin("MainWindow", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar); ImGui::Text("This is some useful text."); ImGui::SliderFloat("float", &my_float, 0.0f, 1.0f); - if (gEngineConfig.IsRenderEditorSurface) { + if (gEditorConfig.IsRenderEditorSurface) { TextureDesc surface = graph.GetSurface(); if (!TextureIDList[ctx.frame]) { TextureIDList[ctx.frame] = ctx->AddTexture(graph, surface, sampler); @@ -84,7 +84,7 @@ namespace api { ImGui::Image(TextureIDList[ctx.frame], ImVec2(surface.width, surface.height)); } else { - gEngineConfig.IsRenderEditorSurface = true; + gEditorConfig.IsRenderEditorSurface = true; InitRenderSurface(graph, ctx.frameCount); } ImGui::End(); diff --git a/engine/src/engine/app.cpp b/engine/src/engine/app.cpp new file mode 100644 index 0000000..b63afcf --- /dev/null +++ b/engine/src/engine/app.cpp @@ -0,0 +1,54 @@ +#include "engine/app.h" +#include "scene/scene_system.h" +#include "os/file_manager.h" + +#include "scene/scene.h" +#include "scene/level_blueprint.h" +#include "object/component/transform.h" +#include "os/file_handle.h" +#include "archive/pch.h" +namespace api{ + void CreateDemoScene() { + LevelInfo levelInfo{ "main", "/scene/entry/main.level", Vector3(0, 255, 0) }; + SceneInfo sceneInfo{}; + sceneInfo.mName = "entry"; + sceneInfo.mPath = "/scene/entry.scene"; + sceneInfo.mLevelBlueprint = TAny(new LevelBlueprint()); + sceneInfo.mLevelInfos.push_back(levelInfo); + + Level level{ levelInfo }; + GameObject* obj1 = new GameObject(); + level.AddObject(obj1); + { + FileHandle handle(levelInfo.mPath); + handle.Open(FILE_OP::WRITE); + handle.Write(TextSerialize(level)); + } + Scene scene{ sceneInfo }; + scene.AddLevel(&level); + { + FileHandle handle(sceneInfo.mPath); + handle.Open(FILE_OP::WRITE); + handle.Write(TextSerialize(scene)); + } + } + bool App::Launch() + { + PackagePath scenePath{ "/engine/assets/scene" }; + FileManager::Ptr()->Mount("scene", scenePath.RealPath().c_str()); + CreateDemoScene(); + gProjectConfig.EntryScene = "/scene/entry.scene"; + SceneSystem::Ptr()->LoadScene(gProjectConfig.EntryScene); + return true; + } + void App::Update() + { +#ifdef WITH_EDITOR + gEditorConfig.IsGameStart = true; + if(gEditorConfig.IsGameStart && !gEditorConfig.isGamePause) + SceneSystem::Ptr()->Update(); +#else + SceneSystem::Ptr()->Update(); +#endif // WITH_EDITOR + } +} \ No newline at end of file diff --git a/engine/src/engine/plugin.cpp b/engine/src/engine/plugin.cpp index d65dbae..ba1f02f 100644 --- a/engine/src/engine/plugin.cpp +++ b/engine/src/engine/plugin.cpp @@ -29,8 +29,10 @@ IMPLEMENT_STATIC_MODULE(RENDER_API, api::RenderModule, render); #ifndef APP_API_VAL #define APP_API_VAL 1 +#include "app_module.h" #include "app_impl.inl" #include "event_system_impl.inl" +#include "scene_system_impl.inl" IMPLEMENT_STATIC_MODULE(APP_API, api::AppModule, app) #endif // !APP_API_VAL diff --git a/engine/xmake/rule_api/package_api.lua b/engine/xmake/rule_api/package_api.lua index ef7ea56..f91d8cf 100644 --- a/engine/xmake/rule_api/package_api.lua +++ b/engine/xmake/rule_api/package_api.lua @@ -5,6 +5,9 @@ function main(target) local link = pkg:get("links") local targetdir = target:targetdir() link = link[1] or link + if is_mode("debug") and not os.isdir(targetdir) then + os.mkdir(targetdir) + end if link and os.isdir(targetdir) and not os.isfile(path.join(targetdir, link .. ".lib")) then local linkdirs = pkg:get("linkdirs") os.trycp(linkdirs.."/*", targetdir) diff --git a/game/zworld/src/zworld.cpp b/game/zworld/src/zworld.cpp index 520d154..d56ecde 100644 --- a/game/zworld/src/zworld.cpp +++ b/game/zworld/src/zworld.cpp @@ -1,10 +1,10 @@ #include "zlog.h" #include "zworld.h" -#include "data/global.h" #include "event/event_system.h" #include "vkn/vulkan_window.h" #include "vkn/vulkan_api.h" #include "render/pass/demo_pass.h" +#include "engine/app.h" #ifdef WITH_EDITOR #include "imgui/imgui_impl_sdl2.h" #endif @@ -48,8 +48,9 @@ void ZWorldModule::OnUnload() void ZWorldModule::MainLoop() { - bool running = true; SDL_Event event_; + App app; + bool running = app.Launch(); while (running) { // 处理事件 while (SDL_PollEvent(&event_)) { @@ -59,7 +60,8 @@ void ZWorldModule::MainLoop() if (event_.type == SDL_QUIT) { running = false; } - } + } + app.Update(); API->BeginFrame(); API->Render(); API->EndFrame();