package imgui import "core:container/queue" import "core:log" import "microui" MAX_DRAW_COMMANDS :: #config(IMGUI_MAX_DRAW_COMMANDS, 512 * 1024) // TODO: SS - Consider not having 'microui' as a seperate package and instead have it (and other backends) in the 'imgui' package directly. IMGUI_BACKEND_MICROUI :: #config(IMGUI_BACKEND_MICROUI, false) when IMGUI_BACKEND_MICROUI { Context_Backend :: microui.Context } Context :: struct { backend: ^Context_Backend, draw_commands: queue.Queue(Draw_Command), input: Input, } Input :: struct { mouse_state: Mouse_State, } Mouse_Button_State :: enum { Up, Pressed, Down, Released, } Mouse_State :: struct { pos_x, pos_y: u16, left, middle, right: Mouse_Button_State, } Draw_Command :: struct { color: [4]u8, type: Draw_Command_Type, } Draw_Command_Type :: union { Draw_Command_Rect, } Draw_Command_Rect :: struct { x, y, width, height: u16, } Rect :: struct { x, y, width, height: u16, } init :: proc(ctx: ^Context) -> bool { assert(ctx != nil) assert(ctx.backend == nil) backend, err := new(Context_Backend) if err != .None { log.errorf("Failed to allocate space for the backend. Error: %v", err) return false } ctx.backend = backend ok := false when IMGUI_BACKEND_MICROUI { ok = microui.init(ctx.backend) } if !ok { free(backend) return false } queue_err := queue.init(&ctx.draw_commands, MAX_DRAW_COMMANDS) if queue_err != .None { free(backend) log.errorf("Failed to allocate space for the queue of imgui draw-commands. Error: %v", queue_err) return false } return true } set_input :: proc(ctx: ^Context, input: Input) { ctx.input = input } begin :: proc(ctx: ^Context) { assert(ctx != nil) assert(ctx.backend != nil) when IMGUI_BACKEND_MICROUI { input: microui.Input input.mouse_x = ctx.input.mouse_state.pos_x input.mouse_y = ctx.input.mouse_state.pos_y if ctx.input.mouse_state.left == .Pressed { input.mouse_buttons_pressed += { .LEFT } } else if ctx.input.mouse_state.left == .Released { input.mouse_buttons_released += { .LEFT } } if ctx.input.mouse_state.middle == .Pressed { input.mouse_buttons_pressed += { .MIDDLE } } else if ctx.input.mouse_state.middle == .Released { input.mouse_buttons_released += { .MIDDLE } } if ctx.input.mouse_state.right == .Pressed { input.mouse_buttons_pressed += { .RIGHT } } else if ctx.input.mouse_state.right == .Released { input.mouse_buttons_released += { .RIGHT } } microui.begin(ctx.backend, input) } } end :: proc(ctx: ^Context) { assert(ctx != nil) assert(ctx.backend != nil) when IMGUI_BACKEND_MICROUI { microui.end(ctx.backend) } } begin_window :: proc(ctx: ^Context, title: string, rect: Rect) -> bool { assert(ctx != nil) when IMGUI_BACKEND_MICROUI { return microui.begin_window(ctx.backend, title, microui.Rect { x = i32(rect.x), y = i32(rect.y), w = i32(rect.width), h = i32(rect.height), }) } return false } end_window :: proc(ctx: ^Context) { assert(ctx != nil) when IMGUI_BACKEND_MICROUI { microui.end_window(ctx.backend) } } button :: proc(ctx: ^Context, title: string) -> bool { when IMGUI_BACKEND_MICROUI { return microui.button(ctx.backend, title) } return false } collect :: proc(ctx: ^Context) { // TODO: SS - Come up with a better name. Adds commands from backend to queue in ctx. assert(ctx != nil) // TODO: SS - Reduce code-repetition if possible. MicroUI asks to be "popped"/iterated like this, apparently. when IMGUI_BACKEND_MICROUI { last_cmd: ^microui.Command = nil for { dc: Draw_Command dc.type = nil cmd := microui.pop_draw_command(ctx.backend, last_cmd) if cmd == nil { break } last_cmd = cmd #partial switch &v in &cmd.variant { // case ^microui.Command_Jump: {} // Internal. // case ^microui.Command_Clip: { // } // case ^microui.Command_Icon: { // } case ^microui.Command_Rect: { assert(v.rect.x >= 0) assert(v.rect.y >= 0) assert(v.rect.w >= 0) assert(v.rect.h >= 0) dc.color = { v.color.r, v.color.g, v.color.b, v.color.a, } dc.type = Draw_Command_Rect { x = u16(v.rect.x), y = u16(v.rect.y), width = u16(v.rect.w), height = u16(v.rect.h), } } // case ^microui.Command_Text: { // } } if dc.type != nil { queue.push_back(&ctx.draw_commands, dc) } } } } pop_draw_command :: proc(ctx: ^Context, out_draw_command: ^Draw_Command) -> bool { assert(ctx != nil) assert(out_draw_command != nil) out_draw_command^ = {} elem, ok := queue.pop_front_safe(&ctx.draw_commands) if !ok { return false } out_draw_command^ = elem return true } shutdown :: proc(ctx: ^Context) { assert(ctx != nil) assert(ctx.backend != nil) when IMGUI_BACKEND_MICROUI { microui.shutdown(ctx.backend) } free(ctx.backend) ctx.backend = nil queue.destroy(&ctx.draw_commands) }