support scene serialize

This commit is contained in:
ouczbs 2025-02-11 11:16:46 +08:00
parent cb1c7ad1e5
commit 3d404294ab
50 changed files with 700 additions and 92 deletions

View File

@ -4,6 +4,7 @@
"bitmap.c": "cpp",
"heap.c": "cpp",
"init.c": "cpp",
"random.c": "cpp"
"random.c": "cpp",
"type_traits": "cpp"
}
}

View File

@ -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 开发完整的编辑器工具。

BIN
engine/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -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

View File

@ -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: ~

View File

@ -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();
};
}

View File

@ -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
}

View File

@ -0,0 +1,163 @@
#include "scene/scene_system.h"
#include "scene/scene.h"
namespace api {
class SceneSystemImpl
{
public:
Scene* curScene = nullptr;
table<Name, Scene*> scenes;
table<Name, Name> 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<pmr::string>();
pScene = new Scene();
if (!TextDeserialize<Scene>(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);
}
}

View File

@ -1,25 +0,0 @@
namespace api {
template<typename T>
class AppImpl {
void Setup() {
static_cast<T*>(this)->Setup();
}
void CleanUp() {
static_cast<T*>(this)->CleanUp();
}
void ImGui() {
static_cast<T*>(this)->ImGui();
}
void PreRender() {
static_cast<T*>(this)->PreRender();
}
void PostRender() {
static_cast<T*>(this)->PostRender();
}
};
template<typename T>
inline void App::Run(EngineConfig config, AppImpl<T>& impl)
{
impl.Setup();
}
}

View File

@ -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<typename T>
class AppImpl;
class App {
public:
template<typename T>
void Run(EngineConfig config, AppImpl<T>& impl);
};
}
#include "app.inl"
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "render/type.h"
namespace api{
struct EditorConfig {
bool IsRenderEditorSurface = false;
bool IsGameStart = false;
bool isGamePause = false;
};
}

View File

@ -3,9 +3,5 @@
namespace api{
struct EngineConfig {
GraphicsAPI API = GraphicsAPI::Vulkan;
#ifdef WITH_EDITOR
bool IsRenderEditorSurface = false;
#endif // WITH_EDITOR
};
}

View File

@ -8,4 +8,11 @@ namespace api {
constexpr const char* CFileMountName = "/work/assets/file_mount.meta";
extern APP_API EngineConfig gEngineConfig;
}
extern APP_API ProjectConfig gProjectConfig;
}
#ifdef WITH_EDITOR
#include "editor_config.h"
namespace api{
extern APP_API EditorConfig gEditorConfig;
}
#endif

View File

@ -1,5 +1,8 @@
#pragma once
#include "pmr/name.h"
namespace api{
using pmr::Name;
struct ProjectConfig {
Name EntryScene;
};
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "object/game_object.h"
namespace api {
class Transform : public Component {
};
}

View File

@ -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<TAny<GameObject>> mChildrens;
UPROPERTY()
vector<TAny<Component>> mComponents;
public:
};
class Component {
private:
GENERATED_BODY()
UPROPERTY()
Name mName;
GameObject* mOwner;
public:
};
}
#include ".app/game_object_gen.inl"

View File

@ -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<TAny<GameObject>> mObjects;
public:
Level(const LevelInfo& info) : LevelInfo(info) {};
Level();
~Level();
void AddObject(TAny<GameObject> object);
};
}
#include ".app/level_gen.inl"

View File

@ -0,0 +1,11 @@
#pragma once
#include "object/game_object.h"
namespace api {
class Scene;
class LevelBlueprint {
public:
LevelBlueprint();
~LevelBlueprint();
void LoadScene(Scene* scene);
};
}

View File

@ -0,0 +1,31 @@
#pragma once
#include "level.h"
namespace api {
class LevelBlueprint;
struct SceneInfo {
UPROPERTY()
Name mName;
Name mPath;
UPROPERTY()
TAny<LevelBlueprint> mLevelBlueprint;
UPROPERTY()
vector<LevelInfo> mLevelInfos;
};
class Scene : public SceneInfo{
protected:
GENERATED_BODY()
vector<Level*> mLevels;
vector<GameObject*> 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"

View File

@ -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);
};
}

