diff --git a/src/editor/level_editor.jai b/src/editor/level_editor.jai index 1b2843b..3d5a891 100644 --- a/src/editor/level_editor.jai +++ b/src/editor/level_editor.jai @@ -194,7 +194,7 @@ tick_level_editor :: () { } draw_level_editor :: () { - draw_sky(*get_level_editor_camera()); + draw_sky(*get_level_editor_camera(), *world.conf); cam := get_level_editor_camera(); mvp := create_viewproj(*cam); @@ -244,5 +244,7 @@ draw_level_editor_ui :: (theme: *GR.Overall_Theme) { if current_tab == { case .TACOMA; draw_tacoma_tab(theme, r); + case .INFO; + autoedit(r, *world.conf, theme); } } diff --git a/src/main.jai b/src/main.jai index db3bbe3..f64b1c8 100644 --- a/src/main.jai +++ b/src/main.jai @@ -1,4 +1,10 @@ -#import "Basic"()(MEMORY_DEBUGGER=true); +MEM_DEBUG :: false; + +#if MEM_DEBUG { + #import "Basic"()(MEMORY_DEBUGGER=true); +} else { + #import "Basic"; +} #import "Math"; #import "Input"; #import "Hash_Table"; @@ -129,9 +135,9 @@ frame :: () { sg_commit(); input_per_frame_event_and_flag_update(); - - - // memory_visualizer_per_frame_update(); + #if MEM_DEBUG { + memory_visualizer_per_frame_update(); + } profiler_update(); reset_temporary_storage(); diff --git a/src/ui/autoedit.jai b/src/ui/autoedit.jai new file mode 100644 index 0000000..6232e19 --- /dev/null +++ b/src/ui/autoedit.jai @@ -0,0 +1,134 @@ +#scope_file + +#import "String"; + +autoedit_scrolls : Table(u64, float); + +loc_to_key :: (line: s32) -> string { + print("Creating key: %\n", line); + return tprint("%", line); +} + +Autoedit_Conf :: struct { + Kind :: enum { + COLOR; + SLIDER; + DEFAULT; + } + + kind: Kind = .DEFAULT; + + min: string = "0"; + max: string = "100"; + step: string = "1"; +} + +note_to_autoedit_conf :: (notes: []string) -> Autoedit_Conf { + if notes.count == 0 { + return .{kind = .DEFAULT}; + } + + note := notes[0]; + note_parts := split(note,","); + + assert(note_parts.count > 0, "Note has to have a part"); + if note_parts[0] == "Slider" { + assert(note_parts.count == 4, "Slider must have min, max and step."); + return .{ + kind = .SLIDER, + min = note_parts[1], + max = note_parts[2], + step = note_parts[3] + }; + } else if note_parts[0] == "Color" { + return .{kind = .COLOR}; + } else if note_parts[0] == "Input" { + if note_parts.count == 1 { + return .{ + kind = .DEFAULT + }; + } else if note_parts.count == 3 { + return .{ + kind = .DEFAULT, + min = note_parts[1], + max = note_parts[2] + }; + } + assert(false, "Input must have either 1 or 3 parts"); + } +} + +input_code_from_type_and_notes :: (name: string, type: *Type_Info, notes: []string) -> string { + autoconf := note_to_autoedit_conf(notes); + builder : String_Builder; + print_to_builder(*builder, "GR.label(r, \"%\", *t_label_left(theme));\n", name); + print_to_builder(*builder, "r.y += r.h;\n"); + + if type == type_info(float) || type == type_info(s32) { + if autoconf.kind == .SLIDER { + print_to_builder(*builder, "GR.slider(r, *value.%, %, %, %, *theme.slider_theme);\n", name, autoconf.min, autoconf.max, autoconf.step); + } else { + print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%), *value.%, %, %, *number_theme);\n", name, name, autoconf.min, autoconf.max); + } + } else if type == type_info(Vector3) { + if autoconf.kind == .DEFAULT { + print_to_builder(*builder, "{\n"); + print_to_builder(*builder, "orig_w := r.w; orig_x := r.x; r.w = r.w / 3;\n"); + print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%.x), *value.%.x, 0, 100, *number_theme);\n", name, name); + print_to_builder(*builder, "r.x += r.w;\n"); + print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%.y), *value.%.y, 0, 100, *number_theme);\n", name, name); + print_to_builder(*builder, "r.x += r.w;\n"); + print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%.z), *value.%.z, 0, 100, *number_theme);\n", name, name); + print_to_builder(*builder, "r.w = orig_w; r.x = orig_x;\n"); + print_to_builder(*builder, "}\n"); + } else if autoconf.kind == .COLOR { + print_to_builder(*builder, "if GR.button(r, \"Edit color\", *t_button_color(theme, .{value.%.x, value.%.y, value.%.z, 1.0})) then cur_edit_color = *value.%;\n", name, name, name, name); + } + + } + print_to_builder(*builder, "r.y += r.h;\n"); + return builder_to_string(*builder); +} + +cur_edit_color : *Vector3 = null; +color_edit_already_active : bool = false; + +#scope_export +// Generates code automatically to edit a struct consisting of simple fields. +autoedit :: (rect: GR.Rect, value: *$T, theme: *GR.Overall_Theme, identifier: s32 = 0, loc := #caller_location) { + hash := GR.get_hash(loc, identifier); + scroll_val := find_or_add(*autoedit_scrolls, hash); + + number_theme : GR.Number_Input_Theme; + generate_autoedit_code :: () -> string { + builder : String_Builder; + ti := type_info(T); + #assert #run type_info(T).type == .STRUCT "Autoedit only works for structs"; + for ti.members { + print_to_builder(*builder, "%\n", input_code_from_type_and_notes(it.name, it.type, it.notes)); + } + return builder_to_string(*builder); + } + + + region, r := GR.begin_scrollable_region(rect, *theme.scrollable_region_theme); + r.y -= scroll_val.*; + r.h = ui_h(4,0); + + if !cur_edit_color { + #insert #run generate_autoedit_code(); + color_edit_already_active = false; + } else { + r.h = ui_h(50,0); + applied, drag, state := GR.color_picker(r, cur_edit_color); + + if !color_edit_already_active { + GR.set_original_and_current_color_rgb(state, cur_edit_color.*); + color_edit_already_active = true; + } + + if applied then cur_edit_color = null; + } + r.y += ui_h(8,0); + GR.end_scrollable_region(region, r.x + r.w, r.y, scroll_val); +} diff --git a/src/ui/component_themes.jai b/src/ui/component_themes.jai index eea5eeb..c74cd01 100644 --- a/src/ui/component_themes.jai +++ b/src/ui/component_themes.jai @@ -25,3 +25,9 @@ t_button_selectable :: (theme: *GR.Overall_Theme, active: bool) -> GR.Button_The return t; } + +t_button_color :: (theme: *GR.Overall_Theme, color: Vector4) -> GR.Button_Theme { + t := theme.button_theme; + t.surface_color = color; + return t; +} diff --git a/src/ui/ui.jai b/src/ui/ui.jai index 21017f8..1b14b13 100644 --- a/src/ui/ui.jai +++ b/src/ui/ui.jai @@ -2,6 +2,7 @@ GR :: #import "GetRect_LeftHanded"()(Type_Indicator = Ui_Type_Indicator); Input :: #import "Input"; #load "component_themes.jai"; +#load "autoedit.jai"; // vw is 1/100 of view width vw : float; diff --git a/src/world.jai b/src/world.jai index 749fd74..4e1e98b 100644 --- a/src/world.jai +++ b/src/world.jai @@ -1,18 +1,19 @@ World_Config :: struct { - skyBase : Vector3 = .{0.38, 0.81, 0.95}; - skyTop : Vector3 = .{0.17, 0.4, 0.95}; - sunDisk : Vector3 = .{1.0, 1.0, 1.0}; - horizonHalo : Vector3 = .{1.0, 1.0, 1.0}; - sunHalo : Vector3 = .{1.0, 1.0, 1.0}; - sunLightColor : Vector3 = .{1.0, 1.0, 1.0}; + // All of the @Notes are for the autoedit functionality. + skyBase : Vector3 = .{0.38, 0.81, 0.95}; @Color + skyTop : Vector3 = .{0.17, 0.4, 0.95}; @Color + sunDisk : Vector3 = .{1.0, 1.0, 1.0}; @Color + horizonHalo : Vector3 = .{1.0, 1.0, 1.0}; @Color + sunHalo : Vector3 = .{1.0, 1.0, 1.0}; @Color + sunLightColor : Vector3 = .{1.0, 1.0, 1.0}; @Color sunPosition : Vector3 = #run normalize(Vector3.{0.2, 0.3, 0.4}); - sunIntensity : float = 2.0; + sunIntensity : float = 2.0; @Slider,0,10,0.5 - hasClouds : s32 = 1; + hasClouds : s32 = 1; @Slider,0,1,1 - hasPlane : s32 = 0; - planeHeight : float = 0.0; - planeType : s32 = 0; + hasPlane : s32 = 0; @Slider,0,1,1 + planeHeight : float = 0.0; @Slider,-100,100,1 + planeType : s32 = 0; @Slider,0,2,1 } // Copies over all the fields of our world config into a given shader type.