From 2208a7200f8749ad741dfb8c74394d5cc95f6dfd Mon Sep 17 00:00:00 2001 From: Daniel Bross Date: Sat, 22 Mar 2025 17:33:10 +0100 Subject: [PATCH] DearImGui is back again --- core/string_helpers.jai | 4 ++ editor/editor_ui.jai | 63 ++++++++++++------------- imgui/imgui_sdl.jai | 31 ++++++++++++ input/sdl_input.jai | 4 ++ metaprogram.jai | 102 ++++++++++++++++++++++++++++++++++++++-- module.jai | 17 +++---- 6 files changed, 172 insertions(+), 49 deletions(-) diff --git a/core/string_helpers.jai b/core/string_helpers.jai index b2ecae7..15ace50 100644 --- a/core/string_helpers.jai +++ b/core/string_helpers.jai @@ -4,3 +4,7 @@ to_temp_c_string :: (s: string) -> *u8 { result[s.count] = 0; return result; } + +tprint_c :: (str: string, args: .. Any) -> *u8 { + return to_temp_c_string(tprint(str, ..args)); +} \ No newline at end of file diff --git a/editor/editor_ui.jai b/editor/editor_ui.jai index 098e8b0..b70b747 100644 --- a/editor/editor_ui.jai +++ b/editor/editor_ui.jai @@ -33,7 +33,8 @@ pick_scene_view_at :: (camera: Camera, coordinates: Vector2) { editor_ui :: () { // Scene picking - if !ui_mouse_over_window() { + blocking_input := ImGui.GetIO().WantCaptureMouse || ImGui.GetIO().WantCaptureKeyboard; + if !blocking_input { if key_down(.MOUSE_LEFT) { if engine.current_scene != null { coords := engine.input.normalized_viewport_mouse_position; @@ -43,7 +44,8 @@ editor_ui :: () { } { - ui_window_begin("Create", cast(s32)engine.renderer.render_target_width - 200, 5, 200, 200); + ImGui.Begin("Create", flags=ImGui.WindowFlags.NoResize); + new_entity := editor_ui_entity_creation(); if new_entity != null { set_position(*new_entity.transform, engine.editor.camera.position + engine.editor.camera.forward * 20.0); @@ -51,23 +53,30 @@ editor_ui :: () { array_add(*engine.editor.selected_entities, new_entity); } - ui_window_end(); + ImGui.End(); } - ui_window_begin("Entities", 1, 5, 200, 600); + ImGui.Begin("Entities"); if engine.current_scene != null { for engine.current_scene.entities { if it.flags & .DELETED continue; - ui_set_next_padding(20); clicked := false; selected := array_find(engine.editor.selected_entities, it); + + label : *u8; + if it.name.count == 0 { - clicked = ui_clickable_label(tprint("%", it.type), selected, it.id); + label = tprint_c("%", it.type); } else { - clicked = ui_clickable_label(it.name, selected, it.id); + label = to_temp_c_string(it.name); + //clicked = ui_clickable_label(it.name, selected, it.id); } + ImGui.PushID(tprint("%", it_index)); + clicked = ImGui.Selectable(label, selected); + ImGui.PopID(); + if clicked { if !key_pressed(.CTRL) { engine.editor.selected_entities.count = 0; @@ -80,59 +89,44 @@ editor_ui :: () { } } } - //ui_space(0, 5); } } - ui_window_end(); + ImGui.End(); - ui_window_begin("Settings", 0, cast(s32)engine.renderer.render_target_height-80, 300, 80); + ImGui.Begin("Settings"); { if engine.editor.transform_gizmo.snap_to_grid { - if ui_toolbar_button("Snap to grid enabled", .{0.0, 0.4, 0.0, 1.0}) { + if ImGui.Button("Snap to grid enabled") { engine.editor.transform_gizmo.snap_to_grid = false; } } else { - if ui_toolbar_button("Snap to grid disabled", .{0.4, 0.0, 0.0, 1.0}) { + if ImGui.Button("Snap to grid disabled") { engine.editor.transform_gizmo.snap_to_grid = true; } } if engine.editor.transform_gizmo.space == .LOCAL { - if ui_toolbar_button("LOCAL", .{0.0, 0.3, 0.0, 1.0}) { + if ImGui.Button("LOCAL") { engine.editor.transform_gizmo.space = .WORLD; } } else { - if ui_toolbar_button("WORLD", .{0.0, 0.0, 0.3, 1.0}) { + if ImGui.Button("WORLD") { engine.editor.transform_gizmo.space = .LOCAL; } } - //ui_space(15, 10) - - ui_space(20, 0); } - ui_window_end(); + ImGui.End(); // Properties { if engine.editor.selected_entities.count == 1 { - ui_window_begin("Properties", 200, 200, 400, 500); - + ImGui.Begin("Properties"); if engine.editor.selected_entities.count == 1 { entity := engine.editor.selected_entities[0]; - //updated := ui_vector_field("Position", *entity.transform.position); - //euler_rotation := quaternion_to_euler_v3(entity.transform.orientation); - //euler_rotation *= RADIANS_TO_DEGREES; - //updated |= ui_vector_field("Rotation", *euler_rotation); - //euler_rotation *= DEGREES_TO_RADIANS; - //entity.transform.orientation = euler_to_quaternion(euler_rotation); - //updated |= ui_vector_field("Scale", *entity.transform.scale); - - //if updated { - // update_matrix(*entity.transform); - //} entity_ui(entity); } - ui_window_end(); + + ImGui.End(); } } } @@ -146,6 +140,7 @@ base_editor_update :: () { } camera := *engine.editor.camera; + blocking_input := ImGui.GetIO().WantCaptureMouse || ImGui.GetIO().WantCaptureKeyboard; if engine.editor.focused_widget == null && engine.mode == .EDITING { engine.editor.should_check_entities = true; @@ -162,14 +157,14 @@ base_editor_update :: () { //coordinates := Vector2.{engine.editor.mouse_viewport_state.normalized_local_mouse_coordinates.x, 1.0 - engine.editor.mouse_viewport_state.normalized_local_mouse_coordinates.y}; ray := normalized_screen_to_ray_v2(engine.editor.camera, coordinates); - if !ui_mouse_over_window() { + if !blocking_input { if update_transform_gizmo(ray, coordinates) { engine.editor.should_check_entities = false; } } } - if !engine.editor.focused_widget { + if !blocking_input { if key_pressed(.CTRL) && key_down(.Z) { undo(); } diff --git a/imgui/imgui_sdl.jai b/imgui/imgui_sdl.jai index 160e2f0..9349f36 100644 --- a/imgui/imgui_sdl.jai +++ b/imgui/imgui_sdl.jai @@ -144,3 +144,34 @@ ImGui_ImplSdl_SetClipboardText :: (data: *void, text: *u8) #c_call { SDL_SetClipboardText(text); } +text_resize_callback :: (data: *ImGui.InputTextCallbackData) -> s32 #c_call { + push_context { + str := cast(*string)data.UserData; + result : *u8 = alloc(data.BufTextLen + 1); + memcpy(result, str.data, str.count); + result[str.count] = 0; + + if str.data != null { + free(str.data); + } + + str.count = data.BufTextLen; + str.data = result; + data.Buf = str.data; + } + return 0; +} + +imgui_input_text :: (label: string, text: *string) { + if text.data == null { + text.data = alloc(1); + memset(text.data, 0, 1); + } + changed := ImGui.InputText(to_temp_c_string(label), to_temp_c_string(text.*), cast(u64) text.count + 1, .CallbackResize, text_resize_callback, user_data=text); +} + +imgui_input_int :: (label: string, val: *int) { + new_val := cast(s32)val.*; + ImGui.InputInt(to_temp_c_string(label), *new_val); + val.* = cast(int)new_val; +} diff --git a/input/sdl_input.jai b/input/sdl_input.jai index 810da6d..9fd3872 100644 --- a/input/sdl_input.jai +++ b/input/sdl_input.jai @@ -85,6 +85,10 @@ init_sdl_input :: () { update_sdl_input :: () { event : SDL_Event; while SDL_PollEvent(*event) { + #if EDITOR { + ImGui_ImplSdl_ProcessEvent(*event); + } + if event.type == { case SDL_QUIT; { engine.input.exit = true; diff --git a/metaprogram.jai b/metaprogram.jai index 69d69ed..5c66c7d 100644 --- a/metaprogram.jai +++ b/metaprogram.jai @@ -44,6 +44,10 @@ build :: (build_release: bool, main_path: string, game_name: string, working_dir entity_serialize_proc_string: [..] string; should_serialize :: (type: *Type_Info_Struct, member: Type_Info_Struct_Member) -> bool { + if type.name == "Color" { + return true; + } + if type != null { if type.name == { case "Vector2"; { @@ -62,6 +66,7 @@ should_serialize :: (type: *Type_Info_Struct, member: Type_Info_Struct_Member) - } } case "Vector4"; #through; + case "Color"; #through; case "Quaternion"; { if member.name == { case "x"; #through; @@ -91,7 +96,7 @@ should_make_ui :: (type: *Type_Info_Struct, member: Type_Info_Struct_Member) -> if to_lower_copy(it,, allocator = temp) == "hide" return false; } - if type!= null { + if type != null { if type.name == { case "Vector2"; { if member.name == { @@ -118,6 +123,7 @@ should_make_ui :: (type: *Type_Info_Struct, member: Type_Info_Struct_Member) -> case; return false; } } + case "Color"; return true; } } @@ -190,6 +196,64 @@ generate_member_ui :: (type: *Type_Info_Struct, builder: *String_Builder, path: } } +generate_member_ui_imgui :: (type: *Type_Info_Struct, builder: *String_Builder, path: string = "") { + for type.members { + readonly := is_readonly(type, it); + if should_make_ui(type, it) && (should_serialize(type, it) || readonly) { + new_path : string; + if it.name != "entity" { + if path.count == 0 { + new_path = it.name; + } else { + new_path = tprint("%1.%2", path, it.name); + } + } + + tag : Type_Info_Tag; + if it.type.type == .VARIANT { + info_variant := cast(*Type_Info_Variant)it.type; + tag = info_variant.variant_of.type; + } else { + tag = it.type.type; + } + + if readonly { + print_to_builder(builder, "\tImGui.Text(\"%\", e.%);\n", new_path, new_path); + } else { + if tag == { + case .STRUCT; { + info_struct := cast(*Type_Info_Struct) it.type; + if info_struct.name == "Transform" { + print_to_builder(builder, TRANSFORM_UI_IMGUI); + } else if info_struct.name == "Vector3" { + print_to_builder(builder, "\tImGui.DragFloat3(tprint_c(\"%\"), *e.%.component);\n", new_path, new_path); + } else if info_struct.name == "Color" || info_struct.name == "Vector4" { + print_to_builder(builder, "\tImGui.ColorEdit4(tprint_c(\"%\"), *e.%.component);\n", new_path, new_path); + } else { + generate_member_ui_imgui(info_struct, builder, new_path); + } + } + case .BOOL; { + print_to_builder(builder, "\tImGui.Checkbox(tprint_c(\"%\"), *e.%);\n", new_path, new_path); + } + case .STRING; { + print_to_builder(builder, "\timgui_input_text(tprint(\"%\"), *e.%);\n", new_path, new_path); + //ui_textfield :: (label: string, text: *string, identifier: s64 = 0, loc := #caller_location) { + } + case .FLOAT; { + print_to_builder(builder, "\tImGui.DragFloat(tprint_c(\"%\"), *e.%);\n", new_path, new_path); + } + //case .ENUM; #through; + case .INTEGER; { + print_to_builder(builder, "\t{val := cast(int)e.%;\n", new_path); + print_to_builder(builder, "\timgui_input_int(tprint(\"%\"), *val);\n", new_path); + print_to_builder(builder, "\te.% = xx val;}\n", new_path); + } + } + } + } + } +} TRANSFORM_UI :: #string DONE updated := ui_vector_field("Position", *e.transform.position); @@ -205,6 +269,20 @@ if updated { } DONE +TRANSFORM_UI_IMGUI :: #string DONE +updated := ImGui.DragFloat3("Position", *e.transform.position.component); +euler_rotation := quaternion_to_euler_v3(e.transform.orientation); +euler_rotation *= RADIANS_TO_DEGREES; +updated |= ImGui.DragFloat3("Rotation", *euler_rotation.component); +euler_rotation *= DEGREES_TO_RADIANS; +e.transform.orientation = euler_to_quaternion(euler_rotation); +updated |= ImGui.DragFloat3("Scale", *e.transform.scale.component); + +if updated { + update_matrix(*e.transform); +} +DONE + generate_member_serialization :: (struct_type: *Type_Info_Struct, builder: *String_Builder, path: string = "") { for struct_type.members { if should_serialize(struct_type, it) { @@ -335,6 +413,20 @@ generate_ui_procedure_for_entity :: (code_struct: *Code_Struct) { array_add(*entity_serialize_proc_string, builder_to_string(*ui)); } +generate_ui_procedure_for_entity_imgui :: (code_struct: *Code_Struct) { + name := code_struct.defined_type.name; + + // Serialize + ui : String_Builder; + print_to_builder(*ui, "#if EDITOR {"); + print_to_builder(*ui, "entity_ui_proc_imgui :: (e: *%) {\n", name); + generate_member_ui_imgui(code_struct.defined_type, *ui); + print_to_builder(*ui, "}\n"); + print_to_builder(*ui, "}"); + + array_add(*entity_serialize_proc_string, builder_to_string(*ui)); +} + generate_serialize_procedure_for_entity :: (code_struct: *Code_Struct) { name := code_struct.defined_type.name; @@ -389,7 +481,7 @@ note_struct :: (code_struct: *Code_Struct) { print("Detected entity '%'.\n", name); generate_serialize_procedure_for_entity(code_struct); - generate_ui_procedure_for_entity(code_struct); + generate_ui_procedure_for_entity_imgui(code_struct); } } } @@ -484,11 +576,11 @@ generate_code :: (w: Workspace) { for entity_type_names { lower := to_lower_copy (it,, allocator=temp); - print_to_builder(*builder, "if ui_clickable_label(\"New %1\") return new_%2();", it, lower); + print_to_builder(*builder, "if ImGui.Button(\"New %1\") return new_%2();", it, lower); } for new_entity_procs { - print_to_builder(*builder, "if ui_clickable_label(\"%1\") return %1();", it); + print_to_builder(*builder, "if ImGui.Button(\"%1\") return %1();", it); } build_string := sprint(EDITOR_UI_ENTITY_CREATION, builder_to_string(*builder)); @@ -543,7 +635,7 @@ generate_code :: (w: Workspace) { builder: String_Builder; for entity_type_names { - print_to_builder(*builder, "\tcase %1; entity_ui_proc(cast(*%1)e);\n", it); + print_to_builder(*builder, "\tcase %1; entity_ui_proc_imgui(cast(*%1)e);\n", it); } build_string := sprint(ENTITY_UI, builder_to_string(*builder)); diff --git a/module.jai b/module.jai index 90bec13..10b60ec 100644 --- a/module.jai +++ b/module.jai @@ -106,12 +106,6 @@ coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_ frame_index += 1; - ImGui_ImplSdl_NewFrame((cast(*SDL_Window_Type)engine.window).sdl_window); - imgui_impldx11_new_frame(); - ImGui.NewFrame(); - - show: bool = true; - ImGui.ShowDemoWindow(*show); update_input(); @@ -131,7 +125,11 @@ coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_ update_console(); #if EDITOR { - ui_begin(); + ImGui_ImplSdl_NewFrame((cast(*SDL_Window_Type)engine.window).sdl_window); + imgui_impldx11_new_frame(); + ImGui.NewFrame(); + + //ui_begin(); } clamped_dt := min(0.4, dt); @@ -166,18 +164,17 @@ coven_run :: (game_update_proc: (float), game_editor_update_proc: (float), game_ } #if EDITOR { - ui_end(); + ImGui.Render(); } update_audio(dt); - ImGui.Render(); render(); } - imgui_impldx11_shutdown(); #if WITH_EDITOR { + imgui_impldx11_shutdown(); ImGui.DestroyContext(engine.imgui_context); }