updating graphics libraries
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 3 Mar 2022 16:52:00 +0000 (10:52 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 3 Mar 2022 16:52:00 +0000 (10:52 -0600)
src/gfx/canvas.onyx
src/gfx/font.onyx
src/gfx/immediate.onyx
src/gfx/texture.onyx
src/gfx/ui.onyx
src/utils/input.onyx

index d2f08e4a3e037b2ddfd764749cf2181503d17825..f8ffef2cd8f95c8b5d9b56479dec205e1d80f019 100644 (file)
@@ -4,21 +4,58 @@ use package opengles
 
 
 Canvas :: struct {
+    width, height: i32;
+
     framebuffer: GLint;
     depth_stencil_buffer: GLint;
     color_texture: GLint;
 }
 
-canvas_make :: () -> Canvas {
+canvas_make :: (width, height: i32) -> Canvas {
     canvas: Canvas;
+    canvas.width = width;
+    canvas.height = height;
+
+    glGenFramebuffers(1, ^canvas.framebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, canvas.framebuffer);
+
+    glGenTextures(1, ^canvas.color_texture);
+    glBindTexture(GL_TEXTURE_2D, canvas.color_texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, null);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, canvas.color_texture, 0);
+
+    glGenRenderbuffers(1, ^canvas.depth_stencil_buffer);
+    glBindRenderbuffer(GL_RENDERBUFFER, canvas.depth_stencil_buffer);
+    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
+    glBindRenderbuffer(GL_RENDERBUFFER, 0);
+    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, canvas.depth_stencil_buffer);
+
+    if glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE {
+        debug_log(.Error, "Framebuffer is not complete!");
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);  
+    return canvas;
+}
+
+canvas_free :: (use canvas: ^Canvas) {
+    glDeleteFramebuffers(1, ^canvas.framebuffer);
+    glDeleteTextures(1, ^canvas.color_texture);
+    glDeleteRenderbuffers(1, ^canvas.depth_stencil_buffer);
 }
 
 canvas_use :: (use canvas: ^Canvas) {
     if canvas == null {
         glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        update_view_matrix();
     } else {
         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+        // update_view_matrix(width, height);
     }
 }
 
+canvas_to_texture :: (canvas: ^Canvas) => Texture.{ canvas.color_texture, canvas.width, canvas.height, 3, "<canvas>" };
 
index 094760ead05dc9e891dde9cab0c0963f7d3e0e48..35994bbb11d3719cb11e7cbb7db6e1cfd404a41e 100644 (file)
@@ -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);
index 7c6b5e63860fa7c16a640b62787d85e335005fb0..8bdd5baa928c2849f6db08f3282c68bdbc9a30f0 100644 (file)
@@ -3,9 +3,6 @@ use package core
 use package opengles
 use package glfw3
 
-#local window_width  :: camera.window_width
-#local window_height :: camera.window_height
-
 immediate_init :: () {
     memory.alloc_slice(^vertex_data, Maximum_Vertex_Count);
     vertex_count = 0;
@@ -13,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);
 
@@ -131,7 +129,7 @@ immediate_push_scissor :: (x, y, w, h: f32) {
 
     scissors << .{x, y, w, h};
     glEnable(GL_SCISSOR_TEST);
-    glScissor(~~x, ~~(window_height - ~~(y + h)), ~~w, ~~h);
+    glScissor(~~x, cast(i32) camera.window_height - ~~(y + h), ~~w, ~~h);
 }
 
 immediate_pop_scissor :: () {
@@ -142,12 +140,19 @@ immediate_pop_scissor :: () {
     if scissors.count > 0 {
         glEnable(GL_SCISSOR_TEST);
         s := scissors[scissors.count - 1];
-        glScissor(~~s.x, ~~(window_height - (s.y + s.h)), ~~s.w, ~~s.h);
+        glScissor(~~s.x, cast(i32) camera.window_height - ~~(s.y + s.h), ~~s.w, ~~s.h);
     } else {
         glDisable(GL_SCISSOR_TEST);
     }
 }
 
+immediate_set_scroll :: (scroll_x, scroll_y: f32) {
+    offset = .{ scroll_x, scroll_y };
+    update_model_matrix(.{ offset.x, offset.y, 0 });
+}
+
+immediate_get_scroll :: () => offset;
+
 Color :: struct {
     r, g, b :  f32;
     a       := 1.0f;
@@ -183,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();
index 2ceb9801ff913943772242c44d77ca46ae2eb3c7..0df03b8a17d59231de75580b318d24b779dc278b 100644 (file)
@@ -46,7 +46,7 @@ texture_lookup :: #match {}
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
     glBindTexture(GL_TEXTURE_2D, 0);
 
@@ -65,3 +65,16 @@ texture_use :: (use tex: ^Texture, texture_binding := 0) {
     glActiveTexture(GL_TEXTURE0 + texture_binding);
     glBindTexture(GL_TEXTURE_2D, texture);
 }
+
+
+Texture_Wrap :: enum {
+    Clamp :: GL_CLAMP_TO_EDGE | 0;
+    Repeat :: GL_REPEAT | 0;
+    Mirrored_Repeat :: GL_MIRRORED_REPEAT | 0;
+}
+
+texture_wrap :: (use tex: ^Texture, wrap: Texture_Wrap) {
+    glBindTexture(GL_TEXTURE_2D, texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ~~ wrap);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ~~ wrap);
+}
\ No newline at end of file
index 32264afe03bd97a723fd40c393f69951ce25cba4..f0a50b0f432623e3e99b4faa1c8fbba26e66f831 100644 (file)
@@ -342,6 +342,37 @@ draw_checkbox :: (use r: Rect, value: ^bool, text: str, theme := ^default_checkb
     return result;
 }
 
+
+
+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);
+}
+
 #if !#defined(Rect) {
     Rect :: struct {
         x, y, w, h: f32;
@@ -366,9 +397,6 @@ draw_checkbox :: (use r: Rect, value: ^bool, text: str, theme := ^default_checkb
             *v = target;
             return;
         }
-
-        if *v < target do *v += diff;
-        if *v > target do *v -= diff;
     }
 }
 
