diff options
author | alaric <alaric@netmythos.org> | 2024-03-31 20:19:27 -0700 |
---|---|---|
committer | alaric <alaric@netmythos.org> | 2024-03-31 20:19:27 -0700 |
commit | c43b1f972cd91b157f7d0997c5bdd9d94590d93d (patch) | |
tree | 819ceae67a4d7a88c16d798384cd7ce25cb5eac7 | |
download | menger-c43b1f972cd91b157f7d0997c5bdd9d94590d93d.tar.gz menger-c43b1f972cd91b157f7d0997c5bdd9d94590d93d.zip |
Initial Commit
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | build.zig | 37 | ||||
-rw-r--r-- | build.zig.zon | 62 | ||||
-rw-r--r-- | flake.lock | 146 | ||||
-rw-r--r-- | flake.nix | 48 | ||||
-rw-r--r-- | src/shell.html | 134 | ||||
-rw-r--r-- | src/wasm_msponge.zig | 10 | ||||
-rw-r--r-- | src/webgl.js | 273 | ||||
-rw-r--r-- | src/webgl.zig | 155 |
9 files changed, 866 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c80a22 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +zig-* diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..d7173b3 --- /dev/null +++ b/build.zig @@ -0,0 +1,37 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.resolveTargetQuery(.{ + .cpu_arch = .wasm32, + .os_tag = .freestanding, + }); + const optimize = b.standardOptimizeOption(.{}); + + b.installFile("src/shell.html", "index.html"); + b.installFile("src/webgl.js", "webgl.js"); + + const exe = b.addExecutable(.{ + .name = "msponge", + .root_source_file = .{ .path = "src/wasm_msponge.zig" }, + .target = target, + .optimize = optimize, + }); + exe.entry = .disabled; + exe.root_module.export_symbol_names = &[_][]const u8{ + "init", + "update", + }; + + b.installArtifact(exe); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/wasm_msponge.zig" }, + .target = target, + .optimize = optimize, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..d77ca61 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,62 @@ +.{ + .name = "menger-sponge", + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // This field is optional. + // This is currently advisory only; Zig does not yet do anything + // with this value. + //.minimum_zig_version = "0.11.0", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + // See `zig fetch --save <url>` for a command-line interface for adding dependencies. + //.example = .{ + // // When updating this field to a new URL, be sure to delete the corresponding + // // `hash`, otherwise you are communicating that you expect to find the old hash at + // // the new URL. + // .url = "https://example.com/foo.tar.gz", + // + // // This is computed from the file contents of the directory of files that is + // // obtained after fetching `url` and applying the inclusion rules given by + // // `paths`. + // // + // // This field is the source of truth; packages do not come from a `url`; they + // // come from a `hash`. `url` is just one of many possible mirrors for how to + // // obtain a package matching this `hash`. + // // + // // Uses the [multihash](https://multiformats.io/multihash/) format. + // .hash = "...", + // + // // When this is provided, the package is found in a directory relative to the + // // build root. In this case the package's hash is irrelevant and therefore not + // // computed. This field and `url` are mutually exclusive. + // .path = "foo", + //}, + }, + + // Specifies the set of files and directories that are included in this package. + // Only files and directories listed here are included in the `hash` that + // is computed for this package. + // Paths are relative to the build root. Use the empty string (`""`) to refer to + // the build root itself. + // A directory listed here means that all files within, recursively, are included. + .paths = .{ + // This makes *all* files, recursively, included in this package. It is generally + // better to explicitly list the files and directories instead, to insure that + // fetching from tarballs, file system paths, and version control all result + // in the same contents hash. + "", + // For example... + //"build.zig", + //"build.zig.zon", + //"src", + //"LICENSE", + //"README.md", + }, +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..1567007 --- /dev/null +++ b/flake.lock @@ -0,0 +1,146 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1704290814, + "narHash": "sha256-LWvKHp7kGxk/GEtlrGYV68qIvPHkU9iToomNFGagixU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "70bdadeb94ffc8806c0570eb5c2695ad29f0e421", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1702350026, + "narHash": "sha256-A+GNZFZdfl4JdDphYKBJ5Ef1HOiFsP18vQe9mqjmUis=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9463103069725474698139ab10f17a9d125da859", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "zig": "zig" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "zig": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1711800454, + "narHash": "sha256-uanB/jYcVbIq9+K7n8Iom1+gADAW8T+AjK2x7XdtxOY=", + "owner": "mitchellh", + "repo": "zig-overlay", + "rev": "7bd8979683da11946fe29f7654567356ac3b1989", + "type": "github" + }, + "original": { + "owner": "mitchellh", + "repo": "zig-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..07d50eb --- /dev/null +++ b/flake.nix @@ -0,0 +1,48 @@ +{ + description = "The flake for Menger Sponge"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05"; + flake-utils.url = "github:numtide/flake-utils"; + zig.url = "github:mitchellh/zig-overlay"; + + # Used for shell.nix + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + ... + } @ inputs: let + overlays = [ + # Other overlays + (final: prev: { + zigpkgs = inputs.zig.packages.${prev.system}; + }) + ]; + + # Our supported systems are the same supported systems as the Zig binaries + systems = builtins.attrNames inputs.zig.packages; + in + flake-utils.lib.eachSystem systems ( + system: let + pkgs = import nixpkgs {inherit overlays system;}; + in { + devShells.default = pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + zigpkgs.master + python3 + ]; + }; + + # For compatibility with older versions of the `nix` binary + devShell = self.devShells.${system}.default; + } + ); +} + diff --git a/src/shell.html b/src/shell.html new file mode 100644 index 0000000..cc1e002 --- /dev/null +++ b/src/shell.html @@ -0,0 +1,134 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Menger Sponge</title> + <style> + body { + overflow: hidden; + min-width: 1280px; + min-height: 720px; + display: flex; + flex-direction: column; + margin: 0; + } + #app-canvas { + display: flex; + flex-grow: 1; + width: 100%; + height: 100%; + } + </style> + </head> + <body> + <canvas id="app-canvas" tabindex="0"></canvas> + <script src="webgl.js"></script> + <script> + canvas.width = canvas.clientWidth; + canvas.height = canvas.clientHeight; + let memory = null; + let last_frame_time = Date.now(); + + const writeString = (str, pointer, length) => { + if (!memory) { + return null; + } + + const l = Math.min(length, str.length); + const from = new TextEncoder().encode(str.slice(0, l)); + const to = new Uint8Array(memory.buffer, pointer, length); + to.set(from); + return l; + }; + + const readString = (pointer, length) => { + if (!memory) { + return null; + } + + // Memory in WASM is one big buffer. We can read a string from the + // Zig/WASM space if we know the pointer and length. + return new TextDecoder().decode( + new Uint8Array(memory.buffer, pointer, length), + ); + }; + + + const consoleLog = (ptr, len) => { + console.log(readString(ptr, len)); + } + + const rand = () => { + return Math.random(); + }; + + const loadTexture = (ptr, len, tex_id, ret_ptr) => { + const path = readString(ptr, len); + var image = new Image(); + image.src = path; + console.log("loading ", path); + image.addEventListener('load', function() { + const ret_list = new Uint32Array(memory.buffer, ret_ptr, 3); + ret_list[0] = 1; + ret_list[1] = image.width; + ret_list[2] = image.height; + console.log(path, " loaded"); + const tex = glTextures.get(tex_id); + gfx_ctx.bindTexture(gfx_ctx.TEXTURE_2D, tex); + gfx_ctx.texImage2D(gfx_ctx.TEXTURE_2D, 0, gfx_ctx.RGBA, gfx_ctx.RGBA, gfx_ctx.UNSIGNED_BYTE, image); + gfx_ctx.generateMipmap(gfx_ctx.TEXTURE_2D); + }); + }; + + const keyRegistry = new Map(); + canvas.addEventListener("keydown", (e) => { + const p = keyRegistry.get(e.code); + if (p) { + p[0] = 1; + } + }); + + canvas.addEventListener("keyup", (e) => { + const p = keyRegistry.get(e.code); + if (p) { + p[0] = 0; + } + }); + + const registerKeyInput = (ptr, len, out_ptr) => { + const code = readString(ptr, len); + const list = new Uint32Array(memory.buffer, out_ptr, 1); + keyRegistry.set(code, list); + }; + + const importObject = { + env: { + ...webgl, + consoleLog, + rand, + loadTexture, + registerKeyInput, + }, + }; + + WebAssembly.instantiateStreaming(fetch("bin/msponge.wasm"), importObject).then( + (obj) => { + memory = obj.instance.exports.memory; + obj.instance.exports.init(); + + const update = obj.instance.exports.update; + function step() { + const time = Date.now(); + const elapsed = time - last_frame_time; + update(elapsed / 1000); + last_frame_time = time; + window.requestAnimationFrame(step); + } + + window.requestAnimationFrame(step); + } + ); + </script> + </body> +</html> diff --git a/src/wasm_msponge.zig b/src/wasm_msponge.zig new file mode 100644 index 0000000..376e011 --- /dev/null +++ b/src/wasm_msponge.zig @@ -0,0 +1,10 @@ +extern fn consoleLog(ptr: [*c]const u8, len: u32) void; + +export fn init() void { + const message = "Hello Menger Sponge!"; + consoleLog(message.ptr, message.len); +} + +export fn update(delta_time: f32) void { + _ = delta_time; +} diff --git a/src/webgl.js b/src/webgl.js new file mode 100644 index 0000000..7c60142 --- /dev/null +++ b/src/webgl.js @@ -0,0 +1,273 @@ +const canvas = document.getElementById("app-canvas"); +const gfx_ctx = canvas.getContext("webgl2"); +if (gfx_ctx === null) { + alert("There was a problem initializing WebGL. Your browser or machine may not support it."); +} + +gfx_ctx.enable(gfx_ctx.BLEND); +gfx_ctx.enable(gfx_ctx.DEPTH_TEST); +gfx_ctx.blendFunc(gfx_ctx.SRC_ALPHA, gfx_ctx.ONE_MINUS_SRC_ALPHA); + +let next_id = 0; +const getId = () => { + next_id += 1; + return next_id - 1; +}; + +const glBuffers = new Map(); +const glShaders = new Map(); +const glPrograms = new Map(); +const glVertexArrays = new Map(); +const glUniformLocations = new Map(); +const glTextures = new Map(); + +const attachShader = (program_id, shader_id) => { + const program = glPrograms.get(program_id); + const shader = glShaders.get(shader_id); + gfx_ctx.attachShader(program, shader); +}; + +const blendFunc = (sfactor, dfactor) => { + gfx_ctx.blendFunc(sfactor, dfactor); +}; + +const bindBuffer = (target, id) => { + gfx_ctx.bindBuffer(target, glBuffers.get(id)); +}; + +const bufferData = (target, ptr, len, usage) => { + const floats = new Float32Array(memory.buffer, ptr, len); + if (len === 9) { + console.log(floats); + } + gfx_ctx.bufferData(target, floats, usage); +}; + +const bindVertexArray = (vao) => { + gfx_ctx.bindVertexArray(glVertexArrays.get(vao)); +}; + +const createVertexArray = () => { + const id = getId(); + glVertexArrays.set(id, gfx_ctx.createVertexArray()); + return id; +}; + +const clearColor = (r, g, b, a) => { + gfx_ctx.clearColor(r, g, b, a); +}; + +const clear = (mask) => { + gfx_ctx.clear(mask); +}; + +const createBuffer = () => { + const id = getId(); + glBuffers.set(id, gfx_ctx.createBuffer()); + return id; +}; + +const createShader = (type) => { + const id = getId(); + glShaders.set(id, gfx_ctx.createShader(type)); + return id; +}; + +const compileShader = (shader) => { + gfx_ctx.compileShader(glShaders.get(shader)); +}; + +const createProgram = (type) => { + const id = getId(); + glPrograms.set(id, gfx_ctx.createProgram()); + return id; +}; + +const deleteShader = (shader) => { + gfx_ctx.deleteShader(glShaders.get(shader)); +}; + +const deleteProgram = (program) => { + gfx_ctx.deleteProgram(glPrograms.get(program)); +}; + +const enable = (cap) => { + gfx_ctx.enable(cap); +}; + + +const enableVertexAttribArray = (attrib_location) => { + gfx_ctx.enableVertexAttribArray(attrib_location); +}; + +const getShaderParameter = (shader, info) => { + return gfx_ctx.getShaderParameter(glShaders.get(shader), info); +}; + +const getShaderInfoLog = (shader, ptr, len) => { + const msg = gfx_ctx.getShaderInfoLog(glShaders.get(shader)); + const r = writeString(msg, ptr, len); + return r; +}; + +const getProgramParameter = (program_id, info) => { + const program = glPrograms.get(program_id); + return gfx_ctx.getProgramParameter(program, info); +}; + +const getProgramInfoLog = (program, ptr, len) => { + const msg = gfx_ctx.getProgramInfoLog(glPrograms.get(program)); + const r = writeString(msg, ptr, len); + return r; +}; + +const getAttribLocation = (program, ptr, len) => { + const attrib = readString(ptr, len); + return gfx_ctx.getAttribLocation(glPrograms.get(program), attrib); +}; + +const getUniformLocation = (program, ptr, len) => { + const uniform = readString(ptr, len); + const loc = gfx_ctx.getUniformLocation(glPrograms.get(program), uniform); + if (!loc) console.log("Uniform ", uniform, " could not be found"); + if (!loc) return -1; + + const id = getId(); + glUniformLocations.set(id, loc); + return id; +}; + +const linkProgram = (program) => { + gfx_ctx.linkProgram(glPrograms.get(program)); +}; + +const shaderSource = (shader, ptr, len) => { + const source = readString(ptr, len); + console.log(source); + gfx_ctx.shaderSource(glShaders.get(shader), source); +}; + +const useProgram = (prog) => { + gfx_ctx.useProgram(glPrograms.get(prog)); +}; + +const uniform1i = (location, v0) => { + gfx_ctx.uniform1i(glUniformLocations.get(location), v0); +}; + +const uniform2f = (location, v0, v1) => { + gfx_ctx.uniform2f(glUniformLocations.get(location), v0, v1); +}; + +const uniform4f = (location, v0, v1, v2, v3) => { + gfx_ctx.uniform4f(glUniformLocations.get(location), v0, v1, v2, v3); +}; + +const uniformMatrix3fv = (location, ptr) => { + const u = glUniformLocations.get(location); + const floats = new Float32Array(memory.buffer, ptr, 9); + + gfx_ctx.uniformMatrix3fv(glUniformLocations.get(location), false, floats); +}; + +const vertexAttribPointer = (loc, size, type, normalize, stride, offset) => { + gfx_ctx.vertexAttribPointer(loc, size, type, normalize, stride, offset); +}; + +const viewport = (x, y, width, height) => { + gfx_ctx.viewport(x, y, width, height); +}; + +const drawArrays = (mode, first, count) => { + gfx_ctx.drawArrays(mode, first, count); +}; + +const createTexture = () => { + const id = getId(); + glTextures.set(id, gfx_ctx.createTexture()); + return id; +}; + +const bindTexture = (target, tex_id) => { + const texture = glTextures.get(tex_id); + gfx_ctx.bindTexture(target, texture); +}; + +const texImage2D = (target, level, interal_format, + width, height, border, format, + data_type, ptr, count, offset) => { + const data = new Uint8Array(memory.buffer, ptr, count); + gfx_ctx.texImage2D(target, level, interal_format, width, height, border, format, data_type, data, offset); +}; + +const activeTexture = (tex_id) => { + gfx_ctx.activeTexture(tex_id); +}; + +const vertexAttribDivisor = (loc, divisor) => { + gfx_ctx.vertexAttribDivisor(loc, divisor); +}; + +const drawArraysInstanced = (mode, first, count, instanceCount) => { + gfx_ctx.drawArraysInstanced(mode, first, count, instanceCount); +}; + +const getScreenWidth = () => { + return gfx_ctx.drawingBufferWidth; +}; + +const getScreenHeight = () => { + return gfx_ctx.drawingBufferHeight; +}; + +const webgl = { + bindBuffer, + blendFunc, + bufferData, + + createShader, + clear, + clearColor, + createBuffer, + + enable, + + shaderSource, + compileShader, + getShaderParameter, + deleteShader, + getShaderInfoLog, + + createProgram, + deleteProgram, + attachShader, + linkProgram, + getProgramParameter, + getProgramInfoLog, + useProgram, + + getAttribLocation, + getUniformLocation, + createVertexArray, + bindVertexArray, + enableVertexAttribArray, + vertexAttribPointer, + viewport, + drawArrays, + + uniform1i, + uniform2f, + uniform4f, + uniformMatrix3fv, + + createTexture, + bindTexture, + texImage2D, + activeTexture, + + vertexAttribDivisor, + drawArraysInstanced, + + getScreenWidth, + getScreenHeight, +}; diff --git a/src/webgl.zig b/src/webgl.zig new file mode 100644 index 0000000..b97c8fa --- /dev/null +++ b/src/webgl.zig @@ -0,0 +1,155 @@ +pub const Buffer = extern struct { handle: u32 }; +pub const Shader = packed struct(u32) { handle: u32 }; +pub const Program = packed struct(u32) { handle: u32 }; +pub const Texture = packed struct(u32) { handle: u32 }; + +pub const GLProgramInfo = enum(u32) { + delete_status = 0x8B80, + link_status = 0x8B82, +}; + +pub const GLShaderType = enum(u32) { + fragment_shader = 0x8B30, + vertex_shader = 0x8B31, +}; + +pub const GLShaderInfo = enum(u32) { + shader_type = 0x8B4F, + delete_status = 0x8B80, + compile_status = 0x8B81, +}; + +pub const GLBindingPoint = enum(u32) { + array_buffer = 0x8892, + element_array_buffer = 0x8893, +}; + +pub const GLUsagePattern = enum(u32) { + stream_draw = 0x88E0, + static_draw = 0x88E4, + dynamic_draw = 0x88E8, +}; + +pub const color_buffer_bit = 0x00004000; +pub const depth_buffer_bit = 0x00000100; + +pub extern fn clearColor(r: f32, g: f32, b: f32, a: f32) void; +pub extern fn clear(mask: u32) void; + +pub extern fn enable(cap: u32) void; +pub extern fn blendFunc(sfactor: u32, dfactor: u32) void; + +pub extern fn createBuffer() Buffer; +pub extern fn bindBuffer(target: GLBindingPoint, buffer: Buffer) void; +pub extern fn bufferData( + target: GLBindingPoint, + ptr: [*c]const f32, + len: u32, + usage: GLUsagePattern, +) void; + +pub extern fn createShader(shader_type: GLShaderType) Shader; +pub extern fn shaderSource(shader: Shader, source_ptr: [*c]const u8, len: u32) void; +pub extern fn compileShader(shader: Shader) void; +pub extern fn getShaderParameter(shader: Shader, info: GLShaderInfo) u32; +pub extern fn deleteShader(shader: Shader) void; +pub extern fn getShaderInfoLog(shader: Shader, buf: [*c]u8, len: u32) u32; + +pub extern fn createProgram() Program; +pub extern fn deleteProgram(program: Program) void; +pub extern fn attachShader(program: Program, shader: Shader) void; +pub extern fn linkProgram(program: Program) void; +pub extern fn getProgramParameter(program: Program, info: GLProgramInfo) u32; +pub extern fn getProgramInfoLog(program: Program, buf: [*c]const u8, len: u32) u32; +pub extern fn useProgram(program: Program) void; + +pub extern fn getAttribLocation(program: Program, buf: [*c]const u8, len: u32) i32; +pub extern fn getUniformLocation(program: Program, buf: [*c]const u8, len: u32) i32; + +pub extern fn uniform1i(location: i32, v0: i32) void; +pub extern fn uniform2f(location: i32, v0: f32, v1: f32) void; +pub extern fn uniform4f(location: i32, v0: f32, v1: f32, v2: f32, v3: f32) void; +pub extern fn uniformMatrix3fv(location: i32, ptr: [*c]const @Vector(3, f32)) void; + +pub const VertexArrayObject = packed struct(u32) { handle: u32 }; +const GLType = enum(u32) { + i8 = 0x1400, + u8 = 0x1401, + i16 = 0x1402, + u16 = 0x1403, + i32 = 0x1404, + u32 = 0x1405, + f32 = 0x1406, +}; + +const GLBool = enum(i32) { + false = 0, + true = 1, +}; + +pub extern fn createVertexArray() VertexArrayObject; +pub extern fn bindVertexArray(vao: VertexArrayObject) void; +pub extern fn enableVertexAttribArray(attrib_location: i32) void; +pub extern fn vertexAttribPointer( + attrib_location: u32, + size: i32, + gl_type: GLType, + normalize: GLBool, + stride: i32, + offset: i32, +) void; + +pub extern fn viewport(x: i32, y: i32, width: i32, height: i32) void; + +const GLDrawMode = enum(u32) { + points = 0x0000, + lines = 0x0001, + line_loop = 0x0002, + line_strip = 0x0003, + triangles = 0x0004, + triangle_strip = 0x00005, + triangle_fan = 0x00006, +}; + +pub extern fn drawArrays(mode: GLDrawMode, first: i32, count: i32) void; + +pub extern fn createTexture() Texture; + +const TextureBindTarget = enum(u32) { + texture_2d = 0x0DE1, + texture_cube_map = 0x8514, + texture_3d = 0x806F, + texture_2d_array = 0x8C1A, +}; +pub extern fn bindTexture(target: TextureBindTarget, texture: Texture) void; + +pub const texture_0 = 0x84c0; +pub extern fn activeTexture(idx: u32) void; + +const TextureTarget = enum(u32) { + texture_2d = 0x0DE1, +}; +const TextureFormat = enum(u32) { + rgba = 0x1908, +}; +pub extern fn texImage2D( + target: TextureTarget, + level: i32, + internal_format: TextureFormat, + width: i32, + height: i32, + border: i32, + format: TextureFormat, + data_type: GLType, + ptr: *const anyopaque, + count: u32, + offset: u32, +) void; + +pub extern fn vertexAttribDivisor(loc: i32, divisor: i32) void; +pub extern fn drawArraysInstanced( + mode: GLDrawMode, + first: i32, + count: i32, + instace_count: i32, +) void; |