// ui_icons.cpp - SVG icon rasterization via lunasvg #include "ui/ui_icons.h" #include #include #include UI_IconInfo g_icons[UI_ICON_COUNT] = {}; // Simple SVG icon sources (24x24 viewBox) static const char *g_icon_svgs[UI_ICON_COUNT] = { // UI_ICON_CLOSE - X mark R"( )", // UI_ICON_CHECK - checkmark R"( )", // UI_ICON_CHEVRON_DOWN - downward arrow R"( )", // UI_ICON_KNOB - filled circle with indicator line pointing up (12 o'clock) R"( )", // UI_ICON_SLIDER_THUMB - solid body with grip ridges R"( )", // UI_ICON_FADER - exact asset fader cap from assets/fader.svg R"SVG( )SVG", }; U8 *ui_icons_rasterize_atlas(S32 *out_w, S32 *out_h, S32 icon_size) { // Pack icons in a row S32 atlas_w = icon_size * UI_ICON_COUNT; S32 atlas_h = icon_size; // Pad to power of 2 isn't necessary for correctness, but ensure minimum size if (atlas_w < 64) atlas_w = 64; if (atlas_h < 64) atlas_h = 64; U8 *atlas = (U8 *)calloc(atlas_w * atlas_h * 4, 1); if (!atlas) return nullptr; S32 pen_x = 0; for (S32 i = 0; i < UI_ICON_COUNT; i++) { auto doc = lunasvg::Document::loadFromData(g_icon_svgs[i]); if (!doc) continue; lunasvg::Bitmap bmp = doc->renderToBitmap(icon_size, icon_size); if (bmp.isNull()) continue; // Copy BGRA premultiplied → RGBA straight (un-premultiply) U8 *src = bmp.data(); S32 bmp_w = bmp.width(); S32 bmp_h = bmp.height(); S32 stride = bmp.stride(); for (S32 y = 0; y < bmp_h && y < atlas_h; y++) { for (S32 x = 0; x < bmp_w && (pen_x + x) < atlas_w; x++) { U8 *s = &src[y * stride + x * 4]; S32 dst_idx = (y * atlas_w + pen_x + x) * 4; U8 b = s[0], g = s[1], r = s[2], a = s[3]; if (a > 0 && a < 255) { r = (U8)((r * 255) / a); g = (U8)((g * 255) / a); b = (U8)((b * 255) / a); } atlas[dst_idx + 0] = r; atlas[dst_idx + 1] = g; atlas[dst_idx + 2] = b; atlas[dst_idx + 3] = a; } } // Store UV and pixel info g_icons[i].u0 = (F32)pen_x / (F32)atlas_w; g_icons[i].v0 = 0.0f; g_icons[i].u1 = (F32)(pen_x + bmp_w) / (F32)atlas_w; g_icons[i].v1 = (F32)bmp_h / (F32)atlas_h; g_icons[i].w = (F32)bmp_w; g_icons[i].h = (F32)bmp_h; pen_x += icon_size; } *out_w = atlas_w; *out_h = atlas_h; return atlas; }