couple-repo/Projects/WIP/GroveEngine_RenderModule.md
StillHammer 0654db6a81 Add project documentation for morning setup
- Confluent: Conlang skeleton (phonology + proto-roots)
- GroveEngine RenderModule: Window + 2D UI rendering architecture
- Aissia: AI subsystem with LLM API calls + async processing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 12:02:43 +08:00

13 KiB

GroveEngine - RenderModule (Framework Module)

Type : Framework Module (base avancée) Stack : bgfx + SDL2 Objectif : Window + UI 2D element rendering Dernière mise à jour : 26 novembre 2025


Vue d'ensemble

Module framework pour GroveEngine fournissant les capacités de rendu 2D de base :

  • Window management via SDL2
  • Rendering 2D via bgfx (multi-backend : Vulkan/DX12/Metal/OpenGL)
  • UI element rendering (primitives 2D)

Base avancée = Intégration complète dans le GroveEngine + capacités rendering fonctionnelles


Architecture Module

Integration GroveEngine

class RenderModule : public grove::IModule {
public:
    // IModule interface
    void initialize(const IDataNode& config, IIO* io) override;
    void update(float dt) override;
    void shutdown() override;

    // Rendering API
    void BeginFrame();
    void EndFrame();

    // 2D Primitives
    void DrawRect(const Rect& rect, Color color);
    void DrawSprite(const Sprite& sprite);
    void DrawText(const std::string& text, Font font, Vec2 pos);

private:
    SDL_Window* window;
    bgfx::ViewId main_view;
    Renderer2D renderer;
};

Composants Clés

1. Window Management (SDL2)

struct WindowConfig {
    int width;
    int height;
    std::string title;
    bool fullscreen;
    bool vsync;
};

// Création window SDL2
window = SDL_CreateWindow(
    config.title.c_str(),
    SDL_WINDOWPOS_CENTERED,
    SDL_WINDOWPOS_CENTERED,
    config.width,
    config.height,
    SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);

2. bgfx Initialization

bgfx::Init init;
init.type = bgfx::RendererType::Count; // Auto-detect
init.resolution.width = width;
init.resolution.height = height;
init.resolution.reset = BGFX_RESET_VSYNC;

// Utilise window SDL2
SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
SDL_GetWindowWMInfo(window, &wmi);

#if BX_PLATFORM_WINDOWS
    init.platformData.nwh = wmi.info.win.window;
#elif BX_PLATFORM_LINUX
    init.platformData.ndt = wmi.info.x11.display;
    init.platformData.nwh = (void*)(uintptr_t)wmi.info.x11.window;
#endif

bgfx::init(init);

3. Renderer2D (Primitives)

class Renderer2D {
public:
    void DrawRect(const Rect& rect, Color color);
    void DrawSprite(const Sprite& sprite);
    void Flush();  // Submit batched draws

private:
    bgfx::ProgramHandle sprite_shader;
    bgfx::ProgramHandle color_shader;

    struct SpriteBatch {
        std::vector<SpriteVertex> vertices;
        bgfx::TextureHandle texture;
    };

    std::vector<SpriteBatch> batches;
};

Rendering Pipeline

Frame Structure

void RenderModule::update(float dt) {
    BeginFrame();

    // Rendering commands
    DrawRect({100, 100, 200, 150}, Color::Red());
    DrawSprite(test_sprite);
    DrawText("Hello GroveEngine", main_font, {50, 50});

    EndFrame();
}

void RenderModule::BeginFrame() {
    bgfx::touch(main_view);
    bgfx::setViewClear(main_view,
        BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH,
        0x303030ff, 1.0f, 0);
}

void RenderModule::EndFrame() {
    renderer.Flush();  // Submit batched draws
    bgfx::frame();     // Advance frame
}

Vertex Formats

Sprite Vertex (textured quad)

struct SpriteVertex {
    float x, y, z;     // Position
    float u, v;        // UV coords
    uint32_t color;    // Tint (ABGR)
};

bgfx::VertexLayout sprite_layout;
sprite_layout.begin()
    .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
    .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
    .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
    .end();

Color Vertex (solid color quad)

struct ColorVertex {
    float x, y, z;
    uint32_t color;
};

bgfx::VertexLayout color_layout;
color_layout.begin()
    .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
    .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
    .end();

Shaders

Sprite Shader (Vertex)

// vs_sprite.sc
$input a_position, a_texcoord0, a_color0
$output v_texcoord0, v_color0

#include <bgfx_shader.sh>

void main() {
    gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
    v_texcoord0 = a_texcoord0;
    v_color0 = a_color0;
}

Sprite Shader (Fragment)

// fs_sprite.sc
$input v_texcoord0, v_color0

