#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); }