commit 7dfb47fcced6aa37479df6ad612b8824421b9b88
parent a98eb13225176520c149b948cd0bb56199e852e2
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date: Sun, 23 Nov 2025 14:55:00 -0300
example: microui
Signed-off-by: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Diffstat:
4 files changed, 587 insertions(+), 182 deletions(-)
diff --git a/example/microui.odin b/example/microui.odin
@@ -1,88 +1,624 @@
+/*
+ This example showcases Blend2d as the rendering backend for microui, using SDL
+ as the cross platform graphics API.
+
+ SDL is used to create the OS window and provide a rendering context.
+ Blend2d draws directly into the pixel buffer of an SDL GPU texture.
+ microui is used to implement the UI layout.
+
+ SDL events -> microui
+ microui -> render commands -> Blend2d
+ Blend2d -> GPU texture
+
+ You can also render microui using SDL drawing primitives, but the point is
+ to use Blend2d to do rendering on the CPU.
+
+ Bugs:
+ - log text input not working
+ - clips are too aggressive on paths (text + icons)
+*/
package main
+import "core:c"
+
+import "base:runtime"
import "core:fmt"
-import "core:thread"
+import "core:math"
+import "core:mem/virtual"
+import "core:strings"
import bl "../binding"
import mu "vendor:microui"
import sdl "vendor:sdl3"
-//todo need windowing lib
-// SDL3
-// tigr (neess bindings)
-// glfw
-//todo user input
-// font loading
+// FontHandle is provided to microui, allowing access to the context within text
+// measuring callbacks.
+FontHandle :: struct {
+ ctx: ^Context,
+ font: ^bl.FontCore,
+}
+
+// Context is an amalgam of state required by SDL, microui, blend2d and the ui logic.
Context :: struct {
+ runtime_context: runtime.Context,
mu_ctx: ^mu.Context,
bl_ctx: ^bl.ContextCore,
+ face: ^bl.FontFaceCore,
+ font: ^bl.FontCore,
+ window: ^sdl.Window,
+ renderer: ^sdl.Renderer,
+ texture: ^sdl.Texture,
+ bg: mu.Color,
+ cookie: bl.ContextCookie,
log_buf: [1 << 16]byte,
log_buf_len: int,
log_buf_updated: bool,
- bg: mu.Color,
+ frame_count: i64,
+ render_width: i32,
+ render_height: i32,
+ logical_width: i32,
+ logical_height: i32,
+ scale: i32,
+ debug_text: bool,
}
+// context_init initializes SDL, blend2d and microui.
context_init :: proc(ctx: ^Context) {
+ ctx.runtime_context = context
+
ctx.bl_ctx = new(bl.ContextCore)
- bl.context_init(ctx.bl_ctx)
+
+ if bl.context_init(ctx.bl_ctx) != 0 {
+ panic("failed to create blend2d context")
+ }
+
ctx.mu_ctx = new(mu.Context)
mu.init(ctx.mu_ctx)
+
+ assert(sdl.Init({.VIDEO, .EVENTS}))
+
+ display_mode := sdl.GetCurrentDisplayMode(sdl.GetPrimaryDisplay())
+ ctx.scale = i32(display_mode.pixel_density)
+
+ window := sdl.CreateWindow(
+ "microui - blend2d - sdl3",
+ WINDOW_WIDTH,
+ WINDOW_HEIGHT,
+ {.RESIZABLE, .HIGH_PIXEL_DENSITY},
+ )
+
+ ctx.window = window
+
+ renderer := sdl.CreateRenderer(window, "")
+
+ ctx.renderer = renderer
+
+ sdl.GetRenderOutputSize(renderer, &ctx.render_width, &ctx.render_height)
+
+ texture := sdl.CreateTexture(
+ renderer,
+ .RGBA32,
+ .STREAMING,
+ ctx.render_width,
+ ctx.render_height,
+ )
+ ctx.texture = texture
+
+ sdl.SetTextureBlendMode(
+ texture,
+ sdl.ComposeCustomBlendMode(
+ .ONE,
+ .ONE_MINUS_SRC_ALPHA,
+ .ADD,
+ .ONE,
+ .ONE_MINUS_SRC_ALPHA,
+ .ADD,
+ ),
+ )
+
+ sdl.SetRenderVSync(renderer, 1)
+
+ window_scale := sdl.GetWindowDisplayScale(ctx.window)
+ window_pixel_density := sdl.GetWindowPixelDensity(ctx.window)
+ sdl.GetRenderOutputSize(ctx.renderer, &ctx.render_width, &ctx.render_height)
+
+ /*
+ init font
+ */
+
+ {
+ ctx.face = new(bl.FontFaceCore)
+ bl.font_face_init(ctx.face)
+
+ if bl.font_face_create_from_file(
+ ctx.face,
+ "./example/resource/Roboto-Medium.ttf",
+ .NO_FLAGS,
+ ) !=
+ 0 {
+ panic("failed to load font")
+ }
+
+ ctx.font = new(bl.FontCore)
+ assert(bl.font_init(ctx.font) == 0)
+
+ assert(bl.font_create_from_face(ctx.font, ctx.face, f32(14 * ctx.scale)) == 0)
+
+ // Setup the font handle. Provides access to the context in the text measuring
+ // callbacks.
+ fh := new(FontHandle)
+ fh.ctx = ctx
+ fh.font = ctx.font
+ ctx.mu_ctx.style.font = mu.Font(fh)
+
+ ctx.mu_ctx.text_height = proc(font: mu.Font) -> i32 {
+ if font == nil {
+ return 0
+ }
+
+ fh := cast(^FontHandle)(font)
+
+ fm: bl.FontMetrics
+ bl.font_get_metrics(fh.font, &fm)
+
+ height := i32(fm.ascent + fm.descent)
+
+ // The font measurements need to be unscaled because microui
+ // works within a logical coordinate space.
+ return height / fh.ctx.scale
+ }
+
+ ctx.mu_ctx.text_width = proc(font: mu.Font, text: string) -> i32 {
+ if font == nil {
+ return 0
+ }
+
+ fh := cast(^FontHandle)(font)
+
+ @(static) gb: bl.GlyphBufferCore
+ bl.glyph_buffer_init(&gb)
+ defer bl.glyph_buffer_reset(&gb)
+
+ bl.glyph_buffer_set_text(&gb, raw_data(text), len(text), .UTF8)
+
+ tm: bl.TextMetrics
+ bl.font_get_text_metrics(fh.font, &gb, &tm)
+
+ // The font measurements need to be unscaled because microui
+ // works within a logical coordinate space.
+ return i32(tm.advance.x) / fh.ctx.scale
+ }
+ }
}
+WINDOW_WIDTH :: 800
+WINDOW_HEIGHT :: 800
+
main :: proc() {
ctx: Context
-
context_init(&ctx)
- assert(sdl.Init({.VIDEO, .EVENTS}))
+ arena: virtual.Arena
+ assert(virtual.arena_init_growing(&arena) == nil)
+ context.allocator = virtual.arena_allocator(&arena)
+
+ sdl.GetWindowSize(ctx.window, &ctx.logical_width, &ctx.logical_height)
+
+ mainloop: for {
+ defer virtual.arena_free_all(&arena)
+ defer ctx.frame_count += 1
+
+ event: sdl.Event
+
+ for sdl.PollEvent(&event) {
+ #partial switch event.type {
+ case .QUIT:
+ break mainloop
+ case .MOUSE_MOTION:
+ mu.input_mouse_move(
+ ctx.mu_ctx,
+ i32(math.round(event.motion.x)),
+ i32(math.round(event.motion.y)),
+ )
+ case .MOUSE_BUTTON_DOWN:
+ if btn := sdl_button_to_mu_button(event.button.button); btn != nil {
+ mu.input_mouse_down(
+ ctx.mu_ctx,
+ i32(math.round(event.button.x)),
+ i32(math.round(event.button.y)),
+ btn.?,
+ )
+ }
+ case .MOUSE_BUTTON_UP:
+ if btn := sdl_button_to_mu_button(event.button.button); btn != nil {
+ mu.input_mouse_up(
+ ctx.mu_ctx,
+ i32(math.round(event.button.x)),
+ i32(math.round(event.button.y)),
+ btn.?,
+ )
+ }
+ case .MOUSE_WHEEL:
+ mu.input_scroll(
+ ctx.mu_ctx,
+ i32(event.wheel.integer_x * -30),
+ i32(event.wheel.integer_y * -30),
+ )
+ case .KEY_DOWN:
+ if key := sdl_key_to_mu_key(event.key.key); key != nil {
+ mu.input_key_down(ctx.mu_ctx, key.?)
+ }
+ case .KEY_UP:
+ if key := sdl_key_to_mu_key(event.key.key); key != nil {
+ mu.input_key_up(ctx.mu_ctx, key.?)
+ }
+ case .TEXT_INPUT:
+ mu.input_text(ctx.mu_ctx, strings.clone_from_cstring(event.text.text))
+ }
+ }
- window := sdl.CreateWindow(
- "microui - blend2d - sdl3",
- 800,
- 800,
- {.HIGH_PIXEL_DENSITY, .RESIZABLE},
+ render(&ctx)
+ }
+}
+
+sdl_button_to_mu_button :: proc(sdl_btn: u8) -> Maybe(mu.Mouse) {
+ switch sdl_btn {
+ case sdl.BUTTON_LEFT:
+ return .LEFT
+ case sdl.BUTTON_RIGHT:
+ return .RIGHT
+ case sdl.BUTTON_MIDDLE:
+ return .MIDDLE
+ case:
+ return nil
+ }
+}
+
+sdl_key_to_mu_key :: proc(sdl_key: sdl.Keycode) -> (ret: Maybe(mu.Key)) {
+ switch sdl_key {
+ case sdl.K_LSHIFT, sdl.K_RSHIFT:
+ return .SHIFT
+ case sdl.K_LCTRL, sdl.K_RCTRL:
+ return .CTRL
+ case sdl.K_LALT, sdl.K_RALT:
+ return .ALT
+ case sdl.K_BACKSPACE:
+ return .BACKSPACE
+ case sdl.K_DELETE:
+ return .DELETE
+ case sdl.K_RETURN:
+ return .RETURN
+ case sdl.K_LEFT:
+ return .LEFT
+ case sdl.K_RIGHT:
+ return .RIGHT
+ case sdl.K_HOME:
+ return .HOME
+ case sdl.K_END:
+ return .END
+ case sdl.K_A:
+ return .A
+ case sdl.K_X:
+ return .X
+ case sdl.K_C:
+ return .C
+ case sdl.K_V:
+ return .V
+ case:
+ return nil
+ }
+}
+
+render :: proc(ctx: ^Context) {
+ pixels: rawptr
+ pitch: c.int
+
+ if !sdl.LockTexture(ctx.texture, nil, &pixels, &pitch) {
+ return
+ }
+
+ img: bl.ImageCore
+
+ image_init_res := bl.image_init_as_from_data(
+ &img,
+ i32(ctx.render_width),
+ i32(ctx.render_height),
+ .PRGB32,
+ pixels,
+ int(pitch),
+ .RW,
+ nil,
+ nil,
)
- // NOTE: mus tbe requeried if window is resized.
- surface := sdl.GetWindowSurface(window)
+ if image_init_res != 0 {
+ return
+ }
- print_sdl_pixel_format(surface.format)
+ defer bl.image_reset(&img)
+
+ {
+ bl.context_begin(ctx.bl_ctx, &img, nil)
+ defer bl.context_end(ctx.bl_ctx)
+
+ mu.begin(ctx.mu_ctx)
+ all_windows(ctx)
+ mu.end(ctx.mu_ctx)
+
+ bl.context_clear_all(ctx.bl_ctx)
+ bl.context_fill_all_rgba32(ctx.bl_ctx, transmute(u32)(ctx.bg))
+
+ // cmd_backing is the iteration context, since mu.next_command is implemented
+ // via pointer math.
+ cmd_backing: ^mu.Command
+ for var in mu.next_command_iterator(ctx.mu_ctx, &cmd_backing) {
+ switch cmd in var {
+ case ^mu.Command_Text:
+ _render_text(ctx, cmd)
+ case ^mu.Command_Icon:
+ _render_icon(ctx, cmd)
+ case ^mu.Command_Rect:
+ _render_rect(ctx, cmd)
+ case ^mu.Command_Clip:
+ _set_clip(ctx, cmd)
+ case ^mu.Command_Jump:
+ panic("jm_ jump command")
+ }
+ }
- // img: bl.ImageCore
+ }
- // bl.image_init(&img)
- // bl.image_create(&img, 480, 480, .PRGB32)
+ src := sdl.FRect {
+ w = f32(ctx.render_width),
+ h = f32(ctx.render_height),
+ }
- // for {
- // defer thread.yield()
- // mu.begin(ctx.mu_ctx)
- // all_windows(&ctx)
- // mu.end(ctx.mu_ctx)
- // render(&ctx)
- // }
+ sdl.UnlockTexture(ctx.texture)
+ sdl.SetRenderDrawColor(ctx.renderer, 0, 0, 0, 255)
+ sdl.RenderClear(ctx.renderer)
+ sdl.RenderTexture(ctx.renderer, ctx.texture, &src, nil)
+ sdl.RenderPresent(ctx.renderer)
+
+ texture_width: f32
+ texture_height: f32
+ sdl.GetTextureSize(ctx.texture, &texture_width, &texture_height)
+
+ sdl.SetWindowTitle(
+ ctx.window,
+ fmt.ctprintf(
+ "render %vx%v texture %vx%v logical %vx%v scale %v mouse (%v,%v)",
+ ctx.render_width,
+ ctx.render_height,
+ ctx.logical_width,
+ ctx.logical_height,
+ texture_width,
+ texture_height,
+ ctx.scale,
+ ctx.mu_ctx.mouse_pos.x,
+ ctx.mu_ctx.mouse_pos.y,
+ ),
+ )
}
-render :: proc(ctx: ^Context) {
- bl.context_clear_all(ctx.bl_ctx)
- defer bl.context_end(ctx.bl_ctx)
-
- // cmd_backing is the iteration context, since mu.next_command is implemented
- // via pointer math.
- cmd_backing: ^mu.Command
- for var in mu.next_command_iterator(ctx.mu_ctx, &cmd_backing) {
- switch cmd in var {
- case ^mu.Command_Text:
- case ^mu.Command_Icon:
- case ^mu.Command_Rect:
- rect := cast(bl.RectI)(cmd.rect)
- bl.context_fill_rect_i_rgba32(ctx.bl_ctx, &rect, transmute(u32)(cmd.color))
- case ^mu.Command_Clip:
- case ^mu.Command_Jump:
+_render_text :: proc(ctx: ^Context, cmd: ^mu.Command_Text) {
+ font := cast(^FontHandle)(cmd.font)
+ text_data := cast(cstring)(raw_data(cmd.str))
+ text_len := uint(len(cmd.str))
+
+ fm: bl.FontMetrics
+ bl.font_get_metrics(font.font, &fm)
+
+ @(static) glyph_buffer: bl.GlyphBufferCore
+ bl.glyph_buffer_init(&glyph_buffer)
+ defer bl.glyph_buffer_reset(&glyph_buffer)
+
+ bl.glyph_buffer_set_text(&glyph_buffer, rawptr(text_data), uint(text_len), .UTF8)
+
+ tm: bl.TextMetrics
+ bl.font_get_text_metrics(font.font, &glyph_buffer, &tm)
+
+ // draw the text
+ {
+ origin := bl.PointI {
+ x = (cmd.pos.x * ctx.scale) + i32(tm.bounding_box.x0),
+ y = (cmd.pos.y * ctx.scale) + i32(fm.ascent), // Adjust from top to baseline
+ }
+ bl.context_fill_glyph_run_i_rgba32(
+ ctx.bl_ctx,
+ &origin,
+ ctx.font,
+ bl.glyph_buffer_get_glyph_run(&glyph_buffer),
+ transmute(u32)(cmd.color),
+ )
+ }
+
+ if ctx.debug_text {
+ // draw bounding box
+ {
+ rect := bl.RectI {
+ x = (cmd.pos.x * ctx.scale) + i32(tm.bounding_box.x0),
+ y = (cmd.pos.y * ctx.scale),
+ w = i32((tm.advance.x)),
+ h = i32(fm.descent + fm.ascent),
+ }
+ bl.context_stroke_rect_i_rgba32(ctx.bl_ctx, &rect, transmute(u32)(cmd.color))
+
+ }
+ // draw baseline
+ {
+ rect := bl.RectI {
+ x = (cmd.pos.x * ctx.scale) + i32(tm.bounding_box.x0),
+ y = (cmd.pos.y * ctx.scale) + i32(fm.ascent),
+ w = i32((tm.bounding_box.x1 - tm.bounding_box.x0)),
+ h = 1,
+ }
+ bl.context_stroke_rect_i_rgba32(ctx.bl_ctx, &rect, transmute(u32)(cmd.color))
+ }
+ // draw origin
+ {
+ rect := bl.RectI {
+ x = (cmd.pos.x * ctx.scale) + i32(tm.bounding_box.x0) - 6,
+ y = (cmd.pos.y * ctx.scale) - 6,
+ w = 12,
+ h = 12,
+ }
+ bl.context_stroke_rect_i_rgba32(ctx.bl_ctx, &rect, transmute(u32)(cmd.color))
+ }
+ }
+}
+
+_render_rect :: proc(ctx: ^Context, cmd: ^mu.Command_Rect) {
+ rect := bl.RectI {
+ x = cmd.rect.x * ctx.scale,
+ y = cmd.rect.y * ctx.scale,
+ w = cmd.rect.w * ctx.scale,
+ h = cmd.rect.h * ctx.scale,
+ }
+ bl.context_fill_rect_i_rgba32(ctx.bl_ctx, &rect, transmute(u32)(cmd.color))
+}
+
+// _render_icon uses vector paths to draw the icons to showcase blend's path api.
+_render_icon :: proc(ctx: ^Context, cmd: ^mu.Command_Icon) {
+ color := transmute(u32)(cmd.color)
+
+ rect := bl.Rect {
+ x = f64(cmd.rect.x * ctx.scale),
+ y = f64(cmd.rect.y * ctx.scale),
+ w = f64(cmd.rect.w * ctx.scale),
+ h = f64(cmd.rect.h * ctx.scale),
+ }
+
+ switch cmd.id {
+ case .NONE:
+ return
+ case .RESIZE:
+ size := bl.Size {
+ w = 18,
+ h = 18,
+ }
+ _draw_resize(ctx, rect, size, color)
+ case .CLOSE:
+ size := bl.Size {
+ w = 18,
+ h = 18,
+ }
+ _draw_close(ctx, rect, size, color)
+ case .CHECK:
+ size := bl.Size {
+ w = 18,
+ h = 18,
+ }
+ _draw_check(ctx, rect, size, color)
+ case .EXPANDED:
+ size := bl.Size {
+ w = 12,
+ h = 8,
+ }
+ _draw_down_angle(ctx, rect, size, color)
+ case .COLLAPSED:
+ size := bl.Size {
+ w = 8,
+ h = 12,
}
+ _draw_right_angle(ctx, rect, size, color)
+ }
+}
+
+_draw_resize :: proc(ctx: ^Context, rect: bl.Rect, size: bl.Size, rgba: u32) {
+ _draw_icon(ctx, rect, size, rgba, proc(p: ^bl.PathCore, size: bl.Size) {
+ bl.path_move_to(p, size.w, size.h / 2)
+ bl.path_line_to(p, size.w, size.h)
+ bl.path_move_to(p, size.w / 2, size.h)
+ bl.path_line_to(p, size.w, size.h)
+ })
+}
+
+_draw_close :: proc(ctx: ^Context, rect: bl.Rect, size: bl.Size, rgba: u32) {
+ _draw_icon(ctx, rect, size, rgba, proc(p: ^bl.PathCore, size: bl.Size) {
+ bl.path_move_to(p, 0, 0)
+ bl.path_line_to(p, size.w, size.h)
+ bl.path_move_to(p, size.w, 0)
+ bl.path_line_to(p, 0, size.h)
+ })
+}
+
+_draw_check :: proc(ctx: ^Context, rect: bl.Rect, size: bl.Size, rgba: u32) {
+ _draw_icon(ctx, rect, size, rgba, proc(p: ^bl.PathCore, size: bl.Size) {
+ bl.path_move_to(p, 0, (size.h / 2))
+ bl.path_line_to(p, (size.w / 3), size.h)
+ bl.path_line_to(p, size.w, 0)
+ })
+}
+
+_draw_right_angle :: proc(ctx: ^Context, rect: bl.Rect, size: bl.Size, rgba: u32) {
+ _draw_icon(ctx, rect, size, rgba, proc(p: ^bl.PathCore, size: bl.Size) {
+ bl.path_move_to(p, 0, 0)
+ bl.path_line_to(p, size.w, (size.h / 2))
+ bl.path_line_to(p, 0, size.h)
+ })
+}
+
+_draw_down_angle :: proc(ctx: ^Context, rect: bl.Rect, size: bl.Size, rgba: u32) {
+ _draw_icon(ctx, rect, size, rgba, proc(p: ^bl.PathCore, size: bl.Size) {
+ bl.path_move_to(p, 0, 0)
+ bl.path_line_to(p, (size.w / 2), size.h)
+ bl.path_line_to(p, size.w, 0)
+ })
+}
+
+
+// _draw_icon centers the path on the rect and draws it via the path_proc.
+// path_proc is expected to fill the PathCore with lines.
+_draw_icon :: proc(
+ ctx: ^Context,
+ rect: bl.Rect,
+ size: bl.Size,
+ rgba: u32,
+ path_proc: proc(_: ^bl.PathCore, _: bl.Size),
+) {
+ @(static) p: bl.PathCore
+
+ bl.path_init(&p)
+ defer bl.path_reset(&p)
+
+ path_proc(&p, size)
+
+ origin := bl.Point {
+ x = rect.x + (rect.w - size.w) / 2,
+ y = rect.y + (rect.w - size.h) / 2,
}
+ bl.context_set_stroke_options(ctx.bl_ctx, &bl.StrokeOptionsCore{width = 2})
+ defer bl.context_set_stroke_options(ctx.bl_ctx, &bl.StrokeOptionsCore{width = 1})
+
+ bl.context_stroke_path_d_rgba32(ctx.bl_ctx, &origin, &p, rgba)
+}
+
+// FIXME: there's some weird clipping behaviour: the moment text is even partially occluded,
+// the entire text run disappears. Also occurs for icons.
+_set_clip :: proc(ctx: ^Context, cmd: ^mu.Command_Clip) {
+ // TODO: verify this magic number.
+ // It's the number that microui spits out, I think it represents a clip clear
+ // by logically setting the clip to a super large dimension.
+ if cmd.rect.h == 16777216 {
+ bl.context_restore(ctx.bl_ctx, &ctx.cookie)
+ } else {
+ bl.context_save(ctx.bl_ctx, &ctx.cookie)
+ bl.context_clip_to_rect_i(
+ ctx.bl_ctx,
+ &bl.RectI {
+ x = cmd.rect.x * ctx.scale,
+ y = (ctx.render_height - (cmd.rect.y * ctx.scale + cmd.rect.h * ctx.scale)),
+ w = cmd.rect.w * ctx.scale,
+ h = cmd.rect.h * ctx.scale,
+ },
+ )
+ }
}
+/*
+ UI Logic
+*/
u8_slider :: proc(ctx: ^mu.Context, val: ^u8, lo, hi: u8) -> (res: mu.Result_Set) {
mu.push_id(ctx, uintptr(val))
@@ -113,7 +649,7 @@ reset_log :: proc(ctx: ^Context) {
all_windows :: proc(ctx: ^Context) {
@(static) opts := mu.Options{.NO_CLOSE}
- if mu.window(ctx.mu_ctx, "Demo Window", {40, 40, 300, 450}, opts) {
+ if mu.window(ctx.mu_ctx, "Demo Window", {40, 40, 300, 500}, opts) {
if .ACTIVE in mu.header(ctx.mu_ctx, "Window Info") {
win := mu.get_current_container(ctx.mu_ctx)
mu.layout_row(ctx.mu_ctx, {54, -1}, 0)
@@ -201,6 +737,7 @@ all_windows :: proc(ctx: ^Context) {
mu.label(ctx.mu_ctx, "Red:"); u8_slider(ctx.mu_ctx, &ctx.bg.r, 0, 255)
mu.label(ctx.mu_ctx, "Green:"); u8_slider(ctx.mu_ctx, &ctx.bg.g, 0, 255)
mu.label(ctx.mu_ctx, "Blue:"); u8_slider(ctx.mu_ctx, &ctx.bg.b, 0, 255)
+ mu.label(ctx.mu_ctx, "Alpha:"); u8_slider(ctx.mu_ctx, &ctx.bg.a, 0, 255)
}
mu.layout_end_column(ctx.mu_ctx)
@@ -276,141 +813,5 @@ all_windows :: proc(ctx: ^Context) {
mu.draw_rect(ctx.mu_ctx, mu.layout_next(ctx.mu_ctx), ctx.mu_ctx.style.colors[col])
}
}
-
-}
-
-print_sdl_pixel_format :: proc(pf: sdl.PixelFormat) {
- switch pf {
- case .UNKNOWN:
- fmt.println("UNKNOWN")
- case .INDEX1LSB:
- fmt.println("INDEX1LSB")
- case .INDEX1MSB:
- fmt.println("INDEX1MSB")
- case .INDEX2LSB:
- fmt.println("INDEX2LSB")
- case .INDEX2MSB:
- fmt.println("INDEX2MSB")
- case .INDEX4LSB:
- fmt.println("INDEX4LSB")
- case .INDEX4MSB:
- fmt.println("INDEX4MSB")
- case .INDEX8:
- fmt.println("INDEX8")
- case .RGB332:
- fmt.println("RGB332")
- case .XRGB4444:
- fmt.println("XRGB4444")
- case .XBGR4444:
- fmt.println("XBGR4444")
- case .XRGB1555:
- fmt.println("XRGB1555")
- case .XBGR1555:
- fmt.println("XBGR1555")
- case .ARGB4444:
- fmt.println("ARGB4444")
- case .RGBA4444:
- fmt.println("RGBA4444")
- case .ABGR4444:
- fmt.println("ABGR4444")
- case .BGRA4444:
- fmt.println("BGRA4444")
- case .ARGB1555:
- fmt.println("ARGB1555")
- case .RGBA5551:
- fmt.println("RGBA5551")
- case .ABGR1555:
- fmt.println("ABGR1555")
- case .BGRA5551:
- fmt.println("BGRA5551")
- case .RGB565:
- fmt.println("RGB565")
- case .BGR565:
- fmt.println("BGR565")
- case .RGB24:
- fmt.println("RGB24")
- case .BGR24:
- fmt.println("BGR24")
- case .XRGB8888:
- fmt.println("XRGB8888")
- case .RGBX8888:
- fmt.println("RGBX8888")
- case .XBGR8888:
- fmt.println("XBGR8888")
- case .BGRX8888:
- fmt.println("BGRX8888")
- case .ARGB8888:
- fmt.println("ARGB8888")
- case .RGBA8888:
- fmt.println("RGBA8888")
- case .ABGR8888:
- fmt.println("ABGR8888")
- case .BGRA8888:
- fmt.println("BGRA8888")
- case .XRGB2101010:
- fmt.println("XRGB2101010")
- case .XBGR2101010:
- fmt.println("XBGR2101010")
- case .ARGB2101010:
- fmt.println("ARGB2101010")
- case .ABGR2101010:
- fmt.println("ABGR2101010")
- case .RGB48:
- fmt.println("RGB48")
- case .BGR48:
- fmt.println("BGR48")
- case .RGBA64:
- fmt.println("RGBA64")
- case .ARGB64:
- fmt.println("ARGB64")
- case .BGRA64:
- fmt.println("BGRA64")
- case .ABGR64:
- fmt.println("ABGR64")
- case .RGB48_FLOAT:
- fmt.println("RGB48_FLOAT")
- case .BGR48_FLOAT:
- fmt.println("BGR48_FLOAT")
- case .RGBA64_FLOAT:
- fmt.println("RGBA64_FLOAT")
- case .ARGB64_FLOAT:
- fmt.println("ARGB64_FLOAT")
- case .BGRA64_FLOAT:
- fmt.println("BGRA64_FLOAT")
- case .ABGR64_FLOAT:
- fmt.println("ABGR64_FLOAT")
- case .RGB96_FLOAT:
- fmt.println("RGB96_FLOAT")
- case .BGR96_FLOAT:
- fmt.println("BGR96_FLOAT")
- case .RGBA128_FLOAT:
- fmt.println("RGBA128_FLOAT")
- case .ARGB128_FLOAT:
- fmt.println("ARGB128_FLOAT")
- case .BGRA128_FLOAT:
- fmt.println("BGRA128_FLOAT")
- case .ABGR128_FLOAT:
- fmt.println("ABGR128_FLOAT")
- case .YV12:
- fmt.println("YV12")
- case .IYUV:
- fmt.println("IYUV")
- case .YUY2:
- fmt.println("YUY2")
- case .UYVY:
- fmt.println("UYVY")
- case .YVYU:
- fmt.println("YVYU")
- case .NV12:
- fmt.println("NV12")
- case .NV21:
- fmt.println("NV21")
- case .P010:
- fmt.println("P010")
- case .EXTERNAL_OES:
- fmt.println("EXTERNAL_OES")
- case .MJPG:
- fmt.println("MJPG")
- }
}
diff --git a/example/resource/Roboto-Medium.ttf b/example/resource/Roboto-Medium.ttf
Binary files differ.
diff --git a/example/resource/angle-down.svg b/example/resource/angle-down.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc. --><path fill="currentColor" d="M169.4 374.6c12.5 12.5 32.8 12.5 45.3 0l160-160c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 306.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160z"/></svg>
+\ No newline at end of file
diff --git a/example/resource/angle-right.svg b/example/resource/angle-right.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc. --><path fill="currentColor" d="M247.1 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L179.2 256 41.9 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg>
+\ No newline at end of file