game: { launch: start_game },
+ dummy: { breakable() { debugger; }, },
+
event: {
setup(esp, event_size) {
// Indicies into a Uint32Array are not based on bytes,
font_direction_hint : i16;
index_to_loc_format : TTIndexToLocFormat;
glyph_data_format : i16;
+
+ hhea : struct {
+ version : u32;
+ ascent : i16;
+ descent : i16;
+ line_gap : i16;
+ advance_width_max : u16;
+ min_left_side_bearing : i16;
+ min_right_side_bearing : i16;
+ x_max_extent : i16;
+ caret_slope_rise : i16;
+ caret_slope_run : i16;
+ caret_offset : i16;
+ metric_data_format : i16;
+ num_of_long_hor_metrics : u16;
+ };
}
TTTableInfo :: struct {
i32map_init(^ttf.table_map);
array_init(^ttf.char_maps);
ttf_read_offset_table(^ttf);
+ ttf_read_head_table(^ttf);
+ ttf_read_cmap_table(^ttf);
+ ttf_read_hhea_table(^ttf);
return ttf;
}
i32map_put(^table_map, tag_int, table_info);
if !string_equal(tag, "head") {
- // TODO: Calculate checksum to ensure everything looks right
csum := ttf_calc_table_checksum(^reader, table_info.offset, table_info.length);
if table_info.checksum != csum {
print("WARNING: Checksum for table '");
return glyph;
}
+ttf_glyph_destroy :: proc (glyph: ^TTGlyph) {
+ array_free(^glyph.contour_ends);
+ array_free(^glyph.points);
+ cfree(glyph);
+}
+
#private_file
TTGlyphFlags :: enum #flags {
On_Curve :: 0x01;
cmap.cmap0.format = TTCmapFormat.Simple;
glyphs : [..] u8;
- array_init(^glyphs, 256);
+ array_init(^glyphs, 256);
for i: 0 .. 256 do array_push(^glyphs, read_u8(^reader));
cmap.cmap0.glyph_indicies = array_to_slice(^glyphs);
cmap : TTCmap;
cmap.cmap4.format = TTCmapFormat.Segmented;
map := ^cmap.cmap4;
+ i32map_init(^map.cache);
map.seg_count = read_u16(^reader) >> ~~1;
map.search_range = read_u16(^reader);
#private_file
ttf_lookup_in_cmap4 :: proc (use ttf: ^TrueTypeFont, cmap: ^TTCmap4, charcode: u32) -> u32 {
- // TODO: Lookup in the cache
+ if i32map_has(^cmap.cache, charcode) do return i32map_get(^cmap.cache, charcode);
index := 0;
for ^seg: cmap.segments {
}
}
+ i32map_put(^cmap.cache, charcode, index);
+
return index;
}
+ttf_read_hhea_table :: proc (use ttf: ^TrueTypeFont) {
+ empty_table_hack := TTTableInfo.{};
+ hhea_table_info := i32map_get(^table_map, string_to_beu32("hhea"), empty_table_hack);
+ seek(^reader, hhea_table_info.offset);
+
+ hhea.version = read_u32(^reader);
+ hhea.ascent = read_fword(^reader);
+ hhea.descent = read_fword(^reader);
+ hhea.line_gap = read_fword(^reader);
+ hhea.advance_width_max = read_u16(^reader);
+ hhea.min_left_side_bearing = read_u16(^reader);
+ hhea.min_right_side_bearing = read_u16(^reader);
+ hhea.x_max_extent = read_fword(^reader);
+ hhea.caret_slope_rise = read_i16(^reader);
+ hhea.caret_slope_run = read_i16(^reader);
+ hhea.caret_offset = read_fword(^reader);
+ read_i16(^reader); // Reserved
+ read_i16(^reader); // Reserved
+ read_i16(^reader); // Reserved
+ read_i16(^reader); // Reserved
+ hhea.metric_data_format = read_i16(^reader);
+ hhea.num_of_long_hor_metrics = read_u16(^reader);
+}
+
+TTHorizontalMetrics :: struct {
+ advance_width : u16;
+ left_side_bearing : i16;
+}
+
+ttf_lookup_horizontal_metrics :: proc (use ttf: ^TrueTypeFont, glyph_index: u32) -> TTHorizontalMetrics {
+ empty_table_hack := TTTableInfo.{};
+ hmtx_table_info := i32map_get(^table_map, string_to_beu32("hmtx"), empty_table_hack);
+ offset := hmtx_table_info.offset;
+
+ hmtx : TTHorizontalMetrics;
+
+ nmets := cast(u32) hhea.num_of_long_hor_metrics;
+
+ if glyph_index < nmets {
+ offset += glyph_index * 4;
+ old := seek(^reader, offset);
+ defer seek(^reader, old);
+
+ hmtx.advance_width = read_u16(^reader);
+ hmtx.left_side_bearing = read_i16(^reader);
+
+ } else {
+ old := seek(^reader, offset + (nmets - 1) * 4);
+ defer seek(^reader, old);
+
+ hmtx.advance_width = read_u16(^reader);
+ seek(^reader, offset + nmets * 4 + 2 * (glyph_index - nmets));
+ hmtx.left_side_bearing = read_i16(^reader);
+ }
+
+ return hmtx;
+}
+
+
+// Renders a grayscale image
+// 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;
+
+ scale := cast(f32) height / ~~cast(i32) units_per_em;
+
+ state := 0;
+ count := 0;
+ contour_start := 0;
+
+ curr_x := 0;
+ curr_y := 0;
+
+ poly_points : [..] V2i;
+ array_init(^poly_points, 16);
+ defer array_free(^poly_points);
+
+ for i: 0 .. glyph.points.count {
+ p := glyph.points[i];
+
+
+ switch state {
+ case 0 {
+ // curr_x = cast(i32) p.x;
+ // curr_y = cast(i32) p.y;
+
+ array_push(^poly_points, V2i.{ ~~p.x, ~~p.y });
+ state = 1;
+ }
+
+ case 1 do if p.on_curve {
+ // draw_line(data, width, height, scale,
+ // curr_x, curr_y,
+ // ~~p.x, ~~p.y);
+
+ // curr_x = cast(i32) p.x;
+ // curr_y = cast(i32) p.y;
+ array_push(^poly_points, V2i.{ ~~p.x, ~~p.y });
+
+ } else {
+ state = 2;
+ }
+
+ case #default {
+ prev := glyph.points[i - 1];
+ if p.on_curve {
+ // draw_quadratic_line(data, width, height, scale,
+ // curr_x, curr_y,
+ // ~~prev.x, ~~prev.y,
+ // ~~p.x, ~~p.y);
+
+ // curr_x = cast(i32) p.x;
+ // curr_y = cast(i32) p.y;
+ // array_push(^poly_points, V2i.{ ~~prev.x, ~~prev.y });
+ array_push(^poly_points, V2i.{ ~~p.x, ~~p.y });
+ state = 1;
+
+ } else {
+ //draw_quadratic_line(data, width, height, scale,
+ // curr_x, curr_y,
+ // ~~prev.x, ~~prev.y,
+ // ~~((prev.x + p.x) / ~~2), ~~((prev.y + p.y) / ~~2));
+
+ //curr_x = cast(i32) ((prev.x + p.x) / ~~2);
+ //curr_y = cast(i32) ((prev.y + p.y) / ~~2);
+ array_push(^poly_points, V2i.{ ~~prev.x, ~~prev.y });
+ array_push(^poly_points, V2i.{ ~~((prev.x + p.x) / ~~2), ~~((prev.y + p.y) / ~~2) });
+ }
+ }
+ }
+
+ if i == ~~glyph.contour_ends[count] {
+ prev := p;
+ p = glyph.points[contour_start];
+
+ if p.on_curve {
+ // draw_quadratic_line(data, width, height, scale,
+ // curr_x, curr_y,
+ // ~~prev.x, ~~prev.y,
+ // ~~p.x, ~~p.y);
+
+ // curr_x = cast(i32) p.x;
+ // curr_y = cast(i32) p.y;
+ array_push(^poly_points, V2i.{ ~~prev.x, ~~prev.y });
+
+ } else {
+ // draw_quadratic_line(data, width, height, scale,
+ // curr_x, curr_y,
+ // ~~prev.x, ~~prev.y,
+ // ~~((prev.x + p.x) / ~~2), ~~((prev.y + p.y) / ~~2));
+
+ // curr_x = cast(i32) ((prev.x + p.x) / ~~2);
+ // curr_y = cast(i32) ((prev.y + p.y) / ~~2);
+ array_push(^poly_points, V2i.{ ~~prev.x, ~~prev.y });
+ array_push(^poly_points, V2i.{ ~~((prev.x + p.x) / ~~2), ~~((prev.y + p.y) / ~~2) });
+ }
+
+ contour_start = i + 1;
+ count += 1;
+ state = 0;
+
+
+ // col := cast(u8) 255;
+ // if v2_orientation(poly_points[0], poly_points[1], poly_points[2]) < 0 do col = cast(u8) 0;
+
+ for p: poly_points do print_vec(p);
+ for y: 0 .. height do for x: 0 .. width {
+ if is_inside_polygon(array_to_slice(^poly_points), V2i.{ ~~(~~x / scale), ~~(~~y / scale) }) {
+ curr := data[x + (height - 1 - y) * width];
+ if curr == ~~0 do data[x + (height - 1 - y) * width] = cast(u8) 255;
+ else do data[x + (height - 1 - y) * width] = cast(u8) 0;
+ }
+ }
+
+ array_clear(^poly_points);
+ }
+ }
+}
+
+#private_file
+draw_line :: proc (data: ^u8, width: u32, height: u32, scale: f32, x0: u32, y0: u32, x1: u32, y1: u32) {
+ start := V2i.{ x0, y0 };
+ end := V2i.{ x1, y1 };
+ dist := sqrt_f32(~~v2_square_dist(start, end));
+
+ for t: 0 .. ~~dist {
+ p := v2_lerp(~~t / dist, start, end);
+ px := cast(i32) (~~p.x * scale);
+ py := cast(i32) (~~p.y * scale);
+ if px >= 0 && py >= 0 && px < width && py < height {
+ data[px + (height - 1 - py) * width] = cast(u8) 255;
+ }
+ }
+}
+
+#private_file
+draw_quadratic_line :: proc (data: ^u8, width: u32, height: u32, scale: f32, x0: u32, y0: u32, x1: u32, y1: u32, x2: u32, y2: u32) {
+ // draw_line(data, width, height, scale, x0, y0, x1, y1);
+ // draw_line(data, width, height, scale, x1, y1, x2, y2);
+
+ points : [3] V2f;
+ points[0] = V2f.{ ~~x0, ~~y0 };
+ points[1] = V2f.{ ~~x1, ~~y1 };
+ points[2] = V2f.{ ~~x2, ~~y2 };
+
+ for t: 0 .. 200 {
+ p := bezier_curve(~~t / 200.0f, points[0 .. 3]);
+
+ px := cast(i32) (~~p.x * scale);
+ py := cast(i32) (~~p.y * scale);
+ if px >= 0 && py >= 0 && px < width && py < height {
+ data[px + (height - 1 - py) * width] = cast(u8) 255;
+ }
+ }
+}
+
#private_file
ttf_calc_table_checksum :: proc (reader: ^BinaryReader, offset: u32, length: u32) -> u32 {
old := seek(reader, offset);
Color3 :: struct { r: u8; g: u8; b: u8; }
+#private_file current_tex_id := 0;
+
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
// if it is stored in the data section.
- data : [] Color3;
+ data : [] u8;
width : i32;
height : i32;
+ data_mode : TextureDataMode;
+
texture_id : gl.GLTexture;
}
+TextureDataMode :: enum {
+ RGB :: 0x01;
+ BRIGHTNESS :: 0x02;
+}
+
// NOTE: This assumes that the data is raw u8 RGB packed color data.
-texture_create :: proc (texdata: [] Color3, width: i32, height: i32) -> Texture {
+texture_create :: proc (texdata: [] u8, width: i32, height: i32, data_mode := TextureDataMode.RGB) -> Texture {
tex : Texture;
tex.data = texdata;
tex.width = width;
tex.height = height;
+ tex.data_mode = data_mode;
tex.texture_id = -1;
- if width * height != tex.data.count {
- println("Warning: Texture width and height does not match the size of data given.");
- }
-
return tex;
}
texture_prepare :: proc (use tex: ^Texture) {
if texture_id != -1 do return;
- texdata := (cast(^u8) data.data)[0 .. data.count * 3];
+ format := gl.RGB;
+ if data_mode == TextureDataMode.BRIGHTNESS do format = gl.LUMINANCE;
texture_id = gl.createTexture();
- gl.activeTexture(gl.TEXTURE0);
+ // gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_id);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, width, height, 0, gl.RGB, gl.UNSIGNED_BYTE, texdata);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
- gl.bindTexture(gl.TEXTURE_2D, -1);
+ gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, gl.UNSIGNED_BYTE, data);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ // gl.bindTexture(gl.TEXTURE_2D, -1);
}
texture_use :: proc (use tex: ^Texture) {
pos = Vec2.{ x, y },
size = Vec2.{ w, h },
color = color,
+
+ tex_size = Vec2.{ 1.0f, 1.0f },
});
curr_quad_idx += 1;
quad_rebuffer_data(quad_renderer);
quad_renderer_draw(quad_renderer);
+ 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
if input.key_down(^input_state, Key.ArrowRight) do player.x += player_speed;
}
-draw :: proc () {
- defer render_context_flush(^renderer);
+glyph_size :: 128
+glyph_data : [glyph_size * glyph_size] u8
+draw :: proc () {
gl.clearColor(0.2f, 0.2f, 0.2f, 1.0f);
+ // gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
gl.clear(gl.COLOR_BUFFER_BIT);
- renderer.color = Color4f32.{ 1f, 0f, 0f, 1f };
+ // renderer.color = Color4f32.{ 1f, 0f, 0f, 1f };
- 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 };
+ // 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 };
- for i: 0 .. 200 {
- pos := bezier_curve(~~i / 200.0f, points[0 .. 6]);
- draw_rect(^renderer, pos.x, pos.y, 16f, 16f);
- }
+ // for i: 0 .. 200 {
+ // pos := bezier_curve(~~i / 200.0f, points[0 .. 6]);
+ // draw_rect(^renderer, pos.x, pos.y, 16f, 16f);
+ // }
- glyph : ^TTGlyph = null;
- glyph_index := ttf_lookup_glyph_by_char(^ttf, ~~ #char "A");
- glyph = ttf_read_glyph(^ttf, glyph_index);
- defer cfree(glyph);
- defer array_free(^glyph.points);
- defer array_free(^glyph.contour_ends);
-
- 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);
- }
+ // 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);
+ // }
+ // }
+
+ // mets := ttf_lookup_horizontal_metrics(^ttf, glyph_index);
+ // println(cast(u32) mets.advance_width);
- draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 10f, 10f);
+ // 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);
+ // }
+
+
+ texture_use(^smile);
+ draw_rect(^renderer, ~~input_state.mouse.x, ~~input_state.mouse.y, 100f, 100f);
draw_rect(^renderer, player.pos.x, player.pos.y, 100f, 100f);
+ render_context_flush(^renderer);
+
+ texture_use(^font_tex);
+ draw_rect(^renderer, 100f, 100f, 64f, 64f);
+ render_context_flush(^renderer);
}
// This procedure is called asynchronously from JS every frame.
render_context_init(^renderer, null);
- // CLEANUP: Maybe there should be a way to cast between slices?
- // Automatically multiply / divide the count by the ratio of the type sizes?
- // This could be very buggy
- raw_image_data := #file_contents "res/smile.data";
- image_data := (cast(^Color3) raw_image_data.data)[0 .. raw_image_data.count / 3];
-
- smile := texture_create(image_data, 32, 32);
+ image_data := #file_contents "res/smile.data";
+ smile = texture_create(image_data, 32, 32);
texture_prepare(^smile);
- texture_use(^smile);
event.init();
input.init(^input_state);
- ttf_data := #file_contents "res/Inconsolata-Regular.ttf";
+ ttf_data := #file_contents "res/Hack-Regular.ttf";
ttf = ttf_create(ttf_data);
- ttf_read_head_table(^ttf);
- ttf_read_cmap_table(^ttf);
-
- // for i: 0 .. ttf_glyph_count(^ttf) {
- // glyph := ttf_read_glyph(^ttf, i);
- // if glyph == null do continue;
- // defer cfree(glyph);
-
- // // println(glyph.points.count);
- // // for p: glyph.points {
- // // print(p.on_curve);
- // // print(" ");
- // // print(cast(i32) p.x);
- // // print(", ");
- // // print(cast(i32) p.y);
- // // print("\n");
- // // }
- // }
+
+ glyph : ^TTGlyph = null;
+ glyph_index := ttf_lookup_glyph_by_char(^ttf, ~~ #char "%");
+ glyph = ttf_read_glyph(^ttf, glyph_index);
+ if glyph == null do return;
+ defer ttf_glyph_destroy(glyph);
+
+ 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();
}
package vecmath
+use package core
+
// BUG: Default values do not work on polymorphic structs.
V2 :: struct ($T) { x: T; y: T; }
ret.y = a.y * scalar;
return ret;
}
+
+v2_lerp :: proc (t: f32, start: V2($T), end: V2(T)) -> V2(T) {
+ ret : V2(T);
+ ret.x = ~~(t * ~~(end.x - start.x)) + start.x;
+ ret.y = ~~(t * ~~(end.y - start.y)) + start.y;
+ return ret;
+}
+
+v2_square_dist :: proc (a: V2($T), b: V2(T)) -> T {
+ return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
+}
+
+// -1 for counter-clockwise
+// 0 for colinear
+// 1 for clockwise
+v2_orientation :: proc (a: V2($T), b: V2(T), c: V2(T)) -> i32 {
+ val := (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y);
+ if val == ~~0 do return 0;
+ if val > ~~0 do return 1;
+ return -1;
+}
+
+// assumes a b and c are colinear
+v2_on_segment :: proc (a: V2($T), b: V2(T), c: V2(T)) -> bool {
+ return b.x <= max_poly(a.x, c.x)
+ && b.x >= min_poly(a.x, c.x)
+ && b.y <= max_poly(a.y, c.y)
+ && b.y >= min_poly(a.y, c.y);
+}
+
+
+lines_intersect :: proc (p1: V2($T), q1: V2(T), p2: V2(T), q2: V2(T)) -> bool {
+ o1 := v2_orientation(p1, q1, p2);
+ o2 := v2_orientation(p1, q1, q2);
+ o3 := v2_orientation(p2, q2, p1);
+ o4 := v2_orientation(p2, q2, q1);
+
+ if o1 != o2 && o3 != o4 do return true;
+
+ if o1 == 0 && v2_on_segment(p1, p2, q1) do return true;
+ if o2 == 0 && v2_on_segment(p1, q2, q1) do return true;
+ if o3 == 0 && v2_on_segment(p2, p1, q2) do return true;
+ if o4 == 0 && v2_on_segment(p2, q1, q2) do return true;
+
+ return false;
+}
+
+is_inside_polygon :: proc (polygon: [] V2($T), p: V2(T)) -> bool {
+ if polygon.count < 3 do return false;
+
+ extreme : V2(T);
+ extreme.x = cast(T) 1000000; // Needs be infinity... close enough
+ extreme.y = p.y;
+
+ count := 0;
+ for i: 0 .. polygon.count {
+ next := (i + 1) % polygon.count;
+
+ if lines_intersect(polygon[i], polygon[next], p, extreme) {
+ if v2_orientation(polygon[i], p, polygon[next]) == 0 {
+ return v2_on_segment(polygon[i], p, polygon[next]);
+ }
+
+ count += 1;
+ }
+ }
+
+ return (count % 2) == 1;
+}
+
+
+
+print_vec :: proc (v: V2($T)) {
+ print("V2(");
+ print(v.x);
+ print(", ");
+ print(v.y);
+ println(")");
+}
TTCmapFormat src/font.onyx /^TTCmapFormat :: enum (u16) {$/
TTGlyph src/font.onyx /^TTGlyph :: struct {$/
TTGlyphPoint src/font.onyx /^TTGlyphPoint :: struct {$/
+TTHorizontalMetrics src/font.onyx /^TTHorizontalMetrics :: struct {$/
TTIndexToLocFormat src/font.onyx /^TTIndexToLocFormat :: enum (i16) {$/
TTSegment src/font.onyx /^TTSegment :: struct {$/
TTTableInfo src/font.onyx /^TTTableInfo :: struct {$/
Texture src/gfx/texture.onyx /^Texture :: struct {$/
+TextureDataMode src/gfx/texture.onyx /^TextureDataMode :: enum {$/
TrueTypeFont src/font.onyx /^TrueTypeFont :: struct {$/
UNIFORM_ARRAY_STRIDE /usr/share/onyx/core/js/webgl.onyx /^UNIFORM_ARRAY_STRIDE :: 0x8A3C$/
UNIFORM_BLOCK_ACTIVE_UNIFORMS /usr/share/onyx/core/js/webgl.onyx /^UNIFORM_BLOCK_ACTIVE_UNIFORMS :: 0x8A42$/
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" ---$/
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 :: 128$/
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;$/
invalidateFramebuffer /usr/share/onyx/core/js/webgl.onyx /^invalidateFramebuffer :: proc (target: GLenum, attachments: string) #foreign "gl" "invalidateFramebuffer" ---$/
invalidateSubFramebuffer /usr/share/onyx/core/js/webgl.onyx /^invalidateSubFramebuffer :: proc (target: GLenum, attachments: string, x: GLint, y: GLint, width: GLsizei, height: GLsizei) #foreign "gl" "invalidateSubFramebuffer" ---$/
isEnabled /usr/share/onyx/core/js/webgl.onyx /^isEnabled :: proc (cap: GLenum) -> GLboolean #foreign "gl" "isEnabled" ---$/
+is_inside_polygon src/vecmath.onyx /^is_inside_polygon :: proc (polygon: [] V2($T), p: V2(T)) -> bool {$/
key_down src/input.onyx /^key_down :: proc (use state: ^InputState, key: Key) -> bool {$/
key_just_down src/input.onyx /^key_just_down :: proc (use state: ^InputState, key: Key) -> bool {$/
key_up src/input.onyx /^key_up :: proc (use state: ^InputState, key: Key) -> bool {$/
lineWidth /usr/share/onyx/core/js/webgl.onyx /^lineWidth :: proc (width: GLfloat) #foreign "gl" "lineWidth" ---$/
+lines_intersect src/vecmath.onyx /^lines_intersect :: proc (p1: V2($T), q1: V2(T), p2: V2(T), q2: V2(T)) -> bool {$/
linkProgram /usr/share/onyx/core/js/webgl.onyx /^linkProgram :: proc (program: GLProgram) #foreign "gl" "linkProgram" ---$/
link_program src/utils/gl.onyx /^link_program :: proc (vertex_shader: gl.GLShader, frag_shader: gl.GLShader) -> gl.GLProgram {$/
main src/main.onyx /^main :: proc (args: [] cstring) {$/
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)) {$/
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) {$/
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 {$/
stdio_init /usr/share/onyx/core/stdio.onyx /^stdio_init :: proc () {$/
stencilFunc /usr/share/onyx/core/js/webgl.onyx /^stencilFunc :: proc (func: GLenum, ref: GLint, mask: GLuint) #foreign "gl" "stencilFunc" ---$/
stencilFuncSeparate /usr/share/onyx/core/js/webgl.onyx /^stencilFuncSeparate :: proc (face: GLenum, func: GLenum, ref: GLint, mask: GLuint) #foreign "gl" "stencilFuncSeparate" ---$/
texParameterf /usr/share/onyx/core/js/webgl.onyx /^texParameterf :: proc (target: GLenum, pname: GLenum, param: GLfloat) #foreign "gl" "texParameterf" ---$/
texParameteri /usr/share/onyx/core/js/webgl.onyx /^texParameteri :: proc (target: GLenum, pname: GLenum, param: GLint) #foreign "gl" "texParameteri" ---$/
texSubImage2D /usr/share/onyx/core/js/webgl.onyx /^texSubImage2D :: proc (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: string) #foreign "gl" "texSubImage2D" ---$/
-texture_create src/gfx/texture.onyx /^texture_create :: proc (texdata: [] Color3, width: i32, height: i32) -> Texture {$/
+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) {$/
trunc_f32 /usr/share/onyx/core/intrinsics.onyx /^trunc_f32 :: proc (val: f32) -> f32 #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) {$/
ttf_lookup_glyph_by_char src/font.onyx /^ttf_lookup_glyph_by_char :: proc (use ttf: ^TrueTypeFont, charcode: u32) -> u32 {$/
ttf_lookup_glyph_offset src/font.onyx /^ttf_lookup_glyph_offset :: proc (use ttf: ^TrueTypeFont, glyph_index: i32) -> u32 {$/
+ttf_lookup_horizontal_metrics src/font.onyx /^ttf_lookup_horizontal_metrics :: proc (use ttf: ^TrueTypeFont, glyph_index: u32) -> TTHorizontalMetrics {$/
ttf_read_cmap src/font.onyx /^ttf_read_cmap :: proc (use ttf: ^TrueTypeFont, offset: u32) {$/
ttf_read_cmap0 src/font.onyx /^ttf_read_cmap0 :: proc (use ttf: ^TrueTypeFont) {$/
ttf_read_cmap4 src/font.onyx /^ttf_read_cmap4 :: proc (use ttf: ^TrueTypeFont) {$/
ttf_read_cmap_table src/font.onyx /^ttf_read_cmap_table :: proc (use ttf: ^TrueTypeFont) {$/
ttf_read_glyph src/font.onyx /^ttf_read_glyph :: proc (use ttf: ^TrueTypeFont, glyph_index: i32) -> ^TTGlyph {$/
ttf_read_head_table src/font.onyx /^ttf_read_head_table :: proc (use ttf: ^TrueTypeFont) {$/
+ttf_read_hhea_table src/font.onyx /^ttf_read_hhea_table :: proc (use ttf: ^TrueTypeFont) {$/
ttf_read_offset_table src/font.onyx /^ttf_read_offset_table :: proc (use ttf: ^TrueTypeFont) {$/
+ttf_render_glyph src/font.onyx /^ttf_render_glyph :: proc (use ttf: ^TrueTypeFont, glyph: ^TTGlyph, data: ^u8, width: u32, height: u32) {$/
uniform1f /usr/share/onyx/core/js/webgl.onyx /^uniform1f :: proc (loc: GLUniformLocation, x: GLfloat) #foreign "gl" "uniform1f" ---$/
uniform1i /usr/share/onyx/core/js/webgl.onyx /^uniform1i :: proc (loc: GLUniformLocation, x: GLint) #foreign "gl" "uniform1i" ---$/
uniform2f /usr/share/onyx/core/js/webgl.onyx /^uniform2f :: proc (loc: GLUniformLocation, x: GLfloat, y: GLfloat) #foreign "gl" "uniform2f" ---$/
update src/main.onyx /^update :: proc () {$/
useProgram /usr/share/onyx/core/js/webgl.onyx /^useProgram :: proc (program: GLProgram) #foreign "gl" "useProgram" ---$/
v2_add src/vecmath.onyx /^v2_add :: proc (a: V2($T), b: V2(T)) -> V2(T) {$/
+v2_lerp src/vecmath.onyx /^v2_lerp :: proc (t: f32, start: V2($T), end: V2(T)) -> V2(T) {$/
v2_mul src/vecmath.onyx /^v2_mul :: proc (a: V2($T), scalar: T) -> V2(T) {$/
+v2_on_segment src/vecmath.onyx /^v2_on_segment :: proc (a: V2($T), b: V2(T), c: V2(T)) -> bool {$/
+v2_orientation src/vecmath.onyx /^v2_orientation :: proc (a: V2($T), b: V2(T), c: V2(T)) -> i32 {$/
+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" ---$/
vertexAttrib1f /usr/share/onyx/core/js/webgl.onyx /^vertexAttrib1f :: proc (idx: GLuint, x: GLfloat) #foreign "gl" "vertexAttrib1f" ---$/