From 0ea1ceb12061e7a34f1981b0b05ef849ba675291 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sat, 5 Mar 2022 16:00:33 -0600 Subject: [PATCH] code clean and color picker --- run_tree/scenes/level1.scene | 4 +- src/entity/components/background.onyx | 6 +- src/entity/editor.onyx | 88 ++++++++++++++++++++++----- src/entity/items.onyx | 2 +- src/entity/scene.onyx | 2 + src/gfx/ui.onyx | 85 +++++++++++++++++++++++++- src/main.onyx | 1 + src/sfx/audio_manager.onyx | 2 +- src/utils/colors.onyx | 50 +++++++++++++++ 9 files changed, 219 insertions(+), 21 deletions(-) create mode 100644 src/utils/colors.onyx diff --git a/run_tree/scenes/level1.scene b/run_tree/scenes/level1.scene index c2d9a19..d7050a5 100644 --- a/run_tree/scenes/level1.scene +++ b/run_tree/scenes/level1.scene @@ -498,7 +498,7 @@ max_timeout = 2.0000 [Player] id = 152 flags = 2 -pos.x = 276.7525 +pos.x = 277.7525 pos.y = 229.4651 size.x = 16.0000 size.y = 32.0000 @@ -515,7 +515,7 @@ velocity.y = 0.0000 :PlayerComponent holding = 155 :RenderComponent -layer = 0 +layer = 10 color.r = 1.0000 color.g = 0.0000 color.b = 1.0000 diff --git a/src/entity/components/background.onyx b/src/entity/components/background.onyx index 9473564..2336e17 100644 --- a/src/entity/components/background.onyx +++ b/src/entity/components/background.onyx @@ -18,6 +18,8 @@ BackgroundComponent :: struct { texture_wrap(^background_texture, .Repeat); r := entity->get_rect(); - immediate_subimage(^background_texture, r.x, r.y, r.w, r.h, 0, 0, r.w, r.h); + tw := math.ceil(r.w / ~~background_texture.width) * ~~background_texture.width; + th := math.ceil(r.h / ~~background_texture.height) * ~~background_texture.height; + immediate_subimage(^background_texture, r.x, r.y, tw, th, 0, 0, tw, th); } -} \ No newline at end of file +} diff --git a/src/entity/editor.onyx b/src/entity/editor.onyx index e6c26d2..e8e49b4 100644 --- a/src/entity/editor.onyx +++ b/src/entity/editor.onyx @@ -14,7 +14,7 @@ use package glfw3 Editor_Range :: struct {min, max: f32;} Editor_Disabled :: struct {} Editor_Hidden :: struct {} -Editor_Custom_Field :: struct { func: () -> void; } +Editor_Custom_Field :: struct { func: (v: any, x: f32, y: f32, w: f32, h: f32, field_name: str) -> void; } editor_init :: () { editor_font = font_lookup(.{"./assets/fonts/calibri.ttf", 18}); @@ -22,9 +22,9 @@ editor_init :: () { selected_entity_id = Entity_Nothing; array.ensure_capacity(^save_path, 512); - save_path.count = 512; - s := conv.format(save_path, "./scenes/level1.scene"); - save_path.count = s.count; + conv.format(^save_path, "./scenes/level1.scene"); + + custom_editors[Color] = render_color_picker; } editor_shown :: () => editor_openness != 0.0f || editor_target_openness != 0.0f; @@ -231,6 +231,22 @@ editor_draw :: () { if draw_button(.{ x + w / 2, y + 40, w / 2, 40 }, "Load") { scene->load_from_file(save_path); } + + @Cleanup // This is rather expensive to do every frame, I think? + dir, success := os.dir_open("./scenes"); + entry: os.DirectoryEntry; + y += 80; + while os.dir_read(dir, ^entry) { + if string.ends_with(entry->name(), ".scene") { + if draw_button(.{ x, y, w, 40 }, entry->name(), increment=entry.identifier) { + buf: [1024] u8; + path := conv.format(buf, "./scenes/{}", entry->name()); + scene->load_from_file(path); + } + y += 40; + } + } + os.dir_close(dir); } case .Create { @@ -250,11 +266,19 @@ editor_draw :: () { } #local render_create_sidebar :: (x, y, w, h: f32) { + #persist search_value: [..] u8; + draw_textbox(.{x, y, w, 40}, ^search_value, placeholder="Search..."); + h -= 40; + y += 40; + i := 0; for^ scene.schematics.entries { defer i += 1; name := it.key; + if search_value.count != 0 { + if !string.contains(name, search_value) do continue; + } y += 40.0f; theme := Button_Theme.{active = active_index == i}; @@ -266,7 +290,7 @@ editor_draw :: () { #local render_entity_list :: (x, y, w, h: f32) { #persist search_value: [..] u8; - draw_textbox(.{x, y, w, 40}, ^search_value); + draw_textbox(.{x, y, w, 40}, ^search_value, placeholder="Search..."); h -= 40; y += 40; @@ -360,11 +384,28 @@ editor_draw :: () { } } + member_info := type_info.get_type_info(it.type); + if active_index + 1 == i { immediate_set_color(.{.4,.4,.2}); immediate_rectangle(x, y + 2, w, Field_Height + 2); - render_field_editor(member_any, y, it.name); + w := sidebar_width / 2; + h := 200.0f; + x := ~~ window_width - sidebar_width; + render := render_field_editor; + + if custom_editors[it.type] != null_proc { + render = custom_editors[it.type]; + } + + for it.tags { + if it.type == Editor_Custom_Field { + render = (cast(^Editor_Custom_Field) it.data).func; + } + } + + render(member_any, x, y, w, h, it.name); } elseif i % 2 == 0 { immediate_set_color(.{.3,.3,.3}); @@ -380,7 +421,7 @@ editor_draw :: () { Color.{0.4, 0.4, 0.2} ]; - if type_info.get_type_info(it.type).kind == .Struct { + if member_info.kind == .Struct { new_y, new_i := render_struct_fields(member_any, i, x + Field_Height, y, w - Field_Height, h, depth + 1); immediate_set_color(depth_colors[depth % 4]); immediate_rectangle(x, y + Field_Height + 4, Field_Height / 2, new_y - y); @@ -399,15 +440,10 @@ editor_draw :: () { #local prepare_field_editor :: (v: any) { array.ensure_capacity(^field_buffer, 256); - field_buffer.count = 256; - s := conv.format_va(field_buffer, "{\"d}", .[v]); - field_buffer.count = s.count; + conv.format_va(^field_buffer, "{\"d}", .[v]); } -#local render_field_editor :: (v: any, y: f32, field_name: str) { - w := sidebar_width / 2; - h := 200.0f; - x := ~~ window_width - sidebar_width; +#local render_field_editor :: (v: any, x, y, w, h: f32, field_name: str) { immediate_set_color(.{.3,.3,.3}); immediate_rectangle(x, y, w, h); @@ -459,6 +495,28 @@ editor_draw :: () { } } +#local render_color_picker :: (v: any, x, y, w, h: f32, field_name: str) { + color := cast(^Color) v.data; + + immediate_set_color(.{.3, .3, .3}); + immediate_rectangle(x, y, w, h); + + draw_slider(.{x, y+0, w, 40}, ^color.r, 0, 1); + draw_slider(.{x, y+40, w, 40}, ^color.g, 0, 1); + draw_slider(.{x, y+80, w, 40}, ^color.b, 0, 1); + + buf: [64] u8; + msg := conv.format(buf, "Red: {}", color.r); + font_draw_centered(editor_font, x, y+24, w, msg); + msg = conv.format(buf, "Green: {}", color.g); + font_draw_centered(editor_font, x, y+64, w, msg); + msg = conv.format(buf, "Blue: {}", color.b); + font_draw_centered(editor_font, x, y+104, w, msg); + + immediate_set_color(*color); + immediate_rectangle(x, y+120, w, h - 120); +} + #local { background_color :: Color.{0.15, 0.15, 0.15, 1}; @@ -493,4 +551,6 @@ editor_draw :: () { editor_grid_size := 16.0f; @TODO // This should be configurable save_path: [..] u8; + + custom_editors : Map(type_expr, (any, f32, f32, f32, f32, str) -> void); } diff --git a/src/entity/items.onyx b/src/entity/items.onyx index dfa5d99..d75fa46 100644 --- a/src/entity/items.onyx +++ b/src/entity/items.onyx @@ -122,7 +122,7 @@ ItemComponent :: struct { #local { - render_item_picker :: () { + render_item_picker :: (v: any, x, y, w, h: f32, field_name: str) { } } \ No newline at end of file diff --git a/src/entity/scene.onyx b/src/entity/scene.onyx index 7ee3beb..a0a8414 100644 --- a/src/entity/scene.onyx +++ b/src/entity/scene.onyx @@ -283,6 +283,8 @@ scene_modify_component :: macro (this: ^Scene, entity: ^Entity, $component_type: // This 'modify_component' function is more often used by the programmer, so initializing // the component here before returning is a good idea. __initialize(comp); + } else { + comp = ~~ entity->get(component_type); } #insert init_block; diff --git a/src/gfx/ui.onyx b/src/gfx/ui.onyx index a58f30b..8765ac4 100644 --- a/src/gfx/ui.onyx +++ b/src/gfx/ui.onyx @@ -26,7 +26,10 @@ ui_end_frame :: () { if active_countdown > 0 { active_countdown -= 1; - if active_countdown == 0 do set_active_item(0); + if active_countdown == 0 { + set_active_item(0); + input_release_keys(); + } } } @@ -105,6 +108,86 @@ draw_button :: (use r: Rect, text: str, theme := ^default_button_theme, site := } +// +// Sliders +// +Slider_Theme :: struct { + use text_theme := Text_Theme.{}; + use animation_theme := Animation_Theme.{}; + + box_color := Color.{ 0.1, 0.1, 0.1 }; + box_border_color := Color.{ 0.2, 0.2, 0.2 }; + box_border_width := 4.0f; @InPixels + + bar_color := Color.{ 0.4, 0.4, 0.4 }; + bar_hover_color := Color.{ 0, 0, 1 }; + bar_hover_negative_color := Color.{ 1, 0, 0 }; // The color when value is less than 0 +} + +#local default_slider_theme := Slider_Theme.{}; + +draw_slider :: (use r: Rect, value: ^$T, min_value: T, max_value: T, theme := ^default_slider_theme, site := #callsite, increment := 0) -> bool { + result := false; + + hash := get_site_hash(site, increment); + state := get_animation(hash); + mx, my := mouse_get_position(); + + if is_hot_item(hash) { + if is_button_down(GLFW_MOUSE_BUTTON_LEFT) { + set_active_item(hash); + result = true; + + // Animate this? + sx := ~~mx - x; + + if T == i32 || T == i64 || T == u32 || T == u64 { + step_width := w / ~~math.abs(max_value - min_value); + percent := (sx + step_width / 2) / w; + *value = math.lerp(percent, min_value, max_value); + *value = math.clamp(*value, min_value, max_value); + + } else { + percent := sx / w; + *value = math.lerp(percent, min_value, max_value); + *value = math.clamp(*value, min_value, max_value); + } + } else { + set_active_item(0); + } + } + + if Rect.contains(r, .{ ~~mx, ~~my }) { + set_hot_item(hash); + } + + if is_hot_item(hash) { + move_towards(^state.hover_time, 1.0f, theme.hover_speed); + } else { + move_towards(^state.hover_time, 0.0f, theme.hover_speed); + } + + box_border_width := theme.box_border_width; + + bar_color := theme.bar_color; + if *value < 0 do bar_color = color_lerp(state.hover_time, bar_color, theme.bar_hover_negative_color); + else do bar_color = color_lerp(state.hover_time, bar_color, theme.bar_hover_color); + + immediate_set_color(theme.box_border_color); + immediate_rectangle(x, y, w, h); + + immediate_set_color(theme.box_border_color); + immediate_rectangle(x + box_border_width, y + box_border_width, w - box_border_width * 2, h - box_border_width * 2); + + box_width := cast(f32) (*value - min_value) / ~~(max_value - min_value); + box_width *= w - box_border_width * 2; + box_width = math.clamp(box_width, 0, w - box_border_width * 2); + immediate_set_color(bar_color); + immediate_rectangle(x + box_border_width, y + box_border_width, box_width, h - box_border_width * 2); + + return result; +} + // // Textbox // diff --git a/src/main.onyx b/src/main.onyx index 882d3a2..6dcc89f 100644 --- a/src/main.onyx +++ b/src/main.onyx @@ -155,4 +155,5 @@ main :: (args) => { init(); run(); + deinit(); } diff --git a/src/sfx/audio_manager.onyx b/src/sfx/audio_manager.onyx index 7a57bfb..7e7bdd0 100644 --- a/src/sfx/audio_manager.onyx +++ b/src/sfx/audio_manager.onyx @@ -96,4 +96,4 @@ Audio_Manager :: struct { loaded_sounds: Map(str, Sound); playing_sounds: [..] u32; // List of sources -} \ No newline at end of file +} diff --git a/src/utils/colors.onyx b/src/utils/colors.onyx new file mode 100644 index 0000000..886387d --- /dev/null +++ b/src/utils/colors.onyx @@ -0,0 +1,50 @@ + +use package core + +color_to_hsl :: (c: Color) -> (h: f32, s: f32, l: f32) { + r := c.r / 255; + g := c.g / 255; + b := c.b / 255; + cmax := math.max(math.max(r, g), b); + cmin := math.min(math.min(r, g), b); + delta := cmax - cmin; + + h := 0.0f; + if cmax == r { + m := (g - b) / delta; + while m >= 6 do m -= 6; + while m < 0 do m += 6; + h = 60 * m; + } + if cmax == g do h = 60 * (b - r) / delta + 2; + if cmax == b do h = 60 * (r - g) / delta + 4; + + l := (cmax + cmin) / 2; + s := delta / (1 - math.abs(2 * l - 1)); + + return h, s, l; +} + +hsl_to_color :: (h, s, l: f32) -> Color { + c := (1 - math.abs(2 * l - 1)) * s; + + h_term := h / 60; + while h_term < 0 do h_term += 2; + while h_term >= 0 do h_term -= 2; + + x := c * (1 - math.abs(h_term - 1)); + m := l - c / 2; + + r, g, b: f32; + if 0 <= h && h < 60 { r = c; g = x; b = 0; } + if 60 <= h && h < 120 { r = x; g = c; b = 0; } + if 120 <= h && h < 180 { r = 0; g = c; b = x; } + if 180 <= h && h < 240 { r = 0; g = x; b = c; } + if 240 <= h && h < 300 { r = x; g = 0; b = c; } + if 300 <= h && h < 360 { r = c; g = 0; b = x; } + + r = (r + m) * 255; + g = (g + m) * 255; + b = (b + m) * 255; + return .{ r, g, b, 1 }; +} \ No newline at end of file -- 2.25.1