diff --git a/program.odin b/program.odin index 03782d8..d5f13b6 100644 --- a/program.odin +++ b/program.odin @@ -4,6 +4,7 @@ import rl "libraries/raylib" import ui "libraries/snths_ui" import "core:fmt" import "core:math/linalg" +import "core:strconv" UiContainerType :: enum { Normal, @@ -63,18 +64,6 @@ MatrixTypes :: enum { .Rotation = rl.KeyboardKey.R, } -matrix_add_hotkey_proc_identity :: proc() {program_add_identity_matrix()} -matrix_add_hotkey_proc_translation :: proc() {program_show_dialog(&program, .CreateTranslationMatrix)} -matrix_add_hotkey_proc_scale :: proc() {program_show_dialog(&program, .CreateScaleMatrix)} -matrix_add_hotkey_proc_rotation :: proc() {program_show_dialog(&program, .CreateRotationMatrix)} - -@rodata matrix_add_procs := [MatrixTypes](proc()) { - .Identity = matrix_add_hotkey_proc_identity, - .Translation = matrix_add_hotkey_proc_translation, - .Scale = matrix_add_hotkey_proc_scale, - .Rotation = matrix_add_hotkey_proc_rotation, -} - FontStyle :: struct { font: rl.Font, size, spacing: f32 @@ -161,6 +150,16 @@ matrix_pool_get_mat3 :: proc() -> ^mat3 { return mat } +matrix_pool_get_mat3_2 :: proc() -> []InputFloatField { + assert(program.matrix_count + 1 < matrix_pool_max(), "Max matrix count exceeded") + value_strings := program.matrix_value_string_pool[program.matrix_count * 9 : program.matrix_count * 9 + 9] + for &str in value_strings { + str[0] = '0' + } + program.matrix_count += 1 + return value_strings +} + program_show_dialog :: proc(program: ^Program, dialog_type: ProgramDialogType) { program.dialog_data = {} program.ui_overlay_queue_focus_first = true @@ -198,22 +197,29 @@ program_update :: proc() { ui_elements, matrix_container := program_build_workspace_ui(&program.ui_context) ui_overlay_elements: []ui.Element - for hotkey, i in matrix_add_hotkeys { - if rl.IsKeyPressed(hotkey) { - matrix_add_procs[i]() - } - } - switch program.state { case .Normal: program.mouse_state = program_handle_mouse_workspace(program.mouse_state, matrix_container) if rl.IsKeyPressed(.TAB) { program.ui_element_focus = ui.focus_next_element(program.ui_element_focus, ui_elements, UI_ALLOWED_FOCUS) } + for hotkey, index in matrix_add_hotkeys { + if rl.IsKeyPressed(hotkey) { + switch index { + case .Identity: program_add_identity_matrix() + case .Translation: program_show_dialog(&program, .CreateTranslationMatrix) + case .Scale: program_show_dialog(&program, .CreateScaleMatrix) + case .Rotation: program_show_dialog(&program, .CreateRotationMatrix) + } + } + } case .Message: case .Dialog: ui_overlay_elements = program_build_dialog_ui(&program.ui_overlay_context, program.dialog_type) + if rl.IsKeyPressed(.TAB) { + program.ui_overlay_element_focus = ui.focus_next_element(program.ui_overlay_element_focus, ui_overlay_elements, UI_ALLOWED_FOCUS) + } if rl.IsKeyDown(.ENTER) { vals := program.dialog_data.input_values switch program.dialog_type { @@ -234,7 +240,9 @@ program_update :: proc() { grid_inner_position := rect_get_tl(grid.inner_area) draw_grid(grid.area, {32.0, 32.0}, rl.GRAY) - program.ui_element_focus = program_render_ui_and_handle_focus(&program.ui_context, program.ui_element_focus, program.font_style, ui_elements) + ui_element_focus := program.state == .Normal ? program.ui_element_focus : ui.element_id_invalid() + program.ui_element_focus = program_render_ui_and_handle_focus(&program.ui_context, ui_element_focus, program.font_style, ui_elements) + if len(ui_overlay_elements) > 0 { rl.DrawRectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, {0, 0, 0, 192}) program.ui_overlay_element_focus = program_render_ui_and_handle_focus( @@ -246,40 +254,43 @@ program_update :: proc() { } program_add_identity_matrix :: proc() { - mat := matrix_pool_get_mat3() - mat^ = { - 1, 0, 0, - 0, 1, 0, - 0, 0, 1, - } + value_strings := matrix_pool_get_mat3_2() + value_strings[0][0] = '1' + value_strings[4][0] = '1' + value_strings[8][0] = '1' } program_add_translation_matrix :: proc(x, y, z: f32) { - mat := matrix_pool_get_mat3() - mat^ = { - 1, 0, x, - 0, 1, y, - 0, 0, z, - } + value_strings := matrix_pool_get_mat3_2() + fmt.bprint(value_strings[2][:], x) + fmt.bprint(value_strings[5][:], y) + fmt.bprint(value_strings[8][:], z) } program_add_scalar_matrix :: proc(x, y, z: f32) { - mat := matrix_pool_get_mat3() - mat^ = { - x, 0, 0, - 0, y, 0, - 0, 0, z, - } + value_strings := matrix_pool_get_mat3_2() + fmt.bprint(value_strings[0][:], x) + fmt.bprint(value_strings[4][:], y) + fmt.bprint(value_strings[8][:], z) } program_add_rotation_matrix :: proc(angle: f32) { - mat := matrix_pool_get_mat3() + value_strings := matrix_pool_get_mat3_2() rotmat := linalg.matrix2_rotate_f32(angle) - mat^ = { - rotmat[0, 0], rotmat[0, 1], 0, - rotmat[1, 0], rotmat[1, 1], 0, - 0, 0, 1, - } + fmt.bprint(value_strings[0][:], rotmat[0, 0]) + fmt.bprint(value_strings[1][:], rotmat[0, 1]) + fmt.bprint(value_strings[3][:], rotmat[1, 0]) + fmt.bprint(value_strings[4][:], rotmat[1, 1]) +} + +ui_labeled_input_float_element :: proc(label: cstring, margin: f32, value: ^f32, value_string: ^InputFloatField, allocator := context.temp_allocator) -> ^ui.Element { + label := fmt.ctprintf("%s: ", label) + label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) + dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} + ui.same_line() + input_data := new(UiElementData_FloatInput, context.temp_allocator) + input_data^ = {value = value, value_string = cstring(&value_string[0])} + return ui.element(.InputFloat, dimensions, {margin = margin}, input_data) } program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType) -> []ui.Element { @@ -297,11 +308,17 @@ program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType ui.start(ctx, V2_ZERO, {WINDOW_WIDTH, WINDOW_HEIGHT}) ui.container_begin(ui.dimensions_auto(), {margin = container_margin, padding = 8.0}) - ui.element(.Label, {}, {label = program_dialog_messages[program.dialog_type], color = ui.col(rl.WHITE), margin = element_margin}) - ui_labeled_input_float_element("X", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0]) - ui_labeled_input_float_element("Y", 4.0, &dialog_data.input_values[1], &dialog_data.input_value_strings[1]) - ui_labeled_input_float_element("Z", 4.0, &dialog_data.input_values[2], &dialog_data.input_value_strings[2]) + switch dialog_type { + case .CreateTranslationMatrix, .CreateScaleMatrix: + ui.element(.Label, {}, {label = program_dialog_messages[program.dialog_type], color = ui.col(rl.WHITE), margin = element_margin}) + ui_labeled_input_float_element("X", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0]) + ui_labeled_input_float_element("Y", 4.0, &dialog_data.input_values[1], &dialog_data.input_value_strings[1]) + ui_labeled_input_float_element("Z", 4.0, &dialog_data.input_values[2], &dialog_data.input_value_strings[2]) + case .CreateRotationMatrix: + ui.element(.Label, {}, {label = program_dialog_messages[program.dialog_type], color = ui.col(rl.WHITE), margin = element_margin}) + ui_labeled_input_float_element("Angle", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0]) + } button_data: ^UiElementData_Button button_data = new(UiElementData_Button, context.temp_allocator) button_data^ = {type = button_type} @@ -315,39 +332,6 @@ program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType return ui.end() } -ui_labeled_input_float_element :: proc(label: cstring, margin: f32, value: ^f32, value_string: ^InputFloatField, allocator := context.temp_allocator) -> ^ui.Element { - label := fmt.ctprintf("%s: ", label) - label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) - dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} - ui.same_line() - input_data := new(UiElementData_FloatInput, context.temp_allocator) - input_data^ = {value = value, value_string = cstring(&value_string[0])} - return ui.element(.InputFloat, dimensions, {margin = margin}, input_data) -} - -program_handle_mouse_workspace :: proc(mouse_state: MouseState, matrix_container: ^ui.Element) -> MouseState { - mouse := rl.GetMousePosition() - switch mouse_state { - case .Hover: - if rl.IsMouseButtonPressed(.LEFT) { - return .DraggingGrid - } else if rect_has_point(rect2(matrix_container.area), mouse) { - return .HoverMatrices - } - case .DraggingGrid: - program.grid.inner_area = rect_translate(program.grid.inner_area, rl.GetMouseDelta()) - if !rl.IsMouseButtonDown(.LEFT) { - return .Hover - } - case .HoverMatrices: - program.matrix_scroll = max(0, program.matrix_scroll - rl.GetMouseWheelMove() * program.matrix_scroll_speed) - if !rect_has_point(rect2(matrix_container.area), mouse) { - return .Hover - } - } - return mouse_state -} - program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element, matrix_container: ^ui.Element) { ui.start(ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}) top_bar_container_config := ui.ElementConfiguration {margin = 4.0} @@ -404,6 +388,29 @@ program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element, return } +program_handle_mouse_workspace :: proc(mouse_state: MouseState, matrix_container: ^ui.Element) -> MouseState { + mouse := rl.GetMousePosition() + switch mouse_state { + case .Hover: + if rl.IsMouseButtonPressed(.LEFT) { + return .DraggingGrid + } else if rect_has_point(rect2(matrix_container.area), mouse) { + return .HoverMatrices + } + case .DraggingGrid: + program.grid.inner_area = rect_translate(program.grid.inner_area, rl.GetMouseDelta()) + if !rl.IsMouseButtonDown(.LEFT) { + return .Hover + } + case .HoverMatrices: + program.matrix_scroll = max(0, program.matrix_scroll - rl.GetMouseWheelMove() * program.matrix_scroll_speed) + if !rect_has_point(rect2(matrix_container.area), mouse) { + return .Hover + } + } + return mouse_state +} + program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: ui.ElementId, font_style: FontStyle, elements: []ui.Element) -> (focus: ui.ElementId) { scissor_container: ^ui.Element render_above: ui.Element