#include <bgfx_shader.sh>

SAMPLER2D(s_texture, 0);

void main() {
    vec4 texColor = texture2D(s_texture, v_texcoord0);
    gl_FragColor = texColor * v_color0;
}

Compilation :

shaderc -f vs_sprite.sc -o vs_sprite.bin --type vertex --platform linux -p 120
shaderc -f fs_sprite.sc -o fs_sprite.bin --type fragment --platform linux -p 120

Camera 2D

Orthographic Projection

class Camera2D {
public:
    Vec2 position;
    float zoom = 1.0f;

    Mat4 GetViewMatrix() const {
        return Mat4::Translation(-position.x, -position.y, 0);
    }

    Mat4 GetProjectionMatrix(int width, int height) const {
        float halfW = (width / zoom) * 0.5f;
        float halfH = (height / zoom) * 0.5f;
        return Mat4::Ortho(-halfW, halfW, -halfH, halfH, -1, 1);
    }
};

// Setup view transform
Mat4 view = camera.GetViewMatrix();
Mat4 proj = camera.GetProjectionMatrix(screenW, screenH);
bgfx::setViewTransform(main_view, view.data, proj.data);

UI Element Rendering

DrawRect Implementation

void Renderer2D::DrawRect(const Rect& rect, Color color) {
    ColorVertex vertices[4] = {
        {rect.x,             rect.y,              0, color.abgr()},
        {rect.x + rect.w,    rect.y,              0, color.abgr()},
        {rect.x + rect.w,    rect.y + rect.h,     0, color.abgr()},
        {rect.x,             rect.y + rect.h,     0, color.abgr()}
    };

    uint16_t indices[6] = {0, 1, 2, 0, 2, 3};

    bgfx::TransientVertexBuffer tvb;
    bgfx::TransientIndexBuffer tib;

    bgfx::allocTransientVertexBuffer(&tvb, 4, color_layout);
    bgfx::allocTransientIndexBuffer(&tib, 6);

    memcpy(tvb.data, vertices, sizeof(vertices));
    memcpy(tib.data, indices, sizeof(indices));

    bgfx::setVertexBuffer(0, &tvb);
    bgfx::setIndexBuffer(&tib);
    bgfx::setState(BGFX_STATE_DEFAULT);
    bgfx::submit(main_view, color_shader);
}

DrawSprite Implementation (Batched)

void Renderer2D::DrawSprite(const Sprite& sprite) {
    // Find or create batch for this texture
    SpriteBatch* batch = GetBatchForTexture(sprite.texture);

    // Add quad to batch
    float x0 = sprite.pos.x;
    float y0 = sprite.pos.y;
    float x1 = x0 + sprite.size.x;
    float y1 = y0 + sprite.size.y;

    uint32_t color = sprite.tint.abgr();

    batch->vertices.push_back({x0, y0, 0, 0, 0, color});
    batch->vertices.push_back({x1, y0, 0, 1, 0, color});
    batch->vertices.push_back({x1, y1, 0, 1, 1, color});
    batch->vertices.push_back({x0, y1, 0, 0, 1, color});
}

void Renderer2D::Flush() {
    for (auto& batch : batches) {
        size_t quad_count = batch.vertices.size() / 4;

        // Generate indices (0,1,2, 0,2,3 per quad)
        std::vector<uint16_t> indices;
        for (size_t i = 0; i < quad_count; ++i) {
            uint16_t base = i * 4;
            indices.push_back(base + 0);
            indices.push_back(base + 1);
            indices.push_back(base + 2);
            indices.push_back(base + 0);
            indices.push_back(base + 2);
            indices.push_back(base + 3);
        }

        // Submit draw call
        bgfx::TransientVertexBuffer tvb;
        bgfx::TransientIndexBuffer tib;

        bgfx::allocTransientVertexBuffer(&tvb, batch.vertices.size(), sprite_layout);
        bgfx::allocTransientIndexBuffer(&tib, indices.size());

        memcpy(tvb.data, batch.vertices.data(), batch.vertices.size() * sizeof(SpriteVertex));
        memcpy(tib.data, indices.data(), indices.size() * sizeof(uint16_t));

        bgfx::setTexture(0, sampler, batch.texture);
        bgfx::setVertexBuffer(0, &tvb);
        bgfx::setIndexBuffer(&tib);
        bgfx::setState(BGFX_STATE_DEFAULT);
        bgfx::submit(main_view, sprite_shader);
    }

    batches.clear();
}

Configuration Module

Config File (JSON)

{
  "module": "RenderModule",
  "window": {
    "width": 1280,
    "height": 720,
    "title": "GroveEngine - RenderModule Test",
    "fullscreen": false,
    "vsync": true
  },
  "rendering": {
    "clear_color": "#303030",
    "main_view_id": 0
  }
}

