added basic camera controls
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 30 Sep 2020 03:20:07 +0000 (22:20 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 30 Sep 2020 03:20:07 +0000 (22:20 -0500)
js/environment.js
src/events.onyx
src/gfx/atlas.onyx
src/gfx/quad_renderer.onyx
src/input.onyx
src/main.onyx
src/quad_tree.onyx
src/shaders/quad.vert
tags

index 17d8e53c2998c4a962043ca8aab69719ab836620..b004561d6fdd90b2ffbf119f85276cd181c4f12d 100644 (file)
@@ -79,6 +79,10 @@ return {
                 push_event_to_buffer(esp, event_size, 0x03, [ ev.clientX, ev.clientY, -1 ]);
             });
 
+            document.addEventListener("wheel", (ev) => {
+                push_event_to_buffer(esp, event_size, 0x07, [ ev.clientX, ev.clientY, ev.deltaY >= 0 ? 0x04 : 0x03 ]);
+            });
+
             window.addEventListener("resize", (ev) => {
                 push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]);
             });
index 80cb2cb2b3f6ce8877a68673b126a6a2b0e7867d..f87c4d8f24735ec3d97f68e8c056496ac9b0e168 100644 (file)
@@ -6,16 +6,17 @@ use package core { print }
 
 // NOTE: These need to match exactly what is in the corresponding javascript
 DomEventKind :: enum {
-    None      :: 0x00;
+    None       :: 0x00;
 
-    MouseDown :: 0x01;
-    MouseUp   :: 0x02;
-    MouseMove :: 0x03;
+    MouseDown  :: 0x01;
+    MouseUp    :: 0x02;
+    MouseMove  :: 0x03;
+    MouseWheel :: 0x07;
 
-    KeyDown   :: 0x04;
-    KeyUp     :: 0x05;
+    KeyDown    :: 0x04;
+    KeyUp      :: 0x05;
 
-    Resize    :: 0x06;
+    Resize     :: 0x06;
 }
 
 DomEvent :: struct {
index 54f230b1da7555d9adf222a3d7e1f11b4e8824a7..ae92c1cdb00240ce2308d5048cdd8dd11eec5e88 100644 (file)
@@ -10,10 +10,10 @@ Atlas :: struct {
 }
 
 AtlasSprite :: struct {
-    x : i32 = 0;
-    y : i32 = 0;
-    w : i32 = 0;
-    h : i32 = 0;
+    x : f32 = 0.0f;
+    y : f32 = 0.0f;
+    w : f32 = 0.0f;
+    h : f32 = 0.0f;
 }
 
 atlas_create :: proc (tex: ^Texture) -> Atlas {
@@ -28,10 +28,19 @@ atlas_map :: proc (use atlas: ^Atlas, id: i32, sprite: AtlasSprite) {
     i32map_put(^map, id, sprite);
 }
 
+atlas_lookup :: proc (use atlas: ^Atlas, id: i32) -> AtlasSprite {
+    sprite := i32map_get(^map, id, AtlasSprite.{});
+    sprite.x /= ~~texture.width;
+    sprite.y /= ~~texture.width;
+    sprite.w /= ~~texture.width;
+    sprite.h /= ~~texture.width;
+    return sprite;
+}
+
 atlas_apply_to_quad :: proc (use atlas: ^Atlas, id: i32, quad: ^Quad) {
     sprite := i32map_get(^map, id, AtlasSprite.{});
-    quad.tex_size.x = cast(f32) sprite.w / ~~texture.width;
-    quad.tex_size.y = cast(f32) sprite.h / ~~texture.height;
-    quad.tex_pos.x = cast(f32) sprite.x / ~~texture.width;
-    quad.tex_pos.y = cast(f32) sprite.y / ~~texture.height;
+    quad.tex_size.x = sprite.w / ~~texture.width;
+    quad.tex_size.y = sprite.h / ~~texture.height;
+    quad.tex_pos.x = sprite.x / ~~texture.width;
+    quad.tex_pos.y = sprite.y / ~~texture.height;
 }
index eb8a7b1dae742c1ab5091d155a378dc74cd868d0..993d1917e63fa99d6b0d3bed6eff9b037d55a55d 100644 (file)
@@ -4,7 +4,7 @@ use package core
 use package gl as gl
 use package gl_utils as gl_utils
 use package vecmath
-use package main { window_width, window_height }
+use package main { half_window_width, half_window_height }
 
 #private_file
 quad_program : gl.GLProgram = -1;
@@ -17,7 +17,8 @@ QuadRenderer :: struct {
     indexBuffer  : gl.GLBuffer;
     quadBuffer   : gl.GLBuffer;
 
-    u_proj_loc : gl.GLUniformLocation;
+    u_proj_loc  : gl.GLUniformLocation;
+    u_world_loc : gl.GLUniformLocation;
 
     is_data_dirty : bool = false;
 }
@@ -109,6 +110,9 @@ quad_renderer_init :: proc (use qr: ^QuadRenderer, initial_quads := 10) {
 
     u_proj_loc = gl.getUniformLocation(quad_program, "u_proj");
     quad_renderer_update_view(qr);
+
+    u_world_loc = gl.getUniformLocation(quad_program, "u_world");
+    quad_renderer_update_world(qr);
 }
 
 quad_renderer_draw :: proc (use qr: ^QuadRenderer, count := -1) {
@@ -127,10 +131,10 @@ quad_renderer_update_view :: proc (use qr: ^QuadRenderer) {
 
     // Orthographic projection matrix shamelessly stolen from:
     //     https://en.wikipedia.org/wiki/Orthographic_projection
-    r :: cast(f32) window_width;
-    l :: 0.0f;
-    t :: 0.0f;
-    b :: cast(f32) window_height;
+    r :: cast(f32) half_window_width;
+    l :: -cast(f32) half_window_width;
+    t :: -cast(f32) half_window_height;
+    b :: cast(f32) half_window_height;
 
     proj_mat[0 * 4 + 0] = 2.0f / (r - l);
     proj_mat[0 * 4 + 3] = -(r + l) / (r - l);
@@ -144,6 +148,22 @@ quad_renderer_update_view :: proc (use qr: ^QuadRenderer) {
     gl.uniformMatrix4(u_proj_loc, true, proj_mat);
 }
 
+quad_renderer_update_world :: proc (use qr: ^QuadRenderer,
+        scale_x := 1.0f, scale_y := 1.0f, trans_x := 0.0f, trans_y := 0.0f) {
+    world_mat : [4 * 4] gl.GLfloat;
+    for ^it: world_mat do *it = 0.0f;
+
+    world_mat[0 * 4 + 0] = scale_x;
+    world_mat[1 * 4 + 1] = scale_y;
+    world_mat[2 * 4 + 2] = 0.0f;
+    world_mat[3 * 4 + 3] = 1.0f;
+
+    world_mat[3 * 4 + 0] = trans_x * scale_x;
+    world_mat[3 * 4 + 1] = trans_y * scale_y;
+
+    gl.uniformMatrix4(u_world_loc, false, world_mat);
+}
+
 quad_update_at_index :: proc (use qr: ^QuadRenderer, idx: i32, quad: Quad) {
     quad_data[idx] = quad;
     is_data_dirty = true;
index 4096d1dd5f6dae5b4cb30b385db53760eb634ba5..35e72af1457457552ddb1f2919402161de248ce0 100644 (file)
@@ -2,6 +2,7 @@ package input
 
 use package event as event
 use package core { print }
+use package main { half_window_width, half_window_height }
 
 #private_file KEY_COUNT :: 256
 #private_file BUTTON_COUNT :: 3
@@ -21,11 +22,14 @@ InputState :: struct {
     keys_just_down : [KEY_COUNT] bool;
 
     mouse : struct {
-        x : u32;
-        y : u32;
+        x : i32;
+        y : i32;
 
         buttons_down      : [BUTTON_COUNT] bool;
         buttons_just_down : [BUTTON_COUNT] bool;
+
+        wheel_ups   : u8;
+        wheel_downs : u8;
     };
 }
 
@@ -37,38 +41,53 @@ init :: proc (use state: ^InputState) {
 
     mouse.x = 0;
     mouse.y = 0;
+
+    mouse.wheel_ups   = ~~0;
+    mouse.wheel_downs = ~~0;
 }
 
 process_event :: proc (use state: ^InputState, ev: ^event.Event) {
+    use event.DomEventKind;
+
     switch ev.kind {
-        case event.DomEventKind.KeyDown {
+        case KeyDown {
             keys_just_down[ev.keyboard.keycode] = !keys_down[ev.keyboard.keycode];
             keys_down[ev.keyboard.keycode] = true;
         }
 
-        case event.DomEventKind.KeyUp {
+        case KeyUp {
             keys_down[ev.keyboard.keycode] = false;
             keys_just_down[ev.keyboard.keycode] = false;
         }
 
-        case event.DomEventKind.MouseDown {
-            mouse.x = ev.mouse.pos_x;
-            mouse.y = ev.mouse.pos_y;
+        case MouseDown {
+            mouse.x = ev.mouse.pos_x - half_window_width;
+            mouse.y = ev.mouse.pos_y - half_window_height;
 
             mouse.buttons_just_down[cast(u32) ev.mouse.button] = !mouse.buttons_down[cast(u32) ev.mouse.button];
             mouse.buttons_down[cast(u32) ev.mouse.button] = true;
         }
 
-        case event.DomEventKind.MouseUp {
-            mouse.x = ev.mouse.pos_x;
-            mouse.y = ev.mouse.pos_y;
+        case MouseUp {
+            mouse.x = ev.mouse.pos_x - half_window_width;
+            mouse.y = ev.mouse.pos_y - half_window_height;
             mouse.buttons_down[cast(u32) ev.mouse.button] = false;
             mouse.buttons_just_down[cast(u32) ev.mouse.button] = false;
         }
 
-        case event.DomEventKind.MouseMove {
-            mouse.x = ev.mouse.pos_x;
-            mouse.y = ev.mouse.pos_y;
+        case MouseMove {
+            mouse.x = ev.mouse.pos_x - half_window_width;
+            mouse.y = ev.mouse.pos_y - half_window_height;
+        }
+
+        case MouseWheel {
+            // @TEST: These may be backwards
+            is_up := ev.mouse.button == event.MouseButton.WheelUp;
+
+            // @FIXME: This could overflow... if there were 256+ wheel up/down events
+            // in one frame. Still something that should be considered.
+            if is_up do mouse.wheel_ups   += ~~1;
+            else     do mouse.wheel_downs += ~~1;
         }
     }
 }
@@ -78,6 +97,9 @@ preupdate :: proc (use state: ^InputState) ---
 postupdate :: proc (use state: ^InputState) {
     for ^key: keys_just_down             do *key = false;
     for ^button: mouse.buttons_just_down do *button = false;
+
+    if mouse.wheel_ups > ~~0   do mouse.wheel_ups -= ~~1;
+    if mouse.wheel_downs > ~~0 do mouse.wheel_downs -= ~~1;
 }
 
 
index 110a4ba58052c66bf17125cecb6e8b448d5d8f1e..036b66d391319c02268c5d7d6d58cfddef1f631b 100644 (file)
@@ -34,6 +34,10 @@ RenderContext :: struct {
     curr_quad_idx: i32 = 0;
     max_quad_idx:  i32 = 0;
 
+    scale : f32 = 1.0f;
+    trans_x : f32 = 0.0f;
+    trans_y : f32 = 0.0f;
+
     color: Color4f32 = Color4f32.{ 1.0f, 1.0f, 1.0f, 1.0f };
 }
 
@@ -87,11 +91,10 @@ draw_quad :: proc (use rc: ^RenderContext, quad: ^Quad) {
 }
 
 render_context_flush :: proc (use rc: ^RenderContext) {
+    quad_renderer_update_world(quad_renderer, scale, scale, trans_x, trans_y);
     quad_rebuffer_data(quad_renderer);
     quad_renderer_draw(quad_renderer, curr_quad_idx);
 
-    // for i: 0 .. curr_quad_idx do quad_update_at_index(quad_renderer, i, Quad.{});
-
     curr_quad_idx = 0;
 }
 
@@ -100,6 +103,8 @@ render_context_flush :: proc (use rc: ^RenderContext) {
 // @Cleanup
 window_width  := 0
 window_height := 0
+half_window_width  := 0
+half_window_height := 0
 
 renderer      : RenderContext
 input_state   : input.InputState
@@ -112,17 +117,20 @@ poll_events :: proc () {
 
     ev : event.Event;
     while event.poll(^ev) do switch ev.kind {
-        case KeyDown, KeyUp, MouseDown, MouseUp, MouseMove do input.process_event(^input_state, ^ev);
-
         case Resize {
             window_width  = ev.resize.width;
             window_height = ev.resize.height;
 
+            half_window_width = window_width / 2;
+            half_window_height = window_height / 2;
+
             gl.canvasSize(window_width, window_height);
             gl.viewport(0, 0, window_width, window_height);
 
             quad_renderer_update_view(renderer.quad_renderer);
         }
+
+        case #default do input.process_event(^input_state, ^ev);
     }
 }
 
@@ -136,22 +144,29 @@ update :: proc () {
 
     if input.key_just_down(^input_state, Key.Space) do simulating = !simulating;
 
+    if input.key_down(^input_state, Key.ArrowUp)    do renderer.trans_y += 10.0f;
+    if input.key_down(^input_state, Key.ArrowDown)  do renderer.trans_y -= 10.0f;
+    if input.key_down(^input_state, Key.ArrowLeft)  do renderer.trans_x += 10.0f;
+    if input.key_down(^input_state, Key.ArrowRight) do renderer.trans_x -= 10.0f;
+
+    if input_state.mouse.wheel_ups > ~~0   do renderer.scale *= 1.125f;
+    if input_state.mouse.wheel_downs > ~~0 do renderer.scale /= 1.125f;
+
     if simulating {
         quad_scratch : ScratchState;
         quad_alloc : Allocator;
         scratch_state_init(^quad_scratch, ~~quad_scratch_buffer, 512 * 1024);
         scratch_alloc_init(^quad_alloc, ^quad_scratch);
 
-        quadtree_init(^dude_tree, AABB.{ 0.0f, 0.0f, ~~window_width, ~~window_height });
+        quadtree_init(^dude_tree, AABB.{ ~~-half_window_width, ~~-half_window_height, ~~window_width, ~~window_height });
         for ^d: dudes do quadtree_insert(^dude_tree, d, quad_alloc);
 
         for ^d: dudes do dude_update(d, ^dude_tree);
         for ^d: dudes {
-            if !d.can_move_x do d.vel.x = -d.vel.x;
-            if !d.can_move_y do d.vel.y = -d.vel.y;
+            if d.can_move_x do d.pos.x += d.vel.x;
+            if d.can_move_y do d.pos.y += d.vel.y;
 
-            d.pos.x += d.vel.x;
-            d.pos.y += d.vel.y;
+            if !d.can_move_x && !d.can_move_y do d.couldnt_move_count += ~~1;
         }
     }
 }
@@ -162,27 +177,27 @@ draw :: proc () {
 
     texture_use(^textures.tilemap);
 
-    draw_quad_tree(^dude_tree);
-
-    draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 10f, 10f);
+    // draw_quad_tree(^dude_tree);
 
+    dude_sprite := atlas_lookup(^atlas, 0);
     for ^d: dudes {
         aabb := dude_get_aabb(d);
-        draw_rect(^renderer, aabb.x, aabb.y, aabb.w, aabb.h);
+        renderer.color = d.color;
+        draw_textured_rect(^renderer, aabb.x, aabb.y, aabb.w, aabb.h,
+                                      dude_sprite.x, dude_sprite.y,
+                                      dude_sprite.w, dude_sprite.h);
     }
 
+    renderer.color = Color4f32.{ 1.0f, 1.0f, 1.0f, 1.0f };
+    draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 10f, 10f);
     render_context_flush(^renderer);
 }
 
-draw_quad_tree :: proc (qt: ^QuadTree($T), level := 0, corner := 0) {
+draw_quad_tree :: proc (qt: ^QuadTree($T)) {
     col := cast(f32) (0.0f + ~~ qt.points_count * 0.25f);
     if col > 1.0f do col = 1.0f;
 
-    color := Color4f32.{ 0.0f, 0.0f, 0.0f, 1.0f };
-
-    if corner == 1 do color.r = col;
-    if corner == 2 do color.g = col;
-    if corner == 3 do color.b = col;
+    color := Color4f32.{ col, col, col, 1.0f };
 
     quad := Quad.{
         pos  = V2f.{ qt.region.x, qt.region.y },
@@ -194,10 +209,10 @@ draw_quad_tree :: proc (qt: ^QuadTree($T), level := 0, corner := 0) {
     draw_quad(^renderer, ^quad);
 
     if qt.nw != null {
-        draw_quad_tree(qt.nw, level + 1, 1);
-        draw_quad_tree(qt.ne, level + 1, 2);
-        draw_quad_tree(qt.sw, level + 1, 3);
-        draw_quad_tree(qt.se, level + 1, 4);
+        draw_quad_tree(qt.nw);
+        draw_quad_tree(qt.ne);
+        draw_quad_tree(qt.sw);
+        draw_quad_tree(qt.se);
     }
 }
 
@@ -227,13 +242,17 @@ main :: proc (args: [] cstring) {
     textures_init();
 
     atlas = atlas_create(^textures.tilemap);
-    atlas_map(^atlas, 0, AtlasSprite.{ x = 16, y = 0, w = 16, h = 16 });
+    atlas_map(^atlas, 0, AtlasSprite.{ x = 16.0f, y = 0.0f, w = 16.0f, h = 16.0f });
 
     event.init();
     input.init(^input_state);
 
+    Dude_Color_Table[0] = Color4f32.{ 1.0f, 0.0f, 0.0f, 1.0f };
+    Dude_Color_Table[1] = Color4f32.{ 0.0f, 1.0f, 0.0f, 1.0f };
+    Dude_Color_Table[2] = Color4f32.{ 0.0f, 0.0f, 1.0f, 1.0f };
+
     array_init(^dudes);
-    for i: 0 .. 2500 {
+    for i: 0 .. 4000 {
         array_push(^dudes, dude_create_random());
     }
 
@@ -242,7 +261,7 @@ main :: proc (args: [] cstring) {
 }
 
 
-Dude_Color_Table : [4] Color4f32;
+Dude_Color_Table : [3] Color4f32;
 
 Dude :: struct {
     pos  : V2f;
@@ -252,22 +271,24 @@ Dude :: struct {
 
     can_move_x : bool = true;
     can_move_y : bool = true;
+    couldnt_move_count : u16 = ~~0;
 }
 
 dude_create_random :: proc () -> Dude {
     return Dude.{
-        pos = V2f.{ random_float(0.0f, 1000.0f), random_float(0.0f, 1000.0f) },
+        pos = V2f.{ random_float(-600.0f, 600.0f), random_float(-600.0f, 600.0f) },
         vel = V2f.{ random_float(-3.0f, 3.0f), random_float(-3.0f, 3.0f) },
         size = random_float(2.0f, 3.0f),
-        color = Dude_Color_Table[random_between(0, 3)],
+        color = Dude_Color_Table[random() % 3],
     };
 }
 
 dude_update :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {
-    // if random_between(0, 100) < 1 {
-    //     vel.x = random_float(-2.0f, 2.0f);
-    //     vel.y = random_float(-2.0f, 2.0f);
-    // }
+    if random_between(0, 100) < 1 || couldnt_move_count >= ~~2 {
+        vel.x = random_float(-3.0f, 3.0f);
+        vel.y = random_float(-3.0f, 3.0f);
+        couldnt_move_count = ~~0;
+    }
 
     dude_try_move(dude, other_dudes);
 }
@@ -285,7 +306,7 @@ dude_try_move :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {
     collided := false;
 
     pos.x += vel.x;
-    if pos.x - size < 0.0f || pos.x + size >= ~~window_width do collided = true;
+    if pos.x - size < ~~-half_window_width || pos.x + size >= ~~half_window_width do collided = true;
 
     dude_aabb := dude_get_aabb(dude);
     for other: potential_dudes {
@@ -304,7 +325,7 @@ dude_try_move :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {
     collided = false;
 
     pos.y += vel.y;
-    if pos.y - size < 0.0f || pos.y + size >= ~~window_height do collided = true;
+    if pos.y - size < ~~-half_window_height || pos.y + size >= ~~half_window_height do collided = true;
 
     dude_aabb = dude_get_aabb(dude);
     for other: potential_dudes {
index f57a62cffc3453fe3cab92b24258323d01e75b7c..58b3550ce9b7df1fb521db49bc9cbbfc3c5e2cf7 100644 (file)
@@ -54,7 +54,7 @@ quadtree_subdivide :: proc (use qt: ^QuadTree($T), a: Allocator) {
     qt.se = alloc(a, sizeof QuadTree(T));
 
     quadtree_init(qt.nw, AABB.{ region.x,      region.y,      hw, hh });
-    quadtree_init(qt.ne, AABB.{ region.x + hw, region.y,      hw, hh }); 
+    quadtree_init(qt.ne, AABB.{ region.x + hw, region.y,      hw, hh });
     quadtree_init(qt.sw, AABB.{ region.x,      region.y + hh, hw, hh });
     quadtree_init(qt.se, AABB.{ region.x + hw, region.y + hh, hw, hh });
 }
index c7fa3964725b423ee327b9f3bf9eea3018e069a3..cb6575f595859aa03e7257a6ceeb8d47e0b6385f 100644 (file)
@@ -11,13 +11,13 @@ layout(location = 4) in vec2 a_tex_size;
 layout(location = 5) in vec4 a_col;
 
 uniform mat4 u_proj;
-// uniform mat4 u_world;
+uniform mat4 u_world;
 
 out vec2 v_tex_pos;
 out vec4 v_col;
 
 void main() {
-       gl_Position = u_proj * vec4(a_vert_pos * a_size + a_pos, 0, 1);
+       gl_Position = u_proj * u_world * vec4(a_vert_pos * a_size + a_pos, 0, 1);
     v_col = a_col;
 
     if (a_tex_pos.x < 0.0) {
diff --git a/tags b/tags
index 35910a31655601996643848d9902c23fbaff4d57..19bbc0a86c9a7e792b0452aac7f33df7f9493082 100644 (file)
--- a/tags
+++ b/tags
@@ -136,7 +136,7 @@ DYNAMIC_READ        /usr/share/onyx/core/js/webgl.onyx      /^DYNAMIC_READ
 DomEvent       src/events.onyx /^DomEvent :: struct {$/
 DomEventKind   src/events.onyx /^DomEventKind :: enum {$/
 Dude   src/main.onyx   /^Dude :: struct {$/
-Dude_Color_Table       src/main.onyx   /^Dude_Color_Table : [4] Color4f32;$/
+Dude_Color_Table       src/main.onyx   /^Dude_Color_Table : [3] Color4f32;$/
 ELEMENT_ARRAY_BUFFER   /usr/share/onyx/core/js/webgl.onyx      /^ELEMENT_ARRAY_BUFFER           :: 0x8893$/
 ELEMENT_ARRAY_BUFFER_BINDING   /usr/share/onyx/core/js/webgl.onyx      /^ELEMENT_ARRAY_BUFFER_BINDING   :: 0x8895$/
 EQUAL  /usr/share/onyx/core/js/webgl.onyx      /^EQUAL                          :: 0x0202$/
@@ -671,6 +671,7 @@ array_to_slice      /usr/share/onyx/core/array.onyx /^array_to_slice :: proc (arr: ^[
 atlas  src/main.onyx   /^atlas         : Atlas$/
 atlas_apply_to_quad    src/gfx/atlas.onyx      /^atlas_apply_to_quad :: proc (use atlas: ^Atlas, id: i32, quad: ^Quad) {$/
 atlas_create   src/gfx/atlas.onyx      /^atlas_create :: proc (tex: ^Texture) -> Atlas {$/
+atlas_lookup   src/gfx/atlas.onyx      /^atlas_lookup :: proc (use atlas: ^Atlas, id: i32) -> AtlasSprite {$/
 atlas_map      src/gfx/atlas.onyx      /^atlas_map :: proc (use atlas: ^Atlas, id: i32, sprite: AtlasSprite) {$/
 attachShader   /usr/share/onyx/core/js/webgl.onyx      /^attachShader                   :: proc (program: GLProgram, shader: GLShader) -> GLProgram #foreign "gl" "attachShader" ---$/
 bezier_curve   src/font.onyx   /^bezier_curve :: proc (t: f32, ps: [] V2f) -> V2f {$/
@@ -750,7 +751,7 @@ drawArraysInstanced /usr/share/onyx/core/js/webgl.onyx      /^drawArraysInstanced
 drawElements   /usr/share/onyx/core/js/webgl.onyx      /^drawElements                   :: proc (mode: GLenum, count: GLsizei, type: GLenum, offset: GLint) #foreign "gl" "drawElements" ---$/
 drawElementsInstanced  /usr/share/onyx/core/js/webgl.onyx      /^drawElementsInstanced          :: proc (mode: GLenum, count: GLsizei, type: GLenum, offset: GLint, instanceCount: GLsizei) #foreign "gl" "drawElementsInstanced" ---$/
 draw_quad      src/main.onyx   /^draw_quad :: proc (use rc: ^RenderContext, quad: ^Quad) {$/
-draw_quad_tree src/main.onyx   /^draw_quad_tree :: proc (qt: ^QuadTree($T), level := 0, corner := 0) {$/
+draw_quad_tree src/main.onyx   /^draw_quad_tree :: proc (qt: ^QuadTree($T)) {$/
 draw_rect      src/main.onyx   /^draw_rect :: proc (use rc: ^RenderContext, x: f32, y: f32, w: f32, h: f32) {$/
 draw_textured_rect     src/main.onyx   /^draw_textured_rect :: proc (use rc: ^RenderContext, x: f32, y: f32, w: f32, h: f32, tx: f32, ty: f32, tw: f32, th: f32) {$/
 dude_create_random     src/main.onyx   /^dude_create_random :: proc () -> Dude {$/
@@ -782,6 +783,8 @@ getProgramParameter /usr/share/onyx/core/js/webgl.onyx      /^getProgramParameter
 getShaderParameter     /usr/share/onyx/core/js/webgl.onyx      /^getShaderParameter             :: proc (shader: GLShader, pname: GLenum) -> GLenum #foreign "gl" "getShaderParameter" ---$/
 getUniformLocation     /usr/share/onyx/core/js/webgl.onyx      /^getUniformLocation             :: proc (program: GLProgram, name: string) -> GLUniformLocation #foreign "gl" "getUniformLocation" ---$/
 getVertexAttribOffset  /usr/share/onyx/core/js/webgl.onyx      /^getVertexAttribOffset          :: proc (index: GLuint, pname: GLenum) #foreign "gl" "getVertexAttribOffset" ---$/
+half_window_height     src/main.onyx   /^half_window_height := 0$/
+half_window_width      src/main.onyx   /^half_window_width  := 0$/
 heap_alloc     /usr/share/onyx/core/alloc.onyx /^heap_alloc :: proc (size_: u32, align: u32) -> rawptr {$/
 heap_alloc_proc        /usr/share/onyx/core/alloc.onyx /^heap_alloc_proc :: proc (data: rawptr, aa: AllocAction, size: u32, align: u32, oldptr: rawptr) -> rawptr {$/
 heap_allocator /usr/share/onyx/core/alloc.onyx /^heap_allocator : Allocator;$/
@@ -870,6 +873,7 @@ quad_rebuffer_data  src/gfx/quad_renderer.onyx      /^quad_rebuffer_data :: proc (use
 quad_renderer_draw     src/gfx/quad_renderer.onyx      /^quad_renderer_draw :: proc (use qr: ^QuadRenderer, count := -1) {$/
 quad_renderer_init     src/gfx/quad_renderer.onyx      /^quad_renderer_init :: proc (use qr: ^QuadRenderer, initial_quads := 10) {$/
 quad_renderer_update_view      src/gfx/quad_renderer.onyx      /^quad_renderer_update_view :: proc (use qr: ^QuadRenderer) {$/
+quad_renderer_update_world     src/gfx/quad_renderer.onyx      /^quad_renderer_update_world :: proc (use qr: ^QuadRenderer,$/
 quad_scratch_buffer    src/main.onyx   /^quad_scratch_buffer : [512 * 1024] u8;$/
 quad_update_at_index   src/gfx/quad_renderer.onyx      /^quad_update_at_index :: proc (use qr: ^QuadRenderer, idx: i32, quad: Quad) {$/
 quadtree_free  src/quad_tree.onyx      /^quadtree_free :: proc (qt: ^QuadTree($T), initial := true) {$/