Skip to content

Commit

Permalink
gh-36: setup new scene mng api & introduce game module
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorOrachyov committed Oct 27, 2024
1 parent fb698e3 commit 8bfb355
Show file tree
Hide file tree
Showing 50 changed files with 1,586 additions and 634 deletions.
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
12 changes: 11 additions & 1 deletion engine/plugins/runtime/asset/default_asset_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -55,7 +56,13 @@ namespace wmoge {
Ref<AssetImportData> import_data = context.asset_meta.import_data.cast<AssetImportData>();
assert(import_data);

RttiClass* rtti = context.ioc->resolve_value<RttiTypeStorage>()->find_class(context.asset_meta.rtti);
RttiTypeStorage* type_storage = context.ioc->resolve_value<RttiTypeStorage>();
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;
Expand All @@ -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<RttiTypeStorage*>(type_storage);
context.io_context.add<AssetManager*>(context.ioc->resolve_value<AssetManager>());

if (!asset->read_from_tree(context.io_context, asset_tree)) {
WG_LOG_ERROR("failed to load asset from file " << asset_id);
return StatusCode::FailedRead;
Expand Down
3 changes: 0 additions & 3 deletions engine/runtime/asset/asset_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>& asset) { return StatusCode::NotImplemented; }
virtual Status unload(Asset* asset) { return StatusCode::Ok; }
Expand Down
1 change: 0 additions & 1 deletion engine/runtime/asset/asset_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ namespace wmoge {
class AssetManager {
public:
AssetManager(class IocContainer* ioc);
~AssetManager() = default;

AsyncResult<Ref<Asset>> load_async(const AssetId& name);
Ref<Asset> load(const AssetId& name);
Expand Down
50 changes: 8 additions & 42 deletions engine/runtime/asset/asset_ref.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,6 @@ namespace wmoge {
AssetRef(Ref<T> ptr) : Ref<T>(std::move(ptr)) {}
};

/**
* @class AssetRefWeak
* @brief Aux box to store asset ref and serialize/deserialize it automatically to and from files
*/
template<typename T>
class AssetRefWeak : public AssetId {
public:
static_assert(std::is_base_of_v<Asset, T>, "Must be an asset");

AssetRefWeak() = default;
AssetRefWeak(const AssetId& id) : AssetId(id) {}
AssetRefWeak(const AssetRef<T>& ref) : AssetId(ref ? ref->get_id() : AssetId()) {}
};

template<typename T>
Status tree_read(IoContext& context, IoTree& tree, AssetRef<T>& ref) {
AssetId id;
Expand Down Expand Up @@ -110,33 +96,13 @@ namespace wmoge {
}

template<typename T>
Status tree_read(IoContext& context, IoTree& tree, AssetRefWeak<T>& ref) {
AssetId id;
WG_TREE_READ(context, tree, id);
ref = AssetRefWeak<T>(id);
return WG_OK;
}

template<typename T>
Status tree_write(IoContext& context, IoTree& tree, const AssetRefWeak<T>& ref) {
AssetId id = ref;
WG_TREE_WRITE(context, tree, id);
return WG_OK;
}

template<typename T>
Status stream_read(IoContext& context, IoStream& stream, AssetRefWeak<T>& ref) {
AssetId id;
WG_ARCHIVE_READ(context, stream, id);
ref = AssetRefWeak<T>(id);
return WG_OK;
}

template<typename T>
Status stream_write(IoContext& context, IoStream& stream, const AssetRefWeak<T>& ref) {
AssetId id = ref;
WG_ARCHIVE_WRITE(context, stream, id);
return WG_OK;
}
struct RttiTypeOf<AssetRef<T>, typename std::enable_if<std::is_base_of_v<Asset, T>>::type> {
static Strid name() {
return SID(std::string("asset<") + rtti_type<T>()->get_str() + ">");
}
static Ref<RttiType> make() {
return make_ref<RttiTypeRefT<T>>(name());
}
};

}// namespace wmoge
2 changes: 1 addition & 1 deletion engine/runtime/core/any_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace wmoge {
AnyStorage() = default;

template<typename T>
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<typename T>
bool has() const noexcept { return m_map.find(typeid(T)) != m_map.end(); }
Expand Down
2 changes: 1 addition & 1 deletion engine/runtime/core/string_id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 0 additions & 3 deletions engine/runtime/ecs/ecs_component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,4 @@ namespace wmoge {
std::function<void(void*, void*)> swap;
};

#define WG_ECS_COMPONENT(ecs_component_class) \
static constexpr char NAME_CSTR[] = #ecs_component_class;

}// namespace wmoge
31 changes: 28 additions & 3 deletions engine/runtime/ecs/ecs_query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,16 @@ namespace wmoge {
m_range_count(count) {
}

template<typename Functor>
void for_each(Functor f);

template<typename Component>
bool has() { return m_arch.has_component<Component>(); }
[[nodiscard]] bool has_component() const;

template<typename Component>
Component& get_component(int entity_idx) { return *m_storage.get_component<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; }
Expand All @@ -142,4 +146,25 @@ namespace wmoge {
/** @brief Function used to execute ecs query */
using EcsQueuryFunction = std::function<void(EcsQueryContext& context)>;

template<typename Functor>
inline void EcsQueryContext::for_each(Functor f) {
for (int i = m_range_start; i < m_range_start + m_range_count; i++) {
f(i);
}
}

template<typename Component>
inline bool EcsQueryContext::has_component() const {
return m_arch.has_component<Component>();
}

template<typename Component>
inline Component& EcsQueryContext::get_component(int entity_idx) {
return *m_storage.get_component<Component>(entity_idx);
}

inline EcsEntity wmoge::EcsQueryContext::get_entity(int entity_idx) {
return m_storage.get_entity(entity_idx);
}

}// namespace wmoge
6 changes: 3 additions & 3 deletions engine/runtime/ecs/ecs_registry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ namespace wmoge {
[[nodiscard]] int get_expand_size() const { return m_expand_size; }

template<typename Component>
void register_component();
void register_component(const std::string& name);

private:
static const int MAX_CMP = EcsLimits::MAX_COMPONENTS;
Expand All @@ -75,7 +75,7 @@ namespace wmoge {
};

template<typename Component>
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);

Expand All @@ -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;
Expand Down
11 changes: 5 additions & 6 deletions engine/runtime/ecs/ecs_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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&) {
Expand All @@ -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) {
Expand All @@ -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() {
Expand Down
9 changes: 4 additions & 5 deletions engine/runtime/ecs/ecs_world.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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();
Expand All @@ -129,15 +129,14 @@ namespace wmoge {
private:
std::vector<EcsEntityInfo> m_entity_info; // entity info, accessed by entity idx
std::deque<EcsEntity> m_entity_pool; // pool with free entities handles
int m_entity_counter = 0;// total count of created entities
flat_map<EcsArch, int> m_arch_to_idx; // arch to unique index
std::vector<std::unique_ptr<EcsArchStorage>> m_arch_storage; // storage per arch, indexed by arch idx
std::vector<EcsArch> m_arch_by_idx; // arch mask, indexed by arch idx
std::vector<std::pair<EcsQuery, EcsQueuryFunction>> 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;
};
Expand Down
3 changes: 1 addition & 2 deletions engine/runtime/engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<GmDebugMeshFeature>();
rtti_type<GmDebugLabelFeature>();
rtti_type<GmDebugPrimitiveFeature>();
rtti_type<GmTransformFeature>();
}

}// namespace wmoge
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,10 @@
/* SOFTWARE. */
/**********************************************************************************/

#include "scene_components.hpp"
#pragma once

namespace wmoge {

void rtti_game();

}// namespace wmoge
Loading

0 comments on commit 8bfb355

Please sign in to comment.