Loading Config

void RenderModule::initialize(const IDataNode& config, IIO* io) {
    WindowConfig window_config;
    window_config.width = config.get("window.width", 1280);
    window_config.height = config.get("window.height", 720);
    window_config.title = config.get("window.title", "GroveEngine");
    window_config.vsync = config.get("window.vsync", true);

    InitializeWindow(window_config);
    InitializeBgfx(window_config);
    InitializeRenderer();
}

Roadmap Développement

Phase 1 - Window + Init (Semaine 1)

Objectif : Window SDL2 + bgfx initialized, clear screen

  • Setup SDL2 window
  • Initialize bgfx avec window handle
  • Clear screen avec couleur
  • Main loop fonctionnel
  • Event handling basique (close window)

Livrable : Window qui affiche fond gris, ferme proprement


Phase 2 - Primitives 2D (Semaine 2)

Objectif : DrawRect fonctionnel

  • Vertex layouts (ColorVertex, SpriteVertex)
  • Shader compilation (color shader)
  • DrawRect implementation
  • Camera 2D orthographic
  • Afficher 1 rectangle coloré

Livrable : Fenêtre avec rectangle rouge affiché


Phase 3 - Sprite Rendering (Semaine 3)

Objectif : DrawSprite fonctionnel

  • Texture loading (stb_image)
  • Sprite shader (vertex + fragment)
  • DrawSprite implementation (batched)
  • Afficher 1 sprite texturé

Livrable : Fenêtre avec sprite test affiché


Phase 4 - UI Elements (Semaine 4)

Objectif : Text rendering + UI primitives

  • Font loading (stb_truetype ou FreeType)
  • DrawText implementation
  • UI element base class
  • UIPanel, UIText primitives

Livrable : Fenêtre avec panneau UI + texte


Dépendances

Externes (Libraries)

  • SDL2 : Window + input
  • bgfx : Rendering abstraction
  • bx : Base library (bgfx dependency)
  • bimg : Image loading (bgfx dependency)
  • stb_image : Texture loading
  • stb_truetype ou FreeType : Font rendering

GroveEngine (Internes)

  • IModule interface
  • IDataNode (config system)
  • IIO (inter-module communication)

Test Case - Base Avancée

Validation Criteria

Window + UI 2D element = base avancée validée si :

  1. Window SDL2 créée et stable
  2. bgfx initialisé et rendering fonctionnel
  3. DrawRect affiche rectangle coloré
  4. DrawSprite affiche sprite texturé
  5. DrawText affiche texte (police)
  6. UI element (panel) rendu correctement
  7. Module intégré dans GroveEngine (IModule interface)

Example Test Code

// main.cpp
int main() {
    auto engine = grove::EngineFactory::CreateDebugEngine();

    auto config = LoadConfig("render_module_config.json");
    engine->LoadModule("RenderModule", config);

    // Game loop
    while (!should_quit) {
        engine->Update(dt);
    }

    return 0;
}

// Dans RenderModule::update()
void RenderModule::update(float dt) {
    BeginFrame();

    // Test: Rectangle
    DrawRect({100, 100, 200, 100}, Color{255, 0, 0, 255});

    // Test: Sprite
    DrawSprite(test_sprite);

    // Test: UI Panel
    DrawRect({50, 50, 300, 200}, Color{64, 64, 64, 200});
    DrawText("Base Avancée OK!", main_font, {60, 60});

    EndFrame();
}

Questions Ouvertes

Architecture

  1. Text rendering : stb_truetype (simple) ou FreeType (complet) ?
  2. Asset management : AssetManager séparé ou intégré dans RenderModule ?
  3. Multi-window : Support futur ou single window only ?

Performance

  1. Sprite batching : Sort by texture ou sort by Z-order ?
  2. Transient buffers : OK pour MVP ou besoin persistent buffers ?

Integration

  1. ImGui : Garder ImGuiUI.h existant ou remplacer par custom UI ?
  2. Hot-reload : Shader hot-reload nécessaire ou compilation statique OK ?

Ressources

Documentation bgfx

Tutorials 2D avec bgfx

SDL2


Liens Projets

  • GroveEngine core : Projects/WIP/GroveEngine.md
  • GroveEngine architecture : Projects/WIP/grove-sup.md
  • Aissia (utilisateur) : Projects/WIP/AISSIA.md
  • Pokrovsk (utilisateur futur) : Projects/CONCEPT/pokrovsk_last_day.md

Créé : 26 novembre 2025 Status : Architecture planning Type : Framework module (base avancée) Objectif : Window + UI 2D rendering pour GroveEngine