From 443014b47282e9245b7625c0a9c968210eeaacb9 Mon Sep 17 00:00:00 2001 From: Egor Orachyov Date: Sun, 25 Feb 2024 21:11:53 +0300 Subject: [PATCH] gh-1: big engine rework - add IoC & dependency injection to manage singleton systems - rewrite application and engine core loop exectuion and init - refactor mesh resoruce (gh-57) - add io macro to autogen serialization code for structs (gh-46) - refactor scene nodes structure (gh-36) --- engine/CMakeLists.txt | 82 +++-- engine/core/array_view.hpp | 7 +- engine/core/async.hpp | 7 +- engine/core/callback_queue.hpp | 7 +- engine/core/callback_stream.hpp | 7 +- engine/core/class.cpp | 48 +-- engine/core/class.hpp | 20 +- engine/core/cmd_line.hpp | 7 +- engine/core/crc32.cpp | 9 + engine/core/crc32.hpp | 26 +- engine/core/data.hpp | 7 +- engine/core/engine.cpp | 162 ---------- engine/core/fast_map.hpp | 31 +- engine/core/fast_set.hpp | 7 +- engine/core/fast_vector.hpp | 7 +- engine/core/hook.hpp | 9 +- engine/core/ioc_container.cpp | 71 +++++ engine/core/ioc_container.hpp | 192 +++++++++++ engine/core/layer.hpp | 8 +- engine/core/log.cpp | 12 +- engine/core/log.hpp | 7 +- engine/core/mask.hpp | 25 +- engine/core/object.cpp | 30 +- engine/core/object.hpp | 47 ++- engine/core/pool_vector.hpp | 227 +++++++++++++ engine/core/random.hpp | 7 +- engine/core/ref.cpp | 11 +- engine/core/ref.hpp | 12 +- .../signal.hpp} | 92 ++++-- engine/core/status.hpp | 7 +- engine/core/string_id.cpp | 3 +- engine/core/string_id.hpp | 13 +- engine/core/string_utf.hpp | 7 +- engine/core/string_utils.hpp | 7 +- engine/core/synchronization.hpp | 7 +- engine/core/task.cpp | 2 +- engine/core/task.hpp | 7 +- engine/core/task_hnd.hpp | 7 +- engine/core/task_manager.cpp | 2 +- engine/core/task_manager.hpp | 7 +- engine/core/task_parallel_for.cpp | 2 +- engine/core/task_parallel_for.hpp | 7 +- engine/core/task_runtime.hpp | 7 +- engine/core/timer.hpp | 7 +- engine/core/typed_array.hpp | 7 +- engine/core/typed_map.hpp | 7 +- engine/core/unrolled_list.hpp | 250 --------------- engine/core/uuid.hpp | 7 +- engine/core/var.hpp | 7 +- engine/core/weak_ref.cpp | 65 ++++ engine/core/weak_ref.hpp | 201 ++++++++++++ engine/debug/console.cpp | 5 +- engine/debug/console.hpp | 7 +- engine/debug/debug_layer.cpp | 25 +- engine/debug/debug_layer.hpp | 7 +- engine/debug/profiler.cpp | 15 +- engine/debug/profiler.hpp | 27 +- engine/ecs/ecs_component.hpp | 48 +-- engine/ecs/ecs_core.cpp | 2 +- engine/ecs/ecs_core.hpp | 28 +- engine/ecs/ecs_entity.hpp | 7 +- engine/ecs/ecs_memory.cpp | 10 +- engine/ecs/ecs_memory.hpp | 10 +- engine/ecs/ecs_registry.cpp | 2 +- engine/ecs/ecs_registry.hpp | 48 ++- engine/ecs/ecs_system.hpp | 7 +- engine/ecs/ecs_world.cpp | 93 ++++-- engine/ecs/ecs_world.hpp | 73 ++++- engine/engine.hpp | 37 ++- engine/event/event.hpp | 5 +- engine/event/event_action.hpp | 5 +- engine/event/event_filesystem.hpp | 7 +- engine/event/event_input.hpp | 5 +- engine/event/event_listener.hpp | 7 +- engine/event/event_manager.hpp | 7 +- engine/event/event_resource.hpp | 5 +- engine/event/event_script.hpp | 5 +- engine/event/event_token.hpp | 5 +- engine/event/event_window.hpp | 5 +- engine/event/register_classes_event.hpp | 7 +- engine/gameplay/action_manager.cpp | 2 +- engine/gameplay/action_map.cpp | 2 +- engine/gameplay/game_token_manager.cpp | 2 +- engine/gfx/gfx_buffers.cpp | 47 +++ engine/gfx/gfx_buffers.hpp | 29 ++ engine/gfx/gfx_defs.hpp | 1 + engine/gfx/gfx_desc_set.cpp | 22 +- engine/gfx/gfx_desc_set.hpp | 5 +- engine/gfx/gfx_dynamic_buffers.cpp | 2 +- engine/gfx/gfx_pass.cpp | 26 ++ .../gfx_pass.hpp} | 54 ++-- engine/gfx/gfx_sampler.cpp | 40 +-- engine/gfx/gfx_sampler.hpp | 5 +- engine/gfx/gfx_shader.cpp | 89 ++---- engine/gfx/gfx_shader.hpp | 11 +- engine/gfx/gfx_vector.hpp | 2 +- engine/gfx/threaded/gfx_worker.cpp | 2 +- engine/gfx/vulkan/vk_driver.cpp | 2 +- engine/gfx/vulkan/vk_pipeline.cpp | 2 +- engine/gfx/vulkan/vk_shader.cpp | 19 +- engine/gfx/vulkan/vk_shader.hpp | 4 +- engine/gfx/vulkan/vk_window.cpp | 2 +- engine/hgfx/hgfx_pass_base.cpp | 2 +- engine/hgfx/hgfx_pass_text.cpp | 2 +- engine/hooks/hook_config.hpp | 18 +- engine/hooks/hook_logs.hpp | 16 +- engine/hooks/hook_profiler.hpp | 101 ++++++ engine/hooks/hook_root_remap.hpp | 13 +- engine/hooks/hook_uuid_gen.hpp | 9 +- engine/io/archive.cpp | 12 + engine/io/archive.hpp | 118 +++++-- engine/io/archive_file.hpp | 7 +- engine/io/archive_memory.hpp | 7 +- engine/io/base64.hpp | 7 +- engine/io/serialization.hpp | 137 ++++++++ engine/io/yaml.cpp | 10 +- engine/io/yaml.hpp | 144 ++++++--- engine/main/main.cpp | 298 ------------------ engine/main/main.hpp | 93 ------ engine/math/aabb.hpp | 20 +- engine/math/frustum.hpp | 7 +- engine/math/mat.hpp | 7 +- engine/math/math_utils.hpp | 7 +- engine/math/math_utils3d.hpp | 16 +- engine/math/plane.hpp | 7 +- engine/math/quat.hpp | 16 +- engine/math/range.hpp | 7 +- engine/math/transform.hpp | 71 ++++- engine/math/vec.hpp | 40 ++- engine/mesh/mesh_batch.cpp | 49 +-- engine/mesh/mesh_batch.hpp | 46 +-- engine/mesh/mesh_bucket.hpp | 7 +- engine/mesh/mesh_builder.cpp | 212 +++---------- engine/mesh/mesh_builder.hpp | 50 +-- engine/mesh/mesh_pass.cpp | 25 +- engine/mesh/mesh_pass.hpp | 52 +-- engine/mesh/mesh_processors.cpp | 3 - engine/mesh/mesh_processors.hpp | 7 +- engine/pfx/pfx_emitter.cpp | 2 +- engine/platform/application.cpp | 217 +++++++++++-- engine/platform/application.hpp | 59 +++- engine/platform/file_system.cpp | 2 +- engine/platform/file_system.hpp | 2 +- engine/platform/glfw/glfw_input.cpp | 2 +- engine/platform/glfw/glfw_input_devices.cpp | 2 +- engine/platform/glfw/glfw_window_manager.cpp | 31 +- engine/platform/glfw/glfw_window_manager.hpp | 9 +- .../scene_property.hpp => platform/time.cpp} | 78 +++-- .../pass_bloom.hpp => platform/time.hpp} | 53 ++-- engine/platform/window_manager.hpp | 13 +- engine/render/aux_draw_manager.cpp | 2 +- .../render/{render_camera.cpp => camera.cpp} | 81 ++--- .../render/{render_camera.hpp => camera.hpp} | 77 ++--- engine/render/canvas.cpp | 3 +- engine/render/deferred_pipeline.cpp | 52 +-- engine/render/deferred_pipeline.hpp | 13 - engine/render/geometry/pass_gbuffer.cpp | 70 ---- engine/render/graphics_pipeline.cpp | 194 ++---------- engine/render/graphics_pipeline.hpp | 144 +++------ .../{render_mesh_skinned.cpp => light.cpp} | 2 +- engine/render/light.hpp | 99 ++++++ .../model_instance.cpp} | 8 +- .../pass_gbuffer.hpp => model_instance.hpp} | 30 +- .../render/post_process/pass_autoexposure.cpp | 151 --------- engine/render/post_process/pass_bloom.cpp | 226 ------------- .../render/post_process/pass_composition.cpp | 115 ------- .../render/post_process/pass_composition.hpp | 60 ---- engine/render/post_process/pass_tonemap.cpp | 147 --------- engine/render/render_engine.cpp | 63 +--- engine/render/render_engine.hpp | 89 ++++-- engine/render/render_mesh_static.cpp | 124 -------- engine/render/render_queue.hpp | 6 +- engine/render/render_scene.cpp | 38 --- engine/render/render_scene.hpp | 21 +- engine/render/shader_builder.cpp | 2 +- engine/render/shader_manager.cpp | 2 +- engine/render/texture_compression.cpp | 42 +-- engine/render/texture_compression.hpp | 5 +- engine/render/texture_manager.cpp | 2 +- engine/render/vertex_factories.cpp | 84 ----- engine/render/vertex_factories.hpp | 67 ---- engine/render/vertex_factory.cpp | 67 ---- engine/render/vertex_factory.hpp | 97 ------ .../{render_mesh_skinned.hpp => view.cpp} | 18 +- engine/render/view.hpp | 32 ++ engine/render/view_manager.cpp | 32 ++ engine/render/view_manager.hpp | 32 ++ engine/render/visibility.cpp | 2 +- engine/render/visibility.hpp | 7 +- engine/resource/array_mesh.cpp | 220 +++++++++++++ engine/resource/array_mesh.hpp | 117 +++++++ engine/resource/audio_stream_wav.cpp | 2 +- engine/resource/config_file.cpp | 2 +- engine/resource/font.cpp | 22 +- engine/resource/font.hpp | 4 +- engine/resource/image.cpp | 19 +- engine/resource/image.hpp | 4 +- .../loaders/resource_loader_assimp.cpp | 56 ++-- .../loaders/resource_loader_assimp.hpp | 13 +- .../loaders/resource_loader_texture.cpp | 2 +- engine/resource/material.cpp | 60 +--- engine/resource/material.hpp | 10 +- engine/resource/mesh.cpp | 257 ++++++--------- engine/resource/mesh.hpp | 114 +++---- engine/resource/model.cpp | 40 ++- engine/resource/model.hpp | 54 ++-- engine/resource/paks/resource_pak_fs.cpp | 2 +- engine/resource/prefab.hpp | 8 +- engine/resource/register_classes_resource.cpp | 2 + engine/resource/register_classes_resource.hpp | 7 +- engine/resource/resource.cpp | 65 +++- engine/resource/resource.hpp | 48 ++- engine/resource/resource_manager.cpp | 13 +- engine/resource/resource_manager.hpp | 2 +- engine/resource/resource_ref.hpp | 40 ++- engine/resource/scene_packed.cpp | 2 +- engine/resource/scene_tree_packed.cpp | 3 +- engine/resource/script.cpp | 2 +- engine/resource/shader.cpp | 121 ++----- engine/resource/shader.hpp | 14 +- engine/resource/texture.cpp | 98 ++---- engine/resource/texture.hpp | 13 +- engine/scene/register_classes_scene.cpp | 9 +- engine/scene/register_classes_scene.hpp | 7 +- engine/scene/scene.cpp | 112 +------ engine/scene/scene.hpp | 169 ++-------- engine/scene/scene_camera.cpp | 215 ------------- engine/scene/scene_camera.hpp | 134 -------- engine/scene/scene_components.hpp | 124 +++++--- engine/scene/scene_data.cpp | 50 +++ .../scene_data.hpp} | 91 ++++-- .../scene_entity.cpp} | 25 +- .../scene_entity.hpp} | 74 +++-- engine/scene/scene_manager.cpp | 95 ++---- engine/scene/scene_manager.hpp | 14 +- engine/scene/scene_node.cpp | 251 ++++++++------- engine/scene/scene_node.hpp | 117 ++++--- engine/scene/scene_node_props.cpp | 44 +++ .../scene_node_props.hpp} | 47 +-- engine/scene/scene_properties.cpp | 99 ------ engine/scene/scene_properties.hpp | 106 ------- engine/scene/scene_systems.cpp | 32 ++ engine/scene/scene_systems.hpp | 32 ++ engine/scene/scene_transform.cpp | 169 ---------- engine/scene/scene_transform.hpp | 107 ------- engine/scene/scene_tree.cpp | 122 +------ engine/scene/scene_tree.hpp | 34 +- engine/scripting/lua/lua_script.cpp | 2 +- .../lua_bindings/lua_bindings_core.hpp | 2 +- .../lua_bindings/lua_bindings_event.hpp | 2 +- .../lua_bindings/lua_bindings_gameplay.hpp | 2 +- .../lua_bindings/lua_bindings_platform.hpp | 2 +- .../lua_bindings/lua_bindings_resource.hpp | 2 +- .../lua_bindings/lua_bindings_scene.hpp | 2 +- engine/shaders/brdf.glsl | 99 ++++++ engine/shaders/color.glsl | 5 +- engine/shaders/common_consts.glsl | 47 +++ engine/shaders/common_defines.glsl | 2 - engine/shaders/common_funcs.glsl | 41 +++ engine/shaders/deferred_shading.comp | 8 + engine/shaders/gbuffer.glsl | 57 ++++ .../generated/auto_base_gl410_frag.hpp | 70 +++- .../generated/auto_base_gl410_vert.hpp | 3 +- engine/shaders/generated/auto_base_pass.hpp | 2 +- .../generated/auto_base_reflection.hpp | 2 +- .../generated/auto_base_vk450_frag.hpp | 70 +++- .../generated/auto_base_vk450_vert.hpp | 3 +- .../generated/auto_bloom_gl410_comp.hpp | 70 +++- engine/shaders/generated/auto_bloom_pass.hpp | 2 +- .../generated/auto_bloom_reflection.hpp | 2 +- .../generated/auto_bloom_vk450_comp.hpp | 70 +++- .../generated/auto_canvas_gl410_frag.hpp | 70 +++- .../generated/auto_canvas_gl410_vert.hpp | 33 +- engine/shaders/generated/auto_canvas_pass.hpp | 2 +- .../generated/auto_canvas_reflection.hpp | 2 +- .../generated/auto_canvas_vk450_frag.hpp | 70 +++- .../generated/auto_canvas_vk450_vert.hpp | 33 +- .../generated/auto_composition_gl410_frag.hpp | 3 +- .../generated/auto_composition_gl410_vert.hpp | 33 +- .../generated/auto_composition_pass.hpp | 2 +- .../generated/auto_composition_reflection.hpp | 2 +- .../generated/auto_composition_vk450_frag.hpp | 3 +- .../generated/auto_composition_vk450_vert.hpp | 33 +- .../auto_luminance_avg_gl410_comp.hpp | 2 +- .../generated/auto_luminance_avg_pass.hpp | 2 +- .../auto_luminance_avg_reflection.hpp | 2 +- .../auto_luminance_avg_vk450_comp.hpp | 2 +- .../auto_luminance_histogram_gl410_comp.hpp | 72 ++++- .../auto_luminance_histogram_pass.hpp | 2 +- .../auto_luminance_histogram_reflection.hpp | 2 +- .../auto_luminance_histogram_vk450_comp.hpp | 72 ++++- .../generated/auto_material_gl410_frag.hpp | 182 +++++++++-- .../generated/auto_material_gl410_vert.hpp | 70 +++- .../shaders/generated/auto_material_pass.hpp | 2 +- .../generated/auto_material_reflection.hpp | 2 +- .../generated/auto_material_vk450_frag.hpp | 182 +++++++++-- .../generated/auto_material_vk450_vert.hpp | 70 +++- .../generated/auto_text_gl410_frag.hpp | 76 ++++- .../generated/auto_text_gl410_vert.hpp | 39 ++- engine/shaders/generated/auto_text_pass.hpp | 2 +- .../generated/auto_text_reflection.hpp | 8 +- .../generated/auto_text_vk450_frag.hpp | 76 ++++- .../generated/auto_text_vk450_vert.hpp | 39 ++- .../generated/auto_tonemap_gl410_comp.hpp | 70 +++- .../shaders/generated/auto_tonemap_pass.hpp | 2 +- .../generated/auto_tonemap_reflection.hpp | 2 +- .../generated/auto_tonemap_vk450_comp.hpp | 70 +++- engine/shaders/light.glsl | 12 + engine/shaders/light_grid.glsl | 69 ++++ engine/shaders/light_grid_build.hlsl | 58 ++++ engine/shaders/lighting.glsl | 80 +++++ engine/shaders/luminance_histogram.comp | 3 +- engine/shaders/material.frag | 29 +- engine/shaders/material_fs.glsl | 28 +- engine/shaders/math.glsl | 28 ++ engine/shaders/scripts/common.py | 73 +++++ engine/shaders/scripts/light_grid_build.py | 31 ++ engine/shaders/scripts/material.py | 43 +-- engine/shaders/scripts/text.py | 6 +- engine/shaders/surface.glsl | 32 ++ engine/system/engine.cpp | 242 ++++++++++++++ engine/{core => system}/engine.hpp | 38 +-- engine/systems/system_render.hpp | 118 ------- template/config/engine.cfg | 3 +- template/main.cpp | 48 +-- template/resources/shaders/test_shader.shader | 2 +- template/resources/textures/dirt_mask.res | 1 - 327 files changed, 7191 insertions(+), 6492 deletions(-) delete mode 100644 engine/core/engine.cpp create mode 100644 engine/core/ioc_container.cpp create mode 100644 engine/core/ioc_container.hpp create mode 100644 engine/core/pool_vector.hpp rename engine/{render/render_mesh_static.hpp => core/signal.hpp} (56%) delete mode 100644 engine/core/unrolled_list.hpp create mode 100644 engine/core/weak_ref.cpp create mode 100644 engine/core/weak_ref.hpp create mode 100644 engine/gfx/gfx_buffers.cpp create mode 100644 engine/gfx/gfx_pass.cpp rename engine/{render/post_process/pass_autoexposure.hpp => gfx/gfx_pass.hpp} (67%) create mode 100644 engine/hooks/hook_profiler.hpp create mode 100644 engine/io/serialization.hpp delete mode 100644 engine/main/main.cpp delete mode 100644 engine/main/main.hpp rename engine/{scene/scene_property.hpp => platform/time.cpp} (60%) rename engine/{render/post_process/pass_bloom.hpp => platform/time.hpp} (67%) rename engine/render/{render_camera.cpp => camera.cpp} (60%) rename engine/render/{render_camera.hpp => camera.hpp} (74%) delete mode 100644 engine/render/geometry/pass_gbuffer.cpp rename engine/render/{render_mesh_skinned.cpp => light.cpp} (98%) create mode 100644 engine/render/light.hpp rename engine/{scene/scene_property.cpp => render/model_instance.cpp} (93%) rename engine/render/{geometry/pass_gbuffer.hpp => model_instance.hpp} (79%) delete mode 100644 engine/render/post_process/pass_autoexposure.cpp delete mode 100644 engine/render/post_process/pass_bloom.cpp delete mode 100644 engine/render/post_process/pass_composition.cpp delete mode 100644 engine/render/post_process/pass_composition.hpp delete mode 100644 engine/render/post_process/pass_tonemap.cpp delete mode 100644 engine/render/render_mesh_static.cpp delete mode 100644 engine/render/vertex_factories.cpp delete mode 100644 engine/render/vertex_factories.hpp delete mode 100644 engine/render/vertex_factory.cpp delete mode 100644 engine/render/vertex_factory.hpp rename engine/render/{render_mesh_skinned.hpp => view.cpp} (85%) create mode 100644 engine/render/view.hpp create mode 100644 engine/render/view_manager.cpp create mode 100644 engine/render/view_manager.hpp create mode 100644 engine/resource/array_mesh.cpp create mode 100644 engine/resource/array_mesh.hpp delete mode 100644 engine/scene/scene_camera.cpp delete mode 100644 engine/scene/scene_camera.hpp create mode 100644 engine/scene/scene_data.cpp rename engine/{render/render_object.hpp => scene/scene_data.hpp} (53%) rename engine/{render/render_object.cpp => scene/scene_entity.cpp} (86%) rename engine/{systems/system_transform.hpp => scene/scene_entity.hpp} (60%) create mode 100644 engine/scene/scene_node_props.cpp rename engine/{render/post_process/pass_tonemap.hpp => scene/scene_node_props.hpp} (73%) delete mode 100644 engine/scene/scene_properties.cpp delete mode 100644 engine/scene/scene_properties.hpp create mode 100644 engine/scene/scene_systems.cpp create mode 100644 engine/scene/scene_systems.hpp delete mode 100644 engine/scene/scene_transform.cpp delete mode 100644 engine/scene/scene_transform.hpp create mode 100644 engine/shaders/brdf.glsl create mode 100644 engine/shaders/common_consts.glsl create mode 100644 engine/shaders/deferred_shading.comp create mode 100644 engine/shaders/gbuffer.glsl create mode 100644 engine/shaders/light.glsl create mode 100644 engine/shaders/light_grid.glsl create mode 100644 engine/shaders/light_grid_build.hlsl create mode 100644 engine/shaders/lighting.glsl create mode 100644 engine/shaders/math.glsl create mode 100644 engine/shaders/scripts/common.py create mode 100644 engine/shaders/scripts/light_grid_build.py create mode 100644 engine/shaders/surface.glsl create mode 100644 engine/system/engine.cpp rename engine/{core => system}/engine.hpp (83%) delete mode 100644 engine/systems/system_render.hpp diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 4159ba9be..41f6410a7 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -28,13 +28,13 @@ add_library(wmoge STATIC core/crc32.hpp core/data.cpp core/data.hpp - core/engine.cpp - core/engine.hpp core/fast_map.hpp core/fast_set.hpp core/fast_vector.hpp core/hook.cpp core/hook.hpp + core/ioc_container.cpp + core/ioc_container.hpp core/layer.cpp core/layer.hpp core/log.cpp @@ -42,10 +42,12 @@ add_library(wmoge STATIC core/mask.hpp core/object.cpp core/object.hpp + core/pool_vector.hpp core/random.cpp core/random.hpp core/ref.cpp core/ref.hpp + core/signal.hpp core/status.hpp core/string_id.cpp core/string_id.hpp @@ -67,11 +69,12 @@ add_library(wmoge STATIC core/timer.hpp core/typed_array.hpp core/typed_map.hpp - core/unrolled_list.hpp core/uuid.cpp core/uuid.hpp core/var.cpp core/var.hpp + core/weak_ref.cpp + core/weak_ref.hpp ecs/ecs_component.hpp ecs/ecs_core.cpp ecs/ecs_core.hpp @@ -110,6 +113,7 @@ add_library(wmoge STATIC gameplay/action_map.hpp gameplay/game_token_manager.cpp gameplay/game_token_manager.hpp + gfx/gfx_buffers.cpp gfx/gfx_buffers.hpp gfx/gfx_defs.hpp gfx/gfx_desc_set.cpp @@ -119,10 +123,12 @@ add_library(wmoge STATIC gfx/gfx_driver.hpp gfx/gfx_dynamic_buffers.cpp gfx/gfx_dynamic_buffers.hpp - gfx/gfx_pipeline.cpp - gfx/gfx_pipeline.hpp + gfx/gfx_pass.hpp + gfx/gfx_pass.cpp gfx/gfx_pipeline_cache.cpp gfx/gfx_pipeline_cache.hpp + gfx/gfx_pipeline.cpp + gfx/gfx_pipeline.hpp gfx/gfx_render_pass.cpp gfx/gfx_render_pass.hpp gfx/gfx_resource.hpp @@ -185,6 +191,7 @@ add_library(wmoge STATIC hgfx/hgfx_pass_text.hpp hooks/hook_config.hpp hooks/hook_logs.hpp + hooks/hook_profiler.hpp hooks/hook_root_remap.hpp hooks/hook_uuid_gen.hpp io/archive.cpp @@ -198,6 +205,7 @@ add_library(wmoge STATIC io/compression.cpp io/compression.hpp io/enum.hpp + io/serialization.hpp io/yaml.cpp io/yaml.hpp math/aabb.hpp @@ -249,6 +257,8 @@ add_library(wmoge STATIC platform/input.hpp platform/input_defs.hpp platform/input_devices.hpp + platform/time.cpp + platform/time.hpp platform/window.hpp platform/window_manager.hpp platform/glfw/glfw_input.cpp @@ -262,22 +272,20 @@ add_library(wmoge STATIC platform/glfw/glfw_window_manager.hpp render/aux_draw_manager.cpp render/aux_draw_manager.hpp + render/camera.cpp + render/camera.hpp render/canvas.cpp render/canvas.hpp render/deferred_pipeline.cpp render/deferred_pipeline.hpp render/graphics_pipeline.cpp render/graphics_pipeline.hpp - render/render_camera.cpp - render/render_camera.hpp + render/light.cpp + render/light.hpp + render/model_instance.cpp + render/model_instance.hpp render/render_engine.cpp render/render_engine.hpp - render/render_mesh_skinned.cpp - render/render_mesh_skinned.hpp - render/render_mesh_static.cpp - render/render_mesh_static.hpp - render/render_object.cpp - render/render_object.hpp render/render_queue.cpp render/render_queue.hpp render/render_scene.cpp @@ -292,22 +300,14 @@ add_library(wmoge STATIC render/texture_compression.hpp render/texture_manager.cpp render/texture_manager.hpp - render/vertex_factories.cpp - render/vertex_factories.hpp - render/vertex_factory.cpp - render/vertex_factory.hpp + render/view.cpp + render/view.hpp + render/view_manager.cpp + render/view_manager.hpp render/visibility.cpp render/visibility.hpp - render/geometry/pass_gbuffer.cpp - render/geometry/pass_gbuffer.hpp - render/post_process/pass_autoexposure.cpp - render/post_process/pass_autoexposure.hpp - render/post_process/pass_bloom.cpp - render/post_process/pass_bloom.hpp - render/post_process/pass_composition.cpp - render/post_process/pass_composition.hpp - render/post_process/pass_tonemap.cpp - render/post_process/pass_tonemap.hpp + resource/array_mesh.cpp + resource/array_mesh.hpp resource/audio_stream.cpp resource/audio_stream.hpp resource/audio_stream_wav.cpp @@ -363,24 +363,24 @@ add_library(wmoge STATIC resource/loaders/resource_loader_wav.hpp resource/paks/resource_pak_fs.cpp resource/paks/resource_pak_fs.hpp - scene/scene.cpp - scene/scene.hpp - scene/scene_camera.cpp - scene/scene_camera.hpp scene/scene_components.cpp scene/scene_components.hpp + scene/scene_data.cpp + scene/scene_data.hpp + scene/scene_entity.cpp + scene/scene_entity.hpp scene/scene_manager.cpp scene/scene_manager.hpp + scene/scene_node_props.cpp + scene/scene_node_props.hpp scene/scene_node.cpp scene/scene_node.hpp - scene/scene_properties.cpp - scene/scene_properties.hpp - scene/scene_property.cpp - scene/scene_property.hpp - scene/scene_transform.cpp - scene/scene_transform.hpp + scene/scene_systems.cpp + scene/scene_systems.hpp scene/scene_tree.cpp scene/scene_tree.hpp + scene/scene.cpp + scene/scene.hpp scene/register_classes_scene.cpp scene/register_classes_scene.hpp scripting/script_instance.hpp @@ -414,16 +414,14 @@ add_library(wmoge STATIC scripting/lua_bindings/lua_bindings_resource.hpp scripting/lua_bindings/lua_bindings_scene.cpp scripting/lua_bindings/lua_bindings_scene.hpp - systems/system_render.hpp - systems/system_transform.hpp + system/engine.cpp + system/engine.hpp debug/console.cpp debug/console.hpp debug/profiler.cpp debug/profiler.hpp debug/debug_layer.cpp - debug/debug_layer.hpp - main/main.cpp - main/main.hpp) + debug/debug_layer.hpp) # specify public include path, so user can reference engine files by modules names target_include_directories(wmoge PUBLIC ${CMAKE_CURRENT_LIST_DIR}/) diff --git a/engine/core/array_view.hpp b/engine/core/array_view.hpp index 4b962bc01..e427be8bf 100644 --- a/engine/core/array_view.hpp +++ b/engine/core/array_view.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ARRAY_VIEW_HPP -#define WMOGE_ARRAY_VIEW_HPP +#pragma once #include "svector.hpp" @@ -81,6 +80,4 @@ namespace wmoge { std::size_t m_size = 0; }; -}// namespace wmoge - -#endif//WMOGE_ARRAY_VIEW_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/async.hpp b/engine/core/async.hpp index fe1b169e1..474161b3b 100644 --- a/engine/core/async.hpp +++ b/engine/core/async.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ASYNC_HPP -#define WMOGE_ASYNC_HPP +#pragma once #include "core/array_view.hpp" #include "core/fast_vector.hpp" @@ -286,6 +285,4 @@ namespace wmoge { } }; -}// namespace wmoge - -#endif//WMOGE_ASYNC_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/callback_queue.hpp b/engine/core/callback_queue.hpp index 534bca24b..ff733df1a 100644 --- a/engine/core/callback_queue.hpp +++ b/engine/core/callback_queue.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_CALLBACK_QUEUE_HPP -#define WMOGE_CALLBACK_QUEUE_HPP +#pragma once #include "core/synchronization.hpp" @@ -74,6 +73,4 @@ namespace wmoge { m_queue.emplace_back(std::forward(callback)); } -}// namespace wmoge - -#endif//WMOGE_CALLBACK_QUEUE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/callback_stream.hpp b/engine/core/callback_stream.hpp index 9df10701f..af668e491 100644 --- a/engine/core/callback_stream.hpp +++ b/engine/core/callback_stream.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_CALLBACK_STREAM_HPP -#define WMOGE_CALLBACK_STREAM_HPP +#pragma once #include "core/synchronization.hpp" @@ -92,6 +91,4 @@ namespace wmoge { wait(); } -}// namespace wmoge - -#endif//WMOGE_CALLBACK_STREAM_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/class.cpp b/engine/core/class.cpp index cb287ae1a..5998557cc 100644 --- a/engine/core/class.cpp +++ b/engine/core/class.cpp @@ -29,11 +29,6 @@ #include "core/object.hpp" -#include "event/register_classes_event.hpp" -#include "pfx/register_classes_pfx.hpp" -#include "resource/register_classes_resource.hpp" -#include "scene/register_classes_scene.hpp" - namespace wmoge { ClassMember::ClassMember(StringId name) @@ -55,6 +50,24 @@ namespace wmoge { return m_callable(*this, object, argc, argv, ret); } + Class* ClassDB::class_emplace(StringId name) { + Class* ptr = class_ptr(name); + if (!ptr) { + auto& storage = m_db[name]; + storage = std::make_unique(); + ptr = storage.get(); + } + return ptr; + } + Class* ClassDB::class_ptr(StringId name) { + auto query = m_db.find(name); + return query != m_db.end() ? query->second.get() : nullptr; + } + ClassDB* ClassDB::instance() { + static ClassDB g_class_db; + return &g_class_db; + } + const Class* Class::super() const { return class_ptr(super_name()); } @@ -95,9 +108,8 @@ namespace wmoge { } Class* Class::class_ptr(StringId name) { - ClassDB* db = class_db(); - auto query = db->find(name); - return query != db->end() ? query->second.get() : nullptr; + ClassDB* db = class_db(); + return db->class_ptr(name); } Class* Class::register_class(const StringId& name, const StringId& super, std::size_t size, std::function instantiate) { if (!class_ptr(super)) { @@ -108,10 +120,9 @@ namespace wmoge { WG_LOG_ERROR("class: " << name << " already registered"); return cls; } - ClassDB& db = *class_db(); - db[name] = std::make_unique(); - Class* cls = db[name].get(); - Class* super_cls = db[super].get(); + ClassDB* db = class_db(); + Class* cls = db->class_emplace(name); + Class* super_cls = db->class_ptr(super); cls->m_name = name; cls->m_super_name = super; cls->m_size = size; @@ -125,8 +136,7 @@ namespace wmoge { return cls; } ClassDB* Class::class_db() { - static ClassDB classDb; - return &classDb; + return ClassDB::instance(); } Class* Class::add_property(ClassProperty property) { @@ -137,21 +147,13 @@ namespace wmoge { } void Class::register_types() { - ClassDB& db = *class_db(); - db[Object::class_name_static()] = std::make_unique(); - Class* cls = db[Object::class_name_static()].get(); - + Class* cls = class_db()->class_emplace(Object::class_name_static()); cls->m_name = SID("Object"); cls->m_size = sizeof(Object); cls->m_instantiate = []() { return new Object(); }; cls->m_supers.emplace(Object::class_name_static()); cls->add_method(ClassMethod(VarType::Int, SID("hash"), {}), &Object::hash, {}); cls->add_method(ClassMethod(VarType::String, SID("to_string"), {}), &Object::to_string, {}); - - register_classes_event(); - register_classes_resource(); - register_classes_pfx(); - register_classes_scene(); } }// namespace wmoge diff --git a/engine/core/class.hpp b/engine/core/class.hpp index 47c99c398..cfa5779f0 100644 --- a/engine/core/class.hpp +++ b/engine/core/class.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_CLASS_HPP -#define WMOGE_CLASS_HPP +#pragma once #include "core/log.hpp" #include "core/ref.hpp" @@ -143,9 +142,18 @@ namespace wmoge { }; /** + * @class ClassDB * @brief Stores information about all registered engine object classes */ - using ClassDB = std::unordered_map>; + class ClassDB final { + public: + class Class* class_emplace(StringId name); + class Class* class_ptr(StringId name); + static ClassDB* instance(); + + private: + std::unordered_map> m_db; + }; /** * @class Class @@ -188,8 +196,6 @@ namespace wmoge { Class* add_property(ClassProperty property); - private: - friend class Main; static void register_types(); private: @@ -366,6 +372,4 @@ namespace wmoge { return this; } -}// namespace wmoge - -#endif//WMOGE_CLASS_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/cmd_line.hpp b/engine/core/cmd_line.hpp index cbaab2324..11658051e 100644 --- a/engine/core/cmd_line.hpp +++ b/engine/core/cmd_line.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_CMD_LINE_HPP -#define WMOGE_CMD_LINE_HPP +#pragma once #include @@ -57,6 +56,4 @@ namespace wmoge { cxxopts::ParseResult m_parsed; }; -}// namespace wmoge - -#endif//WMOGE_CMD_LINE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/crc32.cpp b/engine/core/crc32.cpp index a99d20380..bae50b030 100644 --- a/engine/core/crc32.cpp +++ b/engine/core/crc32.cpp @@ -116,4 +116,13 @@ namespace wmoge { return crc ^ 0xFFFFFFFF; } + Crc32Builder& Crc32Builder::hash(const void* buffer, std::size_t size) { + m_hash ^= Crc32::hash(buffer, size); + return *this; + } + + Crc32Hash Crc32Builder::get() const { + return m_hash; + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/core/crc32.hpp b/engine/core/crc32.hpp index e8488b2b3..f7ab9c948 100644 --- a/engine/core/crc32.hpp +++ b/engine/core/crc32.hpp @@ -25,25 +25,39 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_CRC32_HPP -#define WMOGE_CRC32_HPP +#pragma once #include namespace wmoge { - /** @brief Crc hash type */ + /** + * @brief Crc hash type + */ using Crc32Hash = unsigned int; /** * @class Crc32 * @brief Utility for crc32 hashing - */ + */ class Crc32 { public: static Crc32Hash hash(const void* buffer, std::size_t size); }; -}// namespace wmoge + /** + * @class Crc32Builder + * @brief Utility to build crc32 hash for complex objects + */ + class Crc32Builder { + public: + Crc32Builder() = default; -#endif//WMOGE_CRC32_HPP + Crc32Builder& hash(const void* buffer, std::size_t size); + Crc32Hash get() const; + + private: + Crc32Hash m_hash; + }; + +}// namespace wmoge diff --git a/engine/core/data.hpp b/engine/core/data.hpp index 648e16eda..174789714 100644 --- a/engine/core/data.hpp +++ b/engine/core/data.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_DATA_HPP -#define WMOGE_DATA_HPP +#pragma once #include "core/ref.hpp" #include "io/archive.hpp" @@ -79,6 +78,4 @@ namespace wmoge { std::uint8_t* m_buffer = nullptr; }; -}// namespace wmoge - -#endif//WMOGE_DATA_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/engine.cpp b/engine/core/engine.cpp deleted file mode 100644 index 292ee8fac..000000000 --- a/engine/core/engine.cpp +++ /dev/null @@ -1,162 +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. */ -/**********************************************************************************/ - -#include "engine.hpp" - -#include - -namespace wmoge { - - void Engine::request_close() { - m_close_requested.store(true); - } - bool Engine::close_requested() const { - return m_close_requested.load(); - } - - class Application* Engine::application() { - return m_application; - } - LayerStack* Engine::layer_stack() { - return m_layer_stack; - } - HookList* Engine::hook_list() { - return m_hook_list; - } - CmdLine* Engine::cmd_line() { - return m_cmd_line; - } - ConfigFile* Engine::config() { - return m_config; - } - CallbackQueue* Engine::main_queue() { - return m_main_queue; - } - FileSystem* Engine::file_system() { - return m_file_system; - } - TaskManager* Engine::task_manager() { - return m_task_manager; - } - EventManager* Engine::event_manager() { - return m_event_manager; - } - ResourceManager* Engine::resource_manager() { - return m_resource_manager; - } - WindowManager* Engine::window_manager() { - return m_window_manager; - } - Input* Engine::input() { - return m_input; - } - GfxDriver* Engine::gfx_driver() { - return m_gfx_driver; - } - GfxCtx* Engine::gfx_ctx() { - return m_gfx_ctx; - } - ShaderManager* Engine::shader_manager() { - return m_shader_manager; - } - TextureManager* Engine::texture_manager() { - return m_texture_manager; - } - AuxDrawManager* Engine::aux_draw_manager() { - return m_aux_draw_manager; - } - SceneManager* Engine::scene_manager() { - return m_scene_manager; - } - ActionManager* Engine::action_manager() { - return m_action_manager; - } - GameTokenManager* Engine::game_token_manager() { - return m_game_token_manager; - } - Profiler* Engine::profiler() { - return m_profiler; - } - Console* Engine::console() { - return m_console; - } - Canvas* Engine::canvas_debug() { - return m_canvas_debug; - } - ScriptSystem* Engine::script_system() { - return m_script_system; - } - AudioEngine* Engine::audio_engine() { - return m_audio_engine; - } - class RenderEngine* Engine::render_engine() { - return m_render_engine; - } - class EcsRegistry* Engine::ecs_registry() { - return m_ecs_registry; - } - - Engine* Engine::instance() { - static auto g_engine = std::make_unique(); - return g_engine.get(); - } - - std::chrono::steady_clock::time_point Engine::get_start() { - return m_start; - } - std::time_t Engine::get_time() { - return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - } - std::tm Engine::get_tm(std::time_t time) { - std::tm tm; -#if defined(TARGET_WINDOWS) - localtime_s(&tm, &time); -#else - localtime_r(&time, &tm); -#endif - return tm; - } - std::string Engine::get_time_formatted(const char* format, std::time_t time) { - char buffer[128]; - std::tm tm = get_tm(time); - strftime(buffer, 128, format, &tm); - return buffer; - } - std::size_t Engine::get_iteration() { - return m_iteration; - } - float Engine::get_time() const { - return m_time; - } - float Engine::get_delta_time() const { - return m_current_delta; - } - float Engine::get_delta_time_game() const { - return m_current_delta_game; - } - -}// namespace wmoge \ No newline at end of file diff --git a/engine/core/fast_map.hpp b/engine/core/fast_map.hpp index 3bb01ca99..bfbb9c938 100644 --- a/engine/core/fast_map.hpp +++ b/engine/core/fast_map.hpp @@ -25,10 +25,10 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_FAST_MAP_HPP -#define WMOGE_FAST_MAP_HPP +#pragma once #include "io/archive.hpp" +#include "io/yaml.hpp" #include #include @@ -68,8 +68,29 @@ namespace wmoge { } return StatusCode::Ok; } -#endif -}// namespace wmoge + template + Status yaml_read(const YamlConstNodeRef& node, fast_map& map) { + assert(map.empty()); + map.reserve(node.num_children()); + for (auto child = node.first_child(); child.valid(); child = child.next_sibling()) { + robin_hood::pair entry; + WG_YAML_READ(child, entry); + map.insert(std::move(entry)); + } + return StatusCode::Ok; + } + + template + Status yaml_write(YamlNodeRef node, const fast_map& map) { + WG_YAML_SEQ(node); + for (const auto& entry : map) { + YamlNodeRef entry_child = node.append_child(); + WG_YAML_WRITE(entry_child, entry); + } + return StatusCode::Ok; + } + +#endif -#endif//WMOGE_FAST_MAP_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/fast_set.hpp b/engine/core/fast_set.hpp index db5eb636d..0af25bac8 100644 --- a/engine/core/fast_set.hpp +++ b/engine/core/fast_set.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_FAST_SET_HPP -#define WMOGE_FAST_SET_HPP +#pragma once #include "io/archive.hpp" @@ -68,6 +67,4 @@ namespace wmoge { } #endif -}// namespace wmoge - -#endif//WMOGE_FAST_SET_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/fast_vector.hpp b/engine/core/fast_vector.hpp index ee8caff3b..51b95409f 100644 --- a/engine/core/fast_vector.hpp +++ b/engine/core/fast_vector.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_FAST_VECTOR_HPP -#define WMOGE_FAST_VECTOR_HPP +#pragma once #include "io/archive.hpp" #include "io/yaml.hpp" @@ -90,6 +89,4 @@ namespace wmoge { } #endif -}// namespace wmoge - -#endif//WMOGE_FAST_VECTOR_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/hook.hpp b/engine/core/hook.hpp index 1fbe66852..de98a1e75 100644 --- a/engine/core/hook.hpp +++ b/engine/core/hook.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_HOOK_HPP -#define WMOGE_HOOK_HPP +#pragma once #include "core/cmd_line.hpp" #include "core/status.hpp" @@ -48,7 +47,7 @@ namespace wmoge { virtual std::string get_name() const { return ""; } virtual void on_attach() {} virtual void on_add_cmd_line_options(CmdLine& cmd_line) {} - virtual Status on_process(CmdLine& cmd_line, class Engine& engine) { return StatusCode::Ok; } + virtual Status on_process(CmdLine& cmd_line) { return StatusCode::Ok; } }; /** @@ -83,6 +82,4 @@ namespace wmoge { } } -}// namespace wmoge - -#endif//WMOGE_HOOK_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/ioc_container.cpp b/engine/core/ioc_container.cpp new file mode 100644 index 000000000..3545fcb98 --- /dev/null +++ b/engine/core/ioc_container.cpp @@ -0,0 +1,71 @@ +/**********************************************************************************/ +/* 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 "ioc_container.hpp" + +namespace wmoge { + + void IocContainer::clear() { + m_entries.clear(); + } + + void IocContainer::add(IocEntry&& entry) { + auto query = m_entries.find(entry.source_type.value()); + + if (query != m_entries.end()) { + WG_LOG_ERROR("attempt to re-bind type " << entry.source_type.value().name() + << " with " << entry.provided_type.value().name()); + return; + } + + WG_LOG_INFO("bind '" << entry.source_type.value().name() << "'"); + m_entries[entry.source_type.value()] = std::move(entry); + } + + void IocContainer::erase(std::type_index entry_type) { + auto iter = m_entries.find(entry_type); + if (iter != m_entries.end()) { + m_entries.erase(iter); + } + } + + std::optional IocContainer::get(std::type_index entry_type) { + auto query = m_entries.find(entry_type); + + if (query != m_entries.end()) { + return std::optional(&(query->second)); + } + + return std::nullopt; + } + + IocContainer* IocContainer::instance() { + static IocContainer instance; + return &instance; + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/ioc_container.hpp b/engine/core/ioc_container.hpp new file mode 100644 index 000000000..e3eb00f9a --- /dev/null +++ b/engine/core/ioc_container.hpp @@ -0,0 +1,192 @@ +/**********************************************************************************/ +/* 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/log.hpp" +#include "core/status.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace wmoge { + + /** + * @brief Life-time type of ioc entry + */ + enum class IocEntryType { + Singleton = 0 + }; + + /** + * @class IocEntry + * @brief Stores information about managed entry in IoC container + */ + struct IocEntry { + std::any instance; + std::function factory; + std::optional provided_type; + std::optional source_type; + IocEntryType type = IocEntryType::Singleton; + }; + + /** + * @class IocContainer + * @brief Inversion of control container for simpler dependency injection of global engine managers + * + * IoC container allows to store and access singletons and factories for any kind of objects. + */ + class IocContainer { + public: + IocContainer() = default; + IocContainer(const IocContainer&) = delete; + IocContainer(IocContainer&&) noexcept = delete; + + void clear(); + void add(IocEntry&& entry); + void erase(std::type_index entry_type); + std::optional get(std::type_index entry_type); + + template + void bind_f(Factory&& factory); + + template + void bind_i(std::shared_ptr instance); + + template + void bind(); + + template + void bind_alias(); + + template + void unbind(); + + template + std::optional resolve(); + + static IocContainer* instance(); + + private: + std::unordered_map m_entries; + }; + + template + inline void IocContainer::bind_f(Factory&& factory) { + IocEntry entry; + entry.source_type = typeid(S); + entry.provided_type = typeid(T); + entry.factory = [f = std::move(factory)](std::any& out) -> Status { + out = std::move(f()); + return StatusCode::Ok; + }; + + add(std::move(entry)); + } + + template + inline void IocContainer::bind_i(std::shared_ptr instance) { + bind_f([i = std::move(instance)]() { + return i; + }); + } + + template + inline void IocContainer::bind() { + bind_f([]() { + return std::make_shared(); + }); + } + + template + inline void IocContainer::bind_alias() { + bind_f([]() { + auto instance = resolve(); + if (!instance.has_value()) { + WG_LOG_ERROR("no such entry to alias with type " << std::type_index(typeid(T)).name()); + return std::shared_ptr(); + } + auto opt_entry = get(typeid(S)); + IocEntry& entry = *(opt_entry.value()); + return entry.instance; + }); + } + + template + inline void IocContainer::unbind() { + erase(typeid(S)); + } + + template + inline std::optional IocContainer::resolve() { + auto opt_entry = get(typeid(S)); + + if (!opt_entry) { + WG_LOG_ERROR("no such entry to resolve with type " << std::type_index(typeid(S)).name()); + return std::nullopt; + } + + IocEntry& entry = *(opt_entry.value()); + + if (entry.type != IocEntryType::Singleton) { + WG_LOG_ERROR("non-singleton entry not supported for type " << std::type_index(typeid(S)).name()); + return std::nullopt; + } + + if (!entry.instance.has_value()) { + auto status = entry.factory(entry.instance); + if (!status) { + WG_LOG_ERROR("failed to instantiate object of type " << entry.provided_type.value().name()); + return std::nullopt; + } + } + + S* ptr = nullptr; + + try { + ptr = std::any_cast>(entry.instance).get(); + } catch (const std::bad_any_cast&) { + WG_LOG_ERROR("failed to cast entry to type " << std::type_index(typeid(S)).name() + << " from type " << entry.provided_type.value().name()); + assert(false); + } + + if (!ptr) { + WG_LOG_ERROR("instance is null " << std::type_index(typeid(S)).name()); + return std::nullopt; + } + + return ptr; + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/layer.hpp b/engine/core/layer.hpp index 9c9d189d0..b0711bcfa 100644 --- a/engine/core/layer.hpp +++ b/engine/core/layer.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_LAYER_HPP -#define WMOGE_LAYER_HPP +#pragma once #include "core/array_view.hpp" @@ -45,6 +44,7 @@ namespace wmoge { virtual void on_attach() {} virtual void on_start_frame() {} + virtual void on_iter() {} virtual void on_debug_draw() {} virtual void on_end_frame() {} }; @@ -94,6 +94,4 @@ namespace wmoge { } } -}// namespace wmoge - -#endif//WMOGE_LAYER_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/log.cpp b/engine/core/log.cpp index 8ee65fb6a..57b1e4234 100644 --- a/engine/core/log.cpp +++ b/engine/core/log.cpp @@ -27,11 +27,12 @@ #include "log.hpp" -#include - -#include "core/engine.hpp" #include "debug/console.hpp" #include "platform/file_system.hpp" +#include "platform/time.hpp" +#include "system/engine.hpp" + +#include #include #include @@ -88,13 +89,14 @@ namespace wmoge { : m_name(std::move(name)), m_level(level) { Engine* engine = Engine::instance(); FileSystem* file_system = engine->file_system(); + Time* engine_time = engine->time(); - std::time_t time = engine->get_time(); + std::time_t time = engine_time->get_time(); std::stringstream log_file_name; log_file_name << "logs://log_" << m_name << " " - << engine->get_time_formatted("%Y-%m-%d %H-%M-%S", time) + << engine_time->get_time_formatted("%Y-%m-%d %H-%M-%S", time) << ".log"; file_system->open_file(log_file_name.str(), m_stream, std::ios::out); diff --git a/engine/core/log.hpp b/engine/core/log.hpp index 2d8e114a2..4dd6ca3c4 100644 --- a/engine/core/log.hpp +++ b/engine/core/log.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_LOG_HPP -#define WMOGE_LOG_HPP +#pragma once #include #include @@ -133,8 +132,6 @@ namespace wmoge { LogLevel m_level; }; -}// namespace wmoge - #define WG_LOG_MESSAGE(level, message) \ do { \ std::stringstream __ss; \ @@ -146,4 +143,4 @@ namespace wmoge { #define WG_LOG_WARNING(message) WG_LOG_MESSAGE(::wmoge::LogLevel::Warning, message) #define WG_LOG_ERROR(message) WG_LOG_MESSAGE(::wmoge::LogLevel::Error, message) -#endif//WMOGE_LOG_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/mask.hpp b/engine/core/mask.hpp index 0a3a76bea..1b916931c 100644 --- a/engine/core/mask.hpp +++ b/engine/core/mask.hpp @@ -25,9 +25,10 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MASK_HPP -#define WMOGE_MASK_HPP +#pragma once +#include "core/fast_vector.hpp" +#include "io/archive.hpp" #include "io/yaml.hpp" #include @@ -55,8 +56,8 @@ namespace wmoge { for (auto e : elements) set(e); } - Mask operator&(const Mask& other) { return Mask(bits & other.bits); } - Mask operator|(const Mask& other) { return Mask(bits | other.bits); } + Mask operator&(const Mask& other) const { return Mask(bits & other.bits); } + Mask operator|(const Mask& other) const { return Mask(bits | other.bits); } Mask& operator&=(const Mask& other) { bits &= other.bits; @@ -91,7 +92,7 @@ namespace wmoge { template Status yaml_read(const YamlConstNodeRef& node, Mask& mask) { - std::vector flags; + fast_vector flags; WG_YAML_READ(node, flags); for (auto flag : flags) { @@ -103,7 +104,7 @@ namespace wmoge { template Status yaml_write(YamlNodeRef node, const Mask& mask) { - std::vector flags; + fast_vector flags; mask.for_each([&](int, T flag) { flags.push_back(flag); @@ -113,6 +114,14 @@ namespace wmoge { return StatusCode::Ok; } -}// namespace wmoge + template + Status archive_read(Archive& archive, Mask& mask) { + return archive.nread(sizeof(Mask), &mask); + } + + template + Status archive_write(Archive& archive, const Mask& mask) { + return archive.nwrite(sizeof(Mask), &mask); + } -#endif//WMOGE_MASK_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/object.cpp b/engine/core/object.cpp index 597f698aa..221bfae1a 100644 --- a/engine/core/object.cpp +++ b/engine/core/object.cpp @@ -147,11 +147,37 @@ namespace wmoge { } Status yaml_write_object(YamlNodeRef node, const Ref& object) { assert(object); - WG_YAML_MAP(node); WG_YAML_WRITE_AS(node, "class", object->class_name()); - return object->write_to_yaml(node); } + Status archive_read_object(Archive& archive, Ref& object) { + assert(!object); + + StringId class_name; + WG_ARCHIVE_READ(archive, class_name); + + auto* cls = Class::class_ptr(class_name); + + if (!cls) { + WG_LOG_ERROR("no such class to read from archive " << class_name); + return StatusCode::NoClass; + } + + object = cls->instantiate(); + + if (!object) { + WG_LOG_ERROR("failed to instantiate class " << class_name); + return StatusCode::FailedInstantiate; + } + + return object->read_from_archive(archive); + } + Status archive_write_object(Archive& archive, const Ref& object) { + assert(object); + WG_ARCHIVE_WRITE(archive, object->class_name()); + return object->write_to_archive(archive); + } + }// namespace wmoge diff --git a/engine/core/object.hpp b/engine/core/object.hpp index 346f67706..d8cfe00d3 100644 --- a/engine/core/object.hpp +++ b/engine/core/object.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_OBJECT_HPP -#define WMOGE_OBJECT_HPP +#pragma once #include "core/ref.hpp" #include "core/status.hpp" @@ -49,14 +48,14 @@ namespace wmoge { * @brief Base class for any scene tree object or resource with reflection support * * Object is a thin as possible class which comes with only thread-safe reference - * counting and single virtual table pointer overhead. The object provides and interface + * counting and single virtual table pointer overhead. The object provides an interface * for common methods, which may be required to manipulate objects and write generalized * runtime code. * * The main feature of the object is the runtime type information support (or reflection). * It is possible to get object class, query its inheritance tree, get all methods, * properties and fields. Object can be used for more simple automated serialization - * and deserialization, viewing in structure in the inspector and so on. + * and deserialization, viewing its structure in the inspector and so on. */ class Object : public RefCnt { public: @@ -72,6 +71,8 @@ namespace wmoge { virtual Status copy_to(Object& other) const { return StatusCode::Ok; } virtual Status read_from_yaml(const YamlConstNodeRef& node) { return StatusCode::NotImplemented; } virtual Status write_to_yaml(YamlNodeRef node) const { return StatusCode::NotImplemented; } + virtual Status read_from_archive(Archive& archive) { return StatusCode::NotImplemented; } + virtual Status write_to_archive(Archive& archive) const { return StatusCode::NotImplemented; } virtual Status clone(Ref& object) const; virtual Ref duplicate() const; @@ -86,6 +87,9 @@ namespace wmoge { friend Status yaml_read_object(const YamlConstNodeRef& node, Ref& object); friend Status yaml_write_object(YamlNodeRef node, const Ref& object); + + friend Status archive_read_object(Archive& archive, Ref& object); + friend Status archive_write_object(Archive& archive, const Ref& object); }; template @@ -120,7 +124,7 @@ namespace wmoge { return {}; } - return result; + return std::move(result); } template @@ -154,7 +158,36 @@ namespace wmoge { return StatusCode::Ok; } -}// namespace wmoge + template + Status archive_read(Archive& archive, Ref& ref, typename std::enable_if_t>* = 0) { + Ref object; + auto status = archive_read_object(archive, object); + if (!status) return status; + ref = object.template cast(); + return StatusCode::Ok; + } + + template + Status archive_read(Archive& archive, Ref& ref, typename std::enable_if_t>* = 0) { + ref = make_ref(); + WG_ARCHIVE_READ(archive, *ref); + return StatusCode::Ok; + } + + template + Status archive_write(Archive& archive, const Ref& ref, typename std::enable_if_t>* = 0) { + Ref object = ref.template as(); + auto status = archive_write_object(archive, object); + if (!status) return status; + return StatusCode::Ok; + } + + template + Status archive_write(Archive& archive, const Ref& ref, typename std::enable_if_t>* = 0) { + assert(ref); + WG_ARCHIVE_WRITE(archive, *ref); + return StatusCode::Ok; + } #define WG_OBJECT(name, super) \ public: \ @@ -177,4 +210,4 @@ public: return super::class_name_static(); \ } -#endif//WMOGE_OBJECT_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/pool_vector.hpp b/engine/core/pool_vector.hpp new file mode 100644 index 000000000..01a593ef3 --- /dev/null +++ b/engine/core/pool_vector.hpp @@ -0,0 +1,227 @@ +/**********************************************************************************/ +/* 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/fast_vector.hpp" +#include "io/yaml.hpp" + +#include +#include +#include +#include +#include + +namespace wmoge { + + /** + * @class PoolVector + * @brief Typed container as well as vector but values stored in chunks with persistent mem address in grow operation + */ + template + class PoolVector { + public: + static constexpr std::size_t NODE_CAPACITY = NodeCapacity; + + PoolVector() = default; + + PoolVector(const PoolVector& other) { + reserve(other.size()); + for (const auto& value : other) { + emplace_back(value); + } + } + + PoolVector(PoolVector&& other) { + m_nodes = std::move(other.m_nodes); + m_size = other.m_size; + other.m_size = 0; + } + + ~PoolVector(); + + template + T& emplace_back(TArgs&&... args); + void push_back(const T& element); + void push_back(T&& element); + void clear(); + void reserve(std::size_t size); + + T& operator[](std::size_t i); + const T& operator[](std::size_t i) const; + + [[nodiscard]] std::size_t size() const { return m_size; } + [[nodiscard]] std::size_t capacity() const { return m_nodes.size() * NODE_CAPACITY; } + [[nodiscard]] bool is_empty() const { return m_size == 0; } + + struct Item { + std::uint8_t mem[sizeof(T)]; + }; + + template + struct Node { + std::array items; + }; + + template + using NodePtr = std::unique_ptr>; + + template + class Iterator { + public: + Iterator(NodePtr* nodes, std::size_t i) { + m_nodes = nodes; + m_i = i; + }; + + bool operator==(const Iterator& other) const { + return m_i == other.m_i; + } + bool operator!=(const Iterator& other) const { + return m_i != other.m_i; + } + IterType& operator*() { + return (IterType*) m_nodes[m_i / NODE_CAPACITY]->items[m_i % NODE_CAPACITY].mem; + } + void operator++() { + m_i += 1; + } + + private: + NodePtr* m_nodes = nullptr; + std::size_t m_i = 0; + }; + + using iterator = Iterator; + using const_iterator = Iterator; + + iterator begin() { return iterator(m_nodes.data(), 0); } + iterator end() { return iterator(m_nodes.data(), m_size); } + const_iterator begin() const { return iterator(m_nodes.data(), 0); } + const_iterator end() const { return iterator(m_nodes.data(), m_size); } + + private: + void* allocate_back(); + + private: + fast_vector> m_nodes; + std::size_t m_size = 0; + }; + + template + inline PoolVector::~PoolVector() { + clear(); + } + + template + template + inline T& PoolVector::emplace_back(TArgs&&... args) { + void* mem = allocate_back(); + return *(new (mem) T(std::forward(args...))); + } + + template + inline void PoolVector::push_back(const T& element) { + void* mem = allocate_back(); + new (mem) T(element); + } + + template + inline void PoolVector::push_back(T&& element) { + void* mem = allocate_back(); + new (mem) T(std::move(element)); + } + + template + inline void PoolVector::clear() { + for (std::size_t i = 0; i < m_size; i++) { + std::size_t node_idx = i / NODE_CAPACITY; + std::size_t item_idx = i % NODE_CAPACITY; + ((T*) (m_nodes[node_idx]->items[item_idx].mem))->~T(); + } + + m_nodes.clear(); + m_size = 0; + } + + template + inline void PoolVector::reserve(std::size_t size) { + if (m_size >= size) { + return; + } + + const std::size_t required_nodes_count = (size + NODE_CAPACITY - 1) / NODE_CAPACITY; + m_nodes.reserve(required_nodes_count); + } + + template + inline T& PoolVector::operator[](std::size_t i) { + std::size_t node_idx = m_size / NODE_CAPACITY; + std::size_t item_idx = m_size % NODE_CAPACITY; + return m_nodes[node_idx]->items[item_idx].mem; + } + + template + inline const T& PoolVector::operator[](std::size_t i) const { + std::size_t node_idx = m_size / NODE_CAPACITY; + std::size_t item_idx = m_size % NODE_CAPACITY; + return m_nodes[node_idx]->items[item_idx].mem; + } + + template + inline void* PoolVector::allocate_back() { + if (capacity() == size()) { + m_nodes.push_back(std::make_unique>()); + } + std::size_t node_idx = m_size / NODE_CAPACITY; + std::size_t item_idx = m_size % NODE_CAPACITY; + m_size += 1; + return m_nodes[node_idx]->items[item_idx].mem; + } + + template + Status yaml_read(const YamlConstNodeRef& node, PoolVector& vec) { + vec.reserve(node.num_children()); + for (auto child = node.first_child(); child.valid(); child = child.next_sibling()) { + T element; + WG_YAML_READ(child, element); + vec.push_back(std::move(element)); + } + return StatusCode::Ok; + } + + template + Status yaml_write(YamlNodeRef node, const PoolVector& vec) { + WG_YAML_SEQ(node); + for (const T& value : vec) { + YamlNodeRef child = node.append_child(); + WG_YAML_WRITE(child, value); + } + return StatusCode::Ok; + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/random.hpp b/engine/core/random.hpp index 6870052ae..09977c0b9 100644 --- a/engine/core/random.hpp +++ b/engine/core/random.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_RANDOM_HPP -#define WMOGE_RANDOM_HPP +#pragma once #include #include @@ -46,6 +45,4 @@ namespace wmoge { static float next_float(float left, float right); }; -}// namespace wmoge - -#endif//WMOGE_RANDOM_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/ref.cpp b/engine/core/ref.cpp index 903c99fbf..3d49e4f45 100644 --- a/engine/core/ref.cpp +++ b/engine/core/ref.cpp @@ -26,6 +26,7 @@ /**********************************************************************************/ #include "core/ref.hpp" +#include "ref.hpp" namespace wmoge { @@ -44,8 +45,7 @@ namespace wmoge { if (refs == 1) { // Was last reference - // Destroy object and release memory - destroy(); + reach_zero(); } return refs; @@ -59,4 +59,9 @@ namespace wmoge { delete this; } -}// namespace wmoge \ No newline at end of file + void RefCnt::reach_zero() { + // Destroy object and release memory + destroy(); + } + +}// namespace wmoge diff --git a/engine/core/ref.hpp b/engine/core/ref.hpp index 1a21db2ba..6255c041a 100644 --- a/engine/core/ref.hpp +++ b/engine/core/ref.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_REF_HPP -#define WMOGE_REF_HPP +#pragma once #include #include @@ -39,6 +38,8 @@ namespace wmoge { /** * @class RefCnt * @brief Base class for any atomic reference counted class + * + * @note Thread-safe */ class RefCnt { public: @@ -50,6 +51,7 @@ namespace wmoge { protected: virtual void destroy(); + virtual void reach_zero(); private: std::atomic_uint m_refs_count{0}; @@ -68,7 +70,7 @@ namespace wmoge { /** * @class Ref - * @brief Smart reference-counted pointer to T class + * @brief Smart shared reference-counted pointer to T class */ template class Ref { @@ -188,6 +190,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_REF_HPP +}// namespace std \ No newline at end of file diff --git a/engine/render/render_mesh_static.hpp b/engine/core/signal.hpp similarity index 56% rename from engine/render/render_mesh_static.hpp rename to engine/core/signal.hpp index 58d84166b..e3f22d489 100644 --- a/engine/render/render_mesh_static.hpp +++ b/engine/core/signal.hpp @@ -25,54 +25,76 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_RENDER_MESH_STATIC_HPP -#define WMOGE_RENDER_MESH_STATIC_HPP +#pragma once #include "core/fast_vector.hpp" -#include "math/math_utils3d.hpp" -#include "mesh/mesh_pass.hpp" -#include "render/render_object.hpp" -#include "render/vertex_factories.hpp" -#include "resource/material.hpp" -#include "resource/mesh.hpp" -#include "resource/model.hpp" +#include "core/status.hpp" -#include +#include +#include +#include +#include namespace wmoge { /** - * @class RenderMeshStatic - * @brief Static renderable mesh - */ - class RenderMeshStatic : public RenderObject { + * @class Signal + * @brief Allows to immediately notify listeners when something occurse on singnal holder side + */ + template + class Signal { public: - RenderMeshStatic(Ref model); + using Callback = std::function; - void collect(const RenderCameras& cameras, RenderCameraMask mask, MeshBatchCollector& collector) override; - void procces_visibility(RenderCameraMask mask, float distance) override; - bool has_materials() const override; - std::optional> get_material() const override; - std::vector> get_materials() const override; - Aabbf get_aabb() const override; + Signal() = default; + Signal(const Signal&) = delete; + Signal(Signal&&) noexcept = delete; - private: - struct PerLodData { - VertexFactoryStatic factory; - fast_vector pass_list; - }; + void emit(TArgs&&... args); + int bind(Callback&& callback); + bool unbind(int id); + void clear(); - struct LodState { - float dist = 0.0f; - int lodIdx = 0; + private: + struct Client { + Callback callback; + int id = -1; }; - fast_vector> m_materials; - fast_vector m_lod_data; - LodState m_lod_state; - Ref m_model; + fast_vector m_callbacks; + int m_next_id = 0; }; -}// namespace wmoge + template + inline void Signal::emit(TArgs&&... args) { + for (const auto& client : m_callbacks) { + client.callback(std::forward(args)...); + } + } + + template + inline int Signal::bind(Callback&& callback) { + Client& client = m_callbacks.emplace_back(); + client.callback = std::move(callback); + client.id = m_next_id++; + return client.id; + } + + template + inline bool Signal::unbind(int id) { + auto target = std::find_if(m_callbacks.begin(), m_callbacks.end(), [&](const Client& c) { + return c.id == id; + }); + if (target != m_callbacks.end()) { + m_callbacks.erase(target); + return true; + } + return false; + } + + template + inline void Signal::clear() { + m_callbacks.clear(); + } -#endif//WMOGE_RENDER_MESH_STATIC_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/status.hpp b/engine/core/status.hpp index ab7936c9f..e95261815 100644 --- a/engine/core/status.hpp +++ b/engine/core/status.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_STATUS_HPP -#define WMOGE_STATUS_HPP +#pragma once #include "core/string_id.hpp" #include "io/enum.hpp" @@ -116,6 +115,4 @@ namespace wmoge { return stream; } -}// namespace wmoge - -#endif//WMOGE_STATUS_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/string_id.cpp b/engine/core/string_id.cpp index 0c90eaece..dc9af612f 100644 --- a/engine/core/string_id.cpp +++ b/engine/core/string_id.cpp @@ -27,6 +27,7 @@ #include "core/string_id.hpp" #include "core/fast_map.hpp" +#include "core/synchronization.hpp" #include #include @@ -50,7 +51,7 @@ namespace wmoge { private: fast_map> m_entries; - mutable std::mutex m_mutex; + mutable SpinMutex m_mutex; }; void StringStorage::get_or_create(const std::string& key, const std::string*& str) { diff --git a/engine/core/string_id.hpp b/engine/core/string_id.hpp index bd6798479..5ec916170 100644 --- a/engine/core/string_id.hpp +++ b/engine/core/string_id.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_STRING_ID_HPP -#define WMOGE_STRING_ID_HPP +#pragma once #include #include @@ -59,13 +58,15 @@ namespace wmoge { const std::string* m_string; }; - static_assert(std::is_trivially_destructible_v, "string must be trivial as ptr on int"); + static_assert(std::is_trivially_destructible_v, "string must be trivial as ptr or int"); inline std::ostream& operator<<(std::ostream& stream, const StringId& id) { stream << '\'' << id.str() << '\''; return stream; } +#define SID(id) ::wmoge::StringId(id) + }// namespace wmoge namespace std { @@ -78,8 +79,4 @@ namespace std { } }; -}// namespace std - -#define SID(id) ::wmoge::StringId(id) - -#endif//WMOGE_STRING_ID_HPP \ No newline at end of file +}// namespace std \ No newline at end of file diff --git a/engine/core/string_utf.hpp b/engine/core/string_utf.hpp index dd661a73b..33bd0dc7c 100644 --- a/engine/core/string_utf.hpp +++ b/engine/core/string_utf.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_STRING_UTF_HPP -#define WMOGE_STRING_UTF_HPP +#pragma once #include @@ -81,6 +80,4 @@ namespace wmoge { static bool utf16_to_utf8(const std::u16string& in, std::string& out); }; -}// namespace wmoge - -#endif//WMOGE_STRING_UTF_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/string_utils.hpp b/engine/core/string_utils.hpp index c229e1ed9..da444b2ba 100644 --- a/engine/core/string_utils.hpp +++ b/engine/core/string_utils.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_STRING_UTILS_HPP -#define WMOGE_STRING_UTILS_HPP +#pragma once #include #include @@ -86,6 +85,4 @@ namespace wmoge { static std::string find_replace_first(const std::string& source, const std::string& substring, const std::string& replacement); }; -}// namespace wmoge - -#endif//WMOGE_STRING_UTILS_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/synchronization.hpp b/engine/core/synchronization.hpp index f9bfb0e92..e9e0c6132 100644 --- a/engine/core/synchronization.hpp +++ b/engine/core/synchronization.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_SYNCHRONIZATION_HPP -#define WMOGE_SYNCHRONIZATION_HPP +#pragma once #include #include @@ -75,6 +74,4 @@ namespace wmoge { */ using SpinMutex = SpinMutexTtas; -}// namespace wmoge - -#endif//WMOGE_SYNCHRONIZATION_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/task.cpp b/engine/core/task.cpp index ef0b79c5b..6fbef0b57 100644 --- a/engine/core/task.cpp +++ b/engine/core/task.cpp @@ -27,9 +27,9 @@ #include "core/task.hpp" -#include "core/engine.hpp" #include "core/task_runtime.hpp" #include "debug/profiler.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/core/task.hpp b/engine/core/task.hpp index 02668ddb6..0688e9d31 100644 --- a/engine/core/task.hpp +++ b/engine/core/task.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TASK_HPP -#define WMOGE_TASK_HPP +#pragma once #include "core/async.hpp" #include "core/string_id.hpp" @@ -105,6 +104,4 @@ namespace wmoge { StringId m_name; }; -}// namespace wmoge - -#endif//WMOGE_TASK_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/task_hnd.hpp b/engine/core/task_hnd.hpp index 0387b40fc..a844096dc 100644 --- a/engine/core/task_hnd.hpp +++ b/engine/core/task_hnd.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TASK_HND_HPP -#define WMOGE_TASK_HND_HPP +#pragma once #include "core/async.hpp" @@ -37,6 +36,4 @@ namespace wmoge { */ using TaskHnd = AsyncResult; -}// namespace wmoge - -#endif//WMOGE_TASK_HND_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/task_manager.cpp b/engine/core/task_manager.cpp index 78f9f3e12..a143e3845 100644 --- a/engine/core/task_manager.cpp +++ b/engine/core/task_manager.cpp @@ -27,10 +27,10 @@ #include "task_manager.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "core/task_runtime.hpp" #include "debug/profiler.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/core/task_manager.hpp b/engine/core/task_manager.hpp index de05295b0..12a34fbcb 100644 --- a/engine/core/task_manager.hpp +++ b/engine/core/task_manager.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TASK_MANAGER_HPP -#define WMOGE_TASK_MANAGER_HPP +#pragma once #include "core/ref.hpp" #include "core/string_id.hpp" @@ -79,6 +78,4 @@ namespace wmoge { SpinMutex m_mutex; }; -}// namespace wmoge - -#endif//WMOGE_TASK_MANAGER_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/task_parallel_for.cpp b/engine/core/task_parallel_for.cpp index bf227e1d4..074d94db9 100644 --- a/engine/core/task_parallel_for.cpp +++ b/engine/core/task_parallel_for.cpp @@ -27,9 +27,9 @@ #include "task_parallel_for.hpp" -#include "core/engine.hpp" #include "core/task_runtime.hpp" #include "debug/profiler.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/core/task_parallel_for.hpp b/engine/core/task_parallel_for.hpp index 7cf4c73c3..21ee0bfc5 100644 --- a/engine/core/task_parallel_for.hpp +++ b/engine/core/task_parallel_for.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TASK_PARALLEL_FOR_HPP -#define WMOGE_TASK_PARALLEL_FOR_HPP +#pragma once #include "core/async.hpp" #include "core/string_id.hpp" @@ -113,6 +112,4 @@ namespace wmoge { StringId m_name; }; -}// namespace wmoge - -#endif//WMOGE_TASK_PARALLEL_FOR_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/task_runtime.hpp b/engine/core/task_runtime.hpp index a896406b6..23b1a4f72 100644 --- a/engine/core/task_runtime.hpp +++ b/engine/core/task_runtime.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TASK_RUNTIME_HPP -#define WMOGE_TASK_RUNTIME_HPP +#pragma once #include "core/async.hpp" #include "core/string_id.hpp" @@ -82,6 +81,4 @@ namespace wmoge { std::atomic_int m_tasks_failed{0}; }; -}// namespace wmoge - -#endif//WMOGE_TASK_RUNTIME_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/timer.hpp b/engine/core/timer.hpp index 733108014..dfdcbc968 100644 --- a/engine/core/timer.hpp +++ b/engine/core/timer.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TIMER_HPP -#define WMOGE_TIMER_HPP +#pragma once #include @@ -51,6 +50,4 @@ namespace wmoge { std::chrono::steady_clock::time_point m_end{}; }; -}// namespace wmoge - -#endif//WMOGE_TIMER_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/typed_array.hpp b/engine/core/typed_array.hpp index 7566b0395..2b1a57ae3 100644 --- a/engine/core/typed_array.hpp +++ b/engine/core/typed_array.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TYPED_ARRAY_HPP -#define WMOGE_TYPED_ARRAY_HPP +#pragma once #include "core/ref.hpp" #include "io/yaml.hpp" @@ -117,6 +116,4 @@ namespace wmoge { return StatusCode::Ok; } -}// namespace wmoge - -#endif//WMOGE_TYPED_ARRAY_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/typed_map.hpp b/engine/core/typed_map.hpp index 6c496b6f5..e6b9eabd5 100644 --- a/engine/core/typed_map.hpp +++ b/engine/core/typed_map.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TYPED_MAP_HPP -#define WMOGE_TYPED_MAP_HPP +#pragma once #include "core/ref.hpp" #include "io/yaml.hpp" @@ -125,6 +124,4 @@ namespace wmoge { return StatusCode::Ok; } -}// namespace wmoge - -#endif//WMOGE_TYPED_MAP_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/unrolled_list.hpp b/engine/core/unrolled_list.hpp deleted file mode 100644 index b68cbc4b5..000000000 --- a/engine/core/unrolled_list.hpp +++ /dev/null @@ -1,250 +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. */ -/**********************************************************************************/ - -#ifndef WMOGE_UNROLLED_LIST -#define WMOGE_UNROLLED_LIST - -#include "core/fast_vector.hpp" -#include "io/yaml.hpp" - -#include -#include -#include -#include - -namespace wmoge { - - /** - * @class UnrolledList - * @brief Typed container as well as vector but values stored in chunks with persistent mem address in grow operation - */ - template - class UnrolledList { - public: - static constexpr std::size_t NODE_CAPACITY = NodeCapacity; - static constexpr std::size_t NODE_SIZE = sizeof(T[NODE_CAPACITY]); - - UnrolledList() = default; - UnrolledList(const UnrolledList&) = delete; - UnrolledList(UnrolledList&&) = delete; - ~UnrolledList(); - - template - T& emplace_back(TArgs&&... args); - void push_back(T&& element); - void clear(); - void free(); - void reserve(std::size_t size); - - [[nodiscard]] const fast_vector& nodes() const { return m_nodes; } - [[nodiscard]] const fast_vector& sizes() const { return m_nodes_size; } - [[nodiscard]] std::size_t size() const { return m_size; } - [[nodiscard]] bool is_empty() const { return m_size == 0; } - - template - class Iterator { - public: - Iterator(IterType** nodes, const int* nodes_size, std::size_t nodes_count) { - m_node_curr = nodes; - m_node_end = m_node_curr + nodes_count; - m_node_sizes = nodes_size; - - if (m_node_curr != m_node_end) { - m_elem_curr = *m_node_curr; - m_elem_end = m_elem_curr + *m_node_sizes; - } - }; - - Iterator(IterType** nodes) { - m_node_curr = m_node_end = nodes; - } - - bool operator==(const Iterator& other) const { - return m_node_curr == other.m_node_curr && m_elem_curr == other.m_elem_curr; - } - bool operator!=(const Iterator& other) const { - return m_node_curr != other.m_node_curr || m_elem_curr != other.m_elem_curr; - } - IterType& operator*() { - return *m_elem_curr; - } - void operator++() { - if (m_elem_curr != m_elem_end) { - m_elem_curr++; - } - if (m_elem_curr == m_elem_end) { - m_elem_curr = nullptr; - m_elem_end = nullptr; - - if (m_node_curr != m_node_end) { - m_node_curr++; - m_node_sizes++; - } - if (m_node_curr != m_node_end) { - m_elem_curr = *m_node_curr; - m_elem_end = m_elem_curr + *m_node_sizes; - } - } - } - - private: - IterType** m_node_curr = nullptr; - IterType** m_node_end = nullptr; - const int* m_node_sizes = nullptr; - IterType* m_elem_curr = nullptr; - IterType* m_elem_end = nullptr; - }; - - using iterator = Iterator; - using const_iterator = Iterator; - - iterator begin() { return iterator(m_nodes.data(), m_nodes_size.data(), m_nodes.size()); } - iterator end() { return iterator(m_nodes.data() + m_nodes.size()); } - const_iterator begin() const { return const_iterator(m_nodes.data(), m_nodes_size.data(), m_nodes.size()); } - const_iterator end() const { return const_iterator(m_nodes.data() + m_nodes.size()); } - - private: - void* allocate_back(); - void* allocate_pool(); - - private: - fast_vector m_nodes; - fast_vector m_nodes_size; - fast_vector m_pool; - std::size_t m_size = 0; - }; - - template - inline UnrolledList::~UnrolledList() { - free(); - } - - template - template - inline T& UnrolledList::emplace_back(TArgs&&... args) { - void* mem = allocate_back(); - return *(new (mem) T(std::forward(args...))); - } - - template - inline void UnrolledList::push_back(T&& element) { - void* mem = allocate_back(); - new (mem) T(std::forward(element)); - } - - template - inline void UnrolledList::clear() { - for (std::size_t i = 0; i < m_nodes.size(); i++) { - T* elements = m_nodes[i]; - const std::size_t elements_count = m_nodes_size[i]; - - for (std::size_t element_idx = 0; element_idx < elements_count; element_idx++) { - elements[element_idx].~T(); - } - - m_pool.push_back(elements); - } - - m_nodes.clear(); - m_nodes_size.clear(); - m_size = 0; - } - - template - inline void UnrolledList::free() { - clear(); - - for (void* ptr : m_pool) { - std::free(ptr); - } - - m_pool.clear(); - } - - template - inline void UnrolledList::reserve(std::size_t size) { - if (m_size >= size) { - return; - } - - const std::size_t required_nodes_count = (size + NODE_CAPACITY - 1) / NODE_CAPACITY; - m_nodes.reserve(required_nodes_count); - m_nodes_size.reserve(required_nodes_count); - - for (std::size_t node_idx = m_nodes.size(); node_idx < required_nodes_count; node_idx++) { - m_nodes.push_back(static_cast(allocate_pool())); - m_nodes_size.push_back(0); - } - } - - template - inline void* UnrolledList::allocate_back() { - if (m_nodes.empty() || m_nodes_size.back() == NODE_CAPACITY) { - m_nodes.push_back(static_cast(allocate_pool())); - m_nodes_size.push_back(0); - } - - m_size += 1; - const int offset = m_nodes_size.back()++; - return m_nodes.back() + offset; - } - - template - inline void* UnrolledList::allocate_pool() { - if (m_pool.empty()) { - m_pool.push_back(std::malloc(NODE_SIZE)); - } - - void* mem = m_pool.back(); - m_pool.pop_back(); - return mem; - } - - template - Status yaml_read(const YamlConstNodeRef& node, UnrolledList& list) { - list.reserve(node.num_children()); - for (auto child = node.first_child(); child.valid(); child = child.next_sibling()) { - T element; - WG_YAML_READ(child, element); - list.push_back(std::move(element)); - } - return StatusCode::Ok; - } - - template - Status yaml_write(YamlNodeRef node, const UnrolledList& list) { - WG_YAML_SEQ(node); - for (const T& value : list) { - YamlNodeRef child = node.append_child(); - WG_YAML_WRITE(child, value); - } - return StatusCode::Ok; - } - -}// namespace wmoge - -#endif//WMOGE_UNROLLED_LIST \ No newline at end of file diff --git a/engine/core/uuid.hpp b/engine/core/uuid.hpp index eff1e9254..f98b90b45 100644 --- a/engine/core/uuid.hpp +++ b/engine/core/uuid.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_UUID_HPP -#define WMOGE_UUID_HPP +#pragma once #include "io/archive.hpp" #include "io/yaml.hpp" @@ -93,6 +92,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_UUID_HPP +}// namespace std \ No newline at end of file diff --git a/engine/core/var.hpp b/engine/core/var.hpp index 62e6fa8af..37142bff5 100644 --- a/engine/core/var.hpp +++ b/engine/core/var.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_VAR_HPP -#define WMOGE_VAR_HPP +#pragma once #include "core/ref.hpp" #include "core/string_id.hpp" @@ -192,6 +191,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_VAR_HPP +}// namespace std \ No newline at end of file diff --git a/engine/core/weak_ref.cpp b/engine/core/weak_ref.cpp new file mode 100644 index 000000000..7177b9a69 --- /dev/null +++ b/engine/core/weak_ref.cpp @@ -0,0 +1,65 @@ +/**********************************************************************************/ +/* 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 "weak_ref.hpp" + +namespace wmoge { + + bool WeakRefAccess::try_release_object() { + std::lock_guard guard(m_mutex); + + if (!m_object) { + // Already released, it is ok + // since it is possible that a-bb-a (2 shared ptr) reached 0 at some point + // due to b constucted from weak ref + return false; + } + + if (m_object->refs_count() == 0) { + // It is actually was last ref to object in some shared prt + // and now there no more refs, we must destory object here. + // Note: it is safe, since we are under mutex now, only here weak prts can add refs + m_object = nullptr; + return true; + } + + return false; + } + + std::optional> WeakRefAccess::try_acquire_object() { + std::lock_guard guard(m_mutex); + + if (m_object) { + // Object is alive, construct shared ref under mutex + Ref ptr(m_object); + return std::optional>(std::move(ptr)); + } + + return std::nullopt; + } + +}// namespace wmoge \ No newline at end of file diff --git a/engine/core/weak_ref.hpp b/engine/core/weak_ref.hpp new file mode 100644 index 000000000..67c7050e8 --- /dev/null +++ b/engine/core/weak_ref.hpp @@ -0,0 +1,201 @@ +/**********************************************************************************/ +/* 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/ref.hpp" +#include "core/synchronization.hpp" + +#include + +namespace wmoge { + + /** + * @class WeakRefAccess + * @brief Manages access to a shared object to access in a weak pointer + * + * This base struct is referenced by weak ptr and alive until last weak ref is released. + * Used to track life-time of a shared object. If object destructed, it is no + * more reachable by any weak ref. + * + * @note Thread-safe + */ + class WeakRefAccess : public RefCnt { + public: + WeakRefAccess() = default; + WeakRefAccess(class RefCnt* object) : m_object(object) {} + + bool try_release_object(); + std::optional> try_acquire_object(); + + private: + mutable SpinMutex m_mutex; + mutable class RefCnt* m_object = nullptr; + }; + + /** + * @class WeakRefCnt + * @brief Base class for any shared object which wants weak referencing support + * + * @tparam BaseRefCntClass Base class which provides shared ref cnt mechanism + */ + template + class WeakRefCnt : public BaseRefCntClass { + public: + ~WeakRefCnt() override = default; + + [[nodiscard]] const Ref& get_weak_access() const { return m_weak_access; } + + protected: + void reach_zero() override { + if (m_weak_access->try_release_object()) { + BaseRefCntClass::destroy(); + } + } + + private: + Ref m_weak_access = make_ref(this); + }; + + template + inline Ref weak_ref_access(T* object) { + return object ? object->get_weak_access() : Ref(); + } + + /** + * @class WeakRef + * @brief Smart weak reference-counted pointer to type T + */ + template + class WeakRef { + public: + WeakRef() = default; + + WeakRef(std::nullptr_t){}; + + explicit WeakRef(T* object) { + m_ptr = std::move(weak_ref_access(object)); + } + + WeakRef(const WeakRef& p) { + m_ptr = p.m_ptr; + } + + WeakRef(const Ref& p) { + m_ptr = std::move(weak_ref_access(p.get())); + } + + template> = true> + WeakRef(const WeakRef& p) { + m_ptr = p.m_ptr; + } + + template> = true> + WeakRef(const Ref& p) { + m_ptr = weak_ref_access(p.get()); + } + + WeakRef(WeakRef&& p) noexcept { + m_ptr = std::move(p.m_ptr); + } + + template> = true> + WeakRef(WeakRef&& p) noexcept { + m_ptr = std::move(p.m_ptr); + } + + ~WeakRef() = default; + + WeakRef& operator=(const WeakRef& p) { + m_ptr = p.ptr; + return *this; + } + + WeakRef& operator=(WeakRef&& p) noexcept { + m_ptr = std::move(p.m_ptr); + return *this; + } + + bool operator==(const WeakRef& p) const { + return m_ptr == p.m_ptr; + } + + bool operator!=(const WeakRef& p) const { + return m_ptr != p.m_ptr; + } + + operator bool() const { + return m_ptr != nullptr; + } + + template> = true> + operator WeakRef() const { + return WeakRef(*this); + } + + Ref acquire() const { + if (!m_ptr) { + return Ref(); + } + std::optional> access = m_ptr->try_acquire_object(); + if (!access) { + return Ref(); + } + return access.value().cast(); + } + + template + Ref acquire_cast() const { + return acquire().cast(); + } + + void reset(T* object = nullptr) { + m_ptr = std::move(weak_ref_access(object)); + } + + template> = true> + WeakRef as() const { + return WeakRef(m_ptr); + } + + private: + Ref m_ptr; + }; + +}// namespace wmoge + +namespace std { + + template + struct hash> { + public: + std::size_t operator()(const wmoge::WeakRef& ref) const { + return std::hash()(ref.get()); + } + }; + +}// namespace std \ No newline at end of file diff --git a/engine/debug/console.cpp b/engine/debug/console.cpp index 6a2db0dce..c66634b42 100644 --- a/engine/debug/console.cpp +++ b/engine/debug/console.cpp @@ -27,7 +27,6 @@ #include "console.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "core/string_utils.hpp" #include "debug/profiler.hpp" @@ -37,11 +36,13 @@ #include "event/event_manager.hpp" #include "gameplay/action_manager.hpp" #include "math/math_utils.hpp" +#include "platform/time.hpp" #include "platform/window.hpp" #include "platform/window_manager.hpp" #include "render/canvas.hpp" #include "resource/config_file.hpp" #include "resource/resource_manager.hpp" +#include "system/engine.hpp" #include #include @@ -236,7 +237,7 @@ namespace wmoge { std::lock_guard lock(m_mutex); - auto dt = float(Engine::instance()->get_delta_time()); + auto dt = float(Engine::instance()->time()->get_delta_time()); m_state_open = m_state_open + m_current_speed * dt; if (m_state_open > 1.0f) { diff --git a/engine/debug/console.hpp b/engine/debug/console.hpp index 74f4a7bc2..1058a0296 100644 --- a/engine/debug/console.hpp +++ b/engine/debug/console.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_CONSOLE_HPP -#define WMOGE_CONSOLE_HPP +#pragma once #include "core/fast_map.hpp" #include "core/string_id.hpp" @@ -213,6 +212,4 @@ namespace wmoge { int m_max_to_display = 0; }; -}// namespace wmoge - -#endif//WMOGE_CONSOLE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/debug/debug_layer.cpp b/engine/debug/debug_layer.cpp index 771ec1b86..f997c9ea4 100644 --- a/engine/debug/debug_layer.cpp +++ b/engine/debug/debug_layer.cpp @@ -27,13 +27,16 @@ #include "debug_layer.hpp" -#include "core/engine.hpp" +#include "core/timer.hpp" #include "debug/console.hpp" #include "debug/profiler.hpp" +#include "platform/time.hpp" #include "platform/window.hpp" #include "platform/window_manager.hpp" #include "render/aux_draw_manager.hpp" #include "render/render_engine.hpp" +#include "scene/scene_manager.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -53,15 +56,31 @@ namespace wmoge { auto canvas_debug = engine->canvas_debug(); auto aux_draw_manager = engine->aux_draw_manager(); auto console = engine->console(); + auto window = engine->window_manager()->primary_window(); console->update(); console->render(); - aux_draw_manager->flush(engine->get_delta_time_game()); + aux_draw_manager->flush(engine->time()->get_delta_time_game()); render_engine->render_aux_geom(*aux_draw_manager); + { + auto time = engine->time(); + auto scene_manager = engine->scene_manager(); + auto scene = scene_manager->get_running_scene(); + + auto font = engine->resource_manager()->load(SID("res://fonts/anonymous_pro")).cast(); + + const float fps = Math::round(Math::clamp(1.0f / time->get_delta_time_game(), 0.0f, 1000.0f)); + + canvas_debug->add_text("frame: " + StringUtils::from_int(int(time->get_iteration())), font, 16.0f, Vec2f(10, 60), Color::YELLOW4f); + canvas_debug->add_text("fps: " + StringUtils::from_float(fps) + " (" + StringUtils::from_float(time->get_delta_time_game()) + "ms)", font, 16.0f, Vec2f(10, 40), Color::YELLOW4f); + canvas_debug->add_text("scene: " + (scene ? scene->get_name().str() : String("")), font, 16.0f, Vec2f(10, 20), Color::YELLOW4f); + } + canvas_debug->compile(true); - render_engine->render_canvas(*canvas_debug, Vec4f(0.0f, 0.0f, 1280.0f, 720.0f)); + canvas_debug->render(window, Rect2i(0, 0, window->fbo_size()), Vec4f(0.0f, 0.0f, 1280.0f, 720.0f), 2.2f); + // render_engine->render_canvas(*canvas_debug, Vec4f(0.0f, 0.0f, 1280.0f, 720.0f)); canvas_debug->clear(false); } diff --git a/engine/debug/debug_layer.hpp b/engine/debug/debug_layer.hpp index 871d2d4ce..fd1c05834 100644 --- a/engine/debug/debug_layer.hpp +++ b/engine/debug/debug_layer.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_DEBUG_LAYER_HPP -#define WMOGE_DEBUG_LAYER_HPP +#pragma once #include "core/layer.hpp" @@ -43,6 +42,4 @@ namespace wmoge { void on_debug_draw() override; }; -}// namespace wmoge - -#endif//WMOGE_DEBUG_LAYER_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/debug/profiler.cpp b/engine/debug/profiler.cpp index 005bcff6b..ab47e5000 100644 --- a/engine/debug/profiler.cpp +++ b/engine/debug/profiler.cpp @@ -27,9 +27,10 @@ #include "profiler.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "platform/file_system.hpp" +#include "platform/time.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -101,7 +102,7 @@ namespace wmoge { return; } - auto start = engine->get_start(); + auto start = engine->time()->get_start(); auto tid_names = profiler->get_tid_names(); file_stream << R"({"otherData":{}, "traceEvents":[)"; @@ -143,17 +144,23 @@ namespace wmoge { add_tid(std::this_thread::get_id(), SID("main-thread")); } void Profiler::set_enabled(bool value) { + std::lock_guard guard(m_mutex); + m_is_enabled.store(value); + m_is_collecting.store(value && m_capture); WG_LOG_INFO("time profiler status is " << value); } void Profiler::start_capture(std::shared_ptr capture) { - if (!is_enabled()) return; std::lock_guard guard(m_mutex); + m_capture = std::move(capture); - m_is_collecting.store(true); + if (is_enabled()) { + m_is_collecting.store(true); + } } void Profiler::end_capture() { std::lock_guard guard(m_mutex); + m_is_collecting.store(false); m_capture.reset(); } diff --git a/engine/debug/profiler.hpp b/engine/debug/profiler.hpp index 23efd9d30..6e7c02a73 100644 --- a/engine/debug/profiler.hpp +++ b/engine/debug/profiler.hpp @@ -25,10 +25,10 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_PROFILER_HPP -#define WMOGE_PROFILER_HPP +#pragma once #include "core/string_id.hpp" +#include "core/synchronization.hpp" #include "core/timer.hpp" #include @@ -94,6 +94,8 @@ namespace wmoge { */ class ProfilerCapture { public: + ProfilerCapture() = default; + void set_name(StringId name); void set_file(std::string file); void add_entry(ProfilerEntry&& entry); @@ -131,7 +133,7 @@ namespace wmoge { std::atomic_bool m_is_collecting{false}; std::shared_ptr m_capture; std::unordered_map m_tid_names; - std::mutex m_mutex; + SpinMutex m_mutex; }; }// namespace wmoge @@ -173,16 +175,15 @@ namespace wmoge { #define WG_AUTO_PROFILE_PFX(label) WG_AUTO_PROFILE(pfx, label) #define WG_AUTO_PROFILE_AUDIO(label) WG_AUTO_PROFILE(audio, label) #define WG_AUTO_PROFILE_OPENAL(label) WG_AUTO_PROFILE(openal, label) +#define WG_AUTO_PROFILE_SYSTEM(label) WG_AUTO_PROFILE(system, label) -#define WG_PROFILE_CAPTURE_START(session, file_path) \ - std::shared_ptr __capture_##session = std::make_shared(); \ - __capture_##session->set_name(SID(#session)); \ - __capture_##session->set_file(file_path); \ - Engine::instance()->profiler()->start_capture(__capture_##session); +#define WG_PROFILE_CAPTURE_START(capture, session, file_path) \ + capture = std::make_shared(); \ + capture->set_name(SID(#session)); \ + capture->set_file(file_path); \ + Engine::instance()->profiler()->start_capture(capture); -#define WG_PROFILE_CAPTURE_END(session) \ +#define WG_PROFILE_CAPTURE_END(capture) \ Engine::instance()->profiler()->end_capture(); \ - __capture_##session->save_to_json(); \ - __capture_##session.reset(); - -#endif//WMOGE_PROFILER_HPP + capture->save_to_json(); \ + capture.reset(); \ No newline at end of file diff --git a/engine/ecs/ecs_component.hpp b/engine/ecs/ecs_component.hpp index 12aa163f6..31cfc8bd0 100644 --- a/engine/ecs/ecs_component.hpp +++ b/engine/ecs/ecs_component.hpp @@ -25,9 +25,9 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_COMPONENT_HPP -#define WMOGE_ECS_COMPONENT_HPP +#pragma once +#include "core/fast_vector.hpp" #include "core/object.hpp" #include "core/string_id.hpp" #include "core/string_utils.hpp" @@ -43,29 +43,41 @@ namespace wmoge { * @class EcsComponent * @brief Base class for any engine ecs component */ - struct EcsComponent {}; + template + struct EcsComponent { + static int IDX; + static StringId NAME; + + static bool is(int id) { return id == IDX; } + static bool is(const std::string& name) { return name == NAME.str(); } + static bool is(const StringId& name) { return name == NAME; } + + static void bind(int id, const StringId& name) { + IDX = id; + NAME = name; + } + }; + + template + int EcsComponent::IDX = -1; + + template + StringId EcsComponent::NAME; /** * @class EcsComponentInfo * @brief Holds information required to work with components */ struct EcsComponentInfo { - StringId name; - int idx = -1; - int size = -1; - std::function create; - std::function destroy; - std::function swap; + StringId name; + int idx = -1; + int size = -1; + std::function create; + std::function destroy; + std::function swap; }; -#define WG_ECS_COMPONENT(ecs_component_class, ecs_idx) \ - static_assert(ecs_idx < EcsLimits::MAX_COMPONENTS, "Index for " #ecs_component_class " is out of limits"); \ - static constexpr int IDX = ecs_idx; \ - static constexpr const char NAME[] = #ecs_component_class; \ - static bool is(int id) { return id == IDX; } \ - static bool is(const std::string& name) { return name == NAME; } \ - static bool is(const StringId& name) { return name.str() == NAME; } +#define WG_ECS_COMPONENT(ecs_component_class) \ + static constexpr char NAME_CSTR[] = #ecs_component_class; }// namespace wmoge - -#endif//WMOGE_ECS_COMPONENT_HPP diff --git a/engine/ecs/ecs_core.cpp b/engine/ecs/ecs_core.cpp index 6ffc38f2b..d8a83f780 100644 --- a/engine/ecs/ecs_core.cpp +++ b/engine/ecs/ecs_core.cpp @@ -27,8 +27,8 @@ #include "ecs_core.hpp" -#include "core/engine.hpp" #include "ecs/ecs_registry.hpp" +#include "system/engine.hpp" #include #include diff --git a/engine/ecs/ecs_core.hpp b/engine/ecs/ecs_core.hpp index e7ec5dead..336b3f1cc 100644 --- a/engine/ecs/ecs_core.hpp +++ b/engine/ecs/ecs_core.hpp @@ -25,8 +25,10 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_CORE_HPP -#define WMOGE_ECS_CORE_HPP +#pragma once + +#include "io/archive.hpp" +#include "io/yaml.hpp" #include #include @@ -55,6 +57,11 @@ namespace wmoge { * @brief An entity archetype defining its component structure */ struct EcsArch final : public std::bitset { + using Bitset = std::bitset; + + EcsArch() = default; + EcsArch(const Bitset& b) : Bitset(b) {} + template void set_component() { set(Component::IDX); } @@ -71,6 +78,19 @@ namespace wmoge { } [[nodiscard]] std::string to_string() const; + + friend Status yaml_read(const YamlConstNodeRef& node, EcsArch& arch) { + return yaml_read(node, *((EcsArch::Bitset*) &arch)); + } + friend Status yaml_write(YamlNodeRef node, const EcsArch& arch) { + return yaml_write(node, *((const EcsArch::Bitset*) &arch)); + } + friend Status archive_read(Archive& archive, EcsArch& arch) { + return archive_read(archive, *((EcsArch::Bitset*) &arch)); + } + friend Status archive_write(Archive& archive, const EcsArch& arch) { + return archive_write(archive, *((const EcsArch::Bitset*) &arch)); + } }; inline std::ostream& operator<<(std::ostream& stream, const EcsArch& arch) { @@ -133,6 +153,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_ECS_CORE_HPP +}// namespace std \ No newline at end of file diff --git a/engine/ecs/ecs_entity.hpp b/engine/ecs/ecs_entity.hpp index fd753675b..fbfeaf759 100644 --- a/engine/ecs/ecs_entity.hpp +++ b/engine/ecs/ecs_entity.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_ENTITY_HPP -#define WMOGE_ECS_ENTITY_HPP +#pragma once #include "ecs/ecs_core.hpp" @@ -119,6 +118,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_ECS_ENTITY_HPP +}// namespace std \ No newline at end of file diff --git a/engine/ecs/ecs_memory.cpp b/engine/ecs/ecs_memory.cpp index d8bb015fc..8c6379c22 100644 --- a/engine/ecs/ecs_memory.cpp +++ b/engine/ecs/ecs_memory.cpp @@ -27,9 +27,9 @@ #include "ecs_memory.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" #include "ecs/ecs_registry.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -53,7 +53,7 @@ namespace wmoge { return ((std::uint8_t*) m_chunks[idx / m_chunk_size]) + m_element_size * (idx % m_chunk_size); } - EcsArchStorage::EcsArchStorage(EcsArch arch) : m_arch(arch) { + EcsArchStorage::EcsArchStorage(EcsArch arch, class EcsWorld* world) : m_world(world), m_arch(arch) { WG_AUTO_PROFILE_ECS("EcsArchStorage::EcsArchStorage"); EcsRegistry* registry = Engine::instance()->ecs_registry(); @@ -92,7 +92,7 @@ namespace wmoge { *m_pool.back().get_element(entity_idx) = entity; m_arch.for_each_component([&](int component_idx) { - m_components_info[component_idx]->create(m_pool[component_idx].get_element_raw(entity_idx)); + m_components_info[component_idx]->create(m_world, m_pool[component_idx].get_element_raw(entity_idx)); }); out_entity_idx = entity_idx; @@ -125,7 +125,7 @@ namespace wmoge { } m_arch.for_each_component([&](int component_idx) { - m_components_info[component_idx]->destroy(m_pool[component_idx].get_element_raw(last_entity)); + m_components_info[component_idx]->destroy(m_world, m_pool[component_idx].get_element_raw(last_entity)); }); m_size -= 1; @@ -137,7 +137,7 @@ namespace wmoge { for (int entity_idx = 0; entity_idx < m_size; entity_idx++) { *m_pool.back().get_element(entity_idx) = EcsEntity(); m_arch.for_each_component([&](int component_idx) { - m_components_info[component_idx]->destroy(m_pool[component_idx].get_element_raw(entity_idx)); + m_components_info[component_idx]->destroy(m_world, m_pool[component_idx].get_element_raw(entity_idx)); }); } diff --git a/engine/ecs/ecs_memory.hpp b/engine/ecs/ecs_memory.hpp index 11aeca1e2..002d0b197 100644 --- a/engine/ecs/ecs_memory.hpp +++ b/engine/ecs/ecs_memory.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_MEMORY_HPP -#define WMOGE_ECS_MEMORY_HPP +#pragma once #include "ecs/ecs_component.hpp" #include "ecs/ecs_core.hpp" @@ -71,7 +70,7 @@ namespace wmoge { */ class EcsArchStorage { public: - explicit EcsArchStorage(EcsArch arch); + explicit EcsArchStorage(EcsArch arch, class EcsWorld* world); EcsArchStorage(const EcsArchStorage&) = delete; EcsArchStorage(EcsArchStorage&&) = delete; ~EcsArchStorage(); @@ -92,7 +91,8 @@ namespace wmoge { std::array m_pool{}; std::array m_components_info{}; - const EcsArch m_arch; + class EcsWorld* m_world = nullptr; + const EcsArch m_arch; int m_chunk_size = 0;// num entities data within single chunk int m_size = 0;// count of allocated entities @@ -106,5 +106,3 @@ namespace wmoge { } }// namespace wmoge - -#endif//WMOGE_ECS_MEMORY_HPP diff --git a/engine/ecs/ecs_registry.cpp b/engine/ecs/ecs_registry.cpp index 9c459a32d..8c78185b7 100644 --- a/engine/ecs/ecs_registry.cpp +++ b/engine/ecs/ecs_registry.cpp @@ -27,8 +27,8 @@ #include "ecs_registry.hpp" -#include "core/engine.hpp" #include "resource/config_file.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/ecs/ecs_registry.hpp b/engine/ecs/ecs_registry.hpp index a55143555..3ca2c96f4 100644 --- a/engine/ecs/ecs_registry.hpp +++ b/engine/ecs/ecs_registry.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_REGISTRY_HPP -#define WMOGE_ECS_REGISTRY_HPP +#pragma once #include "core/fast_map.hpp" #include "core/fast_vector.hpp" @@ -64,33 +63,44 @@ namespace wmoge { template void register_component(); + template + void on_create_hook(Func&& on_destroy); + + template + void on_destroy_hook(Func&& on_destroy); + private: std::array m_components_info; // type info of component, indexed by component id std::array, EcsLimits::MAX_COMPONENTS> m_components_pool; // pools to allocate components chunks fast_map m_components_name_to_idx;// resolve component name to its idx std::unique_ptr m_entity_pool; // pool to allocate entities chunks - int m_chunk_size = 16;// num of components of a single type sequentially allocate in one chunk - int m_expand_size = 2; // num of chunks in a single pooled allocation in head + int m_chunk_size = 16;// num of components of a single type sequentially allocate in one chunk + int m_expand_size = 2; // num of chunks in a single pooled allocation in head + int m_component_types = 0; // total num of registered components }; template void EcsRegistry::register_component() { - EcsComponentInfo& component_info = m_components_info[Component::IDX]; + const int component_idx = m_component_types++; + assert(component_idx < EcsLimits::MAX_COMPONENTS); + EcsComponentInfo& component_info = m_components_info[component_idx]; assert(component_info.name == StringId()); assert(component_info.idx == -1); assert(component_info.size == -1); - component_info.name = SID(Component::NAME); + Component::bind(component_idx, SID(Component::NAME_CSTR)); + + component_info.name = Component::NAME; component_info.idx = Component::IDX; component_info.size = sizeof(Component); - component_info.create = [](void* mem) -> void { + component_info.create = [](class EcsWorld*, void* mem) -> void { new (mem) Component(); }; - component_info.destroy = [](void* mem) -> void { + component_info.destroy = [](class EcsWorld*, void* mem) -> void { static_cast(mem)->~Component(); }; @@ -104,6 +114,24 @@ namespace wmoge { m_components_pool[component_info.idx] = std::make_unique(component_info.size * m_chunk_size, m_expand_size); } -}// namespace wmoge + template + inline void EcsRegistry::on_create_hook(Func&& on_destroy) { + EcsComponentInfo& component_info = m_components_info[Component::IDX]; + + component_info.create = [](class EcsWorld* w, void* mem) -> void { + new (mem) Component(); + f(*w, *(static_cast(mem))); + }; + } + + template + inline void EcsRegistry::on_destroy_hook(Func&& on_destroy) { + EcsComponentInfo& component_info = m_components_info[Component::IDX]; + + component_info.destroy = [f = std::forward(on_destroy)](class EcsWorld* w, void* mem) -> void { + f(*w, *(static_cast(mem))); + static_cast(mem)->~Component(); + }; + } -#endif//WMOGE_ECS_REGISTRY_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/ecs/ecs_system.hpp b/engine/ecs/ecs_system.hpp index def08530f..dd234e6fe 100644 --- a/engine/ecs/ecs_system.hpp +++ b/engine/ecs/ecs_system.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_SYSTEM_HPP -#define WMOGE_ECS_SYSTEM_HPP +#pragma once #include "debug/profiler.hpp" #include "ecs/ecs_core.hpp" @@ -177,6 +176,4 @@ namespace wmoge { } } -}// namespace wmoge - -#endif//WMOGE_ECS_SYSTEM_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/ecs/ecs_world.cpp b/engine/ecs/ecs_world.cpp index 18db30094..51df16358 100644 --- a/engine/ecs/ecs_world.cpp +++ b/engine/ecs/ecs_world.cpp @@ -27,12 +27,13 @@ #include "ecs_world.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "core/task.hpp" #include "core/task_parallel_for.hpp" #include "debug/profiler.hpp" +#include "ecs/ecs_registry.hpp" #include "math/math_utils.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -40,6 +41,10 @@ namespace wmoge { m_task_manager = Engine::instance()->task_manager(); } + EcsWorld::~EcsWorld() { + clear(); + } + EcsEntity EcsWorld::allocate_entity() { WG_AUTO_PROFILE_ECS("EcsWorld::allocate_entity"); @@ -61,26 +66,11 @@ namespace wmoge { WG_AUTO_PROFILE_ECS("EcsWorld::make_entity"); assert(arch.any()); - m_entity_info.resize(m_entity_counter); - if (m_arch_to_idx.find(arch) == m_arch_to_idx.end()) { - const int arch_idx = int(m_arch_storage.size()); - m_arch_to_idx[arch] = arch_idx; - m_arch_by_idx.emplace_back(arch); - m_arch_storage.emplace_back() = std::make_unique(arch); - - for (EcsSystemInfo& system_info : m_systems) { - auto filter = system_info.query.affected(); - - if ((filter & arch) == filter) { - system_info.filtered_arch.push_back(arch_idx); - } - } - } + register_arch(arch); assert(m_arch_to_idx.find(arch) != m_arch_to_idx.end()); - const int arch_idx = m_arch_to_idx[arch]; EcsEntityInfo& entity_info = m_entity_info[entity.idx]; @@ -91,6 +81,56 @@ namespace wmoge { m_arch_storage[arch_idx]->make_entity(entity, entity_info.storage); } + void EcsWorld::swap_entity(const EcsEntity& left, const EcsEntity& right) { + WG_AUTO_PROFILE_ECS("EcsWorld::swap_entity"); + + assert(left.is_valid()); + assert(left.idx < m_entity_info.size()); + assert(right.is_valid()); + assert(right.idx < m_entity_info.size()); + + const EcsEntityInfo& right_info = m_entity_info[right.idx]; + const EcsEntityInfo& left_info = m_entity_info[left.idx]; + + EcsArchStorage* right_storage = m_arch_storage[right_info.arch].get(); + EcsArchStorage* left_storage = m_arch_storage[left_info.arch].get(); + + const EcsArch right_arch = m_arch_by_idx[right_info.arch]; + const EcsArch left_arch = m_arch_by_idx[left_info.arch]; + + EcsRegistry* ecs_registry = Engine::instance()->ecs_registry(); + + EcsArch(right_arch & left_arch).for_each_component([&](int idx) { + const EcsComponentInfo& info = ecs_registry->get_component_info(idx); + info.swap(right_storage->get_component(right_info.storage, idx), left_storage->get_component(left_info.storage, idx)); + }); + } + + void EcsWorld::rearch_entity(const EcsEntity& entity, const EcsArch& new_arch) { + WG_AUTO_PROFILE_ECS("EcsWorld::rearch_entity"); + + assert(new_arch.any()); + assert(entity.is_valid()); + assert(entity.idx < m_entity_info.size()); + + EcsEntityInfo& entity_info = m_entity_info[entity.idx]; + EcsArch prev_arch = m_arch_by_idx[entity_info.arch]; + + if (prev_arch == new_arch) { + return; + } + + EcsEntity tmp_entity = allocate_entity(); + make_entity(tmp_entity, new_arch); + swap_entity(tmp_entity, entity); + + EcsEntityInfo& tmp_entity_info = m_entity_info[tmp_entity.idx]; + std::swap(tmp_entity_info.arch, entity_info.arch); + std::swap(tmp_entity_info.storage, entity_info.storage); + + destroy_entity(tmp_entity); + } + void EcsWorld::destroy_entity(const EcsEntity& entity) { WG_AUTO_PROFILE_ECS("EcsWorld::destroy_entity"); @@ -131,8 +171,6 @@ namespace wmoge { } std::vector EcsWorld::filter_arch_idx(const EcsQuery& query) { - WG_AUTO_PROFILE_ECS("EcsWorld::filter_arch_idx"); - std::vector filtered_arch; const auto filter = query.affected(); @@ -145,6 +183,23 @@ namespace wmoge { return filtered_arch; } + void EcsWorld::register_arch(EcsArch arch) { + if (m_arch_to_idx.find(arch) == m_arch_to_idx.end()) { + const int arch_idx = int(m_arch_storage.size()); + m_arch_to_idx[arch] = arch_idx; + m_arch_by_idx.emplace_back(arch); + m_arch_storage.emplace_back() = std::make_unique(arch, this); + + for (EcsSystemInfo& system_info : m_systems) { + auto filter = system_info.query.affected(); + + if ((filter & arch) == filter) { + system_info.filtered_arch.push_back(arch_idx); + } + } + } + } + void EcsWorld::register_system(const std::shared_ptr& system) { WG_AUTO_PROFILE_ECS("EcsWorld::register_system"); diff --git a/engine/ecs/ecs_world.hpp b/engine/ecs/ecs_world.hpp index 4b4a45282..71157b356 100644 --- a/engine/ecs/ecs_world.hpp +++ b/engine/ecs/ecs_world.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ECS_WORLD_HPP -#define WMOGE_ECS_WORLD_HPP +#pragma once #include "core/callback_queue.hpp" #include "core/fast_map.hpp" @@ -62,6 +61,7 @@ namespace wmoge { class EcsWorld { public: EcsWorld(); + ~EcsWorld(); /** @brief Allocates new entity for later creation */ [[nodiscard]] EcsEntity allocate_entity(); @@ -69,6 +69,12 @@ namespace wmoge { /** @brief Create new entity within world with requested archetype */ void make_entity(const EcsEntity& entity, const EcsArch& arch); + /** @brief Swap entity components data to other entity */ + void swap_entity(const EcsEntity& dst, const EcsEntity& src); + + /** @brief Change existing entity arch to a new archetype */ + void rearch_entity(const EcsEntity& entity, const EcsArch& new_arch); + /** @brief Destroys entity by a handle */ void destroy_entity(const EcsEntity& entity); @@ -78,6 +84,10 @@ namespace wmoge { /** @brief Return archetype of given entity by its handle */ [[nodiscard]] EcsArch get_arch(const EcsEntity& entity) const; + /** @brief Returns component existing or new (possibly changes enity arch) */ + template + [[nodiscard]] Component& get_or_create_component(const EcsEntity& entity); + /** @brief Returns component for read-only operations */ template [[nodiscard]] const Component& get_component(const EcsEntity& entity) const; @@ -96,6 +106,9 @@ namespace wmoge { /** @brief Ids of matching arch for given query */ std::vector filter_arch_idx(const EcsQuery& query); + /** @brief Possibly add new arch to the world allocating space */ + void register_arch(EcsArch arch); + /** @brief Registers system within a world */ void register_system(const std::shared_ptr& system); @@ -114,17 +127,24 @@ namespace wmoge { /** @brief Sync world, flushing all scheduled operations on it */ void sync(); - 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 + /** @brief Sets world specific attribute to access external context of the world */ + template + void set_attribute(int slot, T& attribute); - fast_map m_system_to_idx;// map unique system name to idx - std::vector m_systems; // registered systems info + /** @brief Get world specific attribute to access external context of the world */ + template + T& get_attribute(int slot = 0); - fast_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 + 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 + fast_map m_system_to_idx; // map unique system name to idx + std::vector m_systems; // registered systems info + fast_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 + fast_vector m_attributes; // custom attributes to access context within world CallbackQueue m_queue; // queue for async world operations, flushed on sync TaskManager* m_task_manager;// manager for parallel system update @@ -132,6 +152,23 @@ namespace wmoge { SpinMutex m_mutex; }; + template + inline Component& EcsWorld::get_or_create_component(const EcsEntity& entity) { + assert(entity.is_valid()); + assert(is_alive(entity)); + + const EcsEntityInfo& entity_info = m_entity_info[entity.idx]; + const EcsArch& enity_arch = m_arch_by_idx[entity_info.arch]; + + if (!enity_arch.has_component()) { + EcsArch new_arch = enity_arch; + new_arch.set_component(); + rearch_entity(entity, new_arch); + } + + return get_component_rw(entity); + } + template const Component& EcsWorld::get_component(const EcsEntity& entity) const { assert(entity.is_valid()); @@ -159,6 +196,16 @@ namespace wmoge { return m_arch_by_idx[entity_info.arch].template has_component(); } -}// namespace wmoge + template + inline void EcsWorld::set_attribute(int slot, T& attribute) { + if (slot >= m_attributes.size()) m_attributes.resize(slot + 1); + m_attributes[slot] = &attribute; + } -#endif//WMOGE_ECS_WORLD_HPP + template + inline T& EcsWorld::get_attribute(int slot) { + assert(slot < m_attributes.size()); + return *(static_cast(m_attributes[slot])); + } + +}// namespace wmoge diff --git a/engine/engine.hpp b/engine/engine.hpp index 62d370dc6..5b966dc2d 100644 --- a/engine/engine.hpp +++ b/engine/engine.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ENGINE_GLOBAL_HPP -#define WMOGE_ENGINE_GLOBAL_HPP +#pragma once #include "audio/audio_bus.hpp" #include "audio/audio_defs.hpp" @@ -40,17 +39,19 @@ #include "core/cmd_line.hpp" #include "core/crc32.hpp" #include "core/data.hpp" -#include "core/engine.hpp" #include "core/fast_map.hpp" #include "core/fast_set.hpp" #include "core/fast_vector.hpp" #include "core/hook.hpp" +#include "core/ioc_container.hpp" #include "core/layer.hpp" #include "core/log.hpp" #include "core/mask.hpp" #include "core/object.hpp" +#include "core/pool_vector.hpp" #include "core/random.hpp" #include "core/ref.hpp" +#include "core/signal.hpp" #include "core/status.hpp" #include "core/string_id.hpp" #include "core/string_utf.hpp" @@ -63,9 +64,9 @@ #include "core/timer.hpp" #include "core/typed_array.hpp" #include "core/typed_map.hpp" -#include "core/unrolled_list.hpp" #include "core/uuid.hpp" #include "core/var.hpp" +#include "core/weak_ref.hpp" #include "ecs/ecs_component.hpp" #include "ecs/ecs_core.hpp" @@ -96,6 +97,7 @@ #include "gfx/gfx_desc_set.hpp" #include "gfx/gfx_driver.hpp" #include "gfx/gfx_dynamic_buffers.hpp" +#include "gfx/gfx_pass.hpp" #include "gfx/gfx_pipeline.hpp" #include "gfx/gfx_pipeline_cache.hpp" #include "gfx/gfx_render_pass.hpp" @@ -117,6 +119,7 @@ #include "io/base64.hpp" #include "io/compression.hpp" #include "io/enum.hpp" +#include "io/serialization.hpp" #include "io/yaml.hpp" #include "math/color.hpp" @@ -148,25 +151,28 @@ #include "platform/input.hpp" #include "platform/input_defs.hpp" #include "platform/input_devices.hpp" +#include "platform/time.hpp" #include "platform/window.hpp" #include "platform/window_manager.hpp" #include "render/aux_draw_manager.hpp" +#include "render/camera.hpp" #include "render/canvas.hpp" -#include "render/render_camera.hpp" +#include "render/graphics_pipeline.hpp" +#include "render/light.hpp" +#include "render/model_instance.hpp" #include "render/render_engine.hpp" -#include "render/render_mesh_skinned.hpp" -#include "render/render_mesh_static.hpp" -#include "render/render_object.hpp" #include "render/render_queue.hpp" #include "render/render_scene.hpp" #include "render/shader_manager.hpp" #include "render/shader_pass.hpp" #include "render/texture_compression.hpp" #include "render/texture_manager.hpp" -#include "render/vertex_factory.hpp" +#include "render/view.hpp" +#include "render/view_manager.hpp" #include "render/visibility.hpp" +#include "resource/array_mesh.hpp" #include "resource/audio_stream.hpp" #include "resource/config_file.hpp" #include "resource/font.hpp" @@ -189,20 +195,19 @@ #include "resource/texture.hpp" #include "scene/scene.hpp" -#include "scene/scene_camera.hpp" #include "scene/scene_components.hpp" +#include "scene/scene_data.hpp" +#include "scene/scene_entity.hpp" #include "scene/scene_manager.hpp" #include "scene/scene_node.hpp" -#include "scene/scene_properties.hpp" -#include "scene/scene_property.hpp" -#include "scene/scene_transform.hpp" +#include "scene/scene_node_props.hpp" #include "scene/scene_tree.hpp" #include "scripting/script_instance.hpp" #include "scripting/script_native.hpp" #include "scripting/script_system.hpp" -#include "debug/console.hpp" -#include "debug/profiler.hpp" +#include "system/engine.hpp" -#endif//WMOGE_ENGINE_GLOBAL_HPP +#include "debug/console.hpp" +#include "debug/profiler.hpp" \ No newline at end of file diff --git a/engine/event/event.hpp b/engine/event/event.hpp index e0da8050d..225d91820 100644 --- a/engine/event/event.hpp +++ b/engine/event/event.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_HPP -#define WMOGE_EVENT_HPP +#pragma once #include "core/class.hpp" #include "core/object.hpp" @@ -75,5 +74,3 @@ namespace wmoge { return g_id; \ } \ std::string to_string() override; - -#endif//WMOGE_EVENT_HPP diff --git a/engine/event/event_action.hpp b/engine/event/event_action.hpp index e2f4f2670..eba6dbc5e 100644 --- a/engine/event/event_action.hpp +++ b/engine/event/event_action.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_ACTION_HPP -#define WMOGE_EVENT_ACTION_HPP +#pragma once #include "event/event.hpp" @@ -45,5 +44,3 @@ namespace wmoge { }; }// namespace wmoge - -#endif//WMOGE_EVENT_ACTION_HPP diff --git a/engine/event/event_filesystem.hpp b/engine/event/event_filesystem.hpp index df4993f33..5d4bacfa0 100644 --- a/engine/event/event_filesystem.hpp +++ b/engine/event/event_filesystem.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_FILESYSTEM_HPP -#define WMOGE_EVENT_FILESYSTEM_HPP +#pragma once #include "event/event.hpp" @@ -57,6 +56,4 @@ namespace wmoge { std::string entry; }; -}// namespace wmoge - -#endif//WMOGE_EVENT_FILESYSTEM_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/event/event_input.hpp b/engine/event/event_input.hpp index 889ab76f7..3d59b0173 100644 --- a/engine/event/event_input.hpp +++ b/engine/event/event_input.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_INPUT_HPP -#define WMOGE_EVENT_INPUT_HPP +#pragma once #include "event/event.hpp" #include "platform/input.hpp" @@ -116,5 +115,3 @@ namespace wmoge { }; }// namespace wmoge - -#endif//WMOGE_EVENT_INPUT_HPP diff --git a/engine/event/event_listener.hpp b/engine/event/event_listener.hpp index bb379c599..c966f0325 100644 --- a/engine/event/event_listener.hpp +++ b/engine/event/event_listener.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_LISTENER_HPP -#define WMOGE_EVENT_LISTENER_HPP +#pragma once #include "core/log.hpp" #include "core/string_utils.hpp" @@ -83,6 +82,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_EVENT_LISTENER_HPP +}// namespace std \ No newline at end of file diff --git a/engine/event/event_manager.hpp b/engine/event/event_manager.hpp index b426433e7..84437451f 100644 --- a/engine/event/event_manager.hpp +++ b/engine/event/event_manager.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_MANAGER_HPP -#define WMOGE_EVENT_MANAGER_HPP +#pragma once #include "core/fast_map.hpp" #include "core/fast_vector.hpp" @@ -128,6 +127,4 @@ namespace wmoge { return subscribe(E::type_static(), std::move(callback)); } -}// namespace wmoge - -#endif//WMOGE_EVENT_MANAGER_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/event/event_resource.hpp b/engine/event/event_resource.hpp index 3d838472d..e32b8a3d8 100644 --- a/engine/event/event_resource.hpp +++ b/engine/event/event_resource.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_RESOURCE_HPP -#define WMOGE_EVENT_RESOURCE_HPP +#pragma once #include "event/event.hpp" #include "resource/resource.hpp" @@ -57,5 +56,3 @@ namespace wmoge { }; }// namespace wmoge - -#endif//WMOGE_EVENT_RESOURCE_HPP diff --git a/engine/event/event_script.hpp b/engine/event/event_script.hpp index ebbe7ce91..f4f05f105 100644 --- a/engine/event/event_script.hpp +++ b/engine/event/event_script.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_SCRIPT_HPP -#define WMOGE_EVENT_SCRIPT_HPP +#pragma once #include "event/event.hpp" @@ -49,5 +48,3 @@ namespace wmoge { }; }// namespace wmoge - -#endif//WMOGE_EVENT_SCRIPT_HPP diff --git a/engine/event/event_token.hpp b/engine/event/event_token.hpp index f6ffbd4a8..0954bbb0f 100644 --- a/engine/event/event_token.hpp +++ b/engine/event/event_token.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_TOKEN_HPP -#define WMOGE_EVENT_TOKEN_HPP +#pragma once #include "event/event.hpp" @@ -55,5 +54,3 @@ namespace wmoge { }; }// namespace wmoge - -#endif//WMOGE_EVENT_TOKEN_HPP diff --git a/engine/event/event_window.hpp b/engine/event/event_window.hpp index 83bca5b15..c4359370e 100644 --- a/engine/event/event_window.hpp +++ b/engine/event/event_window.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_EVENT_WINDOW_HPP -#define WMOGE_EVENT_WINDOW_HPP +#pragma once #include "event/event.hpp" #include "platform/window.hpp" @@ -61,5 +60,3 @@ namespace wmoge { }; }// namespace wmoge - -#endif//WMOGE_EVENT_WINDOW_HPP diff --git a/engine/event/register_classes_event.hpp b/engine/event/register_classes_event.hpp index 98244137a..088bacff9 100644 --- a/engine/event/register_classes_event.hpp +++ b/engine/event/register_classes_event.hpp @@ -25,13 +25,10 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_REGISTER_CLASSES_EVENT_HPP -#define WMOGE_REGISTER_CLASSES_EVENT_HPP +#pragma once namespace wmoge { void register_classes_event(); -} - -#endif//WMOGE_REGISTER_CLASSES_EVENT_HPP +} \ No newline at end of file diff --git a/engine/gameplay/action_manager.cpp b/engine/gameplay/action_manager.cpp index d9f150cf9..f3f97c654 100644 --- a/engine/gameplay/action_manager.cpp +++ b/engine/gameplay/action_manager.cpp @@ -27,10 +27,10 @@ #include "action_manager.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "debug/profiler.hpp" #include "event/event_manager.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/gameplay/action_map.cpp b/engine/gameplay/action_map.cpp index 58e61104b..c06a45dc2 100644 --- a/engine/gameplay/action_map.cpp +++ b/engine/gameplay/action_map.cpp @@ -28,13 +28,13 @@ #include "action_map.hpp" #include "core/data.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "debug/profiler.hpp" #include "io/enum.hpp" #include "io/yaml.hpp" #include "platform/file_system.hpp" #include "platform/input.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/gameplay/game_token_manager.cpp b/engine/gameplay/game_token_manager.cpp index 6fcd77987..855f05c3f 100644 --- a/engine/gameplay/game_token_manager.cpp +++ b/engine/gameplay/game_token_manager.cpp @@ -27,10 +27,10 @@ #include "game_token_manager.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "event/event_manager.hpp" #include "event/event_token.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/gfx/gfx_buffers.cpp b/engine/gfx/gfx_buffers.cpp new file mode 100644 index 000000000..b5b4aa777 --- /dev/null +++ b/engine/gfx/gfx_buffers.cpp @@ -0,0 +1,47 @@ +/**********************************************************************************/ +/* 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 "gfx_buffers.hpp" + +namespace wmoge { + + WG_IO_BEGIN(GfxVertStream) + WG_IO_FIELD(attribs) + WG_IO_FIELD(buffer) + WG_IO_FIELD(offset) + WG_IO_FIELD(size) + WG_IO_FIELD(stride) + WG_IO_END(GfxVertStream) + + WG_IO_BEGIN(GfxIndexStream) + WG_IO_FIELD(index_type) + WG_IO_FIELD(buffer) + WG_IO_FIELD(offset) + WG_IO_FIELD(size) + WG_IO_END(GfxIndexStream) + +}// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/gfx_buffers.hpp b/engine/gfx/gfx_buffers.hpp index 17bc199ee..dd4cbd979 100644 --- a/engine/gfx/gfx_buffers.hpp +++ b/engine/gfx/gfx_buffers.hpp @@ -28,7 +28,9 @@ #ifndef WMOGE_GFX_BUFFERS_HPP #define WMOGE_GFX_BUFFERS_HPP +#include "core/data.hpp" #include "gfx/gfx_resource.hpp" +#include "io/serialization.hpp" #include @@ -140,6 +142,33 @@ namespace wmoge { /** @brief Setup to bind storage buffer */ using GfxStorageBufferSetup = GfxBufferSetup; + /** + * @class GfxVertStream + * @brief Provides setup for a stream of vertex attributes packed into vertex buffer + */ + struct GfxVertStream { + GfxVertAttribs attribs; + int buffer = -1; + int offset = 0; + int size = 0; + int stride = 0; + + WG_IO_DECLARE(GfxVertStream); + }; + + /** + * @class GfxIndexStream + * @brief Provides setup with index data packed into index buffer + */ + struct GfxIndexStream { + GfxIndexType index_type = GfxIndexType::None; + int buffer = -1; + int offset = 0; + int size = 0; + + WG_IO_DECLARE(GfxIndexStream); + }; + }// namespace wmoge #endif//WMOGE_GFX_BUFFERS_HPP diff --git a/engine/gfx/gfx_defs.hpp b/engine/gfx/gfx_defs.hpp index 2f833943d..3d0dba177 100644 --- a/engine/gfx/gfx_defs.hpp +++ b/engine/gfx/gfx_defs.hpp @@ -83,6 +83,7 @@ namespace wmoge { /** @brief Type of elements in index buffer */ enum class GfxIndexType : int { + None, Uint32, Uint16 }; diff --git a/engine/gfx/gfx_desc_set.cpp b/engine/gfx/gfx_desc_set.cpp index 9530f2003..1a8b4f1ef 100644 --- a/engine/gfx/gfx_desc_set.cpp +++ b/engine/gfx/gfx_desc_set.cpp @@ -31,22 +31,12 @@ namespace wmoge { - Status archive_read(Archive& archive, GfxDescBinging& binging) { - WG_ARCHIVE_READ(archive, binging.type); - WG_ARCHIVE_READ(archive, binging.binding); - WG_ARCHIVE_READ(archive, binging.count); - WG_ARCHIVE_READ(archive, binging.name); - - return StatusCode::Ok; - } - Status archive_write(Archive& archive, const GfxDescBinging& binging) { - WG_ARCHIVE_WRITE(archive, binging.type); - WG_ARCHIVE_WRITE(archive, binging.binding); - WG_ARCHIVE_WRITE(archive, binging.count); - WG_ARCHIVE_WRITE(archive, binging.name); - - return StatusCode::Ok; - } + WG_IO_BEGIN(GfxDescBinging) + WG_IO_FIELD(type) + WG_IO_FIELD(binding) + WG_IO_FIELD(count) + WG_IO_FIELD(name) + WG_IO_END(GfxDescBinging) bool GfxDescBinging::operator==(const GfxDescBinging& other) const { return type == other.type && diff --git a/engine/gfx/gfx_desc_set.hpp b/engine/gfx/gfx_desc_set.hpp index 71b81c500..bf5ba163f 100644 --- a/engine/gfx/gfx_desc_set.hpp +++ b/engine/gfx/gfx_desc_set.hpp @@ -33,7 +33,7 @@ #include "gfx/gfx_defs.hpp" #include "gfx/gfx_resource.hpp" #include "gfx/gfx_sampler.hpp" -#include "io/archive.hpp" +#include "io/serialization.hpp" #include #include @@ -56,8 +56,7 @@ namespace wmoge { [[nodiscard]] bool operator!=(const GfxDescBinging& other) const; [[nodiscard]] std::size_t hash() const; - friend Status archive_read(Archive& archive, GfxDescBinging& binging); - friend Status archive_write(Archive& archive, const GfxDescBinging& binging); + WG_IO_DECLARE(GfxDescBinging); }; /** diff --git a/engine/gfx/gfx_dynamic_buffers.cpp b/engine/gfx/gfx_dynamic_buffers.cpp index 197d76aaa..91464e417 100644 --- a/engine/gfx/gfx_dynamic_buffers.cpp +++ b/engine/gfx/gfx_dynamic_buffers.cpp @@ -27,13 +27,13 @@ #include "gfx/gfx_dynamic_buffers.hpp" -#include "core/engine.hpp" #include "core/log.hpp" #include "core/string_id.hpp" #include "core/string_utils.hpp" #include "gfx/gfx_ctx.hpp" #include "gfx/gfx_driver.hpp" #include "math/math_utils.hpp" +#include "system/engine.hpp" #include "gfx_dynamic_buffers.hpp" #include diff --git a/engine/gfx/gfx_pass.cpp b/engine/gfx/gfx_pass.cpp new file mode 100644 index 000000000..7fcec4f1c --- /dev/null +++ b/engine/gfx/gfx_pass.cpp @@ -0,0 +1,26 @@ +/**********************************************************************************/ +/* 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. */ +/**********************************************************************************/ \ No newline at end of file diff --git a/engine/render/post_process/pass_autoexposure.hpp b/engine/gfx/gfx_pass.hpp similarity index 67% rename from engine/render/post_process/pass_autoexposure.hpp rename to engine/gfx/gfx_pass.hpp index 0c509892e..0ceb52034 100644 --- a/engine/render/post_process/pass_autoexposure.hpp +++ b/engine/gfx/gfx_pass.hpp @@ -25,37 +25,43 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_PASS_AUTOEXPOSURE_HPP -#define WMOGE_PASS_AUTOEXPOSURE_HPP +#pragma once -#include "gfx/gfx_buffers.hpp" -#include "gfx/gfx_desc_set.hpp" -#include "gfx/gfx_pipeline.hpp" -#include "gfx/gfx_sampler.hpp" -#include "render/graphics_pipeline.hpp" -#include "render/render_engine.hpp" +#include "gfx/gfx_defs.hpp" namespace wmoge { /** - * @class PassAutoExposure - * @brief Executes auto exposure to extract luminance histogram of frame and calc exposure correction + * @class GfxPassDesc + * @brief Base class for a description to setup a gfx pass + * + * Gfx pass descriptor is a minimal self-contained representation, + * required to setup a GfxPass for rendering. + * + * Description can be created from any system and used to automate + * setup of required for the rendering data: + * - gather required defines for the shader + * - compile gfx shader items + * - setup required vertex format and render state + * - compile pipeline state object */ - class PassAutoExposure : public GraphicsPipelineStage { + class GfxPassDesc { public: - PassAutoExposure(); - - void execute(int view_idx); - - std::string get_name() const override; - GraphicsPipelineStageType get_type() const override; - - private: - Ref m_pipeline_histogram; - Ref m_pipeline_avg; - Ref m_sampler; }; -}// namespace wmoge + /** + * @class GfxPass + * @brief Base class for any GPU shaders + * + * Gfx pass is a high level shading program representation. It provides connection + * between a shader, written using glsl in engine source code, optional user defined + * material and a low-level engine gfx api. + * + * Gfx pass provides info about required pipeline layout, allows to obtain final + * shader source code, provides defines info and etc. + */ + class GfxPass { + public: + }; -#endif//WMOGE_PASS_AUTOEXPOSURE_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/gfx_sampler.cpp b/engine/gfx/gfx_sampler.cpp index 527e42eeb..656e75df6 100644 --- a/engine/gfx/gfx_sampler.cpp +++ b/engine/gfx/gfx_sampler.cpp @@ -35,6 +35,18 @@ namespace wmoge { + WG_IO_BEGIN(GfxSamplerDesc) + WG_IO_FIELD(min_lod) + WG_IO_FIELD(max_lod) + WG_IO_FIELD(max_anisotropy) + WG_IO_FIELD(min_flt) + WG_IO_FIELD(mag_flt) + WG_IO_FIELD(u) + WG_IO_FIELD(v) + WG_IO_FIELD(w) + WG_IO_FIELD(brd_clr) + WG_IO_END(GfxSamplerDesc) + GfxSamplerDesc::GfxSamplerDesc() { std::memset(this, 0, sizeof(GfxSamplerDesc)); min_lod = 0; @@ -63,32 +75,4 @@ namespace wmoge { return sampler_name.str(); } - Status yaml_read(const YamlConstNodeRef& node, GfxSamplerDesc& desc) { - WG_YAML_READ_AS_OPT(node, "min_lod", desc.min_lod); - WG_YAML_READ_AS_OPT(node, "max_lod", desc.max_lod); - WG_YAML_READ_AS_OPT(node, "max_anisotropy", desc.max_anisotropy); - WG_YAML_READ_AS_OPT(node, "min_flt", desc.min_flt); - WG_YAML_READ_AS_OPT(node, "mag_flt", desc.mag_flt); - WG_YAML_READ_AS_OPT(node, "u", desc.u); - WG_YAML_READ_AS_OPT(node, "v", desc.v); - WG_YAML_READ_AS_OPT(node, "w", desc.w); - WG_YAML_READ_AS_OPT(node, "brd_clr", desc.brd_clr); - - return StatusCode::Ok; - } - Status yaml_write(YamlNodeRef node, const GfxSamplerDesc& desc) { - WG_YAML_MAP(node); - WG_YAML_WRITE_AS(node, "min_lod", desc.min_lod); - WG_YAML_WRITE_AS(node, "max_lod", desc.max_lod); - WG_YAML_WRITE_AS(node, "max_anisotropy", desc.max_anisotropy); - WG_YAML_WRITE_AS(node, "min_flt", desc.min_flt); - WG_YAML_WRITE_AS(node, "mag_flt", desc.mag_flt); - WG_YAML_WRITE_AS(node, "u", desc.u); - WG_YAML_WRITE_AS(node, "v", desc.v); - WG_YAML_WRITE_AS(node, "w", desc.w); - WG_YAML_WRITE_AS(node, "brd_clr", desc.brd_clr); - - return StatusCode::Ok; - } - }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/gfx_sampler.hpp b/engine/gfx/gfx_sampler.hpp index 611e1e480..4a9a329cb 100644 --- a/engine/gfx/gfx_sampler.hpp +++ b/engine/gfx/gfx_sampler.hpp @@ -29,7 +29,7 @@ #define WMOGE_GFX_SAMPLER_HPP #include "gfx/gfx_resource.hpp" -#include "io/yaml.hpp" +#include "io/serialization.hpp" #include @@ -55,8 +55,7 @@ namespace wmoge { GfxSampAddress w; // = GfxSampAddress::Repeat; GfxSampBrdClr brd_clr; // = GfxSampBrdClr::Black; - friend Status yaml_read(const YamlConstNodeRef& node, GfxSamplerDesc& desc); - friend Status yaml_write(YamlNodeRef node, const GfxSamplerDesc& desc); + WG_IO_DECLARE(GfxSamplerDesc); }; /** diff --git a/engine/gfx/gfx_shader.cpp b/engine/gfx/gfx_shader.cpp index 7a195e322..ac4869679 100644 --- a/engine/gfx/gfx_shader.cpp +++ b/engine/gfx/gfx_shader.cpp @@ -31,71 +31,28 @@ namespace wmoge { - Status archive_write(Archive& archive, const GfxShaderReflection::Texture& texture) { - WG_AUTO_PROFILE_GFX("GfxShaderReflection::Texture::Archive<<"); - - WG_ARCHIVE_WRITE(archive, texture.name); - WG_ARCHIVE_WRITE(archive, texture.set); - WG_ARCHIVE_WRITE(archive, texture.binding); - WG_ARCHIVE_WRITE(archive, texture.array_size); - WG_ARCHIVE_WRITE(archive, texture.tex); - - return StatusCode::Ok; - } - Status archive_read(Archive& archive, GfxShaderReflection::Texture& texture) { - WG_AUTO_PROFILE_GFX("GfxShaderReflection::Texture::Archive>>"); - - WG_ARCHIVE_READ(archive, texture.name); - WG_ARCHIVE_READ(archive, texture.set); - WG_ARCHIVE_READ(archive, texture.binding); - WG_ARCHIVE_READ(archive, texture.array_size); - WG_ARCHIVE_READ(archive, texture.tex); - - return StatusCode::Ok; - } - Status archive_write(Archive& archive, const GfxShaderReflection::Buffer& buffer) { - WG_AUTO_PROFILE_GFX("GfxShaderReflection::Buffer::Archive<<"); - - WG_ARCHIVE_WRITE(archive, buffer.name); - WG_ARCHIVE_WRITE(archive, buffer.set); - WG_ARCHIVE_WRITE(archive, buffer.binding); - WG_ARCHIVE_WRITE(archive, buffer.size); - - return StatusCode::Ok; - } - Status archive_read(Archive& archive, GfxShaderReflection::Buffer& buffer) { - WG_AUTO_PROFILE_GFX("GfxShaderReflection::Buffer::Archive>>"); - - WG_ARCHIVE_READ(archive, buffer.name); - WG_ARCHIVE_READ(archive, buffer.set); - WG_ARCHIVE_READ(archive, buffer.binding); - WG_ARCHIVE_READ(archive, buffer.size); - - return StatusCode::Ok; - } - Status archive_write(Archive& archive, const GfxShaderReflection& reflection) { - WG_AUTO_PROFILE_GFX("GfxShaderReflection::Archive<<"); - - WG_ARCHIVE_WRITE(archive, reflection.textures); - WG_ARCHIVE_WRITE(archive, reflection.ub_buffers); - WG_ARCHIVE_WRITE(archive, reflection.sb_buffers); - WG_ARCHIVE_WRITE(archive, reflection.textures_per_desc); - WG_ARCHIVE_WRITE(archive, reflection.ub_buffers_per_desc); - WG_ARCHIVE_WRITE(archive, reflection.sb_buffers_per_desc); - - return StatusCode::Ok; - } - Status archive_read(Archive& archive, GfxShaderReflection& reflection) { - WG_AUTO_PROFILE_GFX("GfxShaderReflection::Archive>>"); - - WG_ARCHIVE_READ(archive, reflection.textures); - WG_ARCHIVE_READ(archive, reflection.ub_buffers); - WG_ARCHIVE_READ(archive, reflection.sb_buffers); - WG_ARCHIVE_READ(archive, reflection.textures_per_desc); - WG_ARCHIVE_READ(archive, reflection.ub_buffers_per_desc); - WG_ARCHIVE_READ(archive, reflection.sb_buffers_per_desc); - - return StatusCode::Ok; - } + WG_IO_BEGIN_NMSP(GfxShaderReflection, Texture) + WG_IO_FIELD(name); + WG_IO_FIELD(set); + WG_IO_FIELD(binding); + WG_IO_FIELD(array_size); + WG_IO_FIELD(tex); + WG_IO_END_NMSP(GfxShaderReflection, Texture) + + WG_IO_BEGIN_NMSP(GfxShaderReflection, Buffer) + WG_IO_FIELD(name); + WG_IO_FIELD(set); + WG_IO_FIELD(binding); + WG_IO_FIELD(size); + WG_IO_END_NMSP(GfxShaderReflection, Buffer) + + WG_IO_BEGIN(GfxShaderReflection) + WG_IO_FIELD(textures); + WG_IO_FIELD(ub_buffers); + WG_IO_FIELD(sb_buffers); + WG_IO_FIELD(textures_per_desc); + WG_IO_FIELD(ub_buffers_per_desc); + WG_IO_FIELD(sb_buffers_per_desc); + WG_IO_END(GfxShaderReflection) }// namespace wmoge \ No newline at end of file diff --git a/engine/gfx/gfx_shader.hpp b/engine/gfx/gfx_shader.hpp index 7a02af394..cff7f63c1 100644 --- a/engine/gfx/gfx_shader.hpp +++ b/engine/gfx/gfx_shader.hpp @@ -32,7 +32,7 @@ #include "core/fast_map.hpp" #include "core/string_id.hpp" #include "gfx/gfx_resource.hpp" -#include "io/archive.hpp" +#include "io/serialization.hpp" #include #include @@ -53,8 +53,7 @@ namespace wmoge { std::int16_t array_size = -1; GfxTex tex = GfxTex::Unknown; - friend Status archive_write(Archive& archive, const Texture& texture); - friend Status archive_read(Archive& archive, Texture& texture); + WG_IO_DECLARE(Texture); }; struct Buffer { StringId name; @@ -62,8 +61,7 @@ namespace wmoge { std::int16_t binding = -1; int size = -1; - friend Status archive_write(Archive& archive, const Buffer& buffer); - friend Status archive_read(Archive& archive, Buffer& buffer); + WG_IO_DECLARE(Buffer); }; fast_map textures; fast_map ub_buffers; @@ -72,8 +70,7 @@ namespace wmoge { std::array ub_buffers_per_desc{}; std::array sb_buffers_per_desc{}; - friend Status archive_write(Archive& archive, const GfxShaderReflection& reflection); - friend Status archive_read(Archive& archive, GfxShaderReflection& reflection); + WG_IO_DECLARE(GfxShaderReflection); }; /** diff --git a/engine/gfx/gfx_vector.hpp b/engine/gfx/gfx_vector.hpp index a1aa12cca..3d5f52cac 100644 --- a/engine/gfx/gfx_vector.hpp +++ b/engine/gfx/gfx_vector.hpp @@ -28,12 +28,12 @@ #ifndef WMOGE_GFX_VECTOR_HPP #define WMOGE_GFX_VECTOR_HPP -#include "core/engine.hpp" #include "core/string_utils.hpp" #include "gfx/gfx_buffers.hpp" #include "gfx/gfx_ctx.hpp" #include "gfx/gfx_driver.hpp" #include "math/math_utils.hpp" +#include "system/engine.hpp" #include #include diff --git a/engine/gfx/threaded/gfx_worker.cpp b/engine/gfx/threaded/gfx_worker.cpp index 631490ca6..cb82d3b9b 100644 --- a/engine/gfx/threaded/gfx_worker.cpp +++ b/engine/gfx/threaded/gfx_worker.cpp @@ -27,8 +27,8 @@ #include "gfx_worker.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" +#include "system/engine.hpp" #include diff --git a/engine/gfx/vulkan/vk_driver.cpp b/engine/gfx/vulkan/vk_driver.cpp index cc6ac6ae3..e78658315 100644 --- a/engine/gfx/vulkan/vk_driver.cpp +++ b/engine/gfx/vulkan/vk_driver.cpp @@ -27,7 +27,6 @@ #include "vk_driver.hpp" -#include "core/engine.hpp" #include "core/string_utils.hpp" #include "core/task.hpp" #include "debug/profiler.hpp" @@ -39,6 +38,7 @@ #include "gfx/vulkan/vk_texture.hpp" #include "platform/file_system.hpp" #include "resource/config_file.hpp" +#include "system/engine.hpp" #include #include diff --git a/engine/gfx/vulkan/vk_pipeline.cpp b/engine/gfx/vulkan/vk_pipeline.cpp index 32c883497..74addd299 100644 --- a/engine/gfx/vulkan/vk_pipeline.cpp +++ b/engine/gfx/vulkan/vk_pipeline.cpp @@ -28,10 +28,10 @@ #include "vk_pipeline.hpp" #include "vk_driver.hpp" -#include "core/engine.hpp" #include "core/task.hpp" #include "core/timer.hpp" #include "debug/profiler.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/gfx/vulkan/vk_shader.cpp b/engine/gfx/vulkan/vk_shader.cpp index 9128fdeba..e7cedc913 100644 --- a/engine/gfx/vulkan/vk_shader.cpp +++ b/engine/gfx/vulkan/vk_shader.cpp @@ -36,20 +36,11 @@ namespace wmoge { - Status archive_read(Archive& archive, VKShaderBinary& binary) { - WG_ARCHIVE_READ(archive, binary.spirvs); - WG_ARCHIVE_READ(archive, binary.layouts); - WG_ARCHIVE_READ(archive, binary.reflection); - - return StatusCode::Ok; - } - Status archive_write(Archive& archive, const VKShaderBinary& binary) { - WG_ARCHIVE_WRITE(archive, binary.spirvs); - WG_ARCHIVE_WRITE(archive, binary.layouts); - WG_ARCHIVE_WRITE(archive, binary.reflection); - - return StatusCode::Ok; - } + WG_IO_BEGIN(VKShaderBinary) + WG_IO_FIELD(spirvs) + WG_IO_FIELD(layouts) + WG_IO_FIELD(reflection) + WG_IO_END(VKShaderBinary) VKShader::VKShader(std::string vertex, std::string fragment, const GfxDescSetLayouts& layouts, const StringId& name, class VKDriver& driver) : VKResource(driver) { diff --git a/engine/gfx/vulkan/vk_shader.hpp b/engine/gfx/vulkan/vk_shader.hpp index a6e52d00c..042eac974 100644 --- a/engine/gfx/vulkan/vk_shader.hpp +++ b/engine/gfx/vulkan/vk_shader.hpp @@ -33,6 +33,7 @@ #include "gfx/gfx_shader.hpp" #include "gfx/vulkan/vk_defs.hpp" #include "gfx/vulkan/vk_resource.hpp" +#include "io/serialization.hpp" #include #include @@ -54,8 +55,7 @@ namespace wmoge { GfxDescSetLayoutDescs layouts; GfxShaderReflection reflection; - friend Status archive_read(Archive& archive, VKShaderBinary& binary); - friend Status archive_write(Archive& archive, const VKShaderBinary& binary); + WG_IO_DECLARE(VKShaderBinary); }; /** diff --git a/engine/gfx/vulkan/vk_window.cpp b/engine/gfx/vulkan/vk_window.cpp index c33ef7278..a11f1fe47 100644 --- a/engine/gfx/vulkan/vk_window.cpp +++ b/engine/gfx/vulkan/vk_window.cpp @@ -27,7 +27,6 @@ #include "vk_window.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" #include "event/event_manager.hpp" #include "event/event_window.hpp" @@ -35,6 +34,7 @@ #include "gfx/vulkan/vk_texture.hpp" #include "math/math_utils.hpp" #include "resource/config_file.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/hgfx/hgfx_pass_base.cpp b/engine/hgfx/hgfx_pass_base.cpp index 316dd3af8..2ef3ab2a4 100644 --- a/engine/hgfx/hgfx_pass_base.cpp +++ b/engine/hgfx/hgfx_pass_base.cpp @@ -28,10 +28,10 @@ #include "hgfx_pass_base.hpp" #include "core/class.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" #include "render/shader_manager.hpp" #include "shaders/generated/auto_base_reflection.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/hgfx/hgfx_pass_text.cpp b/engine/hgfx/hgfx_pass_text.cpp index 9f9467031..3c2fe3cea 100644 --- a/engine/hgfx/hgfx_pass_text.cpp +++ b/engine/hgfx/hgfx_pass_text.cpp @@ -28,11 +28,11 @@ #include "hgfx_pass_text.hpp" #include "core/class.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" #include "math/math_utils3d.hpp" #include "render/shader_manager.hpp" #include "shaders/generated/auto_text_reflection.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/hooks/hook_config.hpp b/engine/hooks/hook_config.hpp index 316b69d30..b61971f94 100644 --- a/engine/hooks/hook_config.hpp +++ b/engine/hooks/hook_config.hpp @@ -25,14 +25,12 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_HOOK_CONFIG_HPP -#define WMOGE_HOOK_CONFIG_HPP +#pragma once #include "core/cmd_line.hpp" -#include "core/engine.hpp" #include "core/hook.hpp" -#include "debug/profiler.hpp" #include "resource/config_file.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -53,9 +51,9 @@ namespace wmoge { cmd_line.add_string("config_game", "path to game config", "root://config/game.cfg"); } - Status on_process(CmdLine& cmd_line, class Engine& engine) override { - ConfigFile* config = engine.config(); - Profiler* profiler = engine.profiler(); + Status on_process(CmdLine& cmd_line) override { + Engine* engine = Engine::instance(); + ConfigFile* config = engine->config(); if (!config->load_and_stack(cmd_line.get_string("config_engine"))) { std::cerr << "failed to load config engine file, check your configure"; @@ -64,12 +62,8 @@ namespace wmoge { std::cerr << "failed to load config game file, check your configure"; } - profiler->set_enabled(config->get_bool(SID("debug.profiler"), false)); - return StatusCode::Ok; } }; -}// namespace wmoge - -#endif//WMOGE_HOOK_CONFIG_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/hooks/hook_logs.hpp b/engine/hooks/hook_logs.hpp index a09eac30d..56694da16 100644 --- a/engine/hooks/hook_logs.hpp +++ b/engine/hooks/hook_logs.hpp @@ -25,15 +25,14 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_HOOK_LOGS_HPP -#define WMOGE_HOOK_LOGS_HPP +#pragma once #include "core/cmd_line.hpp" -#include "core/engine.hpp" #include "core/hook.hpp" #include "core/log.hpp" #include "io/enum.hpp" #include "resource/config_file.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -53,8 +52,9 @@ namespace wmoge { cmd_line.add_bool("disable_logs", "disable all logs entirely (overrides config)", "false"); } - Status on_process(CmdLine& cmd_line, class Engine& engine) override { - ConfigFile* config = engine.config(); + Status on_process(CmdLine& cmd_line) override { + Engine* engine = Engine::instance(); + ConfigFile* config = engine->config(); const bool no_logs = cmd_line.get_bool("disable_logs"); if (no_logs) { @@ -80,7 +80,7 @@ namespace wmoge { WG_LOG_INFO("attach stdout log listener"); } if (log_to_console) { - auto log_listener_console = std::make_shared(engine.console(), log_to_console_level); + auto log_listener_console = std::make_shared(engine->console(), log_to_console_level); Log::instance()->listen(log_listener_console); WG_LOG_INFO("attach console log listener"); } @@ -89,6 +89,4 @@ namespace wmoge { } }; -}// namespace wmoge - -#endif//WMOGE_HOOK_LOGS_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/hooks/hook_profiler.hpp b/engine/hooks/hook_profiler.hpp new file mode 100644 index 000000000..fa700d69b --- /dev/null +++ b/engine/hooks/hook_profiler.hpp @@ -0,0 +1,101 @@ +/**********************************************************************************/ +/* 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/cmd_line.hpp" +#include "core/hook.hpp" +#include "core/log.hpp" +#include "debug/profiler.hpp" +#include "platform/application.hpp" +#include "resource/config_file.hpp" +#include "system/engine.hpp" + +namespace wmoge { + + /** + * @class HookProfiler + * @brief Engine hook to setup profiler of game application + */ + class HookProfiler : public Hook { + public: + ~HookProfiler() override = default; + + std::string get_name() const override { + return "profiler"; + } + + void on_add_cmd_line_options(CmdLine& cmd_line) override { + cmd_line.add_bool("profiler", "enable cpu profiler hook", "false"); + } + + Status on_process(CmdLine& cmd_line) override { + Engine* engine = Engine::instance(); + ConfigFile* config = engine->config(); + Profiler* profiler = engine->profiler(); + Application* application = engine->application(); + + enable_profiler = enable_profiler || cmd_line.get_bool("profiler"); + enable_profiler = enable_profiler || config->get_bool(SID("debug.profiler"), false); + + profiler->set_enabled(enable_profiler); + + if (enable_profiler) { + WG_LOG_INFO("attach cpu performance profiler"); + + application->signal_before_init.bind([this]() { + WG_PROFILE_CAPTURE_START(m_capture_startup, startup, "debug://profile_startup.json"); + }); + application->signal_after_init.bind([this]() { + WG_PROFILE_CAPTURE_END(m_capture_startup); + }); + application->signal_before_loop.bind([this]() { + WG_PROFILE_CAPTURE_START(m_capture_runtime, runtime, "debug://profile_runtime.json"); + }); + application->signal_after_loop.bind([this]() { + WG_PROFILE_CAPTURE_END(m_capture_runtime); + }); + application->signal_before_shutdown.bind([this]() { + WG_PROFILE_CAPTURE_START(m_capture_shutdown, shutdown, "debug://profile_shutdown.json"); + }); + application->signal_after_shutdown.bind([this]() { + WG_PROFILE_CAPTURE_END(m_capture_shutdown); + }); + } + + return StatusCode::Ok; + } + + private: + std::shared_ptr m_capture_startup; + std::shared_ptr m_capture_runtime; + std::shared_ptr m_capture_shutdown; + + bool enable_profiler = false; + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/hooks/hook_root_remap.hpp b/engine/hooks/hook_root_remap.hpp index dfeab4973..c00f15cc3 100644 --- a/engine/hooks/hook_root_remap.hpp +++ b/engine/hooks/hook_root_remap.hpp @@ -25,13 +25,12 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_HOOK_ROOT_REMAP_HPP -#define WMOGE_HOOK_ROOT_REMAP_HPP +#pragma once #include "core/cmd_line.hpp" -#include "core/engine.hpp" #include "core/hook.hpp" #include "platform/file_system.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -51,11 +50,11 @@ namespace wmoge { cmd_line.add_string("root_remap", "remap path to engine root folder", ""); } - Status on_process(CmdLine& cmd_line, class Engine& engine) override { + Status on_process(CmdLine& cmd_line) override { const std::string remap_path = cmd_line.get_string("root_remap"); if (!remap_path.empty()) { - engine.file_system()->root(remap_path); + Engine::instance()->file_system()->root(remap_path); std::cout << "remap exe root to " << remap_path << std::endl; } @@ -63,6 +62,4 @@ namespace wmoge { } }; -}// namespace wmoge - -#endif//WMOGE_HOOK_ROOT_REMAP_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/hooks/hook_uuid_gen.hpp b/engine/hooks/hook_uuid_gen.hpp index b78dfeb61..8e9222ec1 100644 --- a/engine/hooks/hook_uuid_gen.hpp +++ b/engine/hooks/hook_uuid_gen.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_HOOK_UUID_GEN_HPP -#define WMOGE_HOOK_UUID_GEN_HPP +#pragma once #include "core/cmd_line.hpp" #include "core/hook.hpp" @@ -50,7 +49,7 @@ namespace wmoge { cmd_line.add_int("gen_uuids", "gen desired count of uuids' values and outputs them", "0"); } - Status on_process(CmdLine& cmd_line, class Engine& engine) override { + Status on_process(CmdLine& cmd_line) override { const int uuid_count = cmd_line.get_int("gen_uuids"); if (uuid_count > 0) { @@ -64,6 +63,4 @@ namespace wmoge { } }; -}// namespace wmoge - -#endif//WMOGE_HOOK_UUID_GEN_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/io/archive.cpp b/engine/io/archive.cpp index 3f67be4d3..d723dc218 100644 --- a/engine/io/archive.cpp +++ b/engine/io/archive.cpp @@ -29,6 +29,18 @@ namespace wmoge { + Status archive_read(Archive& archive, bool& value) { + char v; + WG_ARCHIVE_READ(archive, v); + value = v != 0; + return StatusCode::Ok; + } + Status archive_write(Archive& archive, const bool& value) { + char v = value ? 1 : 0; + WG_ARCHIVE_WRITE(archive, v); + return StatusCode::Ok; + } + Status archive_write(Archive& archive, const StringId& value) { WG_ARCHIVE_WRITE(archive, value.str()); return StatusCode::Ok; diff --git a/engine/io/archive.hpp b/engine/io/archive.hpp index 9e180ba47..ef025240a 100644 --- a/engine/io/archive.hpp +++ b/engine/io/archive.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ARCHIVE_HPP -#define WMOGE_ARCHIVE_HPP +#pragma once #include "core/log.hpp" #include "core/ref.hpp" @@ -34,7 +33,9 @@ #include "core/string_id.hpp" #include +#include #include +#include #include #include @@ -69,9 +70,6 @@ namespace wmoge { bool m_can_write = false; }; - Status archive_read(Archive& archive, bool& value); - Status archive_write(Archive& archive, const bool& value); - template Status archive_read(Archive& archive, T& value, typename std::enable_if_t>* = nullptr) { assert(archive.can_read()); @@ -94,6 +92,18 @@ namespace wmoge { return archive.nwrite(sizeof(T), &value); } + template + Status archive_read(Archive& archive, std::bitset& bitset) { + return archive.nread(sizeof(std::bitset), &bitset); + } + template + Status archive_write(Archive& archive, const std::bitset& bitset) { + return archive.nwrite(sizeof(std::bitset), &bitset); + } + + Status archive_read(Archive& archive, bool& value); + Status archive_write(Archive& archive, const bool& value); + Status archive_write(Archive& archive, const StringId& value); Status archive_write(Archive& archive, const std::string& value); @@ -114,34 +124,22 @@ namespace wmoge { } \ } while (false) - template - Status archive_write(Archive& archive, const std::array& array) { - for (std::size_t i = 0; i < S; i++) { - WG_ARCHIVE_WRITE(archive, array[i]); - } - return StatusCode::Ok; - } - template - Status archive_write(Archive& archive, const std::vector& vector) { - WG_ARCHIVE_WRITE(archive, vector.size()); - for (const auto& entry : vector) { - WG_ARCHIVE_WRITE(archive, entry); - } - return StatusCode::Ok; - } - template - Status archive_write(Archive& archive, const std::unordered_map& map) { - WG_ARCHIVE_WRITE(archive, map.size()); - for (const auto& entry : map) { - WG_ARCHIVE_WRITE(archive, entry.first); - WG_ARCHIVE_WRITE(archive, entry.second); - } +#define WG_ARCHIVE_READ_SUPER(archive, super, what) \ + WG_ARCHIVE_READ(archive, *((super*) &what)) + +#define WG_ARCHIVE_WRITE_SUPER(archive, super, what) \ + WG_ARCHIVE_WRITE(archive, *((const super*) &what)) + + template + Status archive_read(Archive& archive, std::pair& pair) { + WG_ARCHIVE_READ(archive, pair.first); + WG_ARCHIVE_READ(archive, pair.second); return StatusCode::Ok; } - template - Status archive_write(Archive& archive, const T& enum_value, typename std::enable_if_t>* = nullptr) { - int value = static_cast(enum_value); - WG_ARCHIVE_WRITE(archive, value); + template + Status archive_write(Archive& archive, const std::pair& pair) { + WG_ARCHIVE_WRITE(archive, pair.first); + WG_ARCHIVE_WRITE(archive, pair.second); return StatusCode::Ok; } @@ -152,6 +150,14 @@ namespace wmoge { } return StatusCode::Ok; } + template + Status archive_write(Archive& archive, const std::array& array) { + for (std::size_t i = 0; i < S; i++) { + WG_ARCHIVE_WRITE(archive, array[i]); + } + return StatusCode::Ok; + } + template Status archive_read(Archive& archive, std::vector& vector) { assert(vector.empty()); @@ -163,6 +169,15 @@ namespace wmoge { } return StatusCode::Ok; } + template + Status archive_write(Archive& archive, const std::vector& vector) { + WG_ARCHIVE_WRITE(archive, vector.size()); + for (const auto& entry : vector) { + WG_ARCHIVE_WRITE(archive, entry); + } + return StatusCode::Ok; + } + template Status archive_read(Archive& archive, std::unordered_map& map) { assert(map.empty()); @@ -176,6 +191,16 @@ namespace wmoge { } return StatusCode::Ok; } + template + Status archive_write(Archive& archive, const std::unordered_map& map) { + WG_ARCHIVE_WRITE(archive, map.size()); + for (const auto& entry : map) { + WG_ARCHIVE_WRITE(archive, entry.first); + WG_ARCHIVE_WRITE(archive, entry.second); + } + return StatusCode::Ok; + } + template Status archive_read(Archive& archive, T& enum_value, typename std::enable_if_t>* = nullptr) { int value; @@ -183,6 +208,33 @@ namespace wmoge { enum_value = static_cast(value); return StatusCode::Ok; } + template + Status archive_write(Archive& archive, const T& enum_value, typename std::enable_if_t>* = nullptr) { + int value = static_cast(enum_value); + WG_ARCHIVE_WRITE(archive, value); + return StatusCode::Ok; + } + + template + Status archive_read(Archive& archive, std::optional& opt) { + bool has_value = false; + WG_ARCHIVE_READ(archive, has_value); + if (has_value) { + T v; + WG_ARCHIVE_READ(archive, v); + opt = std::move(v); + } + return StatusCode::Ok; + } + template + Status archive_write(Archive& archive, const std::optional& opt) { + const bool has_value = opt.has_value(); + WG_ARCHIVE_WRITE(archive, has_value); + if (has_value) { + WG_ARCHIVE_WRITE(archive, opt.value()); + } + return StatusCode::Ok; + } template Archive& operator<<(Archive& archive, const T& value) { @@ -203,6 +255,4 @@ namespace wmoge { return archive; } -}// namespace wmoge - -#endif//WMOGE_ARCHIVE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/io/archive_file.hpp b/engine/io/archive_file.hpp index 3b53abd29..180b496f9 100644 --- a/engine/io/archive_file.hpp +++ b/engine/io/archive_file.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ARCHIVE_FILE_HPP -#define WMOGE_ARCHIVE_FILE_HPP +#pragma once #include "archive.hpp" @@ -71,6 +70,4 @@ namespace wmoge { std::fstream& m_stream; }; -}// namespace wmoge - -#endif//WMOGE_ARCHIVE_FILE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/io/archive_memory.hpp b/engine/io/archive_memory.hpp index 161f51627..747c10eee 100644 --- a/engine/io/archive_memory.hpp +++ b/engine/io/archive_memory.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_ARCHIVE_MEMORY_HPP -#define WMOGE_ARCHIVE_MEMORY_HPP +#pragma once #include @@ -80,6 +79,4 @@ namespace wmoge { std::size_t m_pos = 0; }; -}// namespace wmoge - -#endif//WMOGE_ARCHIVE_MEMORY_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/io/base64.hpp b/engine/io/base64.hpp index 680a7d8ae..7080a7c98 100644 --- a/engine/io/base64.hpp +++ b/engine/io/base64.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_BASE64_HPP -#define WMOGE_BASE64_HPP +#pragma once #include "core/data.hpp" #include "core/status.hpp" @@ -52,6 +51,4 @@ namespace wmoge { static Status decode(const std::string_view& data, std::string& result); }; -}// namespace wmoge - -#endif//WMOGE_BASE64_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/io/serialization.hpp b/engine/io/serialization.hpp new file mode 100644 index 000000000..7668be91c --- /dev/null +++ b/engine/io/serialization.hpp @@ -0,0 +1,137 @@ +/**********************************************************************************/ +/* 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/log.hpp" +#include "core/mask.hpp" +#include "core/status.hpp" +#include "io/archive.hpp" +#include "io/yaml.hpp" + +#include + +namespace wmoge { + + enum class IoFlag { + ReadOptional = 0 + }; + + using IoFlags = Mask; + + struct IoTagRead; + struct IoTagWrite; + +#define WG_IO_DECLARE(cls) \ + friend Status yaml_read(const YamlConstNodeRef& node, cls& value); \ + friend Status yaml_write(YamlNodeRef node, const cls& value); \ + friend Status archive_read(Archive& archive, cls& value); \ + friend Status archive_write(Archive& archive, const cls& value); + +#define WG_IO_IMPLEMENT(nmsp, prfx, cls) \ + Status yaml_read(const YamlConstNodeRef& node, prfx##cls& value) { \ + return nmsp##__##cls##Serializer()(node, value); \ + } \ + Status yaml_write(YamlNodeRef node, const prfx##cls& value) { \ + return nmsp##__##cls##Serializer()(node, value); \ + } \ + Status archive_read(Archive& archive, prfx##cls& value) { \ + return nmsp##__##cls##Serializer()(archive, value); \ + } \ + Status archive_write(Archive& archive, const prfx##cls& value) { \ + return nmsp##__##cls##Serializer()(archive, value); \ + } + +#define WG_IO_BEGIN_SUPER(cls, super) \ + template \ + struct __##cls##Serializer final { \ + Status operator()(Stream stream, Target target) { \ + if constexpr (std::is_same_v) { \ + WG_YAML_READ_SUPER(stream, super, target); \ + } \ + if constexpr (std::is_same_v) { \ + WG_YAML_WRITE_SUPER(stream, super, target); \ + } \ + if constexpr (std::is_same_v && std::is_same_v) { \ + WG_ARCHIVE_READ_SUPER(stream, super, target); \ + } \ + if constexpr (std::is_same_v && std::is_same_v) { \ + WG_ARCHIVE_WRITE_SUPER(stream, super, target); \ + } + +#define WG_IO_BEGIN_NMSP(nmsp, cls) \ + template \ + struct nmsp##__##cls##Serializer final { \ + Status operator()(Stream stream, Target target) { \ + if constexpr (std::is_same_v) { \ + WG_YAML_MAP(stream); \ + } + +#define WG_IO_BEGIN(cls) WG_IO_BEGIN_NMSP(, cls) + +#define WG_IO_FIELD_EXT(field, name, flags) \ + if constexpr (std::is_same_v) { \ + const IoFlags mask = flags; \ + if (mask.get(IoFlag::ReadOptional)) { \ + WG_YAML_READ_AS_OPT(stream, name, target.field); \ + } else { \ + WG_YAML_READ_AS(stream, name, target.field); \ + } \ + } \ + if constexpr (std::is_same_v) { \ + WG_YAML_WRITE_AS(stream, name, target.field); \ + } \ + if constexpr (std::is_same_v && std::is_same_v) { \ + WG_ARCHIVE_READ(stream, target.field); \ + } \ + if constexpr (std::is_same_v && std::is_same_v) { \ + WG_ARCHIVE_WRITE(stream, target.field); \ + } + +#define WG_IO_FIELD_OPT(field) WG_IO_FIELD_EXT(field, #field, {IoFlag::ReadOptional}) + +#define WG_IO_FIELD(field) WG_IO_FIELD_EXT(field, #field, {}) + +#define WG_IO_FIELD_AS(field, name) WG_IO_FIELD_EXT(field, name, {}) + +#define WG_IO_END_NMSP(nmsp, cls) \ + return StatusCode::Ok; \ + } \ + ; \ + } \ + ; \ + WG_IO_IMPLEMENT(nmsp, nmsp## ::, cls) + +#define WG_IO_END(cls) \ + return StatusCode::Ok; \ + } \ + ; \ + } \ + ; \ + WG_IO_IMPLEMENT(, , cls) + +}// namespace wmoge \ No newline at end of file diff --git a/engine/io/yaml.cpp b/engine/io/yaml.cpp index 12cd93d29..7e0d11a81 100644 --- a/engine/io/yaml.cpp +++ b/engine/io/yaml.cpp @@ -27,8 +27,8 @@ #include "yaml.hpp" -#include "core/engine.hpp" #include "platform/file_system.hpp" +#include "system/engine.hpp" #include #include @@ -76,6 +76,10 @@ namespace wmoge { } return StatusCode::Ok; } + Status yaml_read(const YamlConstNodeRef& node, std::int16_t& value) { + node >> value; + return StatusCode::Ok; + } Status yaml_write(YamlNodeRef node, const bool& value) { node << value; @@ -97,5 +101,9 @@ namespace wmoge { node << value; return StatusCode::Ok; } + Status yaml_write(YamlNodeRef node, const std::int16_t& value) { + node << value; + return StatusCode::Ok; + } }// namespace wmoge \ No newline at end of file diff --git a/engine/io/yaml.hpp b/engine/io/yaml.hpp index 1c64c0dee..a09726b04 100644 --- a/engine/io/yaml.hpp +++ b/engine/io/yaml.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_YAML_HPP -#define WMOGE_YAML_HPP +#pragma once #include "core/log.hpp" #include "core/ref.hpp" @@ -34,10 +33,12 @@ #include "core/string_id.hpp" #include +#include #include #include #include +#include #include #include #include @@ -87,12 +88,14 @@ namespace wmoge { Status yaml_read(const YamlConstNodeRef& node, float& value); Status yaml_read(const YamlConstNodeRef& node, StringId& value); Status yaml_read(const YamlConstNodeRef& node, std::string& value); + Status yaml_read(const YamlConstNodeRef& node, std::int16_t& value); Status yaml_write(YamlNodeRef node, const bool& value); Status yaml_write(YamlNodeRef node, const int& value); Status yaml_write(YamlNodeRef node, const float& value); Status yaml_write(YamlNodeRef node, const StringId& value); Status yaml_write(YamlNodeRef node, const std::string& value); + Status yaml_write(YamlNodeRef node, const std::int16_t& value); #define WG_YAML_READ(node, what) \ do { \ @@ -169,6 +172,38 @@ namespace wmoge { WG_YAML_READ_AS(node, "value", pair.second); return StatusCode::Ok; } + template + Status yaml_write(YamlNodeRef node, const std::pair& pair) { + WG_YAML_MAP(node); + + YamlNodeRef key = node.append_child(); + WG_YAML_WRITE_AS(key, "key", pair.first); + + YamlNodeRef value = node.append_child(); + WG_YAML_WRITE_AS(value, "value", pair.second); + + return StatusCode::Ok; + } + + template + Status yaml_read(const YamlConstNodeRef& node, robin_hood::pair& pair) { + WG_YAML_READ_AS(node, "key", pair.first); + WG_YAML_READ_AS(node, "value", pair.second); + return StatusCode::Ok; + } + template + Status yaml_write(YamlNodeRef node, const robin_hood::pair& pair) { + WG_YAML_MAP(node); + + YamlNodeRef key = node.append_child(); + WG_YAML_WRITE_AS(key, "key", pair.first); + + YamlNodeRef value = node.append_child(); + WG_YAML_WRITE_AS(value, "value", pair.second); + + return StatusCode::Ok; + } + template Status yaml_read(const YamlConstNodeRef& node, std::array& array) { std::size_t element_id = 0; @@ -178,6 +213,16 @@ namespace wmoge { } return StatusCode::Ok; } + template + Status yaml_write(YamlNodeRef node, const std::array& array) { + WG_YAML_SEQ(node); + for (std::size_t i = 0; i < S; i++) { + YamlNodeRef child = node.append_child(); + WG_YAML_WRITE(child, array[i]); + } + return StatusCode::Ok; + } + template Status yaml_read(const YamlConstNodeRef& node, std::vector& vector) { assert(vector.empty()); @@ -189,6 +234,16 @@ namespace wmoge { } return StatusCode::Ok; } + template + Status yaml_write(YamlNodeRef node, const std::vector& vector) { + WG_YAML_SEQ(node); + for (const T& value : vector) { + YamlNodeRef child = node.append_child(); + WG_YAML_WRITE(child, value); + } + return StatusCode::Ok; + } + template Status yaml_read(const YamlConstNodeRef& node, std::unordered_map& map) { assert(map.empty()); @@ -200,6 +255,16 @@ namespace wmoge { } return StatusCode::Ok; } + template + Status yaml_write(YamlNodeRef node, const std::unordered_map& map) { + WG_YAML_SEQ(node); + for (const auto& entry : map) { + YamlNodeRef entry_child = node.append_child(); + WG_YAML_WRITE(entry_child, entry); + } + return StatusCode::Ok; + } + template::value>::type> Status yaml_read(const YamlConstNodeRef& node, T& enum_value) { std::string s; @@ -211,64 +276,47 @@ namespace wmoge { enum_value = parsed.value(); return StatusCode::Ok; } + template::value>::type> + Status yaml_write(YamlNodeRef node, const T& enum_value) { + node << std::string(magic_enum::enum_name(enum_value)); + return StatusCode::Ok; + } + template Status yaml_read(const YamlConstNodeRef& node, std::optional& wrapper) { wrapper.emplace(); WG_YAML_READ(node, wrapper.value()); return StatusCode::Ok; } - - template - Status yaml_write(YamlNodeRef node, const std::pair& pair) { - WG_YAML_MAP(node); - - YamlNodeRef key = node.append_child(); - WG_YAML_WRITE_AS(key, "key", pair.first); - - YamlNodeRef value = node.append_child(); - WG_YAML_WRITE_AS(value, "value", pair.second); - - return StatusCode::Ok; - } - template - Status yaml_write(YamlNodeRef node, const std::array& array) { - WG_YAML_SEQ(node); - for (std::size_t i = 0; i < S; i++) { - YamlNodeRef child = node.append_child(); - WG_YAML_WRITE(child, array[i]); - } - return StatusCode::Ok; - } template - Status yaml_write(YamlNodeRef node, const std::vector& vector) { - WG_YAML_SEQ(node); - for (const T& value : vector) { - YamlNodeRef child = node.append_child(); - WG_YAML_WRITE(child, value); - } + Status yaml_write(YamlNodeRef node, const std::optional& wrapper) { + assert(wrapper.has_value()); + WG_YAML_WRITE(node, wrapper.value()); return StatusCode::Ok; } - template - Status yaml_write(YamlNodeRef node, const std::unordered_map& map) { - WG_YAML_SEQ(node); - for (const auto& entry : map) { - YamlNodeRef entry_child = node.append_child(); - WG_YAML_WRITE(entry_child, entry); + + template + Status yaml_read(const YamlConstNodeRef& node, std::bitset& bitset) { + std::array values; + WG_YAML_READ(node, values); + for (int i = 0; i < N; i++) { + if (values[i]) { + bitset.set(i); + } } return StatusCode::Ok; } - template::value>::type> - Status yaml_write(YamlNodeRef node, const T& enum_value) { - node << std::string(magic_enum::enum_name(enum_value)); - return StatusCode::Ok; - } - template - Status yaml_write(YamlNodeRef node, const std::optional& wrapper) { - assert(wrapper.has_value()); - WG_YAML_WRITE(node, wrapper.value()); + template + Status yaml_write(YamlNodeRef node, const std::bitset& bitset) { + std::array values; + values.fill(false); + for (int i = 0; i < N; i++) { + if (bitset.test(i)) { + values[i] = true; + } + } + WG_YAML_WRITE(node, values); return StatusCode::Ok; } -}// namespace wmoge - -#endif//WMOGE_YAML_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/main/main.cpp b/engine/main/main.cpp deleted file mode 100644 index 950fe6af8..000000000 --- a/engine/main/main.cpp +++ /dev/null @@ -1,298 +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. */ -/**********************************************************************************/ - -#include "main.hpp" - -#include "audio/openal/al_engine.hpp" -#include "core/callback_queue.hpp" -#include "core/class.hpp" -#include "core/cmd_line.hpp" -#include "core/engine.hpp" -#include "core/hook.hpp" -#include "core/layer.hpp" -#include "core/log.hpp" -#include "core/task_manager.hpp" -#include "debug/console.hpp" -#include "debug/debug_layer.hpp" -#include "debug/profiler.hpp" -#include "ecs/ecs_registry.hpp" -#include "event/event_manager.hpp" -#include "gameplay/action_manager.hpp" -#include "gameplay/game_token_manager.hpp" -#include "gfx/vulkan/vk_driver.hpp" -#include "io/enum.hpp" -#include "platform/application.hpp" -#include "platform/file_system.hpp" -#include "platform/glfw/glfw_window_manager.hpp" -#include "platform/input.hpp" -#include "platform/window_manager.hpp" -#include "render/aux_draw_manager.hpp" -#include "render/canvas.hpp" -#include "render/render_engine.hpp" -#include "render/shader_manager.hpp" -#include "render/texture_manager.hpp" -#include "resource/config_file.hpp" -#include "resource/resource_manager.hpp" -#include "scene/scene_manager.hpp" -#include "scripting/lua/lua_script_system.hpp" -#include "scripting/script_system.hpp" - -#include - -namespace wmoge { - - Main::Main(Application* application) { - auto* engine = Engine::instance(); - - engine->m_application = application; - - m_layer_stack = std::make_unique(); - engine->m_layer_stack = m_layer_stack.get(); - - m_hook_list = std::make_unique(); - engine->m_hook_list = m_hook_list.get(); - - m_cmd_line = std::make_unique(); - engine->m_cmd_line = m_cmd_line.get(); - - m_config = std::make_unique(); - engine->m_config = m_config.get(); - - m_file_system = std::make_unique(); - engine->m_file_system = m_file_system.get(); - - m_console = std::make_unique(); - engine->m_console = m_console.get(); - - m_profiler = std::make_unique(); - engine->m_profiler = m_profiler.get(); - - WG_LOG_INFO("init essential"); - } - - Main::~Main() = default; - - bool Main::initialize() { - WG_AUTO_PROFILE_PLATFORM("Main::initialize"); - - auto* engine = Engine::instance(); - auto* config = engine->config(); - - Class::register_types(); - WG_LOG_INFO("init core classes reflection"); - - m_event_manager = std::make_unique(); - engine->m_event_manager = m_event_manager.get(); - WG_LOG_INFO("init event manager"); - - m_task_manager = std::make_unique(config->get_int(SID("task_manager.workers"), 4)); - engine->m_task_manager = m_task_manager.get(); - WG_LOG_INFO("init task manager"); - - m_main_queue = std::make_unique(); - engine->m_main_queue = m_main_queue.get(); - WG_LOG_INFO("init main queue"); - - engine->application()->on_register(); - - WindowInfo window_info; - window_info.width = config->get_int(SID("window.width"), 1280); - window_info.height = config->get_int(SID("window.height"), 720); - window_info.title = config->get_string(SID("window.title"), "wmoge"); - window_info.icons[0] = make_ref(); - window_info.icons[0]->load(config->get_string(SID("window.icon_default")), 4); - window_info.icons[1] = make_ref(); - window_info.icons[1]->load(config->get_string(SID("window.icon_small")), 4); - - bool vsync = config->get_bool(SID("window.vsync"), true); - bool exit = config->get_bool(SID("window.exit"), true); - - m_glfw_window_manager = std::make_unique(vsync, false); - engine->m_window_manager = m_glfw_window_manager.get(); - engine->m_input = m_glfw_window_manager->input().get(); - WG_LOG_INFO("init window system"); - - auto window = m_glfw_window_manager->create(window_info); - WG_LOG_INFO("init window " << window_info.id); - - VKInitInfo init_info; - init_info.window = window; - init_info.app_name = window_info.title; - init_info.engine_name = "wmoge"; - init_info.required_ext = m_glfw_window_manager->extensions(); - init_info.factory = m_glfw_window_manager->factory(); - - m_vk_driver = std::make_unique(std::move(init_info)); - engine->m_gfx_driver = m_vk_driver->driver_wrapper(); - engine->m_gfx_ctx = m_vk_driver->ctx_immediate_wrapper(); - - m_al_engine = std::make_unique(); - engine->m_audio_engine = m_al_engine.get(); - - m_lua_script_system = std::make_unique(); - engine->m_script_system = m_lua_script_system.get(); - - m_shader_manager = std::make_unique(); - engine->m_shader_manager = m_shader_manager.get(); - - m_texture_manager = std::make_unique(); - engine->m_texture_manager = m_texture_manager.get(); - - m_render_engine = std::make_unique(); - engine->m_render_engine = m_render_engine.get(); - - m_resource_manager = std::make_unique(); - engine->m_resource_manager = m_resource_manager.get(); - - m_ecs_registry = std::make_unique(); - engine->m_ecs_registry = m_ecs_registry.get(); - - m_aux_draw_manager = std::make_unique(); - engine->m_aux_draw_manager = m_aux_draw_manager.get(); - - m_scene_manager = std::make_unique(); - engine->m_scene_manager = m_scene_manager.get(); - - m_action_manager = std::make_unique(); - engine->m_action_manager = m_action_manager.get(); - - m_game_token_manager = std::make_unique(); - engine->m_game_token_manager = m_game_token_manager.get(); - - m_canvas_debug = std::make_unique(); - engine->m_canvas_debug = m_canvas_debug.get(); - - m_console->init(); - WG_LOG_INFO("init high level systems"); - - m_dbg_layer = std::make_shared(); - m_layer_stack->attach(m_dbg_layer); - WG_LOG_INFO("init debug layer"); - - engine->application()->on_init(); - - if (exit) { - engine->event_manager()->subscribe([](const EventWindow& event) { - auto engine = Engine::instance(); - if (event.window == engine->window_manager()->primary_window() && - event.notification == WindowNotification::CloseRequested) - engine->request_close(); - return false; - }); - - WG_LOG_INFO("configure exit on primary window close"); - } - - m_time_point = clock::now(); - - return true; - } - bool Main::iteration() { - WG_AUTO_PROFILE_PLATFORM("Main::iteration"); - - m_num_iterations += 1; - - auto* engine = Engine::instance(); - auto* gfx_driver = engine->gfx_driver(); - - auto new_point = clock::now(); - auto t = float(double(std::chrono::duration_cast(new_point - m_runtime_time).count()) * 1e-9); - auto dt = float(double(std::chrono::duration_cast(new_point - m_time_point).count()) * 1e-9); - m_time_point = new_point; - - engine->m_iteration = m_num_iterations; - engine->m_time = t; - engine->m_current_delta = dt; - engine->m_current_delta_game = Math::min(dt, 1.0f / 20.0f); - - m_layer_stack->each_up([](LayerStack::LayerPtr& layer) { - layer->on_start_frame(); - }); - - gfx_driver->begin_frame(); - gfx_driver->prepare_window(m_glfw_window_manager->primary_window()); - - m_glfw_window_manager->poll_events(); - m_main_queue->flush(); - m_event_manager->flush(); - m_action_manager->update(); - m_scene_manager->update(); - - m_layer_stack->each_up([](LayerStack::LayerPtr& layer) { - layer->on_debug_draw(); - }); - - gfx_driver->end_frame(); - - m_layer_stack->each_down([](LayerStack::LayerPtr& layer) { - layer->on_end_frame(); - }); - - gfx_driver->swap_buffers(m_glfw_window_manager->primary_window()); - - return true; - } - bool Main::shutdown() { - WG_AUTO_PROFILE_PLATFORM("Main::shutdown"); - - auto* engine = Engine::instance(); - - engine->application()->on_shutdown(); - - m_layer_stack->clear(); - m_resource_manager->clear(); - m_task_manager->shutdown(); - m_main_queue->flush(); - m_console->shutdown(); - m_scene_manager->clear(); - m_event_manager->flush(); - - m_lua_script_system.reset(); - m_scene_manager.reset(); - m_game_token_manager.reset(); - m_action_manager.reset(); - m_aux_draw_manager.reset(); - m_canvas_debug.reset(); - m_ecs_registry.reset(); - m_render_engine.reset(); - m_texture_manager.reset(); - m_shader_manager.reset(); - m_al_engine.reset(); - m_vk_driver.reset(); - m_glfw_window_manager.reset(); - m_main_queue.reset(); - m_task_manager.reset(); - m_event_manager.reset(); - m_resource_manager.reset(); - m_hook_list.reset(); - - WG_LOG_INFO("shutdown engine systems"); - - return true; - } - -}// namespace wmoge \ No newline at end of file diff --git a/engine/main/main.hpp b/engine/main/main.hpp deleted file mode 100644 index aa32b53b0..000000000 --- a/engine/main/main.hpp +++ /dev/null @@ -1,93 +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. */ -/**********************************************************************************/ - -#ifndef WMOGE_MAIN_HPP -#define WMOGE_MAIN_HPP - -#include -#include -#include -#include - -namespace wmoge { - - /** - * @class Main - * @brief Control engine execution: initialization, runtime, and shutdown - * - * Main is an internal singleton class, which is responsible for engine - * start-up, sub-systems initialization and de-initialization, and per - * frame update. - */ - class Main { - public: - explicit Main(class Application* application); - ~Main(); - - bool initialize(); - bool iteration(); - bool shutdown(); - - private: - using clock = std::chrono::steady_clock; - using time_point = clock::time_point; - using ns = std::chrono::nanoseconds; - - std::size_t m_num_iterations = 0; - time_point m_time_point{}; - time_point m_runtime_time{}; - - std::shared_ptr m_dbg_layer; - std::unique_ptr m_layer_stack; - std::unique_ptr m_hook_list; - std::unique_ptr m_cmd_line; - std::unique_ptr m_config; - std::unique_ptr m_main_queue; - std::unique_ptr m_file_system; - std::unique_ptr m_task_manager; - std::unique_ptr m_event_manager; - std::unique_ptr m_resource_manager; - std::unique_ptr m_aux_draw_manager; - std::unique_ptr m_scene_manager; - std::unique_ptr m_action_manager; - std::unique_ptr m_game_token_manager; - std::unique_ptr m_profiler; - std::unique_ptr m_console; - std::unique_ptr m_canvas_debug; - std::unique_ptr m_shader_manager; - std::unique_ptr m_texture_manager; - std::unique_ptr m_render_engine; - std::unique_ptr m_ecs_registry; - std::unique_ptr m_glfw_window_manager; - std::unique_ptr m_vk_driver; - std::unique_ptr m_al_engine; - std::unique_ptr m_lua_script_system; - }; - -}// namespace wmoge - -#endif//WMOGE_MAIN_HPP diff --git a/engine/math/aabb.hpp b/engine/math/aabb.hpp index 8b2819d8f..d0efc4974 100644 --- a/engine/math/aabb.hpp +++ b/engine/math/aabb.hpp @@ -25,9 +25,9 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_AABB_HPP -#define WMOGE_AABB_HPP +#pragma once +#include "io/archive.hpp" #include "io/yaml.hpp" #include "math/mat.hpp" #include "math/vec.hpp" @@ -123,7 +123,17 @@ namespace wmoge { WG_YAML_WRITE_AS(node, "size_half", aabb.size_half); return StatusCode::Ok; } + template + Status archive_read(Archive& archive, TAabb& aabb) { + WG_ARCHIVE_READ(archive, aabb.pos); + WG_ARCHIVE_READ(archive, aabb.size_half); + return StatusCode::Ok; + } + template + Status archive_write(Archive& archive, const TAabb& aabb) { + WG_ARCHIVE_WRITE(archive, aabb.pos); + WG_ARCHIVE_WRITE(archive, aabb.size_half); + return StatusCode::Ok; + } -}// namespace wmoge - -#endif//WMOGE_AABB_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/frustum.hpp b/engine/math/frustum.hpp index 4e28de3f8..a0e32444d 100644 --- a/engine/math/frustum.hpp +++ b/engine/math/frustum.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_FRUSTUM_HPP -#define WMOGE_FRUSTUM_HPP +#pragma once #include "math/aabb.hpp" #include "math/math_utils.hpp" @@ -139,6 +138,4 @@ namespace wmoge { using Frustumf = TFrustum; -}// namespace wmoge - -#endif//WMOGE_FRUSTUM_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/mat.hpp b/engine/math/mat.hpp index 017dce03c..a913c7d06 100644 --- a/engine/math/mat.hpp +++ b/engine/math/mat.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MAT_HPP -#define WMOGE_MAT_HPP +#pragma once #include #include @@ -428,6 +427,4 @@ namespace wmoge { } }; -}// namespace wmoge - -#endif//WMOGE_MAT_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/math_utils.hpp b/engine/math/math_utils.hpp index b9bbc7341..43c96da46 100644 --- a/engine/math/math_utils.hpp +++ b/engine/math/math_utils.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MATH_UTILS_HPP -#define WMOGE_MATH_UTILS_HPP +#pragma once #include #include @@ -242,6 +241,4 @@ namespace wmoge { }; }; -}// namespace wmoge - -#endif//WMOGE_MATH_UTILS_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/math_utils3d.hpp b/engine/math/math_utils3d.hpp index b3f59ec09..18e59ea29 100644 --- a/engine/math/math_utils3d.hpp +++ b/engine/math/math_utils3d.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MATH_UTILS3D_HPP -#define WMOGE_MATH_UTILS3D_HPP +#pragma once #include "mat.hpp" #include "math_utils.hpp" @@ -184,6 +183,15 @@ namespace wmoge { 0.0f, 0.0f, -1.0f, 0.0f); } + static Mat4x4f perspective_inv(float fov, float aspect, float near, float far) { + float ctg_angle = 1.0f / Math::tan(fov / 2.0f); + + return Mat4x4f(aspect / ctg_angle, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f / ctg_angle, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, -1.0f, + 0.0f, 0.0f, (near - far) / (2 * far * near), (far + near) / (2 * far * near)); + } + /** * @brief Orthographic projection * @@ -222,6 +230,4 @@ namespace wmoge { } }; -}// namespace wmoge - -#endif//WMOGE_MATH_UTILS3D_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/plane.hpp b/engine/math/plane.hpp index b8bb927aa..1ecc4efb9 100644 --- a/engine/math/plane.hpp +++ b/engine/math/plane.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_PLANE_HPP -#define WMOGE_PLANE_HPP +#pragma once #include "math/vec.hpp" @@ -85,6 +84,4 @@ namespace wmoge { using Planef = TPlane; -}// namespace wmoge - -#endif//WMOGE_PLANE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/quat.hpp b/engine/math/quat.hpp index 4a3776d02..52b27b6d4 100644 --- a/engine/math/quat.hpp +++ b/engine/math/quat.hpp @@ -25,9 +25,9 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_QUAT_HPP -#define WMOGE_QUAT_HPP +#pragma once +#include "io/archive.hpp" #include "io/yaml.hpp" #include "math/mat.hpp" #include "math/vec.hpp" @@ -451,6 +451,14 @@ namespace wmoge { WG_YAML_WRITE_AS(node, "vec", quat.vec); return StatusCode::Ok; } + template + Status archive_read(Archive& archive, TQuat& quat) { + return archive.nread(sizeof(TQuat), &quat); + } + template + Status archive_write(Archive& archive, const TQuat& quat) { + return archive.nwrite(sizeof(TQuat), &quat); + } }// namespace wmoge @@ -464,6 +472,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_QUAT_HPP +}// namespace std \ No newline at end of file diff --git a/engine/math/range.hpp b/engine/math/range.hpp index 825b27dfa..e8d0564ae 100644 --- a/engine/math/range.hpp +++ b/engine/math/range.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_RANGE_HPP -#define WMOGE_RANGE_HPP +#pragma once #include "math/math_utils.hpp" @@ -68,6 +67,4 @@ namespace wmoge { int m_to = -1; }; -}// namespace wmoge - -#endif//WMOGE_RANGE_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/transform.hpp b/engine/math/transform.hpp index 389013589..882de3cca 100644 --- a/engine/math/transform.hpp +++ b/engine/math/transform.hpp @@ -25,10 +25,9 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_TRANSFORM_HPP -#define WMOGE_TRANSFORM_HPP +#pragma once -#include "io/yaml.hpp" +#include "io/serialization.hpp" #include "math/mat.hpp" #include "math/math_utils2d.hpp" #include "math/math_utils3d.hpp" @@ -83,6 +82,19 @@ namespace wmoge { WG_YAML_WRITE_AS(node, "rotation", transform.m_rotation); WG_YAML_WRITE_AS(node, "translation", transform.m_translation); WG_YAML_WRITE_AS(node, "scale", transform.m_scale); + + return StatusCode::Ok; + } + friend Status archive_read(Archive& archive, Transform2d& transform) { + WG_ARCHIVE_READ(archive, transform.m_rotation); + WG_ARCHIVE_READ(archive, transform.m_translation); + WG_ARCHIVE_READ(archive, transform.m_scale); + return StatusCode::Ok; + } + friend Status archive_write(Archive& archive, const Transform2d& transform) { + WG_ARCHIVE_WRITE(archive, transform.m_rotation); + WG_ARCHIVE_WRITE(archive, transform.m_translation); + WG_ARCHIVE_WRITE(archive, transform.m_scale); return StatusCode::Ok; } @@ -103,6 +115,8 @@ namespace wmoge { } void set_translation(const Vec3f& translation) { m_translation = translation; } + void set_rotation(const Quatf& quat) { m_rotation = quat; } + void set_scale(const Vec3f& s) { m_scale = s; } void translate(const Vec3f& offset) { m_translation += offset; } void rotate(const Vec3f& axis, float rad) { m_rotation = Quatf(axis, rad) * m_rotation; } @@ -111,6 +125,28 @@ namespace wmoge { void rotate_z(float rad) { m_rotation = Quatf(Vec3f::axis_z(), rad) * m_rotation; } void scale(const Vec3f& scale) { m_scale *= scale; } + Vec3f transform(const Vec3f& v) const { + return m_translation + m_rotation.rotate(m_scale * v); + } + + Transform3d operator*(const Transform3d& other) const { + // v' = t1 + r1(s1 * v) + // v'' = t2 + r2(s2 * v') + // = t2 + r2(s2 * t1 + s2 * r1(s1 * v)) + // = (t2 + r2(s2 * t1)) + r2(s2 * r1(s1 * v)) + // = (t2 + r2(s2 * t1)) + r2(r1(r1^-1(s2) * s1 * v))) + // + // t' = t2 + r2(s2 * t1) + // r' = r2 x r1 + // s' = r1^-1(s2) * s1 + + Transform3d result; + result.set_translation(m_translation + transform(other.m_translation)); + result.set_rotation(m_rotation * other.m_rotation); + result.set_scale(other.m_rotation.conjugate().rotate(m_scale) * other.m_scale); + return result; + } + [[nodiscard]] Mat4x4f get_transform() const { return Math3d::translate(m_translation) * m_rotation.as_matrix() * @@ -138,6 +174,19 @@ namespace wmoge { WG_YAML_WRITE_AS(node, "rotation", transform.m_rotation); WG_YAML_WRITE_AS(node, "translation", transform.m_translation); WG_YAML_WRITE_AS(node, "scale", transform.m_scale); + + return StatusCode::Ok; + } + friend Status archive_read(Archive& archive, Transform3d& transform) { + WG_ARCHIVE_READ(archive, transform.m_rotation); + WG_ARCHIVE_READ(archive, transform.m_translation); + WG_ARCHIVE_READ(archive, transform.m_scale); + return StatusCode::Ok; + } + friend Status archive_write(Archive& archive, const Transform3d& transform) { + WG_ARCHIVE_WRITE(archive, transform.m_rotation); + WG_ARCHIVE_WRITE(archive, transform.m_translation); + WG_ARCHIVE_WRITE(archive, transform.m_scale); return StatusCode::Ok; } @@ -204,6 +253,18 @@ namespace wmoge { return StatusCode::Ok; } + friend Status archive_read(Archive& archive, TransformEdt& transform) { + WG_ARCHIVE_READ(archive, transform.m_rotation); + WG_ARCHIVE_READ(archive, transform.m_translation); + WG_ARCHIVE_READ(archive, transform.m_scale); + return StatusCode::Ok; + } + friend Status archive_write(Archive& archive, const TransformEdt& transform) { + WG_ARCHIVE_WRITE(archive, transform.m_rotation); + WG_ARCHIVE_WRITE(archive, transform.m_translation); + WG_ARCHIVE_WRITE(archive, transform.m_scale); + return StatusCode::Ok; + } private: Vec3f m_rotation; @@ -211,6 +272,4 @@ namespace wmoge { Vec3f m_scale; }; -}// namespace wmoge - -#endif//WMOGE_TRANSFORM_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/math/vec.hpp b/engine/math/vec.hpp index e51a32259..d2d97d1f8 100644 --- a/engine/math/vec.hpp +++ b/engine/math/vec.hpp @@ -25,12 +25,11 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_VEC_HPP -#define WMOGE_VEC_HPP - -#include "math_utils.hpp" +#pragma once +#include "io/archive.hpp" #include "io/yaml.hpp" +#include "math_utils.hpp" #include #include @@ -83,6 +82,25 @@ namespace wmoge { values[M] = a; } + template + TVecN(T a, const TVecN& v) : TVecN() { + static_assert(N >= M + 1, "Out of bounds index assignment"); + values[0] = a; + for (int i = 0; i < M; i++) { + values[i + 1] = v.values[i]; + } + } + + template + TVecN(T a, T b, const TVecN& v) : TVecN() { + static_assert(N >= M + 2, "Out of bounds index assignment"); + values[0] = a; + values[1] = b; + for (int i = 0; i < M; i++) { + values[i + 2] = v.values[i]; + } + } + TVecN(const std::initializer_list& list) noexcept : TVecN() { int i = 0; for (const auto& a : list) { @@ -656,6 +674,16 @@ namespace wmoge { return yaml_write(node, stream.str()); } + template + Status archive_read(Archive& archive, TVecN& v) { + return archive.nread(sizeof(TVecN), &v); + } + + template + Status archive_write(Archive& archive, const TVecN& v) { + return archive.nwrite(sizeof(TVecN), &v); + } + }// namespace wmoge namespace std { @@ -668,6 +696,4 @@ namespace std { } }; -}// namespace std - -#endif//WMOGE_VEC_HPP +}// namespace std \ No newline at end of file diff --git a/engine/mesh/mesh_batch.cpp b/engine/mesh/mesh_batch.cpp index 1b4901ed9..e7b9d3ab4 100644 --- a/engine/mesh/mesh_batch.cpp +++ b/engine/mesh/mesh_batch.cpp @@ -27,7 +27,6 @@ #include "mesh_batch.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" #include "gfx/gfx_driver.hpp" #include "mesh/mesh_bucket.hpp" @@ -35,9 +34,9 @@ #include "render/render_engine.hpp" #include "render/render_scene.hpp" #include "render/shader_manager.hpp" -#include "render/vertex_factory.hpp" #include "resource/material.hpp" #include "resource/shader.hpp" +#include "system/engine.hpp" namespace wmoge { @@ -75,48 +74,26 @@ namespace wmoge { batch.material->validate(); - const Ref& shader = batch.material->get_shader(); - const ShaderPipelineState pipeline_state = shader->get_pipeline_state(); - const int primitive_id = batch.object->get_primitive_id(); - const bool supports_merging = batch.vertex_factory->get_type_info().supports_merging; + const Ref& shader = batch.material->get_shader(); + const ShaderPipelineState pipeline_state = shader->get_pipeline_state(); for (int cam_idx = 0; cam_idx < int(m_cameras->get_size()); cam_idx++) { if (!batch.cam_mask[cam_idx]) { continue; } - const RenderCameraData& camera = m_cameras->data_at(cam_idx); - const MeshPassRelevance& relevance = camera.pass_relevance; - RenderView& view = m_views[cam_idx]; + const CameraData& camera = m_cameras->data_at(cam_idx); + RenderView& view = m_views[cam_idx]; for (int pass_id = 0; pass_id < MESH_PASSES_TOTAL; pass_id++) { const MeshPassType pass_type = static_cast(pass_id); - if (!relevance.get(pass_type)) { - continue; - } if (!m_processors[pass_id] || !m_processors[pass_id]->filter(batch)) { continue; } Ref gfx_pso; - if (batch.pass_list && batch.pass_list->has_pass(pass_type)) { - gfx_pso = batch.pass_list->get_pass(pass_type).value(); - } - if (!gfx_pso) { - Status result = m_processors[pass_id]->compile(batch, gfx_pso); - - if (result.is_error()) { - WG_LOG_ERROR("failed to compile pass " << m_processors[pass_id]->get_name() << " for batch=" << batch_index); - continue; - } - - if (batch.pass_list) { - batch.pass_list->add_pass(gfx_pso, pass_type); - } - } - RenderCmd cmd; cmd.index_setup = batch.index_buffer; cmd.desc_sets[0] = view.view_set.get(); @@ -124,16 +101,14 @@ namespace wmoge { cmd.desc_sets[1] = batch.material->get_desc_set().get(); cmd.desc_sets_slots[1] = 1; cmd.pipeline = gfx_pso.get(); - cmd.call_params = batch.elements[0].draw_call; + cmd.call_params = batch.draw_call; cmd.primitive_buffer = 0; - batch.vertex_factory->fill_setup(VertexInputType::Default, cmd.vert_buffers, cmd.primitive_buffer); - RenderCmdKey cmd_key; RenderCmd* final_cmd; int bucket_slot = -1; - if (cmd.call_params.instances == 1 && supports_merging) { + if (cmd.call_params.instances == 1 /*&& supports_merging*/) { MeshBucketMap& bucket_map = m_scene->get_bucket_map(pass_type); bucket_map.add_for_instancing(cmd, final_cmd, bucket_slot); cmd_key.value = (std::uint64_t(bucket_slot) << 32u) | std::uint64_t(batch.dist); @@ -144,10 +119,10 @@ namespace wmoge { } SortableRenderCmd sortable_cmd; - sortable_cmd.cmd = final_cmd; - sortable_cmd.cmd_key = cmd_key; - sortable_cmd.bucket_slot = bucket_slot; - sortable_cmd.primitive_id = primitive_id; + sortable_cmd.cmd = final_cmd; + sortable_cmd.cmd_key = cmd_key; + sortable_cmd.bucket_slot = bucket_slot; + // sortable_cmd.primitive_id = primitive_id; view.queues[pass_id].push(sortable_cmd); } @@ -161,7 +136,7 @@ namespace wmoge { void MeshBatchCompiler::set_views(ArrayView views) { m_views = views; } - void MeshBatchCompiler::set_cameras(RenderCameras& cameras) { + void MeshBatchCompiler::set_cameras(CameraList& cameras) { m_cameras = &cameras; } void MeshBatchCompiler::set_cmd_allocator(RenderCmdAllocator& allocator) { diff --git a/engine/mesh/mesh_batch.hpp b/engine/mesh/mesh_batch.hpp index 494e033a1..47bfb1eca 100644 --- a/engine/mesh/mesh_batch.hpp +++ b/engine/mesh/mesh_batch.hpp @@ -25,14 +25,12 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MESH_BATCH_HPP -#define WMOGE_MESH_BATCH_HPP +#pragma once #include "core/array_view.hpp" #include "core/fast_vector.hpp" #include "core/status.hpp" #include "core/synchronization.hpp" -#include "core/unrolled_list.hpp" #include "gfx/gfx_buffers.hpp" #include "gfx/gfx_desc_set.hpp" #include "gfx/gfx_dynamic_buffers.hpp" @@ -41,7 +39,7 @@ #include "math/aabb.hpp" #include "math/mat.hpp" #include "mesh/mesh_pass.hpp" -#include "render/render_camera.hpp" +#include "render/camera.hpp" #include #include @@ -51,32 +49,20 @@ namespace wmoge { - /** - * @class MeshBatchElement - * @brief Single instance of a mesh batch subset with unique transform to draw - */ - struct MeshBatchElement final { - StringId name; //< Unique element name for debug - GfxDrawCall draw_call;//< Params to dispatch a draw - }; - - static_assert(std::is_trivially_destructible_v, "mesh element must be trivial as possible"); - /** * @class MeshBatch * @brief Batch of mesh elements with the same vertex/index buffer and material instances */ struct MeshBatch final { - MeshBatchElement elements[1]; //< List of batch elements to draw - GfxIndexBufferSetup index_buffer; //< Optional index buffer with batch indices - RenderCameraMask cam_mask; //< Mask in which cameras mesh batch wants to be rendered - class VertexFactory* vertex_factory = nullptr; //< Vertex factory to provide vertex data and format - class Material* material = nullptr; //< Material to apply to rendered elements - class GfxDescSet* mesh_params = nullptr; //< Mesh descriptor set with batch common resources - class MeshPassList* pass_list = nullptr; //< Cached list with mesh passes for faster RenderCmd generation - class RenderObject* object = nullptr; //< Render object this batch belongs to - GfxPrimType prim_type = GfxPrimType::Triangles;//< Type of primitives to render - float dist = 0.0f; //< Distance from camera for sorting + StringId name; //< Unique element name for debug + GfxDrawCall draw_call; //< Params to dispatch a draw + GfxIndexBufferSetup index_buffer; //< Optional index buffer with batch indices + RenderCameraMask cam_mask; //< Mask in which cameras mesh batch wants to be rendered + class Material* material = nullptr; //< Material to apply to rendered elements + class GfxDescSet* mesh_params = nullptr; //< Mesh descriptor set with batch common resources + class MeshPassList* pass_list = nullptr; //< Cached list with mesh passes for faster RenderCmd generation + GfxPrimType prim_type = GfxPrimType::Triangles;//< Type of primitives to render + float dist = 0.0f; //< Distance from camera for sorting }; static_assert(std::is_trivially_destructible_v, "mesh batch must be trivial as possible"); @@ -87,7 +73,7 @@ namespace wmoge { * * Allows to collect mesh batches (draw requests) from any type of render objects. * Mesh batch allows to translate draw request from user code to engine code. - * Engine itself can compile batches and work with the in the unified and optimized way. + * Engine itself can compile batches and work with them in the unified and optimized way. */ class MeshBatchCollector final { public: @@ -134,7 +120,7 @@ namespace wmoge { Status compile_batch(const MeshBatch& batch, int batch_index); void set_scene(class RenderScene* scene); void set_views(ArrayView views); - void set_cameras(class RenderCameras& cameras); + void set_cameras(class CameraList& cameras); void set_cmd_allocator(class RenderCmdAllocator& allocator); void clear(); @@ -144,13 +130,11 @@ namespace wmoge { ArrayView m_views; class RenderCmdAllocator* m_cmd_allocator = nullptr; - class RenderCameras* m_cameras = nullptr; class RenderScene* m_scene = nullptr; class ShaderManager* m_shader_manager = nullptr; + class CameraList* m_cameras = nullptr; class GfxDriver* m_driver = nullptr; class GfxCtx* m_ctx = nullptr; }; -}// namespace wmoge - -#endif//WMOGE_MESH_BATCH_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/mesh/mesh_bucket.hpp b/engine/mesh/mesh_bucket.hpp index f337cccf1..6b1389019 100644 --- a/engine/mesh/mesh_bucket.hpp +++ b/engine/mesh/mesh_bucket.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MESH_BUCKET_HPP -#define WMOGE_MESH_BUCKET_HPP +#pragma once #include "core/fast_map.hpp" #include "core/synchronization.hpp" @@ -119,6 +118,4 @@ namespace wmoge { std::atomic_uint32_t m_primitive_offset{0}; }; -}// namespace wmoge - -#endif//WMOGE_MESH_BUCKET_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/mesh/mesh_builder.cpp b/engine/mesh/mesh_builder.cpp index abbbb43f6..8483934c0 100644 --- a/engine/mesh/mesh_builder.cpp +++ b/engine/mesh/mesh_builder.cpp @@ -39,182 +39,72 @@ namespace wmoge { m_mesh = std::move(mesh); } - void MeshBuilder::add_index(std::uint32_t i) { - m_indices.push_back(i); - m_num_indices += 1; - } - - void MeshBuilder::add_triangle(std::uint32_t v0, std::uint32_t v1, std::uint32_t v2) { - add_index(v0); - add_index(v1); - add_index(v2); - } - - void MeshBuilder::add_vertex(const MeshVertex& v) { - const GfxVertAttribs& attribs = v.attribs; - - if (!attribs.bits.any()) { - WG_LOG_ERROR("passed vertex with no attributes to add"); - return; - } - - if (attribs.get(GfxVertAttrib::Pos3f)) { - m_pos3.push_back(v.pos3); - } - if (attribs.get(GfxVertAttrib::Pos2f)) { - m_pos2.push_back(v.pos2); - } - if (attribs.get(GfxVertAttrib::Norm3f)) { - m_norm.push_back(v.norm); - } - if (attribs.get(GfxVertAttrib::Tang3f)) { - m_tang.push_back(v.tang); - } - if (attribs.get(GfxVertAttrib::BoneIds4i)) { - m_bone_ids.push_back(v.bone_ids); - } - if (attribs.get(GfxVertAttrib::BoneWeights4f)) { - m_bone_weights.push_back(v.bone_weights); - } - if (attribs.get(GfxVertAttrib::Col04f)) { - m_col[0].push_back(v.col[0]); - } - if (attribs.get(GfxVertAttrib::Col14f)) { - m_col[1].push_back(v.col[1]); - } - if (attribs.get(GfxVertAttrib::Col24f)) { - m_col[2].push_back(v.col[2]); - } - if (attribs.get(GfxVertAttrib::Col34f)) { - m_col[3].push_back(v.col[3]); - } - if (attribs.get(GfxVertAttrib::Uv02f)) { - m_uv[0].push_back(v.uv[0]); - } - if (attribs.get(GfxVertAttrib::Uv12f)) { - m_uv[1].push_back(v.uv[1]); - } - if (attribs.get(GfxVertAttrib::Uv22f)) { - m_uv[2].push_back(v.uv[2]); - } - if (attribs.get(GfxVertAttrib::Uv32f)) { - m_uv[3].push_back(v.uv[3]); - } + void MeshBuilder::add_chunk(const StringId& name, const Ref& data) { + assert(data); - m_num_vertices += 1; + m_chunks.push_back(data); + m_chunks_names.push_back(name); + m_chunks_parents.push_back(-1); + m_chunks_children.emplace_back(); } - void MeshBuilder::add_chunk(const MeshChunk& chunk) { - m_chunks.push_back(chunk); + void MeshBuilder::add_child(int parent_idx, int child_idx) { + m_chunks_children[parent_idx].push_back(child_idx); + m_chunks_parents[child_idx] = parent_idx; } Status MeshBuilder::build() { - if (m_num_vertices == 0) { - WG_LOG_ERROR("no vertices to build"); - return StatusCode::InvalidData; - } - if (m_num_indices == 0) { - WG_LOG_ERROR("no indices to build"); - return StatusCode::InvalidData; - } - if (m_chunks.empty()) { - WG_LOG_ERROR("no chunks to build"); - return StatusCode::InvalidData; - } + const GfxVertAttribs attribs_stream1 = {GfxVertAttrib::Pos3f, GfxVertAttrib::Pos2f, GfxVertAttrib::Norm3f, GfxVertAttrib::Tang3f}; + const GfxVertAttribs attribs_stream2 = {GfxVertAttrib::BoneIds4i, GfxVertAttrib::BoneWeights4f}; + const GfxVertAttribs attribs_stream3 = {GfxVertAttrib::Col04f, GfxVertAttrib::Col14f, GfxVertAttrib::Col24f, GfxVertAttrib::Col34f, GfxVertAttrib::Uv02f, GfxVertAttrib::Uv12f, GfxVertAttrib::Uv22f, GfxVertAttrib::Uv32f}; + const GfxVertAttribsStreams stream_masks = {attribs_stream1, attribs_stream2, attribs_stream3}; - GfxVertAttribs attribs; + int curr_vert_buffer = 0; + int curr_index_buffer = 0; + int curr_vert_stream = 0; + int curr_index_stream = 0; - if (!m_pos3.empty()) { - attribs.set(GfxVertAttrib::Pos3f); - } - if (!m_norm.empty()) { - attribs.set(GfxVertAttrib::Norm3f); - } - if (!m_tang.empty()) { - attribs.set(GfxVertAttrib::Tang3f); - } - if (!m_bone_ids.empty()) { - attribs.set(GfxVertAttrib::BoneIds4i); - } - if (!m_bone_weights.empty()) { - attribs.set(GfxVertAttrib::BoneWeights4f); - } - if (!m_col[0].empty()) { - attribs.set(GfxVertAttrib::Col04f); - } - if (!m_col[1].empty()) { - attribs.set(GfxVertAttrib::Col14f); - } - if (!m_col[2].empty()) { - attribs.set(GfxVertAttrib::Col24f); - } - if (!m_col[3].empty()) { - attribs.set(GfxVertAttrib::Col34f); - } - if (!m_uv[0].empty()) { - attribs.set(GfxVertAttrib::Uv02f); - } - if (!m_uv[1].empty()) { - attribs.set(GfxVertAttrib::Uv12f); - } - if (!m_uv[2].empty()) { - attribs.set(GfxVertAttrib::Uv22f); - } - if (!m_uv[3].empty()) { - attribs.set(GfxVertAttrib::Uv32f); - } + const int n_chunks = int(m_chunks.size()); + + for (int i = 0; i < n_chunks; i++) { + Ref vert_data; + fast_vector vert_streams; + m_chunks[i]->pack_attribs(stream_masks, vert_data, vert_streams); - int stride = 0; - - attribs.for_each([&](int i, GfxVertAttrib attrib) { - stride += GfxVertAttribSizes[i]; - }); - - Ref vert_data = make_ref(m_num_vertices * stride); - Ref ind_data = make_ref(m_num_indices * sizeof(std::uint32_t)); - - std::memcpy(ind_data->buffer(), m_indices.data(), m_indices.size() * sizeof(std::uint32_t)); - - int offset = 0; - - const void* attribs_data[] = { - m_pos3.data(), - m_pos2.data(), - m_norm.data(), - m_tang.data(), - m_bone_ids.data(), - m_bone_weights.data(), - m_col[0].data(), - m_col[1].data(), - m_col[2].data(), - m_col[3].data(), - m_uv[0].data(), - m_uv[1].data(), - m_uv[2].data(), - m_uv[3].data()}; - - attribs.for_each([&](int i, GfxVertAttrib attrib) { - const auto* src_ptr = reinterpret_cast(attribs_data[i]); - auto* dst_ptr = reinterpret_cast(vert_data->buffer()) + offset; - - for (int vert_id = 0; vert_id < m_num_vertices; vert_id += 1) { - std::memcpy(dst_ptr, src_ptr, GfxVertAttribSizes[i]); - src_ptr += GfxVertAttribSizes[i]; - dst_ptr += stride; + for (auto& vert_stream : vert_streams) { + vert_stream.buffer = curr_vert_buffer; } - offset += GfxVertAttribSizes[i]; - }); + Ref index_data; + GfxIndexStream index_stream; + m_chunks[i]->pack_faces(index_data, index_stream); + + index_stream.buffer = curr_index_buffer; + m_mesh->add_intex_stream(index_stream); + + MeshChunk chunk; + chunk.name = m_chunks_names[i]; + chunk.aabb = m_chunks[i]->get_data().aabb; + chunk.attribs = m_chunks[i]->get_data().attribs; + chunk.index_stream = curr_index_stream; + chunk.vert_stream_offset = curr_vert_stream; + chunk.vert_stream_count = int(vert_streams.size()); + chunk.prim_type = GfxPrimType::Triangles; + chunk.elem_count = m_chunks[i]->get_num_faces() * 3; + chunk.parent = m_chunks_parents[i]; + chunk.children = m_chunks_children[i]; + m_mesh->add_chunk(chunk); - assert(m_mesh); + m_mesh->add_vertex_buffer(vert_data); + m_mesh->add_index_buffer(index_data); - for (const MeshChunk& chunk : m_chunks) { - m_mesh->add_chunk(chunk); + curr_index_stream += 1; + curr_vert_stream += int(vert_streams.size()); + + curr_vert_buffer += 1; + curr_index_buffer += 1; } - m_mesh->set_vertex_params(m_num_vertices, GfxPrimType::Triangles); - m_mesh->set_vertex_buffer(0, vert_data, attribs); - m_mesh->set_index_buffer(ind_data, m_num_indices, GfxIndexType::Uint32); m_mesh->update_aabb(); m_mesh->update_gfx_buffers(); diff --git a/engine/mesh/mesh_builder.hpp b/engine/mesh/mesh_builder.hpp index 1205f85eb..ae5c16235 100644 --- a/engine/mesh/mesh_builder.hpp +++ b/engine/mesh/mesh_builder.hpp @@ -25,34 +25,19 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MESH_BUILDER_HPP -#define WMOGE_MESH_BUILDER_HPP +#pragma once +#include "core/fast_vector.hpp" #include "core/status.hpp" #include "gfx/gfx_defs.hpp" #include "math/vec.hpp" +#include "resource/array_mesh.hpp" #include "resource/mesh.hpp" #include namespace wmoge { - /** - * @class MeshVertex - * @brief Holds the data of a single vertex - */ - struct MeshVertex { - Vec3f pos3; - Vec2f pos2; - Vec3f norm; - Vec3f tang; - Vec4i bone_ids; - Vec4f bone_weights; - Vec4f col[4]; - Vec2f uv[4]; - GfxVertAttribs attribs; - }; - /** * @class MeshBuilder * @brief Utility class to build a mesh from arrays @@ -60,35 +45,20 @@ namespace wmoge { class MeshBuilder { public: void set_mesh(Ref mesh); - void add_index(std::uint32_t i); - void add_triangle(std::uint32_t v0, std::uint32_t v1, std::uint32_t v2); - void add_vertex(const MeshVertex& v); - void add_chunk(const MeshChunk& chunk); + void add_chunk(const StringId& name, const Ref& data); + void add_child(int parent_idx, int child_idx); Status build(); [[nodiscard]] const Ref& get_mesh() const { return m_mesh; } - [[nodiscard]] int get_num_vertices() const { return m_num_vertices; } - [[nodiscard]] int get_num_indices() const { return m_num_indices; } private: - std::vector m_chunks; - std::vector m_indices; - std::vector m_pos3; - std::vector m_pos2; - std::vector m_norm; - std::vector m_tang; - std::vector m_bone_ids; - std::vector m_bone_weights; - std::vector m_col[4]; - std::vector m_uv[4]; - - int m_num_vertices = 0; - int m_num_indices = 0; + std::vector> m_chunks; + std::vector m_chunks_names; + std::vector m_chunks_parents; + std::vector> m_chunks_children; Ref m_mesh; }; -}// namespace wmoge - -#endif//WMOGE_MESH_BUILDER_HPP +}// namespace wmoge \ No newline at end of file diff --git a/engine/mesh/mesh_pass.cpp b/engine/mesh/mesh_pass.cpp index 5c7015144..e801b9c07 100644 --- a/engine/mesh/mesh_pass.cpp +++ b/engine/mesh/mesh_pass.cpp @@ -27,7 +27,7 @@ #include "mesh_pass.hpp" -#include "core/engine.hpp" +#include "system/engine.hpp" #include @@ -37,11 +37,11 @@ namespace wmoge { return m_mask.get(pass_type); } - std::optional> MeshPassList::get_pass(MeshPassType pass_type) const { + std::optional MeshPassList::get_pass(MeshPassType pass_type) { if (m_mask.get(pass_type)) { for (std::size_t i = 0; i < get_size(); i++) { - if (m_types[i] == pass_type) { - return m_pipelines[i]; + if (m_passes[i].pass_type == pass_type) { + return &m_passes[i]; } } @@ -51,25 +51,20 @@ namespace wmoge { return std::nullopt; } - void MeshPassList::add_pass(Ref pass, MeshPassType pass_type, bool overwrite) { - assert(pass); - - if (!m_mask.get(pass_type)) { - m_pipelines.push_back(std::move(pass)); - m_types.push_back(pass_type); - m_mask.set(pass_type); + void MeshPassList::add_pass(MeshPass&& pass, bool overwrite) { + if (!m_mask.get(pass.pass_type)) { + m_passes.push_back(std::move(pass)); + m_mask.set(m_passes.back().pass_type); return; } if (overwrite) { for (std::size_t i = 0; i < get_size(); i++) { - if (m_types[i] == pass_type) { - m_pipelines[i] = std::move(pass); + if (m_passes[i].pass_type == pass.pass_type) { + m_passes[i] = std::move(pass); return; } } - - assert(false && "Invalid invariant of mask state and list state"); } } diff --git a/engine/mesh/mesh_pass.hpp b/engine/mesh/mesh_pass.hpp index 51aaeafe6..1a526bb15 100644 --- a/engine/mesh/mesh_pass.hpp +++ b/engine/mesh/mesh_pass.hpp @@ -25,14 +25,15 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MESH_PASS_HPP -#define WMOGE_MESH_PASS_HPP +#pragma once #include "core/array_view.hpp" #include "core/fast_vector.hpp" #include "core/mask.hpp" #include "core/status.hpp" +#include "gfx/gfx_buffers.hpp" #include "gfx/gfx_pipeline.hpp" +#include "gfx/gfx_vert_format.hpp" #include @@ -41,44 +42,49 @@ namespace wmoge { /** @brief Supported engine mesh pass types */ enum class MeshPassType { Background = 0,//< - Shadow, //< Shadow cache generation for lights - GBuffer, //< GBuffer generation for opaque geometry - Forward, //< - Pfx, //< Particles simulation + Shadow, //< Pass: Shadow cache generation for lights + GBuffer, //< Pass: GBuffer generation for opaque geometry + Forward, //< Pass: Forward for transparent geometry and complex shading Ui, //< Outline, //< Overlay, //< - Total = 8 + Total = 7 }; /** @brief Total num of mesh passes */ static constexpr int MESH_PASSES_TOTAL = static_cast(MeshPassType::Total); - /** @brief Mask of mesh passes */ - using MeshPassRelevance = Mask; + /** + * @class MeshPass + * @brief Compiled state required to draw a mesh subset into a particular pass + */ + struct MeshPass { + GfxVertBuffersSetup vert_setup; + GfxIndexBufferSetup index_setup; + Ref format; + Ref pipeline; + MeshPassType pass_type = MeshPassType::Total; + }; /** * @class MeshPassList * @brief List with compiled PSO states to render mesh in multiple passes - */ + */ class MeshPassList { public: static constexpr int NUM_PASSES_INLINE = 3; - bool has_pass(MeshPassType pass_type) const; - std::optional> get_pass(MeshPassType pass_type) const; - void add_pass(Ref pass, MeshPassType pass_type, bool overwrite = true); + bool has_pass(MeshPassType pass_type) const; + std::optional get_pass(MeshPassType pass_type); + void add_pass(MeshPass&& pass, bool overwrite = true); - [[nodiscard]] ArrayView> get_pipelines() const { return m_pipelines; } - [[nodiscard]] ArrayView get_types() const { return m_types; } - [[nodiscard]] const Mask& get_mask() const { return m_mask; } - [[nodiscard]] std::size_t get_size() const { return m_pipelines.size(); } - [[nodiscard]] bool is_empty() const { return m_pipelines.empty(); } + [[nodiscard]] const Mask& get_mask() const { return m_mask; } + [[nodiscard]] std::size_t get_size() const { return m_passes.size(); } + [[nodiscard]] bool is_empty() const { return m_passes.empty(); } private: - fast_vector, NUM_PASSES_INLINE> m_pipelines; - fast_vector m_types; - Mask m_mask; + fast_vector m_passes; + Mask m_mask; }; /** @@ -100,6 +106,4 @@ namespace wmoge { class GfxDriver* m_gfx_driver = nullptr; }; -}// namespace wmoge - -#endif//WMOGE_MESH_PASS_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/mesh/mesh_processors.cpp b/engine/mesh/mesh_processors.cpp index 136b3ed0c..f14c52b25 100644 --- a/engine/mesh/mesh_processors.cpp +++ b/engine/mesh/mesh_processors.cpp @@ -31,7 +31,6 @@ #include "gfx/gfx_driver.hpp" #include "mesh/mesh_batch.hpp" #include "render/shader_manager.hpp" -#include "render/vertex_factory.hpp" #include "resource/material.hpp" #include "resource/shader.hpp" @@ -53,14 +52,12 @@ namespace wmoge { } GfxVertAttribs attribs; - batch.vertex_factory->fill_required_attributes(attribs, VertexInputType::Default); // additional attribute to fetch gpu data attribs.set(GfxVertAttrib::PrimitiveIdi); GfxPipelineState gfx_pso_state; gfx_pso_state.shader = m_shader_manager->get_shader(shader->get_domain(), attribs, defines, shader); - gfx_pso_state.vert_format = batch.vertex_factory->get_vert_format(VertexInputType::Default); gfx_pso_state.prim_type = batch.prim_type; gfx_pso_state.poly_mode = pipeline_state.poly_mode; gfx_pso_state.cull_mode = pipeline_state.cull_mode; diff --git a/engine/mesh/mesh_processors.hpp b/engine/mesh/mesh_processors.hpp index 386c150ed..fd0d83329 100644 --- a/engine/mesh/mesh_processors.hpp +++ b/engine/mesh/mesh_processors.hpp @@ -25,8 +25,7 @@ /* SOFTWARE. */ /**********************************************************************************/ -#ifndef WMOGE_MESH_PROCESSORS_HPP -#define WMOGE_MESH_PROCESSORS_HPP +#pragma once #include "mesh/mesh_pass.hpp" @@ -47,6 +46,4 @@ namespace wmoge { MeshPassType get_pass_type() const override; }; -}// namespace wmoge - -#endif//WMOGE_MESH_PROCESSORS_HPP \ No newline at end of file +}// namespace wmoge \ No newline at end of file diff --git a/engine/pfx/pfx_emitter.cpp b/engine/pfx/pfx_emitter.cpp index 6b62436e2..9907d469b 100644 --- a/engine/pfx/pfx_emitter.cpp +++ b/engine/pfx/pfx_emitter.cpp @@ -27,9 +27,9 @@ #include "pfx_emitter.hpp" -#include "core/engine.hpp" #include "debug/profiler.hpp" #include "resource/pfx_effect.hpp" +#include "system/engine.hpp" namespace wmoge { diff --git a/engine/platform/application.cpp b/engine/platform/application.cpp index 4be63cb3d..263afaeed 100644 --- a/engine/platform/application.cpp +++ b/engine/platform/application.cpp @@ -27,32 +27,74 @@ #include "application.hpp" +#include "audio/openal/al_engine.hpp" +#include "core/callback_queue.hpp" +#include "core/class.hpp" #include "core/cmd_line.hpp" -#include "core/engine.hpp" #include "core/hook.hpp" +#include "core/ioc_container.hpp" +#include "core/layer.hpp" +#include "core/log.hpp" +#include "core/task_manager.hpp" +#include "debug/console.hpp" +#include "debug/debug_layer.hpp" #include "debug/profiler.hpp" +#include "ecs/ecs_registry.hpp" +#include "event/event_manager.hpp" +#include "gameplay/action_manager.hpp" +#include "gameplay/game_token_manager.hpp" +#include "gfx/vulkan/vk_driver.hpp" #include "hooks/hook_config.hpp" #include "hooks/hook_logs.hpp" +#include "hooks/hook_profiler.hpp" #include "hooks/hook_root_remap.hpp" #include "hooks/hook_uuid_gen.hpp" -#include "main/main.hpp" +#include "io/enum.hpp" +#include "platform/application.hpp" +#include "platform/file_system.hpp" +#include "platform/glfw/glfw_window_manager.hpp" +#include "platform/input.hpp" +#include "platform/time.hpp" +#include "platform/window_manager.hpp" +#include "render/aux_draw_manager.hpp" +#include "render/canvas.hpp" +#include "render/render_engine.hpp" +#include "render/shader_manager.hpp" +#include "render/texture_manager.hpp" +#include "resource/config_file.hpp" +#include "resource/resource_manager.hpp" +#include "scene/scene_manager.hpp" +#include "scripting/lua/lua_script_system.hpp" +#include "scripting/script_system.hpp" +#include "system/engine.hpp" + +#include "event/register_classes_event.hpp" +#include "pfx/register_classes_pfx.hpp" +#include "resource/register_classes_resource.hpp" +#include "scene/register_classes_scene.hpp" namespace wmoge { + Status Application::on_register() { + IocContainer* ioc = IocContainer::instance(); + + ioc->bind(); + ioc->bind(); + + return StatusCode::Ok; + } + int Application::run(int argc, const char* const* argv) { - Main main(this); + IocContainer* ioc = IocContainer::instance(); - auto* engine = Engine::instance(); - auto* hook_list = engine->hook_list(); - auto* cmd_line = engine->cmd_line(); + on_register(); + CmdLine* cmd_line = ioc->resolve().value(); cmd_line->add_bool("h,help", "display help message", "false"); - hook_list->attach(std::make_shared()); - hook_list->attach(std::make_shared()); - hook_list->attach(std::make_shared()); - hook_list->attach(std::make_shared()); + on_hook(); + HookList* hook_list = ioc->resolve().value(); hook_list->each([&](HookList::HookPtr& hook) { hook->on_add_cmd_line_options(*cmd_line); return false; @@ -69,7 +111,7 @@ namespace wmoge { std::optional ret_code; hook_list->each([&](HookList::HookPtr& hook) { - const Status status = hook->on_process(*cmd_line, *engine); + const Status status = hook->on_process(*cmd_line); const StatusCode code = status.code(); if (code == StatusCode::ExitCode0) { @@ -94,33 +136,162 @@ namespace wmoge { return ret_code.value(); } - WG_PROFILE_CAPTURE_START(startup, "debug://wmoge_profile_startup.json"); + signal_before_init.emit(); + { + WG_AUTO_PROFILE_PLATFORM("Application::initialize"); - if (!main.initialize()) { - return 1; + if (!on_init()) { + return 1; + } } + signal_after_init.emit(); - WG_PROFILE_CAPTURE_END(startup); + signal_before_loop.emit(); - WG_PROFILE_CAPTURE_START(runtime, "debug://wmoge_profile_runtime.json"); + while (!should_close()) { + WG_AUTO_PROFILE_PLATFORM("Application::iteration"); - while (!engine->close_requested()) { - if (!main.iteration()) { + if (!on_loop()) { return 1; } } - WG_PROFILE_CAPTURE_END(runtime); + signal_after_loop.emit(); - WG_PROFILE_CAPTURE_START(shutdown, "debug://wmoge_profile_shutdown.json"); + signal_before_shutdown.emit(); + { + WG_AUTO_PROFILE_PLATFORM("Application::shutdown"); - if (!main.shutdown()) { - return 1; + if (!on_shutdown()) { + return 1; + } } + signal_after_shutdown.emit(); - WG_PROFILE_CAPTURE_END(shutdown); + ioc->clear(); return 0; } + Status BaseApplication::on_register() { + Application::on_register(); + + Class::register_types(); + register_classes_event(); + register_classes_resource(); + register_classes_pfx(); + register_classes_scene(); + + IocContainer* ioc = IocContainer::instance(); + + ioc->bind