+++ /dev/null
-# Modules
-
-These are the modules that current ship with the compiler, but are not
-part of the "core" libraries. In the far-future, these modules will be
-obtained from a dedicated package manager shipped with the compiler,
-and will be downloaded from a central repository. It seems too ambious
-to do that work right now, so I am holding off on starting that process
-until I have other people producing code and libraries for Onyx.
+++ /dev/null
-package bmfont
-
-use package core
-#local json :: package json
-
-load_bmfont :: (fnt_data: [] u8) -> BMFont {
- bmf := create_bmfont();
-
- parse_bmfont(fnt_data, ^bmf);
-
- for ^it: bmf.glyphs.entries {
- it.value.tex_x = ~~ it.value.x / cast(f32) bmf.common.scale_width;
- it.value.tex_y = ~~ it.value.y / cast(f32) bmf.common.scale_height;
- it.value.tex_w = ~~ it.value.w / cast(f32) bmf.common.scale_width;
- it.value.tex_h = ~~ it.value.h / cast(f32) bmf.common.scale_height;
- }
-
- return bmf;
-}
-
-load_bmfont_from_json :: (fnt_data: [] u8) -> BMFont {
- bmf := create_bmfont();
-
- j := json.decode(fnt_data);
- defer json.free(j);
-
- extract_bmfont_from_json(^bmf, j.root);
-}
-
-#local
-create_bmfont :: () -> BMFont {
- bmf: BMFont;
- memory.set(^bmf, 0, sizeof BMFont);
-
- map.init(^bmf.pages);
- map.init(^bmf.glyphs);
-
- return bmf;
-}
-
-#local
-parse_bmfont :: (fnt_data: [] u8, font: ^BMFont) {
- R :: package core.string.reader
-
- parser_arena := alloc.arena.make(context.allocator, arena_size=4 * 1024);
- parser_allocator := alloc.arena.make_allocator(^parser_arena);
- defer alloc.arena.free(^parser_arena);
-
- reader := R.make(fnt_data);
-
- while !R.empty(^reader) {
- line := R.read_line(^reader);
- pieces := string.split(line, #char " ", allocator=parser_allocator);
-
- tag := pieces[0];
- pieces = pieces.data[1 .. pieces.count];
-
- if tag == "page" {
- id := -1;
- filename := null_str;
-
- for ^piece: pieces {
- key := string.read_until(piece, #char "=");
- string.advance(piece, 1);
-
- if key == "id" do id = ~~ conv.str_to_i64(*piece);
- if key == "file" do filename = string.alloc_copy(*piece);
- }
-
- map.put(^font.pages, id, filename);
- continue;
- }
-
- if tag == "char" {
- char: BMFont_Glyph;
-
- for ^piece: pieces {
- key := string.read_until(piece, #char "=");
- string.advance(piece, 1);
-
- if key == "id" do char.id = ~~ conv.str_to_i64(*piece);
- elseif key == "x" do char.x = ~~ conv.str_to_i64(*piece);
- elseif key == "y" do char.y = ~~ conv.str_to_i64(*piece);
- elseif key == "width" do char.w = ~~ conv.str_to_i64(*piece);
- elseif key == "height" do char.h = ~~ conv.str_to_i64(*piece);
- elseif key == "xoffset" do char.xoffset = ~~ conv.str_to_i64(*piece);
- elseif key == "yoffset" do char.yoffset = ~~ conv.str_to_i64(*piece);
- elseif key == "xadvance" do char.xadvance = ~~ conv.str_to_i64(*piece);
- elseif key == "page" do char.page = ~~ conv.str_to_i64(*piece);
- elseif key == "chhl" do char.channel = ~~ conv.str_to_i64(*piece);
- }
-
- map.put(^font.glyphs, char.id, char);
- continue;
- }
-
- @Note // this for loop is very destructive of the data that is here, but
- // it is assumed that after a line is processed, the data will not be needed
- // again. To be clear, this means that it destroys the pieces from the split,
- // not the data in fnt_data.
- for ^piece: pieces {
- key := string.read_until(piece, #char "=");
- string.advance(piece, 1);
-
- if tag == "info" do parse_info_tag(font, parser_allocator, key, *piece);
- if tag == "common" do parse_common_tag(font, parser_allocator, key, *piece);
- }
- }
-
- parse_info_tag :: (font: ^BMFont, parser_allocator: Allocator, key: str, value: str) {
- info := ^font.info;
-
- if key == "face" do info.face_name = string.alloc_copy(value);
- elseif key == "size" do info.size = ~~ conv.str_to_i64(value);
- elseif key == "bold" do info.bold = value == "1";
- elseif key == "italic" do info.italic = value == "1";
- elseif key == "charset" do info.charset = string.alloc_copy(value);
- elseif key == "unicode" do info.unicode = value == "1";
- elseif key == "stretchH" do info.stretchH = ~~ conv.str_to_i64(value);
- elseif key == "smooth" do info.smooth = value == "1";
- elseif key == "aa" do info.supersampling = ~~ conv.str_to_i64(value);
-
- elseif key == "padding" {
- values := string.split(value, #char ",", allocator=parser_allocator);
- info.padding.top = ~~ conv.str_to_i64(values[0]);
- info.padding.right = ~~ conv.str_to_i64(values[1]);
- info.padding.bottom = ~~ conv.str_to_i64(values[2]);
- info.padding.left = ~~ conv.str_to_i64(values[3]);
- }
-
- elseif key == "spacing" {
- values := string.split(value, #char ",", allocator=parser_allocator);
- info.spacing.horizontal = ~~ conv.str_to_i64(values[0]);
- info.spacing.vertical = ~~ conv.str_to_i64(values[1]);
- }
- }
-
- parse_common_tag :: (font: ^BMFont, parser_allocator: Allocator, key: str, value: str) {
- common := ^font.common;
-
- if key == "lineHeight" do common.line_height = ~~ conv.str_to_i64(value);
- elseif key == "base" do common.baseline = ~~ conv.str_to_i64(value);
- elseif key == "scaleW" do common.scale_width = ~~ conv.str_to_i64(value);
- elseif key == "scaleH" do common.scale_height = ~~ conv.str_to_i64(value);
- elseif key == "pages" do common.page_count = ~~ conv.str_to_i64(value);
- elseif key == "packed" do common.packed = value == "1";
- elseif key == "alphaChnl" do common.alpha_channel = ~~ conv.str_to_i64(value);
- elseif key == "redChnl" do common.red_channel = ~~ conv.str_to_i64(value);
- elseif key == "greenChnl" do common.alpha_channel = ~~ conv.str_to_i64(value);
- elseif key == "blueChnl" do common.blue_channel = ~~ conv.str_to_i64(value);
- }
-}
-
-#local
-extract_bmfont_from_json :: (font: ^BMFont, root: ^json.Value) {
- font_info := root["info"];
- font.info.face_name = font_info["face"]->as_str();
- font.info.size = ~~font_info["size"]->as_int();
- font.info.bold = font_info["bold"]->as_int() != 0;
- font.info.italic = font_info["italic"]->as_int() != 0;
- font.info.unicode = font_info["unicode"]->as_int() != 0;
- font.info.stretchH = ~~font_info["stretchH"]->as_int();
- font.info.smooth = font_info["smooth"]->as_int() != 0;
- font.info.supersampling = ~~font_info["aa"]->as_int();
-
- font_padding := font_info["padding"];
- font.info.padding.top = ~~font_padding[0]->as_int();
- font.info.padding.right = ~~font_padding[1]->as_int();
- font.info.padding.bottom = ~~font_padding[2]->as_int();
- font.info.padding.left = ~~font_padding[3]->as_int();
-
- font_spacing := font_info["spacing"];
- font.info.spacing.horizontal = ~~font_spacing[0]->as_int();
- font.info.spacing.vertical = ~~font_spacing[1]->as_int();
-
- font_common := root["common"];
- font.common.line_height = ~~font_common["lineHeight"]->as_int();
- font.common.baseline = ~~font_common["base"]->as_int();
- font.common.scale_width = ~~font_common["scaleW"]->as_int();
- font.common.scale_height = ~~font_common["scaleH"]->as_int();
- font.common.page_count = ~~font_common["pages"]->as_int();
- font.common.packed = font_common["packed"]->as_int() != 0;
- font.common.alpha_channel = ~~font_common["alphaChnl"]->as_int();
- font.common.red_channel = ~~font_common["redChnl"]->as_int();
- font.common.green_channel = ~~font_common["greenChnl"]->as_int();
- font.common.blue_channel = ~~font_common["blueChnl"]->as_int();
-
- i := 0;
- for page: root["pages"]->as_array() {
- defer i += 1;
-
- font.pages[i] = page->as_str();
- }
-
- for ch: root["chars"]->as_array() {
- id := cast(i32) ch["id"]->as_int();
- font.glyphs[id] = .{
- id = id,
-
- x = ~~ch["x"]->as_int(),
- y = ~~ch["y"]->as_int(),
- w = ~~ch["width"]->as_int(),
- h = ~~ch["height"]->as_int(),
-
- xoffset = ~~ch["xoffset"]->as_int(),
- yoffset = ~~ch["yoffset"]->as_int(),
- xadvance = ~~ch["xadvance"]->as_int(),
-
- page = ~~ch["page"]->as_int(),
- channel = ~~ch["chnl"]->as_int(),
- };
- }
-}
+++ /dev/null
-/*
-TODO:
- - Add rendering SDF fonts generated using msdf-bmfont-xml from npm.
-
-
-
-A simple package for reading BMFont files. A good source of documentation can be found here: https://www.angelcode.com/products/bmfont/
-
-This pacakge is responible for:
- - Reading *.fnt files to parse their contents into glyphs
-
-*/
-
-
-package bmfont
-
-#load "./types"
-#load "./bmfont_loader"
-#load "./utils"
-#load "./position"
-
+++ /dev/null
-package bmfont
-
-#local {
- math :: package core.math
-
- renderable_glyph: Renderable_Glyph;
- Renderable_Glyph :: struct {
- pos_x, pos_y : f32;
- pos_w, pos_h : f32;
-
- tex_x, tex_y : f32;
- tex_w, tex_h : f32;
-
- x_advance : f32;
- }
-
- rendering_context: Rendering_Context;
- Rendering_Context :: struct {
- font : ^BMFont;
- size : f32;
-
- x, y : f32;
-
- original_x : f32;
- baseline : f32;
- line_height : f32;
-
- text : str;
- text_position : u32;
- }
-}
-
-@FontSizing // Currently, `size` is just a multipler for the baked font size. This should be changed to be height in pixels, or 'em's.
-@Rename
-get_character_positions :: (font: ^BMFont, size: f32, text: str, x: f32, y: f32) -> Iterator(^Renderable_Glyph) {
- rendering_context.font = font;
- rendering_context.size = size;
-
- rendering_context.x, rendering_context.y = x, y;
-
- rendering_context.original_x = x;
- rendering_context.baseline = ~~font.common.baseline * size;
- rendering_context.line_height = ~~font.common.line_height * size;
-
- rendering_context.text = text;
- rendering_context.text_position = 0;
-
- next :: (data: rawptr) -> (^Renderable_Glyph, bool) {
- rc := cast(^Rendering_Context) data;
- char: u8;
-
- while true {
- if rc.text_position >= rc.text.count {
- return null, false;
- }
-
- char = rc.text[rc.text_position];
- defer rc.text_position += 1;
-
- if char == #char "\n" {
- rc.y += rc.line_height;
- rc.x = rc.original_x;
- continue;
- }
-
- if char == #char "\t" {
- rc.x += ~~(rc.font->get_glyph(#char " ")).xadvance * 4.0f;
- continue;
- }
-
- glyph := rc.font->get_glyph(char);
-
- if glyph == null {
- continue;
- }
-
- renderable_glyph.pos_x = math.floor(rc.x + ~~glyph.xoffset * rc.size + .5);
- renderable_glyph.pos_y = math.floor(rc.y + ~~glyph.yoffset * rc.size + .5) - math.floor(rc.baseline);
- renderable_glyph.pos_w = math.floor(~~glyph.w * rc.size + .5);
- renderable_glyph.pos_h = math.floor(~~glyph.h * rc.size + .5);
-
- renderable_glyph.tex_x = glyph.tex_x;
- renderable_glyph.tex_y = glyph.tex_y;
- renderable_glyph.tex_w = glyph.tex_w;
- renderable_glyph.tex_h = glyph.tex_h;
-
- renderable_glyph.x_advance = math.floor(~~glyph.xadvance * rc.size + 0.5);
- rc.x += math.floor(~~glyph.xadvance * rc.size + 0.5);
-
- return ^renderable_glyph, true;
- }
- }
-
- close :: (data: rawptr) {
- rc := cast(^Rendering_Context) data;
- rc.text = null_str;
- }
-
- return .{
- next = next,
- close = close,
- data = ^rendering_context,
- };
-}
+++ /dev/null
-package bmfont
-
-use package core
-
-
-BMFont :: struct {
- info : BMFont_Info;
- common : BMFont_Common;
-
- pages : Map(i32, str);
- glyphs : Map(i32, BMFont_Glyph);
-
- get_glyph :: (use bmfont: ^BMFont, char: u8) => ^glyphs[~~char];
-}
-
-BMFont_Info :: struct {
- face_name : str;
- size : u32;
- bold : bool;
- italic : bool;
- charset : str;
- unicode : bool;
- stretchH : u32;
- smooth : bool;
- supersampling : u32;
-
- padding: struct {
- top, right, bottom, left: i32;
- };
-
- spacing: struct {
- horizontal, vertical: i32;
- };
-
- outline: u32;
-}
-
-BMFont_Common :: struct {
-
- @Cleanup // I made a lot of these fields 32-bits in size, even though most of them could be probably be 16-bit if not 8-bit.
- line_height : i32;
- baseline : i32; // From absolute top of the line to the base of the characaters
- scale_width : u32;
- scale_height : u32;
- page_count : u32;
- packed : bool;
-
- alpha_channel : Channel;
- red_channel : Channel;
- green_channel : Channel;
- blue_channel : Channel;
-
- Channel :: enum {
- Glyph :: 0x00;
- Outline :: 0x01;
- Glyph_And_Outline :: 0x02;
- Zero :: 0x03;
- One :: 0x04;
- }
-}
-
-BMFont_Glyph :: struct {
- id : i32;
- x, y : u32;
- w, h : u32;
-
- xoffset, yoffset : i32;
- xadvance : i32;
-
- page : u8;
- channel : u8;
-
- tex_x: f32 = 0;
- tex_y: f32 = 0;
- tex_w: f32 = 0;
- tex_h: f32 = 0;
-}
+++ /dev/null
-package bmfont
-
-#local math :: package core.math
-
-get_width :: (use font: ^BMFont, text: str, size: f32) -> f32 {
- max_x := 0.0f;
- x := 0.0f;
-
- for char: text {
- if char == #char "\n" {
- max_x = math.max(max_x, x);
- x = 0.0f;
- continue;
- }
-
- glyph := font->get_glyph(char);
-
- if glyph == null {
- glyph = font->get_glyph(0);
- }
-
- x += ~~ glyph.xadvance * size;
- }
-
- return math.max(max_x, x);
-}
-
-get_height :: (use font: ^BMFont, text: str, size: f32) -> f32 {
- line_count := 0;
-
- for char: text {
- if char == #char "\n" {
- line_count += 1;
- }
- }
-
- return ~~(line_count + 1) * size * ~~font.common.line_height;
-
- // Old way that was wrong
- #if false {
- max_y := 0.0f;
- y := 0.0f;
-
- for char: text {
- if char == #char "\n" {
- y += max_y;
- max_y = 0;
- continue;
- }
-
- glyph := font->get_glyph(char);
-
- if glyph == null {
- glyph = font->get_glyph(0);
- }
-
- max_y = math.max(max_y, ~~glyph.h * size);
- }
-
- return y + max_y;
- }
-}
+++ /dev/null
-package immediate_mode
-
-use package core
-
-// A render target that can be used instead of the default
-Canvas :: struct {
- color_texture : Texture;
- depth_stencil_buffer : gl.GLRenderbuffer;
- framebuffer : gl.GLFramebuffer;
-
- width, height: i32;
-}
-
-create_canvas :: (width: i32, height: i32) -> Canvas {
-
- color_texture := create_texture(width, height, gl.RGBA8);
-
- depth_stencil_buffer := gl.createRenderbuffer();
- gl.bindRenderbuffer(gl.RENDERBUFFER, depth_stencil_buffer);
- gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, width, height);
- gl.bindRenderbuffer(gl.RENDERBUFFER, -1);
-
- framebuffer := gl.createFramebuffer();
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, color_texture.texture, 0);
- gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depth_stencil_buffer);
- gl.bindFramebuffer(gl.FRAMEBUFFER, -1);
-
- assert(gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE, "Framebuffer not complete!");
-
- return .{
- color_texture = color_texture,
- depth_stencil_buffer = depth_stencil_buffer,
- framebuffer = framebuffer,
- width = width,
- height = height,
- };
-}
-
+++ /dev/null
-package immediate_mode
-
-use package core
-#local gl :: package gl
-
-// This Shader represents an OpenGL program, not a shader. The name
-// is confusing but conceptually for most people, shaders are a bundled
-// version of the vertex and fragment shader.
-
-@Todo // Rewrite this so members that start with "uniform_" are automatically detected and the uniform location
-// is automatically retrieved. Same thing with vertex attributes.
-Shader :: struct {
- program : gl.GLProgram;
-
- position_loc : gl.GLint;
- color_loc : gl.GLint;
- texture_loc : gl.GLint;
-
- texture_uniform : gl.GLUniformLocation;
- view_uniform : gl.GLUniformLocation;
- world_uniform : gl.GLUniformLocation;
-
- make_from_source :: (vertex_source: str, fragment_source: str) -> Shader {
- shader: Shader;
- init_from_source(^shader, vertex_source, fragment_source);
- return shader;
- }
-
- init_from_source :: (use shader: ^Shader, vertex_source: str, fragment_source: str) {
- vertex_shader, vertex_compiled := compile_shader(vertex_source, gl.VERTEX_SHADER);
- fragment_shader, fragment_compiled := compile_shader(fragment_source, gl.FRAGMENT_SHADER);
- assert(vertex_compiled, "Vertex shader failed to compile");
- assert(fragment_compiled, "Fragment shader failed to compile");
- defer {
- gl.deleteShader(vertex_shader);
- gl.deleteShader(fragment_shader);
- }
-
- shader_program, program_linked := link_program(vertex_shader, fragment_shader);
- assert(program_linked, "Program failed to link");
- program = shader_program;
-
- position_loc = gl.getAttribLocation(program, "a_position");
- color_loc = gl.getAttribLocation(program, "a_color");
- texture_loc = gl.getAttribLocation(program, "a_texture");
-
- texture_uniform = gl.getUniformLocation(program, "u_texture");
- view_uniform = gl.getUniformLocation(program, "u_view");
- world_uniform = gl.getUniformLocation(program, "u_world");
- }
-
- free :: (use shader: ^Shader) {
- gl.deleteProgram(program);
- }
-}
-
-compile_shader :: (source: str, shader_type: gl.GLenum) -> (gl.GLShader, bool) {
- shader := gl.createShader(shader_type);
- gl.shaderSource(shader, source);
- gl.compileShader(shader);
-
- success := true;
- if gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0 {
- println("Error compiling shader.");
- gl.printShaderInfoLog(shader);
- success = false;
- }
-
- return shader, success;
-}
-
-link_program :: (vertex_shader: gl.GLShader, fragment_shader: gl.GLShader) -> (gl.GLProgram, bool) {
- program := gl.createProgram();
- gl.attachShader(program, vertex_shader);
- gl.attachShader(program, fragment_shader);
- gl.linkProgram(program);
-
- success := true;
- if gl.getProgramParameter(program, gl.LINK_STATUS) == 0 {
- println("Error linking program.");
- gl.printProgramInfoLog(program);
- success = false;
- }
-
- return program, success;
-}
\ No newline at end of file
+++ /dev/null
-package immediate_mode
-
-use package core
-use package core.intrinsics.onyx { __initialize }
-
-Vector2 :: struct {
- x, y: f32;
-
- zero :: Vector2.{ 0, 0 };
-}
-
-Color4 :: struct {
- r, g, b: f32;
- a: f32 = 1;
-}
-
-Immediate_Mode :: enum {
- Triangles;
- Lines;
-}
-
-Immediate_Vertex :: struct {
- position : Vector2;
- color : Color4;
- texture : Vector2;
-}
-
-Scissor_State :: struct {
- x, y, w, h: f32;
-}
-
-Immediate_Renderer :: struct {
- // Needs to be a multiple of 6!!
- Default_Max_Verticies :: 1020;
-
- active_shader : ^Shader;
-
- simple_shader, textured_shader : Shader;
- alpha_shader : Shader;
-
- // 'verticies' contains the vertex data and the maximum number of verticies
- // that can be rendered at a given time. 'vertex_count' is used to store how
- // many verticies will be rendered in the next draw call. 'vertex_count' is
- // expected to be a multiple of 3 or 2, given that triangles or lines are
- // being rendered.
- verticies : [] Immediate_Vertex;
- vertex_count : u32;
-
- clear_color : Color4;
-
- vertex_array : gl.GLVertexArrayObject;
- vertex_buffer : gl.GLBuffer;
-
- mode := Immediate_Mode.Triangles;
-
- canvas: ^Canvas = null;
-
- window_width, window_height: i32;
-
- world_transform_stack : [..] Transform;
- world_transform_dirty := false; // If the world transform matrix should be pushed to the shader uniform.
-
- scissor_stack : [..] Scissor_State;
-
- make :: (max_verticies := Default_Max_Verticies) -> Immediate_Renderer {
- ir : Immediate_Renderer;
- __initialize(^ir);
- init(^ir, max_verticies);
-
- return ir;
- }
-
- init :: (use ir: ^Immediate_Renderer, max_verticies := Default_Max_Verticies) {
- IMMEDIATE_VERTEX_SHADER :: #file_contents "./shaders/basic_vertex.glsl"
- IMMEDIATE_FRAGMENT_SHADER :: #file_contents "./shaders/basic_fragment.glsl"
- IMMEDIATE_FRAGMENT_SHADER_TEXTURED :: #file_contents "./shaders/textured_fragment.glsl"
- IMMEDIATE_ALPHA_SHADER :: #file_contents "./shaders/alpha_fragment.glsl"
-
- simple_shader = Shader.make_from_source(IMMEDIATE_VERTEX_SHADER, IMMEDIATE_FRAGMENT_SHADER);
- textured_shader = Shader.make_from_source(IMMEDIATE_VERTEX_SHADER, IMMEDIATE_FRAGMENT_SHADER_TEXTURED);
- alpha_shader = Shader.make_from_source(IMMEDIATE_VERTEX_SHADER, IMMEDIATE_ALPHA_SHADER);
- active_shader = ^simple_shader;
-
- verticies = memory.make_slice(Immediate_Vertex, max_verticies);
- memory.set(verticies.data, 0, verticies.count * sizeof Immediate_Vertex);
-
- vertex_array = gl.createVertexArray();
-
- vertex_buffer = gl.createBuffer();
- gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
- gl.bufferData(gl.ARRAY_BUFFER, cast(gl.GLsizei) (max_verticies * sizeof Immediate_Vertex), gl.STREAM_DRAW);
-
- world_transform_stack = array.make(Transform, capacity=1);
- array.insert_empty(^world_transform_stack, 0);
- transform_identity(array.get_ptr(world_transform_stack, -1));
-
- scissor_stack = array.make(Scissor_State);
-
- ir->init_shader_params(^simple_shader);
- ir->init_shader_params(^textured_shader);
- ir->init_shader_params(^alpha_shader);
-
- gl.useProgram(active_shader.program);
- }
-
- init_shader_params :: (use ir: ^Immediate_Renderer, shader: ^Shader) {
- gl.useProgram(shader.program);
-
- gl.bindVertexArray(vertex_array);
- defer gl.bindVertexArray(-1);
-
- gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
-
- offset_of :: (package runtime.info).offset_of;
- IV :: Immediate_Vertex;
-
- // Position
- gl.enableVertexAttribArray(0);
- gl.vertexAttribPointer(0, 2, gl.FLOAT, false, sizeof IV, offset_of(IV, "position"));
-
- // Color
- gl.enableVertexAttribArray(1);
- gl.vertexAttribPointer(1, 4, gl.FLOAT, false, sizeof IV, offset_of(IV, "color"));
-
- // Texture
- gl.enableVertexAttribArray(2);
- gl.vertexAttribPointer(2, 2, gl.FLOAT, false, sizeof IV, offset_of(IV, "texture"));
-
- gl.bindBuffer(gl.ARRAY_BUFFER, -1);
-
- world_transform := array.get_ptr(world_transform_stack, -1);
- world_matrix := transform_to_matrix(world_transform);
-
- gl.uniformMatrix4(shader.world_uniform, false, world_matrix);
- }
-
- free :: (use ir: ^Immediate_Renderer) {
- simple_shader->free();
- textured_shader->free();
- alpha_shader->free();
-
- gl.deleteVertexArray(vertex_array);
- gl.deleteBuffer(vertex_buffer);
- }
-
- flush :: (use ir: ^Immediate_Renderer) {
- if vertex_count == 0 do return;
-
- if world_transform_dirty {
- world_transform_dirty = false;
- world_transform := array.get_ptr(world_transform_stack, -1);
- world_matrix := transform_to_matrix(world_transform);
-
- for shader: (^Shader).[ ^simple_shader, ^textured_shader, ^alpha_shader ] {
- gl.useProgram(shader.program);
- gl.uniformMatrix4(shader.world_uniform, false, world_matrix);
- }
- }
-
- gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
- gl.bufferSubData(gl.ARRAY_BUFFER, 0, .{ count = vertex_count * sizeof Immediate_Vertex, data = ~~verticies.data });
- gl.bindBuffer(gl.ARRAY_BUFFER, -1);
-
- gl_mode : gl.GLenum;
- switch mode {
- case .Triangles do gl_mode = gl.TRIANGLES;
- case .Lines do gl_mode = gl.LINES;
- }
-
- gl.useProgram(active_shader.program);
- gl.bindVertexArray(vertex_array);
- gl.drawArrays(gl_mode, 0, vertex_count);
- gl.bindVertexArray(-1);
-
- vertex_count = 0;
- }
-
- push_vertex :: #match {
- // If a color is not provided, the previous color is used.
- (use ir: ^Immediate_Renderer, position: Vector2) {
- push_vertex(ir, position, color = verticies[vertex_count - 1].color);
- },
-
- (use ir: ^Immediate_Renderer, position: Vector2, color: Color4, texture: Vector2 = .{0,0}) {
- if vertex_count >= verticies.count do ir->flush();
-
- vertex_ptr := ^verticies[vertex_count];
- defer vertex_count += 1;
-
- vertex_ptr.position = position;
- vertex_ptr.color = color;
- vertex_ptr.texture = texture;
- },
- }
-
- rect :: (use ir: ^Immediate_Renderer, position: Vector2, size: Vector2, color: Color4 = .{1,1,1}) {
- if vertex_count >= verticies.count - 6 do ir->flush();
-
- vertex_ptr := ^verticies[vertex_count];
- defer vertex_count += 6;
-
- vertex_ptr[0] = .{ .{ position.x, position.y }, color, .{ 0, 0 } };
- vertex_ptr[1] = .{ .{ position.x + size.x, position.y }, color, .{ 0, 0 } };
- vertex_ptr[2] = .{ .{ position.x + size.x, position.y + size.y }, color, .{ 0, 0 } };
-
- vertex_ptr[3] = .{ .{ position.x, position.y }, color, .{ 0, 0 } };
- vertex_ptr[4] = .{ .{ position.x + size.x, position.y + size.y }, color, .{ 0, 0 } };
- vertex_ptr[5] = .{ .{ position.x, position.y + size.y }, color, .{ 0, 0 } };
- }
-
- textured_rect :: (use ir: ^Immediate_Renderer, position: Vector2, size: Vector2, texture_position: Vector2, texture_size: Vector2, color: Color4 = .{1,1,1}) {
- if vertex_count >= verticies.count - 6 do ir->flush();
-
- vertex_ptr := ^verticies[vertex_count];
- defer vertex_count += 6;
-
- vertex_ptr[0] = .{ .{ position.x, position.y }, color, .{ texture_position.x, texture_position.y } };
- vertex_ptr[1] = .{ .{ position.x + size.x, position.y }, color, .{ texture_position.x + texture_size.x, texture_position.y } };
- vertex_ptr[2] = .{ .{ position.x + size.x, position.y + size.y }, color, .{ texture_position.x + texture_size.x, texture_position.y + texture_size.y } };
-
- vertex_ptr[3] = .{ .{ position.x, position.y }, color, .{ texture_position.x, texture_position.y } };
- vertex_ptr[4] = .{ .{ position.x + size.x, position.y + size.y }, color, .{ texture_position.x + texture_size.x, texture_position.y + texture_size.y } };
- vertex_ptr[5] = .{ .{ position.x, position.y + size.y }, color, .{ texture_position.x, texture_position.y + texture_size.y } };
- }
-
- circle :: (use ir: ^Immediate_Renderer, center: Vector2, radius: f32, color := Color4.{ 1, 1, 1 }, segments := 12) {
- if vertex_count >= verticies.count - segments * 3 do ir->flush();
-
- assert(verticies.count >= segments * 3, "[Immediate Renderer] Too many segments to draw in a single call.");
-
- vertex_ptr := ^verticies[vertex_count];
- defer vertex_count += segments * 3;
-
- cx := center.x;
- cy := center.y;
-
- px := radius + cx;
- py := cy;
-
- ptr_offset := 0;
-
- for s: 1 .. segments + 1 {
- angle := math.PI * 2 * cast(f32) s / ~~segments;
- x := math.cos(angle) * radius + cx;
- y := math.sin(angle) * radius + cy;
-
- vertex_ptr[ptr_offset + 0] = .{ .{ cx, cy }, color, .{ 0, 0 } };
- vertex_ptr[ptr_offset + 1] = .{ .{ px, py }, color, .{ 0, 0 } };
- vertex_ptr[ptr_offset + 2] = .{ .{ x, y }, color, .{ 0, 0 } };
-
- px = x;
- py = y;
- ptr_offset += 3;
- }
- }
-
- // NOTE: Calling set_texture without a parameter will disable textured rendering.
- set_texture :: (use ir: ^Immediate_Renderer, texture_id: i32 = -1) {
- if vertex_count > 0 do flush(ir);
-
- previous_active := active_shader;
- if texture_id >= 0 do active_shader = ^textured_shader;
- else do active_shader = ^simple_shader;
-
- // Skip the GL calls if the texture didn't change.
- if previous_active == active_shader do return;
-
- gl.useProgram(active_shader.program);
- gl.uniform1i(active_shader.texture_uniform, math.max(texture_id, 0));
- }
-
- use_alpha_shader :: (use ir: ^Immediate_Renderer, texture_id: i32 = -1) {
- if active_shader != ^alpha_shader {
- if vertex_count > 0 do flush(ir);
- active_shader = ^alpha_shader;
- }
-
- gl.useProgram(active_shader.program);
- gl.uniform1i(active_shader.texture_uniform, math.max(texture_id, 0));
- }
-
- use_ortho_projection :: (use ir: ^Immediate_Renderer, left, right, top, bottom: f32) {
- projection_matrix := f32.[
- 2 / (right - left), 0, 0, 0,
- 0, 2 / (top - bottom), 0, 0,
- 0, 0, -2, 0,
- -(right + left) / (right - left), -(top + bottom) / (top - bottom), -1, 1
- ];
-
- gl.useProgram(simple_shader.program);
- gl.uniformMatrix4(simple_shader.view_uniform, false, projection_matrix);
- gl.useProgram(textured_shader.program);
- gl.uniformMatrix4(textured_shader.view_uniform, false, projection_matrix);
- gl.useProgram(alpha_shader.program);
- gl.uniformMatrix4(alpha_shader.view_uniform, false, projection_matrix);
-
- gl.useProgram(active_shader.program);
- }
-
- push_scissor :: (use ir: ^Immediate_Renderer, x, y, w, h: f32) {
- if vertex_count > 0 do ir->flush();
-
- if !gl.isEnabled(gl.SCISSOR_TEST) {
- gl.enable(gl.SCISSOR_TEST);
- }
-
- transform := ir->get_transform();
-
- new_x0 := x * transform.scale.x + transform.translation.x;
- new_y0 := y * transform.scale.y + transform.translation.y;
- new_x1 := (x + w) * transform.scale.x + transform.translation.x;
- new_y1 := (y + h) * transform.scale.y + transform.translation.y;
- new_w := new_x1 - new_x0;
- new_h := new_y1 - new_y0;
-
- array.push(^scissor_stack, .{ new_x0, new_y0, new_w + 1, new_h + 1 });
-
- gl.scissor(~~new_x0, window_height - ~~new_y1, ~~math.ceil(new_w + 1), ~~math.ceil(new_h + 1));
- }
-
- pop_scissor :: (use ir: ^Immediate_Renderer) {
- if vertex_count > 0 do ir->flush();
-
- array.pop(^scissor_stack);
-
- if scissor_stack.count > 0 {
- s := scissor_stack[scissor_stack.count - 1];
-
- gl.scissor(~~s.x, window_height - ~~s.y - ~~s.h, ~~s.w, ~~s.h);
-
- } else {
- ir->scissor_disable();
- }
- }
-
- scissor_disable :: (use ir: ^Immediate_Renderer) {
- if gl.isEnabled(gl.SCISSOR_TEST) {
- ir->flush();
- gl.disable(gl.SCISSOR_TEST);
- }
- }
-
- set_mode :: (use ir: ^Immediate_Renderer, new_mode: Immediate_Mode) {
- if mode != new_mode {
- ir->flush();
- mode = new_mode;
- }
- }
-
- use_canvas :: (use ir: ^Immediate_Renderer, new_canvas: ^Canvas) {
- if canvas == new_canvas do return;
- ir->flush();
-
- canvas = new_canvas;
- if canvas != null {
- gl.bindFramebuffer(gl.FRAMEBUFFER, canvas.framebuffer);
- gl.viewport(0, 0, canvas.width, canvas.height);
-
- @Note // This flips the projection because generally with using framebuffers as textures,
- // the bottom left, (0, 0) in WebGL world, you want to be the top left when you render it.
- ir->use_ortho_projection(0, ~~canvas.width, ~~canvas.height, 0);
-
- } else {
- gl.bindFramebuffer(gl.FRAMEBUFFER, -1);
- gl.viewport(0, 0, window_width, window_height);
- ir->use_ortho_projection(0, ~~window_width, 0, ~~window_height);
- }
- }
-
- set_window_size :: (use ir: ^Immediate_Renderer, width, height: i32) {
- window_width = width;
- window_height = height;
-
- // If there is no active canvas, immediately update the values.
- // Maybe this should flush the current buffer first?
- if canvas == null {
- gl.viewport(0, 0, window_width, window_height);
- ir->use_ortho_projection(0, ~~window_width, 0, ~~window_height);
- }
- }
-
- push_matrix :: (use ir: ^Immediate_Renderer) {
- if vertex_count > 0 do flush(ir);
- world_transform_dirty = true;
-
- array.push(^world_transform_stack, world_transform_stack[world_transform_stack.count - 1]);
- *array.get_ptr(world_transform_stack, -1) = *array.get_ptr(world_transform_stack, -2);
-
- // transform_identity(array.get_ptr(^world_transform_stack, -1));
- }
-
- pop_matrix :: (use ir: ^Immediate_Renderer) {
- if vertex_count > 0 do flush(ir);
- world_transform_dirty = true;
-
- array.pop(^world_transform_stack);
- }
-
- identity :: (use ir: ^Immediate_Renderer) {
- transform_identity(array.get_ptr(world_transform_stack, -1));
- }
-
- get_transform :: (use ir: ^Immediate_Renderer) -> ^Transform {
- return array.get_ptr(world_transform_stack, -1);
- }
-
- apply_transform :: (use ir: ^Immediate_Renderer, transform: Transform) {
- transform_apply(array.get_ptr(world_transform_stack, -1), transform);
- world_transform_dirty = true;
- }
-
- to_screen_coordinates :: (use ir: ^Immediate_Renderer, use v: Vector2) -> Vector2 {
- transform := ir->get_transform();
-
- return .{
- x * transform.scale.x + transform.translation.x,
- y * transform.scale.y + transform.translation.y,
- };
- }
-
- to_world_coordinates :: (use ir: ^Immediate_Renderer, use v: Vector2) -> Vector2 {
- transform := ir->get_transform();
-
- return .{
- (x - transform.translation.x) / transform.scale.x,
- (y - transform.translation.y) / transform.scale.y,
- };
- }
-}
-
-
-
-
-// While the immediate renderer can be used on its own, below is a set of wrapping functions
-// that operate on a global immediate renderer. This is probably the most common way that
-// it will be used.
-
-global_renderer : Immediate_Renderer;
-
-immediate_renderer_init :: () {
- global_renderer = Immediate_Renderer.make();
-}
-
-immediate_renderer_free :: () {
- Immediate_Renderer.free(^global_renderer);
-}
-
-vertex :: #match {
- macro (position: Vector2) {
- gr :: global_renderer
- gr->push_vertex(position);
- },
- macro (position: Vector2, color: Color4) {
- gr :: global_renderer
- gr->push_vertex(position, color);
- },
-}
-
-rect :: macro (position: Vector2, size: Vector2, color: Color4 = .{1,1,1}) {
- gr :: global_renderer
- gr->rect(position, size, color);
-}
-
-textured_rect :: macro (position: Vector2, size: Vector2, texture_position: Vector2, texture_size: Vector2, color: Color4 = .{1,1,1}) {
- gr :: global_renderer
- gr->textured_rect(position, size, texture_position, texture_size, color);
-}
-
-circle :: macro (center: Vector2, radius: f32, color: Color4 = .{1,1,1}, segments := 12) {
- gr :: global_renderer
- gr->circle(center, radius, color, segments);
-}
-
-flush :: macro () {
- gr :: global_renderer
- gr->flush();
-}
-
-set_texture :: #match {
- macro (texture_id: i32 = -1) {
- gr :: global_renderer
- gr->set_texture(texture_id);
- },
- macro (texture: ^Texture, texture_index := 0) {
- gr :: global_renderer
- gr->set_texture(texture_index);
-
- if texture_index >= 0 {
- gl.activeTexture(gl.TEXTURE0 + texture_index);
- gl.bindTexture(gl.TEXTURE_2D, texture.texture);
-
- } else {
- gl.bindTexture(gl.TEXTURE_2D, -1);
- }
- }
-}
-
-use_ortho_projection :: macro (left: f32, right: f32, top: f32, bottom: f32) {
- gr :: global_renderer
- gr->use_ortho_projection(left, right, top, bottom);
-}
-
-use_alpha_shader :: macro (texture_id: i32 = -1) {
- gr :: global_renderer
- gr->use_alpha_shader(texture_id);
-}
-
-push_scissor :: (x: f32, y: f32, w: f32, h: f32) {
- gr :: global_renderer
- gr->push_scissor(x, y, w, h);
-}
-
-pop_scissor :: macro () {
- gr :: global_renderer
- gr->pop_scissor();
-}
-
-scissor_disable :: macro () {
- gr :: global_renderer
- gr->scissor_disable();
-}
-
-set_mode :: macro (mode: Immediate_Mode) {
- gr :: global_renderer
- gr->set_mode(mode);
-}
-
-use_canvas :: macro (canvas: ^Canvas) {
- gr :: global_renderer
- gr->use_canvas(canvas);
-}
-
-set_window_size :: macro (width: i32, height: i32) {
- gr :: global_renderer
- gr->set_window_size(width, height);
-}
-
-get_window_size :: macro () -> (width: i32, height: i32) {
- gr :: global_renderer
- return gr.window_width, gr.window_height;
-}
-
-push_matrix :: macro () { gr :: global_renderer; gr->push_matrix(); }
-pop_matrix :: macro () { gr :: global_renderer; gr->pop_matrix(); }
-identity :: macro () { gr :: global_renderer; gr->identity(); }
-apply_transform :: macro (transform: Transform) {
- gr :: global_renderer
- gr->apply_transform(transform);
-}
-
-
-
-save_matrix :: macro () {
- push_m :: push_matrix
- pop_m :: pop_matrix
-
- push_m();
- defer pop_m();
-}
+++ /dev/null
-@Rename
-package immediate_mode
-
-#load "./immediate_renderer"
-#load "./gl_utils"
-#load "./canvas"
-#load "./texture"
-#load "./transform"
-
-#package gl :: package gl
+++ /dev/null
-#version 300 es
-
-precision mediump float;
-
-uniform sampler2D u_texture;
-
-in vec4 v_color;
-in vec2 v_texture;
-
-out vec4 fragColor;
-
-void main() {
- float alpha = texture(u_texture, v_texture).r;
- fragColor = v_color * alpha;
-}
\ No newline at end of file
+++ /dev/null
-#version 300 es
-
-precision mediump float;
-
-uniform sampler2D u_texture;
-
-in vec4 v_color;
-in vec2 v_texture;
-
-out vec4 fragColor;
-
-void main() {
- fragColor = v_color;
-}
\ No newline at end of file
+++ /dev/null
-#version 300 es
-
-layout(location = 0) in vec2 a_vertex;
-layout(location = 1) in vec4 a_color;
-layout(location = 2) in vec2 a_texture;
-
-uniform mat4 u_view;
-uniform mat4 u_world;
-
-out vec4 v_color;
-out vec2 v_texture;
-
-void main() {
- gl_Position = u_view * u_world * vec4(a_vertex, 0, 1);
-
- v_color = a_color;
- v_texture = a_texture;
-}
\ No newline at end of file
+++ /dev/null
-#version 300 es
-
-precision mediump float;
-
-uniform sampler2D u_texture;
-
-in vec4 v_color;
-in vec2 v_texture;
-
-out vec4 fragColor;
-
-void main() {
- fragColor = v_color * texture(u_texture, v_texture);
-}
\ No newline at end of file
+++ /dev/null
-package immediate_mode
-
-use package core
-
-Texture :: struct {
- texture : gl.GLTexture;
-
- width, height: i32;
-}
-
-create_texture :: (width: i32, height: i32, format: gl.GLenum) -> Texture {
- texture := gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
-
- // Setting some reasonable defaults for the texture parameters
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-
- gl.bindTexture(gl.TEXTURE_2D, -1);
-
- return .{
- texture = texture,
- width = width,
- height = height,
- };
-}
-
-load_texture :: (width: i32, height: i32, data: [] u8, format: gl.GLenum, internal_format: gl.GLenum, internal_type := gl.UNSIGNED_BYTE) -> Texture {
- texture := gl.createTexture();
- gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, internal_format, width, height, 0, format, internal_type, data);
-
- // Setting some reasonable defaults for the texture parameters
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
-
- gl.bindTexture(gl.TEXTURE_2D, -1);
-
- return .{
- texture = texture,
- width = width,
- height = height,
- };
-}
+++ /dev/null
-package immediate_mode
-
-
-Transform :: struct {
- translation: Vector2;
- scale: Vector2;
-
- // No rotation for right now. Not need for GUI stuff.
- // rotation: f32; // In radians
-}
-
-transform_identity :: (use t: ^Transform) {
- translation = .{ 0, 0 };
- scale = .{ 1, 1 };
-
- // rotation = 0;
-}
-
-transform_to_matrix :: (use t: ^Transform) -> [16] f32 {
- math :: package core.math
-
- // st := math.sin(rotation);
- // ct := math.cos(rotation);
-
- sx := scale.x;
- sy := scale.y;
-
- tx := translation.x;
- ty := translation.y;
-
- return f32.[
- sx, 0, 0, 0,
- 0, sy, 0, 0,
- 0, 0, 1, 0,
- tx, ty, 0, 1
- ];
-}
-
-transform_translate :: (use t: ^Transform, v: Vector2) {
- translation.x += v.x;
- translation.y += v.y;
-}
-
-transform_scale :: (use t: ^Transform, v: Vector2) {
- scale.x *= v.x;
- scale.y *= v.y;
-}
-
-transform_apply :: (use t: ^Transform, other: Transform) {
- translation.x += other.translation.x * scale.x;
- translation.y += other.translation.y * scale.y;
- scale.x *= other.scale.x;
- scale.y *= other.scale.y;
-}
-
-transform_point :: (use t: ^Transform, v: Vector2) -> Vector2 {
- return .{
- x = (v.x - translation.x) / scale.x,
- y = (v.y - translation.y) / scale.y,
- };
-}
\ No newline at end of file
+++ /dev/null
-window.ONYX_MODULES = window.ONYX_MODULES || [];
-
-function push_event_to_buffer(esp, event_size, event_kind, data) {
- let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer);
-
- if (WASM_U32[esp] >= WASM_U32[esp + 1]) {
- console.log("Event buffer full!");
- return;
- }
-
- WASM_U32[esp] += 1;
-
- let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2;
- WASM_U32[event_idx] = event_kind;
- WASM_U32[event_idx + 1] = Date.now();
-
- for (let i = 0; i < data.length; i++) {
- WASM_U32[event_idx + 2 + i] = data[i];
- }
-}
-
-var requested_file_data = {};
-
-window.ONYX_MODULES.push({
- module_name: "js_events",
-
- setup: function(esp, event_size) {
- // Indicies into a Uint32Array are not based on bytes,
- // but on the index.
- esp /= 4;
-
- document.addEventListener("keydown", function (ev) {
- if (ev.isComposing || ev.keyCode === 229) return;
- ev.preventDefault();
-
- // NOTE: These modifiers need to match in js_events.onyx.
- var modifiers = 0x0000;
- if (ev.ctrlKey) modifiers |= 0x01;
- if (ev.altKey) modifiers |= 0x02;
- if (ev.metaKey) modifiers |= 0x04;
- if (ev.shiftKey) modifiers |= 0x08;
-
- push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode, modifiers ]);
-
- var keyname = ev.code;
- let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer);
- let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2;
-
- let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer);
-
- for (var i = 0; i < keyname.length; i++) {
- WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i);
- }
-
- WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length;
- return false;
- });
-
- document.addEventListener("keyup", function (ev) {
- if (ev.isComposing || ev.keyCode === 229) return;
- ev.preventDefault();
-
- // NOTE: These modifiers need to match in js_events.onyx.
- var modifiers = 0x0000;
- if (ev.ctrlKey) modifiers |= 0x01;
- if (ev.altKey) modifiers |= 0x02;
- if (ev.metaKey) modifiers |= 0x04;
- if (ev.shiftKey) modifiers |= 0x08;
-
- push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode, modifiers ]);
-
- var keyname = ev.code;
- let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer);
- let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2;
-
- let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer);
-
- for (var i = 0; i < keyname.length; i++) {
- WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i);
- }
-
- WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length;
-
- return false;
- });
-
- document.addEventListener("mousedown", function (ev) {
- push_event_to_buffer(esp, event_size, 0x01, [ ev.clientX, ev.clientY, ev.button ]);
- });
-
- document.addEventListener("mouseup", function (ev) {
- push_event_to_buffer(esp, event_size, 0x02, [ ev.clientX, ev.clientY, ev.button ]);
- });
-
- document.addEventListener("mousemove", function (ev) {
- push_event_to_buffer(esp, event_size, 0x03, [ ev.clientX, ev.clientY, -1 ]);
- });
-
- document.addEventListener("wheel", function (ev) {
- push_event_to_buffer(esp, event_size, 0x07, [ ev.clientX, ev.clientY, ev.deltaY >= 0 ? 0x04 : 0x03 ]);
- });
-
- window.addEventListener("resize", function (ev) {
- push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]);
- });
-
- push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]);
-
- document.getElementsByTagName("canvas")[0].addEventListener("drop", function (ev) {
- ev.preventDefault();
-
- // ROBUSTNESS: Currently, this only gives the first file, which for a lot of purposes, will be enough.
- // But if multiple files are dropped, the application will only know about the first one.
- var response = ev.dataTransfer.items[0].getAsFile();
- response.arrayBuffer().then(data => {
- // 0 is assumed to be reserved in request_file.onyx.
- requested_file_data[0] = {
- name: response.name,
- data: data,
- };
- push_event_to_buffer(esp, event_size, 0x08, [0x01, 0, data.byteLength, response.name.length ]);
- })
- .catch(error => {
- push_event_to_buffer(esp, event_size, 0x08, [0x02, 0, 0, 0]);
- });
-
- return false;
- });
-
- document.getElementsByTagName("canvas")[0].addEventListener("dragover", function(ev) {
- ev.preventDefault();
- return false;
- });
-
- document.oncontextmenu = (e) => {
- e.preventDefault = true;
- return false;
- };
- },
-
- request_file(esp, event_size, filename_ptr, filename_len, fileid) {
- esp /= 4;
-
- var data_view = new DataView(ONYX_MEMORY.buffer);
- var path = "";
- for (var i = 0; i < filename_len; i++) path += String.fromCharCode(data_view.getUint8(filename_ptr + i));
- console.log(`Requesting file '${path}'`);
-
- fetch(path)
- .then(response => response.arrayBuffer())
- .then(array_buffer => {
- requested_file_data[fileid] = {
- name: path,
- data: array_buffer,
- };
-
- push_event_to_buffer(esp, event_size, 0x09, [ 0x01, fileid, array_buffer.byteLength, path.length ]);
- })
- .catch((error) => {
- push_event_to_buffer(esp, event_size, 0x09, [ 0x02, fileid, 0, 0 ]);
- });
- },
-
- get_requested_file_data(fileid, bufferptr, bufferlen, nameptr, namelen) {
- var file_data = requested_file_data[fileid];
- if (file_data == null) return 0;
-
- if (bufferlen < file_data.data.byteLength) return 0;
-
- let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer);
- var u8_data = new Uint8Array(file_data.data);
-
- WASM_U8.set(u8_data, bufferptr);
-
- if (nameptr != 0 && namelen <= file_data.name.length) {
- var name_data = new TextEncoder().encode(file_data.name);
- WASM_U8.set(name_data, nameptr);
- }
-
- requested_file_data[fileid] = null;
- delete requested_file_data[fileid];
-
- return 1;
- },
-});
-
+++ /dev/null
-// This is a simple buffered system to receive events from the webbrowser
-// in a buffer that you can poll and consume all of the events. It is not
-// direclty used by the immediate mode graphics, but it makes standing up
-// a simple application much easier.
-
-package js_events
-
-#local Max_Buffered_Events :: 16
-
-// NOTE: These need to match exactly what is in the corresponding javascript
-DomEventKind :: enum {
- None :: 0x00;
-
- MouseDown :: 0x01;
- MouseUp :: 0x02;
- MouseMove :: 0x03;
- MouseWheel :: 0x07;
-
- KeyDown :: 0x04;
- KeyUp :: 0x05;
-
- Resize :: 0x06;
-
- FileDropped :: 0x08;
- FileRequest :: 0x09;
-}
-
-DomEvent :: struct {
- kind : DomEventKind;
- timestamp : u32;
-}
-
-KeyboardEvent :: struct {
- use event : DomEvent;
-
- keycode : u32; // Apparently, keyCode is deprecated on browsers now??? Stupid web standards that aren't "standards" at all.
- modifiers : Modifiers;
-
- // This is assuming that no single keyname is greater than 15 characters in length.
- // A quick look at https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values makes
- // me think that that isn't possible, but it's the web so anything is possible. 🙄
- keyname : [15] u8;
- keyname_count : u8;
-
- Modifiers :: enum #flags {
- CTRL :: 0x01;
- ALT :: 0x02;
- META :: 0x04;
- SHIFT :: 0x08;
- }
-
- get_name :: (use e: ^KeyboardEvent) => str.{ ~~keyname, ~~keyname_count };
-}
-
-MouseEvent :: struct {
- use event : DomEvent;
-
- Button :: enum {
- Left :: 0x00;
- Middle :: 0x01;
- Right :: 0x02;
-
- WheelUp :: 0x03;
- WheelDown :: 0x04;
- }
-
- pos_x : u32;
- pos_y : u32;
- button : Button;
-}
-
-ResizeEvent :: struct {
- use event : DomEvent;
-
- width : u32;
- height : u32;
-}
-
-FileEvent :: struct {
- use dom : DomEvent;
-
- Status :: enum (u32) { Success :: 0x01; Failed :: 0x02; };
- status : Status;
-
- file_id : u32;
- size : u32;
- name_length : u32;
-}
-
-Event :: struct #union {
- use dom : DomEvent;
-
- keyboard : KeyboardEvent;
- mouse : MouseEvent;
- resize : ResizeEvent;
- file : FileEvent;
-}
-
-clear_event :: (ev: ^Event) {
- ev.kind = DomEventKind.None;
- ev.timestamp = 0;
-}
-
-init :: () {
- event_storage.event_count = 0;
- event_storage.max_events = Max_Buffered_Events;
-
- for ^ev: event_storage.event_buffer do clear_event(ev);
-
- event_setup(^event_storage, sizeof Event);
-}
-
-#local processing_event: Event
-consume :: () -> Iterator(^Event) {
- next :: (_: rawptr) -> (^Event, bool) {
- if event_storage.event_count == 0 do return null, false;
-
- @CodeGeneration // This instruction (and all instructions involving Event) generate a TON of instructions because Event is a union.
- processing_event = event_storage.event_buffer[0];
-
- for i: 0 .. Max_Buffered_Events - 2 {
- event_storage.event_buffer[i] = event_storage.event_buffer[i + 1];
- }
- event_storage.event_count -= 1;
-
- return ^processing_event, true;
- }
-
- return .{ null, next };
-}
-
-/* Private members */
-
-#package EventStorage :: struct {
- event_count : u32;
- max_events : u32;
- event_buffer : [Max_Buffered_Events] Event;
-}
-
-#package event_storage : EventStorage;
-#package event_setup :: (event_storage: ^EventStorage, event_size: u32) -> void #foreign "js_events" "setup" ---
+++ /dev/null
-
-#load "./js_events"
-#load "./request_file"
\ No newline at end of file
+++ /dev/null
-package js_events
-
-// 0 is reserved for dropped files
-#local next_request_id := 1;
-
-request_file :: (filepath: str) -> u32 {
- js_request_file :: (event_storage: ^EventStorage, event_size: u32, filepath: str, fileid: u32) -> void #foreign "js_events" "request_file" ---;
-
- fileid := next_request_id;
- next_request_id += 1;
-
- js_request_file(^event_storage, sizeof Event, filepath, fileid);
- return fileid;
-}
-
-get_requested_file_data :: (fileid: u32, buffer: [] u8, name_buffer: [] u8 = .{ null, 0 } ) -> bool {
- js_get_requested_file_data :: (fileid: u32, buffer: [] u8, name_buffer: [] u8) -> u32 #foreign "js_events" "get_requested_file_data" ---;
-
- return js_get_requested_file_data(fileid, buffer, name_buffer) == 1;
-}
+++ /dev/null
-<!DOCTYPE html>
-<html>
- <head>
- <title>OUIT</title>
-
- <style>
- html, body, canvas {
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
- overflow: hidden;
- background-color: black;
- }
- </style>
-
- <script type="application/onyx" multi-threaded="true" data="ouit.wasm.data" src="ouit.wasm"></script>
- <script type="text/javascript" src="modules/webgl2/webgl2.js"></script>
- <script type="text/javascript" src="modules/js_events/js_events.js"></script>
- <script type="text/javascript" src="modules/ouit/ouit.js"></script>
- <script type="text/javascript" src="js/onyx-loader.js"></script>
-
- <script>window.ONYX_THREAD_SCRIPT = "js/onyx-thread.js";</script>
- </head>
-
- <body>
- <canvas id="main_canvas">This browser does not support the Canvas API.</canvas>
- </body>
-</html>
+++ /dev/null
-package ouit
-
-/*
-
-Ouit ("Wheat") - The Onyx User-Interface Template
-
-An all-encompassing user-interface template for Onyx program thats makes
-it easy to setup a web-based user interface.
-
-*/
-
-#load "core/std"
-
-#load "modules/bmfont/module"
-#load "modules/immediate_mode/module"
-#load "modules/js_events/module"
-#load "modules/ui/module"
-#load "modules/webgl2/module"
-#load "modules/json/module"
-
-#load "./ouit"
+++ /dev/null
-window.ONYX_MODULES = window.ONYX_MODULES || [];
-
-window.ONYX_MODULES.push({
- module_name: "ouit",
-
- loop: function() {
- function loop() {
- window.ONYX_INSTANCE.exports.ouit_loop();
- window.requestAnimationFrame(loop);
- }
-
- window.requestAnimationFrame(loop);
- },
-
- time_now: function() {
- return Date.now();
- },
-});
\ No newline at end of file
+++ /dev/null
-package ouit
-
-#local {
- gl :: package gl
- gfx :: package immediate_mode
- events :: package js_events
-}
-
-start :: () -> void #foreign "ouit" "loop" ---
-
-init :: (canvas_name: str,
- he: typeof ouit_handle_event,
- u: typeof ouit_update,
- d: typeof ouit_draw) {
-
- gl.init(canvas_name);
- events.init();
- gfx.immediate_renderer_init();
-
- ouit_handle_event = he;
- ouit_update = u;
- ouit_draw = d;
-}
-
-#package {
- ouit_handle_event : (^events.Event) -> void;
- ouit_update : (dt: f32) -> void;
- ouit_draw : () -> void;
-}
-
-#export "ouit_loop" () {
- time_now :: () -> i32 #foreign "ouit" "time_now" --- ;
-
- #persist last_time := 0;
- if last_time == 0 do last_time = time_now();
-
- now := time_now();
- dt := cast(f32) (now - last_time) / 1000.0f;
- last_time = now;
-
- for event: events.consume() do ouit_handle_event(event);
-
- ouit_update(dt);
- ouit_draw();
-}
\ No newline at end of file
+++ /dev/null
-#!/bin/sh
-
-[ -z "$ONYX_FOLDER" ] && ONYX_FOLDER="$HOME/dev/c/onyx"
-
-[ ! -s "./modules" ] && ln -s "$ONYX_FOLDER/modules" $(pwd)/modules
-[ ! -s "./js" ] && ln -s "$ONYX_FOLDER/bin" $(pwd)/js
-[ ! -f "./index.html" ] && cp "$ONYX_FOLDER/modules/ouit/index.html" .
-
-onyx -r js -V --use-multi-threading -o ouit.wasm "$1"
-
+++ /dev/null
-package ttf
-
-
-// A simple big-endian binary reader out of a byte buffer
-TTF_Reader :: struct {
- data : [] u8;
- position : u32 = 0;
-
- seek :: (use br: ^TTF_Reader, pos: u32) -> u32 {
- assert(pos >= 0 && pos < data.count, "Trying to seek outside of buffer.");
- defer position = pos;
- return position;
- }
-
- tell :: (use br: ^TTF_Reader) -> u32 do return position;
-
- get_u8 :: (use br: ^TTF_Reader) -> u8 {
- defer position += 1;
- return data[position];
- }
-
- get_u16 :: (use br: ^TTF_Reader) -> u16 {
- byte1 := cast(u16) get_u8(br);
- byte2 := cast(u16) get_u8(br);
- return byte1 << 8 | byte2;
- }
-
- get_u32 :: (use br: ^TTF_Reader) -> u32 {
- byte1 := cast(u32) get_u8(br);
- byte2 := cast(u32) get_u8(br);
- byte3 := cast(u32) get_u8(br);
- byte4 := cast(u32) get_u8(br);
- return byte1 << 24 | byte2 << 16 | byte3 << 8 | byte4;
- }
-
- get_i16 :: (use br: ^TTF_Reader) -> i16 {
- result := get_u16(br);
- if result & ~~ 0x8000 != 0 {
- result -= (1 << 16);
- }
- }
-
- get_i32 :: (use br: ^TTF_Reader) -> i32 {
- return ~~ get_u32(br);
- }
-
- get_fword :: (use br: ^TTF_Reader) -> i16 {
- return get_i16(br);
- }
-
- get_2dot14 :: (use br: ^TTF_Reader) -> f32 {
- numerator := cast(i32) get_i16(br);
- return ~~ numerator / cast(f32) (1 << 14);
- }
-
- get_fixed :: (use br: ^TTF_Reader) -> f32 {
- numerator := get_i32(br);
- return ~~ numerator / cast(f32) (1 << 16);
- }
-
- @Note // does not allocate a new string.
- get_string :: (use br: ^TTF_Reader, length: u32) -> str {
- defer position += length;
- return data.data[position .. position + length];
- }
-
- @Fix // this is not correct at all.
- get_date :: (use br: ^TTF_Reader) -> u64 {
- mac_time := ~~get_u32(br) * 0x100000000 + cast(u64) get_u32(br);
- utc_time := mac_time * 1000;
- return utc_time;
- }
-}
\ No newline at end of file
+++ /dev/null
-@Incomplete
-// This whole module is very imcomplete
-
-package ttf
-
-#load "./ttf"
-#load "./binary_reader"
\ No newline at end of file
+++ /dev/null
-package ttf
-
-use package core
-
-True_Type_Font :: struct {
- reader : TTF_Reader;
-
- scalar_type : u32;
- search_range : u16;
- entry_selector : u16;
- range_shift : u16;
-
- tables : Map(u32, TTF_Table_Info);
- char_maps : [..] TTF_Cmap;
-
- version : u32;
- font_revision : u32;
- checksum_adjustment : u32;
- magic_number : u32;
- flags : u16;
- units_per_em : u16;
- // created : u64;
- // modified : u64;
- x_min : i16;
- x_max : i16;
- y_min : i16;
- y_max : i16;
- mac_style : u16;
- lowest_rec_ppem : u16;
- font_direction_hint : i16;
- index_to_loc_format : TTF_Index_To_Loc_Format;
- 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;
- };
-}
-
-TTF_Table_Info :: struct {
- checksum : u32 = 0;
- offset : u32 = 0;
- length : u32 = 0;
-}
-
-TTF_Index_To_Loc_Format :: enum (i16) {
- Short :: 0x00;
- Long :: 0x01;
-}
-
-TTF_Glyph :: struct {
- contour_count : i16;
- x_min : i16;
- x_max : i16;
- y_min : i16;
- y_max : i16;
-
- points : [..] TTF_Glyph_Point;
- contour_ends : [..] u16;
-}
-
-TTF_Glyph_Point :: struct {
- on_curve : bool;
- x : i16 = 0;
- y : i16 = 0;
-}
-
-
-TTF_Cmap_Format :: enum (u16) {
- Simple :: 0x00;
- Segmented :: 0x04;
-}
-
-TTF_Cmap_Base :: struct { format : TTF_Cmap_Format; }
-
-TTF_Cmap0 :: struct {
- use base: TTF_Cmap_Base;
-
- glyph_indicies: [] u8;
-}
-
-TTF_Cmap4 :: struct {
- use base: TTF_Cmap_Base;
-
- seg_count : u16;
- search_range : u16;
- entry_selector : u16;
- range_shift : u16;
-
- segments : [..] TTF_Segment;
- cache : Map(i32, i32);
-}
-
-TTF_Segment :: struct {
- start_code : u16;
- end_code : u16;
- id_delta : u16;
- id_range_offset : u16;
-}
-
-TTF_Cmap :: struct #union {
- use base: TTF_Cmap_Base;
- cmap0: TTF_Cmap0;
- cmap4: TTF_Cmap4;
-}
-
-
-ttf_create :: (ttf_data: [] u8) -> True_Type_Font {
- ttf : True_Type_Font;
- ttf.reader = TTF_Reader.{ data = ttf_data };
-
- map.init(^ttf.tables, .{});
- 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;
-}
-
-#package
-ttf_read_offset_table :: (use ttf: ^True_Type_Font) {
- scalar_type = reader->get_u32();
- num_tables := reader->get_u16();
- search_range = reader->get_u16();
- entry_selector = reader->get_u16();
- range_shift = reader->get_u16();
-
- for i: 0 .. ~~num_tables {
- tag := reader->get_string(4);
- tag_int := string_to_beu32(tag);
- println(tag);
-
- table_info : TTF_Table_Info;
- table_info.checksum = reader->get_u32();
- table_info.offset = reader->get_u32();
- table_info.length = reader->get_u32();
-
- map.put(^tables, tag_int, table_info);
-
- if !string.equal(tag, "head") {
- csum := ttf_calc_table_checksum(^reader, table_info.offset, table_info.length);
- if table_info.checksum != csum {
- print("WARNING: Checksum for table '");
- print(tag);
- print("' did not match.");
- }
- }
- }
-}
-
-#package
-ttf_read_head_table :: (use ttf: ^True_Type_Font) {
- head_table_info := map.get(^tables, string_to_beu32("head"));
- reader->seek(head_table_info.offset);
-
- version = reader->get_u32();
- font_revision = reader->get_u32();
- checksum_adjustment = reader->get_u32();
- magic_number = reader->get_u32(); // NOTE: Should be 0x5f0f3cf5
- assert(magic_number == 0x5f0f3cf5, "Magic number was wrong.");
-
- flags = reader->get_u16();
- units_per_em = reader->get_u16();
- reader->get_date(); // created
- reader->get_date(); // modified
- x_min = reader->get_fword();
- y_min = reader->get_fword();
- x_max = reader->get_fword();
- y_max = reader->get_fword();
- mac_style = reader->get_u16();
- lowest_rec_ppem = reader->get_u16();
- font_direction_hint = reader->get_i16();
- index_to_loc_format = cast(TTF_Index_To_Loc_Format) reader->get_i16();
- glyph_data_format = reader->get_i16();
-}
-
-ttf_lookup_glyph_offset :: (use ttf: ^True_Type_Font, glyph_index: i32) -> i32 {
- loca_table_info := map.get(^tables, string_to_beu32("loca"));
- glyf_table_info := map.get(^tables, string_to_beu32("glyf"));
-
- old: u32;
- defer reader->seek(old);
-
- switch index_to_loc_format {
- case .Long {
- old = reader->seek(loca_table_info.offset + glyph_index * 4);
- return reader->get_u32() + glyf_table_info.offset;
- }
-
- case #default {
- old = reader->seek(loca_table_info.offset + glyph_index * 2);
- return 2 * cast(u32) reader->get_u16() + glyf_table_info.offset;
- }
- }
-
- return -1;
-}
-
-// Result is expected to be freed
-ttf_read_glyph :: (use ttf: ^True_Type_Font, glyph_index: i32, allocator := context.allocator) -> ^TTF_Glyph {
- offset := ttf_lookup_glyph_offset(ttf, glyph_index);
-
- glyf_table_info := map.get(^tables, string_to_beu32("glyf"));
-
- if offset >= glyf_table_info.offset + glyf_table_info.length do return null;
-
- reader->seek(offset);
-
- glyph := make(TTF_Glyph, allocator);
- glyph.contour_count = reader->get_i16();
- glyph.x_min = reader->get_fword();
- glyph.y_min = reader->get_fword();
- glyph.x_max = reader->get_fword();
- glyph.y_max = reader->get_fword();
-
- if glyph.contour_count < 0 { raw_free(allocator, glyph); return null; }
- if glyph.contour_count == -1 {
- // Compound glyph
- return null;
-
- } else {
- // Simple glyph
- ttf_read_simple_glyph(ttf, glyph);
- }
-
- return glyph;
-}
-
-ttf_glyph_destroy :: (glyph: ^TTF_Glyph, allocator := context.allocator) {
- array.free(^glyph.contour_ends);
- array.free(^glyph.points);
- raw_free(allocator, glyph);
-}
-
-#local
-TTF_Glyph_Flags :: enum #flags {
- On_Curve :: 0x01;
- X_Is_Byte :: 0x02;
- Y_Is_Byte :: 0x04;
- Repeat :: 0x08;
- X_Delta :: 0x10;
- Y_Delta :: 0x20;
-}
-
-#local
-ttf_read_simple_glyph :: (use ttf: ^True_Type_Font, glyph: ^TTF_Glyph) {
- array.init(^glyph.contour_ends, ~~glyph.contour_count);
- array.init(^glyph.points);
-
- for i: 0 .. ~~glyph.contour_count {
- array.push(^glyph.contour_ends, reader->get_u16());
- }
-
- reader->seek(~~ reader->get_u16() + reader->tell());
-
- if glyph.contour_count == 0 do return;
-
- num_points := array.fold(^glyph.contour_ends, cast(u16) 0, math.max_poly) + 1;
-
- flags : [..] TTF_Glyph_Flags;
- array.init(^flags);
- defer array.free(^flags);
-
- for i: 0 .. ~~num_points {
- flag := cast(TTF_Glyph_Flags) reader->get_u8();
- array.push(^flags, flag);
- array.push(^glyph.points, .{ on_curve = (flag & .On_Curve) != ~~ 0 });
-
- if (flag & .Repeat) != ~~ 0 {
- rep_count := reader->get_u8();
- i += ~~rep_count;
-
- for i: 0 .. ~~rep_count {
- array.push(^flags, flag);
- array.push(^glyph.points, .{ on_curve = (flag & .On_Curve) != ~~ 0 });
- }
- }
- }
-
- value := cast(i16) 0;
- for i: 0 .. ~~num_points {
- flag := flags[i];
-
- if (flag & .X_Is_Byte) != ~~ 0 {
- if (flag & .X_Delta) != ~~ 0 {
- value += ~~ reader->get_u8();
- } else {
- value -= ~~ reader->get_u8();
- }
- } elseif (flag & .X_Delta) == ~~ 0 {
- value += reader->get_i16();
- }
-
- glyph.points[i].x = value;
- }
-
- value = 0;
- for i: 0 .. ~~num_points {
- flag := flags[i];
-
- if (flag & .Y_Is_Byte) != ~~ 0 {
- if (flag & .Y_Delta) != ~~ 0 {
- value += ~~ reader->get_u8();
- } else {
- value -= ~~ reader->get_u8();
- }
- } elseif (flag & .Y_Delta) == ~~ 0 {
- value += reader->get_i16();
- }
-
- glyph.points[i].y = value;
- }
-}
-
-ttf_glyph_count :: (use ttf: ^True_Type_Font) -> u32 {
- maxp_table_info := map.get(^tables, string_to_beu32("maxp"));
- old := reader->seek(maxp_table_info.offset + 4);
- defer reader->seek(old);
-
- return ~~reader->get_u16();
-}
-
-ttf_read_cmap_table :: (use ttf: ^True_Type_Font) {
- cmap_table_info := map.get(^tables, string_to_beu32("cmap"));
- reader->seek(cmap_table_info.offset);
-
- version := reader->get_u16();
- num_subtables := reader->get_u16();
-
- for i: 0 .. ~~num_subtables {
- platform_id := reader->get_u16();
- platform_specific_id := reader->get_u16();
- offset := reader->get_u16();
-
- // Microsoft Unicode, BMP only
- if platform_id == 3 && platform_specific_id <= 1 {
- ttf_read_cmap(ttf, ~~offset + cmap_table_info.offset);
- }
- }
-}
-
-ttf_read_cmap :: (use ttf: ^True_Type_Font, offset: u32) {
- old := reader->seek(offset);
- defer reader->seek(old);
-
- format := cast(TTF_Cmap_Format) reader->get_u16();
- length := reader->get_u16();
- lang := reader->get_u16();
-
- switch format {
- case .Simple do ttf_read_cmap0(ttf);
- case .Segmented do ttf_read_cmap4(ttf);
-
- case #default { printf("Unsupported cmap format: %i\n", cast(i32) format); }
- }
-}
-
-ttf_read_cmap0 :: (use ttf: ^True_Type_Font) {
- cmap : TTF_Cmap;
- cmap.cmap0.format = .Simple;
-
- glyphs : [..] u8;
- array.init(^glyphs, 256);
- for i: 0 .. 256 do array.push(^glyphs, reader->get_u8());
-
- cmap.cmap0.glyph_indicies = array.to_slice(^glyphs);
-
- array.push(^char_maps, cmap);
-}
-
-ttf_read_cmap4 :: (use ttf: ^True_Type_Font) {
- cmap : TTF_Cmap;
- cmap.cmap4.format = .Segmented;
- imap := ^cmap.cmap4;
- map.init(^imap.cache);
-
- imap.seg_count = reader->get_u16() >> 1;
- imap.search_range = reader->get_u16();
- imap.entry_selector = reader->get_u16();
- imap.range_shift = reader->get_u16();
-
- array.init(^imap.segments, ~~imap.seg_count);
- imap.segments.count = cast(u32) imap.seg_count;
-
- for ^seg: imap.segments do seg.end_code = reader->get_u16();
- reader->get_u16(); // Reserved and unused
- for ^seg: imap.segments do seg.start_code = reader->get_u16();
- for ^seg: imap.segments do seg.id_delta = reader->get_u16();
- for ^seg: imap.segments {
- seg.id_range_offset = reader->get_u16();
- if seg.id_range_offset != ~~0 do seg.id_range_offset += ~~(reader->tell() - 2);
- }
-
- array.push(^char_maps, cmap);
-}
-
-ttf_lookup_glyph_by_char :: (use ttf: ^True_Type_Font, charcode: u32) -> u32 {
- potential_code := 0;
-
- for ^cmap: char_maps {
- switch cmap.format {
- case .Simple do potential_code = ttf_lookup_in_cmap0(ttf, ~~cmap, charcode);
- case .Segmented do potential_code = ttf_lookup_in_cmap4(ttf, ~~cmap, charcode);
- }
-
- if potential_code != 0 do return potential_code;
- }
-
- return potential_code;
-}
-
-#local
-ttf_lookup_in_cmap0 :: (use ttf: ^True_Type_Font, cmap: ^TTF_Cmap0, charcode: u32) -> u32 {
- if charcode < 0 || charcode >= 256 do return 0;
- return ~~cmap.glyph_indicies[charcode];
-}
-
-#local
-ttf_lookup_in_cmap4 :: (use ttf: ^True_Type_Font, cmap: ^TTF_Cmap4, charcode: u32) -> u32 {
- if map.has(^cmap.cache, charcode) do return map.get(^cmap.cache, charcode);
-
- index := 0;
- for ^seg: cmap.segments {
- if ~~seg.start_code <= charcode && ~~charcode <= seg.end_code {
- if seg.id_range_offset != 0 {
- glyph_index_address := ~~seg.id_range_offset + 2 * (charcode - ~~seg.start_code);
- reader->seek(glyph_index_address);
- index = cast(u32) reader->get_u16();
- } else {
- index = (~~seg.id_delta + charcode) & 0xffff;
- }
-
- break;
- }
- }
-
- map.put(^cmap.cache, charcode, index);
-
- return index;
-}
-
-
-ttf_read_hhea_table :: (use ttf: ^True_Type_Font) {
- hhea_table_info := map.get(^tables, string_to_beu32("hhea"));
- reader->seek(hhea_table_info.offset);
-
- hhea.version = reader->get_u32();
- hhea.ascent = reader->get_fword();
- hhea.descent = reader->get_fword();
- hhea.line_gap = reader->get_fword();
- hhea.advance_width_max = reader->get_u16();
- hhea.min_left_side_bearing = reader->get_u16();
- hhea.min_right_side_bearing = reader->get_u16();
- hhea.x_max_extent = reader->get_fword();
- hhea.caret_slope_rise = reader->get_i16();
- hhea.caret_slope_run = reader->get_i16();
- hhea.caret_offset = reader->get_fword();
- reader->get_i16(); // Reserved
- reader->get_i16(); // Reserved
- reader->get_i16(); // Reserved
- reader->get_i16(); // Reserved
- hhea.metric_data_format = reader->get_i16();
- hhea.num_of_long_hor_metrics = reader->get_u16();
-}
-
-TTF_Horizontal_Metrics :: struct {
- advance_width : u16;
- left_side_bearing : i16;
-}
-
-ttf_lookup_horizontal_metrics :: (use ttf: ^True_Type_Font, glyph_index: u32) -> TTF_Horizontal_Metrics {
- hmtx_table_info := map.get(^tables, string_to_beu32("hmtx"));
- offset := hmtx_table_info.offset;
-
- hmtx : TTF_Horizontal_Metrics;
-
- nmets := cast(u32) hhea.num_of_long_hor_metrics;
-
- if glyph_index < nmets {
- offset += glyph_index * 4;
- old := reader->seek(offset);
- defer reader->seek(old);
-
- hmtx.advance_width = reader->get_u16();
- hmtx.left_side_bearing = reader->get_i16();
-
- } else {
- old := reader->seek(offset + (nmets - 1) * 4);
- defer reader->seek(old);
-
- hmtx.advance_width = reader->get_u16();
- reader->seek(offset + nmets * 4 + 2 * (glyph_index - nmets));
- hmtx.left_side_bearing = reader->get_i16();
- }
-
- return hmtx;
-}
-
-
-#local
-ttf_calc_table_checksum :: (reader: ^TTF_Reader, offset: u32, length: u32) -> u32 {
- old := reader->seek(offset);
- defer reader->seek(old);
-
- sum := 0;
- nlongs := (length + 3) >> 2;
- for i: 0 .. nlongs do sum += reader->get_u32();
- return sum;
-}
-
-#local
-string_to_beu32 :: (s: str) -> u32 {
- return (cast(u32) s[0] << 24)
- | (cast(u32) s[1] << 16)
- | (cast(u32) s[2] << 8)
- | (cast(u32) s[3]);
-}
+++ /dev/null
-package ui
-use package core
-
-Button_Theme :: struct {
- use text_theme := Text_Theme.{};
- use animation_theme := Animation_Theme.{};
-
- background_color := gfx.Color4.{ 0.1, 0.1, 0.1 };
- hover_color := gfx.Color4.{ 0.3, 0.3, 0.3 };
- click_color := gfx.Color4.{ 0.5, 0.5, 0.7 };
-
- border_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
- border_width := 6.0f; @InPixels
-}
-
-default_button_theme := Button_Theme.{};
-
-button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site := #callsite, increment := 0) -> bool {
- result := false;
-
- hash := get_site_hash(site, increment);
- animation_state := get_animation(hash);
- mx, my := get_mouse_position();
-
- if is_active_item(hash) {
- if mouse_state.left_button_just_up {
- if is_hot_item(hash) && Rectangle.contains(r, mx, my) {
- result = true;
- animation_state.click_time = 1.0f;
- }
-
- set_active_item(0);
- }
-
- } elseif is_hot_item(hash) {
- if mouse_state.left_button_down {
- set_active_item(hash);
- }
- }
-
- if Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
- }
-
- if is_hot_item(hash) {
- move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed);
-
- #if #defined(set_cursor) {
- set_cursor(Cursors.Pointer);
- }
- } else {
- move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed);
- }
-
- border_width := theme.border_width;
- width, height := Rectangle.dimensions(r);
-
- gfx.set_texture();
- gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color);
-
- surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color);
- surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color);
- gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, surface_color);
-
- use_font(theme.font);
- text_width, text_height := current_font->get_dimensions(text, theme.font_size);
-
- @ThemeConfiguration // This always draws the text centered on the button surface.
- draw_text_raw(text,
- x0 + (width - text_width) / 2,
- y0 + current_font->get_baseline(theme.font_size) + (height - text_height) / 2,
- theme.font, theme.font_size, theme.text_color);
-
- move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
-
- return result;
-}
+++ /dev/null
-package ui
-use package core
-
-Checkbox_Theme :: struct {
- use text_theme := Text_Theme.{};
- use animation_theme := Animation_Theme.{};
-
- box_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
- box_border_width := 4.0f; @InPixels
- box_size := 20.0f; @InPixels
-
- checked_color := gfx.Color4.{ 1, 0, 0 };
- checked_hover_color := gfx.Color4.{ 1, 0.6, 0.6 };
-
- background_color := gfx.Color4.{ 0.05, 0.05, 0.05 }; // Background of the checkbox button.
- hover_color := gfx.Color4.{ 0.3, 0.3, 0.3 };
- click_color := gfx.Color4.{ 0.5, 0.5, 0.7 };
-}
-
-default_checkbox_theme := Checkbox_Theme.{};
-
-checkbox :: (use r: Rectangle, value: ^bool, text: str, theme := ^default_checkbox_theme, site := #callsite, increment := 0) -> bool {
- result := false;
-
- hash := get_site_hash(site, increment);
- animation_state := get_animation(hash);
- mx, my := get_mouse_position();
-
- if is_active_item(hash) {
- if mouse_state.left_button_just_up {
- if is_hot_item(hash) && Rectangle.contains(r, mx, my) {
- result = true;
- *value = !*value;
- animation_state.click_time = 1.0f;
- }
-
- set_active_item(0);
- }
-
- } elseif is_hot_item(hash) {
- if mouse_state.left_button_down {
- set_active_item(hash);
- }
- }
-
- if Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
- }
-
- if is_hot_item(hash) {
- move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed);
- } else {
- move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed);
- }
-
-
- box_border_width := theme.box_border_width;
- box_size := theme.box_size;
- width, height := Rectangle.dimensions(r);
-
- gfx.set_texture();
- gfx.rect(
- .{ x0 + 4, y0 + (height - box_size) / 2 }, @Cleanup @ThemeConfiguration // Arbitrary padding on left
- .{ box_size, box_size },
- color=theme.box_color,
- );
-
- surface_color : gfx.Color4;
- if *value {
- surface_color = theme.checked_color;
- surface_color = color_lerp(animation_state.hover_time, surface_color, theme.checked_hover_color);
-
- } else {
- surface_color = theme.background_color;
- surface_color = color_lerp(animation_state.hover_time, surface_color, theme.hover_color);
- }
-
- surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color);
-
- gfx.rect(
- .{ x0 + 4 + box_border_width, y0 + (height - box_size) / 2 + box_border_width },
- .{ box_size - box_border_width * 2, box_size - box_border_width * 2 },
- surface_color
- );
-
- use_font(theme.font);
- text_width, text_height := current_font->get_dimensions(text, theme.font_size);
-
- draw_text_raw(
- text,
- x0 + box_size + 4 * 2, @Cleanup @ThemeConfiguration
- y0 + current_font->get_baseline(theme.font_size) + (height - text_height) / 2,
- theme.font, theme.font_size, theme.text_color);
-
- move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
-
- return result;
-}
+++ /dev/null
-package ui
-use package core
-
-Radio_Theme :: struct {
- use text_theme := Text_Theme.{};
- use animation_theme := Animation_Theme.{};
-
- radio_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
- radio_border_radius := 4.0f; @InPixels
- radio_radius := 12.0f; @InPixels
-
- selected_color := gfx.Color4.{ 1, 0, 0 };
- selected_hover_color := gfx.Color4.{ 1, 0.6, 0.6 };
-
- background_color := gfx.Color4.{ 0.05, 0.05, 0.05 };
- hover_color := gfx.Color4.{ 0.3, 0.3, 0.3 };
- click_color := gfx.Color4.{ 0.5, 0.5, 0.7 };
-}
-
-default_radio_theme := Radio_Theme.{};
-
-radio :: (use r: Rectangle, selected: ^$T, value: T, text: str, theme := ^default_radio_theme, site := #callsite, increment := 0) -> bool {
- result := false;
-
- hash := get_site_hash(site, increment);
- animation_state := get_animation(hash);
-
- mx, my := get_mouse_position();
-
- if is_active_item(hash) {
- if mouse_state.left_button_just_up {
- if is_hot_item(hash) && Rectangle.contains(r, mx, my) {
- result = true;
- *selected = value;
- animation_state.click_time = 1.0f;
- }
-
- set_active_item(0);
- }
-
- } elseif is_hot_item(hash) {
- if mouse_state.left_button_down {
- set_active_item(hash);
- }
- }
-
- if Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
- }
-
- if is_hot_item(hash) {
- move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed);
-
- #if #defined(set_cursor) {
- set_cursor(Cursors.Pointer);
- }
- } else {
- move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed);
- }
-
- radius := theme.radio_radius;
- width, height := Rectangle.dimensions(r);
-
- cx, cy := x0 + radius, y0 + height / 2;
-
- gfx.set_texture();
- gfx.circle(.{ cx, cy }, radius, color=theme.radio_color);
-
- surface_color : gfx.Color4;
- if *selected == value {
- surface_color = theme.selected_color;
- surface_color = color_lerp(animation_state.hover_time, surface_color, theme.selected_hover_color);
-
- } else {
- surface_color = theme.background_color;
- surface_color = color_lerp(animation_state.hover_time, surface_color, theme.hover_color);
- }
-
- surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color);
-
- gfx.circle(.{ cx, cy }, radius - theme.radio_border_radius, color=surface_color);
-
- use_font(theme.font);
- text_width, text_height := current_font->get_dimensions(text, theme.font_size);
-
- draw_text_raw(
- text,
- x0 + 2 * radius + 4, @ThemeConfiguration
- y0 + current_font->get_baseline(theme.font_size) + (height - text_height) / 2,
- theme.font, theme.font_size, theme.text_color);
-
- move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
-
- return result;
-}
+++ /dev/null
-package ui
-
-use package core
-
-Scrollable_Region_State :: struct {
- transform: gfx.Transform = .{
- translation = .{ 0, 0 },
- scale = .{ 1, 1 },
- };
-}
-
-#package
-scrollable_region_states : Map(UI_Id, Scrollable_Region_State);
-
-Scrollable_Region_Controls :: struct {
- minimum_y := 0.0f;
- maximum_y := 340000000000000000000000000000000000000.0f; // Senseless default
- minimum_x := 0.0f;
- maximum_x := 340000000000000000000000000000000000000.0f; // Senseless default
-}
-
-Scrollable_Region_Handle :: struct {
- rect: Rectangle;
- state: ^Scrollable_Region_State;
-
- get_visible_rectangle :: (use this: ^Scrollable_Region_Handle) -> Rectangle {
- trans := ^state.transform;
- x0 := (rect.x0 - trans.translation.x) / trans.scale.x;
- y0 := (rect.y0 - trans.translation.y) / trans.scale.y;
- x1 := (rect.x1 - trans.translation.x) / trans.scale.x;
- y1 := (rect.y1 - trans.translation.y) / trans.scale.y;
-
- return .{ x0, y0, x1, y1 };
- }
-}
-
-scrollable_region_start :: (use r: Rectangle, use src: Scrollable_Region_Controls = .{},
- site := #callsite, increment := 0,
- state: ^Scrollable_Region_State = null) -> Scrollable_Region_Handle {
- hash := get_site_hash(site, increment);
- x, y := Rectangle.top_left(r);
- width, height := Rectangle.dimensions(r);
-
- if state == null {
- state = map.get_ptr(^scrollable_region_states, hash);
-
- if state == null {
- map.put(^scrollable_region_states, hash, .{});
- state = map.get_ptr(^scrollable_region_states, hash);
- }
- }
-
- mx, my := get_mouse_position();
- if Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
- }
-
- if is_hot_item(hash) {
- speed :: 30.0f; @ThemeConfiguration
-
- if is_key_down(38) do state.transform.translation.y += speed;
- if is_key_down(40) do state.transform.translation.y -= speed;
- if is_key_down(37) do state.transform.translation.x -= speed;
- if is_key_down(39) do state.transform.translation.x += speed;
-
- if mouse_state.dwheel > 0 do state.transform.translation.y += speed;
- if mouse_state.dwheel < 0 do state.transform.translation.y -= speed;
-
- state.transform.translation.y = math.clamp(state.transform.translation.y, -maximum_y, minimum_y);
- state.transform.translation.x = math.clamp(state.transform.translation.x, -maximum_x, minimum_x);
- }
-
- gfx.push_scissor(x, y, width, height);
- gfx.push_matrix();
- gfx.apply_transform(state.transform);
-
- return .{ r, state };
-}
-
-scrollable_region_stop :: () {
- gfx.pop_scissor();
- gfx.pop_matrix();
-}
+++ /dev/null
-package ui
-
-use package core
-
-Slider_Theme :: struct {
- use text_theme := Text_Theme.{};
- use animation_theme := Animation_Theme.{};
-
- box_color := gfx.Color4.{ 0.1, 0.1, 0.1 };
- box_border_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
- box_border_width := 4.0f; @InPixels
-
- bar_color := gfx.Color4.{ 0.4, 0.4, 0.4 };
- bar_hover_color := gfx.Color4.{ 0, 0, 1 };
- bar_hover_negative_color := gfx.Color4.{ 1, 0, 0 }; // The color when value is less than 0
-}
-
-default_slider_theme := Slider_Theme.{};
-
-slider :: (use r: Rectangle, value: ^$T, min_value: T, max_value: T, theme := ^default_slider_theme, site := #callsite, increment := 0) -> bool {
- result := false;
-
- hash := get_site_hash(site, increment);
- animation_state := get_animation(hash);
- width, height := Rectangle.dimensions(r);
- mx, my := get_mouse_position();
-
- if is_hot_item(hash) {
- if mouse_state.left_button_down {
- set_active_item(hash);
- result = true;
-
- // Animate this?
- x := mx - x0;
-
- if T == i32 || T == i64 || T == u32 || T == u64 {
- step_width := width / ~~math.abs(max_value - min_value);
- percent := (x + step_width / 2) / width;
- *value = math.lerp(percent, min_value, max_value);
- *value = math.clamp(*value, min_value, max_value);
-
- } else {
- percent := x / width;
- *value = math.lerp(percent, min_value, max_value);
- *value = math.clamp(*value, min_value, max_value);
- }
-
- } else {
- set_active_item(0);
- }
- }
-
- if Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
- }
-
- if is_hot_item(hash) {
- move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed);
- } else {
- move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed);
- }
-
- box_border_width := theme.box_border_width;
-
- bar_color := theme.bar_color;
- if *value < 0 do bar_color = color_lerp(animation_state.hover_time, bar_color, theme.bar_hover_negative_color);
- else do bar_color = color_lerp(animation_state.hover_time, bar_color, theme.bar_hover_color);
-
- gfx.set_texture();
- gfx.rect(.{ x0, y0 }, .{ width, height }, theme.box_border_color);
- gfx.rect(
- .{ x0 + box_border_width, y0 + box_border_width },
- .{ width - box_border_width * 2, height - box_border_width * 2 },
- theme.box_border_color);
-
- box_width := cast(f32) (*value - min_value) / ~~(max_value - min_value);
- box_width *= width - box_border_width * 2;
- box_width = math.clamp(box_width, 0, width - box_border_width * 2);
- gfx.rect(
- .{ x0 + box_border_width, y0 + box_border_width },
- .{ box_width, height - box_border_width * 2 },
- bar_color);
-
- return result;
-}
+++ /dev/null
-package ui
-use package core
-
-Textbox_Theme :: struct {
- use text_theme := Text_Theme.{
- text_color = .{ 0, 0, 0 }
- // text_color = .{1, 1, 1}
- };
-
- use animation_theme := Animation_Theme.{};
-
- // background_color := gfx.Color4.{ 0.1, 0.1, 0.1 };
- // hover_color := gfx.Color4.{ 0.3, 0.3, 0.3 };
- // click_color := gfx.Color4.{ 0.5, 0.5, 0.7 };
-
- background_color := gfx.Color4.{ 0.8, 0.8, 0.8 };
- hover_color := gfx.Color4.{ 1.0, 1.0, 1.0 };
- click_color := gfx.Color4.{ 0.5, 0.5, 0.7 };
-
- border_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
- border_width := 6.0f; @InPixels
-
- cursor_color := gfx.Color4.{ 0.5, 0.5, 0.5 };
- cursor_width := 4.0f; @InPixels
- cursor_blink_speed := 0.04f; // Bigger is faster
-
- placeholder_text_color := gfx.Color4.{ 0.5, 0.5, 0.5 };
-}
-
-default_textbox_theme := Textbox_Theme.{};
-
-#local
-Textbox_Editing_State :: struct {
- hash: UI_Id = 0;
-
- cursor_position: i32 = 0;
-
- cursor_animation := 0.0f;
- cursor_animation_speed := 0.02f;
-}
-
-#package
-// There is only one 'Textbox_Editing_State', not a map of them because there can only be one textbox being edited at once.
-textbox_editing_state := Textbox_Editing_State.{};
-
-textbox :: (use r: Rectangle, text_buffer: ^string.String_Buffer, placeholder := null_str, theme := ^default_textbox_theme, site := #callsite, increment := 0) -> bool {
- result := false;
-
- hash := get_site_hash(site, increment);
- animation_state := get_animation(hash);
- mx, my := get_mouse_position();
-
- border_width := theme.border_width;
- width, height := Rectangle.dimensions(r);
-
- text_color := theme.text_color;
- text := string.buffer_to_str(text_buffer);
- if text.count == 0 && placeholder.count > 0 {
- text = placeholder;
- text_color = theme.placeholder_text_color;
- }
-
- use_font(theme.font);
- text_width, text_height := current_font->get_dimensions(text, theme.font_size);
-
- text_x := x0 + border_width;
- text_y := y0 + current_font->get_baseline(theme.font_size) + (height - text_height) / 2;
-
- if is_hot_item(hash) && !is_active_item(hash) {
- if mouse_state.left_button_down && Rectangle.contains(r, mx, my) {
- set_active_item(hash);
- textbox_editing_state.hash = hash;
- textbox_editing_state.cursor_animation_speed = theme.cursor_blink_speed;
-
- // animation_state.click_time = 1.0f;
- }
- }
-
- if is_active_item(hash) {
- if mouse_state.left_button_just_down && !Rectangle.contains(r, mx, my) {
- set_active_item(0);
- textbox_editing_state.hash = 0;
- textbox_editing_state.cursor_position = 0;
- }
- }
-
- if Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
-
- #if #defined(set_cursor) {
- if is_hot_item(hash) do set_cursor(Cursors.Text);
- }
- }
-
- if textbox_editing_state.hash == hash {
- // This is the actively edited textbox
- move_towards(^textbox_editing_state.cursor_animation, 0.0f, textbox_editing_state.cursor_animation_speed);
- if textbox_editing_state.cursor_animation <= 0.0f do textbox_editing_state.cursor_animation = 1.0f;
-
- if mouse_state.left_button_down && Rectangle.contains(r, mx, my) {
- textbox_editing_state.cursor_animation = 1.0f;
- textbox_editing_state.cursor_position = get_cursor_position(text_buffer, text_x, text_y, theme.font_size, mx, my);
- }
-
- if keyboard_state.keys_down_this_frame > 0 {
- for key_index: keyboard_state.keys_down_this_frame {
- key := keyboard_state.keycodes_down_this_frame[key_index];
-
- @KeycodeIsWrong
- switch key.code {
- case 0x25 do textbox_editing_state.cursor_position -= 1;
- case 0x27 do textbox_editing_state.cursor_position += 1;
- case 0x23 do textbox_editing_state.cursor_position = text_buffer.count;
- case 0x24 do textbox_editing_state.cursor_position = 0;
-
- case 0x08 {
- // Backspace
- if string.buffer_delete(text_buffer, textbox_editing_state.cursor_position) {
- textbox_editing_state.cursor_position -= 1;
- }
- }
-
- case 0x2E {
- // Delete
- string.buffer_delete(text_buffer, textbox_editing_state.cursor_position + 1);
- }
-
- case #default {
- shift_is_pressed := key.modifiers & .SHIFT;
- index := key.code * 2;
- if shift_is_pressed do index += 1;
-
- char := key_map[index];
- if char != #char "\0" {
- if string.buffer_insert(text_buffer, textbox_editing_state.cursor_position, char) {
- textbox_editing_state.cursor_position += 1;
- }
- }
- }
- }
-
- textbox_editing_state.cursor_position = math.clamp(textbox_editing_state.cursor_position, 0, text_buffer.count);
- textbox_editing_state.cursor_animation = 1.0f;
- }
- }
- }
-
- if is_hot_item(hash) {
- move_towards(^animation_state.hover_time, 1.0f, theme.hover_speed);
- } else {
- move_towards(^animation_state.hover_time, 0.0f, theme.hover_speed);
- }
-
- gfx.set_texture();
- gfx.push_scissor(x0, y0, width, height);
- gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color);
-
- surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color);
- surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color);
- gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, surface_color);
-
- draw_text_raw(text, text_x, text_y, theme.font, theme.font_size, text_color);
-
- if textbox_editing_state.hash == hash {
- cursor_x := get_cursor_location(text_buffer, text_x, text_y, theme.font_size, textbox_editing_state.cursor_position);
- cursor_y := y0 + theme.border_width;
- cursor_w := theme.cursor_width;
- cursor_h := height - theme.border_width * 2;
-
- cursor_color := theme.cursor_color;
- cursor_color.a = textbox_editing_state.cursor_animation;
-
- draw_rect(
- .{ cursor_x, cursor_y, cursor_x + cursor_w, cursor_y + cursor_h },
- color=cursor_color);
- }
-
- gfx.pop_scissor();
-
- move_towards(^animation_state.click_time, 0.0f, theme.click_decay_speed);
-
- return result;
-}
-
-#local
-get_cursor_location :: (text_buffer: ^string.String_Buffer, text_x: f32, text_y: f32, text_size: f32, cursor_position: i32) -> f32 {
- countdown := cursor_position + 1;
- last_x : f32 = text_x;
- last_w : f32;
-
- text := string.buffer_to_str(text_buffer);
-
- bm_font := ^current_font.font;
- for glyph: bmfont.get_character_positions(bm_font, text_size * current_font.em / ~~bm_font.common.line_height, text, text_x, text_y) {
- if countdown == 0 do return last_x;
-
- last_x = glyph.pos_x;
- last_w = glyph.x_advance;
-
- countdown -= 1;
- }
-
- if countdown == 0 do return last_x;
-
- return last_x + last_w;
-}
-
-#local
-get_cursor_position :: (text_buffer: ^string.String_Buffer, text_x: f32, text_y: f32, text_size: f32, mouse_x: f32, mouse_y: f32) -> i32 {
- cursor_position := 0;
-
- last_x: f32 = text_x;
- text := string.buffer_to_str(text_buffer);
-
- @FontCleanup
- bm_font := ^current_font.font;
- for glyph: bmfont.get_character_positions(bm_font, text_size * current_font.em / ~~bm_font.common.line_height, text, text_x, text_y) {
- cursor_position += 1;
- if cursor_position == 1 do continue;
-
- @Incomplete // This is still very wrong but it is better than nothing
- if mouse_x <= glyph.pos_x + glyph.pos_w / 2 && mouse_x >= last_x {
- return cursor_position - 1;
- }
-
- last_x = glyph.pos_x + glyph.pos_w / 2;
- }
-
- return text_buffer.count;
-}
-
-@Relocate @Cleanup
-// This keymap is very wrong in a lot of ways. It works for my standard US keyboard, but will break horribly
-// for any other keyboard layout. I would like to use something else from the browser, but unsurprisingly the
-// browser does not make this easy. Gotta love web "standards"....
-key_map := u8.[
- // Keycode Normal Shift
- /* 00 */ #char "\0", #char "\0",
- /* 01 */ #char "\0", #char "\0",
- /* 02 */ #char "\0", #char "\0",
- /* 03 */ #char "\0", #char "\0",
- /* 04 */ #char "\0", #char "\0",
- /* 05 */ #char "\0", #char "\0",
- /* 06 */ #char "\0", #char "\0",
- /* 07 */ #char "\0", #char "\0",
- /* 08 */ #char "\0", #char "\0",
- /* 09 */ #char "\0", #char "\0",
- /* 10 */ #char "\0", #char "\0",
- /* 11 */ #char "\0", #char "\0",
- /* 12 */ #char "\0", #char "\0",
- /* 13 */ #char "\0", #char "\0",
- /* 14 */ #char "\0", #char "\0",
- /* 15 */ #char "\0", #char "\0",
- /* 16 */ #char "\0", #char "\0",
- /* 17 */ #char "\0", #char "\0",
- /* 18 */ #char "\0", #char "\0",
- /* 19 */ #char "\0", #char "\0",
- /* 20 */ #char "\0", #char "\0",
- /* 21 */ #char "\0", #char "\0",
- /* 22 */ #char "\0", #char "\0",
- /* 23 */ #char "\0", #char "\0",
- /* 24 */ #char "\0", #char "\0",
- /* 25 */ #char "\0", #char "\0",
- /* 26 */ #char "\0", #char "\0",
- /* 27 */ #char "\0", #char "\0",
- /* 28 */ #char "\0", #char "\0",
- /* 29 */ #char "\0", #char "\0",
- /* 30 */ #char "\0", #char "\0",
- /* 31 */ #char "\0", #char "\0",
- /* 32 */ #char " ", #char " ",
- /* 33 */ #char "\0", #char "\0",
- /* 34 */ #char "\0", #char "\0",
- /* 35 */ #char "\0", #char "\0",
- /* 36 */ #char "\0", #char "\0",
- /* 37 */ #char "\0", #char "\0",
- /* 38 */ #char "\0", #char "\0",
- /* 39 */ #char "\0", #char "\0",
- /* 40 */ #char "\0", #char "\0",
- /* 41 */ #char "\0", #char "\0",
- /* 42 */ #char "\0", #char "\0",
- /* 43 */ #char "\0", #char "\0",
- /* 44 */ #char "\0", #char "\0",
- /* 45 */ #char "\0", #char "\0",
- /* 46 */ #char "\0", #char "\0",
- /* 47 */ #char "\0", #char "\0",
- /* 48 */ #char "0", #char ")",
- /* 49 */ #char "1", #char "!",
- /* 50 */ #char "2", #char "@",
- /* 51 */ #char "3", #char "#",
- /* 52 */ #char "4", #char "$",
- /* 53 */ #char "5", #char "%",
- /* 54 */ #char "6", #char "^",
- /* 55 */ #char "7", #char "&",
- /* 56 */ #char "8", #char "*",
- /* 57 */ #char "9", #char "(",
- /* 58 */ #char "\0", #char "\0",
- /* 59 */ #char ";", #char ":",
- /* 60 */ #char "\0", #char "\0",
- /* 61 */ #char "=", #char "+",
- /* 62 */ #char "\0", #char "\0",
- /* 63 */ #char "\0", #char "\0",
- /* 64 */ #char "\0", #char "\0",
- /* 65 */ #char "a", #char "A",
- /* 66 */ #char "b", #char "B",
- /* 67 */ #char "c", #char "C",
- /* 68 */ #char "d", #char "D",
- /* 69 */ #char "e", #char "E",
- /* 70 */ #char "f", #char "F",
- /* 71 */ #char "g", #char "G",
- /* 72 */ #char "h", #char "H",
- /* 73 */ #char "i", #char "I",
- /* 74 */ #char "j", #char "J",
- /* 75 */ #char "k", #char "K",
- /* 76 */ #char "l", #char "L",
- /* 77 */ #char "m", #char "M",
- /* 78 */ #char "n", #char "N",
- /* 79 */ #char "o", #char "O",
- /* 80 */ #char "p", #char "P",
- /* 81 */ #char "q", #char "Q",
- /* 82 */ #char "r", #char "R",
- /* 83 */ #char "s", #char "S",
- /* 84 */ #char "t", #char "T",
- /* 85 */ #char "u", #char "U",
- /* 86 */ #char "v", #char "V",
- /* 87 */ #char "w", #char "W",
- /* 88 */ #char "x", #char "X",
- /* 89 */ #char "y", #char "Y",
- /* 90 */ #char "z", #char "Z",
- /* 91 */ #char "\0", #char "\0",
- /* 92 */ #char "\0", #char "\0",
- /* 93 */ #char "\0", #char "\0",
- /* 94 */ #char "\0", #char "\0",
- /* 95 */ #char "\0", #char "\0",
- /* 96 */ #char "\0", #char "\0",
- /* 97 */ #char "\0", #char "\0",
- /* 98 */ #char "\0", #char "\0",
- /* 99 */ #char "\0", #char "\0",
- /* 100 */ #char "\0", #char "\0",
- /* 101 */ #char "\0", #char "\0",
- /* 102 */ #char "\0", #char "\0",
- /* 103 */ #char "\0", #char "\0",
- /* 104 */ #char "\0", #char "\0",
- /* 105 */ #char "\0", #char "\0",
- /* 106 */ #char "\0", #char "\0",
- /* 107 */ #char "\0", #char "\0",
- /* 108 */ #char "\0", #char "\0",
- /* 109 */ #char "\0", #char "\0",
- /* 110 */ #char "\0", #char "\0",
- /* 111 */ #char "\0", #char "\0",
- /* 112 */ #char "\0", #char "\0",
- /* 113 */ #char "\0", #char "\0",
- /* 114 */ #char "\0", #char "\0",
- /* 115 */ #char "\0", #char "\0",
- /* 116 */ #char "\0", #char "\0",
- /* 117 */ #char "\0", #char "\0",
- /* 118 */ #char "\0", #char "\0",
- /* 119 */ #char "\0", #char "\0",
- /* 120 */ #char "\0", #char "\0",
- /* 121 */ #char "\0", #char "\0",
- /* 122 */ #char "\0", #char "\0",
- /* 123 */ #char "\0", #char "\0",
- /* 124 */ #char "\0", #char "\0",
- /* 125 */ #char "\0", #char "\0",
- /* 126 */ #char "\0", #char "\0",
- /* 127 */ #char "\0", #char "\0",
- /* 128 */ #char "\0", #char "\0",
- /* 129 */ #char "\0", #char "\0",
- /* 130 */ #char "\0", #char "\0",
- /* 131 */ #char "\0", #char "\0",
- /* 132 */ #char "\0", #char "\0",
- /* 133 */ #char "\0", #char "\0",
- /* 134 */ #char "\0", #char "\0",
- /* 135 */ #char "\0", #char "\0",
- /* 136 */ #char "\0", #char "\0",
- /* 137 */ #char "\0", #char "\0",
- /* 138 */ #char "\0", #char "\0",
- /* 139 */ #char "\0", #char "\0",
- /* 140 */ #char "\0", #char "\0",
- /* 141 */ #char "\0", #char "\0",
- /* 142 */ #char "\0", #char "\0",
- /* 143 */ #char "\0", #char "\0",
- /* 144 */ #char "\0", #char "\0",
- /* 145 */ #char "\0", #char "\0",
- /* 146 */ #char "\0", #char "\0",
- /* 147 */ #char "\0", #char "\0",
- /* 148 */ #char "\0", #char "\0",
- /* 149 */ #char "\0", #char "\0",
- /* 150 */ #char "\0", #char "\0",
- /* 151 */ #char "\0", #char "\0",
- /* 152 */ #char "\0", #char "\0",
- /* 153 */ #char "\0", #char "\0",
- /* 154 */ #char "\0", #char "\0",
- /* 155 */ #char "\0", #char "\0",
- /* 156 */ #char "\0", #char "\0",
- /* 157 */ #char "\0", #char "\0",
- /* 158 */ #char "\0", #char "\0",
- /* 159 */ #char "\0", #char "\0",
- /* 160 */ #char "\0", #char "\0",
- /* 161 */ #char "\0", #char "\0",
- /* 162 */ #char "\0", #char "\0",
- /* 163 */ #char "\0", #char "\0",
- /* 164 */ #char "\0", #char "\0",
- /* 165 */ #char "\0", #char "\0",
- /* 166 */ #char "\0", #char "\0",
- /* 167 */ #char "\0", #char "\0",
- /* 168 */ #char "\0", #char "\0",
- /* 169 */ #char "\0", #char "\0",
- /* 170 */ #char "\0", #char "\0",
- /* 171 */ #char "\0", #char "\0",
- /* 172 */ #char "\0", #char "\0",
- /* 173 */ #char "-", #char "_",
- /* 174 */ #char "\0", #char "\0",
- /* 175 */ #char "\0", #char "\0",
- /* 176 */ #char "\0", #char "\0",
- /* 177 */ #char "\0", #char "\0",
- /* 178 */ #char "\0", #char "\0",
- /* 179 */ #char "\0", #char "\0",
- /* 180 */ #char "\0", #char "\0",
- /* 181 */ #char "\0", #char "\0",
- /* 182 */ #char "\0", #char "\0",
- /* 183 */ #char "\0", #char "\0",
- /* 184 */ #char "\0", #char "\0",
- /* 185 */ #char "\0", #char "\0",
- /* 186 */ #char ";", #char ":",
- /* 187 */ #char "=", #char "+",
- /* 188 */ #char ",", #char "<",
- /* 189 */ #char "-", #char "_",
- /* 190 */ #char ".", #char ">",
- /* 191 */ #char "/", #char "?",
- /* 192 */ #char "`", #char "~",
- /* 193 */ #char "\0", #char "\0",
- /* 194 */ #char "\0", #char "\0",
- /* 195 */ #char "\0", #char "\0",
- /* 196 */ #char "\0", #char "\0",
- /* 197 */ #char "\0", #char "\0",
- /* 198 */ #char "\0", #char "\0",
- /* 199 */ #char "\0", #char "\0",
- /* 200 */ #char "\0", #char "\0",
- /* 201 */ #char "\0", #char "\0",
- /* 202 */ #char "\0", #char "\0",
- /* 203 */ #char "\0", #char "\0",
- /* 204 */ #char "\0", #char "\0",
- /* 205 */ #char "\0", #char "\0",
- /* 206 */ #char "\0", #char "\0",
- /* 207 */ #char "\0", #char "\0",
- /* 208 */ #char "\0", #char "\0",
- /* 209 */ #char "\0", #char "\0",
- /* 210 */ #char "\0", #char "\0",
- /* 211 */ #char "\0", #char "\0",
- /* 212 */ #char "\0", #char "\0",
- /* 213 */ #char "\0", #char "\0",
- /* 214 */ #char "\0", #char "\0",
- /* 215 */ #char "\0", #char "\0",
- /* 216 */ #char "\0", #char "\0",
- /* 217 */ #char "\0", #char "\0",
- /* 218 */ #char "\0", #char "\0",
- /* 219 */ #char "[", #char "{",
- /* 220 */ #char "\\", #char "|",
- /* 221 */ #char "]", #char "}",
- /* 222 */ #char "'", #char "\"",
- /* 223 */ #char "\0", #char "\0",
- /* 224 */ #char "\0", #char "\0",
- /* 225 */ #char "\0", #char "\0",
- /* 226 */ #char "\0", #char "\0",
- /* 227 */ #char "\0", #char "\0",
- /* 228 */ #char "\0", #char "\0",
- /* 229 */ #char "\0", #char "\0",
-];
+++ /dev/null
-package ui
-
-use package core
-use package core.intrinsics.onyx { __initialize }
-
-Workspace_State :: struct {
- transform: gfx.Transform = .{
- translation = .{ 0, 0 },
- scale = .{ 1, 1 },
- };
-
- @Transient
- target_transform: gfx.Transform = .{
- translation = .{ 0, 0 },
- scale =. { 1, 1 },
- };
-
- transform_transition := 0.0f;
-
- dragging := false;
-}
-
-#package
-workspace_states : Map(UI_Id, Workspace_State);
-
-workspace_start :: (use r: Rectangle, site := #callsite, state: ^Workspace_State = null) {
- hash := get_site_hash(site, 0);
- x, y := Rectangle.top_left(r);
- width, height := Rectangle.dimensions(r);
-
- @Hack // This whole situtation is a hack of trying to a pointer to a valid state.
- if state == null {
- if state = map.get_ptr(^workspace_states, hash); state == null {
- map.put(^workspace_states, hash, .{});
- state = map.get_ptr(^workspace_states, hash);
- }
- }
-
- if state.transform_transition > 0.0f {
- move_towards(^state.transform_transition, 0, 0.08f);
-
- if state.transform_transition == 0.0f {
- state.transform.translation.x = state.target_transform.translation.x;
- state.transform.translation.y = state.target_transform.translation.y;
-
- } else {
- state.transform.translation.x = (state.transform.translation.x + state.target_transform.translation.x) / 2;
- state.transform.translation.y = (state.transform.translation.y + state.target_transform.translation.y) / 2;
- }
- }
-
- if mx, my := get_mouse_position();
- Rectangle.contains(r, mx, my) {
- set_hot_item(hash);
- }
-
- if is_hot_item(hash) {
- speed :: 30.0f; @ThemeConfiguration
- scale_speed :: 0.02f; @ThemeConfiguration
-
- if is_key_down(38) do state.transform.translation.y += speed;
- if is_key_down(40) do state.transform.translation.y -= speed;
- if is_key_down(39) do state.transform.translation.x -= speed;
- if is_key_down(37) do state.transform.translation.x += speed;
-
- // These keys are weird because keycode is not standard between all browsers... ugh
- if is_key_down(187) || is_key_down(61) do workspace_zoom(state, r, 1.02);
- if is_key_down(189) || is_key_down(173) do workspace_zoom(state, r, 0.98);
-
- if mouse_state.left_button_just_down && !state.dragging {
- state.dragging = true;
- }
-
- if state.dragging {
- if !mouse_state.left_button_down {
- state.dragging = false;
-
- } else {
- dx, dy := get_mouse_delta();
- state.transform.translation.x -= dx;
- state.transform.translation.y -= dy;
- }
- }
-
- if mouse_state.dwheel > 0 do workspace_zoom(state, r, 1.04);
- if mouse_state.dwheel < 0 do workspace_zoom(state, r, 0.96);
-
- } else {
- state.dragging = false;
- }
-
- gfx.push_scissor(x, y, width, height);
- gfx.push_matrix();
- gfx.apply_transform(state.transform);
-
-}
-
-workspace_end :: () {
- gfx.pop_scissor();
- gfx.pop_matrix();
-}
-
-workspace_zoom :: (state: ^Workspace_State, r: Rectangle, scale := 1.0f) {
- x, y := Rectangle.top_left(r);
- width, height := Rectangle.dimensions(r);
-
- bx: f32 = (state.transform.translation.x - (width / 2) - x) / state.transform.scale.x;
- by: f32 = (state.transform.translation.y - (height / 2) - y) / state.transform.scale.y;
-
- state.transform.scale.x *= scale;
- state.transform.scale.y *= scale;
-
- state.transform.translation.x = bx * state.transform.scale.x + (width / 2) + x;
- state.transform.translation.y = by * state.transform.scale.y + (height / 2) + y;
-}
\ No newline at end of file
+++ /dev/null
-package ui
-
-// UI Flow
-
-Flow :: struct {
- split_vertical :: #match {
- (r: Rectangle, left_percent: f32, padding := 0.0f) -> (left: Rectangle, right: Rectangle) {
- return split_vertical(r, left_width=left_percent * Rectangle.width(r), padding=padding);
- },
-
- (r: Rectangle, right_percent: f32, padding := 0.0f) -> (left: Rectangle, right: Rectangle) {
- return split_vertical(r, right_width=right_percent * Rectangle.width(r), padding=padding);
- },
-
- (r: Rectangle, left_width: f32, padding := 0.0f) -> (left: Rectangle, right: Rectangle) {
- x0, y0 := Rectangle.top_left(r);
- x1, y1 := Rectangle.bottom_right(r);
-
- return .{ x0=x0, x1=x0+left_width, y0=y0, y1=y1 },
- .{ x0=x0+left_width+padding, x1=x1, y0=y0, y1=y1 };
- },
-
- (r: Rectangle, right_width: f32, padding := 0.0f) -> (left: Rectangle, right: Rectangle) {
- x0, y0 := Rectangle.top_left(r);
- x1, y1 := Rectangle.bottom_right(r);
-
- return .{ x0=x0, x1=x1-right_width-padding, y0=y0, y1=y1 },
- .{ x0=x1-right_width, x1=x1, y0=y0, y1=y1 };
- }
- }
-
-
- split_horizontal :: #match {
- (r: Rectangle, top_percent: f32, padding := 0.0f) -> (top: Rectangle, bottom: Rectangle) {
- return split_horizontal(r, top_height=top_percent * Rectangle.height(r), padding=padding);
- },
-
- (r: Rectangle, bottom_percent: f32, padding := 0.0f) -> (top: Rectangle, bottom: Rectangle) {
- return split_horizontal(r, bottom_height=bottom_percent * Rectangle.height(r), padding=padding);
- },
-
- (r: Rectangle, top_height: f32, padding := 0.0f) -> (top: Rectangle, bottom: Rectangle) {
- x0, y0 := Rectangle.top_left(r);
- x1, y1 := Rectangle.bottom_right(r);
-
- return .{ x0=x0, x1=x1, y0=y0, y1=math.max(y0, y0+top_height) },
- .{ x0=x0, x1=x1, y0=math.min(y1, y0+top_height+padding), y1=y1 };
- },
-
- (r: Rectangle, bottom_height: f32, padding := 0.0f) -> (top: Rectangle, bottom: Rectangle) {
- x0, y0 := Rectangle.top_left(r);
- x1, y1 := Rectangle.bottom_right(r);
-
- return .{ x0=x0, x1=x1, y0=y0, y1=math.max(y0, y1-bottom_height-padding) },
- .{ x0=x0, x1=x1, y0=math.min(y1,y1-bottom_height), y1=y1 };
- }
- }
-
-
- padding :: (r: Rectangle, top := 0.0f, bottom := 0.0f, left := 0.0f, right := 0.0f) -> Rectangle {
- x0, y0 := Rectangle.top_left(r);
- x1, y1 := Rectangle.bottom_right(r);
-
- return .{ x0=x0 + left, x1=x1 - right, y0=y0 + top, y1=y1 - bottom };
- }
-}
+++ /dev/null
-package ui
-
-// A simple wrapper for a BMFont and an OpenGL Texture
-
-#local RK :: enum { Luminance; Color; }
-
-Font :: struct {
- texture : gfx.Texture;
- font : bmfont.BMFont;
-
- em: f32 = 32;
- rendering_kind := RK.Luminance;
-
- get_width :: (use f: ^Font, text: str, font_size: f32) -> f32 {
- size := font_size * (em / ~~font.common.line_height);
- return bmfont.get_width(^font, text, size);
- }
-
- get_height :: (use f: ^Font, text: str, font_size: f32) -> f32 {
- size := font_size * (em / ~~font.common.line_height);
- return bmfont.get_height(^font, text, size);
- }
-
- get_dimensions :: (use f: ^Font, text: str, font_size: f32) -> (width: f32, height: f32) {
- size := font_size * (em / ~~font.common.line_height);
- return bmfont.get_width(^font, text, size),
- bmfont.get_height(^font, text, size);
- }
-
- get_baseline :: (use f: ^Font, font_size: f32) -> f32 {
- size := font_size * (em / ~~font.common.line_height);
- return ~~font.common.baseline * size;
- }
-
- render :: (use f: ^Font, text: str, x, y: f32, font_size: f32, color := gfx.Color4.{1,1,1}) {
- gfx.set_texture(^texture);
-
- switch rendering_kind {
- case .Luminance do gfx.use_alpha_shader(0);
- case .Color do gfx.set_texture(0);
- }
-
- size := font_size * (em / ~~font.common.line_height);
- for glyph: bmfont.get_character_positions(^font, size, text, x, y) {
- gfx.textured_rect(
- .{ glyph.pos_x, glyph.pos_y }, .{ glyph.pos_w, glyph.pos_h },
- .{ glyph.tex_x, glyph.tex_y }, .{ glyph.tex_w, glyph.tex_h },
- color = color);
- }
-
- gfx.set_texture();
- }
-}
-
-create_font :: (bmfont_data: [] u8, font_texture_data: [] u8) -> Font {
- font := bmfont.load_bmfont(bmfont_data);
-
- color_channels_have_data := (font.common.blue_channel + font.common.green_channel + font.common.red_channel) == ~~0;
-
- // This may not always be right
- texture_width, texture_height := font.common.scale_width, font.common.scale_height;
- assert(texture_width * texture_height * (4 if color_channels_have_data else 1) == font_texture_data.count, "Bad font texture size.");
-
- rendering_kind: RK = (.Color) if color_channels_have_data else .Luminance;
- font_format := gl.RGBA if color_channels_have_data else gl.LUMINANCE;
-
- texture := gfx.load_texture(texture_width, texture_height, font_texture_data, font_format, font_format);
-
- return .{ texture=texture, font=font, rendering_kind=rendering_kind };
-}
-
-Font_Index :: i32;
-
-#package font_registry : Map(Font_Index, Font);
-register_font :: (index: Font_Index, font: Font) {
- assert(!map.has(^font_registry, index), "Font with this index already exists.");
- map.put(^font_registry, index, font);
-}
-
-use_font :: (index: Font_Index) {
- font_ptr := map.get_ptr(^font_registry, index);
- if font_ptr == null do font_ptr = map.get_ptr(^font_registry, -1);
- current_font = font_ptr;
-}
\ No newline at end of file
+++ /dev/null
-info face="M+ 2m Nerd Font Complete" size=16 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2
-common lineHeight=24 base=18 scaleW=128 scaleH=128 pages=1 packed=0
-page id=0 file="builtin.png"
-chars count=97
-char id=0 x=95 y=63 width=7 height=13 xoffset=-1 yoffset=6 xadvance=6 page=0 chnl=0
-char id=10 x=95 y=63 width=7 height=13 xoffset=-1 yoffset=6 xadvance=6 page=0 chnl=0
-char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=17 xadvance=8 page=0 chnl=0
-char id=33 x=121 y=35 width=5 height=14 xoffset=2 yoffset=5 xadvance=8 page=0 chnl=0
-char id=34 x=28 y=88 width=6 height=7 xoffset=1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=35 x=75 y=63 width=9 height=14 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=0
-char id=36 x=61 y=0 width=9 height=18 xoffset=0 yoffset=2 xadvance=8 page=0 chnl=0
-char id=37 x=64 y=63 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=0
-char id=38 x=84 y=63 width=11 height=14 xoffset=-1 yoffset=5 xadvance=9 page=0 chnl=0
-char id=39 x=40 y=88 width=4 height=7 xoffset=2 yoffset=4 xadvance=8 page=0 chnl=0
-char id=40 x=12 y=0 width=8 height=18 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0
-char id=41 x=20 y=0 width=8 height=18 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0
-char id=42 x=10 y=88 width=10 height=9 xoffset=-1 yoffset=4 xadvance=9 page=0 chnl=0
-char id=43 x=119 y=77 width=8 height=10 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0
-char id=44 x=44 y=88 width=6 height=7 xoffset=1 yoffset=14 xadvance=8 page=0 chnl=0
-char id=45 x=64 y=88 width=7 height=4 xoffset=1 yoffset=11 xadvance=9 page=0 chnl=0
-char id=46 x=50 y=88 width=5 height=5 xoffset=2 yoffset=14 xadvance=8 page=0 chnl=0
-char id=47 x=49 y=20 width=10 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=48 x=38 y=63 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=49 x=83 y=49 width=8 height=14 xoffset=0 yoffset=5 xadvance=9 page=0 chnl=0
-char id=50 x=91 y=49 width=8 height=14 xoffset=0 yoffset=5 xadvance=7 page=0 chnl=0
-char id=51 x=99 y=49 width=9 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=52 x=108 y=49 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=53 x=118 y=49 width=9 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=54 x=0 y=63 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=55 x=10 y=63 width=8 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=56 x=18 y=63 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=57 x=28 y=63 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=58 x=114 y=77 width=5 height=11 xoffset=1 yoffset=8 xadvance=7 page=0 chnl=0
-char id=59 x=58 y=63 width=6 height=14 xoffset=0 yoffset=8 xadvance=7 page=0 chnl=0
-char id=60 x=102 y=63 width=8 height=13 xoffset=0 yoffset=6 xadvance=8 page=0 chnl=0
-char id=61 x=20 y=88 width=8 height=8 xoffset=0 yoffset=9 xadvance=8 page=0 chnl=0
-char id=62 x=110 y=63 width=8 height=13 xoffset=0 yoffset=6 xadvance=8 page=0 chnl=0
-char id=63 x=48 y=63 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=64 x=80 y=0 width=10 height=16 xoffset=-1 yoffset=6 xadvance=8 page=0 chnl=0
-char id=65 x=69 y=20 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=66 x=79 y=20 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=67 x=89 y=20 width=9 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=68 x=98 y=20 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=69 x=108 y=20 width=9 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=70 x=117 y=20 width=9 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=71 x=0 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=72 x=10 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=73 x=20 y=35 width=7 height=14 xoffset=0 yoffset=5 xadvance=7 page=0 chnl=0
-char id=74 x=27 y=35 width=9 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=75 x=36 y=35 width=9 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=76 x=45 y=35 width=8 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=77 x=53 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=78 x=63 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=79 x=73 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=80 x=83 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=81 x=70 y=0 width=10 height=17 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=82 x=93 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=83 x=103 y=35 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=84 x=113 y=35 width=8 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=85 x=0 y=49 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=86 x=10 y=49 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=87 x=20 y=49 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=88 x=30 y=49 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=89 x=40 y=49 width=10 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=90 x=50 y=49 width=8 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=91 x=28 y=0 width=7 height=18 xoffset=0 yoffset=4 xadvance=8 page=0 chnl=0
-char id=92 x=59 y=20 width=10 height=15 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=93 x=35 y=0 width=8 height=18 xoffset=0 yoffset=4 xadvance=8 page=0 chnl=0
-char id=94 x=0 y=88 width=10 height=10 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=95 x=71 y=88 width=10 height=4 xoffset=-1 yoffset=18 xadvance=8 page=0 chnl=0
-char id=96 x=34 y=88 width=6 height=7 xoffset=1 yoffset=3 xadvance=8 page=0 chnl=0
-char id=97 x=0 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=98 x=90 y=0 width=10 height=15 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=99 x=118 y=63 width=9 height=11 xoffset=0 yoffset=8 xadvance=9 page=0 chnl=0
-char id=100 x=100 y=0 width=10 height=15 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=101 x=10 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=102 x=58 y=49 width=8 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=103 x=110 y=0 width=10 height=15 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=104 x=0 y=20 width=10 height=15 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=105 x=120 y=0 width=7 height=15 xoffset=1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=106 x=5 y=0 width=7 height=19 xoffset=0 yoffset=4 xadvance=8 page=0 chnl=0
-char id=107 x=10 y=20 width=9 height=15 xoffset=0 yoffset=4 xadvance=9 page=0 chnl=0
-char id=108 x=66 y=49 width=9 height=14 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0
-char id=109 x=20 y=77 width=11 height=11 xoffset=-1 yoffset=8 xadvance=9 page=0 chnl=0
-char id=110 x=31 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=111 x=41 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=112 x=19 y=20 width=10 height=15 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=113 x=29 y=20 width=10 height=15 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=114 x=51 y=77 width=8 height=11 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0
-char id=115 x=59 y=77 width=9 height=11 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0
-char id=116 x=75 y=49 width=8 height=14 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0
-char id=117 x=68 y=77 width=9 height=11 xoffset=-1 yoffset=8 xadvance=7 page=0 chnl=0
-char id=118 x=77 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=119 x=87 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=120 x=97 y=77 width=10 height=11 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=121 x=39 y=20 width=10 height=15 xoffset=-1 yoffset=8 xadvance=8 page=0 chnl=0
-char id=122 x=107 y=77 width=7 height=11 xoffset=0 yoffset=8 xadvance=7 page=0 chnl=0
-char id=123 x=43 y=0 width=9 height=18 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0
-char id=124 x=0 y=0 width=5 height=20 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0
-char id=125 x=52 y=0 width=9 height=18 xoffset=0 yoffset=4 xadvance=8 page=0 chnl=0
-char id=126 x=55 y=88 width=9 height=5 xoffset=0 yoffset=11 xadvance=8 page=0 chnl=0
-kernings count=0
+++ /dev/null
-package ui
-
-
-Mouse_State :: struct {
- left_button_down := false;
- left_button_just_down := false;
- left_button_just_up := false;
-
- right_button_down := false;
- right_button_just_down := false;
- right_button_just_up := false;
-
- dwheel : f32 = 0;
-
- x_ : f32 = 0;
- y_ : f32 = 0;
- dx_ : f32 = 0;
- dy_ : f32 = 0;
-}
-
-mouse_state := Mouse_State.{};
-
-Keyboard_State :: struct {
- Max_Keys_Per_Frame :: 4;
-
- Key_Event :: struct {
- code: u32 = 0;
- modifiers: Modifiers = ~~0;
-
- Modifiers :: enum #flags {
- CTRL; ALT; SHIFT; META;
- }
- }
-
- keycodes_down_this_frame : [Max_Keys_Per_Frame] Key_Event;
- keys_down_this_frame : u32;
-
- keycodes_up_this_frame : [Max_Keys_Per_Frame] Key_Event;
- keys_up_this_frame : u32;
-
- Key_Count :: 256;
-
- Key_State :: enum (u8) {
- Up;
- Down;
- Just_Up;
- Just_Down;
- }
-
- state : [Key_Count] Key_State;
-}
-
-@Note // This assumes that this gets zero intialized.
-keyboard_state: Keyboard_State;
-
-
-
-
-//
-// Telling the UI system about hardware updates
-//
-
-update_mouse_position :: (new_x: f32, new_y: f32) {
- mouse_state.dx_ += mouse_state.x_ - new_x;
- mouse_state.dy_ += mouse_state.y_ - new_y;
- mouse_state.x_ = new_x;
- mouse_state.y_ = new_y;
-}
-
-#local Mouse_Button_Kind :: enum { Left; Right; Middle; WheelUp; WheelDown; }
-
-button_pressed :: (kind: Mouse_Button_Kind) {
- switch kind {
- case .Left {
- mouse_state.left_button_down = true;
- mouse_state.left_button_just_down = true;
- }
-
- case .Right {
- mouse_state.right_button_down = true;
- mouse_state.right_button_just_down = true;
- }
-
- case .WheelUp do mouse_state.dwheel = 1.0;
- case .WheelDown do mouse_state.dwheel = -1.0;
- }
-}
-
-button_released :: (kind: Mouse_Button_Kind) {
- switch kind {
- case .Left {
- mouse_state.left_button_down = false;
- mouse_state.left_button_just_up = true;
- }
-
- case .Right {
- mouse_state.right_button_down = false;
- mouse_state.right_button_just_up = true;
- }
-
- case .WheelUp do mouse_state.dwheel = 0;
- case .WheelDown do mouse_state.dwheel = 0;
- }
-}
-
-#local
-__key_state_transition_table := Keyboard_State.Key_State.[
- /* KeyUp */ /* KeyDown */
- /* Up */ Keyboard_State.Key_State.Up, Keyboard_State.Key_State.Just_Down,
- /* Down */ Keyboard_State.Key_State.Just_Up, Keyboard_State.Key_State.Down,
- /* Just_Up */ Keyboard_State.Key_State.Up, Keyboard_State.Key_State.Just_Down,
- /* Just_Down */ Keyboard_State.Key_State.Just_Up, Keyboard_State.Key_State.Down,
-]
-
-key_down :: (keycode: u32, modifiers: Keyboard_State.Key_Event.Modifiers) {
- keyboard_state.keycodes_down_this_frame[keyboard_state.keys_down_this_frame] = .{
- keycode,
- modifiers
- };
-
- keyboard_state.keys_down_this_frame += 1;
- keyboard_state.state[keycode] = __key_state_transition_table[cast(i32) keyboard_state.state[keycode] * 2 + 1];
-}
-
-key_up :: (keycode: u32, modifiers: Keyboard_State.Key_Event.Modifiers) {
- keyboard_state.keycodes_up_this_frame[keyboard_state.keys_up_this_frame] = .{
- keycode,
- modifiers
- };
-
- keyboard_state.keys_up_this_frame += 1;
- keyboard_state.state[keycode] = __key_state_transition_table[cast(i32) keyboard_state.state[keycode] * 2];
-}
-
-
-
-//
-// Querying the UI system for current input state
-//
-
-// Relative to the current transformations on the immediate renderer
-get_mouse_position :: () -> (x: f32, y: f32) {
- transform := gfx.global_renderer->get_transform();
- return (mouse_state.x_ - transform.translation.x) / transform.scale.x,
- (mouse_state.y_ - transform.translation.y) / transform.scale.y;
-}
-
-get_mouse_delta :: () -> (dx: f32, dy: f32) {
- transform := gfx.global_renderer->get_transform();
- return mouse_state.dx_ / transform.scale.x,
- mouse_state.dy_ / transform.scale.y;
-}
-
-is_key_down :: (keycode: u32) -> bool {
- s := keyboard_state.state[keycode];
- return s == .Down || s == .Just_Down;
-}
-
-is_key_just_down :: (keycode: u32) -> bool {
- return keyboard_state.state[keycode] == .Just_Down;
-}
-
-is_key_up :: (keycode: u32) -> bool {
- s := keyboard_state.state[keycode];
- return s == .Up || s == .Just_Up;
-}
+++ /dev/null
-@Todo
-/*
-Document this module better
-
-Add selection to textbox
-
-Add dropdowns
-
-Add scrollable areas
-
-Add proper scissoring for intersecting elements (events get scissored too)
-
-Add a font cache and more preloaded fonts
-
-Add proper font texture decoding to make the WebGL texture depending on how the BMFont was encoded into the image.
-*/
-
-
-/*
-The goal of this module is to provide a low-friction method of producing simple
-user interfaces in WebGL (and OpenGL when Onyx compiles to C).
-
-This module provides several common UI components such as:
- - Buttons
- - Checkbox
- - Radio buttons
- - Sliders
- - Textboxes
-
-This module also provides a simple rectangle division scheme for laying out UI components.
-*/
-
-
-
-
-
-
-
-@Rename
-package ui
-
-#load "./ui"
-#load "./flow"
-#load "./input"
-#load "./font"
-
-#load "./components/button"
-#load "./components/checkbox"
-#load "./components/slider"
-#load "./components/radio"
-#load "./components/textbox"
-#load "./components/workspace"
-#load "./components/scrollable_region"
-
-// Package inclusions that are part of all files in the "ui" package.
-#package gfx :: package immediate_mode // The immediate_mode module needs to be accessible
-#package gl :: package gl
-#package bmfont :: package bmfont
-
-#package math :: package core.math
-#package map :: package core.map
\ No newline at end of file
+++ /dev/null
-package ui
-
-use package core
-
-@Temporary
-DEFAULT_TEXT_SIZE :: 1.0f
-
-UI_Id :: #type u32
-
-#package {
- hot_item : UI_Id = 0
- active_item : UI_Id = 0
- hot_item_was_set := false
-
- current_font : ^Font;
-}
-
-init_ui :: () {
- map.init(^font_registry);
-
- map.init(^animation_states, default=.{});
- map.init(^workspace_states, default=.{});
- map.init(^scrollable_region_states, default=.{});
-
- // Register a default font so things don't break everywhere
- builtin_font := create_font(#file_contents "./fonts/builtin.fnt", #file_contents "./fonts/builtin.data");
- register_font(-1, builtin_font);
- use_font(-1);
-}
-
-// This function should be called at the end of drawing a frame, after all of the UI elements
-// had a chance to interact with the hardware events.
-
-end_frame :: () {
- mouse_state.left_button_just_up = false;
- mouse_state.left_button_just_down = false;
- mouse_state.right_button_just_up = false;
- mouse_state.right_button_just_down = false;
-
- mouse_state.dwheel = 0;
- mouse_state.dx_ = 0;
- mouse_state.dy_ = 0;
-
- // I don't think these need to be cleared every frame, so long as you don't try
- // to use them without checking keys_down_this_frame first.
- // for ^key: keyboard_state.keycodes_down_this_frame do *key = .{};
- // for ^key: keyboard_state.keycodes_up_this_frame do *key = .{};
-
- keyboard_state.keys_down_this_frame = 0;
- keyboard_state.keys_up_this_frame = 0;
-
- hot_item_depth_needed = hot_item_depth;
- if !hot_item_was_set do set_hot_item(0);
- hot_item_depth = 0;
- hot_item_was_set = false;
-
- for ^s: keyboard_state.state {
- if *s == .Just_Down do *s = .Down;
- if *s == .Just_Up do *s = .Up;
- }
-
- for ^state: animation_states.entries {
- // If the animation isn't being used anymore, discard it. This makes the has_active_animation function
- // correct, otherwise, there could be animations that didn't finish, but the element was removed, and is
- // no longer being updated.
- if !state.value.accessed_this_frame || (state.value.click_time == 0 && state.value.hover_time == 0) {
- map.delete(^animation_states, state.key);
- }
- }
-
- for ^state: animation_states.entries {
- state.value.accessed_this_frame = false;
- }
-}
-
-set_active_item :: (id: UI_Id) -> bool {
- active_item = id;
- return true;
-}
-
-#local hot_item_depth := 0;
-#local hot_item_depth_needed := 0;
-
-set_hot_item :: (id: UI_Id, force := false) -> bool {
- if active_item != 0 do return false;
-
- if force {
- hot_item_was_set = true;
- hot_item = id;
- return true;
- }
-
- hot_item_depth += 1;
- if hot_item_depth >= hot_item_depth_needed {
- hot_item_was_set = true;
- hot_item = id;
- return true;
- } else {
- return false;
- }
-}
-
-is_active_item :: (id: UI_Id) -> bool {
- return active_item == id;
-}
-
-is_hot_item :: (id: UI_Id) -> bool {
- return hot_item == id;
-}
-
-@FontSizing // In the new font system, size is in ems, which can be set per font.
-draw_text_raw :: (text: str, x: f32, y: f32, font: i32 = -1, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) {
- use_font(font);
- if current_font == null do use_font(-1);
- current_font->render(text, x, y, size, color);
-}
-
-draw_rect :: #match {
- (use r: Rectangle, color := gfx.Color4.{1,1,1}) {
- gfx.set_texture();
-
- width, height := Rectangle.dimensions(r);
- gfx.rect(.{ x0, y0 }, .{ width, height }, color);
- },
-
- (x, y, w, h: f32, color := gfx.Color4.{1,1,1}) {
- gfx.set_texture();
- gfx.rect(.{ x, y }, .{ w, h }, color);
- }
-}
-
-draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme, site := #callsite) {
- draw_text_raw(text, x0, y0 + current_font->get_baseline(theme.font_size), theme.font, theme.font_size, theme.text_color);
-}
-
-Rectangle :: struct {
- //
- // x0,y0 ------------+
- // | |
- // | |
- // +------------ x1,y1
- //
-
- x0: f32 = 0;
- y0: f32 = 0;
- x1: f32 = 0;
- y1: f32 = 0;
-
- width :: (use r: Rectangle) -> f32 do return math.abs(x1 - x0);
- height :: (use r: Rectangle) -> f32 do return math.abs(y1 - y0);
-
- dimensions :: (use r: Rectangle) -> (width: f32, height: f32) {
- return width(r), height(r);
- }
-
- top_left :: (use r: Rectangle) -> (x: f32, y: f32) do return math.min(x0, x1), math.min(y0, y1);
- top_right :: (use r: Rectangle) -> (x: f32, y: f32) do return math.max(x0, x1), math.min(y0, y1);
- bottom_left :: (use r: Rectangle) -> (x: f32, y: f32) do return math.min(x0, x1), math.max(y0, y1);
- bottom_right :: (use r: Rectangle) -> (x: f32, y: f32) do return math.max(x0, x1), math.max(y0, y1);
-
- contains :: (use r: Rectangle, x, y: f32) -> bool {
- return math.min(x0, x1) <= x && x <= math.max(x0, x1) &&
- math.min(y0, y1) <= y && y <= math.max(y0, y1);
- }
-
- intersects :: (use r: Rectangle, o: Rectangle) -> bool {
- return x1 >= o.x0 && x0 <= o.x1 && y1 >= o.y0 && y0 <= o.y1;
- }
-}
-
-
-
-
-@Relocate
-Text_Theme :: struct {
- text_color := gfx.Color4.{ 1, 1, 1 };
-
- font := 0; // Default to font index 0
- font_size := 1.0f;
-}
-
-default_text_theme := Text_Theme.{};
-
-
-Animation_Theme :: struct {
- hover_speed := 0.1f;
- click_decay_speed := 0.08f;
-}
-
-
-
-// Animation states are stored globally as there is not much to the state of a button.
-// Forcing the end user to store a structure for each button that is just the animation
-// state of the component feels very wrong.
-#local animation_states : Map(UI_Id, Animation_State);
-
-Animation_State :: struct {
- hover_time := 0.0f;
- click_time := 0.0f;
-
- accessed_this_frame := false;
-}
-
-get_animation :: (id: UI_Id) -> ^Animation_State {
- retval := map.get_ptr(^animation_states, id);
-
- if retval == null {
- map.put(^animation_states, id, .{});
- retval = map.get_ptr(^animation_states, id);
- }
-
- retval.accessed_this_frame = true;
- return retval;
-}
-
-has_active_animation :: () -> bool {
- for ^anim: animation_states.entries {
- if anim.value.hover_time != 0.0f || anim.value.hover_time != 1.0f do return true;
- if anim.value.click_time != 0.0f || anim.value.click_time != 1.0f do return true;
- }
-
- return false;
-}
-
-
-// Utilities
-get_site_hash :: macro (site: CallSite, increment := 0) -> UI_Id {
- hash :: package core.hash
-
- file_hash := hash.to_u32(site.file);
- line_hash := hash.to_u32(site.line);
- column_hash := hash.to_u32(site.column);
-
- return file_hash * 0x472839 + line_hash * 0x6849210 + column_hash * 0x1248382 + increment;
-}
-
-get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
- return current_font->get_width(text, size);
-}
-
-get_text_height :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 {
- return current_font->get_height(text, size);
-}
-
-@Relocate
-move_towards :: macro (value: ^$T, target: T, step: T) {
- if *value < target do *value += step;
- if *value > target do *value -= step;
- if *value > target - step && *value < target + step do *value = target;
-}
-
-#package color_lerp :: macro (t: f32, c1: gfx.Color4, c2: gfx.Color4) -> gfx.Color4 {
- return .{
- r = c1.r * (1 - t) + c2.r * t,
- g = c1.g * (1 - t) + c2.g * t,
- b = c1.b * (1 - t) + c2.b * t,
- a = c1.a * (1 - t) + c2.a * t, @Cleanup // should this be interpolating alphas?
- };
-}
+++ /dev/null
-package vecmath
-
-#load "./vector2.onyx"
+++ /dev/null
-package vecmath
-
-#local io :: package core.io
-
-Vector2i :: #type Vector2(i32);
-Vector2f :: #type Vector2(f32);
-
-Vector2 :: struct (T: type_expr) {
- x := T.{};
- y := T.{};
-}
-
-#operator + vector2_add
-vector2_add :: (a: Vector2($T), b: Vector2(T)) -> Vector2(T) {
- return .{ a.x + b.x, a.y + b.y };
-}
-
-#operator - vector2_sub
-vector2_sub :: (a: Vector2($T), b: Vector2(T)) -> Vector2(T) {
- return .{ a.x - b.x, a.y - b.y };
-}
-
-#operator * vector2_mul
-vector2_mul :: (v: Vector2($T), scalar: T) -> Vector2(T) {
- return .{ v.x * scalar, v.y * scalar };
-}
-
-#operator * vector2_dot
-vector2_dot :: (a: Vector2($T), b: Vector2(T)) -> T {
- return a.x * b.x + a.y * b.y;
-}
-
-vector2_lerp :: (t: f32, start: Vector2($T), end: Vector(T)) -> Vector2(T) {
- return .{
- ~~(t * ~~(end.x - start.x)) + start.x,
- ~~(t * ~~(end.y - start.y)) + start.y,
- };
-}
-
-#operator == vector2_equal
-vector2_equal :: (a: Vector2($T), b: Vector2(T)) -> bool {
- return a.x == b.x && a.y == b.y;
-}
-
-#match io.write vector2_write
-vector2_write :: (writer: ^io.Writer, v: Vector2($T)) {
- io.write(writer, "Vector2(");
- io.write(writer, v.x);
- io.write(writer, ", ");
- io.write(writer, v.y);
- io.write(writer, ")");
-}
+++ /dev/null
-package wasm_utils
-
-WasmInstructionCode :: enum {
- unreachable :: 0x00;
- nop :: 0x01;
- block :: 0x02;
- loop :: 0x03;
- if_ :: 0x04;
- else_ :: 0x05;
- end :: 0x0B;
- branch :: 0x0C;
- branch_if :: 0x0D;
- branch_table :: 0x0E;
- return_ :: 0x0F;
- call :: 0x10;
- call_indirect :: 0x11;
-
- ref_null :: 0xD0;
- ref_is_null :: 0xD1;
- ref_func :: 0xD2;
-
- drop :: 0x1A;
- select :: 0x1B;
-
- local_get :: 0x20;
- local_set :: 0x21;
- local_tee :: 0x22;
- global_get :: 0x23;
- global_set :: 0x24;
-
- table_get :: 0x25;
- table_set :: 0x26;
- table_init :: 0xFC0C;
- elem_drop :: 0xFC0D;
- table_copy :: 0xFC0E;
- table_grow :: 0xFC0F;
- table_size :: 0xFC10;
- table_fill :: 0xFC11;
-
- i32_load :: 0x28;
- i64_load :: 0x29;
- f32_load :: 0x2A;
- f64_load :: 0x2B;
-
- i32_load8_s :: 0x2C;
- i32_load8_u :: 0x2D;
- i32_load16_s :: 0x2E;
- i32_load16_u :: 0x2F;
- i64_load8_s :: 0x30;
- i64_load8_u :: 0x31;
- i64_load16_s :: 0x32;
- i64_load16_u :: 0x33;
- i64_load32_s :: 0x34;
- i64_load32_u :: 0x35;
-
- i32_store :: 0x36;
- i64_store :: 0x37;
- f32_store :: 0x38;
- f64_store :: 0x39;
-
- i32_store8 :: 0x3A;
- i32_store16 :: 0x3B;
- i64_store8 :: 0x3C;
- i64_store16 :: 0x3D;
- i64_store32 :: 0x3E;
-
- memory_size :: 0x3F;
- memory_grow :: 0x40;
- memory_init :: 0xFC08;
- data_drop :: 0xFC09;
- memory_copy :: 0xFC0A;
- memory_fill :: 0xFC0B;
-
- i32_const :: 0x41;
- i64_const :: 0x42;
- f32_const :: 0x43;
- f64_const :: 0x44;
-
- i32_eqz :: 0x45;
- i32_eq :: 0x46;
- i32_ne :: 0x47;
- i32_lt_s :: 0x48;
- i32_lt_u :: 0x49;
- i32_gt_s :: 0x4A;
- i32_gt_u :: 0x4B;
- i32_le_s :: 0x4C;
- i32_le_u :: 0x4D;
- i32_ge_s :: 0x4E;
- i32_ge_u :: 0x4F;
-
- i64_eqz :: 0x50;
- i64_eq :: 0x51;
- i64_ne :: 0x52;
- i64_lt_s :: 0x53;
- i64_lt_u :: 0x54;
- i64_gt_s :: 0x55;
- i64_gt_u :: 0x56;
- i64_le_s :: 0x57;
- i64_le_u :: 0x58;
- i64_ge_s :: 0x59;
- i64_ge_u :: 0x5A;
-
- f32_eq :: 0x5B;
- f32_ne :: 0x5C;
- f32_lt :: 0x5D;
- f32_gt :: 0x5E;
- f32_le :: 0x5F;
- f32_ge :: 0x60;
-
- f64_eq :: 0x61;
- f64_ne :: 0x62;
- f64_lt :: 0x63;
- f64_gt :: 0x64;
- f64_le :: 0x65;
- f64_ge :: 0x66;
-
- i32_clz :: 0x67;
- i32_ctz :: 0x68;
- i32_popcnt :: 0x69;
- i32_add :: 0x6A;
- i32_sub :: 0x6B;
- i32_mul :: 0x6C;
- i32_div_s :: 0x6D;
- i32_div_u :: 0x6E;
- i32_rem_s :: 0x6F;
- i32_rem_u :: 0x70;
- i32_and :: 0x71;
- i32_or :: 0x72;
- i32_xor :: 0x73;
- i32_shl :: 0x74;
- i32_shr_s :: 0x75;
- i32_shr_u :: 0x76;
- i32_rotl :: 0x77;
- i32_rotr :: 0x78;
-
- i64_clz :: 0x79;
- i64_ctz :: 0x7A;
- i64_popcnt :: 0x7B;
- i64_add :: 0x7C;
- i64_sub :: 0x7D;
- i64_mul :: 0x7E;
- i64_div_s :: 0x7F;
- i64_div_u :: 0x80;
- i64_rem_s :: 0x81;
- i64_rem_u :: 0x82;
- i64_and :: 0x83;
- i64_or :: 0x84;
- i64_xor :: 0x85;
- i64_shl :: 0x86;
- i64_shr_s :: 0x87;
- i64_shr_u :: 0x88;
- i64_rotl :: 0x89;
- i64_rotr :: 0x8A;
-
- f32_abs :: 0x8B;
- f32_neg :: 0x8C;
- f32_ceil :: 0x8D;
- f32_floor :: 0x8E;
- f32_trunc :: 0x8F;
- f32_nearest :: 0x90;
- f32_sqrt :: 0x91;
- f32_add :: 0x92;
- f32_sub :: 0x93;
- f32_mul :: 0x94;
- f32_div :: 0x95;
- f32_min :: 0x96;
- f32_max :: 0x97;
- f32_copysign :: 0x98;
-
- f64_abs :: 0x99;
- f64_neg :: 0x9A;
- f64_ceil :: 0x9B;
- f64_floor :: 0x9C;
- f64_trunc :: 0x9D;
- f64_nearest :: 0x9E;
- f64_sqrt :: 0x9F;
- f64_add :: 0xA0;
- f64_sub :: 0xA1;
- f64_mul :: 0xA2;
- f64_div :: 0xA3;
- f64_min :: 0xA4;
- f64_max :: 0xA5;
- f64_copysign :: 0xA6;
-
- i32_from_i64 :: 0xA7;
- i32_from_f32_s :: 0xA8;
- i32_from_f32_u :: 0xA9;
- i32_from_f64_s :: 0xAA;
- i32_from_f64_u :: 0xAB;
- i64_from_i32_s :: 0xAC;
- i64_from_i32_u :: 0xAD;
- i64_from_f32_s :: 0xAE;
- i64_from_f32_u :: 0xAF;
- i64_from_f64_s :: 0xB0;
- i64_from_f64_u :: 0xB1;
- f32_from_i32_s :: 0xB2;
- f32_from_i32_u :: 0xB3;
- f32_from_i64_s :: 0xB4;
- f32_from_i64_u :: 0xB5;
- f32_from_f64 :: 0xB6;
- f64_from_i32_s :: 0xB7;
- f64_from_i32_u :: 0xB8;
- f64_from_i64_s :: 0xB9;
- f64_from_i64_u :: 0xBA;
- f64_from_f32 :: 0xBB;
-
- i32_transmute_f32 :: 0xBC;
- i64_transmute_f64 :: 0xBD;
- f32_transmute_i32 :: 0xBE;
- f64_transmute_i64 :: 0xBF;
-
- i32_trunc_sat_f32_s :: 0xFC00;
- i32_trunc_sat_f32_u :: 0xFC01;
- i32_trunc_sat_f64_s :: 0xFC02;
- i32_trunc_sat_f64_u :: 0xFC03;
- i64_trunc_sat_f32_s :: 0xFC04;
- i64_trunc_sat_f32_u :: 0xFC05;
- i64_trunc_sat_f64_s :: 0xFC06;
- i64_trunc_sat_f64_u :: 0xFC07;
-}
-
-WasmInstruction :: struct {
- code : WasmInstructionCode;
-
- // Offset to the immediates after the instruction.
- data : u32;
-}
-
-instruction_iterator :: (binary: ^WasmBinary, code: ^WasmCode, allocator := context.allocator) -> Iterator(WasmInstruction) {
-
- CodeContext :: struct {
- allocator : Allocator;
- binary : ^WasmBinary;
-
- code : ^WasmCode;
-
- stream : io.StringStream;
- reader : io.Reader;
-
- current_block_depth : u32;
- }
-
- data := make(CodeContext, allocator=allocator);
- data.allocator = allocator;
- data.binary = binary;
- data.code = code;
- data.current_block_depth = 1;
-
- data.stream = io.string_stream_make(binary.data.data[code.code_offset .. (code.code_offset + code.size)]);
- data.reader = io.reader_make(^data.stream);
-
- next :: (use c: ^CodeContext) -> (WasmInstruction, bool) {
- if current_block_depth == 0 do return .{}, false;
-
- return parse_instruction(^reader, binary, code.code_offset, ^current_block_depth), true;
- }
-
- close :: (use c: ^CodeContext) {
- raw_free(allocator, c);
- }
-
- return .{ data, next, close };
-}
-
-instructions_as_array :: (binary: ^WasmBinary, code: ^WasmCode, allocator := context.allocator) -> [..] WasmInstruction {
- return instruction_iterator(binary, code, allocator)
- |> iter.to_array(allocator=allocator);
-}
-
-#package
-parse_instruction :: (reader: ^io.Reader, binary: ^WasmBinary, code_offset := 0, current_block_depth: ^i32 = null) -> WasmInstruction {
-
- Parse_After :: enum {
- None;
- Block_Type;
- Index;
- Zero_Byte;
- Memory_Arg;
- Index_Then_Zero_Byte;
- Two_Zero_Bytes;
- Two_Indicies;
-
- Signed_Leb;
- Unsigned_Leb;
- Float32;
- Float64;
-
- Branch_Table;
- }
-
- instr: WasmInstruction;
- instr.data = 0;
-
- parse_after := Parse_After.None;
- block_depth := (*current_block_depth) if current_block_depth != null else 0;
-
- ib := io.read_byte(reader);
- switch cast(u32) ib {
- case 0x00 { instr.code = .unreachable; }
- case 0x01 { instr.code = .nop; }
- case 0x02 { instr.code = .block; block_depth += 1; parse_after = .Block_Type; }
- case 0x03 { instr.code = .loop; block_depth += 1; parse_after = .Block_Type; }
- case 0x04 { instr.code = .if_; block_depth += 1; parse_after = .Block_Type; }
- case 0x05 { instr.code = .else_; }
- case 0x0B { instr.code = .end; block_depth -= 1; }
-
- case 0x0C { instr.code = .branch; parse_after = .Index; }
- case 0x0D { instr.code = .branch_if; parse_after = .Index; }
- case 0x0E { instr.code = .branch_table; parse_after = .Branch_Table; }
-
- case 0x0F { instr.code = .return_; }
- case 0x10 { instr.code = .call; parse_after = .Index; }
- case 0x11 { instr.code = .call_indirect; parse_after = .Two_Indicies; }
- case 0x1A { instr.code = .drop; }
- case 0x1B { instr.code = .select; }
-
- case 0x20 { instr.code = .local_get; parse_after = .Index; }
- case 0x21 { instr.code = .local_set; parse_after = .Index; }
- case 0x22 { instr.code = .local_tee; parse_after = .Index; }
- case 0x23 { instr.code = .global_get; parse_after = .Index; }
- case 0x24 { instr.code = .global_set; parse_after = .Index; }
-
- case 0x28 { instr.code = .i32_load; parse_after = .Memory_Arg; }
- case 0x29 { instr.code = .i64_load; parse_after = .Memory_Arg; }
- case 0x2A { instr.code = .f32_load; parse_after = .Memory_Arg; }
- case 0x2B { instr.code = .f64_load; parse_after = .Memory_Arg; }
-
- case 0x2C { instr.code = .i32_load8_s; parse_after = .Memory_Arg; }
- case 0x2D { instr.code = .i32_load8_u; parse_after = .Memory_Arg; }
- case 0x2E { instr.code = .i32_load16_s; parse_after = .Memory_Arg; }
- case 0x2F { instr.code = .i32_load16_u; parse_after = .Memory_Arg; }
-
- case 0x30 { instr.code = .i64_load8_s; parse_after = .Memory_Arg; }
- case 0x31 { instr.code = .i64_load8_u; parse_after = .Memory_Arg; }
- case 0x32 { instr.code = .i64_load16_s; parse_after = .Memory_Arg; }
- case 0x33 { instr.code = .i64_load16_u; parse_after = .Memory_Arg; }
- case 0x34 { instr.code = .i64_load32_s; parse_after = .Memory_Arg; }
- case 0x35 { instr.code = .i64_load32_u; parse_after = .Memory_Arg; }
-
- case 0x36 { instr.code = .i32_store; parse_after = .Memory_Arg; }
- case 0x37 { instr.code = .i64_store; parse_after = .Memory_Arg; }
- case 0x38 { instr.code = .f32_store; parse_after = .Memory_Arg; }
- case 0x39 { instr.code = .f64_store; parse_after = .Memory_Arg; }
-
- case 0x3A { instr.code = .i32_store8; parse_after = .Memory_Arg; }
- case 0x3B { instr.code = .i32_store16; parse_after = .Memory_Arg; }
- case 0x3C { instr.code = .i64_store8; parse_after = .Memory_Arg; }
- case 0x3D { instr.code = .i64_store16; parse_after = .Memory_Arg; }
- case 0x3E { instr.code = .i64_store32; parse_after = .Memory_Arg; }
-
- case 0x3F { instr.code = .memory_size; parse_after = .Zero_Byte; }
- case 0x40 { instr.code = .memory_copy; parse_after = .Zero_Byte; }
-
- case 0x41 { instr.code = .i32_const; parse_after = .Signed_Leb; }
- case 0x42 { instr.code = .i64_const; parse_after = .Signed_Leb; }
- case 0x43 { instr.code = .f32_const; parse_after = .Float32; }
- case 0x44 { instr.code = .f64_const; parse_after = .Float64; }
-
- case #default {
- // Special instructions
- if ~~ib == 0xFC {
- instr_num := cast(u32) read_uleb128(reader);
- switch instr_num {
- case 0x00 do instr.code = .i32_trunc_sat_f32_s;
- case 0x01 do instr.code = .i32_trunc_sat_f32_u;
- case 0x02 do instr.code = .i32_trunc_sat_f64_s;
- case 0x03 do instr.code = .i32_trunc_sat_f64_u;
- case 0x04 do instr.code = .i64_trunc_sat_f32_s;
- case 0x05 do instr.code = .i64_trunc_sat_f32_u;
- case 0x06 do instr.code = .i64_trunc_sat_f64_s;
- case 0x07 do instr.code = .i64_trunc_sat_f64_u;
-
- case 0x08 { instr.code = .memory_init; parse_after = .Index_Then_Zero_Byte; }
- case 0x09 { instr.code = .data_drop; parse_after = .Index; }
- case 0x0a { instr.code = .memory_copy; parse_after = .Two_Zero_Bytes; }
- case 0x0b { instr.code = .memory_fill; parse_after = .Zero_Byte; }
- }
- } else {
- instr.code = ~~ ib;
- }
- }
- }
-
- _, data_offset := io.stream_tell(reader.stream);
- instr.data = code_offset + data_offset;
-
- // I think these shouldn't just be skipped, but instead should be stored in the instruction struct.
- // However, I don't know the best way other than a complex union.
- switch parse_after {
- case .Block_Type do io.read_byte(reader);
- case .Index do read_uleb128(reader);
- case .Zero_Byte do io.read_byte(reader);
- case .Memory_Arg {
- read_uleb128(reader);
- read_uleb128(reader);
- }
- case .Index_Then_Zero_Byte {
- read_uleb128(reader);
- io.read_byte(reader);
- }
- case .Two_Zero_Bytes {
- io.read_byte(reader);
- io.read_byte(reader);
- }
- case .Two_Indicies {
- read_uleb128(reader);
- read_uleb128(reader);
- }
- case .Signed_Leb do read_sleb128(reader);
- case .Unsigned_Leb do read_uleb128(reader);
- case .Float32 do io.skip_bytes(reader, 4);
- case .Float64 do io.skip_bytes(reader, 8);
- case .Branch_Table {
- parse_vector(reader, binary, read_label);
- read_label(reader, binary);
-
- read_label :: (reader: ^io.Reader, binary: ^WasmBinary) -> u32 {
- return cast(u32) read_uleb128(reader);
- }
- }
- }
-
- if current_block_depth != null do *current_block_depth = block_depth;
-
- return instr;
-}
\ No newline at end of file
+++ /dev/null
-/*
-
-WebAssembly 32-bit disassembly and decompiler utils
-
-*/
-
-package wasm_utils
-
-#load "./types"
-#load "./utils"
-#load "./parser"
-#load "./instructions"
-
-#package map :: package core.map
-#package io :: package core.io
-#package hash :: package core.hash
-#package memory :: package core.memory
-#package iter :: package core.iter
\ No newline at end of file
+++ /dev/null
-//
-// Sections that still need to be parse-able
-// - DataCount
-//
-
-
-package wasm_utils
-
-// The allocator to be used for all allocations in the parser. This is set when
-// calling any of the top-level parsing functions. Because this is here, it is
-// unsafe to use this library in a multi-threaded context, if Wasm ever officially
-// supports that.
-#local wasm_allocator : Allocator
-
-parse_type_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmFuncType {
- if !map.has(^sections, .Type) do return .{ null, 0 };
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Type).offset, .Start);
-
- return parse_vector(^reader, bin, read_func_type);
-
- read_func_type :: (reader: ^io.Reader, binary: ^WasmBinary) -> WasmFuncType {
- _, pos := io.stream_tell(reader.stream);
-
- assert(io.read_byte(reader) == ~~0x60, "function type expected 0x60 as first byte");
-
- params := parse_vector(reader, binary, read_val_type);
- results := parse_vector(reader, binary, read_val_type);
-
- _, after_pos := io.stream_tell(reader.stream);
-
- return .{
- params = params,
- results = results,
- reference = binary.data.data[pos .. ~~(after_pos - pos)],
- };
- }
-}
-
-parse_import_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmImport {
- if !map.has(^sections, .Import) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Import).offset, .Start);
-
- return parse_vector(^reader, bin, read_import);
-
- read_import :: (reader: ^io.Reader, binary: ^WasmBinary) -> WasmImport {
- import: WasmImport;
- import.module_name = parse_name(reader, binary);
- import.import_name = parse_name(reader, binary);
-
- import.type = ~~io.read_byte(reader);
-
- switch import.type {
- case .Memory {
- import.limits = parse_limits(reader, binary);
- }
-
- case #default {
- import.index = ~~read_uleb128(reader);
- }
- }
-
- return import;
- }
-}
-
-parse_export_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmExport {
- if !map.has(^sections, .Export) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Export).offset, .Start);
-
- return parse_vector(^reader, bin, read_export);
-
- read_export :: (reader: ^io.Reader, binary: ^WasmBinary) -> WasmExport {
- name := parse_name(reader, binary);
-
- kind := io.read_byte(reader);
- index := read_uleb128(reader);
-
- return .{ name, ~~kind, ~~index };
- }
-}
-
-parse_function_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmFunction {
- if !map.has(^sections, .Function) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Function).offset, .Start);
-
- return parse_vector(^reader, bin, read_function);
-
- read_function :: (reader: ^io.Reader, binary: ^WasmBinary) -> WasmFunction {
- return .{ ~~read_uleb128(reader) };
- }
-}
-
-parse_start_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> i32 {
- if !map.has(^sections, .Start) do return -1;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Function).offset, .Start);
-
- return ~~read_uleb128(^reader);
-}
-
-parse_memory_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmMemory {
- if !map.has(^sections, .Memory) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Memory).offset, .Start);
-
- return parse_vector(^reader, bin, read_memory);
-
- read_memory :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmMemory {
- limits := parse_limits(reader, bin);
- return .{ limits };
- }
-}
-
-parse_table_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmTable {
- if !map.has(^sections, .Table) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Table).offset, .Start);
-
- return parse_vector(^reader, bin, read_table);
-
- read_table :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmTable {
- type := cast(WasmTableType) io.read_byte(reader);
- limits := parse_limits(reader, bin);
- return .{ type, limits };
- }
-}
-
-parse_global_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmGlobal {
- if !map.has(^sections, .Global) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Global).offset, .Start);
-
- return parse_vector(^reader, bin, read_global);
-
- read_global :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmGlobal {
- type := read_val_type(reader, bin);
- mutable := io.read_byte(reader) == 1;
-
- initial_value := parse_instruction(reader, bin);
- assert(io.read_byte(reader) == ~~0x0B, "Expected '0x0B' after constant expression");
-
- return .{ type, mutable };
- }
-}
-
-parse_element_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmElement {
- if !map.has(^sections, .Element) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Element).offset, .Start);
-
- return parse_vector(^reader, bin, read_element);
-
- read_element :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmElement {
- table_index := read_uleb128(reader);
-
- offset := parse_instruction(reader, bin);
- assert(io.read_byte(reader) == ~~0x0B, "Expected '0x0B' after constant expression");
-
- funcs := parse_vector(reader, bin, read_function_index);
- return .{ ~~table_index, offset, funcs };
- }
-
- read_function_index :: (reader: ^io.Reader, bin: ^WasmBinary) -> u32 {
- return ~~read_uleb128(reader);
- }
-}
-
-parse_data_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmData {
- if !map.has(^sections, .Data) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, sections[WasmSection.Data].offset, .Start);
-
- return parse_vector(^reader, bin, read_data);
-
- read_data :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmData {
- memory_index := read_uleb128(reader);
-
- offset: WasmInstruction;
- if memory_index == 0 {
- offset = parse_instruction(reader, bin);
- assert(io.read_byte(reader) == ~~0x0B, "Expected '0x0B' after constant expression");
- }
-
- size := read_uleb128(reader);
- _, pos := io.stream_tell(reader.stream);
- data := bin.data.data[pos .. (pos + ~~size)];
- io.stream_seek(reader.stream, ~~size, .Current);
-
- return .{ ~~memory_index, offset, data };
- }
-}
-
-parse_code_section :: (use bin: ^WasmBinary, allocator := context.allocator) -> [] WasmCode {
- if !map.has(^sections, .Code) do return .{ null, 0 };
-
- wasm_allocator = allocator;
-
- @Cleanup @WasmStream // These are going to be needed in many places
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- io.stream_seek(^stream, map.get(^sections, .Code).offset, .Start);
-
- return parse_vector(^reader, bin, read_code);
-
- read_code :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmCode {
- size := cast(u32) read_uleb128(reader);
- _, before_locals := io.stream_tell(reader.stream);
-
- array :: package core.array
-
- locals := array.make(WasmLocal);
- defer array.free(^locals);
- local_block_count := cast(u32) read_uleb128(reader);
-
- local_index := 0;
- for _: local_block_count {
- locals_count := cast(u32) read_uleb128(reader);
- local_type := read_val_type(reader, bin);
-
- for _: locals_count {
- array.push(^locals, .{ local_type, local_index });
- local_index += 1;
- }
- }
-
- _, pos := io.stream_tell(reader.stream);
- io.stream_seek(reader.stream, before_locals + size, .Start);
-
- locals_slice: [] WasmLocal = array.copy_range(^locals, 0 .. local_index, allocator=wasm_allocator);
-
- return .{ size, locals_slice, pos };
- }
-}
-
-#package
-parse_vector :: macro (reader: ^io.Reader, bin: ^WasmBinary,
- read: (^io.Reader, ^WasmBinary) -> $T) -> [] T {
- wasm_allocator :: wasm_allocator;
-
- n := cast(u32) read_uleb128(reader);
- result := memory.make_slice(T, n, allocator=wasm_allocator);
-
- for i: n {
- result[i] = read(reader, bin);
- }
-
- return result;
-}
-
-#package
-parse_name :: (reader: ^io.Reader, bin: ^WasmBinary) -> [] u8 {
- return parse_vector(reader, bin, read_byte);
-
- read_byte :: (reader: ^io.Reader, bin: ^WasmBinary) -> u8 {
- return io.read_byte(reader);
- }
-}
-
-#package
-parse_limits :: (reader: ^io.Reader, bin: ^WasmBinary) -> WasmLimits {
- byte := io.read_byte(reader);
-
- minimum, maximum : u32;
- shared := (byte & 2) != 0;
-
- switch byte & 1 {
- case 0 {
- minimum =~~ read_uleb128(reader);
- maximum = 0;
- }
-
- case 1 {
- minimum =~~ read_uleb128(reader);
- maximum =~~ read_uleb128(reader);
- }
-
- case #default do assert(false, "Bad limit header");
- }
-
- return .{ minimum=minimum, maximum=maximum, shared=shared };
-}
-
-#package
-read_val_type :: (reader: ^io.Reader, binary: ^WasmBinary) -> WasmValueType {
- byte := io.read_byte(reader);
- switch byte {
- case 127 do return .I32;
- case 126 do return .I64;
- case 125 do return .F32;
- case 124 do return .F64;
- case 123 do return .V128;
- case #default {
- conv :: package core.conv
-
- buf : [256] u8;
- _, loc := io.stream_tell(reader.stream);
- s := conv.str_format(buf, "Bad wasm value type {} at {x}", cast(i32) byte, loc);
- assert(false, s);
- }
- }
-
- return ~~0;
-}
-
-#package
-parse_const_uint32 :: (reader: ^io.Reader, binary: ^WasmBinary) -> u32 {
- assert(io.read_byte(reader) == 65, "Expected integer constant");
- value := read_uleb128(reader);
- assert(io.read_byte(reader) == 11, "Expected end for integer constant");
-
- return ~~value;
-}
-
-#package
-parse_section_locations :: (use bin: ^WasmBinary) -> bool {
- stream := io.string_stream_make(data);
- reader := io.reader_make(^stream);
-
- {
- // Checking the magic string
- magic_buffer: [4] u8;
-
- @Bug // If these are string literals, then the null byte messes up the compiler and it thinks its a 0-character string.
- io.read_bytes(^reader, magic_buffer);
- if magic_buffer[0 .. 4] != u8.[ 0, #char "a", #char "s", #char "m" ] do return false;
- io.read_bytes(^reader, magic_buffer);
- if magic_buffer[0 .. 4] != u8.[ 1, 0, 0, 0 ] do return false; // This may not be necessary
- }
-
- while !io.reader_empty(^reader) {
- section_number := cast(WasmSection) io.read_byte(^reader);
- section_size := read_uleb128(^reader);
- _, pos := io.stream_tell(^stream);
-
- switch section_number {
- @Incomplete
- case .Custom ---
-
- case .Type, .Import, .Function, .Table, .Memory, .Global,
- .Export, .Start, .Element, .Code, .Data, .DataCount {
- map.put(^sections, section_number, .{
- offset = pos,
- size = ~~section_size,
- });
- }
-
- case #default {
- buffer: [128] u8;
- conv :: package core.conv
- assert(false, conv.str_format(buffer, "Bad section number {}", cast(i32) section_number));
- }
- }
-
- err := io.stream_seek(^stream, pos + ~~section_size, .Start);
- if err == .OutOfBounds do break;
- }
-
- return true;
-}
+++ /dev/null
-package wasm_utils
-
-WasmSection :: enum {
- Custom :: 0x00;
- Type :: 0x01;
- Import :: 0x02;
- Function :: 0x03;
- Table :: 0x04;
- Memory :: 0x05;
- Global :: 0x06;
- Export :: 0x07;
- Start :: 0x08;
- Element :: 0x09;
- Code :: 0x0a;
- Data :: 0x0b;
- DataCount :: 0x0c;
-}
-
-#match hash.to_u32 macro (w: WasmSection) -> u32 {
- return hash.to_u32(cast(u32) w);
-}
-
-WasmBinary :: struct {
- data: [] u8;
-
- // Section number -> Offset+size of data
- // This does not work for custom sections, as they all have the same section number
- sections: Map(WasmSection, WasmSectionData);
-
- // Custom section name -> Offset into data
- // So there is a custom section location that maps the name of the custom section
- // to the offset into the file. The backing-store for the keys is just the data
- // itself, as the names are in the data for the binary.
- custom_section_locations : Map(str, i32);
-}
-
-WasmSectionData :: struct {
- offset: u32 = 0;
- size: u32 = 0;
-}
-
-WasmValueType :: enum (u8) {
- I32; I64;
- F32; F64;
- V128;
-}
-
-WasmFuncType :: struct {
- params : [] WasmValueType;
- results : [] WasmValueType; // This will probably have only 1 value most of the time, but it is a good idea to support the multi-return proposal
-
- reference : [] u8; // Where in the data is this function type
-}
-
-WasmForeignType :: enum {
- Function;
- Table;
- Memory;
- Global;
-}
-
-WasmImport :: struct {
- module_name : str;
- import_name : str;
-
- type : WasmForeignType;
-
- use _: struct #union {
- index : u32;
- limits : WasmLimits;
- };
-}
-
-WasmExport :: struct {
- name : str;
- type : WasmForeignType;
- index : u32;
-}
-
-WasmFunction :: struct {
- type_index : u32;
-}
-
-WasmLimits :: struct {
- minimum, maximum: u32;
- shared: bool;
-}
-
-WasmMemory :: struct {
- use limits: WasmLimits;
-}
-
-WasmTableType :: enum {
- AnyFunc :: 0x70;
-}
-
-WasmTable :: struct {
- element_type: WasmTableType;
-
- use limits: WasmLimits;
-}
-
-WasmGlobal :: struct {
- type : WasmValueType;
- mutable : bool;
-}
-
-WasmElement :: struct {
- table_index : u32;
- offset : WasmInstruction;
- funcs : [] u32;
-}
-
-WasmData :: struct {
- memory_index : u32;
- offset : WasmInstruction;
-
- data : [] u8;
-}
-
-WasmCode :: struct {
- size : u32;
- locals : [] WasmLocal;
- code_offset : u32;
-}
-
-WasmLocal :: struct {
- type : WasmValueType;
- index : u32; // This realistically could be a u16, which would have better packing, but dealing with casts from u16 to u32 is annoying.
-}
-
-@Relocate // This should maybe in the WasmBinary structure? I'll need to see how I want to use this library.
-WasmSections :: struct {
- allocator: Allocator;
-
- type_section : [] WasmFuncType;
- import_section : [] WasmImport;
- export_section : [] WasmExport;
- function_section : [] WasmFunction;
- start_section : i32; // Index of function to start
- memory_section : [] WasmMemory;
- table_section : [] WasmTable;
- global_section : [] WasmGlobal;
- element_section : [] WasmElement;
- code_section : [] WasmCode;
- data_section : [] WasmData;
-}
-
-load :: (data: [] u8, allocator := context.allocator) -> WasmBinary {
- binary: WasmBinary;
- binary.data = data;
-
- #context_scope {
- context.allocator = allocator;
- map.init(^binary.sections, .{});
- map.init(^binary.custom_section_locations, -1);
- }
-
- assert(parse_section_locations(^binary), "Failed to parse WASM binary");
-
- return binary;
-}
-
-parse_sections :: (use bin: ^WasmBinary, allocator := context.allocator) -> WasmSections {
- ws: WasmSections;
- ws.allocator = allocator;
-
- ws.type_section = parse_type_section(bin, allocator);
- ws.import_section = parse_import_section(bin, allocator);
- ws.export_section = parse_export_section(bin, allocator);
- ws.function_section = parse_function_section(bin, allocator);
- ws.start_section = parse_start_section(bin, allocator);
- ws.memory_section = parse_memory_section(bin, allocator);
- ws.table_section = parse_table_section(bin, allocator);
- ws.global_section = parse_global_section(bin, allocator);
- ws.element_section = parse_element_section(bin, allocator);
- ws.code_section = parse_code_section(bin, allocator);
- ws.data_section = parse_data_section(bin, allocator);
-
- return ws;
-}
-
-free :: (use bin: ^WasmBinary) {
- map.free(^sections);
- map.free(^custom_section_locations);
-}
-
-
-free_sections :: (use sections: ^WasmSections) {
- if type_section.data != null do raw_free(allocator, type_section.data);
- if import_section.data != null do raw_free(allocator, import_section.data);
- if export_section.data != null do raw_free(allocator, export_section.data);
- if function_section.data != null do raw_free(allocator, function_section.data);
- if memory_section.data != null do raw_free(allocator, memory_section.data);
- if table_section.data != null do raw_free(allocator, table_section.data);
- if global_section.data != null do raw_free(allocator, global_section.data);
- if code_section.data != null do raw_free(allocator, code_section.data);
- if data_section.data != null do raw_free(allocator, data_section.data);
-}
-
-
+++ /dev/null
-package wasm_utils
-
-#local io :: package core.io
-
-#package
-read_uleb128 :: (use reader: ^io.Reader) -> u64 {
- result: u64 = 0;
- shift := 0;
- byte: u8;
-
- while true {
- byte = io.read_byte(reader);
- result |= ~~((byte & 127) << ~~shift);
- if (byte & 128) == 0 do break;
-
- shift += 7;
- }
-
- return result;
-}
-
-#package
-read_sleb128 :: (use reader: ^io.Reader, size := 4) -> i64 {
- result: i64 = 0;
- shift := 0;
- byte: u8 = 128;
-
- while (byte & 128) != 0 {
- byte = io.read_byte(reader);
- result |= ~~((byte & 127) << ~~shift);
- shift += 7;
- }
-
- if (shift < size) && (byte & 64) > 0 {
- result |= 0xFFFFFFFFFFFFFFFF << ~~shift;
- }
-
- return result;
-}
+++ /dev/null
-
-#load "./webgl2"
+++ /dev/null
-window.ONYX_MODULES = window.ONYX_MODULES || [];
-
-var programs = [];
-var shaders = [];
-var buffers = [];
-var framebuffers = [];
-var renderbuffers = [];
-var textures = [];
-var uniformlocs = [];
-var vertexArrays = [];
-var canvas = null;
-var gl = null;
-
-window.ONYX_MODULES.push({
- module_name: "gl",
-
- init(name, namelen) {
- const canvasname = onyx_decode_text(name, namelen);
-
- canvas = document.getElementById(canvasname);
- if (canvas == null) return 0;
-
- gl = canvas.getContext("webgl2");
- if (gl == null) return 0;
-
- return 1;
- },
-
- activeTexture(texture) { gl.activeTexture(texture); },
- attachShader(program, shader) { gl.attachShader(programs[program], shaders[shader]); return programs[program]; },
- bindAttribLocation(program, index, name, namelen) { console.log("NOT IMPLEMENTED!"); },
- bindBuffer(target, buffer) {
- if (buffer == -1) {
- gl.bindBuffer(target, null);
- } else {
- gl.bindBuffer(target, buffers[buffer]);
- }
- },
- bindFramebuffer(target, framebuffer) {
- if (framebuffer == -1) {
- gl.bindFramebuffer(target, null);
- } else {
- gl.bindFramebuffer(target, framebuffers[framebuffer]);
- }
- },
- bindRenderbuffer(target, renderbuffer) {
- if (renderbuffer == -1) {
- gl.bindRenderbuffer(target, null);
- } else {
- gl.bindRenderbuffer(target, renderbuffers[renderbuffer]);
- }
- },
- bindTexture(target, texture) {
- if (texture == -1) {
- gl.bindTexture(target, null);
- } else {
- gl.bindTexture(target, textures[texture]);
- }
- },
- bindVertexArray(vertexArray) {
- if (vertexArray == -1) {
- gl.bindVertexArray(null);
- } else {
- gl.bindVertexArray(vertexArrays[vertexArray]);
- }
- },
-
- blendColor(red, green, blue, alpha) { gl.blendColor(red, green, blue, alpha); },
- blendEquation(mode) { gl.blendEquation(mode); },
- blendEquationSeparate(modeRGB, modeAlpha) { gl.blendEquationSeparate(modeRGB, modeAlpha); },
- blendFunc(sfactor, dfactor) { gl.blendFunc(sfactor, dfactor); },
- blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) { gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); },
-
- blitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, mask, filter) {
- gl.blitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, mask, filter);
- },
-
- bufferDataWithData(target, bufferdata, bufferlen, usage) {
- const data = new DataView(window.ONYX_MEMORY.buffer, bufferdata, bufferlen);
- gl.bufferData(target, data, usage);
- },
-
- bufferDataNoData(target, size, usage) { gl.bufferData(target, size, usage); },
- bufferSubData(target, offset, bufferdata, bufferlen) {
- const data = new DataView(window.ONYX_MEMORY.buffer, bufferdata, bufferlen);
- gl.bufferSubData(target, offset, data);
- },
- canvasSize(width, height) {
- canvas.width = width;
- canvas.height = height;
- },
- checkFramebufferStatus(target) { return gl.checkFramebufferStatus(target); },
- clear(bit) { gl.clear(bit); },
- clearColor(r, g, b, a) { gl.clearColor(r, g, b, a); },
- clearDepth(depth) { gl.clearDepth(depth); },
- clearStencil(stencil) { gl.clearStencil(stencil); },
- colorMask(r, g, b, a) { gl.colorMask(r, g, b, a); },
- compileShader(shader) { gl.compileShader(shaders[shader]); },
- compressedTexImage2D(target, level, internalformat, width, height, border, data, datalen) {
- const pixels = new DataView(window.ONYX_MEMORY.buffer, data, datalen);
- gl.compressedTexImage2D(target, level, internalformat, width, height, border, pixels);
- },
- compressedTexSubImage2D(target, level, internalformat, xoff, yoff, width, height, format, data, datalen) {
- const pixels = new DataView(window.ONYX_MEMORY.buffer, data, datalen);
- gl.compressedSubTexImage2D(target, level, internalformat, xoff, yoff, width, height, format, pixels);
- },
- copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) { gl.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); },
- copyTexImage2D(target, level, internalformat, x, y, width, height, border) {
- gl.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
- },
- copyTexSubImage2D(target, level, xoff, yoff, x, y, width, height) {
- gl.copyTexSubImage2D(target, level, xoff, yoff, x, y, width, height);
- },
- createBuffer() {
- const buf = gl.createBuffer();
- if (buf == null) return -1;
-
- buffers.push(buf);
- return buffers.length - 1;
- },
- createFramebuffer() {
- const buf = gl.createFramebuffer();
- if (buf == null) return -1;
-
- framebuffers.push(buf);
- return framebuffers.length - 1;
- },
- createProgram() {
- const prog = gl.createProgram();
- if (prog == null) return -1;
-
- programs.push(prog);
- return programs.length - 1;
- },
- createRenderbuffer() {
- const buf = gl.createRenderbuffer();
- if (buf == null) return -1;
-
- renderbuffers.push(buf);
- return renderbuffers.length - 1;
- },
- createShader(type) {
- const shader = gl.createShader(type);
- if (shader == null) return -1;
-
- shaders.push(shader);
- return shaders.length - 1;
- },
- createTexture() {
- const texture = gl.createTexture();
- if (texture == null) return -1;
-
- textures.push(texture);
- return textures.length - 1;
- },
- createVertexArray() {
- const vao = gl.createVertexArray();
- if (vao == null) return -1;
-
- vertexArrays.push(vao);
- return vertexArrays.length - 1;
- },
- cullFace(mode) { gl.cullFace(mode); },
- deleteBuffer(buffer) { gl.deleteBuffer(buffers[buffer]); },
- deleteFramebuffer(framebuffer) { gl.deleteFramebuffer(framebuffers[framebuffer]); },
- deleteProgram(program) { gl.deleteProgram(programs[program]); },
- deleteRenderbuffer(renderbuffer) { gl.deleteRenderbuffer(renderbuffers[renderbuffer]); },
- deleteShader(shader) { gl.deleteShader(shaders[shader]); },
- deleteTexture(texture) { gl.deleteTexture(textures[texture]); },
- deleteVertexArray(vertexArray) { gl.deleteVertexArray(vertexArrays[vertexArray]); },
- depthFunc(func) { gl.depthFunc(func); },
- depthMask(flag) { gl.depthMask(flag); },
- depthRange(znear, zfar) { gl.depthRange(znear, zfar); },
- detachShader(program, shader) { gl.detachShader(programs[program], shaders[shader]); },
- disable(cap) { gl.disable(cap); },
- disableVertexAttribArray(index) { gl.disableVertexAttribArray(index); },
- drawArrays(mode, first, count) { gl.drawArrays(mode, first, count); },
- drawArraysInstanced(mode, first, count, instanceCount) { gl.drawArraysInstanced(mode, first, count, instanceCount); },
- drawElements(mode, count, type, offset) { gl.drawElements(mode, count, type, offset); },
- drawElementsInstanced(mode, count, type, offset, instanceCount) { gl.drawElementsInstanced(mode, count, type, offset, instanceCount); },
- enable(cap) { gl.enable(cap); },
- enableVertexAttribArray(index) { gl.enableVertexAttribArray(index); },
- finish() { gl.finish(); },
- flush() { gl.flush(); },
- framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) {
- gl.framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffers[renderbuffer]);
- },
- framebufferTexture2D(target, attachment, texttarget, texture, level) {
- gl.framebufferTexture2D(target, attachment, texttarget, textures[texture], level);
- },
- framebufferTextureLayer(target, attachment, texture, level, layer) { gl.framebufferTextureLayer(target, attachment, textures[texture], level, layer); },
- frontFace(mode) { gl.frontFace(mode); },
- generateMipmap(target) { gl.generateMipmap(target); },
- getActiveAttrib(program, index, out) {
- const loc = gl.getActiveAttrib(programs[program], index);
- const data = new Int32Array(window.ONYX_MEMORY.buffer, out, 2);
- data[0] = loc.size;
- data[1] = loc.type;
- },
- getActiveUniform(program, index, out) {
- const loc = gl.getActiveUniform(programs[program], index);
- const data = new Int32Array(window.ONYX_MEMORY.buffer, out, 2);
- data[0] = loc.size;
- data[1] = loc.type;
- },
- // getAttachedShaders() { console.log("NOT IMPLEMENTED!"); },
- getAttribLocation(program, name, namelen) {
- const attribname = onyx_decode_text(name, namelen);
-
- return gl.getAttribLocation(programs[program], attribname);
- },
- // getBufferParameter() { console.log("NOT IMPLEMENTED!"); },
- getBufferSubData(target, srcbyteoffset, dstbufferdata, dstbufferlen, dstoffset, length) {
- const dst = new DataView(window.ONYX_MEMORY.buffer, dstbufferdata, dstbufferlen);
- gl.getBufferSubData(target, srcbyteoffset, dst, dstoffset, length);
- },
- getError() { return gl.getError(); },
- getInternalformatParameter(target, internalformat, pname) { return gl.getInternalformatParameter(target, internalformat, pname); },
- // many of the 'gets() { console.log("NOT IMPLEMENTED!"); },
- getShaderParameter(shader, param) { return gl.getShaderParameter(shaders[shader], param); },
- getProgramParameter(program, param) { return gl.getProgramParameter(programs[program], param); },
- getUniformLocation(program, name, namelen) {
- const uniname = onyx_decode_text(name, namelen);
-
- uniformlocs.push(gl.getUniformLocation(programs[program], uniname));
- return uniformlocs.length - 1;
- },
- getVertexAttribOffset(index, pname) { return gl.getVertexAttribOffset(index, pname); },
- hint(target, mode) { gl.hint(target, mode); },
- isEnabled(cap) { return gl.isEnabled(cap); },
- invalidateFramebuffer(target, attachdata, attachlen) {
- const attachments = new Int32Array(window.ONYX_MEMORY.buffer, attachdata, attachlen);
- gl.invalidateFramebuffer(target, attacements);
- },
- invalidateSubFramebuffer(target, attachdata, attachlen, x, y, width, height) {
- const attachments = new Int32Array(window.ONYX_MEMORY.buffer, attachdata, attachlen);
- gl.invalidateFramebuffer(target, attacements, x, y, width, height);
- },
- lineWidth(width) { gl.lineWidth(width); },
- linkProgram(program) { gl.linkProgram(programs[program]); },
- pixelStorei(pname, param) { gl.pixelStorei(pname, param); },
- polygonOffset(factor, units) { gl.polygonOffset(factor, units); },
- printProgramInfoLog(program) { console.log(gl.getProgramInfoLog(programs[program])); },
- printShaderInfoLog(shader) { console.log(gl.getShaderInfoLog(shaders[shader])); },
- readPixels(x, y, width, height, format, type, pixels, pixelslen) {
- const pixeldata = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen);
- gl.readPixels(x, y, width, height, format, type, pixeldata);
- },
- readBuffer(src) { gl.readBuffer(src); },
- renderbufferStorage(target, internalformat, width, height) { gl.renderbufferStorage(target, internalformat, width, height); },
- renderbufferStorageMultisample(target, samples, internalformat, width, height) {
- gl.renderbufferStorageMultisample(target, samples, internalformat, width, height);
- },
- sampleCoverage(value, invert) { gl.sampleCoverage(value, invert); },
- scissor(x, y, width, height) { gl.scissor(x, y, width, height); },
- setSize(width, height) { canvas.width = width; canvas.height = height; },
- shaderSource(shader, source, sourcelen) {
- const sourcedata = onyx_decode_text(source, sourcelen);
-
- gl.shaderSource(shaders[shader], sourcedata);
- },
- stencilFunc(func, ref, mask) { gl.stencilFunc(func, ref, mask); },
- stencilFuncSeparate(face, func, ref, mask) { gl.stencilFuncSeparate(face, func, ref, mask); },
- stencilMask(mask) { gl.stencilMask(mask); },
- stencilMaskSeparate(face, mask) { gl.stencilMaskSeparate(face, mask); },
- stencilOp(fail, zfail, mask) { gl.stencilOp(fail, zfail, mask); },
- stencilOpSeparate(face, fail, zfail, zpass) { gl.stencilOpSeparate(face, fail, zfail, zpass); },
- texImage2D(target, level, internalformat, width, height, border, format, type, pixels, pixelslen) {
- const data = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen);
- gl.texImage2D(target, level, internalformat, width, height, border, format, type, data);
- },
- texParameterf(target, pname, param) { gl.texParameterf(target, pname, param); },
- texParameteri(target, pname, param) { gl.texParameteri(target, pname, param); },
- texStorage2D(target, levels, internalformat, width, height) { gl.texStorage2D(target, levels, internalformat, width, height); },
- texSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels, pixelslen) {
- const data = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen);
- gl.texSubImage2D(target, level, xoff, yoff, width, height, format, type, data);
- },
- uniform1f(loc, x) { gl.uniform1f(uniformlocs[loc], x); },
- uniform1i(loc, x) { gl.uniform1i(uniformlocs[loc], x); },
- uniform2f(loc, x, y) { gl.uniform2f(uniformlocs[loc], x, y); },
- uniform2i(loc, x, y) { gl.uniform2i(uniformlocs[loc], x, y); },
- uniform3f(loc, x, y, z) { gl.uniform3f(uniformlocs[loc], x, y, z); },
- uniform3i(loc, x, y, z) { gl.uniform3i(uniformlocs[loc], x, y, z); },
- uniform4f(loc, x, y, z, w) { gl.uniform4f(uniformlocs[loc], x, y, z, w); },
- uniform4i(loc, x, y, z, w) { gl.uniform4i(uniformlocs[loc], x, y, z, w); },
- uniform1iv(loc, valueptr, valuelen) { gl.uniform1iv(uniformlocs[loc], new Int32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen)); },
- uniform1fv(loc, valueptr, valuelen) { gl.uniform1fv(uniformlocs[loc], new Float32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen)); },
- uniform2iv(loc, valueptr, valuelen) { gl.uniform2iv(uniformlocs[loc], new Int32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen * 2)); },
- uniform2fv(loc, valueptr, valuelen) { gl.uniform2fv(uniformlocs[loc], new Float32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen * 2)); },
- uniform3iv(loc, valueptr, valuelen) { gl.uniform3iv(uniformlocs[loc], new Int32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen * 3)); },
- uniform3fv(loc, valueptr, valuelen) { gl.uniform3fv(uniformlocs[loc], new Float32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen * 3)); },
- uniform4iv(loc, valueptr, valuelen) { gl.uniform4iv(uniformlocs[loc], new Int32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen * 4)); },
- uniform4fv(loc, valueptr, valuelen) { gl.uniform4fv(uniformlocs[loc], new Float32Array(window.ONYX_MEMORY.buffer, valueptr, valuelen * 4)); },
- uniformMatrix2(loc, transpose, valueptr) {
- const data = new Float32Array(window.ONYX_MEMORY.buffer, valueptr, 4);
- gl.uniformMatrix2fv(uniformlocs[loc], transpose, data);
- },
- uniformMatrix3(loc, transpose, valueptr) {
- const data = new Float32Array(window.ONYX_MEMORY.buffer, valueptr, 9);
- gl.uniformMatrix3fv(uniformlocs[loc], transpose, data);
- },
- uniformMatrix4(loc, transpose, valueptr) {
- const data = new Float32Array(window.ONYX_MEMORY.buffer, valueptr, 16);
- gl.uniformMatrix4fv(uniformlocs[loc], transpose, data);
- },
- useProgram(program) { gl.useProgram(programs[program]); },
- validateProgram(program) { gl.validateProgram(program[program]); },
- vertexAttrib1f(idx, x) { gl.vertexAttrib1f(idx, x); },
- vertexAttrib2f(idx, x, y) { gl.vertexAttrib2f(idx, x, y); },
- vertexAttrib3f(idx, x, y, z) { gl.vertexAttrib3f(idx, x, y, z); },
- vertexAttrib4f(idx, x, y, z, w) { gl.vertexAttrib4f(idx, x, y, z, w); },
- vertexAttribIPointer(idx, size, type, stride, offset) { gl.vertexAttribIPointer(idx, size, type, stride, offset); },
- vertexAttribPointer(idx, size, type, normalized, stride, offset) { gl.vertexAttribPointer(idx, size, type, normalized, stride, offset); },
- vertexAttribDivisor(idx, divisor) { gl.vertexAttribDivisor(idx, divisor); },
- viewport(x, y, width, height) { gl.viewport(x, y, width, height); },
-});
+++ /dev/null
-package gl
-
-// To be used with the corresponding gl.js
-// There are many things that are missing but this suffices for me.
-
-#local runtime :: package runtime
-#if runtime.runtime != .Js {
- #error "'webgl' can only be used with the 'js' runtime."
-}
-
-
-// ClearBufferMask
-DEPTH_BUFFER_BIT :: 0x00000100
-STENCIL_BUFFER_BIT :: 0x00000400
-COLOR_BUFFER_BIT :: 0x00004000
-
-// BeginMode
-POINTS :: 0x0000
-LINES :: 0x0001
-LINE_LOOP :: 0x0002
-LINE_STRIP :: 0x0003
-TRIANGLES :: 0x0004
-TRIANGLE_STRIP :: 0x0005
-TRIANGLE_FAN :: 0x0006
-
-// AlphaFunction (not supported in ES20)
-// NEVER
-// LESS
-// EQUAL
-// LEQUAL
-// GREATER
-// NOTEQUAL
-// GEQUAL
-// ALWAYS
-
-// BlendingFactorDest
-ZERO :: 0
-ONE :: 1
-SRC_COLOR :: 0x0300
-ONE_MINUS_SRC_COLOR :: 0x0301
-SRC_ALPHA :: 0x0302
-ONE_MINUS_SRC_ALPHA :: 0x0303
-DST_ALPHA :: 0x0304
-ONE_MINUS_DST_ALPHA :: 0x0305
-
-// BlendingFactorSrc
-// ZERO
-// ONE
-DST_COLOR :: 0x0306
-ONE_MINUS_DST_COLOR :: 0x0307
-SRC_ALPHA_SATURATE :: 0x0308
-// SRC_ALPHA
-// ONE_MINUS_SRC_ALPHA
-// DST_ALPHA
-// ONE_MINUS_DST_ALPHA
-
-// BlendEquationSeparate
-FUNC_ADD :: 0x8006
-BLEND_EQUATION :: 0x8009
-BLEND_EQUATION_RGB :: 0x8009 // same as BLEND_EQUATION
-BLEND_EQUATION_ALPHA :: 0x883D
-
-// BlendSubtract
-FUNC_SUBTRACT :: 0x800A
-FUNC_REVERSE_SUBTRACT :: 0x800B
-
-// Separate Blend Functions
-BLEND_DST_RGB :: 0x80C8
-BLEND_SRC_RGB :: 0x80C9
-BLEND_DST_ALPHA :: 0x80CA
-BLEND_SRC_ALPHA :: 0x80CB
-CONSTANT_COLOR :: 0x8001
-ONE_MINUS_CONSTANT_COLOR :: 0x8002
-CONSTANT_ALPHA :: 0x8003
-ONE_MINUS_CONSTANT_ALPHA :: 0x8004
-BLEND_COLOR :: 0x8005
-
-// Buffer Objects
-ARRAY_BUFFER :: 0x8892
-ELEMENT_ARRAY_BUFFER :: 0x8893
-ARRAY_BUFFER_BINDING :: 0x8894
-ELEMENT_ARRAY_BUFFER_BINDING :: 0x8895
-
-STREAM_DRAW :: 0x88E0
-STATIC_DRAW :: 0x88E4
-DYNAMIC_DRAW :: 0x88E8
-
-BUFFER_SIZE :: 0x8764
-BUFFER_USAGE :: 0x8765
-
-CURRENT_VERTEX_ATTRIB :: 0x8626
-
-// CullFaceMode
-FRONT :: 0x0404
-BACK :: 0x0405
-FRONT_AND_BACK :: 0x0408
-
-// DepthFunction
-// NEVER
-// LESS
-// EQUAL
-// LEQUAL
-// GREATER
-// NOTEQUAL
-// GEQUAL
-// ALWAYS
-
-// EnableCap
-// TEXTURE_2D
-CULL_FACE :: 0x0B44
-BLEND :: 0x0BE2
-DITHER :: 0x0BD0
-STENCIL_TEST :: 0x0B90
-DEPTH_TEST :: 0x0B71
-SCISSOR_TEST :: 0x0C11
-POLYGON_OFFSET_FILL :: 0x8037
-SAMPLE_ALPHA_TO_COVERAGE :: 0x809E
-SAMPLE_COVERAGE :: 0x80A0
-
-// ErrorCode
-NO_ERROR :: 0
-INVALID_ENUM :: 0x0500
-INVALID_VALUE :: 0x0501
-INVALID_OPERATION :: 0x0502
-OUT_OF_MEMORY :: 0x0505
-
-// FrontFaceDirection
-CW :: 0x0900
-CCW :: 0x0901
-
-// GetPName
-LINE_WIDTH :: 0x0B21
-ALIASED_POINT_SIZE_RANGE :: 0x846D
-ALIASED_LINE_WIDTH_RANGE :: 0x846E
-CULL_FACE_MODE :: 0x0B45
-FRONT_FACE :: 0x0B46
-DEPTH_RANGE :: 0x0B70
-DEPTH_WRITEMASK :: 0x0B72
-DEPTH_CLEAR_VALUE :: 0x0B73
-DEPTH_FUNC :: 0x0B74
-STENCIL_CLEAR_VALUE :: 0x0B91
-STENCIL_FUNC :: 0x0B92
-STENCIL_FAIL :: 0x0B94
-STENCIL_PASS_DEPTH_FAIL :: 0x0B95
-STENCIL_PASS_DEPTH_PASS :: 0x0B96
-STENCIL_REF :: 0x0B97
-STENCIL_VALUE_MASK :: 0x0B93
-STENCIL_WRITEMASK :: 0x0B98
-STENCIL_BACK_FUNC :: 0x8800
-STENCIL_BACK_FAIL :: 0x8801
-STENCIL_BACK_PASS_DEPTH_FAIL :: 0x8802
-STENCIL_BACK_PASS_DEPTH_PASS :: 0x8803
-STENCIL_BACK_REF :: 0x8CA3
-STENCIL_BACK_VALUE_MASK :: 0x8CA4
-STENCIL_BACK_WRITEMASK :: 0x8CA5
-VIEWPORT :: 0x0BA2
-SCISSOR_BOX :: 0x0C10
-// SCISSOR_TEST
-COLOR_CLEAR_VALUE :: 0x0C22
-COLOR_WRITEMASK :: 0x0C23
-UNPACK_ALIGNMENT :: 0x0CF5
-PACK_ALIGNMENT :: 0x0D05
-MAX_TEXTURE_SIZE :: 0x0D33
-MAX_VIEWPORT_DIMS :: 0x0D3A
-SUBPIXEL_BITS :: 0x0D50
-RED_BITS :: 0x0D52
-GREEN_BITS :: 0x0D53
-BLUE_BITS :: 0x0D54
-ALPHA_BITS :: 0x0D55
-DEPTH_BITS :: 0x0D56
-STENCIL_BITS :: 0x0D57
-POLYGON_OFFSET_UNITS :: 0x2A00
-// POLYGON_OFFSET_FILL
-POLYGON_OFFSET_FACTOR :: 0x8038
-TEXTURE_BINDING_2D :: 0x8069
-SAMPLE_BUFFERS :: 0x80A8
-SAMPLES :: 0x80A9
-SAMPLE_COVERAGE_VALUE :: 0x80AA
-SAMPLE_COVERAGE_INVERT :: 0x80AB
-
-// GetTextureParameter
-// TEXTURE_MAG_FILTER
-// TEXTURE_MIN_FILTER
-// TEXTURE_WRAP_S
-// TEXTURE_WRAP_T
-
-COMPRESSED_TEXTURE_FORMATS :: 0x86A3
-
-// HintMode
-DONT_CARE :: 0x1100
-FASTEST :: 0x1101
-NICEST :: 0x1102
-
-// HintTarget
-GENERATE_MIPMAP_HINT :: 0x8192
-
-// DataType
-BYTE :: 0x1400
-UNSIGNED_BYTE :: 0x1401
-SHORT :: 0x1402
-UNSIGNED_SHORT :: 0x1403
-INT :: 0x1404
-UNSIGNED_INT :: 0x1405
-FLOAT :: 0x1406
-
-// PixelFormat
-DEPTH_COMPONENT :: 0x1902
-ALPHA :: 0x1906
-RGB :: 0x1907
-RGBA :: 0x1908
-LUMINANCE :: 0x1909
-LUMINANCE_ALPHA :: 0x190A
-
-// PixelType
-// UNSIGNED_BYTE
-UNSIGNED_SHORT_4_4_4_4 :: 0x8033
-UNSIGNED_SHORT_5_5_5_1 :: 0x8034
-UNSIGNED_SHORT_5_6_5 :: 0x8363
-
-// Shaders
-FRAGMENT_SHADER :: 0x8B30
-VERTEX_SHADER :: 0x8B31
-MAX_VERTEX_ATTRIBS :: 0x8869
-MAX_VERTEX_UNIFORM_VECTORS :: 0x8DFB
-MAX_VARYING_VECTORS :: 0x8DFC
-MAX_COMBINED_TEXTURE_IMAGE_UNITS :: 0x8B4D
-MAX_VERTEX_TEXTURE_IMAGE_UNITS :: 0x8B4C
-MAX_TEXTURE_IMAGE_UNITS :: 0x8872
-MAX_FRAGMENT_UNIFORM_VECTORS :: 0x8DFD
-SHADER_TYPE :: 0x8B4F
-DELETE_STATUS :: 0x8B80
-LINK_STATUS :: 0x8B82
-VALIDATE_STATUS :: 0x8B83
-ATTACHED_SHADERS :: 0x8B85
-ACTIVE_UNIFORMS :: 0x8B86
-ACTIVE_ATTRIBUTES :: 0x8B89
-SHADING_LANGUAGE_VERSION :: 0x8B8C
-CURRENT_PROGRAM :: 0x8B8D
-
-// StencilFunction
-NEVER :: 0x0200
-LESS :: 0x0201
-EQUAL :: 0x0202
-LEQUAL :: 0x0203
-GREATER :: 0x0204
-NOTEQUAL :: 0x0205
-GEQUAL :: 0x0206
-ALWAYS :: 0x0207
-
-// StencilOp
-// ZERO
-KEEP :: 0x1E00
-REPLACE :: 0x1E01
-INCR :: 0x1E02
-DECR :: 0x1E03
-INVERT :: 0x150A
-INCR_WRAP :: 0x8507
-DECR_WRAP :: 0x8508
-
-// StringName
-VENDOR :: 0x1F00
-RENDERER :: 0x1F01
-VERSION :: 0x1F02
-
-// TextureMagFilter
-NEAREST :: 0x2600
-LINEAR :: 0x2601
-
-// TextureMinFilter
-// NEAREST
-// LINEAR
-NEAREST_MIPMAP_NEAREST :: 0x2700
-LINEAR_MIPMAP_NEAREST :: 0x2701
-NEAREST_MIPMAP_LINEAR :: 0x2702
-LINEAR_MIPMAP_LINEAR :: 0x2703
-
-// TextureParameterName
-TEXTURE_MAG_FILTER :: 0x2800
-TEXTURE_MIN_FILTER :: 0x2801
-TEXTURE_WRAP_S :: 0x2802
-TEXTURE_WRAP_T :: 0x2803
-
-// TextureTarget
-TEXTURE_2D :: 0x0DE1
-TEXTURE :: 0x1702
-
-TEXTURE_CUBE_MAP :: 0x8513
-TEXTURE_BINDING_CUBE_MAP :: 0x8514
-TEXTURE_CUBE_MAP_POSITIVE_X :: 0x8515
-TEXTURE_CUBE_MAP_NEGATIVE_X :: 0x8516
-TEXTURE_CUBE_MAP_POSITIVE_Y :: 0x8517
-TEXTURE_CUBE_MAP_NEGATIVE_Y :: 0x8518
-TEXTURE_CUBE_MAP_POSITIVE_Z :: 0x8519
-TEXTURE_CUBE_MAP_NEGATIVE_Z :: 0x851A
-MAX_CUBE_MAP_TEXTURE_SIZE :: 0x851C
-
-// TextureUnit
-TEXTURE0 :: 0x84C0
-TEXTURE1 :: 0x84C1
-TEXTURE2 :: 0x84C2
-TEXTURE3 :: 0x84C3
-TEXTURE4 :: 0x84C4
-TEXTURE5 :: 0x84C5
-TEXTURE6 :: 0x84C6
-TEXTURE7 :: 0x84C7
-TEXTURE8 :: 0x84C8
-TEXTURE9 :: 0x84C9
-TEXTURE10 :: 0x84CA
-TEXTURE11 :: 0x84CB
-TEXTURE12 :: 0x84CC
-TEXTURE13 :: 0x84CD
-TEXTURE14 :: 0x84CE
-TEXTURE15 :: 0x84CF
-TEXTURE16 :: 0x84D0
-TEXTURE17 :: 0x84D1
-TEXTURE18 :: 0x84D2
-TEXTURE19 :: 0x84D3
-TEXTURE20 :: 0x84D4
-TEXTURE21 :: 0x84D5
-TEXTURE22 :: 0x84D6
-TEXTURE23 :: 0x84D7
-TEXTURE24 :: 0x84D8
-TEXTURE25 :: 0x84D9
-TEXTURE26 :: 0x84DA
-TEXTURE27 :: 0x84DB
-TEXTURE28 :: 0x84DC
-TEXTURE29 :: 0x84DD
-TEXTURE30 :: 0x84DE
-TEXTURE31 :: 0x84DF
-ACTIVE_TEXTURE :: 0x84E0
-
-// TextureWrapMode
-REPEAT :: 0x2901
-CLAMP_TO_EDGE :: 0x812F
-MIRRORED_REPEAT :: 0x8370
-
-// Uniform Types
-FLOAT_VEC2 :: 0x8B50
-FLOAT_VEC3 :: 0x8B51
-FLOAT_VEC4 :: 0x8B52
-INT_VEC2 :: 0x8B53
-INT_VEC3 :: 0x8B54
-INT_VEC4 :: 0x8B55
-BOOL :: 0x8B56
-BOOL_VEC2 :: 0x8B57
-BOOL_VEC3 :: 0x8B58
-BOOL_VEC4 :: 0x8B59
-FLOAT_MAT2 :: 0x8B5A
-FLOAT_MAT3 :: 0x8B5B
-FLOAT_MAT4 :: 0x8B5C
-SAMPLER_2D :: 0x8B5E
-SAMPLER_CUBE :: 0x8B60
-
-// Vertex Arrays
-VERTEX_ATTRIB_ARRAY_ENABLED :: 0x8622
-VERTEX_ATTRIB_ARRAY_SIZE :: 0x8623
-VERTEX_ATTRIB_ARRAY_STRIDE :: 0x8624
-VERTEX_ATTRIB_ARRAY_TYPE :: 0x8625
-VERTEX_ATTRIB_ARRAY_NORMALIZED :: 0x886A
-VERTEX_ATTRIB_ARRAY_POINTER :: 0x8645
-VERTEX_ATTRIB_ARRAY_BUFFER_BINDING :: 0x889F
-
-// Read Format
-IMPLEMENTATION_COLOR_READ_TYPE :: 0x8B9A
-IMPLEMENTATION_COLOR_READ_FORMAT :: 0x8B9B
-
-// Shader Source
-COMPILE_STATUS :: 0x8B81
-
-// Shader Precision-Specified Types
-LOW_FLOAT :: 0x8DF0
-MEDIUM_FLOAT :: 0x8DF1
-HIGH_FLOAT :: 0x8DF2
-LOW_INT :: 0x8DF3
-MEDIUM_INT :: 0x8DF4
-HIGH_INT :: 0x8DF5
-
-// Framebuffer Object.
-FRAMEBUFFER :: 0x8D40
-RENDERBUFFER :: 0x8D41
-
-RGBA4 :: 0x8056
-RGB5_A1 :: 0x8057
-RGB565 :: 0x8D62
-DEPTH_COMPONENT16 :: 0x81A5
-STENCIL_INDEX :: 0x1901
-STENCIL_INDEX8 :: 0x8D48
-DEPTH_STENCIL :: 0x84F9
-
-RENDERBUFFER_WIDTH :: 0x8D42
-RENDERBUFFER_HEIGHT :: 0x8D43
-RENDERBUFFER_INTERNAL_FORMAT :: 0x8D44
-RENDERBUFFER_RED_SIZE :: 0x8D50
-RENDERBUFFER_GREEN_SIZE :: 0x8D51
-RENDERBUFFER_BLUE_SIZE :: 0x8D52
-RENDERBUFFER_ALPHA_SIZE :: 0x8D53
-RENDERBUFFER_DEPTH_SIZE :: 0x8D54
-RENDERBUFFER_STENCIL_SIZE :: 0x8D55
-
-FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE :: 0x8CD0
-FRAMEBUFFER_ATTACHMENT_OBJECT_NAME :: 0x8CD1
-FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL :: 0x8CD2
-FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE :: 0x8CD3
-
-COLOR_ATTACHMENT0 :: 0x8CE0
-DEPTH_ATTACHMENT :: 0x8D00
-STENCIL_ATTACHMENT :: 0x8D20
-DEPTH_STENCIL_ATTACHMENT :: 0x821A
-
-NONE :: 0
-
-FRAMEBUFFER_COMPLETE :: 0x8CD5
-FRAMEBUFFER_INCOMPLETE_ATTACHMENT :: 0x8CD6
-FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT :: 0x8CD7
-FRAMEBUFFER_INCOMPLETE_DIMENSIONS :: 0x8CD9
-FRAMEBUFFER_UNSUPPORTED :: 0x8CDD
-
-FRAMEBUFFER_BINDING :: 0x8CA6
-RENDERBUFFER_BINDING :: 0x8CA7
-MAX_RENDERBUFFER_SIZE :: 0x84E8
-
-INVALID_FRAMEBUFFER_OPERATION :: 0x0506
-
-READ_BUFFER :: 0x0C02
-UNPACK_ROW_LENGTH :: 0x0CF2
-UNPACK_SKIP_ROWS :: 0x0CF3
-UNPACK_SKIP_PIXELS :: 0x0CF4
-PACK_ROW_LENGTH :: 0x0D02
-PACK_SKIP_ROWS :: 0x0D03
-PACK_SKIP_PIXELS :: 0x0D04
-COLOR :: 0x1800
-DEPTH :: 0x1801
-STENCIL :: 0x1802
-RED :: 0x1903
-RGB8 :: 0x8051
-RGBA8 :: 0x8058
-RGB10_A2 :: 0x8059
-TEXTURE_BINDING_3D :: 0x806A
-UNPACK_SKIP_IMAGES :: 0x806D
-UNPACK_IMAGE_HEIGHT :: 0x806E
-TEXTURE_3D :: 0x806F
-TEXTURE_WRAP_R :: 0x8072
-MAX_3D_TEXTURE_SIZE :: 0x8073
-UNSIGNED_INT_2_10_10_10_REV :: 0x8368
-MAX_ELEMENTS_VERTICES :: 0x80E8
-MAX_ELEMENTS_INDICES :: 0x80E9
-TEXTURE_MIN_LOD :: 0x813A
-TEXTURE_MAX_LOD :: 0x813B
-TEXTURE_BASE_LEVEL :: 0x813C
-TEXTURE_MAX_LEVEL :: 0x813D
-MIN :: 0x8007
-MAX :: 0x8008
-DEPTH_COMPONENT24 :: 0x81A6
-MAX_TEXTURE_LOD_BIAS :: 0x84FD
-TEXTURE_COMPARE_MODE :: 0x884C
-TEXTURE_COMPARE_FUNC :: 0x884D
-CURRENT_QUERY :: 0x8865
-QUERY_RESULT :: 0x8866
-QUERY_RESULT_AVAILABLE :: 0x8867
-STREAM_READ :: 0x88E1
-STREAM_COPY :: 0x88E2
-STATIC_READ :: 0x88E5
-STATIC_COPY :: 0x88E6
-DYNAMIC_READ :: 0x88E9
-DYNAMIC_COPY :: 0x88EA
-MAX_DRAW_BUFFERS :: 0x8824
-DRAW_BUFFER0 :: 0x8825
-DRAW_BUFFER1 :: 0x8826
-DRAW_BUFFER2 :: 0x8827
-DRAW_BUFFER3 :: 0x8828
-DRAW_BUFFER4 :: 0x8829
-DRAW_BUFFER5 :: 0x882A
-DRAW_BUFFER6 :: 0x882B
-DRAW_BUFFER7 :: 0x882C
-DRAW_BUFFER8 :: 0x882D
-DRAW_BUFFER9 :: 0x882E
-DRAW_BUFFER10 :: 0x882F
-DRAW_BUFFER11 :: 0x8830
-DRAW_BUFFER12 :: 0x8831
-DRAW_BUFFER13 :: 0x8832
-DRAW_BUFFER14 :: 0x8833
-DRAW_BUFFER15 :: 0x8834
-MAX_FRAGMENT_UNIFORM_COMPONENTS :: 0x8B49
-MAX_VERTEX_UNIFORM_COMPONENTS :: 0x8B4A
-SAMPLER_3D :: 0x8B5F
-SAMPLER_2D_SHADOW :: 0x8B62
-FRAGMENT_SHADER_DERIVATIVE_HINT :: 0x8B8B
-PIXEL_PACK_BUFFER :: 0x88EB
-PIXEL_UNPACK_BUFFER :: 0x88EC
-PIXEL_PACK_BUFFER_BINDING :: 0x88ED
-PIXEL_UNPACK_BUFFER_BINDING :: 0x88EF
-FLOAT_MAT2x3 :: 0x8B65
-FLOAT_MAT2x4 :: 0x8B66
-FLOAT_MAT3x2 :: 0x8B67
-FLOAT_MAT3x4 :: 0x8B68
-FLOAT_MAT4x2 :: 0x8B69
-FLOAT_MAT4x3 :: 0x8B6A
-SRGB :: 0x8C40
-SRGB8 :: 0x8C41
-SRGB8_ALPHA8 :: 0x8C43
-COMPARE_REF_TO_TEXTURE :: 0x884E
-RGBA32F :: 0x8814
-RGB32F :: 0x8815
-RGBA16F :: 0x881A
-RGB16F :: 0x881B
-VERTEX_ATTRIB_ARRAY_INTEGER :: 0x88FD
-MAX_ARRAY_TEXTURE_LAYERS :: 0x88FF
-MIN_PROGRAM_TEXEL_OFFSET :: 0x8904
-MAX_PROGRAM_TEXEL_OFFSET :: 0x8905
-MAX_VARYING_COMPONENTS :: 0x8B4B
-TEXTURE_2D_ARRAY :: 0x8C1A
-TEXTURE_BINDING_2D_ARRAY :: 0x8C1D
-R11F_G11F_B10F :: 0x8C3A
-UNSIGNED_INT_10F_11F_11F_REV :: 0x8C3B
-RGB9_E5 :: 0x8C3D
-UNSIGNED_INT_5_9_9_9_REV :: 0x8C3E
-TRANSFORM_FEEDBACK_BUFFER_MODE :: 0x8C7F
-MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS :: 0x8C80
-TRANSFORM_FEEDBACK_VARYINGS :: 0x8C83
-TRANSFORM_FEEDBACK_BUFFER_START :: 0x8C84
-TRANSFORM_FEEDBACK_BUFFER_SIZE :: 0x8C85
-TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN :: 0x8C88
-RASTERIZER_DISCARD :: 0x8C89
-MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS :: 0x8C8A
-MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS :: 0x8C8B
-INTERLEAVED_ATTRIBS :: 0x8C8C
-SEPARATE_ATTRIBS :: 0x8C8D
-TRANSFORM_FEEDBACK_BUFFER :: 0x8C8E
-TRANSFORM_FEEDBACK_BUFFER_BINDING :: 0x8C8F
-RGBA32UI :: 0x8D70
-RGB32UI :: 0x8D71
-RGBA16UI :: 0x8D76
-RGB16UI :: 0x8D77
-RGBA8UI :: 0x8D7C
-RGB8UI :: 0x8D7D
-RGBA32I :: 0x8D82
-RGB32I :: 0x8D83
-RGBA16I :: 0x8D88
-RGB16I :: 0x8D89
-RGBA8I :: 0x8D8E
-RGB8I :: 0x8D8F
-RED_INTEGER :: 0x8D94
-RGB_INTEGER :: 0x8D98
-RGBA_INTEGER :: 0x8D99
-SAMPLER_2D_ARRAY :: 0x8DC1
-SAMPLER_2D_ARRAY_SHADOW :: 0x8DC4
-SAMPLER_CUBE_SHADOW :: 0x8DC5
-UNSIGNED_INT_VEC2 :: 0x8DC6
-UNSIGNED_INT_VEC3 :: 0x8DC7
-UNSIGNED_INT_VEC4 :: 0x8DC8
-INT_SAMPLER_2D :: 0x8DCA
-INT_SAMPLER_3D :: 0x8DCB
-INT_SAMPLER_CUBE :: 0x8DCC
-INT_SAMPLER_2D_ARRAY :: 0x8DCF
-UNSIGNED_INT_SAMPLER_2D :: 0x8DD2
-UNSIGNED_INT_SAMPLER_3D :: 0x8DD3
-UNSIGNED_INT_SAMPLER_CUBE :: 0x8DD4
-UNSIGNED_INT_SAMPLER_2D_ARRAY :: 0x8DD7
-DEPTH_COMPONENT32F :: 0x8CAC
-DEPTH32F_STENCIL8 :: 0x8CAD
-FLOAT_32_UNSIGNED_INT_24_8_REV :: 0x8DAD
-FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING :: 0x8210
-FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE :: 0x8211
-FRAMEBUFFER_ATTACHMENT_RED_SIZE :: 0x8212
-FRAMEBUFFER_ATTACHMENT_GREEN_SIZE :: 0x8213
-FRAMEBUFFER_ATTACHMENT_BLUE_SIZE :: 0x8214
-FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE :: 0x8215
-FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE :: 0x8216
-FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE :: 0x8217
-FRAMEBUFFER_DEFAULT :: 0x8218
-UNSIGNED_INT_24_8 :: 0x84FA
-DEPTH24_STENCIL8 :: 0x88F0
-UNSIGNED_NORMALIZED :: 0x8C17
-DRAW_FRAMEBUFFER_BINDING :: 0x8CA6
-READ_FRAMEBUFFER :: 0x8CA8
-DRAW_FRAMEBUFFER :: 0x8CA9
-READ_FRAMEBUFFER_BINDING :: 0x8CAA
-RENDERBUFFER_SAMPLES :: 0x8CAB
-FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER :: 0x8CD4
-MAX_COLOR_ATTACHMENTS :: 0x8CDF
-COLOR_ATTACHMENT1 :: 0x8CE1
-COLOR_ATTACHMENT2 :: 0x8CE2
-COLOR_ATTACHMENT3 :: 0x8CE3
-COLOR_ATTACHMENT4 :: 0x8CE4
-COLOR_ATTACHMENT5 :: 0x8CE5
-COLOR_ATTACHMENT6 :: 0x8CE6
-COLOR_ATTACHMENT7 :: 0x8CE7
-COLOR_ATTACHMENT8 :: 0x8CE8
-COLOR_ATTACHMENT9 :: 0x8CE9
-COLOR_ATTACHMENT10 :: 0x8CEA
-COLOR_ATTACHMENT11 :: 0x8CEB
-COLOR_ATTACHMENT12 :: 0x8CEC
-COLOR_ATTACHMENT13 :: 0x8CED
-COLOR_ATTACHMENT14 :: 0x8CEE
-COLOR_ATTACHMENT15 :: 0x8CEF
-FRAMEBUFFER_INCOMPLETE_MULTISAMPLE :: 0x8D56
-MAX_SAMPLES :: 0x8D57
-HALF_FLOAT :: 0x140B
-RG :: 0x8227
-RG_INTEGER :: 0x8228
-R8 :: 0x8229
-RG8 :: 0x822B
-R16F :: 0x822D
-R32F :: 0x822E
-RG16F :: 0x822F
-RG32F :: 0x8230
-R8I :: 0x8231
-R8UI :: 0x8232
-R16I :: 0x8233
-R16UI :: 0x8234
-R32I :: 0x8235
-R32UI :: 0x8236
-RG8I :: 0x8237
-RG8UI :: 0x8238
-RG16I :: 0x8239
-RG16UI :: 0x823A
-RG32I :: 0x823B
-RG32UI :: 0x823C
-VERTEX_ARRAY_BINDING :: 0x85B5
-R8_SNORM :: 0x8F94
-RG8_SNORM :: 0x8F95
-RGB8_SNORM :: 0x8F96
-RGBA8_SNORM :: 0x8F97
-SIGNED_NORMALIZED :: 0x8F9C
-COPY_READ_BUFFER :: 0x8F36
-COPY_WRITE_BUFFER :: 0x8F37
-COPY_READ_BUFFER_BINDING :: 0x8F36
-COPY_WRITE_BUFFER_BINDING :: 0x8F37
-UNIFORM_BUFFER :: 0x8A11
-UNIFORM_BUFFER_BINDING :: 0x8A28
-UNIFORM_BUFFER_START :: 0x8A29
-UNIFORM_BUFFER_SIZE :: 0x8A2A
-MAX_VERTEX_UNIFORM_BLOCKS :: 0x8A2B
-MAX_FRAGMENT_UNIFORM_BLOCKS :: 0x8A2D
-MAX_COMBINED_UNIFORM_BLOCKS :: 0x8A2E
-MAX_UNIFORM_BUFFER_BINDINGS :: 0x8A2F
-MAX_UNIFORM_BLOCK_SIZE :: 0x8A30
-MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS :: 0x8A31
-MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS :: 0x8A33
-UNIFORM_BUFFER_OFFSET_ALIGNMENT :: 0x8A34
-ACTIVE_UNIFORM_BLOCKS :: 0x8A36
-UNIFORM_TYPE :: 0x8A37
-UNIFORM_SIZE :: 0x8A38
-UNIFORM_BLOCK_INDEX :: 0x8A3A
-UNIFORM_OFFSET :: 0x8A3B
-UNIFORM_ARRAY_STRIDE :: 0x8A3C
-UNIFORM_MATRIX_STRIDE :: 0x8A3D
-UNIFORM_IS_ROW_MAJOR :: 0x8A3E
-UNIFORM_BLOCK_BINDING :: 0x8A3F
-UNIFORM_BLOCK_DATA_SIZE :: 0x8A40
-UNIFORM_BLOCK_ACTIVE_UNIFORMS :: 0x8A42
-UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES :: 0x8A43
-UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER :: 0x8A44
-UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER :: 0x8A46
-INVALID_INDEX :: 0xFFFFFFF
-MAX_VERTEX_OUTPUT_COMPONENTS :: 0x9122
-MAX_FRAGMENT_INPUT_COMPONENTS :: 0x9125
-MAX_SERVER_WAIT_TIMEOUT :: 0x9111
-OBJECT_TYPE :: 0x9112
-SYNC_CONDITION :: 0x9113
-SYNC_STATUS :: 0x9114
-SYNC_FLAGS :: 0x9115
-SYNC_FENCE :: 0x9116
-SYNC_GPU_COMMANDS_COMPLETE :: 0x9117
-UNSIGNALED :: 0x9118
-SIGNALED :: 0x9119
-ALREADY_SIGNALED :: 0x911A
-TIMEOUT_EXPIRED :: 0x911B
-CONDITION_SATISFIED :: 0x911C
-WAIT_FAILED :: 0x911D
-SYNC_FLUSH_COMMANDS_BIT :: 0x0000001
-VERTEX_ATTRIB_ARRAY_DIVISOR :: 0x88FE
-ANY_SAMPLES_PASSED :: 0x8C2F
-ANY_SAMPLES_PASSED_CONSERVATIVE :: 0x8D6A
-SAMPLER_BINDING :: 0x8919
-RGB10_A2UI :: 0x906F
-INT_2_10_10_10_REV :: 0x8D9F
-TRANSFORM_FEEDBACK :: 0x8E22
-TRANSFORM_FEEDBACK_PAUSED :: 0x8E23
-TRANSFORM_FEEDBACK_ACTIVE :: 0x8E24
-TRANSFORM_FEEDBACK_BINDING :: 0x8E25
-TEXTURE_IMMUTABLE_FORMAT :: 0x912F
-MAX_ELEMENT_INDEX :: 0x8D6B
-TEXTURE_IMMUTABLE_LEVELS :: 0x82DF
-TIMEOUT_IGNORED :: -1
-
-// WebGL-specific enums
-UNPACK_FLIP_Y_WEBGL :: 0x9240
-UNPACK_PREMULTIPLY_ALPHA_WEBGL :: 0x9241
-CONTEXT_LOST_WEBGL :: 0x9242
-UNPACK_COLORSPACE_CONVERSION_WEBGL :: 0x9243
-BROWSER_DEFAULT_WEBGL :: 0x9244
-MAX_CLIENT_WAIT_TIMEOUT_WEBGL :: 0x9247
-
-GLenum :: #type u32
-GLboolean :: #type bool
-GLbitfield :: #type u32
-GLbyte :: #type i8
-GLshort :: #type i16
-GLint :: #type i32
-GLsizei :: #type i32
-GLintptr :: #type i64
-GLsizeiptr :: #type i64
-GLubyte :: #type u8
-GLushort :: #type u16
-GLuint :: #type u32
-GLfloat :: #type f32
-GLclampf :: #type f32
-
-GLProgram :: #type i32
-GLShader :: #type i32
-GLFramebuffer :: #type i32
-GLRenderbuffer :: #type i32
-GLTexture :: #type i32
-GLBuffer :: #type i32
-GLUniformLocation :: #type i32
-GLVertexArrayObject :: #type i32
-
-GLActiveInfo :: struct {
- size : GLint;
- type : GLenum;
-
- // Not used
- name : ^u8;
-}
-
-GLMat2 :: #type [4] GLfloat
-GLMat3 :: #type [9] GLfloat
-GLMat4 :: #type [16] GLfloat
-
-activeTexture :: (texture: GLenum) -> void #foreign "gl" "activeTexture" ---
-attachShader :: (program: GLProgram, shader: GLShader) -> GLProgram #foreign "gl" "attachShader" ---
-bindAttribLocation :: (program: GLProgram, index: GLuint, name: str) -> void #foreign "gl" "bindAttribLocation" ---
-bindBuffer :: (target: GLenum, buffer: GLBuffer) -> void #foreign "gl" "bindBuffer" ---
-bindFramebuffer :: (target: GLenum, framebuffer: GLFramebuffer) -> void #foreign "gl" "bindFramebuffer" ---
-bindRenderbuffer :: (target: GLenum, renderbuffer: GLRenderbuffer) -> void #foreign "gl" "bindRenderbuffer" ---
-bindTexture :: (target: GLenum, texture: GLTexture) -> void #foreign "gl" "bindTexture" ---
-bindVertexArray :: (vertexArray: GLVertexArrayObject) -> void #foreign "gl" "bindVertexArray" ---
-blendColor :: (red: GLclampf, green: GLclampf, blue: GLclampf, alpha: GLclampf) -> void #foreign "gl" "blendColor" ---
-blendEquation :: (mode: GLenum) -> void #foreign "gl" "blendEquation" ---
-blendEquationSeparate :: (modeRGB: GLenum, modeAlpha: GLenum) -> void #foreign "gl" "blendEquationSeparate" ---
-blendFunc :: (sfactor: GLenum, dfactor: GLenum) -> void #foreign "gl" "blendFunc" ---
-blendFuncSeparate :: (srcRGB: GLenum, dstRGB: GLenum, srcAlpha: GLenum, dstAlpha: GLenum) -> void #foreign "gl" "blendFuncSeparate" ---
-blitFramebuffer :: (sx0: GLint, sy0: GLint, sx1: GLint, sy1: GLint, dx0: GLint, dy0: GLint, dx1: GLint, dy1: GLint, mask: GLbitfield, filter: GLenum) -> void #foreign "gl" "blitFramebuffer" ---
-bufferDataWithData :: (target: GLenum, buffer: [] void, usage: GLenum) -> void #foreign "gl" "bufferDataWithData" ---
-bufferDataNoData :: (target: GLenum, size: GLsizei, usage: GLenum) -> void #foreign "gl" "bufferDataNoData" ---
-bufferData :: #match { bufferDataWithData, bufferDataNoData }
-bufferSubData :: (target: GLenum, offset: GLsizei, data: [] void) -> void #foreign "gl" "bufferSubData" ---
-canvasSize :: (width: GLsizei, height: GLsizei) -> void #foreign "gl" "canvasSize" ---
-checkFramebufferStatus :: (target: GLenum) -> GLenum #foreign "gl" "checkFramebufferStatus" ---
-clear :: (mask: GLbitfield) -> void #foreign "gl" "clear" ---
-clearColor :: (red: GLclampf, green: GLclampf, blue: GLclampf, alpha: GLclampf) -> void #foreign "gl" "clearColor" ---
-clearDepth :: (depth: GLclampf) -> void #foreign "gl" "clearDepth" ---
-clearStencil :: (s: GLint) -> void #foreign "gl" "clearStencil" ---
-colorMask :: (red: GLboolean, green: GLboolean, blue: GLboolean, alpha: GLboolean) -> void #foreign "gl" "colorMask" ---
-compileShader :: (shader: GLShader) -> void #foreign "gl" "compileShader" ---
-compressedTexImage2D :: (target: GLenum, level: GLint, internalformat: GLenum, width: GLsizei, height: GLsizei, border: GLint, data: str) -> void #foreign "gl" "compressedTexImage2D" ---
-compressedTexSubImage2D :: (target: GLenum, level: GLint, internalformat: GLenum, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, data: str) -> void #foreign "gl" "compressedTexSubImage2D" ---
-copyBufferSubData :: (readTarget: GLenum, writeTarget: GLenum, readOffset: GLintptr, writeOffset: GLintptr, size: GLsizeiptr) -> void #foreign "gl" "copyBufferSubData" ---
-copyTexImage2D :: (target: GLenum, level: GLint, internalformat: GLenum, x: GLint, y: GLint, width: GLsizei, height: GLsizei, border: GLint) -> void #foreign "gl" "copyTexImage2D" ---
-copyTexSubImage2D :: (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, x: GLint, y: GLint, width: GLsizei, height: GLsizei) -> void #foreign "gl" "copyTexSubImage2D" ---
-createBuffer :: () -> GLBuffer #foreign "gl" "createBuffer" ---
-createFramebuffer :: () -> GLFramebuffer #foreign "gl" "createFramebuffer" ---
-createProgram :: () -> GLProgram #foreign "gl" "createProgram" ---
-createRenderbuffer :: () -> GLRenderbuffer #foreign "gl" "createRenderbuffer" ---
-createShader :: (type: GLenum) -> GLShader #foreign "gl" "createShader" ---
-createTexture :: () -> GLTexture #foreign "gl" "createTexture" ---
-createVertexArray :: () -> GLVertexArrayObject #foreign "gl" "createVertexArray" ---
-cullFace :: (mode: GLenum) -> void #foreign "gl" "cullFace" ---
-deleteBuffer :: (buffer: GLBuffer) -> void #foreign "gl" "deleteBuffer" ---
-deleteFramebuffer :: (framebuffer: GLFramebuffer) -> void #foreign "gl" "deleteFramebuffer" ---
-deleteProgram :: (program: GLProgram) -> void #foreign "gl" "deleteProgram" ---
-deleteRenderbuffer :: (renderbuffer: GLRenderbuffer) -> void #foreign "gl" "deleteRenderbuffer" ---
-deleteShader :: (shader: GLShader) -> void #foreign "gl" "deleteShader" ---
-deleteTexture :: (texture: GLTexture) -> void #foreign "gl" "deleteTexture" ---
-deleteVertexArray :: (vertexArray: GLVertexArrayObject) -> void #foreign "gl" "deleteVertexArray" ---
-depthFunc :: (func: GLenum) -> void #foreign "gl" "depthFunc" ---
-depthMask :: (flag: GLboolean) -> void #foreign "gl" "depthMask" ---
-depthRange :: (zNear: GLclampf, zFar: GLclampf) -> void #foreign "gl" "depthRange" ---
-detachShader :: (program: GLProgram, shader: GLShader) -> void #foreign "gl" "detachShader" ---
-disable :: (cap: GLenum) -> void #foreign "gl" "disable" ---
-disableVertexAttribArray :: (index: GLuint) -> void #foreign "gl" "disableVertexAttribArray" ---
-drawArrays :: (mode: GLenum, first: GLint, count: GLsizei) -> void #foreign "gl" "drawArrays" ---
-drawArraysInstanced :: (mode: GLenum, first: GLint, count: GLsizei, instanceCount: GLsizei) -> void #foreign "gl" "drawArraysInstanced" ---
-drawElements :: (mode: GLenum, count: GLsizei, type: GLenum, offset: GLint) -> void #foreign "gl" "drawElements" ---
-drawElementsInstanced :: (mode: GLenum, count: GLsizei, type: GLenum, offset: GLint, instanceCount: GLsizei) -> void #foreign "gl" "drawElementsInstanced" ---
-enable :: (cap: GLenum) -> void #foreign "gl" "enable" ---
-enableVertexAttribArray :: (index: GLuint) -> void #foreign "gl" "enableVertexAttribArray" ---
-finish :: () -> void #foreign "gl" "finish" ---
-flush :: () -> void #foreign "gl" "flush" ---
-framebufferRenderbuffer :: (target: GLenum, attachment: GLenum, renderbuffertarget: GLenum, renderbuffer: GLRenderbuffer) -> void #foreign "gl" "framebufferRenderbuffer" ---
-framebufferTexture2D :: (target: GLenum, attachment: GLenum, textarget: GLenum, texture: GLTexture, level: GLint) -> void #foreign "gl" "framebufferTexture2D" ---
-framebufferTextureLayer :: (target: GLenum, attachment: GLenum, texture: GLTexture, level: GLint, layer: GLint) -> void #foreign "gl" "framebufferTextureLayer" ---
-frontFace :: (mode: GLenum) -> void #foreign "gl" "frontFace" ---
-generateMipmap :: (target: GLenum) -> void #foreign "gl" "generateMipmap" ---
-getActiveAttrib :: (program: GLProgram, index: GLuint, out: ^GLActiveInfo) -> void #foreign "gl" "getActiveAttrib" ---
-getActiveUniform :: (program: GLProgram, index: GLuint, out: ^GLActiveInfo) -> void #foreign "gl" "getActiveUniform" ---
-// getAttachedShaders does not work yet because we can't return a list of things
-getAttribLocation :: (program: GLProgram, name: str) -> GLint #foreign "gl" "getAttribLocation" ---
-getBufferSubData :: (target: GLenum, srcByteOffset: GLintptr, dstBuffer: str, dstOffset: GLuint, length: GLuint) -> void #foreign "gl" "getBufferSubData" ---
-// getBufferParameter and getParameter do not work
-getError :: () -> GLenum #foreign "gl" "getError" ---
-getInternalformatParameter :: (target: GLenum, internalFormat: GLenum, pname: GLenum) -> GLenum #foreign "gl" "getInternalformatParameter" ---
-// many of the 'gets' don't work yet because they return very javascripty things
-getProgramParameter :: (program: GLProgram, pname: GLenum) -> GLenum #foreign "gl" "getProgramParameter" ---
-getShaderParameter :: (shader: GLShader, pname: GLenum) -> GLenum #foreign "gl" "getShaderParameter" ---
-getUniformLocation :: (program: GLProgram, name: str) -> GLUniformLocation #foreign "gl" "getUniformLocation" ---
-getVertexAttribOffset :: (index: GLuint, pname: GLenum) -> void #foreign "gl" "getVertexAttribOffset" ---
-hint :: (target: GLenum, mode: GLenum) -> void #foreign "gl" "hint" ---
-init :: (canvasname: str) -> GLboolean #foreign "gl" "init" ---
-invalidateFramebuffer :: (target: GLenum, attachments: str) -> void #foreign "gl" "invalidateFramebuffer" ---
-invalidateSubFramebuffer :: (target: GLenum, attachments: str, x: GLint, y: GLint, width: GLsizei, height: GLsizei) -> void #foreign "gl" "invalidateSubFramebuffer" ---
-isEnabled :: (cap: GLenum) -> GLboolean #foreign "gl" "isEnabled" ---
-lineWidth :: (width: GLfloat) -> void #foreign "gl" "lineWidth" ---
-linkProgram :: (program: GLProgram) -> void #foreign "gl" "linkProgram" ---
-pixelStorei :: (pname: GLenum, param: GLenum) -> void #foreign "gl" "pixelStorei" ---
-polygonOffset :: (factor: GLfloat, units: GLfloat) -> void #foreign "gl" "polygonOffset" ---
-printProgramInfoLog :: (program: GLProgram) -> void #foreign "gl" "printProgramInfoLog" ---
-printShaderInfoLog :: (shader: GLShader) -> void #foreign "gl" "printShaderInfoLog" ---
-readBuffer :: (src: GLenum) -> void #foreign "gl" "readBuffer" ---
-readPixels :: (x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: str) -> void #foreign "gl" "readPixels" ---
-renderbufferStorage :: (target: GLenum, internalformat: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "renderbufferStorage" ---
-renderbufferStorageMultisample :: (target: GLenum, samples: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "renderbufferStorageMultisample" ---
-sampleCoverage :: (value: GLclampf, invert: GLboolean) -> void #foreign "gl" "sampleCoverage" ---
-scissor :: (x: GLint, y: GLint, width: GLsizei, height: GLsizei) -> void #foreign "gl" "scissor" ---
-setSize :: (width: GLint, y: GLint) -> void #foreign "gl" "setSize" ---
-shaderSource :: (shader: GLShader, source: str) -> void #foreign "gl" "shaderSource" ---
-stencilFunc :: (func: GLenum, ref: GLint, mask: GLuint) -> void #foreign "gl" "stencilFunc" ---
-stencilFuncSeparate :: (face: GLenum, func: GLenum, ref: GLint, mask: GLuint) -> void #foreign "gl" "stencilFuncSeparate" ---
-stencilMask :: (mask: GLuint) -> void #foreign "gl" "stencilMask" ---
-stencilMaskSeparate :: (face: GLenum, mask: GLenum) -> void #foreign "gl" "stencilMaskSeparate" ---
-stencilOp :: (fail: GLenum, zfail: GLenum, zpass: GLenum) -> void #foreign "gl" "stencilOp" ---
-stencilOpSeparate :: (face: GLenum, fail: GLenum, zfail: GLenum, zpass: GLenum) -> void #foreign "gl" "stencilOpSeparate" ---
-texImage2D :: (target: GLenum, level: GLint, internalFormat: GLenum, width: GLsizei, height: GLsizei, border: GLint, format: GLenum, type: GLenum, pixels: str) -> void #foreign "gl" "texImage2D" ---
-texParameterf :: (target: GLenum, pname: GLenum, param: GLfloat) -> void #foreign "gl" "texParameterf" ---
-texParameteri :: (target: GLenum, pname: GLenum, param: GLint) -> void #foreign "gl" "texParameteri" ---
-texStorage2D :: (target: GLenum, levels: GLsizei, internalformat: GLenum, width: GLsizei, height: GLsizei) -> void #foreign "gl" "texStorage2D" ---
-texSubImage2D :: (target: GLenum, level: GLint, xoff: GLint, yoff: GLint, width: GLsizei, height: GLsizei, format: GLenum, type: GLenum, pixels: str) -> void #foreign "gl" "texSubImage2D" ---
-uniform1f :: (loc: GLUniformLocation, x: GLfloat) -> void #foreign "gl" "uniform1f" ---
-uniform1i :: (loc: GLUniformLocation, x: GLint) -> void #foreign "gl" "uniform1i" ---
-uniform2f :: (loc: GLUniformLocation, x: GLfloat, y: GLfloat) -> void #foreign "gl" "uniform2f" ---
-uniform2i :: (loc: GLUniformLocation, x: GLint, y: GLint) -> void #foreign "gl" "uniform2i" ---
-uniform3f :: (loc: GLUniformLocation, x: GLfloat, y: GLfloat, z: GLfloat) -> void #foreign "gl" "uniform3f" ---
-uniform3i :: (loc: GLUniformLocation, x: GLint, y: GLint, z: GLint) -> void #foreign "gl" "uniform3i" ---
-uniform4f :: (loc: GLUniformLocation, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) -> void #foreign "gl" "uniform4f" ---
-uniform4i :: (loc: GLUniformLocation, x: GLint, y: GLint, z: GLint, w: GLint) -> void #foreign "gl" "uniform4i" ---
-uniform1iv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform1iv" ---
-uniform1fv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform1fv" ---
-uniform2iv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform2iv" ---
-uniform2fv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform2fv" ---
-uniform3iv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform3iv" ---
-uniform3fv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform3fv" ---
-uniform4iv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform4iv" ---
-uniform4fv :: (loc: GLUniformLocation, v: [] void) -> void #foreign "gl" "uniform4fv" ---
-uniformMatrix2 :: (loc: GLUniformLocation, transpose: GLboolean, value: GLMat2) -> void #foreign "gl" "uniformMatrix2" ---
-uniformMatrix3 :: (loc: GLUniformLocation, transpose: GLboolean, value: GLMat3) -> void #foreign "gl" "uniformMatrix3" ---
-uniformMatrix4 :: (loc: GLUniformLocation, transpose: GLboolean, value: GLMat4) -> void #foreign "gl" "uniformMatrix4" ---
-useProgram :: (program: GLProgram) -> void #foreign "gl" "useProgram" ---
-validateProgram :: (program: GLProgram) -> void #foreign "gl" "validateProgram" ---
-vertexAttrib1f :: (idx: GLuint, x: GLfloat) -> void #foreign "gl" "vertexAttrib1f" ---
-vertexAttrib2f :: (idx: GLuint, x: GLfloat, y: GLfloat) -> void #foreign "gl" "vertexAttrib2f" ---
-vertexAttrib3f :: (idx: GLuint, x: GLfloat, y: GLfloat, z: GLfloat) -> void #foreign "gl" "vertexAttrib3f" ---
-vertexAttrib4f :: (idx: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) -> void #foreign "gl" "vertexAttrib4f" ---
-vertexAttribIPointer :: (idx: GLuint, size: GLint, type: GLenum, stride: GLsizei, offset: GLint) -> void #foreign "gl" "vertexAttribIPointer" ---
-vertexAttribPointer :: (idx: GLuint, size: GLint, type: GLenum, normalized: GLboolean, stride: GLsizei, offset: GLint) -> void #foreign "gl" "vertexAttribPointer" ---
-vertexAttribDivisor :: (idx: GLuint, divisor: GLuint) -> void #foreign "gl" "vertexAttribDivisor" ---
-viewport :: (x: GLint, y: GLint, width: GLsizei, height: GLsizei) -> void #foreign "gl" "viewport" ---