From: Brendan Hansen Date: Wed, 2 Mar 2022 00:33:29 +0000 (-0600) Subject: support for scrolling regions in the UI X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=971f53da5f50e6d6e6409d316f8d65791b4f9686;p=bar-game.git support for scrolling regions in the UI --- diff --git a/run_tree/assets/shaders/font.glsl b/run_tree/assets/shaders/font.glsl index db0265d..8fdf5c9 100644 --- a/run_tree/assets/shaders/font.glsl +++ b/run_tree/assets/shaders/font.glsl @@ -14,8 +14,13 @@ layout(std140) uniform u_window_matrix_block { mat4 u_window; }; +layout(std140) uniform u_world_matrix_block { + mat4 u_world; + mat4 u_model; +}; + void main() { - gl_Position = u_window * vec4(mix(a_pos_top_left, a_pos_bottom_right, a_interp), 0, 1); + gl_Position = u_window * u_world * u_model * vec4(mix(a_pos_top_left, a_pos_bottom_right, a_interp), 0, 1); v_texture = mix(a_tex_top_left, a_tex_bottom_right, a_interp); } diff --git a/run_tree/assets/shaders/imgui.glsl b/run_tree/assets/shaders/imgui.glsl index 16b6129..26c0260 100644 --- a/run_tree/assets/shaders/imgui.glsl +++ b/run_tree/assets/shaders/imgui.glsl @@ -13,8 +13,13 @@ layout(std140) uniform u_window_matrix_block { mat4 u_window; }; +layout(std140) uniform u_world_matrix_block { + mat4 u_world; + mat4 u_model; +}; + void main() { - gl_Position = u_window * vec4(a_pos, 0, 1); + gl_Position = u_window * u_world * u_model * vec4(a_pos, 0, 1); v_tex = a_tex; v_col = a_col; } diff --git a/src/entity/editor.onyx b/src/entity/editor.onyx index 17cb769..570f4dd 100644 --- a/src/entity/editor.onyx +++ b/src/entity/editor.onyx @@ -271,6 +271,13 @@ editor_draw :: () { #local render_entity_fields :: (entity: ^Entity, x, y, w, h: f32) { assert(entity != null, "entity is null"); + if active_index >= 0 { + scrolling_region_start(.{x - sidebar_width, y, w + sidebar_width, h}); + } else { + scrolling_region_start(.{x, y, w, h}); + } + defer scrolling_region_stop(); + info := cast(^type_info.Type_Info_Struct) type_info.get_type_info(entity.schematic); if info != null { font_print(editor_big_font, x + 2, y + 24, info.name); @@ -372,7 +379,6 @@ editor_draw :: () { w := sidebar_width / 2; h := 200.0f; x := ~~ window_width - sidebar_width; - y = math.min(y, ~~ window_height - h); immediate_set_color(.{.3,.3,.3}); immediate_rectangle(x, y, w, h); diff --git a/src/gfx/font.onyx b/src/gfx/font.onyx index 094760e..35994bb 100644 --- a/src/gfx/font.onyx +++ b/src/gfx/font.onyx @@ -19,6 +19,7 @@ fonts_init :: () { font_shader = shader_make("./assets/shaders/font.glsl"); shader_use(font_shader); shader_link_window_matrix_block(font_shader); + shader_link_world_matrix_block(font_shader); glGenVertexArrays(1, ^font_vao); glBindVertexArray(font_vao); diff --git a/src/gfx/immediate.onyx b/src/gfx/immediate.onyx index 2d9d67a..487e5bd 100644 --- a/src/gfx/immediate.onyx +++ b/src/gfx/immediate.onyx @@ -10,6 +10,7 @@ immediate_init :: () { imgui_shader = shader_make(Shader_Path); shader_use(imgui_shader); shader_link_window_matrix_block(imgui_shader); + shader_link_world_matrix_block(imgui_shader); shader_set_uniform(imgui_shader, #cstr "u_texture_enabled", 0.0f); shader_set_uniform(imgui_shader, #cstr "u_texture", 0); @@ -145,6 +146,13 @@ immediate_pop_scissor :: () { } } +immediate_set_scroll :: (scroll_x, scroll_y: f32) { + offset = .{ scroll_x, scroll_y }; + update_model_matrix(offset); +} + +immediate_get_scroll :: () => offset; + Color :: struct { r, g, b : f32; a := 1.0f; @@ -180,6 +188,8 @@ Immediate_Vertex :: struct { } scissors: [..] Scissor; + offset: Vector2; + set_rendering_type :: (new_type: typeof rendering_type) { if rendering_type != new_type { immediate_flush(); diff --git a/src/gfx/ui.onyx b/src/gfx/ui.onyx index 6d74b10..b1b0f96 100644 --- a/src/gfx/ui.onyx +++ b/src/gfx/ui.onyx @@ -343,6 +343,38 @@ draw_checkbox :: (use r: Rect, value: ^bool, text: str, theme := ^default_checkb } + +scrolling_region_start :: (r: Rect, max_y_scroll := 10000.0f, site := #callsite, increment := 0) { + hash := get_site_hash(site, increment); + mx, my := mouse_get_position(); + state := map.get_ptr(^scroll_states, hash); + if state == null { + animation_states[hash] = .{}; + state = ^scroll_states[hash]; + } + + contains := Rect.contains(r, .{~~mx, ~~my}); + if contains { + scroll_delta := mouse_get_scroll_vector(); + state.xscroll -= scroll_delta.x * 20; + state.yscroll -= scroll_delta.y * 20; + + state.yscroll = math.clamp(state.yscroll, 0, max_y_scroll); + } + + immediate_flush(); + immediate_push_scissor(r.x, r.y, r.w, r.h); + immediate_set_scroll(-state.xscroll, -state.yscroll); +} + +scrolling_region_stop :: () { + immediate_flush(); + immediate_pop_scissor(); + immediate_set_scroll(0, 0); +} + + + #local { hot_item : UI_Id = 0 active_item : UI_Id = 0 @@ -423,6 +455,14 @@ draw_checkbox :: (use r: Rect, value: ^bool, text: str, theme := ^default_checkb return false; } + + Scroll_State :: struct { + xscroll: f32; + yscroll: f32; + } + + scroll_states : Map(UI_Id, Scroll_State); + get_site_hash :: macro (site: CallSite, increment := 0) -> UI_Id { hash :: package core.hash file_hash := hash.to_u32(site.file); diff --git a/src/utils/input.onyx b/src/utils/input.onyx index 2a5f217..5273c50 100644 --- a/src/utils/input.onyx +++ b/src/utils/input.onyx @@ -1,6 +1,13 @@ use package core use package glfw3 +// If you are offseting the mouse coordinate for world space +// or UI scrolling etc., set this function to be the function +// to ask for the current offset. Currently scaling the mouse +// coordinate is not supported, only linear translations. +Mouse_Offset_Function :: immediate_get_scroll + + #local { keys_this_frame : [..] u32 // Keys currently being pressed this frame keys_pulse_frame : [..] u32 // Keys pressed during this frame, only set once per keypress @@ -8,6 +15,9 @@ use package glfw3 buttons_this_frame: [8] bool // Mouse buttons being pressed this frame buttons_last_frame: [8] bool // Mouse buttons being pressed last frame + + scroll_x: f64 + scroll_y: f64 } input_update :: () { @@ -30,6 +40,8 @@ input_post_update :: () { last_mouse_x = mouse_x; last_mouse_y = mouse_y; + scroll_x = 0; + scroll_y = 0; } input_get_keys_this_frame :: () -> [] u32 { @@ -62,22 +74,43 @@ mouse_get_delta_vector :: () -> Vector2 { } mouse_get_position :: () -> (f64, f64) { - return mouse_x, mouse_y; + mx, my := mouse_x, mouse_y; + #if #defined(Mouse_Offset_Function) { + scroll := Mouse_Offset_Function(); + mx -= ~~ scroll.x; + my -= ~~ scroll.y; + } + return mx, my; } mouse_get_position_vector :: () -> Vector2 { - return .{ ~~mouse_x, ~~mouse_y }; + mx, my := mouse_x, mouse_y; + #if #defined(Mouse_Offset_Function) { + scroll := Mouse_Offset_Function(); + mx -= ~~ scroll.x; + my -= ~~ scroll.y; + } + return .{ ~~mx, ~~my }; } +mouse_get_scroll :: () -> (f64, f64) { + return scroll_x, scroll_y; +} + +mouse_get_scroll_vector :: () -> Vector2 { + return .{ ~~scroll_x, ~~scroll_y }; +} input_bind_glfw_events :: (window: GLFWwindow_p) { glfwSetKeyCallback(window, INPUT_KEY_EVENT); glfwSetMouseButtonCallback(window, INPUT_BUTTON_EVENT); + glfwSetScrollCallback(window, INPUT_SCROLL_EVENT); } #local { INPUT_BUTTON_EVENT :: "__input_button_event" INPUT_KEY_EVENT :: "__input_key_event" + INPUT_SCROLL_EVENT :: "__input_scroll_event" } #export INPUT_BUTTON_EVENT (window: GLFWwindow_p, button, action, mod: u32) { @@ -99,3 +132,8 @@ input_bind_glfw_events :: (window: GLFWwindow_p) { array.remove(^keys_this_frame, key); } } + +#export INPUT_SCROLL_EVENT (window: GLFWwindow_p, xoff, yoff: f64) { + scroll_x = xoff; + scroll_y = yoff; +}