--- /dev/null
+package aabb
+
+use package vecmath
+
+AABB :: struct {
+ x: f32; y: f32; w: f32; h: f32;
+}
+
+aabb_contains :: proc (r: AABB, v: V2f) -> bool {
+ return v.x >= r.x
+ && v.x <= r.x + r.w
+ && v.y >= r.y
+ && v.y <= r.y + r.h;
+}
+
+aabb_intersects :: proc (r1: AABB, r2: AABB) -> bool {
+ return r1.x < r2.x + r2.w
+ && r1.x + r1.w > r2.x
+ && r1.y < r2.y + r2.h
+ && r1.y + r1.h > r2.y;
+}
// To be used with gl.LUMANIANCE
ttf_render_glyph :: proc (use ttf: ^TrueTypeFont, glyph: ^TTGlyph, data: ^u8, width: u32, height: u32) {
// Black background
- for y: 0 .. height do for x: 0 .. width do data[x + y * width] = cast(u8) 0;
+ for y: 0 .. height do for x: 0 .. width do data[x + y * width] = cast(u8) 255;
// scale := ~~cast(i32) units_per_em / cast(f32) height;
--- /dev/null
+package gfx
+
+use package core
+use package gl as gl
+use package gl_utils as gl_utils
+
+Atlas :: struct {
+ texture : ^Texture;
+ map : I32Map(AtlasSprite);
+}
+
+AtlasSprite :: struct {
+ x : i32 = 0;
+ y : i32 = 0;
+ w : i32 = 0;
+ h : i32 = 0;
+}
+
+atlas_create :: proc (tex: ^Texture) -> Atlas {
+ atlas : Atlas;
+ atlas.texture = tex;
+ i32map_init(^atlas.map);
+
+ return atlas;
+}
+
+atlas_map :: proc (use atlas: ^Atlas, id: i32, sprite: AtlasSprite) {
+ i32map_put(^map, id, 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;
+}
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 }
-Vec2 :: struct {
- x : f32;
- y : f32;
-}
+#private_file
+quad_program : gl.GLProgram = -1;
QuadRenderer :: struct {
quad_data : [..] Quad;
indexBuffer : gl.GLBuffer;
quadBuffer : gl.GLBuffer;
- program : gl.GLProgram;
-
u_proj_loc : gl.GLUniformLocation;
is_data_dirty : bool = false;
Color4f32 :: struct { r: f32; g: f32; b: f32; a: f32; }
Quad :: struct {
- pos : Vec2 = Vec2.{ 0f, 0f };
- size : Vec2 = Vec2.{ 0f, 0f };
+ pos : V2f = V2f.{ 0f, 0f };
+ size : V2f = V2f.{ 0f, 0f };
- tex_pos : Vec2 = Vec2.{ 0f, 0f };
- tex_size : Vec2 = Vec2.{ 0f, 0f };
+ tex_pos : V2f = V2f.{ 0f, 0f };
+ tex_size : V2f = V2f.{ 0f, 0f };
color : Color4f32 = Color4f32.{ 0f, 0f, 0f, 0f };
}
gl.bindVertexArray(vertexArray);
// Set up vertex and index data
- vertex_data : [4] Vec2;
- vertex_data[0] = Vec2.{ 0.0f, 0.0f };
- vertex_data[1] = Vec2.{ 0.0f, 1.0f };
- vertex_data[2] = Vec2.{ 1.0f, 1.0f };
- vertex_data[3] = Vec2.{ 1.0f, 0.0f };
+ vertex_data : [4] V2f;
+ vertex_data[0] = V2f.{ 0.0f, 0.0f };
+ vertex_data[1] = V2f.{ 0.0f, 1.0f };
+ vertex_data[2] = V2f.{ 1.0f, 1.0f };
+ vertex_data[3] = V2f.{ 1.0f, 0.0f };
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, Buffer.{
- count = sizeof [4] Vec2,
+ count = sizeof [4] V2f,
data = cast(^void) vertex_data
}, gl.STATIC_DRAW);
gl.bindVertexArray(-1);
- vertex_shader := gl_utils.compile_shader(gl.VERTEX_SHADER, #file_contents "./src/shaders/basic.vert");
- fragment_shader := gl_utils.compile_shader(gl.FRAGMENT_SHADER, #file_contents "./src/shaders/basic.frag");
- program = gl_utils.link_program(vertex_shader, fragment_shader);
- gl.useProgram(program);
+ if quad_program == ~~ -1 {
+ vertex_shader := gl_utils.compile_shader(gl.VERTEX_SHADER, #file_contents "./src/shaders/quad.vert");
+ fragment_shader := gl_utils.compile_shader(gl.FRAGMENT_SHADER, #file_contents "./src/shaders/quad.frag");
+ quad_program = gl_utils.link_program(vertex_shader, fragment_shader);
+ gl.useProgram(quad_program);
+ }
- u_proj_loc = gl.getUniformLocation(program, "u_proj");
+ u_proj_loc = gl.getUniformLocation(quad_program, "u_proj");
quad_renderer_update_view(qr);
}
-quad_renderer_draw :: proc (use qr: ^QuadRenderer) {
+quad_renderer_draw :: proc (use qr: ^QuadRenderer, count := -1) {
+ c := count;
+ if count == -1 do c = quad_data.count;
+
+ gl.useProgram(quad_program);
gl.bindVertexArray(vertexArray);
- gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, quad_data.count);
+ gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, c);
gl.bindVertexArray(-1);
}
use package gl as gl
use package gl_utils as gl_utils
+textures : struct {
+ tilemap : Texture;
+ smile : Texture;
+}
+
+textures_init :: proc () {
+ textures.tilemap = texture_create(#file_contents "res/tilemap.data", 256, 256);
+ textures.smile = texture_create(#file_contents "res/smile.data", 32, 32);
+
+ texture_prepare(^textures.tilemap);
+ texture_prepare(^textures.smile);
+}
+
+
Texture :: struct {
// NOTE: After a texture is loaded, we may not want to keep the
// raw texture data in memory any longer. This would not be possible
#include_file "utils/gl"
#include_file "gfx/quad_renderer"
#include_file "gfx/texture"
+#include_file "gfx/atlas"
#include_file "events"
#include_file "input"
#include_file "font"
#include_file "vecmath"
+#include_file "aabb"
+#include_file "quad_tree"
use package core
use package gfx
use package vecmath
use package ttf_font
-NUM_QUADS :: 1 << 10
-
+use package quad_tree
+use package aabb
+NUM_QUADS :: 1 << 17
RenderContext :: struct {
quad_renderer: ^QuadRenderer;
curr_quad_idx: i32 = 0;
max_quad_idx: i32 = 0;
- // @CLEANUP Allow for the syntax:
- // color := Color4f32.{ ... }
- // OR
- // color: Color4f32 = .{ ... }
color: Color4f32 = Color4f32.{ 1.0f, 1.0f, 1.0f, 1.0f };
}
if curr_quad_idx >= max_quad_idx do return;
quad_update_at_index(quad_renderer, curr_quad_idx, Quad.{
- pos = Vec2.{ x, y },
- size = Vec2.{ w, h },
+ pos = V2f.{ x, y },
+ size = V2f.{ w, h },
color = color,
- tex_size = Vec2.{ 1.0f, 1.0f },
+ tex_pos = V2f.{ -1.0f, -1.0f },
});
curr_quad_idx += 1;
}
+draw_textured_rect :: proc (use rc: ^RenderContext, x: f32, y: f32, w: f32, h: f32, tx: f32, ty: f32, tw: f32, th: f32) {
+ if curr_quad_idx >= max_quad_idx do return;
+
+ quad_update_at_index(quad_renderer, curr_quad_idx, Quad.{
+ pos = V2f.{ x, y },
+ size = V2f.{ w, h },
+ color = color,
+
+ tex_pos = V2f.{ tx, ty },
+ tex_size = V2f.{ tw, th },
+ });
+
+ curr_quad_idx += 1;
+}
+
+draw_quad :: proc (use rc: ^RenderContext, quad: ^Quad) {
+ if curr_quad_idx >= max_quad_idx do return;
+ quad_update_at_index(quad_renderer, curr_quad_idx, *quad);
+ curr_quad_idx += 1;
+}
+
render_context_flush :: proc (use rc: ^RenderContext) {
quad_rebuffer_data(quad_renderer);
- quad_renderer_draw(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.{});
+ // for i: 0 .. curr_quad_idx do quad_update_at_index(quad_renderer, i, Quad.{});
curr_quad_idx = 0;
}
renderer : RenderContext
input_state : input.InputState
-ttf : TrueTypeFont
-font_tex : Texture
-smile : Texture
-
-Player :: struct { use pos : Vec2; }
-player : Player
-
+atlas : Atlas
+dudes : [..] Dude
+dude_tree : QuadTree(Dude)
poll_events :: proc () {
use event.DomEventKind;
}
}
+quad_scratch_buffer : [512 * 1024] u8;
+
update :: proc () {
input.preupdate(^input_state);
defer input.postupdate(^input_state);
poll_events();
- player_speed :: 4f;
+ quad_scratch : ScratchState;
+ quad_alloc : Allocator;
+ scratch_state_init(^quad_scratch, ~~quad_scratch_buffer, 128 * 1024);
+ scratch_alloc_init(^quad_alloc, ^quad_scratch);
- if input.key_down(^input_state, Key.ArrowUp) do player.y -= player_speed;
- if input.key_down(^input_state, Key.ArrowDown) do player.y += player_speed;
- if input.key_down(^input_state, Key.ArrowLeft) do player.x -= player_speed;
- if input.key_down(^input_state, Key.ArrowRight) do player.x += player_speed;
-}
+ quadtree_init(^dude_tree, AABB.{ 0.0f, 0.0f, ~~window_width, ~~window_height });
+ for ^d: dudes do quadtree_insert(^dude_tree, d, quad_alloc);
-glyph_size :: 64
-glyph_data : [glyph_size * glyph_size] u8
+ for ^d: dudes do dude_update(d, ^dude_tree);
+ for ^d: dudes {
+ if d.can_move_x do d.pos.x += d.vel.x;
+ else do d.vel.x = -d.vel.x;
+ if d.can_move_y do d.pos.y += d.vel.y;
+ else do d.vel.y = -d.vel.y;
+ }
+}
draw :: proc () {
- gl.clearColor(0.2f, 0.2f, 0.2f, 1.0f);
- // gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.clearColor(0.1f, 0.1f, 0.1f, 1.0f);
gl.clear(gl.COLOR_BUFFER_BIT);
- // renderer.color = Color4f32.{ 1f, 0f, 0f, 1f };
+ texture_use(^textures.tilemap);
+ draw_quad_tree(^dude_tree);
- // points : [6] V2f;
- // points[0] = V2f.{ 500.0f, 700.0f };
- // points[1] = V2f.{ 600.0f, 200.0f };
- // points[2] = V2f.{ 700.0f, 400.0f };
- // points[3] = V2f.{ 1700.0f, 800.0f };
- // points[4] = V2f.{ 1800.0f, 400.0f };
- // points[5] = V2f.{ 1000.0f, 200.0f };
+ draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 10f, 10f);
- // for i: 0 .. 200 {
- // pos := bezier_curve(~~i / 200.0f, points[0 .. 6]);
- // draw_rect(^renderer, pos.x, pos.y, 16f, 16f);
- // }
+ for ^d: dudes {
+ aabb := dude_get_aabb(d);
+ draw_rect(^renderer, aabb.x, aabb.y, aabb.w, aabb.h);
+ }
- // for y: 0 .. glyph_size do for x: 0 .. glyph_size {
- // if glyph_data[x + y * glyph_size] != ~~0 {
- // draw_rect(^renderer, ~~(x * 2 + 100), ~~(y * 2 + 100), 2f, 2f);
- // }
- // }
+ render_context_flush(^renderer);
+}
- // mets := ttf_lookup_horizontal_metrics(^ttf, glyph_index);
- // println(cast(u32) mets.advance_width);
+draw_quad_tree :: proc (qt: ^QuadTree($T), level := 0, corner := 0) {
+ col := cast(f32) (0.2f + 0.15f * ~~level);
+ if col > 1.0f do col = 1.0f;
- // rx := 100.0f / ~~ cast(i32) (glyph.x_max - glyph.x_min);
- // ry := 100.0f / ~~ cast(i32) (glyph.y_min - glyph.y_max);
- // for p: glyph.points {
- // if p.on_curve do continue;
- // draw_rect(^renderer, ~~ cast(i32) p.x * rx + 100f, ~~ cast(i32) p.y * ry + 100f, 10f, 10f);
- // }
+ color := Color4f32.{ 0.0f, 0.0f, 0.0f, 1.0f };
- texture_use(^font_tex);
- draw_rect(^renderer, 100f, 100f, 256f, 256f);
- render_context_flush(^renderer);
+ if corner == 1 do color.r = col;
+ if corner == 2 do color.g = col;
+ if corner == 3 do color.b = col;
- texture_use(^smile);
- draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 10f, 10f);
- draw_rect(^renderer, player.pos.x, player.pos.y, 100f, 100f);
- render_context_flush(^renderer);
+ quad := Quad.{
+ pos = V2f.{ qt.region.x, qt.region.y },
+ size = V2f.{ qt.region.w, qt.region.h },
+ color = color,
+
+ tex_pos = V2f.{ -1.0f, -1.0f },
+ };
+ 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);
+ }
}
+debugger :: proc () #foreign "dummy" "breakable" ---
+
// This procedure is called asynchronously from JS every frame.
new_frame_callback :: proc () #export {
update();
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
render_context_init(^renderer, null);
+ textures_init();
- image_data := #file_contents "res/smile.data";
- smile = texture_create(image_data, 32, 32);
- texture_prepare(^smile);
+ atlas = atlas_create(^textures.tilemap);
+ atlas_map(^atlas, 0, AtlasSprite.{ x = 16, y = 0, w = 16, h = 16 });
event.init();
input.init(^input_state);
- ttf_data := #file_contents "res/Hack-Regular.ttf";
- ttf = ttf_create(ttf_data);
+ array_init(^dudes);
+ for i: 0 .. 500 {
+ array_push(^dudes, dude_create_random());
+ }
- glyph : ^TTGlyph = null;
- glyph_index := ttf_lookup_glyph_by_char(^ttf, ~~ #char "A");
- glyph = ttf_read_glyph(^ttf, glyph_index);
- if glyph == null do return;
- defer ttf_glyph_destroy(glyph);
+ game_launch :: proc () #foreign "game" "launch" ---;
+ game_launch();
+}
- ttf_render_glyph(^ttf, glyph, ~~glyph_data, glyph_size, glyph_size);
- font_tex = texture_create(glyph_data[0 .. glyph_size * glyph_size], glyph_size, glyph_size, TextureDataMode.BRIGHTNESS);
- texture_prepare(^font_tex);
- game_launch();
+Dude_Color_Table : [4] Color4f32;
+
+Dude :: struct {
+ pos : V2f;
+ vel : V2f;
+ size : f32;
+ color : Color4f32;
+
+ can_move_x : bool = true;
+ can_move_y : bool = true;
+}
+
+dude_create_random :: proc () -> Dude {
+ return Dude.{
+ pos = V2f.{ random_float(0.0f, 300.0f), random_float(0.0f, 300.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)],
+ };
+}
+
+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);
+ // }
+
+ dude_try_move(dude, other_dudes);
}
+dude_try_move :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {
+ old_pos := pos;
+ potential_dudes : [..] ^Dude;
+ array_init(^potential_dudes);
+ defer array_free(^potential_dudes);
-game_launch :: proc () #foreign "game" "launch" ---
+ around := AABB.{ x = pos.x - size * 5.0f, y = pos.y - size * 5.0f, w = size * 10.0f, h = size * 10.0f };
+ quadtree_query(other_dudes, around, ^potential_dudes);
+ collided := false;
+
+ pos.x += vel.x;
+ if pos.x - size < 0.0f || pos.x + size >= ~~window_width do collided = true;
+
+ dude_aabb := dude_get_aabb(dude);
+ for other: potential_dudes {
+ if other == dude do continue;
+
+ other_aabb := dude_get_aabb(other);
+ if aabb_intersects(dude_aabb, other_aabb) {
+ // printf("COLLISION\n");
+ collided = true;
+ break;
+ }
+ }
+
+ can_move_x = !collided;
+ pos.x -= vel.x;
+
+ collided = false;
+
+ pos.y += vel.y;
+ if pos.y - size < 0.0f || pos.y + size >= ~~window_height do collided = true;
+
+ dude_aabb = dude_get_aabb(dude);
+ for other: potential_dudes {
+ if other == dude do continue;
+
+ other_aabb := dude_get_aabb(other);
+ if aabb_intersects(dude_aabb, other_aabb) {
+ collided = true;
+ break;
+ }
+ }
+
+ can_move_y = !collided;
+ pos.y -= vel.y;
+}
+
+dude_get_aabb :: proc (use dude: ^Dude) -> AABB {
+ return AABB.{ x = pos.x - size, y = pos.y - size, w = size * 2.0f, h = size * 2.0f };
+}
--- /dev/null
+package main
+
+#include_file "core/std/js"
+#include_file "core/js/webgl"
+
+#include_folder "src/"
+#include_file "utils/gl"
+#include_file "gfx/quad_renderer"
+#include_file "gfx/texture"
+#include_file "gfx/atlas"
+#include_file "events"
+#include_file "input"
+#include_file "font"
+#include_file "vecmath"
+#include_file "aabb"
+#include_file "quad_tree"
+
+use package core
+use package gfx
+use package gl as gl
+use package event as event
+use package input as input { Key }
+use package vecmath
+use package ttf_font
+
+use package quad_tree
+use package aabb
+
+NUM_QUADS :: 1 << 10
+
+RenderContext :: struct {
+ quad_renderer: ^QuadRenderer;
+
+ curr_quad_idx: i32 = 0;
+ max_quad_idx: i32 = 0;
+
+ color: Color4f32 = Color4f32.{ 1.0f, 1.0f, 1.0f, 1.0f };
+}
+
+render_context_init :: proc (use rc: ^RenderContext, qr: ^QuadRenderer = null) {
+ aqr := qr;
+
+ if aqr == null {
+ aqr = calloc(sizeof QuadRenderer);
+ quad_renderer_init(aqr, NUM_QUADS);
+ }
+
+ *rc = RenderContext.{
+ quad_renderer = aqr,
+ max_quad_idx = qr.quad_data.count,
+ };
+}
+
+draw_rect :: proc (use rc: ^RenderContext, x: f32, y: f32, w: f32, h: f32) {
+ if curr_quad_idx >= max_quad_idx do return;
+
+ quad_update_at_index(quad_renderer, curr_quad_idx, Quad.{
+ pos = V2f.{ x, y },
+ size = V2f.{ w, h },
+ color = color,
+
+ tex_pos = V2f.{ -1.0f, -1.0f },
+ });
+
+ curr_quad_idx += 1;
+}
+
+draw_textured_rect :: proc (use rc: ^RenderContext, x: f32, y: f32, w: f32, h: f32, tx: f32, ty: f32, tw: f32, th: f32) {
+ if curr_quad_idx >= max_quad_idx do return;
+
+ quad_update_at_index(quad_renderer, curr_quad_idx, Quad.{
+ pos = V2f.{ x, y },
+ size = V2f.{ w, h },
+ color = color,
+
+ tex_pos = V2f.{ tx, ty },
+ tex_size = V2f.{ tw, th },
+ });
+
+ curr_quad_idx += 1;
+}
+
+draw_quad :: proc (use rc: ^RenderContext, quad: ^Quad) {
+ if curr_quad_idx >= max_quad_idx do return;
+ quad.color = color;
+ quad_update_at_index(quad_renderer, curr_quad_idx, *quad);
+ curr_quad_idx += 1;
+}
+
+render_context_flush :: proc (use rc: ^RenderContext) {
+ 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;
+}
+
+
+
+// @Cleanup
+window_width := 0
+window_height := 0
+
+renderer : RenderContext
+input_state : input.InputState
+atlas : Atlas
+dudes : [..] Dude
+dude_tree : QuadTree(Dude)
+
+poll_events :: proc () {
+ use event.DomEventKind;
+
+ 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;
+
+ gl.canvasSize(window_width, window_height);
+ gl.viewport(0, 0, window_width, window_height);
+
+ quad_renderer_update_view(renderer.quad_renderer);
+ }
+ }
+}
+
+quad_scratch_buffer : [128 * 1024] u8;
+
+update :: proc () {
+ input.preupdate(^input_state);
+ defer input.postupdate(^input_state);
+ poll_events();
+
+ quad_scratch : ScratchState;
+ quad_alloc : Allocator;
+ scratch_state_init(^quad_scratch, ~~quad_scratch_buffer, 128 * 1024);
+ scratch_alloc_init(^quad_alloc, ^quad_scratch);
+
+ quadtree_init(^dude_tree, AABB.{ 0.0f, 0.0f, ~~window_width, ~~window_height });
+ for ^d: dudes do quadtree_insert(^dude_tree, d, quad_alloc);
+
+ for ^d: dudes do dude_update(d, ^dude_tree);
+}
+
+draw :: proc () {
+ gl.clearColor(0.1f, 0.1f, 0.1f, 1.0f);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ texture_use(^textures.tilemap);
+ draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 10f, 10f);
+
+ for ^d: dudes {
+ aabb := dude_get_aabb(d);
+ draw_rect(^renderer, aabb.x, aabb.y, aabb.w, aabb.h);
+ }
+
+ render_context_flush(^renderer);
+}
+
+// This procedure is called asynchronously from JS every frame.
+new_frame_callback :: proc () #export {
+ update();
+ draw();
+}
+
+main :: proc (args: [] cstring) {
+ println("Setting up WebGL2 canvas...");
+
+ if !gl.init("gamecanvas") {
+ print("Failed to initialize GL canvas.");
+ return;
+ }
+
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+ render_context_init(^renderer, null);
+ textures_init();
+
+ atlas = atlas_create(^textures.tilemap);
+ atlas_map(^atlas, 0, AtlasSprite.{ x = 16, y = 0, w = 16, h = 16 });
+
+ event.init();
+ input.init(^input_state);
+
+ array_init(^dudes);
+ for i: 0 .. 50 {
+ array_push(^dudes, dude_create_random());
+ }
+ // array_push(^dudes, Dude.{
+ // pos = V2f.{ 100.0f, 100.0f },
+ // vel = V2f.{ 2.0f, 0.0f },
+ // size = 10.0f,
+ // color = Color4f32.{ 1.0f, 1.0f, 1.0f, 1.0f },
+ // });
+
+ // array_push(^dudes, Dude.{
+ // pos = V2f.{ 1000.0f, 100.0f },
+ // vel = V2f.{ -2.0f, 0.0f },
+ // size = 10.0f,
+ // color = Color4f32.{ 1.0f, 1.0f, 1.0f, 1.0f },
+ // });
+
+ game_launch :: proc () #foreign "game" "launch" ---;
+ game_launch();
+}
+
+
+Dude_Color_Table : [4] Color4f32;
+
+Dude :: struct {
+ pos : V2f;
+ vel : V2f;
+ size : f32;
+ color : Color4f32;
+}
+
+dude_create_random :: proc () -> Dude {
+ return Dude.{
+ pos = V2f.{ random_float(0.0f, 800.0f), random_float(0.0f, 800.0f) },
+ vel = V2f.{ random_float(-3.0f, 3.0f), random_float(-3.0f, 3.0f) },
+ size = random_float(5.0f, 30.0f),
+ color = Dude_Color_Table[random_between(0, 3)],
+ };
+}
+
+dude_update :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {
+ // if random_between(0, 100) < 2 {
+ // vel.x = random_float(-2.0f, 2.0f);
+ // vel.y = random_float(-2.0f, 2.0f);
+ // }
+
+ dude_try_move(dude, other_dudes);
+}
+
+dude_try_move :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {
+ old_pos := pos;
+
+ potential_dudes : [..] ^Dude;
+ array_init(^potential_dudes);
+ defer array_free(^potential_dudes);
+
+ around := AABB.{ x = pos.x - size * 10.0f, y = pos.y - size * 10.0f, w = size * 20.0f, h = size * 20.0f };
+ quadtree_query(other_dudes, around, ^potential_dudes);
+
+ collided := false;
+
+ pos.x += vel.x;
+ if pos.x - size < 0.0f || pos.x + size >= ~~window_width do collided = true;
+
+ dude_aabb := dude_get_aabb(dude);
+ for other: potential_dudes {
+ if other == dude do continue;
+
+ other_aabb := dude_get_aabb(other);
+ if aabb_intersects(dude_aabb, other_aabb) {
+ collided = true;
+ break;
+ }
+ }
+
+ if collided {
+ pos.x -= vel.x;
+ vel.x = -vel.x;
+ }
+
+ collided = false;
+
+ pos.y += vel.y;
+ if pos.y - size < 0.0f || pos.y + size >= ~~window_height do collided = true;
+
+ dude_aabb = dude_get_aabb(dude);
+ for other: potential_dudes {
+ if other == dude do continue;
+
+ other_aabb := dude_get_aabb(other);
+ if aabb_intersects(dude_aabb, other_aabb) {
+ collided = true;
+ break;
+ }
+ }
+
+ if collided {
+ pos.y -= vel.y;
+ vel.y = -vel.y;
+ }
+}
+
+dude_get_aabb :: proc (use dude: ^Dude) -> AABB {
+ return AABB.{ x = pos.x - size, y = pos.y - size, w = size * 2.0f, h = size * 2.0f };
+}
--- /dev/null
+package quad_tree
+
+use package core
+use package aabb
+
+#private_file
+QUAD_TREE_ENTITY_STORAGE :: 2;
+
+QuadTree :: struct ($T) {
+ region : AABB;
+
+ points : [QUAD_TREE_ENTITY_STORAGE] ^T;
+ points_count : u32 = 0;
+
+ nw: ^QuadTree(T) = null;
+ ne: ^QuadTree(T) = null;
+ sw: ^QuadTree(T) = null;
+ se: ^QuadTree(T) = null;
+}
+
+quadtree_init :: proc (qt: ^QuadTree($T), initial_region: AABB) {
+ qt.region = initial_region;
+ qt.nw = null;
+ qt.ne = null;
+ qt.sw = null;
+ qt.se = null;
+ qt.points_count = 0;
+
+ for ^p: qt.points do *p = null;
+}
+
+// quadtree_free :: proc (qt: ^QuadTree($T), initial := true) {
+// if qt.nw != null {
+// quadtree_free(qt.nw, false);
+// quadtree_free(qt.ne, false);
+// quadtree_free(qt.sw, false);
+// quadtree_free(qt.se, false);
+// }
+//
+// if !initial {
+// cfree(qt);
+// }
+// }
+
+quadtree_subdivide :: proc (use qt: ^QuadTree($T), a: Allocator) {
+ if nw != null do return;
+
+ hw := region.w / ~~ 2;
+ hh := region.h / ~~ 2;
+
+ qt.nw = alloc(a, sizeof QuadTree(T));
+ qt.ne = alloc(a, sizeof QuadTree(T));
+ qt.sw = alloc(a, sizeof QuadTree(T));
+ 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.sw, AABB.{ region.x, region.y + hh, hw, hh });
+ quadtree_init(qt.se, AABB.{ region.x + hw, region.y + hh, hw, hh });
+}
+
+quadtree_insert :: proc (use qt: ^QuadTree($T), t: ^T, alloc := context.allocator) -> bool {
+ pos := t.pos; // T is expected to have a 'pos' element.
+
+ if !aabb_contains(region, pos) do return false;
+
+ if points_count < QUAD_TREE_ENTITY_STORAGE && nw == null {
+ points[points_count] = t;
+ points_count += 1;
+ return true;
+ }
+
+ if nw == null do quadtree_subdivide(qt, alloc);
+
+ if quadtree_insert(nw, t, alloc) do return true;
+ if quadtree_insert(ne, t, alloc) do return true;
+ if quadtree_insert(sw, t, alloc) do return true;
+ if quadtree_insert(se, t, alloc) do return true;
+
+ return false;
+}
+
+quadtree_query :: proc (use qt: ^QuadTree($T), r: AABB, p: ^[..] ^T) {
+ if !aabb_intersects(region, r) do return;
+
+ while i := 0; i < points_count {
+ if aabb_contains(r, points[i].pos) do array_push(p, points[i]);
+ i += 1;
+ }
+
+ if nw == null do return;
+
+ quadtree_query(nw, r, p);
+ quadtree_query(ne, r, p);
+ quadtree_query(sw, r, p);
+ quadtree_query(se, r, p);
+}
+++ /dev/null
-#version 300 es
-
-precision mediump float;
-
-uniform sampler2D tex;
-
-in vec2 v_tex_pos;
-in vec4 v_col;
-
-out vec4 fragColor;
-
-void main() {
- fragColor = v_col * texture(tex, v_tex_pos);
-}
+++ /dev/null
-#version 300 es
-
-// Per Vertex
-layout(location = 0) in vec2 a_vert_pos;
-
-// Per Quad
-layout(location = 1) in vec2 a_pos;
-layout(location = 2) in vec2 a_size;
-layout(location = 3) in vec2 a_tex_pos;
-layout(location = 4) in vec2 a_tex_size;
-layout(location = 5) in vec4 a_col;
-
-uniform mat4 u_proj;
-
-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);
- v_col = a_col;
-
- v_tex_pos = a_tex_pos + a_vert_pos * a_tex_size;
-}
--- /dev/null
+#version 300 es
+
+precision mediump float;
+
+uniform sampler2D tex;
+
+in vec2 v_tex_pos;
+in vec4 v_col;
+
+out vec4 fragColor;
+
+void main() {
+ if (v_tex_pos.x < 0.0) {
+ fragColor = v_col;
+ } else {
+ fragColor = v_col * texture(tex, v_tex_pos);
+ }
+}
--- /dev/null
+#version 300 es
+
+// Per Vertex
+layout(location = 0) in vec2 a_vert_pos;
+
+// Per Quad
+layout(location = 1) in vec2 a_pos;
+layout(location = 2) in vec2 a_size;
+layout(location = 3) in vec2 a_tex_pos;
+layout(location = 4) in vec2 a_tex_size;
+layout(location = 5) in vec4 a_col;
+
+uniform mat4 u_proj;
+// 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);
+ v_col = a_col;
+
+ if (a_tex_pos.x < 0.0) {
+ v_tex_pos = vec2(-1.0, -1.0);
+ } else {
+ v_tex_pos = a_tex_pos + a_vert_pos * a_tex_size;
+ }
+}
!_TAG_PROGRAM_NAME Onyx Compiler
!_TAG_PROGRAM_URL https://github.com/brendanfh/onyx
!_TAG_PROGRAM_VERSION 0.0.1
+AABB src/aabb.onyx /^AABB :: struct {$/
ACTIVE_ATTRIBUTES /usr/share/onyx/core/js/webgl.onyx /^ACTIVE_ATTRIBUTES :: 0x8B89$/
ACTIVE_TEXTURE /usr/share/onyx/core/js/webgl.onyx /^ACTIVE_TEXTURE :: 0x84E0$/
ACTIVE_UNIFORMS /usr/share/onyx/core/js/webgl.onyx /^ACTIVE_UNIFORMS :: 0x8B86$/
ATTACHED_SHADERS /usr/share/onyx/core/js/webgl.onyx /^ATTACHED_SHADERS :: 0x8B85$/
AllocAction /usr/share/onyx/core/builtin.onyx /^AllocAction :: enum {$/
Allocator /usr/share/onyx/core/builtin.onyx /^Allocator :: struct {$/
+Atlas src/gfx/atlas.onyx /^Atlas :: struct {$/
+AtlasSprite src/gfx/atlas.onyx /^AtlasSprite :: struct {$/
BACK /usr/share/onyx/core/js/webgl.onyx /^BACK :: 0x0405$/
BLEND /usr/share/onyx/core/js/webgl.onyx /^BLEND :: 0x0BE2$/
BLEND_COLOR /usr/share/onyx/core/js/webgl.onyx /^BLEND_COLOR :: 0x8005$/
DYNAMIC_READ /usr/share/onyx/core/js/webgl.onyx /^DYNAMIC_READ :: 0x88E9$/
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;$/
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$/
POLYGON_OFFSET_FACTOR /usr/share/onyx/core/js/webgl.onyx /^POLYGON_OFFSET_FACTOR :: 0x8038$/
POLYGON_OFFSET_FILL /usr/share/onyx/core/js/webgl.onyx /^POLYGON_OFFSET_FILL :: 0x8037$/
POLYGON_OFFSET_UNITS /usr/share/onyx/core/js/webgl.onyx /^POLYGON_OFFSET_UNITS :: 0x2A00$/
-Player src/main.onyx /^Player :: struct { use pos : Vec2; }$/
PtrMap /usr/share/onyx/core/ptrmap.onyx /^PtrMap :: struct {$/
PtrMapEntry /usr/share/onyx/core/ptrmap.onyx /^PtrMapEntry :: struct {$/
QUERY_RESULT /usr/share/onyx/core/js/webgl.onyx /^QUERY_RESULT :: 0x8866$/
QUERY_RESULT_AVAILABLE /usr/share/onyx/core/js/webgl.onyx /^QUERY_RESULT_AVAILABLE :: 0x8867$/
Quad src/gfx/quad_renderer.onyx /^Quad :: struct {$/
QuadRenderer src/gfx/quad_renderer.onyx /^QuadRenderer :: struct {$/
+QuadTree src/quad_tree.onyx /^QuadTree :: struct ($T) {$/
R11F_G11F_B10F /usr/share/onyx/core/js/webgl.onyx /^R11F_G11F_B10F :: 0x8C3A$/
R16F /usr/share/onyx/core/js/webgl.onyx /^R16F :: 0x822D$/
R16I /usr/share/onyx/core/js/webgl.onyx /^R16I :: 0x8233$/
VERTEX_ATTRIB_ARRAY_TYPE /usr/share/onyx/core/js/webgl.onyx /^VERTEX_ATTRIB_ARRAY_TYPE :: 0x8625$/
VERTEX_SHADER /usr/share/onyx/core/js/webgl.onyx /^VERTEX_SHADER :: 0x8B31$/
VIEWPORT /usr/share/onyx/core/js/webgl.onyx /^VIEWPORT :: 0x0BA2$/
-Vec2 src/gfx/quad_renderer.onyx /^Vec2 :: struct {$/
WAIT_FAILED /usr/share/onyx/core/js/webgl.onyx /^WAIT_FAILED :: 0x911D$/
ZERO /usr/share/onyx/core/js/webgl.onyx /^ZERO :: 0$/
+aabb_contains src/aabb.onyx /^aabb_contains :: proc (r: AABB, v: V2f) -> bool {$/
+aabb_intersects src/aabb.onyx /^aabb_intersects :: proc (r1: AABB, r2: AABB) -> bool {$/
abs_f32 /usr/share/onyx/core/intrinsics.onyx /^abs_f32 :: proc (val: f32) -> f32 #intrinsic ---$/
abs_f64 /usr/share/onyx/core/intrinsics.onyx /^abs_f64 :: proc (val: f64) -> f64 #intrinsic ---$/
activeTexture /usr/share/onyx/core/js/webgl.onyx /^activeTexture :: proc (texture: GLenum) #foreign "gl" "activeTexture" ---$/
array_remove /usr/share/onyx/core/array.onyx /^array_remove :: proc (arr: ^[..] $T, elem: T) {$/
array_sort /usr/share/onyx/core/array.onyx /^array_sort :: proc (arr: ^[..] $T, cmp: proc (T, T) -> i32) {$/
array_to_slice /usr/share/onyx/core/array.onyx /^array_to_slice :: proc (arr: ^[..] $T) -> [] T {$/
+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_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 {$/
binary_reader_create src/font.onyx /^binary_reader_create :: proc (data: [] u8, initial_pos := 0) -> BinaryReader {$/
drawArraysInstanced /usr/share/onyx/core/js/webgl.onyx /^drawArraysInstanced :: proc (mode: GLenum, first: GLint, count: GLsizei, instanceCount: GLsizei) #foreign "gl" "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 := 4) {$/
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 {$/
+dude_get_aabb src/main.onyx /^dude_get_aabb :: proc (use dude: ^Dude) -> AABB {$/
+dude_tree src/main.onyx /^dude_tree : QuadTree(Dude)$/
+dude_try_move src/main.onyx /^dude_try_move :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {$/
+dude_update src/main.onyx /^dude_update :: proc (use dude: ^Dude, other_dudes: ^QuadTree(Dude)) {$/
+dudes src/main.onyx /^dudes : [..] Dude$/
enable /usr/share/onyx/core/js/webgl.onyx /^enable :: proc (cap: GLenum) #foreign "gl" "enable" ---$/
enableVertexAttribArray /usr/share/onyx/core/js/webgl.onyx /^enableVertexAttribArray :: proc (index: GLuint) #foreign "gl" "enableVertexAttribArray" ---$/
+f64_to_string /usr/share/onyx/core/string.onyx /^f64_to_string :: proc (f: f64, buf: [] u8) -> string {$/
finish /usr/share/onyx/core/js/webgl.onyx /^finish :: proc () #foreign "gl" "finish" ---$/
floor_f32 /usr/share/onyx/core/intrinsics.onyx /^floor_f32 :: proc (val: f32) -> f32 #intrinsic ---$/
floor_f64 /usr/share/onyx/core/intrinsics.onyx /^floor_f64 :: proc (val: f64) -> f64 #intrinsic ---$/
flush /usr/share/onyx/core/js/webgl.onyx /^flush :: proc () #foreign "gl" "flush" ---$/
-font_tex src/main.onyx /^font_tex : Texture$/
framebufferRenderbuffer /usr/share/onyx/core/js/webgl.onyx /^framebufferRenderbuffer :: proc (target: GLenum, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLRenderbuffer) #foreign "gl" "framebufferRenderbuffer" ---$/
framebufferTexture2D /usr/share/onyx/core/js/webgl.onyx /^framebufferTexture2D :: proc (target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLTexture, level: GLint) #foreign "gl" "framebufferTexture2D" ---$/
framebufferTextureLayer /usr/share/onyx/core/js/webgl.onyx /^framebufferTextureLayer :: proc (target: GLenum, attachment: GLenum, texture: GLTexture, level: GLint, layer: GLint) #foreign "gl" "framebufferTextureLayer" ---$/
free /usr/share/onyx/core/builtin.onyx /^free :: proc (use a: Allocator, ptr: rawptr) {$/
frontFace /usr/share/onyx/core/js/webgl.onyx /^frontFace :: proc (mode: GLenum) #foreign "gl" "frontFace" ---$/
-game_launch src/main.onyx /^game_launch :: proc () #foreign "game" "launch" ---$/
generateMipmap /usr/share/onyx/core/js/webgl.onyx /^generateMipmap :: proc (target: GLenum) #foreign "gl" "generateMipmap" ---$/
getActiveAttrib /usr/share/onyx/core/js/webgl.onyx /^getActiveAttrib :: proc (program: GLProgram, index: GLuint, out: ^GLActiveInfo) #foreign "gl" "getActiveAttrib" ---$/
getActiveUniform /usr/share/onyx/core/js/webgl.onyx /^getActiveUniform :: proc (program: GLProgram, index: GLuint, out: ^GLActiveInfo) #foreign "gl" "getActiveUniform" ---$/
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" ---$/
-glyph_data src/main.onyx /^glyph_data : [glyph_size * glyph_size] u8$/
-glyph_size src/main.onyx /^glyph_size :: 64$/
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;$/
memory_copy /usr/share/onyx/core/memory.onyx /^memory_copy :: proc (dst_: rawptr, src_: rawptr, len: u32) {$/
memory_grow /usr/share/onyx/core/intrinsics.onyx /^memory_grow :: proc (val: i32) -> i32 #intrinsic ---$/
memory_init /usr/share/onyx/core/alloc.onyx /^memory_init :: proc () {$/
+memory_set /usr/share/onyx/core/memory.onyx /^memory_set :: proc (start: rawptr, length: u32, value: u8) {$/
memory_size /usr/share/onyx/core/intrinsics.onyx /^memory_size :: proc () -> i32 #intrinsic ---$/
min_f32 /usr/share/onyx/core/intrinsics.onyx /^min_f32 :: proc (lhs: f32, rhs: f32) -> f32 #intrinsic ---$/
min_f64 /usr/share/onyx/core/intrinsics.onyx /^min_f64 :: proc (lhs: f64, rhs: f64) -> f64 #intrinsic ---$/
or_i64 /usr/share/onyx/core/intrinsics.onyx /^or_i64 :: proc (lhs: i64, rhs: i64) -> i64 #intrinsic ---$/
output_string /usr/share/onyx/core/sys/js.onyx /^output_string :: proc (s: string) -> u32 #foreign "host" "print_str" ---$/
pixelStorei /usr/share/onyx/core/js/webgl.onyx /^pixelStorei :: proc (pname: GLenum, param: GLenum) #foreign "gl" "pixelStorei" ---$/
-player src/main.onyx /^player : Player$/
poll src/events.onyx /^poll :: proc (ev: ^Event) -> bool {$/
poll_events src/main.onyx /^poll_events :: proc () {$/
polygonOffset /usr/share/onyx/core/js/webgl.onyx /^polygonOffset :: proc (factor: GLfloat, units: GLfloat) #foreign "gl" "polygonOffset" ---$/
print_bool /usr/share/onyx/core/stdio.onyx /^print_bool :: proc (b: bool) do string_builder_append(^print_buffer, b);$/
print_buffer_flush /usr/share/onyx/core/stdio.onyx /^print_buffer_flush :: proc () {$/
print_cstring /usr/share/onyx/core/stdio.onyx /^print_cstring :: proc (s: cstring) do string_builder_append(^print_buffer, s);$/
+print_f32 /usr/share/onyx/core/stdio.onyx /^print_f32 :: proc (n: f32) do string_builder_append(^print_buffer, cast(f64) n);$/
+print_f64 /usr/share/onyx/core/stdio.onyx /^print_f64 :: proc (n: f64) do string_builder_append(^print_buffer, n);$/
print_i32 /usr/share/onyx/core/stdio.onyx /^print_i32 :: proc (n: i32, base := 10) do string_builder_append(^print_buffer, cast(i64) n, cast(u64) base);$/
print_i64 /usr/share/onyx/core/stdio.onyx /^print_i64 :: proc (n: i64, base := 10l) do string_builder_append(^print_buffer, n, base);$/
print_ptr /usr/share/onyx/core/stdio.onyx /^print_ptr :: proc (p: ^void) do string_builder_append(^print_buffer, cast(i64) p, 16l);$/
print_range /usr/share/onyx/core/stdio.onyx /^print_range :: proc (r: range, sep := " ") {$/
print_string /usr/share/onyx/core/stdio.onyx /^print_string :: proc (s: string) {$/
print_vec src/vecmath.onyx /^print_vec :: proc (v: V2($T)) {$/
+printf /usr/share/onyx/core/stdio.onyx /^printf :: proc (format: string, va: ...) {$/
println /usr/share/onyx/core/stdio.onyx /^println :: proc (x: $T) {$/
process_event src/input.onyx /^process_event :: proc (use state: ^InputState, ev: ^event.Event) {$/
ptrmap_clear /usr/share/onyx/core/ptrmap.onyx /^ptrmap_clear :: proc (use pmap: ^PtrMap) {$/
ptrmap_init /usr/share/onyx/core/ptrmap.onyx /^ptrmap_init :: proc (use pmap: ^PtrMap, hash_count: i32 = 16) {$/
ptrmap_put /usr/share/onyx/core/ptrmap.onyx /^ptrmap_put :: proc (use pmap: ^PtrMap, key: rawptr, value: rawptr) {$/
quad_rebuffer_data src/gfx/quad_renderer.onyx /^quad_rebuffer_data :: proc (use qr: ^QuadRenderer) {$/
-quad_renderer_draw src/gfx/quad_renderer.onyx /^quad_renderer_draw :: proc (use qr: ^QuadRenderer) {$/
+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_scratch_buffer src/main.onyx /^quad_scratch_buffer : [128 * 1024] u8;$/
quad_update_at_index src/gfx/quad_renderer.onyx /^quad_update_at_index :: proc (use qr: ^QuadRenderer, idx: i32, quad: Quad) {$/
+quadtree_init src/quad_tree.onyx /^quadtree_init :: proc (qt: ^QuadTree($T), initial_region: AABB) {$/
+quadtree_insert src/quad_tree.onyx /^quadtree_insert :: proc (use qt: ^QuadTree($T), t: ^T, alloc := context.allocator) -> bool {$/
+quadtree_query src/quad_tree.onyx /^quadtree_query :: proc (use qt: ^QuadTree($T), r: AABB, p: ^[..] ^T) {$/
+quadtree_subdivide src/quad_tree.onyx /^quadtree_subdivide :: proc (use qt: ^QuadTree($T), a: Allocator) {$/
random /usr/share/onyx/core/random.onyx /^random :: proc (s := ^seed) -> u32 {$/
random_between /usr/share/onyx/core/random.onyx /^random_between :: proc (lo: i32, hi: i32) -> i32 do return random() % (hi + 1 - lo) + lo;$/
random_float /usr/share/onyx/core/random.onyx /^random_float :: proc (lo := 0.0f, hi := 1.0f) -> f32 {$/
sin /usr/share/onyx/core/math.onyx /^sin :: proc (t_: f32) -> f32 {$/
slr_i32 /usr/share/onyx/core/intrinsics.onyx /^slr_i32 :: proc (lhs: i32, rhs: i32) -> i32 #intrinsic ---$/
slr_i64 /usr/share/onyx/core/intrinsics.onyx /^slr_i64 :: proc (lhs: i64, rhs: i64) -> i64 #intrinsic ---$/
-smile src/main.onyx /^smile : Texture$/
sqrt_f32 /usr/share/onyx/core/intrinsics.onyx /^sqrt_f32 :: proc (val: f32) -> f32 #intrinsic ---$/
sqrt_f64 /usr/share/onyx/core/intrinsics.onyx /^sqrt_f64 :: proc (val: f64) -> f64 #intrinsic ---$/
sqrt_i32 /usr/share/onyx/core/math.onyx /^sqrt_i32 :: proc (x: i32) -> i32 {$/
string_advance_line /usr/share/onyx/core/string.onyx /^string_advance_line :: proc (str: ^string) {$/
string_builder_add_bool /usr/share/onyx/core/string.onyx /^string_builder_add_bool :: proc (use sb: ^StringBuilder, b: bool) -> ^StringBuilder {$/
string_builder_add_cstring /usr/share/onyx/core/string.onyx /^string_builder_add_cstring :: proc (use sb: ^StringBuilder, cstr: cstring) -> ^StringBuilder {$/
+string_builder_add_f64 /usr/share/onyx/core/string.onyx /^string_builder_add_f64 :: proc (use sb: ^StringBuilder, f: f64) -> ^StringBuilder {$/
string_builder_add_i64 /usr/share/onyx/core/string.onyx /^string_builder_add_i64 :: proc (use sb: ^StringBuilder, n: i64, base := 10l) -> ^StringBuilder {$/
string_builder_add_string /usr/share/onyx/core/string.onyx /^string_builder_add_string :: proc (use sb: ^StringBuilder, str: string) -> ^StringBuilder {$/
string_builder_append /usr/share/onyx/core/string.onyx /^string_builder_append :: proc {$/
texture_create src/gfx/texture.onyx /^texture_create :: proc (texdata: [] u8, width: i32, height: i32, data_mode := TextureDataMode.RGB) -> Texture {$/
texture_prepare src/gfx/texture.onyx /^texture_prepare :: proc (use tex: ^Texture) {$/
texture_use src/gfx/texture.onyx /^texture_use :: proc (use tex: ^Texture) {$/
+textures src/gfx/texture.onyx /^textures : struct {$/
+textures_init src/gfx/texture.onyx /^textures_init :: proc () {$/
trunc_f32 /usr/share/onyx/core/intrinsics.onyx /^trunc_f32 :: proc (val: f32) -> f32 #intrinsic ---$/
trunc_f64 /usr/share/onyx/core/intrinsics.onyx /^trunc_f64 :: proc (val: f64) -> f64 #intrinsic ---$/
-ttf src/main.onyx /^ttf : TrueTypeFont$/
ttf_create src/font.onyx /^ttf_create :: proc (ttf_data: [] u8) -> TrueTypeFont {$/
ttf_glyph_count src/font.onyx /^ttf_glyph_count :: proc (use ttf: ^TrueTypeFont) -> u32 {$/
ttf_glyph_destroy src/font.onyx /^ttf_glyph_destroy :: proc (glyph: ^TTGlyph) {$/
v2_square_dist src/vecmath.onyx /^v2_square_dist :: proc (a: V2($T), b: V2(T)) -> T {$/
v2_sub src/vecmath.onyx /^v2_sub :: proc (a: V2($T), b: V2(T)) -> V2(T) {$/
validateProgram /usr/share/onyx/core/js/webgl.onyx /^validateProgram :: proc (program: GLProgram) #foreign "gl" "validateProgram" ---$/
+vararg /usr/share/onyx/core/builtin.onyx /^vararg :: #type ^struct {$/
+vararg_get /usr/share/onyx/core/builtin.onyx /^vararg_get :: proc (va: vararg, ret: ^$T) -> bool {$/
vertexAttrib1f /usr/share/onyx/core/js/webgl.onyx /^vertexAttrib1f :: proc (idx: GLuint, x: GLfloat) #foreign "gl" "vertexAttrib1f" ---$/
vertexAttrib2f /usr/share/onyx/core/js/webgl.onyx /^vertexAttrib2f :: proc (idx: GLuint, x: GLfloat, y: GLfloat) #foreign "gl" "vertexAttrib2f" ---$/
vertexAttrib3f /usr/share/onyx/core/js/webgl.onyx /^vertexAttrib3f :: proc (idx: GLuint, x: GLfloat, y: GLfloat, z: GLfloat) #foreign "gl" "vertexAttrib3f" ---$/