package main import rl "libraries/raylib" import fixed_pool "libraries/pool" import "base:runtime" import "core:math" import "core:math/linalg" import "core:fmt" WINDOW_WIDTH :: 1280 WINDOW_HEIGHT :: 720 WINDOW_FRAMERATE :: 30 WINDOW_CAPTION :: "Transformation Visualizer" MATRIX_FIELD_COUNT :: 1024 MATRIX_FIELD_BYTES :: 8 program: Program FontStyle :: struct { font: rl.Font, size, spacing: f32 } Program :: struct { ui_state: UiState, matrix_field_pool: FieldPool(f32), grid: Grid, font_style: FontStyle, } Grid :: struct { area: rect2, inner_area: rect2, zoom: f32, } FIELD_BYTE_COUNT :: 8 FieldInput :: [FIELD_BYTE_COUNT]byte FieldPool :: struct($T: typeid) { values: fixed_pool.Pool(T), inputs: fixed_pool.Pool(FieldInput), } field_pool_get :: proc(pool: ^FieldPool($T), count: int) -> (values: []T, inputs: []FieldInput) { return fixed_pool.get(&pool.values, count), fixed_pool.get(&pool.inputs, count) } field_pool_init :: proc(pool: ^FieldPool($T), capacity: int, allocator := context.allocator) { fixed_pool.init(&pool.values, capacity, allocator) fixed_pool.init(&pool.inputs, capacity, allocator) } field_pool_free_range :: proc(pool: ^FieldPool($T), from: int, count: int) { fixed_pool.free_range(&pool.values, from, count) fixed_pool.free_range(&pool.inputs, from, count) } Field :: struct($T: typeid) { value: f32, input: FieldInput, } field_pool_get_allocated_elems :: proc(pool: ^FieldPool($T)) -> #soa[]Field(T) { values := fixed_pool.get_allocated_elems(pool.values) fields := fixed_pool.get_allocated_elems(pool.inputs) return soa_zip(value = values, input = fields) } draw_text :: proc(text: cstring, position: v2, style: FontStyle, color: rl.Color) { rl.DrawTextEx(style.font, text, position, style.size, style.spacing, color) } TextHalign :: enum { Left, Middle, Right, } TextValign :: enum { Top, Center, Bottom, } draw_text_aligned :: proc(text: cstring, position: v2, style: FontStyle, halign: TextHalign, valign: TextValign, color: rl.Color) { size := measure_text(text, style) position := position switch halign { case .Left: case .Middle: position.x -= size.x / 2.0 case .Right: position.x -= size.x } switch valign { case .Top: case .Center: position.y -= size.y / 2.0 case .Bottom: position.y -= size.y } draw_text(text, position, style, color) } field_pool_add_mat2 :: proc(pool: ^FieldPool(f32), m: mat2) { values, _ := field_pool_get(pool, 4) m := m floats := cast([^]f32)&m[0, 0] #unroll for i in 0..<4 {values[i] = floats[i]} } program_add_mat2 :: proc(data: rawptr) { data := cast(^UiButton_AddMat2CallbackData)data field_pool_add_mat2(&data.program.matrix_field_pool, data.mat) } UiButton_AddMat2CallbackData :: struct { program: ^Program, mat: mat2, } measure_text :: proc(text: cstring, style: FontStyle) -> v2 { return rl.MeasureTextEx(style.font, text, style.size, style.spacing) } MatrixType :: enum { Mat2, Mat3, Mat4, } @rodata matrix_type_table := [MatrixType]typeid { .Mat2 = mat2, .Mat3 = mat3, .Mat4 = mat4, } init :: proc() { rl.SetTraceLogLevel(.WARNING) rl.SetConfigFlags({.WINDOW_RESIZABLE, .VSYNC_HINT}) rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION) rl.SetTargetFPS(WINDOW_FRAMERATE) field_pool_init(&program.matrix_field_pool, 4096, context.allocator) program.font_style = { font = rl.GetFontDefault(), size = 16.0, spacing = 1.0 } program.grid = { area = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}, inner_area = {-1, -1, 2, 2}, zoom = 1.0, } ui_style := UiStyle{ margin = 4.0, padding = 4.0, font_style = program.font_style, } ui_init(&program.ui_state, ui_style, {0, 0}, context.temp_allocator) } update :: proc() { if rl.IsMouseButtonPressed(.LEFT) { ui_element_focus_reset(&program.ui_state) } matrix_add_button_callback_data := UiButton_AddMat2CallbackData { program = &program, mat = mat2{0, 1, 2, 3}, } ui_button_size_top_bar := v2{32.0, 32.0} ui_start(&program.ui_state) ui_container_begin({label = ""}) ui_button(ui_button_size_top_bar, {label = "#10#", callback = program_add_mat2, callback_data = cast(rawptr)&matrix_add_button_callback_data}) ui_same_line() ui_button(ui_button_size_top_bar, {label = "#11#"}) ui_same_line() ui_button(ui_button_size_top_bar, {label = "#12#"}) ui_container_end() ui_container_begin({label = "Matrices"}) field_pool := &program.matrix_field_pool if fixed_pool.usage(field_pool.values) == 0 { ui_text({text = "Add matrices", color = rl.WHITE}) } else { fields := field_pool_get_allocated_elems(field_pool) matrix_count := len(fields) / 4 matrix_field_input_size := v2{48.0, 32.0} for i in 0.. bool { when ODIN_OS != .JS { if rl.WindowShouldClose() { return false } } return true }