From 7dd89e3cc405ee732c947582e65a67149aafa958 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Fri, 20 Feb 2026 13:43:16 +0700 Subject: [PATCH 01/17] fix(intent-storage) - actually clean up oops memory leaked --- .../game/components/render/intent_handle.h | 2 +- include/game/systems/render/material_intent.h | 6 +++--- include/game/systems/render/rotation_intent.h | 4 ++-- include/game/systems/render/sprite_intent.h | 20 +++++++++---------- include/game/systems/render/text_intent.h | 16 +++++++-------- include/system/intent_storage.h | 11 +++++++--- src/engine/intent_storage.cpp | 12 +++++------ src/windows/scenes/intent_api.cpp | 10 +++++----- src/windows/windows_main.c | 1 + 9 files changed, 44 insertions(+), 38 deletions(-) diff --git a/include/game/components/render/intent_handle.h b/include/game/components/render/intent_handle.h index 403a0f4..b2f9a81 100644 --- a/include/game/components/render/intent_handle.h +++ b/include/game/components/render/intent_handle.h @@ -7,7 +7,7 @@ namespace Game::Render { size_t handle_id; - IntentHandle() : handle_id(System::RenderStorage::alloc_slot()) + IntentHandle() : handle_id(System::Render::IntentStorage::alloc_slot()) {} explicit IntentHandle(const size_t handle_id) : handle_id(handle_id) {} diff --git a/include/game/systems/render/material_intent.h b/include/game/systems/render/material_intent.h index d48af61..127b1d3 100644 --- a/include/game/systems/render/material_intent.h +++ b/include/game/systems/render/material_intent.h @@ -9,19 +9,19 @@ namespace Game::Render for (auto &[id, comps]: query) { const size_t &intent_id = comps.get().handle_id; - std::optional &intent = System::RenderStorage::get_intent(intent_id); + std::optional &intent = System::Render::IntentStorage::get_intent(intent_id); const Material &material = comps.get(); if (!intent.has_value()) { - intent = System::DrawIntent{}; + intent = System::Render::DrawIntent{}; } auto &common = intent.value().common; common.vert_shader = material.vert_shader; common.pixel_shader = material.pixel_shader; common.visible = material.visible; common.render_prior = material.render_prior; - common.color = System::Color(material.color.r, material.color.g, material.color.b, material.color.a); + common.color = System::Render::Color(material.color.r, material.color.g, material.color.b, material.color.a); } } } // namespace Game::Render diff --git a/include/game/systems/render/rotation_intent.h b/include/game/systems/render/rotation_intent.h index 1ce989f..8c17c1d 100644 --- a/include/game/systems/render/rotation_intent.h +++ b/include/game/systems/render/rotation_intent.h @@ -8,12 +8,12 @@ namespace Game::Render for (auto &[id, comps]: query) { const size_t &intent_id = comps.get().handle_id; - std::optional &intent = System::RenderStorage::get_intent(intent_id); + std::optional &intent = System::Render::IntentStorage::get_intent(intent_id); const Rotation &rotation = comps.get(); if (!intent.has_value()) { - intent = System::DrawIntent{}; + intent = System::Render::DrawIntent{}; } auto &common = intent.value().common; diff --git a/include/game/systems/render/sprite_intent.h b/include/game/systems/render/sprite_intent.h index 02d483a..d23adef 100644 --- a/include/game/systems/render/sprite_intent.h +++ b/include/game/systems/render/sprite_intent.h @@ -9,27 +9,27 @@ namespace Game::Render for (auto &[id, comps]: query) { const size_t &intent_id = comps.get().handle_id; - std::optional &intent = System::RenderStorage::get_intent(intent_id); + std::optional &intent = System::Render::IntentStorage::get_intent(intent_id); const Sprite &sprite = comps.get(); if (!intent.has_value()) { - intent = System::DrawIntent{}; + intent = System::Render::DrawIntent{}; } switch (intent.value().kind) { - case System::DrawKind::KIND_UNKNOWN: - intent.value().kind = System::DrawKind::KIND_SPRITE; - case System::DrawKind::KIND_SPRITE: + case System::Render::DrawKind::KIND_UNKNOWN: + intent.value().kind = System::Render::DrawKind::KIND_SPRITE; + case System::Render::DrawKind::KIND_SPRITE: break; default: return; } - if (!std::holds_alternative(intent.value().special)) + if (!std::holds_alternative(intent.value().special)) { - intent.value().special = System::SpriteDrawDesc{}; + intent.value().special = System::Render::SpriteDrawDesc{}; } auto &common = intent.value().common; @@ -37,10 +37,10 @@ namespace Game::Render common.order = sprite.order; auto &[texture, src_rect, dst_rect, flipX, flipY] = - std::get(intent.value().special); + std::get(intent.value().special); texture = sprite.texture; - src_rect = System::Rect{sprite.src_rect.u0, sprite.src_rect.v0, sprite.src_rect.u1, sprite.src_rect.v1}; - dst_rect = System::Rect{sprite.dst_rect.u0, sprite.dst_rect.v0, sprite.dst_rect.u1, sprite.dst_rect.v1}; + src_rect = System::Render::Rect{sprite.src_rect.u0, sprite.src_rect.v0, sprite.src_rect.u1, sprite.src_rect.v1}; + dst_rect = System::Render::Rect{sprite.dst_rect.u0, sprite.dst_rect.v0, sprite.dst_rect.u1, sprite.dst_rect.v1}; flipX = sprite.flipX; flipY = sprite.flipY; } diff --git a/include/game/systems/render/text_intent.h b/include/game/systems/render/text_intent.h index acc53d6..a9a9f2c 100644 --- a/include/game/systems/render/text_intent.h +++ b/include/game/systems/render/text_intent.h @@ -8,30 +8,30 @@ namespace Game::Render for (auto &[id, comps]: query) { const size_t &intent_id = comps.get().handle_id; - std::optional &intent = System::RenderStorage::get_intent(intent_id); + std::optional &intent = System::Render::IntentStorage::get_intent(intent_id); const Text &text_component = comps.get(); if (!intent.has_value()) { - intent = System::DrawIntent{}; + intent = System::Render::DrawIntent{}; } switch (intent.value().kind) { - case System::DrawKind::KIND_UNKNOWN: - intent.value().kind = System::DrawKind::KIND_TEXT; - case System::DrawKind::KIND_TEXT: + case System::Render::DrawKind::KIND_UNKNOWN: + intent.value().kind = System::Render::DrawKind::KIND_TEXT; + case System::Render::DrawKind::KIND_TEXT: break; default: return; } - if (!std::holds_alternative(intent.value().special)) + if (!std::holds_alternative(intent.value().special)) { - intent.value().special = System::TextDrawDesc{}; + intent.value().special = System::Render::TextDrawDesc{}; } - auto &[text, font_name, font_size] = std::get(intent.value().special); + auto &[text, font_name, font_size] = std::get(intent.value().special); text = std::string_view(text_component.text); font_name = text_component.font_name; font_size = text_component.font_size; diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index c6d348b..6a42823 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -4,7 +4,7 @@ #include #include -namespace System +namespace System::Render { // Common enum class DrawKind : uint8_t @@ -129,7 +129,12 @@ namespace System } as{}; }; - class RenderStorage + struct Camera + { + + }; + + class IntentStorage { // TODO: Change storage from any to DrawDescription std::vector> _intent_storage{}; @@ -138,7 +143,7 @@ namespace System public: static size_t alloc_slot(); static void free_slot(size_t slot); - static RenderStorage &instance(); + static IntentStorage &instance(); static std::optional &get_intent(size_t slot); }; } // namespace System diff --git a/src/engine/intent_storage.cpp b/src/engine/intent_storage.cpp index fc1f2f4..b048bc4 100644 --- a/src/engine/intent_storage.cpp +++ b/src/engine/intent_storage.cpp @@ -2,14 +2,14 @@ #include "utils/print_debug.h" -namespace System +namespace System::Render { typedef void *IntentStorageHandler; extern "C" IntentStorageHandler get_render_storage(); - RenderStorage &RenderStorage::instance() + IntentStorage &IntentStorage::instance() { - auto *instance = static_cast(get_render_storage()); + auto *instance = static_cast(get_render_storage()); if (instance == nullptr) { LOG_ERROR("IntentStorage used before initialization or after cleanup"); @@ -18,18 +18,18 @@ namespace System return (*instance); } - size_t RenderStorage::alloc_slot() + size_t IntentStorage::alloc_slot() { instance()._intent_storage.emplace_back(std::nullopt); return (instance()._intent_storage.size() - 1); } - std::optional &RenderStorage::get_intent(const size_t slot) + std::optional &IntentStorage::get_intent(const size_t slot) { return (instance()._intent_storage[slot]); } - void RenderStorage::free_slot(const size_t slot) + void IntentStorage::free_slot(const size_t slot) { instance()._intent_storage[slot] = std::nullopt; } diff --git a/src/windows/scenes/intent_api.cpp b/src/windows/scenes/intent_api.cpp index 4a86fe0..75fae5d 100644 --- a/src/windows/scenes/intent_api.cpp +++ b/src/windows/scenes/intent_api.cpp @@ -4,17 +4,17 @@ HRESULT intent_storage_init(IntentStorageHandler *handler) { HRESULT error = HRESULT_FROM_WIN32(ERROR_SUCCESS); - System::RenderStorage *manager = nullptr; + System::Render::IntentStorage *manager = nullptr; void *manager_alloc = nullptr; - manager_alloc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(System::RenderStorage)); + manager_alloc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(System::Render::IntentStorage)); if (manager_alloc == nullptr) { error = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); goto exit; } - manager = new (manager_alloc) System::RenderStorage(); + manager = new (manager_alloc) System::Render::IntentStorage(); *handler = manager; exit: @@ -26,8 +26,8 @@ void intent_storage_cleanup(IntentStorageHandler *api) if (api == nullptr) return; - auto *manager = static_cast(*api); - manager->~RenderStorage(); + auto *manager = static_cast(*api); + manager->~IntentStorage(); HeapFree(GetProcessHeap(), 0, manager); *api = nullptr; diff --git a/src/windows/windows_main.c b/src/windows/windows_main.c index 8b22053..229d684 100644 --- a/src/windows/windows_main.c +++ b/src/windows/windows_main.c @@ -122,6 +122,7 @@ int real_main() exit: LOG_INFO("Cleaning up"); scene_manager_cleanup(&system_info.scene_manager); + intent_storage_cleanup(&system_info.render_storage); directx_clean_up(&system_info.directx); assets_cleanup(); log_cleanup(); From f3d3461bd99251b22c06852c9c61b05673a05603 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Fri, 20 Feb 2026 14:04:33 +0700 Subject: [PATCH 02/17] feat(intent-storage) - set camera --- include/game/systems.h | 1 + include/game/systems/render/set_camera.h | 18 ++++++++++++++++++ include/system/intent_storage.h | 9 +++++++-- src/engine/intent_storage.cpp | 5 +++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 include/game/systems/render/set_camera.h diff --git a/include/game/systems.h b/include/game/systems.h index 5ddfda9..697ec11 100644 --- a/include/game/systems.h +++ b/include/game/systems.h @@ -23,3 +23,4 @@ #include "systems/render/rotation_intent.h" #include "systems/render/sprite_intent.h" #include "systems/render/text_intent.h" +#include "systems/render/set_camera.h" diff --git a/include/game/systems/render/set_camera.h b/include/game/systems/render/set_camera.h new file mode 100644 index 0000000..09c8236 --- /dev/null +++ b/include/game/systems/render/set_camera.h @@ -0,0 +1,18 @@ +#pragma once + +namespace Game::Render +{ + template + void set_camera([[maybe_unused]] T &syscall, System::ECS::Query &query) + { + const auto &[offsetX, offsetY, scaleX, scaleY, rotation, zoom] = query.front().get(); + // ReSharper disable once CppUseStructuredBinding + auto &intent_camera = System::Render::IntentStorage::get_camera(); + intent_camera.offsetX = offsetX; + intent_camera.offsetY = offsetY; + intent_camera.scaleX = scaleX; + intent_camera.scaleY = scaleY; + intent_camera.zoom = zoom; + intent_camera.rotation = rotation; + } +} // namespace Game::Render diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index 6a42823..36f9234 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -131,7 +131,10 @@ namespace System::Render struct Camera { - + float offsetX, offsetY; + float scaleX, scaleY; + float rotation; + float zoom; }; class IntentStorage @@ -139,11 +142,13 @@ namespace System::Render // TODO: Change storage from any to DrawDescription std::vector> _intent_storage{}; std::vector _packet_storage{}; + Camera _camera{}; public: static size_t alloc_slot(); static void free_slot(size_t slot); static IntentStorage &instance(); static std::optional &get_intent(size_t slot); + static Camera &get_camera(); }; -} // namespace System +} // namespace System::Render diff --git a/src/engine/intent_storage.cpp b/src/engine/intent_storage.cpp index b048bc4..8e383bd 100644 --- a/src/engine/intent_storage.cpp +++ b/src/engine/intent_storage.cpp @@ -34,4 +34,9 @@ namespace System::Render instance()._intent_storage[slot] = std::nullopt; } + Camera &IntentStorage::get_camera() + { + return (instance()._camera); + } + } // namespace System From 09ecc8663b3e230e710657a90d8068d381296f0b Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Fri, 20 Feb 2026 14:30:51 +0700 Subject: [PATCH 03/17] feat(compositor) - set up projection helpers --- include/maths/camera_project_2d.h | 0 include/system.h | 1 + include/system/compositor.h | 91 +++++++++++++++++++++++++++++++ include/system/intent_storage.h | 40 -------------- 4 files changed, 92 insertions(+), 40 deletions(-) create mode 100644 include/maths/camera_project_2d.h create mode 100644 include/system/compositor.h diff --git a/include/maths/camera_project_2d.h b/include/maths/camera_project_2d.h new file mode 100644 index 0000000..e69de29 diff --git a/include/system.h b/include/system.h index 87e21ac..c2a57f8 100644 --- a/include/system.h +++ b/include/system.h @@ -5,6 +5,7 @@ #include "system/ecs.h" #include "system/input.h" #include "system/intent_storage.h" +#include "system/compositor.h" namespace System { diff --git a/include/system/compositor.h b/include/system/compositor.h new file mode 100644 index 0000000..2cdefdc --- /dev/null +++ b/include/system/compositor.h @@ -0,0 +1,91 @@ +#pragma once + +#include "system/intent_storage.h" +#include +#include + +// helpers +namespace Math +{ + + static inline Vector2 rotate(const Vector2& p, const float radians) + { + const float c = std::cos(radians); + const float s = std::sin(radians); + return Vector2{p.x * c - p.y * s, p.x * s + p.y * c}; + } + + // World space -> camera view space + static inline Vector2 world_to_view(const Vector2& world, const System::Render::Camera &cam) + { + // Move world relative to camera position + Vector2 p{world.x - cam.offsetX, world.y - cam.offsetY}; + + // Apply inverse camera rotation (i.e., rotate the world opposite the camera) + p = rotate(p, -cam.rotation); + + // Zoom in means things appear bigger => multiply coordinates by zoom in view space + p.x *= cam.zoom; + p.y *= cam.zoom; + + return p; + } + + // Camera view space -> Normalized device coordinates + static inline Vector2 view_to_ndc(const Vector2& view, const System::Render::Camera &cam) + { + const float halfW = cam.scaleX * 0.5f; + const float halfH = cam.scaleY * 0.5f; + + const float invHalfW = (halfW != 0.0f) ? (1.0f / halfW) : 0.0f; + const float invHalfH = (halfH != 0.0f) ? (1.0f / halfH) : 0.0f; + + // Map view-space to NDC. Flip Y so +Y is up in NDC. + return Vector2{ + view.x * invHalfW, + -view.y * invHalfH + }; + } + + // Takes a world-space axis-aligned rect and returns its 4 corners in NDC: + // order: (x0,y0), (x1,y0), (x1,y1), (x0,y1) in the rect's local orientation (still axis-aligned in world), + // but camera rotation will rotate them in view/ndc. + static inline std::array, 4> project_rect_world_to_ndc(const System::Render::Rect &dstWorld, + const System::Render::Camera &cam) + { + const float x0 = dstWorld.u0; + const float y0 = dstWorld.v0; + const float x1 = dstWorld.u1; + const float y1 = dstWorld.v1; + + const Vector2 w0{x0, y0}; + const Vector2 w1{x1, y0}; + const Vector2 w2{x1, y1}; + const Vector2 w3{x0, y1}; + + const Vector2 v0 = world_to_view(w0, cam); + const Vector2 v1 = world_to_view(w1, cam); + const Vector2 v2 = world_to_view(w2, cam); + const Vector2 v3 = world_to_view(w3, cam); + + return { + view_to_ndc(v0, cam), + view_to_ndc(v1, cam), + view_to_ndc(v2, cam), + view_to_ndc(v3, cam) + }; + } +} // namespace Maths + +namespace System::Render +{ + struct CompositorItem + { + + }; + + class Compositor + { + std::vector _items; + }; +} \ No newline at end of file diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index 36f9234..5116f77 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -90,45 +90,6 @@ namespace System::Render uint32_t order = 0; }; - struct RenderPacket - { - DrawKind kind = DrawKind::KIND_UNKNOWN; - RenderSortKey sort{}; - - // Pipeline selection (resolved once from intent strings). - uint32_t vert_shader = 0; - uint32_t pixel_shader = 0; - - // Resource binding keys - // For sprites: texture asset id. For text: font atlas id (can be 0 for now). - uint32_t resource0 = 0; - - // Common per-draw params - Color color{}; - float rotation_z = 0.0f; - bool visible = true; - - // Draw-specific payload - union - { - struct - { - Rect src_rect{}; - Rect dst_rect{}; - bool flipX = false; - bool flipY = false; - } sprite; - - struct - { - std::string_view text{}; - const char *font_name = nullptr; - uint32_t font_size = 0; - Rect dst_rect{}; // optional: can be used as anchor/box if you want - } text; - } as{}; - }; - struct Camera { float offsetX, offsetY; @@ -141,7 +102,6 @@ namespace System::Render { // TODO: Change storage from any to DrawDescription std::vector> _intent_storage{}; - std::vector _packet_storage{}; Camera _camera{}; public: From 47027930dffa033ef745e9adce4db7851860d66c Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Fri, 20 Feb 2026 14:34:17 +0700 Subject: [PATCH 04/17] refactor(compositor) - remove empty file and convention --- include/maths/camera_project_2d.h | 0 include/system/compositor.h | 36 +++++++++++-------------------- 2 files changed, 13 insertions(+), 23 deletions(-) delete mode 100644 include/maths/camera_project_2d.h diff --git a/include/maths/camera_project_2d.h b/include/maths/camera_project_2d.h deleted file mode 100644 index e69de29..0000000 diff --git a/include/system/compositor.h b/include/system/compositor.h index 2cdefdc..aa0d1ef 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -1,22 +1,22 @@ #pragma once -#include "system/intent_storage.h" #include #include +#include "system/intent_storage.h" // helpers namespace Math { - static inline Vector2 rotate(const Vector2& p, const float radians) + static inline Vector2 rotate(const Vector2 &p, const float radians) { const float c = std::cos(radians); const float s = std::sin(radians); - return Vector2{p.x * c - p.y * s, p.x * s + p.y * c}; + return (Vector2{p.x * c - p.y * s, p.x * s + p.y * c}); } // World space -> camera view space - static inline Vector2 world_to_view(const Vector2& world, const System::Render::Camera &cam) + static inline Vector2 world_to_view(const Vector2 &world, const System::Render::Camera &cam) { // Move world relative to camera position Vector2 p{world.x - cam.offsetX, world.y - cam.offsetY}; @@ -28,11 +28,11 @@ namespace Math p.x *= cam.zoom; p.y *= cam.zoom; - return p; + return (p); } // Camera view space -> Normalized device coordinates - static inline Vector2 view_to_ndc(const Vector2& view, const System::Render::Camera &cam) + static inline Vector2 view_to_ndc(const Vector2 &view, const System::Render::Camera &cam) { const float halfW = cam.scaleX * 0.5f; const float halfH = cam.scaleY * 0.5f; @@ -41,17 +41,14 @@ namespace Math const float invHalfH = (halfH != 0.0f) ? (1.0f / halfH) : 0.0f; // Map view-space to NDC. Flip Y so +Y is up in NDC. - return Vector2{ - view.x * invHalfW, - -view.y * invHalfH - }; + return (Vector2{view.x * invHalfW, -view.y * invHalfH}); } // Takes a world-space axis-aligned rect and returns its 4 corners in NDC: // order: (x0,y0), (x1,y0), (x1,y1), (x0,y1) in the rect's local orientation (still axis-aligned in world), // but camera rotation will rotate them in view/ndc. - static inline std::array, 4> project_rect_world_to_ndc(const System::Render::Rect &dstWorld, - const System::Render::Camera &cam) + static inline std::array, 4> + project_rect_world_to_ndc(const System::Render::Rect &dstWorld, const System::Render::Camera &cam) { const float x0 = dstWorld.u0; const float y0 = dstWorld.v0; @@ -68,24 +65,17 @@ namespace Math const Vector2 v2 = world_to_view(w2, cam); const Vector2 v3 = world_to_view(w3, cam); - return { - view_to_ndc(v0, cam), - view_to_ndc(v1, cam), - view_to_ndc(v2, cam), - view_to_ndc(v3, cam) - }; + return (std::array{view_to_ndc(v0, cam), view_to_ndc(v1, cam), view_to_ndc(v2, cam), view_to_ndc(v3, cam)}); } -} // namespace Maths +} // namespace Math namespace System::Render { struct CompositorItem - { - - }; + {}; class Compositor { std::vector _items; }; -} \ No newline at end of file +} // namespace System::Render From e897949a5c0062bc5f59307f9d2bdd53f821eb3f Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Fri, 20 Feb 2026 14:57:07 +0700 Subject: [PATCH 05/17] refactor(renderer) - split to separate folder --- include/system/compositor.h | 6 +++++- src/renderer/CMakeLists.txt | 9 +++++++++ src/renderer/compositor.cpp | 9 +++++++++ src/{engine => renderer}/intent_storage.cpp | 0 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/renderer/CMakeLists.txt create mode 100644 src/renderer/compositor.cpp rename src/{engine => renderer}/intent_storage.cpp (100%) diff --git a/include/system/compositor.h b/include/system/compositor.h index aa0d1ef..6c443d7 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -72,10 +72,14 @@ namespace Math namespace System::Render { struct CompositorItem - {}; + { + + }; class Compositor { std::vector _items; + + static void compose(); }; } // namespace System::Render diff --git a/src/renderer/CMakeLists.txt b/src/renderer/CMakeLists.txt new file mode 100644 index 0000000..0e204e7 --- /dev/null +++ b/src/renderer/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB + RENDERER_FILES + "./*.cpp" +) + +add_library(renderer + STATIC + ${RENDERER_FILES} +) diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp new file mode 100644 index 0000000..99cfd84 --- /dev/null +++ b/src/renderer/compositor.cpp @@ -0,0 +1,9 @@ +#include "system.h" + +namespace System::Render +{ + void Compositor::compose() + { + + } +} // namespace System::Render diff --git a/src/engine/intent_storage.cpp b/src/renderer/intent_storage.cpp similarity index 100% rename from src/engine/intent_storage.cpp rename to src/renderer/intent_storage.cpp From eb22a161ba7da85bdf7ac106f72e65bf7f93783e Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Fri, 20 Feb 2026 16:19:53 +0700 Subject: [PATCH 06/17] feat(compositor) - compose from intent --- include/game/components/render/text.h | 15 ++++-- include/game/systems/render/text_intent.h | 6 ++- include/system/compositor.h | 54 +++++++++++++++++++-- include/system/intent_storage.h | 6 +++ src/renderer/compositor.cpp | 59 ++++++++++++++++++++++- 5 files changed, 127 insertions(+), 13 deletions(-) diff --git a/include/game/components/render/text.h b/include/game/components/render/text.h index d1298d1..c016274 100644 --- a/include/game/components/render/text.h +++ b/include/game/components/render/text.h @@ -13,12 +13,17 @@ namespace Game::Render char *font_name; // font name in asset uint32_t font_size; // font size - Text() : font_name(nullptr), font_size(0) - {} - explicit Text(std::string value) : text(std::move(value)), font_name(nullptr), font_size(0) + // World-space position + float x; + float y; + // Anchor + float anchor_x; + float anchor_y; + + Text() : font_name(nullptr), font_size(0), x(0.0f), y(0.0f), anchor_x(0.5f), anchor_y(0.5f) {} - explicit Text(std::string value, char *font_name, const uint32_t font_size) : - text(std::move(value)), font_name(font_name), font_size(font_size) + explicit Text(std::string value, char *font_name, const uint32_t font_size, const float x, const float y, const float anchor_x, const float anchor_y) : + text(std::move(value)), font_name(font_name), font_size(font_size), x(x), y(y), anchor_x(anchor_x), anchor_y(anchor_y) {} }; } // namespace Game::Render diff --git a/include/game/systems/render/text_intent.h b/include/game/systems/render/text_intent.h index a9a9f2c..a97cef2 100644 --- a/include/game/systems/render/text_intent.h +++ b/include/game/systems/render/text_intent.h @@ -31,10 +31,12 @@ namespace Game::Render intent.value().special = System::Render::TextDrawDesc{}; } - auto &[text, font_name, font_size] = std::get(intent.value().special); + auto &[text, font_name, font_size, x, y, anchor_x, anchor_y] = std::get(intent.value().special); text = std::string_view(text_component.text); font_name = text_component.font_name; font_size = text_component.font_size; + x = text_component.x; + y = text_component.y; } } -} // namespace Game::Render +} // namespace Game::Render \ No newline at end of file diff --git a/include/system/compositor.h b/include/system/compositor.h index 6c443d7..9836a30 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -45,8 +45,7 @@ namespace Math } // Takes a world-space axis-aligned rect and returns its 4 corners in NDC: - // order: (x0,y0), (x1,y0), (x1,y1), (x0,y1) in the rect's local orientation (still axis-aligned in world), - // but camera rotation will rotate them in view/ndc. + // order: (x0,y0), (x1,y0), (x1,y1), (x0,y1) in the rect's local orientation static inline std::array, 4> project_rect_world_to_ndc(const System::Render::Rect &dstWorld, const System::Render::Camera &cam) { @@ -67,19 +66,66 @@ namespace Math return (std::array{view_to_ndc(v0, cam), view_to_ndc(v1, cam), view_to_ndc(v2, cam), view_to_ndc(v3, cam)}); } + + static bool ndc_in_camera(const std::array, 4> &coords) + { + for (const auto& coord : coords) + { + if (coord.x < -1.0f || coord.x > 1.0f || coord.y < -1.0f || coord.y > 1.0f) + { + return (false); + } + } + return (true); + } + + // TextDrawDesc -> NDC (projects the text's anchor point position). + // Note: Without font metrics we can't compute a full NDC quad here; this gives you the + // projected position you can feed into your text renderer / batching logic. + static inline Vector2 + project_text_anchor_world_to_ndc(const System::Render::TextDrawDesc &text, const System::Render::Camera &cam) + { + const Vector2 world{text.x, text.y}; + const Vector2 view = world_to_view(world, cam); + return (view_to_ndc(view, cam)); + } + + int project_text_anchor_world_to_ndc(int _cpp_par_); } // namespace Math namespace System::Render { - struct CompositorItem + struct ComposedSpriteDesc { + const char *texture = nullptr; + Rect src_rect{}; + std::array, 4> dst_rect{}; + bool flipX = false; + bool flipY = false; + }; + + struct ComposedTextDesc + { + std::string_view text{}; + const char *font_name = nullptr; + uint32_t font_size = 0; + Math::Vector2 position{}; + Math::Vector2 anchor{}; + }; + + struct CompositorItem + { + DrawKind kind = DrawKind::KIND_UNKNOWN; + DrawCommon common; + std::variant special; }; class Compositor { std::vector _items; - static void compose(); + static void compose(const std::vector> &intents, const Camera &camera); + static Compositor& instance(); }; } // namespace System::Render diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index 5116f77..123d754 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -72,6 +72,12 @@ namespace System::Render std::string_view text{}; const char *font_name = nullptr; uint32_t font_size = 0; + + // Placement (world space) + float x = 0.0f; + float y = 0.0f; + float anchor_x = 0.5f; + float anchor_y = 0.5f; }; struct DrawIntent diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index 99cfd84..46271b2 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -2,8 +2,63 @@ namespace System::Render { - void Compositor::compose() + + Compositor &Compositor::instance() { - + // TODO: change this to do that extern "C" thing + static Compositor compositor; + return compositor; + } + + void Compositor::compose(const std::vector> &intents, const Camera &camera) + { + auto &compositor = instance(); + compositor._items.clear(); + for (auto &intent: intents) + { + if (!intent.has_value()) + { + continue; + } + + auto &drawIntent = intent.value(); + switch (drawIntent.kind) + { + case DrawKind::KIND_SPRITE: { + auto &sprite_draw_desc = std::get(drawIntent.special); + auto &dst_rect = sprite_draw_desc.dst_rect; + if (auto composed_dst = Math::project_rect_world_to_ndc(dst_rect, camera); + Math::ndc_in_camera(composed_dst)) + { + compositor._items.push_back( + CompositorItem{ + .kind = DrawKind::KIND_SPRITE, + .common = drawIntent.common, + .special = ComposedSpriteDesc{ + sprite_draw_desc.texture, + sprite_draw_desc.src_rect, + std::move(composed_dst)}}); + } + break; + } + case DrawKind::KIND_TEXT: { + auto &text_draw_desc = std::get(drawIntent.special); + compositor._items.push_back( + CompositorItem{ + .kind = DrawKind::KIND_TEXT, + .common = drawIntent.common, + .special = ComposedTextDesc{ + text_draw_desc.text, + text_draw_desc.font_name, + text_draw_desc.font_size, + Math::project_text_anchor_world_to_ndc(text_draw_desc, camera), + Math::Vector2{text_draw_desc.anchor_x, text_draw_desc.anchor_y}}}); + break; + } + default: { + continue; + } + } + } } } // namespace System::Render From 40f904b04b7b32b18d8f3da5cc29deff871831eb Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sun, 22 Feb 2026 18:55:38 +0700 Subject: [PATCH 07/17] feat(compositor) - wire compositor w/ intentstorage --- include/system/compositor.h | 6 ++-- include/system/intent_storage.h | 1 + src/renderer/compositor.cpp | 14 ++++++-- src/renderer/intent_storage.cpp | 5 +++ src/windows/scenes/CMakeLists.txt | 1 + src/windows/scenes/compositor_api.cpp | 51 +++++++++++++++++++++++++++ src/windows/scenes/compositor_api.h | 16 +++++++++ src/windows/scenes/intent_api.h | 1 - src/windows/windows_main.c | 16 +++++++++ src/windows/windows_types.h | 2 ++ 10 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 src/windows/scenes/compositor_api.cpp create mode 100644 src/windows/scenes/compositor_api.h diff --git a/include/system/compositor.h b/include/system/compositor.h index 9836a30..a51beef 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -67,7 +67,7 @@ namespace Math return (std::array{view_to_ndc(v0, cam), view_to_ndc(v1, cam), view_to_ndc(v2, cam), view_to_ndc(v3, cam)}); } - static bool ndc_in_camera(const std::array, 4> &coords) + static inline bool ndc_in_camera(const std::array, 4> &coords) { for (const auto& coord : coords) { @@ -89,8 +89,6 @@ namespace Math const Vector2 view = world_to_view(world, cam); return (view_to_ndc(view, cam)); } - - int project_text_anchor_world_to_ndc(int _cpp_par_); } // namespace Math namespace System::Render @@ -124,7 +122,7 @@ namespace System::Render class Compositor { std::vector _items; - + public: static void compose(const std::vector> &intents, const Camera &camera); static Compositor& instance(); }; diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index 123d754..2f4ade6 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -116,5 +116,6 @@ namespace System::Render static IntentStorage &instance(); static std::optional &get_intent(size_t slot); static Camera &get_camera(); + static std::vector> &get_intents(); }; } // namespace System::Render diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index 46271b2..4c20fe5 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -1,13 +1,21 @@ #include "system.h" +#include "utils/print_debug.h" namespace System::Render { + typedef void *CompositorHandler; + extern "C" CompositorHandler get_compositor(); + Compositor &Compositor::instance() { - // TODO: change this to do that extern "C" thing - static Compositor compositor; - return compositor; + auto *instance = static_cast(get_compositor()); + if (instance == nullptr) + { + LOG_ERROR("Compositor used before initialization or after cleanup"); + std::abort(); + } + return (*instance); } void Compositor::compose(const std::vector> &intents, const Camera &camera) diff --git a/src/renderer/intent_storage.cpp b/src/renderer/intent_storage.cpp index 8e383bd..23115f9 100644 --- a/src/renderer/intent_storage.cpp +++ b/src/renderer/intent_storage.cpp @@ -39,4 +39,9 @@ namespace System::Render return (instance()._camera); } + std::vector> &IntentStorage::get_intents() + { + return (instance()._intent_storage); + } + } // namespace System diff --git a/src/windows/scenes/CMakeLists.txt b/src/windows/scenes/CMakeLists.txt index cd29734..17fc66e 100644 --- a/src/windows/scenes/CMakeLists.txt +++ b/src/windows/scenes/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(os_scene target_link_libraries(os_scene PRIVATE scene + renderer user32 gdi32 kernel32 diff --git a/src/windows/scenes/compositor_api.cpp b/src/windows/scenes/compositor_api.cpp new file mode 100644 index 0000000..a2d5166 --- /dev/null +++ b/src/windows/scenes/compositor_api.cpp @@ -0,0 +1,51 @@ +#include "compositor_api.h" +#include "intent_api.h" + +#include "system.h" + +HRESULT compositor_init(CompositorHandler *handler) +{ + HRESULT error = HRESULT_FROM_WIN32(ERROR_SUCCESS); + System::Render::Compositor *manager = nullptr; + void *manager_alloc = nullptr; + + manager_alloc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(System::Render::Compositor)); + if (manager_alloc == nullptr) + { + error = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + goto exit; + } + + manager = new (manager_alloc) System::Render::Compositor(); + + *handler = manager; + exit: + return (error); +} + +void compositor_compose(IntentStorageHandler *intent_storage, CompositorHandler *compositor) +{ + if (intent_storage == nullptr) + { + return; + } + + if (compositor == nullptr) + { + return; + } + + System::Render::Compositor::compose(System::Render::IntentStorage::get_intents(), System::Render::IntentStorage::get_camera()); +} + +void compositor_cleanup(CompositorHandler *api) +{ + if (api == nullptr) + return; + + auto *manager = static_cast(*api); + manager->~Compositor(); + + HeapFree(GetProcessHeap(), 0, manager); + *api = nullptr; +} diff --git a/src/windows/scenes/compositor_api.h b/src/windows/scenes/compositor_api.h new file mode 100644 index 0000000..ae42470 --- /dev/null +++ b/src/windows/scenes/compositor_api.h @@ -0,0 +1,16 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" +{ + #endif + typedef void *CompositorHandler; + typedef void *IntentStorageHandler; + + HRESULT compositor_init(CompositorHandler *api); + void compositor_cleanup(CompositorHandler *api); + void compositor_compose(IntentStorageHandler *intent_storage, CompositorHandler *compositor); + #ifdef __cplusplus +} +#endif diff --git a/src/windows/scenes/intent_api.h b/src/windows/scenes/intent_api.h index 2a1820e..99f9a70 100644 --- a/src/windows/scenes/intent_api.h +++ b/src/windows/scenes/intent_api.h @@ -5,7 +5,6 @@ extern "C" { #endif - /* This scene will run on seperate threads */ typedef void *IntentStorageHandler; HRESULT intent_storage_init(IntentStorageHandler *api); diff --git a/src/windows/windows_main.c b/src/windows/windows_main.c index 229d684..7889921 100644 --- a/src/windows/windows_main.c +++ b/src/windows/windows_main.c @@ -11,6 +11,7 @@ #include "directx/directx_api.h" #include "scenes/intent_api.h" +#include "scenes/compositor_api.h" #include "scenes/scenes_api.h" #include "windows_functions.h" @@ -34,6 +35,7 @@ static SystemInfo system_info = { .rendering_queue = NULL, .scene_manager = NULL, .render_storage = NULL, + .compositor = NULL, .directx = NULL, }; @@ -52,6 +54,11 @@ void *get_render_storage() return (system_info.render_storage); } +void *get_compositor() +{ + return (system_info.compositor); +} + HRESULT directx_init(_In_ DirectXHandler *directx_api) { const DirectXConfig config = { @@ -110,11 +117,19 @@ int real_main() goto exit; } + error = compositor_init(&system_info.compositor); + if (error != ERROR_SUCCESS) + { + LOG_ERROR("compositor_init failed, Code 0x%08lx", error); + goto exit; + } + while (system_info.is_running) { process_system_message(&system_info, &msg); scene_manager_update(&system_info.scene_manager); + compositor_compose(&system_info.render_storage, &system_info.compositor); sleep(system_info.precision); } @@ -123,6 +138,7 @@ int real_main() LOG_INFO("Cleaning up"); scene_manager_cleanup(&system_info.scene_manager); intent_storage_cleanup(&system_info.render_storage); + compositor_cleanup(&system_info.compositor); directx_clean_up(&system_info.directx); assets_cleanup(); log_cleanup(); diff --git a/src/windows/windows_types.h b/src/windows/windows_types.h index 9989734..dab5709 100644 --- a/src/windows/windows_types.h +++ b/src/windows/windows_types.h @@ -5,6 +5,7 @@ typedef void *SceneManagerHandler; typedef void *IntentStorageHandler; +typedef void *CompositorHandler; typedef void *DirectxHandler; typedef enum @@ -58,5 +59,6 @@ typedef struct SceneManagerHandler scene_manager; IntentStorageHandler render_storage; + CompositorHandler compositor; DirectxHandler directx; } SystemInfo; From 8a57f2cb220168b0b05f3397624264c42d581d79 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sun, 22 Feb 2026 20:14:27 +0700 Subject: [PATCH 08/17] feat(compositor) - pipe assets_manager --- include/system/compositor.h | 31 +++++++++-- include/system/intent_storage.h | 10 ++-- src/assets_manager/assets_manager.c | 14 +++++ src/assets_manager/assets_manager.h | 8 +++ src/renderer/compositor.cpp | 79 ++++++++++++++++++++--------- 5 files changed, 110 insertions(+), 32 deletions(-) diff --git a/include/system/compositor.h b/include/system/compositor.h index a51beef..f2642d5 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -93,9 +93,30 @@ namespace Math namespace System::Render { + struct ComposedDrawCommon + { + // Pipeline selection (names) + assets_id vert_shader = static_cast(-1); + assets_id pixel_shader = static_cast(-1); + + /* render_prior: coarse render priority */ + uint32_t render_prior = 0; + + // Per-draw parameters + Color color{}; + + // Sorting (kept here so both sprite/text can be sorted uniformly) + uint32_t layer = 0; + uint32_t order = 0; + + // Rotation (what do you mean you still haven't rotated?) + // TODO: figure out if rotation happens here + float rotation_z = 0.0f; + }; + struct ComposedSpriteDesc { - const char *texture = nullptr; + assets_id texture = static_cast(-1); Rect src_rect{}; std::array, 4> dst_rect{}; @@ -106,7 +127,7 @@ namespace System::Render struct ComposedTextDesc { std::string_view text{}; - const char *font_name = nullptr; + assets_id font = static_cast(-1); uint32_t font_size = 0; Math::Vector2 position{}; Math::Vector2 anchor{}; @@ -115,7 +136,7 @@ namespace System::Render struct CompositorItem { DrawKind kind = DrawKind::KIND_UNKNOWN; - DrawCommon common; + ComposedDrawCommon common; std::variant special; }; @@ -124,6 +145,10 @@ namespace System::Render std::vector _items; public: static void compose(const std::vector> &intents, const Camera &camera); + static std::vector& items() + { + return instance()._items; + }; static Compositor& instance(); }; } // namespace System::Render diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index 2f4ade6..773e711 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -33,12 +33,11 @@ namespace System::Render struct DrawCommon { - // Pipeline selection (names/ids, not GPU objects) + // Pipeline selection (names) const char *vert_shader = nullptr; const char *pixel_shader = nullptr; - - /* render_prior: coarse render priority; larger values are drawn later (on top). */ + /* render_prior: coarse render priority */ uint32_t render_prior = 0; // Per-draw parameters @@ -48,11 +47,10 @@ namespace System::Render uint32_t layer = 0; uint32_t order = 0; - // 2D-friendly rotation hint (radians or degrees will depend on convention; - // this merely carries the value through) + // 2D-friendly rotation hint float rotation_z = 0.0f; - // Render intent + // Is visible bool visible = true; }; diff --git a/src/assets_manager/assets_manager.c b/src/assets_manager/assets_manager.c index a74e2de..9d0ebb1 100644 --- a/src/assets_manager/assets_manager.c +++ b/src/assets_manager/assets_manager.c @@ -115,6 +115,14 @@ assets_id load_pixel_shader(const char *path, const char *name, InputAttributeDe return (load_assets(path, name, info)); } +assets_id load_font(const char *path, const char *name, size_t size) +{ + AssetsInfo info = {0}; + info.type = FONT; + info.info.as_font.font_size = size; + return (load_assets(path, name, info)); +} + /* TODO: Change this shit to hash map or my ass will get whip */ assets_id get_assets_id(const char *name) { @@ -128,6 +136,12 @@ assets_id get_assets_id(const char *name) return (-1); } +// I'm so uncivilized - Midfield +int has_assets(const char *name) +{ + return (get_assets_id(name) != -1); +} + void free_assets(assets_id id) { uint16_t index = ASSET_INDEX(id); diff --git a/src/assets_manager/assets_manager.h b/src/assets_manager/assets_manager.h index 79af9f3..9ecaa8c 100644 --- a/src/assets_manager/assets_manager.h +++ b/src/assets_manager/assets_manager.h @@ -7,6 +7,7 @@ #define ASSET_INDEX(id) ((uint16_t) ((id) & 0xFFFFu)) #define ASSET_GEN(id) ((uint16_t) (((id) >> 16) & 0xFFFFu)) +#include typedef unsigned int uint32_t; typedef unsigned short uint16_t; @@ -44,6 +45,7 @@ typedef enum VERTEX_SHADER, PIXEL_SHADER, SPRITE, + FONT } AssetsType; typedef struct @@ -60,6 +62,10 @@ typedef struct { size_t width, height; } as_sprite; + struct + { + size_t font_size; + } as_font; } info; } AssetsInfo; @@ -80,6 +86,8 @@ assets_id get_assets_id(const char *name); assets_id load_sprite(const char *path, const char *name, size_t width, size_t height); assets_id load_vertex_shader(const char *path, const char *name, InputAttributeDescription *attributes, size_t count); assets_id load_pixel_shader(const char *path, const char *name, InputAttributeDescription *attributes, size_t count); +assets_id load_font(const char *path, const char *name, size_t size); +int has_assets(const char *name); void free_assets(assets_id id); diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index 4c20fe5..faca04b 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -1,3 +1,4 @@ +#include "../assets_manager/assets_manager.h" #include "system.h" #include "utils/print_debug.h" @@ -30,43 +31,75 @@ namespace System::Render } auto &drawIntent = intent.value(); + + ComposedDrawCommon common{}; + if (!has_assets(drawIntent.common.pixel_shader)) + { + // TODO: Encode InputAttributeDescription and Count + common.pixel_shader = + load_pixel_shader(drawIntent.common.pixel_shader, drawIntent.common.pixel_shader, nullptr, 0); + } + else + { + common.pixel_shader = get_assets_id(drawIntent.common.pixel_shader); + } + + if (!has_assets(drawIntent.common.vert_shader)) + { + // TODO: Encode InputAttributeDescription and Count + common.vert_shader = + load_vertex_shader(drawIntent.common.vert_shader, drawIntent.common.vert_shader, nullptr, 0); + } + else + { + common.vert_shader = get_assets_id(drawIntent.common.vert_shader); + } + common.render_prior = drawIntent.common.render_prior; + common.color = drawIntent.common.color; + common.layer = drawIntent.common.layer; + common.order = drawIntent.common.order; + common.rotation_z = drawIntent.common.rotation_z; + + std::variant special{}; switch (drawIntent.kind) { case DrawKind::KIND_SPRITE: { auto &sprite_draw_desc = std::get(drawIntent.special); - auto &dst_rect = sprite_draw_desc.dst_rect; - if (auto composed_dst = Math::project_rect_world_to_ndc(dst_rect, camera); - Math::ndc_in_camera(composed_dst)) + special = ComposedSpriteDesc{}; + ComposedSpriteDesc &sprite = std::get(special); + sprite.texture = get_assets_id(sprite_draw_desc.texture); + if (sprite.texture == -1) + { + sprite.texture = load_sprite(sprite_draw_desc.texture, sprite_draw_desc.texture, 0, 0); + } + sprite.src_rect = sprite_draw_desc.src_rect; + sprite.dst_rect = Math::project_rect_world_to_ndc(sprite_draw_desc.dst_rect, camera); + if (!Math::ndc_in_camera(sprite.dst_rect)) { - compositor._items.push_back( - CompositorItem{ - .kind = DrawKind::KIND_SPRITE, - .common = drawIntent.common, - .special = ComposedSpriteDesc{ - sprite_draw_desc.texture, - sprite_draw_desc.src_rect, - std::move(composed_dst)}}); + continue; } + sprite.flipX = sprite_draw_desc.flipX; + sprite.flipY = sprite_draw_desc.flipY; break; } case DrawKind::KIND_TEXT: { auto &text_draw_desc = std::get(drawIntent.special); - compositor._items.push_back( - CompositorItem{ - .kind = DrawKind::KIND_TEXT, - .common = drawIntent.common, - .special = ComposedTextDesc{ - text_draw_desc.text, - text_draw_desc.font_name, - text_draw_desc.font_size, - Math::project_text_anchor_world_to_ndc(text_draw_desc, camera), - Math::Vector2{text_draw_desc.anchor_x, text_draw_desc.anchor_y}}}); + special = ComposedTextDesc{}; + ComposedTextDesc &text = std::get(special); + // text, fontname, fontsize, position, anchor + text.text = text_draw_desc.text; + text.font = get_assets_id(text_draw_desc.font_name); + if (text.font == -1) + { + text.font = load_font(text_draw_desc.font_name, text_draw_desc.font_name, 0); + } break; } - default: { - continue; + case DrawKind::KIND_UNKNOWN: { + break; } } + compositor._items.push_back({drawIntent.kind, std::move(common), std::move(special)}); } } } // namespace System::Render From 176091ac644733b8dd3eccc478e3347125bfb09f Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sun, 22 Feb 2026 20:32:09 +0700 Subject: [PATCH 09/17] fix(compositor) - learn to extern "C" so THAT's what its used for --- include/system/compositor.h | 1 + src/renderer/compositor.cpp | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/system/compositor.h b/include/system/compositor.h index f2642d5..458fff5 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -3,6 +3,7 @@ #include #include #include "system/intent_storage.h" +#include // helpers namespace Math diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index faca04b..85f2837 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -1,12 +1,23 @@ #include "../assets_manager/assets_manager.h" -#include "system.h" +#include "system/compositor.h" +#include #include "utils/print_debug.h" namespace System::Render { typedef void *CompositorHandler; - extern "C" CompositorHandler get_compositor(); + extern "C" + { + typedef uint32_t assets_id; + assets_id get_assets_id(const char *name); + assets_id load_sprite(const char *path, const char *name, size_t width, size_t height); + assets_id load_vertex_shader(const char *path, const char *name, InputAttributeDescription *attributes, size_t count); + assets_id load_pixel_shader(const char *path, const char *name, InputAttributeDescription *attributes, size_t count); + assets_id load_font(const char *path, const char *name, size_t size); + int has_assets(const char *name); + CompositorHandler get_compositor(); + } Compositor &Compositor::instance() { From 39da970b5084f8caac8383a23b5c3506d48ead30 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sun, 22 Feb 2026 20:35:10 +0700 Subject: [PATCH 10/17] refactor(compositor) - adjust includes --- include/system/compositor.h | 4 ++++ src/renderer/compositor.cpp | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/system/compositor.h b/include/system/compositor.h index 458fff5..013ad33 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -94,6 +94,10 @@ namespace Math namespace System::Render { + extern "C" { + typedef uint32_t assets_id; + } + struct ComposedDrawCommon { // Pipeline selection (names) diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index 85f2837..d97deff 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -1,14 +1,30 @@ -#include "../assets_manager/assets_manager.h" + #include "system/compositor.h" #include #include "utils/print_debug.h" namespace System::Render { - typedef void *CompositorHandler; extern "C" { + typedef enum + { + FLOAT32BITS, + FLOAT16BITS, + FLOAT8BITS, + + UINT32BITS, + UINT16BITS, + UINT8BITS, + } InputType; + + typedef struct + { + char *semantic; + InputType type; + size_t offset; + } InputAttributeDescription; typedef uint32_t assets_id; assets_id get_assets_id(const char *name); assets_id load_sprite(const char *path, const char *name, size_t width, size_t height); From 61c970c76d8ea26750686a9f5d9a0e1a39b91d15 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Tue, 24 Feb 2026 14:23:29 +0700 Subject: [PATCH 11/17] test(intent-storage) - set up test --- include/game/systems/render/set_camera.h | 3 + test/intent_storage_test.cpp | 72 ++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 test/intent_storage_test.cpp diff --git a/include/game/systems/render/set_camera.h b/include/game/systems/render/set_camera.h index 09c8236..a800c9e 100644 --- a/include/game/systems/render/set_camera.h +++ b/include/game/systems/render/set_camera.h @@ -5,6 +5,9 @@ namespace Game::Render template void set_camera([[maybe_unused]] T &syscall, System::ECS::Query &query) { + if (query.begin() == query.end()) + return; + const auto &[offsetX, offsetY, scaleX, scaleY, rotation, zoom] = query.front().get(); // ReSharper disable once CppUseStructuredBinding auto &intent_camera = System::Render::IntentStorage::get_camera(); diff --git a/test/intent_storage_test.cpp b/test/intent_storage_test.cpp new file mode 100644 index 0000000..a0f1d62 --- /dev/null +++ b/test/intent_storage_test.cpp @@ -0,0 +1,72 @@ +#include "game.h" +#include "pch.h" +#include "system.h" + +using System::ECS::pid; +using System::ECS::ResourceManager; +using System::ECS::Syscall; +using System::ECS::TaskManager; +using System::Render::IntentStorage; + +using Game::Render::Camera2D; +using Game::Render::IntentHandle; +using Game::Render::Material; +using Game::Render::Rotation; +using Game::Render::Sprite; +using Game::Render::Text; + +using Game::Render::material_intent; +using Game::Render::rotation_intent; +using Game::Render::set_camera; +using Game::Render::sprite_intent; +using Game::Render::text_intent; + +using IntentStorageResourceManager = ResourceManager<1000, IntentHandle, Camera2D, Material, Sprite, Rotation, Text>; +using IntentStorageSyscall = Syscall<1000, IntentHandle, Camera2D, Material, Sprite, Rotation, Text>; +using IntentStorageTaskManager = TaskManager< + IntentStorageResourceManager, + IntentStorageSyscall, + set_camera, + material_intent, + sprite_intent, + rotation_intent, + text_intent>; + +// override the singleton + +std::unique_ptr intent_storage_ptr{}; + +IntentStorage &IntentStorage::instance() +{ + return *intent_storage_ptr; +} + +std::optional &IntentStorage::get_intent(const size_t slot) +{ + return (instance()._intent_storage[slot]); +} + +System::Render::Camera &IntentStorage::get_camera() +{ + return (instance()._camera); +} + +class IntentStorageTest : public ::testing::Test +{ +protected: + void SetUp() override + { + intent_storage_ptr = std::make_unique(); + } + void TearDown() override + { + intent_storage_ptr.reset(); + } +}; + +TEST(IntentStorage, test_can_run) +{ + IntentStorageTaskManager task_manager{}; + task_manager.run_all(); + EXPECT_TRUE(true); +} \ No newline at end of file From 1b6b9e5185591763d53bb4ff914d5ed985182fbd Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Tue, 24 Feb 2026 14:33:57 +0700 Subject: [PATCH 12/17] Revert "test(intent-storage) - set up test" This reverts commit 61c970c76d8ea26750686a9f5d9a0e1a39b91d15. --- include/game/systems/render/set_camera.h | 3 - test/intent_storage_test.cpp | 72 ------------------------ 2 files changed, 75 deletions(-) delete mode 100644 test/intent_storage_test.cpp diff --git a/include/game/systems/render/set_camera.h b/include/game/systems/render/set_camera.h index a800c9e..09c8236 100644 --- a/include/game/systems/render/set_camera.h +++ b/include/game/systems/render/set_camera.h @@ -5,9 +5,6 @@ namespace Game::Render template void set_camera([[maybe_unused]] T &syscall, System::ECS::Query &query) { - if (query.begin() == query.end()) - return; - const auto &[offsetX, offsetY, scaleX, scaleY, rotation, zoom] = query.front().get(); // ReSharper disable once CppUseStructuredBinding auto &intent_camera = System::Render::IntentStorage::get_camera(); diff --git a/test/intent_storage_test.cpp b/test/intent_storage_test.cpp deleted file mode 100644 index a0f1d62..0000000 --- a/test/intent_storage_test.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "game.h" -#include "pch.h" -#include "system.h" - -using System::ECS::pid; -using System::ECS::ResourceManager; -using System::ECS::Syscall; -using System::ECS::TaskManager; -using System::Render::IntentStorage; - -using Game::Render::Camera2D; -using Game::Render::IntentHandle; -using Game::Render::Material; -using Game::Render::Rotation; -using Game::Render::Sprite; -using Game::Render::Text; - -using Game::Render::material_intent; -using Game::Render::rotation_intent; -using Game::Render::set_camera; -using Game::Render::sprite_intent; -using Game::Render::text_intent; - -using IntentStorageResourceManager = ResourceManager<1000, IntentHandle, Camera2D, Material, Sprite, Rotation, Text>; -using IntentStorageSyscall = Syscall<1000, IntentHandle, Camera2D, Material, Sprite, Rotation, Text>; -using IntentStorageTaskManager = TaskManager< - IntentStorageResourceManager, - IntentStorageSyscall, - set_camera, - material_intent, - sprite_intent, - rotation_intent, - text_intent>; - -// override the singleton - -std::unique_ptr intent_storage_ptr{}; - -IntentStorage &IntentStorage::instance() -{ - return *intent_storage_ptr; -} - -std::optional &IntentStorage::get_intent(const size_t slot) -{ - return (instance()._intent_storage[slot]); -} - -System::Render::Camera &IntentStorage::get_camera() -{ - return (instance()._camera); -} - -class IntentStorageTest : public ::testing::Test -{ -protected: - void SetUp() override - { - intent_storage_ptr = std::make_unique(); - } - void TearDown() override - { - intent_storage_ptr.reset(); - } -}; - -TEST(IntentStorage, test_can_run) -{ - IntentStorageTaskManager task_manager{}; - task_manager.run_all(); - EXPECT_TRUE(true); -} \ No newline at end of file From c45be2349ee5a7c480375570927efe9eb50693e5 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Wed, 25 Feb 2026 15:37:26 +0700 Subject: [PATCH 13/17] feat(scene) - demo render scene --- include/game/components/render/camera.h | 8 ++++---- include/game/systems/render/set_camera.h | 6 +++++- include/scene.h | 3 ++- include/scene/demo_render.h | 24 ++++++++++++++++++++++ include/scene/scene_manager.h | 2 +- include/system/ecs/syscall.h | 2 +- src/renderer/intent_storage.cpp | 1 + src/scene/demo_render.cpp | 26 ++++++++++++++++++++++++ src/windows/windows_main.c | 12 +++++------ 9 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 include/scene/demo_render.h create mode 100644 src/scene/demo_render.cpp diff --git a/include/game/components/render/camera.h b/include/game/components/render/camera.h index e4a88ce..e15c974 100644 --- a/include/game/components/render/camera.h +++ b/include/game/components/render/camera.h @@ -5,9 +5,9 @@ namespace Game::Render struct Camera2D { // For setting up view/prep Matrix - float offsetX, offsetY; // Camera View Offset (Position) - float scaleX, scaleY; // Camera View Size - float rotation; // Camera rotation - float zoom; // Camera zoom + float offsetX = 0, offsetY = 0; // Camera View Offset (Position) + float scaleX = 1, scaleY = 1; // Camera View Size + float rotation = 0; // Camera rotation + float zoom = 1; // Camera zoom }; } // namespace Game::Render diff --git a/include/game/systems/render/set_camera.h b/include/game/systems/render/set_camera.h index 09c8236..eb0f61f 100644 --- a/include/game/systems/render/set_camera.h +++ b/include/game/systems/render/set_camera.h @@ -5,7 +5,10 @@ namespace Game::Render template void set_camera([[maybe_unused]] T &syscall, System::ECS::Query &query) { - const auto &[offsetX, offsetY, scaleX, scaleY, rotation, zoom] = query.front().get(); + if (query.begin() == query.end()) + return; + + const auto &[offsetX, offsetY, scaleX, scaleY, rotation, zoom] = query.front().get(); // ReSharper disable once CppUseStructuredBinding auto &intent_camera = System::Render::IntentStorage::get_camera(); intent_camera.offsetX = offsetX; @@ -14,5 +17,6 @@ namespace Game::Render intent_camera.scaleY = scaleY; intent_camera.zoom = zoom; intent_camera.rotation = rotation; + LOG_INFO("Camera set"); } } // namespace Game::Render diff --git a/include/scene.h b/include/scene.h index b9cd43e..2ed38ee 100644 --- a/include/scene.h +++ b/include/scene.h @@ -6,12 +6,13 @@ #include "scene/battle_scene.h" #include "scene/demo.h" #include "scene/demo_rhythm.h" +#include "scene/demo_render.h" // define configuration items namespace Scene::Config { // starting scene - using StartingScene = BattleScene; + using StartingScene = DemoRender; } // namespace Scene::Config diff --git a/include/scene/demo_render.h b/include/scene/demo_render.h new file mode 100644 index 0000000..b4f8303 --- /dev/null +++ b/include/scene/demo_render.h @@ -0,0 +1,24 @@ +#pragma once +#include "game.h" +#include "system.h" + +namespace Scene +{ + struct DemoRender + { + static DemoRender instance(); + + constexpr static auto name = "DemoRender"; + + // declare scene parameters + constexpr static size_t MaxResource = 1000; + using ComponentTuple = std::tuple; + using ResourceManager = Utils::make_resource_manager_t; + using Syscall = Utils::make_syscall_t; + using TaskManager = System::ECS::TaskManager>; + + // declare functions + static TaskManager init(); + static std::vector exit(); + }; +} \ No newline at end of file diff --git a/include/scene/scene_manager.h b/include/scene/scene_manager.h index eeb55ef..1fc7df1 100644 --- a/include/scene/scene_manager.h +++ b/include/scene/scene_manager.h @@ -8,7 +8,7 @@ namespace Scene /* Optimizable */ class SceneManager { - std::variant _current_scene_template; + std::variant _current_scene_template; std::any _current_manager; public: diff --git a/include/system/ecs/syscall.h b/include/system/ecs/syscall.h index d41b178..e14e77b 100644 --- a/include/system/ecs/syscall.h +++ b/include/system/ecs/syscall.h @@ -74,7 +74,7 @@ namespace System::ECS { private: SyscallResource _to_add_components{}; - std::tuple{})...> _to_remove_components; + std::tuple{})...> _to_remove_components{}; std::bitset _to_remove_entities{}; ResourceManager &_resource_manager_ref; diff --git a/src/renderer/intent_storage.cpp b/src/renderer/intent_storage.cpp index 23115f9..ca3a2a6 100644 --- a/src/renderer/intent_storage.cpp +++ b/src/renderer/intent_storage.cpp @@ -20,6 +20,7 @@ namespace System::Render size_t IntentStorage::alloc_slot() { + LOG_INFO("An IntentHandle was allocated"); instance()._intent_storage.emplace_back(std::nullopt); return (instance()._intent_storage.size() - 1); } diff --git a/src/scene/demo_render.cpp b/src/scene/demo_render.cpp new file mode 100644 index 0000000..c75a09a --- /dev/null +++ b/src/scene/demo_render.cpp @@ -0,0 +1,26 @@ +#include "scene.h" +#include "system.h" +#include "utils.h" + +Scene::DemoRender Scene::DemoRender::instance() +{ + static DemoRender instance; + return (instance); +} + +Scene::DemoRender::TaskManager Scene::DemoRender::init() +{ + auto tm = TaskManager{}; + tm.create_entity(Game::Render::Camera2D{}); + tm.create_entity( + Game::Render::Sprite{const_cast("rainbow.hlsl"), Game::Render::Rect(0, 0, 1, 1)}, + Game::Render::IntentHandle{}); + tm.run_all(); + return (tm); +} + +std::vector Scene::DemoRender::exit() +{ + LOG_INFO("Exiting Demo Render Scene."); + return {}; +} diff --git a/src/windows/windows_main.c b/src/windows/windows_main.c index 7889921..236bc14 100644 --- a/src/windows/windows_main.c +++ b/src/windows/windows_main.c @@ -103,24 +103,24 @@ int real_main() goto exit; } - error = scene_manager_init(&system_info.scene_manager); + error = intent_storage_init(&system_info.render_storage); if (error != ERROR_SUCCESS) { - LOG_ERROR("scene_manager_init failed, Code 0x%08lx", error); + LOG_ERROR("intent_storage_init failed, Code 0x%08lx", error); goto exit; } - error = intent_storage_init(&system_info.render_storage); + error = compositor_init(&system_info.compositor); if (error != ERROR_SUCCESS) { - LOG_ERROR("intent_storage_init failed, Code 0x%08lx", error); + LOG_ERROR("compositor_init failed, Code 0x%08lx", error); goto exit; } - error = compositor_init(&system_info.compositor); + error = scene_manager_init(&system_info.scene_manager); if (error != ERROR_SUCCESS) { - LOG_ERROR("compositor_init failed, Code 0x%08lx", error); + LOG_ERROR("scene_manager_init failed, Code 0x%08lx", error); goto exit; } From e74f2c3f820b5d8f3525e8ae93b6f7fd7422b034 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sat, 28 Feb 2026 07:21:38 +0700 Subject: [PATCH 14/17] feat(compositor) - test attach sprite intent --- include/scene/demo_render.h | 3 +-- src/renderer/compositor.cpp | 44 ++++++++++++++++++++++++++----------- src/scene/demo_render.cpp | 2 +- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/include/scene/demo_render.h b/include/scene/demo_render.h index b4f8303..cedf20a 100644 --- a/include/scene/demo_render.h +++ b/include/scene/demo_render.h @@ -1,6 +1,5 @@ #pragma once #include "game.h" -#include "system.h" namespace Scene { @@ -15,7 +14,7 @@ namespace Scene using ComponentTuple = std::tuple; using ResourceManager = Utils::make_resource_manager_t; using Syscall = Utils::make_syscall_t; - using TaskManager = System::ECS::TaskManager>; + using TaskManager = System::ECS::TaskManager, Game::Render::sprite_intent>; // declare functions static TaskManager init(); diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index d97deff..4760c2d 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -60,27 +60,42 @@ namespace System::Render auto &drawIntent = intent.value(); ComposedDrawCommon common{}; - if (!has_assets(drawIntent.common.pixel_shader)) + if (drawIntent.common.pixel_shader != nullptr) { - // TODO: Encode InputAttributeDescription and Count - common.pixel_shader = - load_pixel_shader(drawIntent.common.pixel_shader, drawIntent.common.pixel_shader, nullptr, 0); + if (!has_assets(drawIntent.common.pixel_shader)) + { + // TODO: Encode InputAttributeDescription and Count + common.pixel_shader = + load_pixel_shader(drawIntent.common.pixel_shader, drawIntent.common.pixel_shader, nullptr, 0); + } + else + { + common.pixel_shader = get_assets_id(drawIntent.common.pixel_shader); + } } else { - common.pixel_shader = get_assets_id(drawIntent.common.pixel_shader); + common.pixel_shader = static_cast(-1); } - if (!has_assets(drawIntent.common.vert_shader)) + if (drawIntent.common.vert_shader != nullptr) { - // TODO: Encode InputAttributeDescription and Count - common.vert_shader = - load_vertex_shader(drawIntent.common.vert_shader, drawIntent.common.vert_shader, nullptr, 0); + if (!has_assets(drawIntent.common.vert_shader)) + { + // TODO: Encode InputAttributeDescription and Count + common.vert_shader = + load_vertex_shader(drawIntent.common.vert_shader, drawIntent.common.vert_shader, nullptr, 0); + } + else + { + common.vert_shader = get_assets_id(drawIntent.common.vert_shader); + } } else { - common.vert_shader = get_assets_id(drawIntent.common.vert_shader); + common.vert_shader = static_cast(-1); } + common.render_prior = drawIntent.common.render_prior; common.color = drawIntent.common.color; common.layer = drawIntent.common.layer; @@ -93,7 +108,7 @@ namespace System::Render case DrawKind::KIND_SPRITE: { auto &sprite_draw_desc = std::get(drawIntent.special); special = ComposedSpriteDesc{}; - ComposedSpriteDesc &sprite = std::get(special); + auto &sprite = std::get(special); sprite.texture = get_assets_id(sprite_draw_desc.texture); if (sprite.texture == -1) { @@ -112,7 +127,7 @@ namespace System::Render case DrawKind::KIND_TEXT: { auto &text_draw_desc = std::get(drawIntent.special); special = ComposedTextDesc{}; - ComposedTextDesc &text = std::get(special); + auto &text = std::get(special); // text, fontname, fontsize, position, anchor text.text = text_draw_desc.text; text.font = get_assets_id(text_draw_desc.font_name); @@ -126,7 +141,10 @@ namespace System::Render break; } } - compositor._items.push_back({drawIntent.kind, std::move(common), std::move(special)}); + compositor._items.push_back({drawIntent.kind, common, std::move(special)}); } + auto intent_size = intents.size(); + auto items_size = compositor._items.size(); + LOG_INFO("Composed %d intents into %d items", intent_size, items_size); } } // namespace System::Render diff --git a/src/scene/demo_render.cpp b/src/scene/demo_render.cpp index c75a09a..2db0fa3 100644 --- a/src/scene/demo_render.cpp +++ b/src/scene/demo_render.cpp @@ -13,7 +13,7 @@ Scene::DemoRender::TaskManager Scene::DemoRender::init() auto tm = TaskManager{}; tm.create_entity(Game::Render::Camera2D{}); tm.create_entity( - Game::Render::Sprite{const_cast("rainbow.hlsl"), Game::Render::Rect(0, 0, 1, 1)}, + Game::Render::Sprite{const_cast("shaders/ps/rainbow.hlsl"), Game::Render::Rect(0, 0, 1, 1)}, Game::Render::IntentHandle{}); tm.run_all(); return (tm); From 0333a92b377d4ebcd2e74da8e825a1ec49bbd210 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sat, 28 Feb 2026 14:33:56 +0700 Subject: [PATCH 15/17] feat(compositor) - add traingle compose pipe --- include/game/components.h | 1 + include/game/components/render/triangle.h | 12 +++++ include/game/systems.h | 1 + include/game/systems/render/triangle_intent.h | 52 +++++++++++++++++++ include/scene/demo_render.h | 17 ++++-- include/system/compositor.h | 2 +- include/system/intent_storage.h | 8 ++- src/renderer/compositor.cpp | 7 ++- src/scene/demo_render.cpp | 4 +- 9 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 include/game/components/render/triangle.h create mode 100644 include/game/systems/render/triangle_intent.h diff --git a/include/game/components.h b/include/game/components.h index 9c96e6c..231b896 100644 --- a/include/game/components.h +++ b/include/game/components.h @@ -26,6 +26,7 @@ #include "components/render/rotation.h" #include "components/render/sprite.h" #include "components/render/text.h" +#include "components/render/triangle.h" #include "components/rhythm/holdactive.h" #include "components/rhythm/judgetext.h" #include "components/rhythm/keyinput.h" diff --git a/include/game/components/render/triangle.h b/include/game/components/render/triangle.h new file mode 100644 index 0000000..7d19dc7 --- /dev/null +++ b/include/game/components/render/triangle.h @@ -0,0 +1,12 @@ +#pragma once +#include "maths.h" + +namespace Game::Render +{ + struct Triangle + { + Math::Vector2 points[3]; + uint32_t layer; // Layer to render + uint32_t order; // Order of render in layer + }; +} // namespace Game::Render \ No newline at end of file diff --git a/include/game/systems.h b/include/game/systems.h index 697ec11..7cb20f2 100644 --- a/include/game/systems.h +++ b/include/game/systems.h @@ -24,3 +24,4 @@ #include "systems/render/sprite_intent.h" #include "systems/render/text_intent.h" #include "systems/render/set_camera.h" +#include "systems/render/triangle_intent.h" diff --git a/include/game/systems/render/triangle_intent.h b/include/game/systems/render/triangle_intent.h new file mode 100644 index 0000000..f6a4697 --- /dev/null +++ b/include/game/systems/render/triangle_intent.h @@ -0,0 +1,52 @@ +#pragma once + +namespace Game::Render +{ + template + void triangle_intent([[maybe_unused]] T &syscall, System::ECS::Query &query) + { + for (auto &[id, comps]: query) + { + const size_t &intent_id = comps.get().handle_id; + std::optional &intent = System::Render::IntentStorage::get_intent(intent_id); + const Triangle &triangle = comps.get(); + + if (!intent.has_value()) + { + intent = System::Render::DrawIntent{}; + } + + if (!intent.has_value()) + { + intent = System::Render::DrawIntent{}; + } + + switch (intent.value().kind) + { + case System::Render::DrawKind::KIND_UNKNOWN: + intent.value().kind = System::Render::DrawKind::KIND_TRIANGLE; + case System::Render::DrawKind::KIND_TRIANGLE: + break; + default: + return; + } + + if (!std::holds_alternative(intent.value().special)) + { + intent.value().special = System::Render::TriangleDrawDesc{}; + } + + auto &common = intent.value().common; + common.layer = triangle.layer; + common.order = triangle.order; + + auto &[u0, v0, u1, v1, u2, v2] = std::get(intent.value().special); + u0 = triangle.points[0].x; + v0 = triangle.points[0].y; + u1 = triangle.points[1].x; + v1 = triangle.points[1].y; + u2 = triangle.points[2].x; + v2 = triangle.points[2].y; + } + } +} \ No newline at end of file diff --git a/include/scene/demo_render.h b/include/scene/demo_render.h index cedf20a..42857fe 100644 --- a/include/scene/demo_render.h +++ b/include/scene/demo_render.h @@ -11,13 +11,24 @@ namespace Scene // declare scene parameters constexpr static size_t MaxResource = 1000; - using ComponentTuple = std::tuple; + using ComponentTuple = std::tuple< + Game::Render::Camera2D, + Game::Render::Sprite, + Game::Render::Material, + Game::Render::Text, + Game::Render::IntentHandle, + Game::Render::Rotation, + Game::Render::Triangle>; using ResourceManager = Utils::make_resource_manager_t; using Syscall = Utils::make_syscall_t; - using TaskManager = System::ECS::TaskManager, Game::Render::sprite_intent>; + using TaskManager = System::ECS::TaskManager< + ResourceManager, + Syscall, + Game::Render::set_camera, + Game::Render::sprite_intent>; // declare functions static TaskManager init(); static std::vector exit(); }; -} \ No newline at end of file +} // namespace Scene diff --git a/include/system/compositor.h b/include/system/compositor.h index 013ad33..c05f0a3 100644 --- a/include/system/compositor.h +++ b/include/system/compositor.h @@ -142,7 +142,7 @@ namespace System::Render { DrawKind kind = DrawKind::KIND_UNKNOWN; ComposedDrawCommon common; - std::variant special; + std::variant special; }; class Compositor diff --git a/include/system/intent_storage.h b/include/system/intent_storage.h index 773e711..928b7ce 100644 --- a/include/system/intent_storage.h +++ b/include/system/intent_storage.h @@ -12,6 +12,7 @@ namespace System::Render KIND_UNKNOWN = 0, KIND_SPRITE, KIND_TEXT, + KIND_TRIANGLE, }; struct Color @@ -78,11 +79,16 @@ namespace System::Render float anchor_y = 0.5f; }; + struct TriangleDrawDesc + { + float u0, v0, u1, v1, u2, v2; + }; + struct DrawIntent { DrawKind kind{DrawKind::KIND_UNKNOWN}; DrawCommon common{}; - std::variant special{}; + std::variant special{}; }; // Render Packet diff --git a/src/renderer/compositor.cpp b/src/renderer/compositor.cpp index 4760c2d..f367743 100644 --- a/src/renderer/compositor.cpp +++ b/src/renderer/compositor.cpp @@ -102,7 +102,7 @@ namespace System::Render common.order = drawIntent.common.order; common.rotation_z = drawIntent.common.rotation_z; - std::variant special{}; + std::variant special{}; switch (drawIntent.kind) { case DrawKind::KIND_SPRITE: { @@ -140,8 +140,11 @@ namespace System::Render case DrawKind::KIND_UNKNOWN: { break; } + case DrawKind::KIND_TRIANGLE: + special = std::get(intent.value().special); + break; } - compositor._items.push_back({drawIntent.kind, common, std::move(special)}); + compositor._items.push_back(CompositorItem{drawIntent.kind, common, std::move(special)}); } auto intent_size = intents.size(); auto items_size = compositor._items.size(); diff --git a/src/scene/demo_render.cpp b/src/scene/demo_render.cpp index 2db0fa3..fdac110 100644 --- a/src/scene/demo_render.cpp +++ b/src/scene/demo_render.cpp @@ -1,6 +1,5 @@ #include "scene.h" #include "system.h" -#include "utils.h" Scene::DemoRender Scene::DemoRender::instance() { @@ -13,7 +12,8 @@ Scene::DemoRender::TaskManager Scene::DemoRender::init() auto tm = TaskManager{}; tm.create_entity(Game::Render::Camera2D{}); tm.create_entity( - Game::Render::Sprite{const_cast("shaders/ps/rainbow.hlsl"), Game::Render::Rect(0, 0, 1, 1)}, + Game::Render::Triangle{}, + Game::Render::Material{}, Game::Render::IntentHandle{}); tm.run_all(); return (tm); From 0e0496d7c8eb3bb14ad9f961206527a894c5f262 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sat, 28 Feb 2026 14:35:29 +0700 Subject: [PATCH 16/17] chore(demo-render) - change demo style --- include/scene/demo_render.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/scene/demo_render.h b/include/scene/demo_render.h index 42857fe..fddd325 100644 --- a/include/scene/demo_render.h +++ b/include/scene/demo_render.h @@ -25,7 +25,7 @@ namespace Scene ResourceManager, Syscall, Game::Render::set_camera, - Game::Render::sprite_intent>; + Game::Render::triangle_intent>; // declare functions static TaskManager init(); From f8e6db2d017c4fa5b34248e9201955083535e177 Mon Sep 17 00:00:00 2001 From: ZigmaZero Date: Sat, 28 Feb 2026 14:42:35 +0700 Subject: [PATCH 17/17] add dummy data --- include/scene/demo_render.h | 1 + src/scene/demo_render.cpp | 4 ++-- src/windows/utils/windows_utils.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/scene/demo_render.h b/include/scene/demo_render.h index fddd325..0998918 100644 --- a/include/scene/demo_render.h +++ b/include/scene/demo_render.h @@ -25,6 +25,7 @@ namespace Scene ResourceManager, Syscall, Game::Render::set_camera, + Game::Render::material_intent, Game::Render::triangle_intent>; // declare functions diff --git a/src/scene/demo_render.cpp b/src/scene/demo_render.cpp index fdac110..d92a003 100644 --- a/src/scene/demo_render.cpp +++ b/src/scene/demo_render.cpp @@ -12,8 +12,8 @@ Scene::DemoRender::TaskManager Scene::DemoRender::init() auto tm = TaskManager{}; tm.create_entity(Game::Render::Camera2D{}); tm.create_entity( - Game::Render::Triangle{}, - Game::Render::Material{}, + Game::Render::Triangle{{{0,0}, {0.5, 0.5}, {1, 1}},0, 0}, + Game::Render::Material{const_cast("shaders/vs/rainbow.hlsl"), const_cast("shaders/ps/rainbow.hlsl")}, Game::Render::IntentHandle{}); tm.run_all(); return (tm); diff --git a/src/windows/utils/windows_utils.c b/src/windows/utils/windows_utils.c index f492e25..13bb851 100644 --- a/src/windows/utils/windows_utils.c +++ b/src/windows/utils/windows_utils.c @@ -116,7 +116,7 @@ DWORD file_read(_Out_ FileContent **content, _In_ const char *path) goto exit; } - LOG_INFO("Openning file at: %s", full_path); + LOG_INFO("Opening file at: %s", full_path); byte_read = 0; const HANDLE hfile = CreateFile(full_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);