View File

@ -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<EventSystem>();
AddSystem<SceneSystem>();
}
void AppModule::OnUnload()
{

View File

@ -0,0 +1,16 @@
#include "scene/level.h"
namespace api {
Level::Level()
{
}
Level::~Level()
{
}
void Level::AddObject(TAny<GameObject> object)
{
mObjects.push_back(object);
}
}

View File

@ -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<pmr::string>();
if (!TextDeserialize<Level>(text, pLevel)) {
delete pLevel;
continue;
}
scene->AddLevel(pLevel);
}
}
}

View File

@ -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);
}
}

View File

@ -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")

View File

@ -7,15 +7,15 @@
#define JSON_WRITE_FLAGS YYJSON_WRITE_NOFLAG
#endif
namespace gen {
template<>
inline bool JsonRead<refl::Any>(yyjson_val* node, const refl::Any& t) {
if (!node) return false;
return api::JsonArchive::Deserialize(node, t);
}
template<>
inline yyjson_mut_val* JsonWrite<refl::Any>(yyjson_mut_doc* doc, const refl::Any& t) {
return api::JsonArchive::Serialize(doc, t);
}
template<is_any_v T>
struct JsonSerde<T> {
inline static bool Read(yyjson_val* val, const void* ptr) {
return api::JsonArchive::Deserialize(val, refl::Any{ ptr, refl::meta_info<refl::Any>() });
}
inline static yyjson_mut_val* Write(yyjson_mut_doc* doc, const void* ptr) {
return api::JsonArchive::Serialize(doc, refl::Any{ ptr, refl::meta_info<refl::Any>() });
}
};
}
namespace api {
namespace detail {

View File

@ -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<T>) {
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<T>) {
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);
}
}

View File

@ -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) {

View File

@ -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<api::Vector2> {
using T = api::Vector2;
using Impl = gen::MetaImpl<T, string_hash("Meta")>;
};
}
namespace refl {
template<> struct Meta<api::Vector3> {
using T = api::Vector3;
using Impl = gen::MetaImpl<T, string_hash("Meta")>;
};
}
namespace refl {
template<> struct Meta<api::Vector4> {
using T = api::Vector4;
using Impl = gen::MetaImpl<T, string_hash("Meta")>;
};
}
namespace gen {
template<> struct MetaImpl<api::Vector2, string_hash("Meta")> : 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<api::Vector3, string_hash("Meta")> : 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<api::Vector4, string_hash("Meta")> : 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", {}),
};
};
};
}

View File

