249 lines
6.1 KiB
Odin
249 lines
6.1 KiB
Odin
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)
|
|
} |