From 93ad8a5cdeb8421bcf02195bc470257935062138 Mon Sep 17 00:00:00 2001 From: Alec Goncharow Date: Wed, 27 May 2026 14:34:32 -0400 Subject: Working widget idea, makings of a maze app Forgot to commit as I went over the weekend, which is fine, not a ton of interesting stuff just yet. --- src/main.jai | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 src/main.jai (limited to 'src/main.jai') diff --git a/src/main.jai b/src/main.jai new file mode 100644 index 0000000..897cfb7 --- /dev/null +++ b/src/main.jai @@ -0,0 +1,207 @@ +#import "Basic"; +#import "Window_Creation"; +Simp :: #import "Simp"; +Input :: #import "Input"; +Unicode :: #import "Unicode"; + +#load "widget_interface.jai"; +#load "menu_app.jai"; +#load "apps/example_app.jai"; +#load "apps/maze_app.jai"; +#load "ui_panel.jai"; +#load "debug_overlay.jai"; + +// Global reference to active app state +active_app: *Widget_State; + +// The different apps available +menu_state: Widget_State; +example_state: Widget_State; +maze_state: Widget_State; + +window: Window_Type; +window_width : s32 = 1920; +window_height : s32 = 1080; + +// silly +FRAMES :: 32_768; +frame_times : [FRAMES] float; +frame_times_sum: float; +frame_times_cursor: int; + +FONT_HEIGHT :: 32; + +switch_app :: (new_app: *Widget_State) { + active_app = new_app; +} + + +main :: () { + window = create_window(window_width, window_height, "Jai Sandbox"); + Simp.set_render_target(window); + // Initialize all apps + init_menu_app(*menu_state); + init_example_widget(*example_state); + init_maze_app(*maze_state); + + text_edit: [..] u8; + held_keys: String_Builder; + + if menu_state.init then menu_state.init(*menu_state); + if example_state.init then example_state.init(*example_state); + if maze_state.init then maze_state.init(*maze_state); + + the_font := (cast(*Menu_Data) menu_state.data).font; + active_app = *menu_state; + + quit := false; + last_time := seconds_since_init(); + + sub_frames := false; + + while !quit { + // FIXME lazy FPS cap + sleep_milliseconds(10); + + Input.update_window_events(); + + for Input.get_window_resizes() { + Simp.update_window(it.window); + if it.window == window { + + window_width = it.width; + window_height = it.height; + } + } + + for Input.events_this_frame { + if it.type == { + case .QUIT; + quit = true; + + case .KEYBOARD; + if it.key_pressed == 0 continue; + + // If escape is pressed, toggle back to menu + if it.key_code == .ESCAPE { + if active_app != *menu_state { + switch_app(*menu_state); + } else { + quit = true; // Escape on menu quits + } + } + + if it.key_pressed && it.key_code == .BACKSPACE { + // @FixMe this works fine for English characters since most of that character set + // is one-byte in UTF8, but will not work correctly for many other language characters. + if text_edit.count then pop(*text_edit); + } + + case .TEXT_INPUT; + value := it.utf32; + + str := Unicode.character_utf32_to_utf8(value); + for 0..str.count-1 { + array_add(*text_edit, str[it]); + } + free(str); + } + } + + for Input.input_button_states { + if it & .DOWN { + if it_index >= 0x20 && it_index < 0x7F { + value: u8 = cast(u8) it_index; + str: string; + str.data = *value; + str.count = 1; + append(*held_keys, str); + } else { + print_to_builder(*held_keys, "% ", cast(Input.Key_Code) it_index); + } + } + } + + held_keys_text := builder_to_string(*held_keys); + defer free(held_keys_text); + + now := seconds_since_init(); + dt := cast(float)(now - last_time); + last_time = now; + + if sub_frames { + frame_times_sum -= frame_times[frame_times_cursor]; + } + frame_times_sum += dt; + frame_times[frame_times_cursor] = dt; + frame_times_cursor += 1; + + if frame_times_cursor >= FRAMES { + sub_frames = true; + frame_times_cursor = 0; + } + + fps := 0.0; + if sub_frames { + fps = FRAMES / frame_times_sum; + } else { + fps = frame_times_cursor / frame_times_sum; + } + + text_edit_text: string; + text_edit_text.data = text_edit.data; + text_edit_text.count = text_edit.count; + + // Update active app + if active_app && active_app.update { + active_app.update(active_app, dt); + } + + ui_occludes := ui_handle_input(active_app); + debug_add_value("UI occludes: %", ui_occludes); + active_app.handle_input(active_app, ui_occludes); + + // Render active app + if active_app && active_app.render { + active_app.render(active_app); + } + + mouse_x, mouse_y, _ := get_mouse_pointer_position(window, true); + + // overlay + debug_add_value("FPS: %", fps); + debug_add_value("frame_times_sum: %", frame_times_sum); + debug_add_value("frame_times_cursor: %", frame_times_cursor); + debug_add_value("Window Size: %, %", window_width, window_height); + debug_add_value("Text Input: %", text_edit_text); + debug_add_value("Held keys: %", held_keys_text); + debug_add_value("mouse_pos: %, %", mouse_x, mouse_y); + + // Set up debug overlay elements + render_debug_overlay(the_font); + + // Render global UI panels (on top of active app) + ui_render(active_app); + clear_debug_overlay(); + + finish_frame(); + } + + if menu_state.shutdown then menu_state.shutdown(*menu_state); + if example_state.shutdown then example_state.shutdown(*example_state); +} + +draw_text :: (font: *Simp.Dynamic_Font, color: Vector4, x: int, y: int, fmt: string, args: .. Any) { + assert(font != null); + builder: String_Builder; + + print_to_builder(*builder, fmt, ..args); + text := builder_to_string(*builder); + defer free(text); + + Simp.draw_text(font, x, y, text, color); +} + +finish_frame :: () { + Simp.swap_buffers(window); +} -- cgit v1.2.3-70-g09d2