@ -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<typename T>
struct Meta {};
@ -15,6 +21,9 @@ namespace gen {
template<typename T>
concept is_serde_v = std::is_same_v<T, bool> || std::is_integral_v<T> || std::is_floating_point_v<T> || is_string_v<T> || std::is_enum_v<T>
|| is_string_view_v<T>;
template<typename T>
concept is_any_v = std::is_base_of_v<refl::Any, T>;
}
namespace api {
using meta::result;

View File

@ -1,15 +1,15 @@
#include "yaml/serde.inl"
#include "yaml/serialize.inl"
namespace gen {
template<>
inline bool YamlRead<refl::Any>(const YAML::Node& node, const refl::Any& t) {
if (!node) return false;
return api::YamlArchive::Deserialize(node, refl::Any{ &t, refl::meta_info<refl::Any>() });
}
template<>
inline YAML::Node YamlWrite<refl::Any>(const refl::Any& t) {
return api::YamlArchive::Serialize(refl::Any{&t, refl::meta_info<refl::Any>()});
}
template<is_any_v T>
struct YamlSerde<T> {
inline static bool Read(const YAML::Node& node, const void* ptr) {
return api::YamlArchive::Deserialize(node, refl::Any{ ptr, refl::meta_info<refl::Any>() });
}
inline static YAML::Node Write(const void* ptr) {
return api::YamlArchive::Serialize(refl::Any{ ptr, refl::meta_info<refl::Any>() });
}
};
}
namespace YAML {
inline Node APILoad(std::string_view text) {

View File

@ -13,6 +13,10 @@ namespace gen {
struct YamlSerde<T, std::enable_if_t<refl::is_meta_v<T>>> {
inline static bool Read(const YAML::Node& node, const void* ptr) {
T& v = *(T*)ptr;
if constexpr (refl::has_parent_v<T>) {
using P = refl::parent_t<T>;
YamlRead<refl::parent_t<T>>(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<T>) {
using P = refl::parent_t<T>;
node[PARENT_KEY_NAME] = YamlWrite<P>(*(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<T>) {
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<T>) {
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);
}
}

View File

@ -36,11 +36,11 @@ namespace api {
return Serialize(any.Parent());
}
YAML::Node result;
if (any.cls == meta_info<Any>()) {
if (any.Check(meta_info<Any>())) {
Any obj = any.CastTo<Any>();
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<Any>() && res) {
auto __class = res["__class__"];
if (any.Check(meta_info<Any>()) && 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<Any*>() = obj;
return Deserialize(res["__data__"], obj);
return Deserialize(res[DATA_KEY_NAME], obj);
}
*any.CastTo<Any*>() = {};
return false;

View File

@ -2,4 +2,5 @@
namespace fs {
std::string GetExecutablePath();
std::string GetWorkPath();
void EnsurePathExists(std::string_view path);
}

View File

@ -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<Vector2>();
TextArchive::Register<Vector3>();
TextArchive::Register<Vector4>();
}
void CoreModule::OnUnload()
{

View File

@ -1,4 +1,5 @@
#include "os/file_handle.h"
#include "os/file_system.h"
#include <algorithm>
#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:

View File

@ -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); // 如果目录不存在,则创建它
}
}
}
}

View File

@ -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 {

View File

@ -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<std::mutex> lock(slotPool.mutex);
Name::Slot& slot = slotPool.FindUnusedOrTargetSlot(hashInfo);
if (slot.IsUsed())
{
result.flag3_memory29 = slot.GetSlotValue();
return result;
}
}
}
return result;
}
}

View File

@ -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<is_not_any_v T>
constexpr Any(T&& v) noexcept : ptr(&v), cls(meta_info<T>()) {}
constexpr Any(T&& v) noexcept : ptr(&v), cls(meta_info<std::remove_reference_t<T>>()) {}
template<is_not_any_v T>
constexpr Any(T* v) noexcept : ptr(v), cls(meta_info<T>()) {}
template<typename T>//参数 T* => T*
@ -63,4 +63,16 @@ namespace refl {
Destruct();
}
};
template<typename T>
class TAny : public Any{
public:
TAny() : Any(){}
TAny(T* t) : Any(t){}
T* operator->() {
return (T*)ptr;
}
};
template<typename T> struct Meta<TAny<T>> {
using Parent = Any;
};
}

View File

@ -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<const FieldPtr> GetFields() {
return cls->parent->GetFields(EFieldFind::FIND_ALL_MEMBER, Name(""));

View File

@ -26,6 +26,10 @@ namespace refl {
flag = CLASS_ENUM_FLAG;
parent = meta_info<std::underlying_type_t<T>>();
}
else if constexpr (has_parent_v<T>) {
flag |= CLASS_PARENT_FLAG;
parent = meta_info<parent_t<T>>();
}
vtable.AddConstruct(&UClass::Construct<T>);
vtable.AddDestruct(&UClass::Destruct<T>);
}
@ -170,6 +174,7 @@ namespace refl {
FieldsType Fields{ MetaImpl::MakeFields() };
UClass_Meta() : UClass(meta_name<T>(), sizeof(T)) {
if constexpr (has_parent_v<T>) {
flag |= CLASS_PARENT_FLAG;
parent = meta_info<parent_t<T>>();
}
vtable.AddGetFields(&UClass_Meta::GetFields);

View File

@ -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);
}
}

View File

@ -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();

54
engine/src/engine/app.cpp Normal file
View File

@ -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<LevelBlueprint>(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
}
}

View File

@ -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

View File

@ -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)

View File

@ -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();