- 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>
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)
IModuleinterfaceIDataNode(config system)IIO(inter-module communication)
Test Case - Base Avancée
Validation Criteria
Window + UI 2D element = base avancée validée si :
- ✅ Window SDL2 créée et stable
- ✅ bgfx initialisé et rendering fonctionnel
- ✅ DrawRect affiche rectangle coloré
- ✅ DrawSprite affiche sprite texturé
- ✅ DrawText affiche texte (police)
- ✅ UI element (panel) rendu correctement
- ✅ 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
- Text rendering : stb_truetype (simple) ou FreeType (complet) ?
- Asset management : AssetManager séparé ou intégré dans RenderModule ?
- Multi-window : Support futur ou single window only ?
Performance
- Sprite batching : Sort by texture ou sort by Z-order ?
- Transient buffers : OK pour MVP ou besoin persistent buffers ?
Integration
- ImGui : Garder ImGuiUI.h existant ou remplacer par custom UI ?
- Hot-reload : Shader hot-reload nécessaire ou compilation statique OK ?
Ressources
Documentation bgfx
- Repo : https://github.com/bkaradzic/bgfx
- Examples : https://github.com/bkaradzic/bgfx/tree/master/examples
- API docs : https://bkaradzic.github.io/bgfx/
Tutorials 2D avec bgfx
- bgfx example-26 (vectordisplay)
- NanoVG-bgfx : https://github.com/memononen/nanovg
SDL2
- Wiki : https://wiki.libsdl.org/
- Lazy Foo tutorials : https://lazyfoo.net/tutorials/SDL/
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