#pragma once #include struct GraphData; // forward declare struct GraphRendererConfig { float node_outline = 1.5f; // outline width in pixels float edge_width = 1.0f; // edge line width float edge_alpha = 0.4f; // edge transparency uint32_t bg_color = 0xFF1A1A1E; // ABGR background bool edge_fade_alpha = true; // fade edge alpha by distance to camera // Default palette for communities (when node.color == 0) // 10 distinct colors, ABGR packed }; struct GraphRenderer; // Lifecycle GraphRenderer* graph_renderer_create(int width, int height, const GraphRendererConfig& config = {}); void graph_renderer_destroy(GraphRenderer* r); void graph_renderer_resize(GraphRenderer* r, int width, int height); // Render graph to internal FBO. // cam_x, cam_y: camera center in graph space // cam_zoom: zoom level (1.0 = 1:1 pixel mapping) // Returns OpenGL texture ID suitable for ImGui::Image(). unsigned int graph_renderer_draw(GraphRenderer* r, const GraphData& graph, float cam_x, float cam_y, float cam_zoom); // Optional: bind an icon atlas built by graph_icons. The renderer composes // icons over nodes whose `icon_id` (resolved from override or EntityType) // is non-zero. Pass texture_id=0 to disable icons (default). // // `uv_table`: `count * 4` floats (u0, v0, u1, v1) per icon, 0-indexed // (icon_id k uses uv_table[(k-1)*4..]). Must outlive the renderer or be // re-set whenever changed (the renderer copies it into a uniform array). void graph_renderer_set_icon_atlas(GraphRenderer* r, unsigned int texture_id, const float* uv_table, int count); // --------------------------------------------------------------------------- // RGBA8 packing helpers // --------------------------------------------------------------------------- // Layout: byte 0 (LSB) = R, byte 1 = G, byte 2 = B, byte 3 (MSB) = A. // On a little-endian host this matches GLSL's `unpackUnorm4x8(uint)` which // returns vec4(byte0, byte1, byte2, byte3) / 255 — so the GPU reads it as // (R, G, B, A) without any swizzle. inline uint32_t pack_rgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (uint32_t)r | ((uint32_t)g << 8) | ((uint32_t)b << 16) | ((uint32_t)a << 24); } inline void unpack_rgba8(uint32_t c, uint8_t& r, uint8_t& g, uint8_t& b, uint8_t& a) { r = (uint8_t)( c & 0xFF); g = (uint8_t)((c >> 8 ) & 0xFF); b = (uint8_t)((c >> 16) & 0xFF); a = (uint8_t)((c >> 24) & 0xFF); } // Multiply alpha channel by a [0..1] scale, clamping to 255. inline uint32_t modulate_alpha_rgba8(uint32_t c, float scale) { uint32_t a = (c >> 24) & 0xFFu; float af = (float)a * scale + 0.5f; if (af < 0.0f) af = 0.0f; if (af > 255.0f) af = 255.0f; return (c & 0x00FFFFFFu) | ((uint32_t)af << 24); }