From 8bfb35580b673f8664fc65ee37b3194a7b0a7386 Mon Sep 17 00:00:00 2001 From: Egor Orachyov Date: Mon, 28 Oct 2024 01:34:13 +0300 Subject: [PATCH] gh-36: setup new scene mng api & introduce game module --- .vscode/settings.json | 4 +- README.md | 9 +- .../runtime/asset/default_asset_loader.cpp | 12 +- engine/runtime/asset/asset_loader.hpp | 3 - engine/runtime/asset/asset_manager.hpp | 1 - engine/runtime/asset/asset_ref.hpp | 50 +---- engine/runtime/core/any_storage.hpp | 2 +- engine/runtime/core/string_id.cpp | 2 +- engine/runtime/ecs/ecs_component.hpp | 3 - engine/runtime/ecs/ecs_query.hpp | 31 ++- engine/runtime/ecs/ecs_registry.hpp | 6 +- engine/runtime/ecs/ecs_world.cpp | 11 +- engine/runtime/ecs/ecs_world.hpp | 9 +- engine/runtime/engine.hpp | 3 +- .../scene_packed.cpp => game/_rtti.cpp} | 17 +- .../scene_components.cpp => game/_rtti.hpp} | 8 +- engine/runtime/game/debug/components.hpp | 70 +++++++ engine/runtime/game/debug/features.cpp | 61 ++++++ engine/runtime/game/debug/features.hpp | 119 +++++++++++ engine/runtime/game/debug/systems.cpp | 86 ++++++++ engine/runtime/game/debug/systems.hpp | 57 ++++++ engine/runtime/game/game_manager.cpp | 77 +++++++ engine/runtime/game/game_manager.hpp | 46 +++++ engine/runtime/game/render/components.hpp | 48 +++++ engine/runtime/game/transform/components.hpp | 72 +++++++ engine/runtime/game/transform/features.cpp | 100 +++++++++ .../transform/features.hpp} | 54 +++-- engine/runtime/math/math_utils3d.hpp | 103 +++++++++- engine/runtime/math/transform.hpp | 27 +++ engine/runtime/rtti/class.hpp | 41 ++++ engine/runtime/rtti/traits.hpp | 4 + engine/runtime/scene/_rtti.cpp | 9 +- engine/runtime/scene/scene.cpp | 41 +--- engine/runtime/scene/scene.hpp | 79 ++++---- engine/runtime/scene/scene_components.hpp | 190 ------------------ engine/runtime/scene/scene_data.cpp | 11 - engine/runtime/scene/scene_data.hpp | 91 ++++----- engine/runtime/scene/scene_feature.hpp | 97 +++++++++ .../runtime/scene/scene_feature_adapter.hpp | 57 ++++++ engine/runtime/scene/scene_manager.cpp | 182 ++++++++++------- engine/runtime/scene/scene_manager.hpp | 57 +++--- engine/runtime/scene/scene_prefab.hpp | 6 +- engine/runtime/scene/scene_uuid.cpp | 49 +++++ engine/runtime/scene/scene_uuid.hpp | 58 ++++++ engine/runtime/system/engine.cpp | 13 +- engine/runtime/system/engine.hpp | 2 + engine/runtime/system/game_application.cpp | 7 +- template/assets/scenes/test_scene.asset | 6 +- template/assets/scenes/test_scene.scene | 108 ++++------ template/main.cpp | 21 +- 50 files changed, 1586 insertions(+), 634 deletions(-) rename engine/runtime/{scene/scene_packed.cpp => game/_rtti.cpp} (88%) rename engine/runtime/{scene/scene_components.cpp => game/_rtti.hpp} (96%) create mode 100644 engine/runtime/game/debug/components.hpp create mode 100644 engine/runtime/game/debug/features.cpp create mode 100644 engine/runtime/game/debug/features.hpp create mode 100644 engine/runtime/game/debug/systems.cpp create mode 100644 engine/runtime/game/debug/systems.hpp create mode 100644 engine/runtime/game/game_manager.cpp create mode 100644 engine/runtime/game/game_manager.hpp create mode 100644 engine/runtime/game/render/components.hpp create mode 100644 engine/runtime/game/transform/components.hpp create mode 100644 engine/runtime/game/transform/features.cpp rename engine/runtime/{scene/scene_packed.hpp => game/transform/features.hpp} (68%) delete mode 100644 engine/runtime/scene/scene_components.hpp create mode 100644 engine/runtime/scene/scene_feature.hpp create mode 100644 engine/runtime/scene/scene_feature_adapter.hpp create mode 100644 engine/runtime/scene/scene_uuid.cpp create mode 100644 engine/runtime/scene/scene_uuid.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json index b8b9ac6c3..c4d9f23a4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -99,9 +99,11 @@ "typeindex": "cpp", "**/*.asset": "yaml", "**/*.shader": "yaml", + "**/*.scene": "yaml", "*.moc": "cpp", "coroutine": "cpp", - "resumable": "cpp" + "resumable": "cpp", + "*.rh": "cpp" }, "[python]": { "editor.defaultFormatter": "ms-python.black-formatter" diff --git a/README.md b/README.md index b794a73d0..5faddeedb 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,11 @@ project for educational purposes only. * 🧱 Ecs-based scene model with fast, parallel and memory-friendly update. * 🎧 (in progress) OpenAL audio renderer for playing game sounds. * 📜 (in progress) Modern Lua scripting backend for game logic programming. -* 🐞 Built-in CPU performance and tasking profiling with support to google trace exporting. +* 🐞 Built-in CPU performance and tasking profiling with support for custom labels and metadata. +* 🐞 Built-in GPU performance profiler for separate GPU queues / command lists. +* 🐞 CPU & GPU trace collection with support to google trace exporting. +* 🐞 Debug GPU labels objects and events for RenderDoc captures. * 🐞 In-game dev console with support for console commands and console variables. -* 🐞 Debug labels objects and events for RenderDoc captures. ### Platforms @@ -106,7 +108,8 @@ project for educational purposes only. * [Master Class: In-Depth Guide to Working with Particle Effects in CRYENGINE](https://www.youtube.com/watch?v=npPlJ0npfVQ) * [Master Class: How to assign Game Inputs through Actionmapping in CRYENGINE](https://www.youtube.com/watch?v=uTmHUIypR-4) * [Master Class: Comprehensive Guide to Working with Audio in CRYENGINE](https://www.youtube.com/watch?v=oG1trk1PLMM) -* [CRYENGINE Tutorial - Art Asset Pipeline: PBR Texture Mapping](https://www.youtube.com/watch?v=hGFP_4TYL2o) +* [Master Class: Art Asset Pipeline, PBR Texture Mapping in CRYENGINE](https://www.youtube.com/watch?v=hGFP_4TYL2o) +* [ECS Scripting of Alan Wake 2](https://gdcvault.com/play/1034295/ECS-in-Practice-The-Case) * [HypeHype Mobile Rendering Architecture](https://advances.realtimerendering.com/s2023/index.html) * [Creating a Tools Pipeline for Horizon: Zero Dawn](https://www.youtube.com/watch?v=KRJkBxKv1VM) * [The Future of Scene Description on 'God of War'](https://www.gdcvault.com/play/1026345/The-Future-of-Scene-Description) diff --git a/engine/plugins/runtime/asset/default_asset_loader.cpp b/engine/plugins/runtime/asset/default_asset_loader.cpp index 3a0f47bcb..4a6d022c9 100644 --- a/engine/plugins/runtime/asset/default_asset_loader.cpp +++ b/engine/plugins/runtime/asset/default_asset_loader.cpp @@ -28,6 +28,7 @@ #include "default_asset_loader.hpp" +#include "asset/asset_manager.hpp" #include "core/ioc_container.hpp" #include "io/tree_yaml.hpp" #include "profiler/profiler_cpu.hpp" @@ -55,7 +56,13 @@ namespace wmoge { Ref import_data = context.asset_meta.import_data.cast(); assert(import_data); - RttiClass* rtti = context.ioc->resolve_value()->find_class(context.asset_meta.rtti); + RttiTypeStorage* type_storage = context.ioc->resolve_value(); + if (!type_storage) { + WG_LOG_ERROR("no rtti storage for " << asset_id); + return StatusCode::InvalidState; + } + + RttiClass* rtti = type_storage->find_class(context.asset_meta.rtti); if (!rtti) { WG_LOG_ERROR("no rtti type for " << asset_id); return StatusCode::InvalidData; @@ -72,6 +79,9 @@ namespace wmoge { IoYamlTree asset_tree; WG_CHECKED(asset_tree.parse_data(result.get_data_file(FILE_TAG))); + context.io_context.add(type_storage); + context.io_context.add(context.ioc->resolve_value()); + if (!asset->read_from_tree(context.io_context, asset_tree)) { WG_LOG_ERROR("failed to load asset from file " << asset_id); return StatusCode::FailedRead; diff --git a/engine/runtime/asset/asset_loader.hpp b/engine/runtime/asset/asset_loader.hpp index 5723aae07..cf32f5372 100644 --- a/engine/runtime/asset/asset_loader.hpp +++ b/engine/runtime/asset/asset_loader.hpp @@ -79,9 +79,6 @@ namespace wmoge { public: WG_RTTI_CLASS(AssetLoader, RttiObject); - AssetLoader() = default; - virtual ~AssetLoader() = default; - virtual Status fill_request(AssetLoadContext& context, const AssetId& asset_id, AssetLoadRequest& request) { return StatusCode::NotImplemented; }; virtual Status load(AssetLoadContext& context, const AssetId& asset_id, const AssetLoadResult& result, Ref& asset) { return StatusCode::NotImplemented; } virtual Status unload(Asset* asset) { return StatusCode::Ok; } diff --git a/engine/runtime/asset/asset_manager.hpp b/engine/runtime/asset/asset_manager.hpp index 765018337..c146b4629 100644 --- a/engine/runtime/asset/asset_manager.hpp +++ b/engine/runtime/asset/asset_manager.hpp @@ -64,7 +64,6 @@ namespace wmoge { class AssetManager { public: AssetManager(class IocContainer* ioc); - ~AssetManager() = default; AsyncResult> load_async(const AssetId& name); Ref load(const AssetId& name); diff --git a/engine/runtime/asset/asset_ref.hpp b/engine/runtime/asset/asset_ref.hpp index e30e35a44..cf6fca0b2 100644 --- a/engine/runtime/asset/asset_ref.hpp +++ b/engine/runtime/asset/asset_ref.hpp @@ -51,20 +51,6 @@ namespace wmoge { AssetRef(Ref ptr) : Ref(std::move(ptr)) {} }; - /** - * @class AssetRefWeak - * @brief Aux box to store asset ref and serialize/deserialize it automatically to and from files - */ - template - class AssetRefWeak : public AssetId { - public: - static_assert(std::is_base_of_v, "Must be an asset"); - - AssetRefWeak() = default; - AssetRefWeak(const AssetId& id) : AssetId(id) {} - AssetRefWeak(const AssetRef& ref) : AssetId(ref ? ref->get_id() : AssetId()) {} - }; - template Status tree_read(IoContext& context, IoTree& tree, AssetRef& ref) { AssetId id; @@ -110,33 +96,13 @@ namespace wmoge { } template - Status tree_read(IoContext& context, IoTree& tree, AssetRefWeak& ref) { - AssetId id; - WG_TREE_READ(context, tree, id); - ref = AssetRefWeak(id); - return WG_OK; - } - - template - Status tree_write(IoContext& context, IoTree& tree, const AssetRefWeak& ref) { - AssetId id = ref; - WG_TREE_WRITE(context, tree, id); - return WG_OK; - } - - template - Status stream_read(IoContext& context, IoStream& stream, AssetRefWeak& ref) { - AssetId id; - WG_ARCHIVE_READ(context, stream, id); - ref = AssetRefWeak(id); - return WG_OK; - } - - template - Status stream_write(IoContext& context, IoStream& stream, const AssetRefWeak& ref) { - AssetId id = ref; - WG_ARCHIVE_WRITE(context, stream, id); - return WG_OK; - } + struct RttiTypeOf, typename std::enable_if>::type> { + static Strid name() { + return SID(std::string("asset<") + rtti_type()->get_str() + ">"); + } + static Ref make() { + return make_ref>(name()); + } + }; }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/core/any_storage.hpp b/engine/runtime/core/any_storage.hpp index 5630f654f..eec1ab479 100644 --- a/engine/runtime/core/any_storage.hpp +++ b/engine/runtime/core/any_storage.hpp @@ -45,7 +45,7 @@ namespace wmoge { AnyStorage() = default; template - void add(T element) noexcept { m_map[typeid(T)] = std::move(element); } + void add(T element) noexcept { m_map.emplace(typeid(T), std::move(element)); } template bool has() const noexcept { return m_map.find(typeid(T)) != m_map.end(); } diff --git a/engine/runtime/core/string_id.cpp b/engine/runtime/core/string_id.cpp index 4769ab14a..3a79acdf5 100644 --- a/engine/runtime/core/string_id.cpp +++ b/engine/runtime/core/string_id.cpp @@ -84,7 +84,7 @@ namespace wmoge { Strid::Strid(const std::string& string) : Strid(string, StridPool::Release) { } - Strid::Strid(const std::string& string, StridPool pool) { + Strid::Strid(const std::string& string, StridPool pool) : Strid() { if (string.empty()) return; StringStorage::instance(pool).get_or_create(string, m_string); diff --git a/engine/runtime/ecs/ecs_component.hpp b/engine/runtime/ecs/ecs_component.hpp index dd0f67cea..949c96f9b 100644 --- a/engine/runtime/ecs/ecs_component.hpp +++ b/engine/runtime/ecs/ecs_component.hpp @@ -77,7 +77,4 @@ namespace wmoge { std::function swap; }; -#define WG_ECS_COMPONENT(ecs_component_class) \ - static constexpr char NAME_CSTR[] = #ecs_component_class; - }// namespace wmoge diff --git a/engine/runtime/ecs/ecs_query.hpp b/engine/runtime/ecs/ecs_query.hpp index 918e4e4c2..64e12949f 100644 --- a/engine/runtime/ecs/ecs_query.hpp +++ b/engine/runtime/ecs/ecs_query.hpp @@ -121,12 +121,16 @@ namespace wmoge { m_range_count(count) { } + template + void for_each(Functor f); + template - bool has() { return m_arch.has_component(); } + [[nodiscard]] bool has_component() const; template - Component& get_component(int entity_idx) { return *m_storage.get_component(entity_idx); } - EcsEntity get_entity(int entity_idx) { return m_storage.get_entity(entity_idx); } + [[nodiscard]] Component& get_component(int entity_idx); + + [[nodiscard]] EcsEntity get_entity(int entity_idx); [[nodiscard]] int get_start_idx() const { return m_range_start; } [[nodiscard]] int get_count() const { return m_range_count; } @@ -142,4 +146,25 @@ namespace wmoge { /** @brief Function used to execute ecs query */ using EcsQueuryFunction = std::function; + template + inline void EcsQueryContext::for_each(Functor f) { + for (int i = m_range_start; i < m_range_start + m_range_count; i++) { + f(i); + } + } + + template + inline bool EcsQueryContext::has_component() const { + return m_arch.has_component(); + } + + template + inline Component& EcsQueryContext::get_component(int entity_idx) { + return *m_storage.get_component(entity_idx); + } + + inline EcsEntity wmoge::EcsQueryContext::get_entity(int entity_idx) { + return m_storage.get_entity(entity_idx); + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/ecs/ecs_registry.hpp b/engine/runtime/ecs/ecs_registry.hpp index 30e764701..ebff7968c 100644 --- a/engine/runtime/ecs/ecs_registry.hpp +++ b/engine/runtime/ecs/ecs_registry.hpp @@ -59,7 +59,7 @@ namespace wmoge { [[nodiscard]] int get_expand_size() const { return m_expand_size; } template - void register_component(); + void register_component(const std::string& name); private: static const int MAX_CMP = EcsLimits::MAX_COMPONENTS; @@ -75,7 +75,7 @@ namespace wmoge { }; template - void EcsRegistry::register_component() { + void EcsRegistry::register_component(const std::string& name) { const int component_idx = m_component_types++; assert(component_idx < EcsLimits::MAX_COMPONENTS); @@ -84,7 +84,7 @@ namespace wmoge { assert(component_info.idx == -1); assert(component_info.size == -1); - Component::bind(component_idx, SID(Component::NAME_CSTR)); + Component::bind(component_idx, SIDDBG(name)); component_info.name = Component::NAME; component_info.idx = Component::IDX; diff --git a/engine/runtime/ecs/ecs_world.cpp b/engine/runtime/ecs/ecs_world.cpp index 520baca3f..1073da7b3 100644 --- a/engine/runtime/ecs/ecs_world.cpp +++ b/engine/runtime/ecs/ecs_world.cpp @@ -35,9 +35,8 @@ namespace wmoge { - EcsWorld::EcsWorld(EcsRegistry* ecs_registry, TaskManager* task_manager) { + EcsWorld::EcsWorld(EcsRegistry* ecs_registry) { m_ecs_registry = ecs_registry; - m_task_manager = task_manager; } EcsWorld::~EcsWorld() { @@ -209,7 +208,7 @@ namespace wmoge { } } - Async EcsWorld::execute_async(Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func) { + Async EcsWorld::execute_async(TaskManager* task_manager, Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func) { WG_PROFILE_CPU_ECS("EcsWorld::execute_async"); Task task(query.name, [query, func, this](TaskContext&) { @@ -229,10 +228,10 @@ namespace wmoge { return 0; }); - return task.schedule(m_task_manager, depends_on).as_async(); + return task.schedule(task_manager, depends_on).as_async(); } - Async EcsWorld::execute_parallel(Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func) { + Async EcsWorld::execute_parallel(TaskManager* task_manager, Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func) { WG_PROFILE_CPU_ECS("EcsWorld::execute_parallel"); TaskParallelFor task(query.name, [query, func, this](TaskContext&, int batch_id, int batch_count) { @@ -251,7 +250,7 @@ namespace wmoge { return 0; }); - return task.schedule(m_task_manager, m_task_manager->get_num_workers(), 1, depends_on).as_async(); + return task.schedule(task_manager, task_manager->get_num_workers(), 1, depends_on).as_async(); } void EcsWorld::clear() { diff --git a/engine/runtime/ecs/ecs_world.hpp b/engine/runtime/ecs/ecs_world.hpp index ff70d4e17..19cbe23ef 100644 --- a/engine/runtime/ecs/ecs_world.hpp +++ b/engine/runtime/ecs/ecs_world.hpp @@ -62,7 +62,7 @@ namespace wmoge { */ class EcsWorld { public: - EcsWorld(class EcsRegistry* ecs_registry, class TaskManager* task_manager); + EcsWorld(class EcsRegistry* ecs_registry); ~EcsWorld(); /** @brief Allocates new entity for later creation */ @@ -115,10 +115,10 @@ namespace wmoge { void execute(const EcsQuery& query, const EcsQueuryFunction& func); /** @brief Exec function for each entity matching query in async job */ - Async execute_async(Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func); + Async execute_async(TaskManager* task_manager, Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func); /** @brief Exec function for each entity matching query in async parallel job */ - Async execute_parallel(Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func); + Async execute_parallel(TaskManager* task_manager, Async depends_on, const EcsQuery& query, const EcsQueuryFunction& func); /** @brief Clear world destroying all entities */ void clear(); @@ -129,15 +129,14 @@ namespace wmoge { private: std::vector m_entity_info; // entity info, accessed by entity idx std::deque m_entity_pool; // pool with free entities handles - int m_entity_counter = 0;// total count of created entities flat_map m_arch_to_idx; // arch to unique index std::vector> m_arch_storage; // storage per arch, indexed by arch idx std::vector m_arch_by_idx; // arch mask, indexed by arch idx std::vector> m_on_destroy; // queries executed on destroy of some entities + int m_entity_counter = 0;// total count of created entities CallbackQueue m_queue; // queue for async world operations, flushed on sync EcsRegistry* m_ecs_registry;// registry of the ecs world - TaskManager* m_task_manager;// default task manager for query execution mutable SpinMutex m_mutex; }; diff --git a/engine/runtime/engine.hpp b/engine/runtime/engine.hpp index 799404744..5106017a8 100644 --- a/engine/runtime/engine.hpp +++ b/engine/runtime/engine.hpp @@ -211,10 +211,9 @@ #include "render/view_manager.hpp" #include "scene/scene.hpp" -#include "scene/scene_components.hpp" #include "scene/scene_data.hpp" +#include "scene/scene_feature.hpp" #include "scene/scene_manager.hpp" -#include "scene/scene_packed.hpp" #include "scene/scene_prefab.hpp" #include "io/config.hpp" diff --git a/engine/runtime/scene/scene_packed.cpp b/engine/runtime/game/_rtti.cpp similarity index 88% rename from engine/runtime/scene/scene_packed.cpp rename to engine/runtime/game/_rtti.cpp index c9da22888..a5eee8eda 100644 --- a/engine/runtime/scene/scene_packed.cpp +++ b/engine/runtime/game/_rtti.cpp @@ -25,15 +25,18 @@ /* SOFTWARE. */ /**********************************************************************************/ -#include "scene_packed.hpp" +#include "_rtti.hpp" -#include "core/log.hpp" -#include "core/task.hpp" -#include "core/timer.hpp" -#include "platform/file_system.hpp" -#include "profiler/profiler_cpu.hpp" -#include "scene/scene.hpp" +#include "game/debug/features.hpp" +#include "game/transform/features.hpp" namespace wmoge { + void rtti_game() { + rtti_type(); + rtti_type(); + rtti_type(); + rtti_type(); + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_components.cpp b/engine/runtime/game/_rtti.hpp similarity index 96% rename from engine/runtime/scene/scene_components.cpp rename to engine/runtime/game/_rtti.hpp index 6bddb0a0f..6b2543361 100644 --- a/engine/runtime/scene/scene_components.cpp +++ b/engine/runtime/game/_rtti.hpp @@ -25,4 +25,10 @@ /* SOFTWARE. */ /**********************************************************************************/ -#include "scene_components.hpp" +#pragma once + +namespace wmoge { + + void rtti_game(); + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/debug/components.hpp b/engine/runtime/game/debug/components.hpp new file mode 100644 index 000000000..7313cf1b2 --- /dev/null +++ b/engine/runtime/game/debug/components.hpp @@ -0,0 +1,70 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "ecs/ecs_component.hpp" +#include "ecs/ecs_entity.hpp" +#include "material/material.hpp" +#include "math/mat.hpp" +#include "math/transform.hpp" +#include "math/vec.hpp" +#include "mesh/mesh.hpp" + +#include + +namespace wmoge { + + enum class GmDebugPrimitiveType { + Sphere, + Cylinder, + Cone, + Box + }; + + struct GmDebugDistMinMaxComponent : public EcsComponent { + int dist_min; + int dist_max; + }; + + struct GmDebugMeshComponent : public EcsComponent { + Ref mesh; + Ref material; + }; + + struct GmDebugLabelComponent : public EcsComponent { + std::string text; + Color4f color; + float size; + }; + + struct GmDebugPrimitiveComponent : public EcsComponent { + GmDebugPrimitiveType type; + Color4f color; + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/debug/features.cpp b/engine/runtime/game/debug/features.cpp new file mode 100644 index 000000000..4e5795365 --- /dev/null +++ b/engine/runtime/game/debug/features.cpp @@ -0,0 +1,61 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "features.hpp" + +#include "ecs/ecs_world.hpp" +#include "game/debug/components.hpp" +#include "scene/scene.hpp" +#include "scene/scene_uuid.hpp" + +namespace wmoge { + + Status GmDebugMeshFeatureTrait::setup_entity_typed(EcsArch& arch, const GmDebugMeshFeature& feature, EntitySetupContext& context) { + return Status(); + } + + Status GmDebugMeshFeatureTrait::build_entity_typed(EcsEntity entity, const GmDebugMeshFeature& feature, EntityBuildContext& context) { + return Status(); + } + + Status GmDebugLabelFeatureTrait::setup_entity_typed(EcsArch& arch, const GmDebugLabelFeature& feature, EntitySetupContext& context) { + return Status(); + } + + Status GmDebugLabelFeatureTrait::build_entity_typed(EcsEntity entity, const GmDebugLabelFeature& feature, EntityBuildContext& context) { + return Status(); + } + + Status GmDebugPrimitiveFeatureTrait::setup_entity_typed(EcsArch& arch, const GmDebugPrimitiveFeature& feature, EntitySetupContext& context) { + return Status(); + } + + Status GmDebugPrimitiveFeatureTrait::build_entity_typed(EcsEntity entity, const GmDebugPrimitiveFeature& feature, EntityBuildContext& context) { + return Status(); + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/debug/features.hpp b/engine/runtime/game/debug/features.hpp new file mode 100644 index 000000000..fc6ed07bd --- /dev/null +++ b/engine/runtime/game/debug/features.hpp @@ -0,0 +1,119 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "core/uuid.hpp" +#include "game/debug/components.hpp" +#include "material/material.hpp" +#include "math/color.hpp" +#include "math/transform.hpp" +#include "mesh/mesh.hpp" +#include "scene/scene_feature_adapter.hpp" + +#include + +namespace wmoge { + + class GmDebugMeshFeature : public EntityFeature { + WG_RTTI_CLASS(GmDebugMeshFeature, EntityFeature) + + AssetRef mesh; + AssetRef material; + int dist_min = 0; + int dist_max = 1000; + }; + + WG_RTTI_CLASS_BEGIN(GmDebugMeshFeature) { + WG_RTTI_META_DATA(); + WG_RTTI_FACTORY(); + WG_RTTI_FIELD(mesh, {RttiOptional}); + WG_RTTI_FIELD(material, {RttiOptional}); + WG_RTTI_FIELD(dist_min, {RttiOptional}); + WG_RTTI_FIELD(dist_max, {RttiOptional}); + } + WG_RTTI_END; + + class GmDebugLabelFeature : public EntityFeature { + WG_RTTI_CLASS(GmDebugLabelFeature, EntityFeature) + + std::string text; + Color4f color = Color::WHITE4f; + float size = 1.0f; + int dist_min = 0; + int dist_max = 1000; + }; + + WG_RTTI_CLASS_BEGIN(GmDebugLabelFeature) { + WG_RTTI_META_DATA(); + WG_RTTI_FACTORY(); + WG_RTTI_FIELD(text, {RttiOptional}); + WG_RTTI_FIELD(color, {RttiOptional}); + WG_RTTI_FIELD(size, {RttiOptional}); + WG_RTTI_FIELD(dist_min, {RttiOptional}); + WG_RTTI_FIELD(dist_max, {RttiOptional}); + } + WG_RTTI_END; + + class GmDebugPrimitiveFeature : public EntityFeature { + WG_RTTI_CLASS(GmDebugPrimitiveFeature, EntityFeature) + + GmDebugPrimitiveType type = GmDebugPrimitiveType::Sphere; + Color4f color = Color::WHITE4f; + int dist_min = 0; + int dist_max = 1000; + }; + + WG_RTTI_CLASS_BEGIN(GmDebugPrimitiveFeature) { + WG_RTTI_META_DATA(); + WG_RTTI_FACTORY(); + WG_RTTI_FIELD(type, {RttiOptional}); + WG_RTTI_FIELD(color, {RttiOptional}); + WG_RTTI_FIELD(dist_min, {RttiOptional}); + WG_RTTI_FIELD(dist_max, {RttiOptional}); + } + WG_RTTI_END; + + class GmDebugMeshFeatureTrait : public EntitySimpleFeatureTrait { + public: + Status setup_entity_typed(EcsArch& arch, const GmDebugMeshFeature& feature, EntitySetupContext& context) override; + Status build_entity_typed(EcsEntity entity, const GmDebugMeshFeature& feature, EntityBuildContext& context) override; + }; + + class GmDebugLabelFeatureTrait : public EntitySimpleFeatureTrait { + public: + Status setup_entity_typed(EcsArch& arch, const GmDebugLabelFeature& feature, EntitySetupContext& context) override; + Status build_entity_typed(EcsEntity entity, const GmDebugLabelFeature& feature, EntityBuildContext& context) override; + }; + + class GmDebugPrimitiveFeatureTrait : public EntitySimpleFeatureTrait { + public: + Status setup_entity_typed(EcsArch& arch, const GmDebugPrimitiveFeature& feature, EntitySetupContext& context) override; + Status build_entity_typed(EcsEntity entity, const GmDebugPrimitiveFeature& feature, EntityBuildContext& context) override; + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/debug/systems.cpp b/engine/runtime/game/debug/systems.cpp new file mode 100644 index 000000000..6d599d0dc --- /dev/null +++ b/engine/runtime/game/debug/systems.cpp @@ -0,0 +1,86 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "systems.hpp" + +namespace wmoge { + + static bool gm_debug_cull_item(const Vec3f& cam_pos, const Vec3f& pos, int entity_idx, EcsQueryContext& query) { + if (!query.has_component()) { + return true; + } + const float dist = Vec3f::distance(cam_pos, pos); + auto& bounds = query.get_component(entity_idx); + + return bounds.dist_min <= dist && dist <= bounds.dist_max; + } + + void gm_draw_debug_label_system(AuxDrawManager* draw_manager, Vec3f cam_pos, EcsQueryContext& query) { + query.for_each([&](int entity_idx) { + auto& label = query.get_component(entity_idx); + auto& mat_l2w = query.get_component(entity_idx); + + const Vec3f pos = Math3d::extract_translation(mat_l2w.m); + + if (!gm_debug_cull_item(cam_pos, pos, entity_idx, query)) { + return; + } + + draw_manager->draw_text_3d(label.text, pos, label.size, label.color); + }); + } + + void gm_draw_debug_primitive_system(AuxDrawManager* draw_manager, Vec3f cam_pos, bool solid, EcsQueryContext& query) { + query.for_each([&](int entity_idx) { + auto& prim = query.get_component(entity_idx); + auto& mat_l2w = query.get_component(entity_idx); + + Vec3f pos; + Vec3f scale; + Quatf rot; + Math3d::decompose(mat_l2w.m, pos, scale, rot); + + if (gm_debug_cull_item(cam_pos, pos, entity_idx, query)) { + return; + } + + if (prim.type == GmDebugPrimitiveType::Box) { + draw_manager->draw_box(pos, scale, prim.color, rot, solid); + } + if (prim.type == GmDebugPrimitiveType::Sphere) { + draw_manager->draw_sphere(pos, scale.x(), prim.color, solid); + } + if (prim.type == GmDebugPrimitiveType::Cone) { + draw_manager->draw_cone(pos, scale.x(), scale.y(), prim.color, rot, solid); + } + if (prim.type == GmDebugPrimitiveType::Cylinder) { + draw_manager->draw_cylinder(pos, scale.x(), scale.y(), prim.color, rot, solid); + } + }); + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/debug/systems.hpp b/engine/runtime/game/debug/systems.hpp new file mode 100644 index 000000000..fcea43f6f --- /dev/null +++ b/engine/runtime/game/debug/systems.hpp @@ -0,0 +1,57 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "ecs/ecs_query.hpp" +#include "game/debug/components.hpp" +#include "game/transform/components.hpp" +#include "render/aux_draw_manager.hpp" + +namespace wmoge { + + struct GmDebugLabelQuery : EcsQuery { + GmDebugLabelQuery() { + add(); + add(EcsComponentPresence::Optional); + add(); + } + }; + + struct GmDebugPrimitiveQuery : EcsQuery { + GmDebugPrimitiveQuery() { + add(); + add(EcsComponentPresence::Optional); + add(); + } + }; + + void gm_draw_debug_label_system(AuxDrawManager* draw_manager, Vec3f cam_pos, EcsQueryContext& query); + + void gm_draw_debug_primitive_system(AuxDrawManager* draw_manager, Vec3f cam_pos, EcsQueryContext& query); + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/game_manager.cpp b/engine/runtime/game/game_manager.cpp new file mode 100644 index 000000000..9caf4da65 --- /dev/null +++ b/engine/runtime/game/game_manager.cpp @@ -0,0 +1,77 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "game_manager.hpp" + +#include "core/ioc_container.hpp" + +#include "game/debug/components.hpp" +#include "game/render/components.hpp" +#include "game/transform/components.hpp" + +#include "game/debug/features.hpp" +#include "game/transform/features.hpp" + +namespace wmoge { + + GameManager::GameManager(EcsRegistry* ecs_registry, SceneManager* scene_manager) { + m_ecs_registry = ecs_registry; + m_scene_manager = scene_manager; + + m_ecs_registry->register_component("parent"); + m_ecs_registry->register_component("children"); + m_ecs_registry->register_component("transform"); + m_ecs_registry->register_component("transform_frame"); + m_ecs_registry->register_component("local"); + m_ecs_registry->register_component("local_to_world"); + m_ecs_registry->register_component("local_to_world_prev"); + m_ecs_registry->register_component("world_to_local"); + + m_ecs_registry->register_component("camera"); + m_ecs_registry->register_component("light"); + m_ecs_registry->register_component("mesh"); + + m_ecs_registry->register_component("debug_dist_min_max"); + m_ecs_registry->register_component("debug_shape"); + m_ecs_registry->register_component("debug_label"); + m_ecs_registry->register_component("debug_primitive"); + + m_scene_manager->add_trait(make_ref()); + m_scene_manager->add_trait(make_ref()); + m_scene_manager->add_trait(make_ref()); + m_scene_manager->add_trait(make_ref()); + } + + void bind_by_ioc_game_manager(class IocContainer* ioc) { + ioc->bind_by_factory([ioc]() { + return std::make_shared( + ioc->resolve_value(), + ioc->resolve_value()); + }); + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/game_manager.hpp b/engine/runtime/game/game_manager.hpp new file mode 100644 index 000000000..cda69e321 --- /dev/null +++ b/engine/runtime/game/game_manager.hpp @@ -0,0 +1,46 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "ecs/ecs_registry.hpp" +#include "scene/scene_manager.hpp" + +namespace wmoge { + + class GameManager { + public: + GameManager(EcsRegistry* ecs_registry, SceneManager* scene_manager); + + private: + EcsRegistry* m_ecs_registry = nullptr; + SceneManager* m_scene_manager = nullptr; + }; + + void bind_by_ioc_game_manager(class IocContainer* ioc); + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/render/components.hpp b/engine/runtime/game/render/components.hpp new file mode 100644 index 000000000..87f1fcb59 --- /dev/null +++ b/engine/runtime/game/render/components.hpp @@ -0,0 +1,48 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "ecs/ecs_component.hpp" +#include "ecs/ecs_entity.hpp" +#include "math/mat.hpp" +#include "math/transform.hpp" +#include "math/vec.hpp" +#include "render/camera.hpp" + +namespace wmoge { + + struct GmCameraComponent : public EcsComponent { + }; + + struct GmLightComponent : public EcsComponent { + }; + + struct GmMeshComponent : public EcsComponent { + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/transform/components.hpp b/engine/runtime/game/transform/components.hpp new file mode 100644 index 000000000..5a665c17e --- /dev/null +++ b/engine/runtime/game/transform/components.hpp @@ -0,0 +1,72 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "ecs/ecs_component.hpp" +#include "ecs/ecs_entity.hpp" +#include "math/mat.hpp" +#include "math/transform.hpp" +#include "math/vec.hpp" + +#include + +namespace wmoge { + + struct GmParentComponent : public EcsComponent { + EcsEntity id; + }; + + struct GmChildrenComponent : public EcsComponent { + std::vector ids; + }; + + struct GmTransformComponent : public EcsComponent { + Transform3d t; + }; + + struct GmTransformFrameComponent : public EcsComponent { + int frame = -1; + }; + + struct GmMatLocalToWorldComponent : public EcsComponent { + Mat3x4f m; + }; + + struct GmMatLocalToWorldPrevComponent : public EcsComponent { + Mat3x4f m; + }; + + struct GmMatWorldToLocalComponent : public EcsComponent { + Mat3x4f m; + }; + + struct GmMatLocalComponent : public EcsComponent { + Mat3x4f m; + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/game/transform/features.cpp b/engine/runtime/game/transform/features.cpp new file mode 100644 index 000000000..c46b3e267 --- /dev/null +++ b/engine/runtime/game/transform/features.cpp @@ -0,0 +1,100 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "features.hpp" + +#include "ecs/ecs_world.hpp" +#include "game/transform/components.hpp" +#include "scene/scene.hpp" +#include "scene/scene_uuid.hpp" + +namespace wmoge { + + Status GmTransformFeatureTrait::setup_entity_typed(EcsArch& arch, const GmTransformFeature& feature, EntitySetupContext& context) { + if (feature.type == GmTransformType::MovableHierarchical) { + arch.set_component(); + arch.set_component(); + arch.set_component(); + arch.set_component(); + arch.set_component(); + arch.set_component(); + } + if (feature.type == GmTransformType::Movable) { + arch.set_component(); + arch.set_component(); + arch.set_component(); + arch.set_component(); + } + if (feature.type == GmTransformType::NonMovable) { + arch.set_component(); + } + + return WG_OK; + } + + Status GmTransformFeatureTrait::build_entity_typed(EcsEntity entity, const GmTransformFeature& feature, EntityBuildContext& context) { + EcsWorld* world = context.world; + SceneUuidMap* uuid = context.uuid; + + if (feature.type == GmTransformType::MovableHierarchical) { + auto& children = world->get_component_rw(entity); + auto& mat_l = world->get_component_rw(entity); + auto& trsf = world->get_component_rw(entity); + + trsf.t = feature.transform.to_transform3d(); + mat_l.m = Math3d ::to_m3x4f(trsf.t.to_mat4x4()); + + if (feature.parent) { + auto& parent = world->get_component_rw(entity); + parent.id = uuid->find_entity(*feature.parent).value_or(EcsEntity()); + } + if (!feature.children.empty()) { + auto& children = world->get_component_rw(entity); + children.ids.reserve(feature.children.size()); + for (const UUID id : feature.children) { + if (auto entity = uuid->find_entity(id)) { + children.ids.push_back(*entity); + } + } + } + } + if (feature.type == GmTransformType::Movable) { + auto& mat_l = world->get_component_rw(entity); + auto& trsf = world->get_component_rw(entity); + + trsf.t = feature.transform.to_transform3d(); + mat_l.m = Math3d ::to_m3x4f(trsf.t.to_mat4x4()); + } + if (feature.type == GmTransformType::NonMovable) { + auto& mat_l2w = world->get_component_rw(entity); + mat_l2w.m = Math3d ::to_m3x4f(feature.transform.to_mat4x4()); + } + + return WG_OK; + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_packed.hpp b/engine/runtime/game/transform/features.hpp similarity index 68% rename from engine/runtime/scene/scene_packed.hpp rename to engine/runtime/game/transform/features.hpp index 2a401b5ed..91358b24b 100644 --- a/engine/runtime/scene/scene_packed.hpp +++ b/engine/runtime/game/transform/features.hpp @@ -27,45 +27,43 @@ #pragma once -#include "asset/asset.hpp" -#include "core/async.hpp" -#include "io/tree.hpp" -#include "scene/scene.hpp" +#include "core/uuid.hpp" +#include "math/transform.hpp" +#include "scene/scene_feature_adapter.hpp" #include namespace wmoge { - /** - * @class ScenePacked - * @brief Represents packed scene asset which can be used to load scenes - * - * Packed scene stores serialized scene description. Supported formats are: - * text format based on yaml document, easy to write, read and parse. Scene - * representation loaded and saved in a pack. This serialized representation - * used to instantiate scene. - * - * Scene can be instantiated synchronously or asynchronously by async. - * For instantiation pack constructs and async task graph, so actual scene - * creating starts when deps are ready. Everything is done in task manager. - * - * @see Scene - */ - class ScenePacked final : public Asset { - public: - WG_RTTI_CLASS(ScenePacked, Asset); + enum class GmTransformType { + MovableHierarchical, + Movable, + NonMovable + }; - ScenePacked() = default; - ~ScenePacked() override = default; + class GmTransformFeature : public EntityFeature { + WG_RTTI_CLASS(GmTransformFeature, EntityFeature) - private: - SceneData m_data; + TransformEdt transform; + GmTransformType type = GmTransformType::NonMovable; + std::optional parent; + std::vector children; }; - WG_RTTI_CLASS_BEGIN(ScenePacked) { - WG_RTTI_META_DATA(RttiUiHint("")); + WG_RTTI_CLASS_BEGIN(GmTransformFeature) { + WG_RTTI_META_DATA(); WG_RTTI_FACTORY(); + WG_RTTI_FIELD(transform, {RttiOptional}); + WG_RTTI_FIELD(type, {RttiOptional}); + WG_RTTI_FIELD(parent, {RttiOptional}); + WG_RTTI_FIELD(children, {RttiOptional}); } WG_RTTI_END; + class GmTransformFeatureTrait : public EntitySimpleFeatureTrait { + public: + Status setup_entity_typed(EcsArch& arch, const GmTransformFeature& feature, EntitySetupContext& context) override; + Status build_entity_typed(EcsEntity entity, const GmTransformFeature& feature, EntityBuildContext& context) override; + }; + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/math/math_utils3d.hpp b/engine/runtime/math/math_utils3d.hpp index 18e59ea29..11318a121 100644 --- a/engine/runtime/math/math_utils3d.hpp +++ b/engine/runtime/math/math_utils3d.hpp @@ -27,14 +27,79 @@ #pragma once -#include "mat.hpp" -#include "math_utils.hpp" -#include "vec.hpp" +#include "math/mat.hpp" +#include "math/math_utils.hpp" +#include "math/vec.hpp" +#include "math/quat.hpp" namespace wmoge { class Math3d { public: + static Mat4x4f to_m4x4f(const Mat3x3f& m) { + Mat4x4f mat; + + mat[0][0] = m[0][0]; + mat[0][1] = m[0][1]; + mat[0][2] = m[0][2]; + + mat[1][0] = m[1][0]; + mat[1][1] = m[1][1]; + mat[1][2] = m[1][2]; + + mat[2][0] = m[2][0]; + mat[2][1] = m[2][1]; + mat[2][2] = m[2][2]; + + mat[3][3] = 1.0f; + + return mat; + } + + static Mat4x4f to_m4x4f(const Mat3x4f& m) { + Mat4x4f mat; + + mat[0][0] = m[0][0]; + mat[0][1] = m[0][1]; + mat[0][2] = m[0][2]; + mat[0][3] = m[0][3]; + + mat[1][0] = m[1][0]; + mat[1][1] = m[1][1]; + mat[1][2] = m[1][2]; + mat[1][3] = m[1][3]; + + mat[2][0] = m[2][0]; + mat[2][1] = m[2][1]; + mat[2][2] = m[2][2]; + mat[2][3] = m[2][3]; + + mat[3][3] = 1.0f; + + return mat; + } + + static Mat3x4f to_m3x4f(const Mat4x4f& m) { + Mat3x4f mat; + + mat[0][0] = m[0][0]; + mat[0][1] = m[0][1]; + mat[0][2] = m[0][2]; + mat[0][3] = m[0][3]; + + mat[1][0] = m[1][0]; + mat[1][1] = m[1][1]; + mat[1][2] = m[1][2]; + mat[1][3] = m[1][3]; + + mat[2][0] = m[2][0]; + mat[2][1] = m[2][1]; + mat[2][2] = m[2][2]; + mat[2][3] = m[2][3]; + + return mat; + } + static Mat4x4f identity() { Mat4x4f mat; mat[0][0] = 1.0f; @@ -127,10 +192,42 @@ namespace wmoge { return Vec3f(mat * Vec4f(vec, 1.0f)); } + static Vec3f transform(const Mat3x4f& mat, const Vec3f& vec) { + return mat * Vec4f(vec, 1.0f); + } + static Vec3f transform_w0(const Mat4x4f& mat, const Vec3f& vec) { return Vec3f(mat * Vec4f(vec, 0.0f)); } + static Vec3f extract_translation(const Mat3x4f& mat) { + return Vec3f(mat[0][3], mat[1][3], mat[2][3]); + } + + static Vec3f extract_scale(const Mat3x4f& mat) { + return Vec3f(Vec3f(mat.col(0)).length(), + Vec3f(mat.col(1)).length(), + Vec3f(mat.col(2)).length()); + } + + static void decompose(const Mat3x4f& mat, Vec3f& pos, Vec3f& scale, Quatf& quat) { + pos = extract_translation(mat); + scale = extract_scale(mat); + + Mat3x3f rot; + rot[0][0] = mat[0][0] / scale.x(); + rot[1][0] = mat[1][0] / scale.x(); + rot[2][0] = mat[2][0] / scale.x(); + rot[0][1] = mat[0][1] / scale.y(); + rot[1][1] = mat[1][1] / scale.y(); + rot[2][1] = mat[2][1] / scale.y(); + rot[0][2] = mat[0][2] / scale.z(); + rot[1][2] = mat[1][2] / scale.z(); + rot[2][2] = mat[2][2] / scale.z(); + + quat = Quatf(to_m4x4f(rot)); + } + /** * | y * | diff --git a/engine/runtime/math/transform.hpp b/engine/runtime/math/transform.hpp index e4b944c8f..6376f4e4c 100644 --- a/engine/runtime/math/transform.hpp +++ b/engine/runtime/math/transform.hpp @@ -104,6 +104,15 @@ namespace wmoge { float m_rotation; }; + inline std::ostream& operator<<(std::ostream& ostream, const Transform2d& t) { + ostream << "("; + ostream << "t=" << t.get_translation() << ", "; + ostream << "r=" << t.get_rotation() << ", "; + ostream << "s=" << t.get_scale(); + ostream << ")"; + return ostream; + } + /** * @class Transform3d * @brief Utility to manage 3d space transformations @@ -186,6 +195,15 @@ namespace wmoge { Vec3f m_scale; }; + inline std::ostream& operator<<(std::ostream& ostream, const Transform3d& t) { + ostream << "("; + ostream << "t=" << t.get_translation() << ", "; + ostream << "r=" << t.get_rotation() << ", "; + ostream << "s=" << t.get_scale(); + ostream << ")"; + return ostream; + } + /** * @class TransformEdt * @brief Utility to manage 3d space transformations with euler angles (roll, yaw, pitch) @@ -270,4 +288,13 @@ namespace wmoge { Vec3f m_scale; }; + inline std::ostream& operator<<(std::ostream& ostream, const TransformEdt& t) { + ostream << "("; + ostream << "t=" << t.get_translation() << ", "; + ostream << "r=" << t.get_rotation() << ", "; + ostream << "s=" << t.get_scale(); + ostream << ")"; + return ostream; + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/rtti/class.hpp b/engine/runtime/rtti/class.hpp index 93e017048..98bde250a 100644 --- a/engine/runtime/rtti/class.hpp +++ b/engine/runtime/rtti/class.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include namespace wmoge { @@ -112,4 +113,44 @@ namespace wmoge { RttiClass* m_parent_class = nullptr; }; + template + class RttiSubclass { + public: + RttiSubclass() = default; + RttiSubclass(const RttiSubclass&) = default; + RttiSubclass(RttiSubclass&&) noexcept = default; + + RttiSubclass(RttiClass* rtti) { + if (rtti) { + assert(rtti->is_subtype_of(BaseType::get_class_static())); + m_rtti = rtti; + } + } + + template + operator RttiSubclass() const { + static_assert(std::is_base_of_v); + return RttiSubclass(m_rtti); + } + + template + RttiSubclass cast() const { + if (rtti && rtti->is_subtype_of(OtherType::get_class_static())) { + return RttiSubclass(m_rtti); + } + return RttiSubclass(); + } + + RttiClass& operator*() const { return *m_rtti; } + RttiClass* operator->() const { return m_rtti; } + + operator bool() const { return m_rtti; } + + [[nodiscard]] bool is_empty() const { return !m_rtti; } + [[nodiscard]] bool is_not_empty() const { return m_rtti; } + + private: + RttiClass* m_rtti = nullptr; + }; + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/rtti/traits.hpp b/engine/runtime/rtti/traits.hpp index bf46c5a10..1df862cb7 100644 --- a/engine/runtime/rtti/traits.hpp +++ b/engine/runtime/rtti/traits.hpp @@ -42,6 +42,7 @@ #include "math/aabb.hpp" #include "math/mat.hpp" #include "math/quat.hpp" +#include "math/transform.hpp" #include "math/vec.hpp" #include "rtti/builtin.hpp" #include "rtti/class.hpp" @@ -427,6 +428,9 @@ namespace wmoge { WG_RTTI_FUNDAMENTAL_DECL(Status, "status"); WG_RTTI_FUNDAMENTAL_DECL(Ref, "data"); WG_RTTI_FUNDAMENTAL_DECL(Aabbf, "aabbf"); + WG_RTTI_FUNDAMENTAL_DECL(Transform2d, "transform2d"); + WG_RTTI_FUNDAMENTAL_DECL(Transform3d, "transform3d"); + WG_RTTI_FUNDAMENTAL_DECL(TransformEdt, "transformEdt"); template struct RttiTypeOf> { diff --git a/engine/runtime/scene/_rtti.cpp b/engine/runtime/scene/_rtti.cpp index c7f498592..08600de22 100644 --- a/engine/runtime/scene/_rtti.cpp +++ b/engine/runtime/scene/_rtti.cpp @@ -27,14 +27,17 @@ #include "_rtti.hpp" -#include "scene/scene_packed.hpp" +#include "scene/scene_data.hpp" +#include "scene/scene_feature.hpp" #include "scene/scene_prefab.hpp" namespace wmoge { void rtti_scene() { - rtti_type(); - rtti_type(); + rtti_type(); + rtti_type(); + rtti_type(); + rtti_type(); } }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene.cpp b/engine/runtime/scene/scene.cpp index f86c88b3d..41488d1b0 100644 --- a/engine/runtime/scene/scene.cpp +++ b/engine/runtime/scene/scene.cpp @@ -27,27 +27,10 @@ #include "scene.hpp" -#include "profiler/profiler_cpu.hpp" -#include "render/deferred_pipeline.hpp" -#include "scene/scene_components.hpp" - -#include - namespace wmoge { - Scene::Scene(const SceneCreateInfo& info) { - WG_PROFILE_CPU_SCENE("Scene::Scene"); - - m_name = info.name; - m_ecs_world = std::make_unique(info.ecs_registry, info.task_manager); - m_culling_manager = std::make_unique(); - m_render_scene = std::make_unique(); - } - - Status Scene::build(const SceneData& data) { - WG_PROFILE_CPU_SCENE("Scene::build"); - - return WG_OK; + Scene::Scene(SceneCreateInfo& info) { + m_name = info.name; } void Scene::advance(float delta_time) { @@ -55,30 +38,16 @@ namespace wmoge { m_time += m_delta_time; m_frame_id += 1; } - void Scene::clear() { - m_ecs_world->clear(); - } + void Scene::set_state(SceneState state) { m_state = state; } - void Scene::finalize() { - WG_PROFILE_CPU_SCENE("Scene::finalize"); - m_ecs_world.reset(); - m_culling_manager.reset(); - m_render_scene.reset(); + void Scene::finalize() { } + const Strid& Scene::get_name() { return m_name; } - EcsWorld* Scene::get_ecs_world() { - return m_ecs_world.get(); - } - CullingManager* Scene::get_culling_manager() { - return m_culling_manager.get(); - } - RenderScene* Scene::get_render_scene() { - return m_render_scene.get(); - } }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene.hpp b/engine/runtime/scene/scene.hpp index 6ba09c480..92b3a6bba 100644 --- a/engine/runtime/scene/scene.hpp +++ b/engine/runtime/scene/scene.hpp @@ -27,14 +27,11 @@ #pragma once +#include "core/any_storage.hpp" #include "core/class.hpp" #include "core/ref.hpp" #include "core/string_id.hpp" #include "core/weak_ref.hpp" -#include "ecs/ecs_world.hpp" -#include "render/culling.hpp" -#include "render/graphics_pipeline.hpp" -#include "render/render_scene.hpp" #include "scene/scene_data.hpp" #include @@ -57,9 +54,7 @@ namespace wmoge { * @brief Info for scene construction */ struct SceneCreateInfo { - Strid name; - class EcsRegistry* ecs_registry; - class TaskManager* task_manager; + Strid name; }; /** @@ -72,51 +67,55 @@ namespace wmoge { * in a ECS world in an optimized fashion, what gives fast processing and low overhed. * * Scene data is optimized for runtime simulation, fast deserialization, not for the editing. - * Editing of the scene done by a separate stucture, named SceneTree. Tree manages hierarchy of - * nodes with extra editor information (not shared with final game). It follows SOLID principels, + * Editing of the scene done by a separate stucture, managed outside. Editing metadata stored + * only for editor scenes, don not affecting final runtime performace. It follows SOLID principels, * gives flexibility and performance in the final game (where Godot, UE, CryEngine, Unity use * mix or editor and scene logic, what causes pure CPU performance of scene processing). * * Update of this scene state, sinmulation, scene rendering is done externally. * Scene data is travered by a scene manager, and required operations performed there. - * - * @see SceneNode - * @see SceneTree */ class Scene final : public RefCnt { public: - Scene(const SceneCreateInfo& info); - - Status build(const SceneData& data); - void advance(float delta_time); - void clear(); - void set_state(SceneState state); - void finalize(); - - [[nodiscard]] const Strid& get_name(); - [[nodiscard]] EcsWorld* get_ecs_world(); - [[nodiscard]] CullingManager* get_culling_manager(); - [[nodiscard]] RenderScene* get_render_scene(); - [[nodiscard]] float get_time() const { return m_time; } - [[nodiscard]] float get_delta_time() const { return m_delta_time; } - [[nodiscard]] bool need_simulate() const { return m_need_simulate; } - [[nodiscard]] bool need_render() const { return m_need_render; } - [[nodiscard]] int get_frame_id() const { return m_frame_id; } - [[nodiscard]] SceneState get_state() const { return m_state; } + Scene(SceneCreateInfo& info); - private: - std::unique_ptr m_ecs_world; - std::unique_ptr m_culling_manager; - std::unique_ptr m_render_scene; + void advance(float delta_time); + void set_state(SceneState state); + void finalize(); + + template + T* get(); + + template + void add(std::shared_ptr attribute); - Strid m_name; - float m_time = 0.0f; - float m_delta_time = 0.0f; - bool m_need_simulate = true; - bool m_need_render = true; - int m_frame_id = -1; + [[nodiscard]] const Strid& get_name(); + [[nodiscard]] float get_time() const { return m_time; } + [[nodiscard]] float get_delta_time() const { return m_delta_time; } + [[nodiscard]] int get_frame_id() const { return m_frame_id; } + [[nodiscard]] SceneState get_state() const { return m_state; } + private: + AnyStorage m_attributes; SceneState m_state = SceneState::Default; + Strid m_name; + float m_time = 0.0f; + float m_delta_time = 0.0f; + int m_frame_id = -1; }; + template + inline T* Scene::get() { + return m_attributes.get(); + } + + template + inline void Scene::add(std::shared_ptr attribute) { + T* attribute_ptr = attribute.get(); + m_attributes.add>(std::move(attribute)); + m_attributes.add(attribute_ptr); + } + + using SceneRef = Ref; + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_components.hpp b/engine/runtime/scene/scene_components.hpp deleted file mode 100644 index ef3fd5355..000000000 --- a/engine/runtime/scene/scene_components.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/**********************************************************************************/ -/* Wmoge game engine */ -/* Available at github https://github.com/EgorOrachyov/wmoge */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 Egor Orachyov */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - -#pragma once - -#include "core/buffered_vector.hpp" -#include "ecs/ecs_component.hpp" -#include "ecs/ecs_entity.hpp" -#include "math/aabb.hpp" -#include "math/color.hpp" -#include "math/mat.hpp" -#include "math/math_utils3d.hpp" -#include "math/transform.hpp" -#include "math/vec.hpp" -#include "render/camera.hpp" -#include "render/culling.hpp" -#include "render/light.hpp" - -#include -#include - -namespace wmoge { - - /** - * @class EcsComponentChildren - * @brief List of entity children, for complex objects - */ - struct EcsComponentChildren : EcsComponent { - WG_ECS_COMPONENT(EcsComponentChildren); - - buffered_vector children; - }; - - /** - * @class EcsComponentParent - * @brief Parent entity, for complex objects - */ - struct EcsComponentParent : EcsComponent { - WG_ECS_COMPONENT(EcsComponentParent); - - EcsEntity parent; - }; - - /** - * @class EcsComponentTransform - * @brief Local transform of the entity in some hierarchy - */ - struct EcsComponentTransform : EcsComponent { - WG_ECS_COMPONENT(EcsComponentTransform); - - Transform3d transform; - }; - - /** - * @class EcsComponentTransformUpd - * @brief Local transform update relative data - */ - struct EcsComponentTransformUpd : EcsComponent { - WG_ECS_COMPONENT(EcsComponentTransformUpd); - - int batch_id = 0; - int frame_updated = -1; - bool is_dirty = true; - }; - - /** - * @class EcsComponentLocalToWorld - * @brief Matrix to convert local to world coordinates of an object - */ - struct EcsComponentLocalToWorld : EcsComponent { - WG_ECS_COMPONENT(EcsComponentLocalToWorld); - - Mat4x4f matrix = Math3d::identity(); - }; - - /** - * @class EcsComponentWorldToLocal - * @brief Matrix to convert world to local coordinates of an object - */ - struct EcsComponentWorldToLocal : EcsComponent { - WG_ECS_COMPONENT(EcsComponentWorldToLocal); - - Mat4x4f matrix = Math3d::identity(); - }; - - /** - * @class EcsComponentLocalToParent - * @brief Matrix to convert local to parent coordinates of an object - */ - struct EcsComponentLocalToParent : EcsComponent { - WG_ECS_COMPONENT(EcsComponentLocalToParent); - - Mat4x4f matrix = Math3d::identity(); - }; - - /** - * @class EcsComponentAabbLocal - * @brief Aabb volume of object in the local space - */ - struct EcsComponentAabbLocal : EcsComponent { - WG_ECS_COMPONENT(EcsComponentAabbLocal); - - Aabbf aabb; - }; - - /** - * @class EcsComponentAabbWorld - * @brief Aabb volume of object in the world space - */ - struct EcsComponentAabbWorld : EcsComponent { - WG_ECS_COMPONENT(EcsComponentAabbWorld); - - Aabbf aabb; - }; - - /** - * @class EcsComponentTag - * @brief Unique tag for fast search of an entity - */ - struct EcsComponentTag : EcsComponent { - WG_ECS_COMPONENT(EcsComponentTag); - - Strid tag; - }; - - /** - * @class EcsComponentName - * @brief Unique full name of entity on a scene - */ - struct EcsComponentName : EcsComponent { - WG_ECS_COMPONENT(EcsComponentName); - - std::string name; - }; - - /** - * @class EcsComponentCamera - * @brief Game camera component - */ - struct EcsComponentCamera : EcsComponent { - WG_ECS_COMPONENT(EcsComponentCamera); - - Camera camera; - }; - - /** - * @class EcsComponentLight - * @brief Light source component - */ - struct EcsComponentLight : EcsComponent { - WG_ECS_COMPONENT(EcsComponentLight); - - Light light; - }; - - /** - * @class EcsComponentCullingItem - * @brief Item for culling (shared for geometry, lights, etc.) - */ - struct EcsComponentCullingItem : EcsComponent { - WG_ECS_COMPONENT(EcsComponentCullingItem); - - CullingItem item; - }; - -}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_data.cpp b/engine/runtime/scene/scene_data.cpp index 65efb186c..d9dc0d29c 100644 --- a/engine/runtime/scene/scene_data.cpp +++ b/engine/runtime/scene/scene_data.cpp @@ -27,17 +27,6 @@ #include "scene_data.hpp" -#include "profiler/profiler_cpu.hpp" - namespace wmoge { - void SceneDataCamera::fill(EcsComponentCamera& component) const { - Camera& camera = component.camera; - camera.set_fov(fov); - camera.set_near_far(near, far); - camera.set_color(color); - camera.set_proj(projection); - camera.set_name(name); - } - }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_data.hpp b/engine/runtime/scene/scene_data.hpp index 58ad1a7f6..44e912454 100644 --- a/engine/runtime/scene/scene_data.hpp +++ b/engine/runtime/scene/scene_data.hpp @@ -27,21 +27,10 @@ #pragma once -#include "asset/asset_ref.hpp" -#include "core/buffered_vector.hpp" -#include "core/class.hpp" -#include "core/ref.hpp" -#include "ecs/ecs_core.hpp" -#include "ecs/ecs_world.hpp" -#include "io/serialization.hpp" -#include "math/color.hpp" -#include "math/transform.hpp" -#include "platform/window.hpp" -#include "render/culling.hpp" -#include "render/graphics_pipeline.hpp" -#include "render/model.hpp" -#include "render/render_scene.hpp" -#include "scene/scene_components.hpp" +#include "asset/asset.hpp" +#include "core/string_id.hpp" +#include "rtti/traits.hpp" +#include "scene/scene_feature.hpp" #include #include @@ -51,47 +40,59 @@ namespace wmoge { /** - * @class SceneDataSpatial - * @brief Serializable struct with transform data for a scene entity + * @class EntityDesc + * @brief Struct describing scene entity */ - struct SceneDataSpatial { - Transform3d transform; - std::optional parent; + struct EntityDesc { + WG_RTTI_STRUCT(EntityDesc) + + UUID uuid; + std::string name; + std::vector> features; }; + WG_RTTI_STRUCT_BEGIN(EntityDesc) { + WG_RTTI_FIELD(uuid, {}); + WG_RTTI_FIELD(name, {}); + WG_RTTI_FIELD(features, {}); + } + WG_RTTI_END; + /** - * @class SceneDataCamera - * @brief Serializable struct with camera data for a scene entity + * @class SceneData + * @brief Sctuct storing scene raw data */ - struct SceneDataCamera { - Strid name; - Color4f color = Color::BLACK4f; - float fov = 45.0f; - float near = 0.1f; - float far = 10000.0f; - CameraProjection projection = CameraProjection::Perspective; + struct SceneData { + WG_RTTI_STRUCT(SceneData) - void fill(EcsComponentCamera& component) const; + Strid name; + std::vector entities; }; - /** @brief Index used to reference entities in this struct */ - using SceneEntityIndex = int; - - /** @brief Vector with data mapped to entity by index */ - template - using SceneEntityVector = std::vector>; + WG_RTTI_STRUCT_BEGIN(SceneData) { + WG_RTTI_FIELD(name, {}); + WG_RTTI_FIELD(entities, {}); + } + WG_RTTI_END; /** - * @class SceneData - * @brief Serializable struct with a scene data for a runtime scene + * @class SceneDataAsset + * @brief Represents scene data as asset which can be saved and loaded from disc */ - struct SceneData final { - Strid name; - std::vector entities; - SceneEntityVector names; - SceneEntityVector hier; - SceneEntityVector cameras; - GraphicsPipelineSettings pipeline; + class SceneDataAsset : public Asset { + public: + WG_RTTI_CLASS(SceneDataAsset, Asset) + + [[nodiscard]] const SceneData& get_data() const { return m_data; } + + private: + SceneData m_data; }; + WG_RTTI_CLASS_BEGIN(SceneDataAsset) { + WG_RTTI_FACTORY(); + WG_RTTI_FIELD(m_data, {}); + } + WG_RTTI_END; + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_feature.hpp b/engine/runtime/scene/scene_feature.hpp new file mode 100644 index 000000000..8bbd92451 --- /dev/null +++ b/engine/runtime/scene/scene_feature.hpp @@ -0,0 +1,97 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "core/array_view.hpp" +#include "core/uuid.hpp" +#include "ecs/ecs_entity.hpp" +#include "rtti/traits.hpp" + +namespace wmoge { + + /** + * @class EntityFeature + * @brief Describes single aspect/feature of a particular ecs entity + */ + class EntityFeature : public RttiObject { + public: + WG_RTTI_CLASS(EntityFeature, RttiObject) + + EntityFeature() = default; + }; + + WG_RTTI_CLASS_BEGIN(EntityFeature) { + WG_RTTI_META_DATA(); + WG_RTTI_FACTORY(); + } + WG_RTTI_END; + + /** + * @class EntityFeatureVector + * @brief Optimized storage for features of a group of entities + */ + class EntityFeatureVector : public RttiObject { + public: + WG_RTTI_CLASS(EntityFeatureVector, RttiObject) + + EntityFeatureVector() = default; + }; + + WG_RTTI_CLASS_BEGIN(EntityFeatureVector) { + WG_RTTI_META_DATA(); + WG_RTTI_FACTORY(); + } + WG_RTTI_END; + + /** @brief Context passed to trait on entity setup */ + struct EntitySetupContext { + class EcsWorld* world = nullptr; + class Scene* scene = nullptr; + }; + + /** @brief Context passed to trait on entity creation */ + struct EntityBuildContext { + class EcsWorld* world = nullptr; + class Scene* scene = nullptr; + class SceneUuidMap* uuid = nullptr; + }; + + /** + * @class EntityFeatureTrait + * @brief Entity trait responsible for handling partical features on the entity + */ + class EntityFeatureTrait : public RefCnt { + public: + virtual RttiSubclass get_feature_type() { return {}; } + virtual Status fill_requirements(std::vector>& required_features) { return StatusCode::NotImplemented; } + virtual Status setup_entity(EcsArch& arch, const EntityFeature& feature, EntitySetupContext& context) { return StatusCode::NotImplemented; } + virtual Status build_entity(EcsEntity entity, const EntityFeature& feature, EntityBuildContext& context) { return StatusCode::NotImplemented; } + virtual Status build_entities(array_view entities, const EntityFeatureVector& features, EntityBuildContext& context) { return StatusCode::NotImplemented; } + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_feature_adapter.hpp b/engine/runtime/scene/scene_feature_adapter.hpp new file mode 100644 index 000000000..b582445b5 --- /dev/null +++ b/engine/runtime/scene/scene_feature_adapter.hpp @@ -0,0 +1,57 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "scene/scene_feature.hpp" + +namespace wmoge { + + template + class EntitySimpleFeatureTrait : public EntityFeatureTrait { + public: + virtual Status setup_entity_typed(EcsArch& arch, const T& feature, EntitySetupContext& context) { return StatusCode::NotImplemented; } + virtual Status build_entity_typed(EcsEntity entity, const T& feature, EntityBuildContext& context) { return StatusCode::NotImplemented; } + + RttiSubclass get_feature_type() override { + return T::get_class_static(); + } + + Status fill_requirements(std::vector>& required_features) override { + return WG_OK; + } + + Status setup_entity(EcsArch& arch, const EntityFeature& feature, EntitySetupContext& context) override { + return setup_entity_typed(arch, dynamic_cast(feature), context); + } + + Status build_entity(EcsEntity entity, const EntityFeature& feature, EntityBuildContext& context) override { + return build_entity_typed(entity, dynamic_cast(feature), context); + } + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_manager.cpp b/engine/runtime/scene/scene_manager.cpp index ae20e3736..de76ad942 100644 --- a/engine/runtime/scene/scene_manager.cpp +++ b/engine/runtime/scene/scene_manager.cpp @@ -27,47 +27,19 @@ #include "scene_manager.hpp" -#include "core/async.hpp" #include "core/ioc_container.hpp" -#include "core/task_parallel_for.hpp" -#include "ecs/ecs_registry.hpp" -#include "gfx/gfx_cmd_list.hpp" -#include "gfx/gfx_driver.hpp" -#include "platform/time.hpp" -#include "platform/window.hpp" -#include "platform/window_manager.hpp" +#include "core/task.hpp" +#include "ecs/ecs_core.hpp" +#include "ecs/ecs_entity.hpp" +#include "ecs/ecs_world.hpp" #include "profiler/profiler_cpu.hpp" -#include "render/render_engine.hpp" -#include "scene/scene_components.hpp" +#include "scene/scene_uuid.hpp" #include #include namespace wmoge { - SceneManager::SceneManager(IocContainer* ioc) { - WG_LOG_INFO("init scene manager"); - - m_render_engine = ioc->resolve_value(); - m_task_manager = ioc->resolve_value(); - m_ecs_registry = ioc->resolve_value(); - - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - m_ecs_registry->register_component(); - } - void SceneManager::clear() { WG_PROFILE_CPU_SCENE("SceneManager::clear"); @@ -97,27 +69,20 @@ namespace wmoge { // Play scene scene_play(); } - void SceneManager::change(Ref scene) { - assert(scene); + void SceneManager::change_scene(SceneRef scene) { + assert(scene); m_next = std::move(scene); } - Ref SceneManager::get_running_scene() { + + SceneRef SceneManager::get_running_scene() { return m_running; } - Ref SceneManager::make_scene(const Strid& name) { - WG_PROFILE_CPU_SCENE("SceneManager::make_scene"); - SceneCreateInfo info; - info.name = name; - info.ecs_registry = m_ecs_registry; - info.task_manager = m_task_manager; - return m_scenes.emplace_back(make_ref(info)); - } - std::optional> SceneManager::find_by_name(const Strid& name) { - WG_PROFILE_CPU_SCENE("SceneManager::find_by_name"); + std::optional SceneManager::find_scene_by_name(const Strid& name) { + WG_PROFILE_CPU_SCENE("SceneManager::find_scene_by_name"); - for (Ref& scene : m_scenes) { + for (SceneRef& scene : m_scenes) { if (scene->get_name() == name) { return scene; } @@ -126,20 +91,107 @@ namespace wmoge { return std::nullopt; } - void SceneManager::update_scene_hier() { - WG_PROFILE_CPU_SCENE("SceneManager::update_scene_hier"); + SceneRef SceneManager::make_scene(const Strid& name) { + WG_PROFILE_CPU_SCENE("SceneManager::make_scene"); + + SceneCreateInfo info; + info.name = name; + return m_scenes.emplace_back(make_ref(info)); + } + + Status SceneManager::build_scene(const SceneRef& scene, const SceneData& data) { + WG_PROFILE_CPU_SCENE("SceneManager::build_scene"); + + EcsWorld* world = scene->get(); + + SceneUuidMap uuid_map; + std::vector entities; + std::vector archs; + + EntitySetupContext setup_context; + setup_context.scene = scene.get(); + setup_context.world = world; + + EntityBuildContext build_context; + build_context.scene = scene.get(); + build_context.world = world; + build_context.uuid = &uuid_map; + + archs.reserve(data.entities.size()); + for (const EntityDesc& entity_desc : data.entities) { + EcsArch entity_arch; + + for (const Ref& feature : entity_desc.features) { + EntityFeatureTrait* trait = find_trait(feature->get_class_name()).value_or(nullptr); + if (!trait) { + WG_LOG_ERROR("no such trait type for entity " << entity_desc.name << " feature " << feature->get_class_name()); + return StatusCode::InvalidData; + } + + EcsArch arch; + if (!trait->setup_entity(arch, *feature, setup_context)) { + WG_LOG_ERROR("failed setup entity " << entity_desc.name << " feature " << feature->get_class_name()); + return StatusCode::Error; + } + + if ((arch & entity_arch).any()) { + WG_LOG_ERROR("feature arch collision for entity " << entity_desc.name << " feature " << feature->get_class_name()); + return StatusCode::InvalidData; + } + + entity_arch |= arch; + } + + archs.push_back(entity_arch); + } + + entities.reserve(archs.size()); + for (std::size_t i = 0; i < archs.size(); i++) { + const EcsEntity entity = world->allocate_entity(); + + entities.push_back(entity); + world->make_entity(entity, archs[i]); + uuid_map.add_entity(data.entities[i].uuid, entity); + } + + for (std::size_t i = 0; i < entities.size(); i++) { + const EcsEntity entity = entities[i]; + const EntityDesc& entity_desc = data.entities[i]; + + for (const Ref& feature : entity_desc.features) { + EntityFeatureTrait* trait = find_trait(feature->get_class_name()).value_or(nullptr); + assert(trait); + + if (!trait->build_entity(entity, *feature, build_context)) { + WG_LOG_ERROR("failed build entity " << entity_desc.name << " feature " << feature->get_class_name()); + return StatusCode::Error; + } + } + } + + return WG_OK; } - void SceneManager::update_scene_cameras() { - WG_PROFILE_CPU_SCENE("SceneManager::update_scene_cameras"); + Async SceneManager::build_scene_async(TaskManager* task_manager, const SceneRef& scene, const Ref& data) { + WG_PROFILE_CPU_SCENE("SceneManager::build_scene_async"); + + Task task(scene->get_name(), [scene, data, this](TaskContext&) { + if (!build_scene(scene, data->get_data())) { + return 1; + } + return 0; + }); + + return task.schedule(task_manager).as_async(); } - void SceneManager::update_scene_visibility() { - WG_PROFILE_CPU_SCENE("SceneManager::update_scene_visibility"); + void SceneManager::add_trait(const Ref& trait) { + m_traits[trait->get_feature_type()->get_name()] = trait; } - void SceneManager::render_scene() { - WG_PROFILE_CPU_SCENE("SceneManager::render_scene"); + std::optional SceneManager::find_trait(const Strid& rtti) { + auto iter = m_traits.find(rtti); + return iter != m_traits.end() ? iter->second.get() : std::optional(); } void SceneManager::scene_change() { @@ -173,17 +225,6 @@ namespace wmoge { void SceneManager::scene_play() { WG_PROFILE_CPU_SCENE("SceneManager::scene_play"); - // m_running->advance(... instance()->time()->get_delta_time_game()); - - m_sync = SyncContext(); - - update_scene_hier(); - update_scene_cameras(); - update_scene_visibility(); - render_scene(); - - m_sync.await_all(); - assert(m_running->get_state() == SceneState::Playing); } @@ -205,13 +246,8 @@ namespace wmoge { m_running->set_state(SceneState::Finished); } - void SceneManager::SyncContext::await_all() { - WG_PROFILE_CPU_SCENE("SyncContext::await_all"); - - if (complete_heir.is_not_null()) complete_heir.wait_completed(); - if (complete_cameras.is_not_null()) complete_cameras.wait_completed(); - if (complete_visibility.is_not_null()) complete_visibility.wait_completed(); - if (complete_render.is_not_null()) complete_render.wait_completed(); + void bind_by_ioc_scene_manager(class IocContainer* ioc) { + ioc->bind(); } }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_manager.hpp b/engine/runtime/scene/scene_manager.hpp index 4c0c52487..4908b5c50 100644 --- a/engine/runtime/scene/scene_manager.hpp +++ b/engine/runtime/scene/scene_manager.hpp @@ -28,12 +28,15 @@ #pragma once #include "core/async.hpp" +#include "core/flat_map.hpp" +#include "core/task_manager.hpp" #include "scene/scene.hpp" +#include "scene/scene_data.hpp" +#include "scene/scene_feature.hpp" #include #include #include -#include #include namespace wmoge { @@ -44,20 +47,19 @@ namespace wmoge { */ class SceneManager final { public: - SceneManager(class IocContainer* ioc); + SceneManager() = default; - void clear(); - void update(); - void change(Ref scene); - Ref get_running_scene(); - Ref make_scene(const Strid& name); - std::optional> find_by_name(const Strid& name); + void clear(); + void update(); - private: - void update_scene_hier(); - void update_scene_cameras(); - void update_scene_visibility(); - void render_scene(); + void change_scene(SceneRef scene); + SceneRef get_running_scene(); + std::optional find_scene_by_name(const Strid& name); + SceneRef make_scene(const Strid& name); + Status build_scene(const SceneRef& scene, const SceneData& data); + Async build_scene_async(TaskManager* task_manager, const SceneRef& scene, const Ref& data); + void add_trait(const Ref& trait); + std::optional find_trait(const Strid& rtti); private: void scene_change(); @@ -68,27 +70,14 @@ namespace wmoge { void scene_finish(); private: - std::vector> m_scenes; // allocated scenes in the engine - std::deque> m_to_clear;// scheduled to be cleared - - Ref m_running;// active scene - Ref m_next; // next scene to set - Ref m_default;// default scene to always show something - - class EcsRegistry* m_ecs_registry = nullptr; - class TaskManager* m_task_manager = nullptr; - class RenderEngine* m_render_engine = nullptr; - - struct SyncContext { - Async complete_heir; - Async complete_cameras; - Async complete_visibility; - Async complete_render; - - void await_all(); - }; - - SyncContext m_sync;// Allows to sync different parts of scene update + std::vector m_scenes; // allocated scenes in the engine + std::deque m_to_clear;// scheduled to be cleared + SceneRef m_running; // active scene + SceneRef m_next; // next scene to set + SceneRef m_default; // default scene to always show something + flat_map> m_traits; }; + void bind_by_ioc_scene_manager(class IocContainer* ioc); + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_prefab.hpp b/engine/runtime/scene/scene_prefab.hpp index ceb2c2913..5a0ff8f3a 100644 --- a/engine/runtime/scene/scene_prefab.hpp +++ b/engine/runtime/scene/scene_prefab.hpp @@ -37,11 +37,11 @@ namespace wmoge { /** * @class ScenePrefab - * @brief A prefab asset which can be instantiated into a set of objects + * @brief A prefab asset which can be instantiated into a set of entities * - * Prefab stores a sub-tree of scene nodes, which can be instantiated and added + * Prefab stores a sub-tree of scene entities, which can be instantiated and added * to a scene tree at once. Prefab allows to make a complex object composed from - * nodes and use it to instantiate multiple times and keep all instances in sync. + * multiple entities and use it to instantiate multiple times. */ class ScenePrefab : public Asset { public: diff --git a/engine/runtime/scene/scene_uuid.cpp b/engine/runtime/scene/scene_uuid.cpp new file mode 100644 index 000000000..3375f1dd4 --- /dev/null +++ b/engine/runtime/scene/scene_uuid.cpp @@ -0,0 +1,49 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "scene_uuid.hpp" + +namespace wmoge { + + void SceneUuidMap::add_entity(UUID id, EcsEntity entity) { + m_map[id] = entity; + } + + std::optional SceneUuidMap::find_entity(UUID id) { + auto iter = m_map.find(id); + return iter != m_map.end() ? std::optional(iter->second) : std::optional(); + } + + void SceneUuidManager::add_entity(UUID id, EcsEntity entity) { + m_map.add_entity(id, entity); + } + + std::optional SceneUuidManager::find_entity(UUID id) { + return m_map.find_entity(id); + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/scene/scene_uuid.hpp b/engine/runtime/scene/scene_uuid.hpp new file mode 100644 index 000000000..ed1291435 --- /dev/null +++ b/engine/runtime/scene/scene_uuid.hpp @@ -0,0 +1,58 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "core/flat_map.hpp" +#include "core/uuid.hpp" +#include "ecs/ecs_entity.hpp" + +namespace wmoge { + + class SceneUuidMap { + public: + SceneUuidMap() = default; + + void add_entity(UUID id, EcsEntity entity); + std::optional find_entity(UUID id); + + private: + flat_map m_map; + }; + + class SceneUuidManager { + public: + SceneUuidManager() = default; + + void add_entity(UUID id, EcsEntity entity); + std::optional find_entity(UUID id); + + private: + SceneUuidMap m_map; + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/system/engine.cpp b/engine/runtime/system/engine.cpp index 745819093..2bb5ab873 100644 --- a/engine/runtime/system/engine.cpp +++ b/engine/runtime/system/engine.cpp @@ -37,6 +37,7 @@ #include "core/log.hpp" #include "core/task_manager.hpp" #include "ecs/ecs_registry.hpp" +#include "game/game_manager.hpp" #include "gfx/vulkan/vk_driver.hpp" #include "glsl/glsl_shader_compiler.hpp" #include "grc/pso_cache.hpp" @@ -117,11 +118,6 @@ namespace wmoge { m_profiler_gpu->enable(true); m_profiler_gpu->calibrate(m_time->get_start()); - m_shader_manager = m_ioc_container->resolve_value(); - m_shader_manager->add_compiler(make_ref(m_ioc_container)); - m_shader_manager->add_compiler(make_ref(m_ioc_container)); - m_shader_manager->add_compiler(make_ref(m_ioc_container)); - m_asset_manager->load_loaders(); m_asset_manager->add_library(std::make_shared("", m_ioc_container)); @@ -133,6 +129,12 @@ namespace wmoge { m_ecs_registry = m_ioc_container->resolve_value(); m_scene_manager = m_ioc_container->resolve_value(); m_view_manager = m_ioc_container->resolve_value(); + m_game_manager = m_ioc_container->resolve_value(); + + m_shader_manager = m_ioc_container->resolve_value(); + m_shader_manager->add_compiler(make_ref(m_ioc_container)); + m_shader_manager->add_compiler(make_ref(m_ioc_container)); + m_shader_manager->add_compiler(make_ref(m_ioc_container)); m_console->init(m_asset_manager); @@ -219,6 +221,7 @@ namespace wmoge { RenderEngine* Engine::render_engine() { return m_render_engine; } ViewManager* Engine::view_manager() { return m_view_manager; } EcsRegistry* Engine::ecs_registry() { return m_ecs_registry; } + GameManager* Engine::game_manager() { return m_game_manager; } EngineConfig* Engine::engine_config() { return m_engine_config; } }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/system/engine.hpp b/engine/runtime/system/engine.hpp index 921240bd8..1535663c1 100644 --- a/engine/runtime/system/engine.hpp +++ b/engine/runtime/system/engine.hpp @@ -81,6 +81,7 @@ namespace wmoge { class RenderEngine* render_engine(); class ViewManager* view_manager(); class EcsRegistry* ecs_registry(); + class GameManager* game_manager(); class EngineConfig* engine_config(); private: @@ -113,6 +114,7 @@ namespace wmoge { class EcsRegistry* m_ecs_registry = nullptr; class IocContainer* m_ioc_container = nullptr; class ProfilerGpu* m_profiler_gpu = nullptr; + class GameManager* m_game_manager = nullptr; class EngineConfig* m_engine_config = nullptr; bool m_exit_on_close = true; diff --git a/engine/runtime/system/game_application.cpp b/engine/runtime/system/game_application.cpp index 02d66234c..84ce8d6de 100644 --- a/engine/runtime/system/game_application.cpp +++ b/engine/runtime/system/game_application.cpp @@ -36,6 +36,7 @@ #include "core/log.hpp" #include "core/task_manager.hpp" #include "ecs/ecs_registry.hpp" +#include "game/game_manager.hpp" #include "gfx/vulkan/vk_driver.hpp" #include "glsl/glsl_shader_compiler.hpp" #include "grc/pso_cache.hpp" @@ -66,6 +67,7 @@ #include "asset/_rtti.hpp" #include "audio/_rtti.hpp" +#include "game/_rtti.hpp" #include "glsl/_rtti.hpp" #include "grc/_rtti.hpp" #include "material/_rtti.hpp" @@ -100,7 +102,8 @@ namespace wmoge { ioc->bind_by_ioc(); ioc->bind_by_ioc(); ioc->bind_by_ioc(); - ioc->bind_by_ioc(); + bind_by_ioc_scene_manager(ioc); + bind_by_ioc_game_manager(ioc); ioc->bind_by_ioc(); ioc->bind_by_factory([ioc]() { @@ -150,6 +153,7 @@ namespace wmoge { } static Status unbind_globals(IocContainer* ioc) { + ioc->unbind(); ioc->unbind(); ioc->unbind(); ioc->unbind(); @@ -183,6 +187,7 @@ namespace wmoge { rtti_pfx(); rtti_render(); rtti_scene(); + rtti_game(); rtti_system(); } diff --git a/template/assets/scenes/test_scene.asset b/template/assets/scenes/test_scene.asset index 0d8f4d3af..a6712fa4c 100644 --- a/template/assets/scenes/test_scene.asset +++ b/template/assets/scenes/test_scene.asset @@ -2,9 +2,9 @@ version: 1 uuid: 0 loader: DefaultAssetLoader -rtti: SceneTreePacked -description: "test scene tree" +rtti: SceneDataAsset +description: "test scene" deps: [ ] import_data: rtti: AssetImportData - source_files: [{file: "assets/trees/test_scene.scene"}] \ No newline at end of file + source_files: [{file: "assets/scenes/test_scene.scene"}] \ No newline at end of file diff --git a/template/assets/scenes/test_scene.scene b/template/assets/scenes/test_scene.scene index 9a5e432ae..0c5eeb592 100644 --- a/template/assets/scenes/test_scene.scene +++ b/template/assets/scenes/test_scene.scene @@ -1,68 +1,40 @@ -# Serialized scene tree of scene node into a yaml readable file -pipeline: - bloom: - dirt_mask: "assets/textures/dirt_mask" -nodes: - - name: "cameras" - uuid: "9468856891681035089" - type: Folder - - name: "camera_0" - uuid: "10463498962251759332" - type: Object - transform: - translation: 0 0 -10 - rotation: 0 0 0 - parent: "9468856891681035089" - properties: - - rtti: NodePropSpatial - - rtti: NodePropCamera - fov: 45.0 - projection: Perspective - - name: "camera_1" - uuid: "14122657702121638152" - type: Object - transform: - translation: 0 0 10 - rotation: 0 180 0 - parent: "9468856891681035089" - properties: - - rtti: NodePropSpatial - - rtti: NodePropCamera - fov: 45.0 - projection: Perspective - - name: "camera_2" - uuid: "8120079257729132446" - type: Object - transform: - translation: 10 0 0 - rotation: 0 -90 0 - parent: "9468856891681035089" - properties: - - rtti: NodePropSpatial - - rtti: NodePropCamera - fov: 45.0 - projection: Perspective - - name: "camera_3" - uuid: "9748030122664252639" - type: Object - transform: - translation: -10 0 0 - rotation: 0 90 0 - parent: "9468856891681035089" - properties: - - rtti: NodePropSpatial - - rtti: NodePropCamera - fov: 45.0 - projection: Perspective - - name: "models" - uuid: 13626177115197044525 - type: Folder - - name: "suzanne_auto_0" - uuid: 9635651463089379213 - parent: 13626177115197044525 - type: Object - transform: - translation: -45 0 -45 - rotation: 104.28762792055193 96.22532743218032 102.50450625101503 - scale: 0.1 0.1 0.1 - properties: [] \ No newline at end of file +# Serialized scene data in an yaml readable file +m_data: + name: "test_scene" + entities: + - uuid: 0 + name: "entity-0" + features: + - rtti: GmTransformFeature + transform: + translation: 0 0 0 + scale: 1 1 1 + type: NonMovable + - rtti: GmDebugPrimitiveFeature + type: Cone + - rtti: GmDebugLabelFeature + text: "entity-0" + - uuid: 1 + name: "entity-1" + features: + - rtti: GmTransformFeature + transform: + translation: 4 0 4 + scale: 1 3 1 + type: NonMovable + - rtti: GmDebugPrimitiveFeature + type: Cylinder + - rtti: GmDebugLabelFeature + text: "entity-1" + - uuid: 2 + name: "entity-2" + features: + - rtti: GmTransformFeature + transform: + translation: -4 0 4 + scale: 1 3 1 + type: NonMovable + - rtti: GmDebugPrimitiveFeature + type: Box + - rtti: GmDebugLabelFeature + text: "entity-2" \ No newline at end of file diff --git a/template/main.cpp b/template/main.cpp index 02a663c31..f80c133db 100644 --- a/template/main.cpp +++ b/template/main.cpp @@ -93,19 +93,24 @@ class TemplateApplication : public GameApplication { GameApplication::on_init(); - auto async_mesh = m_engine->asset_manager()->load_async(SID("assets/mesh/suzanne")); - auto async_tex2d = m_engine->asset_manager()->load_async(SID("assets/textures/dirt_mask")); - auto async_texCube = m_engine->asset_manager()->load_async(SID("assets/textures/skybox")); + auto async_mesh = m_engine->asset_manager()->load_async(SID("assets/mesh/suzanne")); + auto async_tex2d = m_engine->asset_manager()->load_async(SID("assets/textures/dirt_mask")); + // auto async_texCube = m_engine->asset_manager()->load_async(SID("assets/textures/skybox")); async_mesh.wait_completed(); async_tex2d.wait_completed(); - async_texCube.wait_completed(); + // async_texCube.wait_completed(); - mesh = async_mesh.result().cast(); - tex2d = async_tex2d.result().cast(); - texCube = async_texCube.result().cast(); + mesh = async_mesh.result().cast(); + tex2d = async_tex2d.result().cast(); + // texCube = async_texCube.result().cast(); - // Engine::instance()->scene_manager()->change(scene); + auto scene_data = m_engine->asset_manager()->load(SID("assets/scenes/test_scene")).cast(); + + auto s = m_engine->scene_manager()->make_scene(SID("test_scene")); + s->add(std::make_shared(m_engine->ecs_registry())); + + // m_engine->scene_manager()->build_scene(s, scene_data->get_data()); ShaderStructRegister rdc(SID("CanvasDrawCmd"), 80, m_engine->shader_manager()); rdc