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/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/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/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/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 5ddfda9..7cb20f2 100644 --- a/include/game/systems.h +++ b/include/game/systems.h @@ -23,3 +23,5 @@ #include "systems/render/rotation_intent.h" #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/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/set_camera.h b/include/game/systems/render/set_camera.h new file mode 100644 index 0000000..eb0f61f --- /dev/null +++ b/include/game/systems/render/set_camera.h @@ -0,0 +1,22 @@ +#pragma once + +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(); + intent_camera.offsetX = offsetX; + intent_camera.offsetY = offsetY; + intent_camera.scaleX = scaleX; + intent_camera.scaleY = scaleY; + intent_camera.zoom = zoom; + intent_camera.rotation = rotation; + LOG_INFO("Camera set"); + } +} // namespace Game::Render 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..a97cef2 100644 --- a/include/game/systems/render/text_intent.h +++ b/include/game/systems/render/text_intent.h @@ -8,33 +8,35 @@ 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, 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/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.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..0998918 --- /dev/null +++ b/include/scene/demo_render.h @@ -0,0 +1,35 @@ +#pragma once +#include "game.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< + 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< + ResourceManager, + Syscall, + Game::Render::set_camera, + Game::Render::material_intent, + Game::Render::triangle_intent>; + + // declare functions + static TaskManager init(); + static std::vector exit(); + }; +} // namespace Scene 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.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..c05f0a3 --- /dev/null +++ b/include/system/compositor.h @@ -0,0 +1,159 @@ +#pragma once + +#include +#include +#include "system/intent_storage.h" +#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 + 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 (std::array{view_to_ndc(v0, cam), view_to_ndc(v1, cam), view_to_ndc(v2, cam), view_to_ndc(v3, cam)}); + } + + static inline 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)); + } +} // namespace Math + +namespace System::Render +{ + extern "C" { + typedef uint32_t assets_id; + } + + 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 + { + assets_id texture = static_cast(-1); + Rect src_rect{}; + std::array, 4> dst_rect{}; + + bool flipX = false; + bool flipY = false; + }; + + struct ComposedTextDesc + { + std::string_view text{}; + assets_id font = static_cast(-1); + uint32_t font_size = 0; + Math::Vector2 position{}; + Math::Vector2 anchor{}; + }; + + struct CompositorItem + { + DrawKind kind = DrawKind::KIND_UNKNOWN; + ComposedDrawCommon common; + std::variant special; + }; + + class Compositor + { + 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/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/include/system/intent_storage.h b/include/system/intent_storage.h index c6d348b..928b7ce 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 @@ -12,6 +12,7 @@ namespace System KIND_UNKNOWN = 0, KIND_SPRITE, KIND_TEXT, + KIND_TRIANGLE, }; struct Color @@ -33,12 +34,11 @@ namespace System 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 +48,10 @@ namespace System 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; }; @@ -72,13 +71,24 @@ namespace System 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 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 @@ -90,55 +100,26 @@ namespace System uint32_t order = 0; }; - struct RenderPacket + struct Camera { - 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{}; + float offsetX, offsetY; + float scaleX, scaleY; + float rotation; + float zoom; }; - class RenderStorage + class IntentStorage { // 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 RenderStorage &instance(); + static IntentStorage &instance(); static std::optional &get_intent(size_t slot); + static Camera &get_camera(); + static std::vector> &get_intents(); }; -} // namespace System +} // namespace System::Render 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/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..f367743 --- /dev/null +++ b/src/renderer/compositor.cpp @@ -0,0 +1,153 @@ + +#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); + 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() + { + 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) + { + auto &compositor = instance(); + compositor._items.clear(); + for (auto &intent: intents) + { + if (!intent.has_value()) + { + continue; + } + + auto &drawIntent = intent.value(); + + ComposedDrawCommon common{}; + if (drawIntent.common.pixel_shader != nullptr) + { + 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 = static_cast(-1); + } + + if (drawIntent.common.vert_shader != nullptr) + { + 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 = static_cast(-1); + } + + 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); + special = ComposedSpriteDesc{}; + auto &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)) + { + 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); + special = ComposedTextDesc{}; + 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); + if (text.font == -1) + { + text.font = load_font(text_draw_desc.font_name, text_draw_desc.font_name, 0); + } + break; + } + case DrawKind::KIND_UNKNOWN: { + break; + } + case DrawKind::KIND_TRIANGLE: + special = std::get(intent.value().special); + break; + } + compositor._items.push_back(CompositorItem{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/engine/intent_storage.cpp b/src/renderer/intent_storage.cpp similarity index 54% rename from src/engine/intent_storage.cpp rename to src/renderer/intent_storage.cpp index fc1f2f4..ca3a2a6 100644 --- a/src/engine/intent_storage.cpp +++ b/src/renderer/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,20 +18,31 @@ namespace System return (*instance); } - size_t RenderStorage::alloc_slot() + size_t IntentStorage::alloc_slot() { + LOG_INFO("An IntentHandle was allocated"); 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; } + Camera &IntentStorage::get_camera() + { + return (instance()._camera); + } + + std::vector> &IntentStorage::get_intents() + { + return (instance()._intent_storage); + } + } // namespace System diff --git a/src/scene/demo_render.cpp b/src/scene/demo_render.cpp new file mode 100644 index 0000000..d92a003 --- /dev/null +++ b/src/scene/demo_render.cpp @@ -0,0 +1,26 @@ +#include "scene.h" +#include "system.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::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); +} + +std::vector Scene::DemoRender::exit() +{ + LOG_INFO("Exiting Demo Render Scene."); + return {}; +} 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.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/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/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); diff --git a/src/windows/windows_main.c b/src/windows/windows_main.c index 8b22053..236bc14 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 = { @@ -96,17 +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 = scene_manager_init(&system_info.scene_manager); + if (error != ERROR_SUCCESS) + { + LOG_ERROR("scene_manager_init failed, Code 0x%08lx", error); goto exit; } @@ -115,6 +129,7 @@ int real_main() 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); } @@ -122,6 +137,8 @@ int real_main() exit: 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;