@@ -453,6 +481,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);
index 77bca1921d72865a1486efea439890c3687b7988..5273c5076f7e623a58cd9363dcdab80cc29566b8 100644 (file)
@@ -1,39 +1,51 @@
 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
-    keys_last_frame  : [..] u32   // Keys being pressed in the last frame
+       keys_this_frame  : [..] u32   // Keys currently being pressed this frame
+       keys_pulse_frame : [..] u32   // Keys pressed during this frame, only set once per keypress
+       keys_last_frame  : [..] u32   // Keys being pressed in the last frame
 
-    buttons_this_frame: [8] bool  // Mouse buttons being pressed this frame
-    buttons_last_frame: [8] bool  // Mouse buttons being pressed last frame
+       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 :: () {
     glfwGetCursorPos(window, ^mouse_x, ^mouse_y);
 
-    array.clear(^keys_pulse_frame);
-    for keys_this_frame {
-        if !array.contains(keys_last_frame, it) {
-            keys_pulse_frame << it;
-        }
-    }
+       array.clear(^keys_pulse_frame);
+       for keys_this_frame {
+               if !array.contains(keys_last_frame, it) {
+                       keys_pulse_frame << it;
+               }
+       }
 }
 
 input_post_update :: () {
-    array.clear(^keys_pulse_frame);
-    array.clear(^keys_last_frame);
-    for keys_this_frame do keys_last_frame << it;
+       array.clear(^keys_pulse_frame);
+       array.clear(^keys_last_frame);
+       for keys_this_frame do keys_last_frame << it;
 
-    for 8 do buttons_last_frame[it] = buttons_this_frame[it];
+       for 8 do buttons_last_frame[it] = buttons_this_frame[it];
 
-    last_mouse_x = mouse_x;
-    last_mouse_y = mouse_y;
+       last_mouse_x = mouse_x;
+       last_mouse_y = mouse_y;
+       scroll_x = 0;
+       scroll_y = 0;
 }
 
 input_get_keys_this_frame :: () -> [] u32 {
-    return keys_pulse_frame;
+       return keys_pulse_frame;
 }
 
 is_key_down      :: (key) => array.contains(keys_this_frame, key);
@@ -45,57 +57,83 @@ is_button_just_down :: (button) => buttons_this_frame[button] && !buttons_last_f
 is_button_just_up   :: (button) => !buttons_this_frame[button] && buttons_last_frame[button];
 
 #local {
-    last_mouse_x: f64;
-    last_mouse_y: f64;
+       last_mouse_x: f64;
+       last_mouse_y: f64;
 
-    mouse_x: f64;
-    mouse_y: f64;
+       mouse_x: f64;
+       mouse_y: f64;
 }
 
 mouse_get_delta :: () -> (f64, f64) {
-    return mouse_x - last_mouse_x, mouse_y - last_mouse_y;
+       return mouse_x - last_mouse_x, mouse_y - last_mouse_y;
 }
 
 mouse_get_delta_vector :: () -> Vector2 {
-    dmx, dmy := mouse_get_delta();
-    return .{ ~~dmx, ~~dmy };
+       dmx, dmy := mouse_get_delta();
+       return .{ ~~dmx, ~~dmy };
 }
 
 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);
+       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_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) {
-    if action == GLFW_PRESS {
-        buttons_this_frame[button] = true;
-    }
+       if action == GLFW_PRESS {
+               buttons_this_frame[button] = true;
+       }
 
-    if action == GLFW_RELEASE {
-        buttons_this_frame[button] = false;
-    }
+       if action == GLFW_RELEASE {
+               buttons_this_frame[button] = false;
+       }
 }
 
 #export INPUT_KEY_EVENT (window: GLFWwindow_p, key, scancode, action, mod: u32) {
-    if action == GLFW_PRESS {
-        keys_this_frame << key;
-    }
+       if action == GLFW_PRESS {
+               keys_this_frame << key;
+       }
+
+       if action == GLFW_RELEASE {
+               array.remove(^keys_this_frame, key);
+       }
+}
 
-    if action == GLFW_RELEASE {
-        array.remove(^keys_this_frame, key);
-    }
+#export INPUT_SCROLL_EVENT (window: GLFWwindow_p, xoff, yoff: f64) {
+       scroll_x = xoff;
+       scroll_y = yoff;
 }