2
0
Эх сурвалжийг харах

Add vendor packages for the `js_wasm32` target

gingerBill 3 жил өмнө
parent
commit
80360f3f51

+ 59 - 0
vendor/wasm/README.md

@@ -0,0 +1,59 @@
+# WASM on the Web
+
+This directory is for use when targeting the `js_wasm32` target and the packages that rely on it.
+
+The `js_wasm32` target assumes that the WASM output will be ran within a web browser rather than a standalone VM. In the VM cases, either `wasi_wasm32` or `freestanding_wasm32` should be used accordingly.
+
+## Example
+
+```js
+import {WasmMemoryInterface, odinSetupDefaultImports} from "./js/runtime.js";
+import {WebGLInterface} from "./WebGL/runtime.js";
+
+const runWasm = async (wasm_path, webglCanvasElement, consoleElement) => {
+	let wasmMemoryInterface = new WasmMemoryInterface();
+
+	let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement);
+	
+	if (webglCanvasElement !== undefined) {
+		let gl_context = new WebGLInterface(
+			wasmMemoryInterface, 
+			webglCanvasElement, 
+			{antialias: false},
+		);
+		if (!gl_context.ctx) {
+			return "WebGL is not available.";
+		}	
+		imports["webgl"] = gl_context.getWebGL1Interface()
+		imports["webgl2"] = gl_context.getWebGL2Interface()
+	}
+		
+	const response = await fetch(wasm_path);
+	const file = await response.arrayBuffer();
+	const wasm = await WebAssembly.instantiate(file, imports);
+	const exports = wasm.instance.exports;
+	wasmMemoryInterface.setMemory(exports.memory);
+	
+	exports._start();
+	
+	if (exports.step) {
+		const odin_ctx = exports.default_context_ptr();
+		
+		let prevTimeStamp = undefined;
+		const step = (currTimeStamp) => {
+			if (prevTimeStamp == undefined) {
+				prevTimeStamp = currTimeStamp;
+			}
+
+			const dt = (currTimeStamp - prevTimeStamp)*0.001;
+			prevTimeStamp = currTimeStamp;
+			exports.step(dt, odin_ctx);
+			window.requestAnimationFrame(step);
+		};
+		
+		window.requestAnimationFrame(step);
+	}
+	
+	return;
+};
+```

+ 1034 - 0
vendor/wasm/WebGL/runtime.js

@@ -0,0 +1,1034 @@
+class WebGLInterface {
+	constructor(wasmMemoryInterface, canvasElement, contextSettings) {
+		this.wasmMemoryInterface = wasmMemoryInterface;
+		this.ctx                = null;
+		this.ctx_version        = 1;
+		this.counter            = 1;
+		this.lastError          = 0;
+		this.buffers            = [];
+		this.mappedBuffers      = {};
+		this.programs           = [];
+		this.framebuffers       = [];
+		this.renderbuffers      = [];
+		this.textures           = [];
+		this.uniforms           = [];
+		this.shaders            = [];
+		this.vaos               = [];
+		this.contexts           = [];
+		this.currentContext     = null;
+		this.offscreenCanvases  = {};
+		this.timerQueriesEXT    = [];
+		this.queries            = [];
+		this.samplers           = [];
+		this.transformFeedbacks = [];
+		this.syncs              = [];
+		this.programInfos       = {};
+		
+		if (contextSettings === undefined) {
+			contextSettings = {antialias: false};
+		}
+		
+		this.ctx = canvasElement.getContext("webgl2", contextSettings) || canvasElement.getContext("webgl", contextSettings);
+		if (!this.ctx) {
+			return;
+		}
+		if (this.ctx.getParameter(0x1F02).indexOf("WebGL 2.0") !== -1) {
+			this.ctx_version = 2.0;
+		} else {
+			this.ctx_version = 1.0;
+		}
+	}
+	
+	get mem() {
+		return this.wasmMemoryInterface
+	}
+	
+	assertWebGL2() {
+		if (this.ctx_version < 2) {
+			throw new Error("WebGL2 procedure called in a canvas without a WebGL2 context");
+		}
+	}
+	getNewId(table) {
+		for (var ret = this.counter++, i = table.length; i < ret; i++) {
+			table[i] = null;
+		}
+		return ret;
+	}
+	recordError(errorCode) {
+		this.lastError || (this.lastError = errorCode);
+	}
+	populateUniformTable(program) {
+		let p = this.programs[program];
+		this.programInfos[program] = {
+			uniforms: {},
+			maxUniformLength: 0,
+			maxAttributeLength: -1,
+			maxUniformBlockNameLength: -1,
+		};
+		for (let ptable = this.programInfos[program], utable = ptable.uniforms, numUniforms = this.ctx.getProgramParameter(p, this.ctx.ACTIVE_UNIFORMS), i = 0; i < numUniforms; ++i) {
+			let u = this.ctx.getActiveUniform(p, i);
+			let name = u.name;
+			if (ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length + 1), name.indexOf("]", name.length - 1) !== -1) {
+				name = name.slice(0, name.lastIndexOf("["));
+			}
+			let loc = this.ctx.getUniformLocation(p, name);
+			if (loc !== null) {
+				let id = this.getNewId(this.uniforms);
+				utable[name] = [u.size, id], this.uniforms[id] = loc;
+				for (let j = 1; j < u.size; ++j) {
+					let n = name + "[" + j + "]";
+					let loc = this.ctx.getUniformLocation(p, n);
+					let id = this.getNewId(this.uniforms);
+					this.uniforms[id] = loc;
+				}
+			}
+		}
+	}
+	getSource(shader, strings_ptr, strings_length) {
+		const STRING_SIZE = 2*4;
+		let source = "";
+		for (let i = 0; i < strings_length; i++) {
+			let ptr = this.mem.loadPtr(strings_ptr + i*STRING_SIZE);
+			let len = this.mem.loadPtr(strings_ptr + i*STRING_SIZE + 4);
+			let str = this.mem.loadString(ptr, len);
+			source += str;
+		}
+		return source;
+	}
+	
+	getWebGL1Interface() {
+		return {
+			DrawingBufferWidth:  () => this.ctx.drawingBufferWidth,
+			DrawingBufferHeight: () => this.ctx.drawingBufferHeight,
+			
+			IsExtensionSupported: (name_ptr, name_len) => {
+				let name = this.mem.loadString(name_ptr, name_len);
+				let extensions = this.ctx.getSupportedExtensions();
+				return extensions.indexOf(name) !== -1
+			},
+			
+			
+			GetError: () => {
+				let err = this.lastError;
+				this.recordError(0);
+				if (err) {
+					return err;
+				}
+				return this.ctx.getError();
+			},
+			
+			GetWebGLVersion: (major_ptr, minor_ptr) => {
+				let version = this.ctx.getParameter(0x1F02);
+				if (version.indexOf("WebGL 2.0") !== -1) {
+					this.mem.storeI32(major_ptr, 2);
+					this.mem.storeI32(minor_ptr, 0);
+					return;
+				}
+				
+				this.mem.storeI32(major_ptr, 1);
+				this.mem.storeI32(minor_ptr, 0);
+			},
+			GetESVersion: (major_ptr, minor_ptr) => {
+				let version = this.ctx.getParameter(0x1F02);
+				if (version.indexOf("OpenGL ES 3.0") !== -1) {
+					this.mem.storeI32(major_ptr, 3);
+					this.mem.storeI32(minor_ptr, 0);
+					return;
+				}
+				
+				this.mem.storeI32(major_ptr, 2);
+				this.mem.storeI32(minor_ptr, 0);
+			},
+			
+			
+			ActiveTexture: (x) => {
+				this.ctx.activeTexture(x);
+			},
+			AttachShader: (program, shader) => {
+				this.ctx.attachShader(this.programs[program], this.shaders[shader]);
+			},
+			BindAttribLocation: (program, index, name_ptr, name_len) => {
+				let name = this.mem.loadString(name_ptr, name_len);
+				this.ctx.bindAttribLocation(this.programs[program], index, name)
+			},
+			BindBuffer: (target, buffer) => {
+				let bufferObj = buffer ? this.buffers[buffer] : null;
+				if (target == 35051) {
+					this.ctx.currentPixelPackBufferBinding = buffer;
+				} else {
+					if (target == 35052) {
+						this.ctx.currentPixelUnpackBufferBinding = buffer;
+					}
+					this.ctx.bindBuffer(target, bufferObj)
+				}
+			},
+			BindFramebuffer: (target, buffer) => {
+				// TODO: BindFramebuffer
+			},
+			BindTexture: (target, texture) => {
+				this.ctx.bindTexture(target, texture ? this.textures[texture] : null)
+			},
+			BlendColor: (red, green, blue, alpha) => {
+				this.ctx.blendColor(red, green, blue, alpha);
+			},
+			BlendEquation: (mode) => {
+				this.ctx.blendEquation(mode);
+			},
+			BlendFunc: (sfactor, dfactor) => {
+				this.ctx.blendFunc(sfactor, dfactor);
+			},
+			BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => {
+				this.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+			},
+			
+			
+			BufferData: (target, size, data, usage) => {
+				if (data) {
+					this.ctx.bufferData(target, this.mem.loadBytes(data, size), usage);
+				} else {
+					this.ctx.bufferData(target, size, usage);
+				}
+			},
+			BufferSubData: (target, offset, size, data) => {
+				if (data) {
+					this.ctx.bufferSubData(target, offset, this.mem.loadBytes(data, size));
+				} else {
+					this.ctx.bufferSubData(target, offset, null);
+				}
+			},
+			
+			
+			Clear: (x) => {
+				this.ctx.clear(x);
+			},
+			ClearColor: (r, g, b, a) => {
+				this.ctx.clearColor(r, g, b, a);
+			},
+			ClearDepth: (x) => {
+				this.ctx.clearDepth(x);
+			},
+			ClearStencil: (x) => {
+				this.ctx.clearStencil(x);
+			},
+			ColorMask: (r, g, b, a) => {
+				this.ctx.colorMask(!!r, !!g, !!b, !!a);
+			},
+			CompileShader: (shader) => {
+				this.ctx.compileShader(this.shaders[shader]);
+			},
+			
+			
+			CompressedTexImage2D: (target, level, internalformat, width, height, border, imageSize, data) => {
+				if (data) {
+					this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, this.mem.loadBytes(data, imageSize));
+				} else {
+					this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, null);
+				}
+			},
+			CompressedTexSubImage2D: (target, level, xoffset, yoffset, width, height, format, imageSize, data) => {
+				if (data) {
+					this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, this.mem.loadBytes(data, imageSize));
+				} else {
+					this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, null);
+				}
+			},
+			
+			CopyTexImage2D: (target, level, internalformat, x, y, width, height, border) => {
+				this.ctx.copyTexImage2D(target, level, internalformat, x, y, width, height, border);
+			},
+			CopyTexSubImage2D: (target, level, xoffset, yoffset, x, y, width, height) => {
+				this.ctx.copyTexImage2D(target, level, xoffset, yoffset, x, y, width, height);
+			},
+			
+			
+			CreateBuffer: () => {
+				let buffer = this.ctx.createBuffer();
+				if (!buffer) {
+					this.recordError(1282);
+					return 0;
+				}
+				let id = this.getNewId(this.buffers);
+				buffer.name = id
+				this.buffers[id] = buffer;
+				return id;
+			},
+			CreateFramebuffer: () => {
+				let buffer = this.ctx.createFramebuffer();
+				let id = this.getNewId(this.framebuffers);
+				buffer.name = id
+				this.framebuffers[id] = buffer;
+				return id;
+			},
+			CreateProgram: () => {
+				let program = this.ctx.createProgram();
+				let id = this.getNewId(this.programs);
+				program.name = id;
+				this.programs[id] = program;
+				return id;
+			},
+			CreateRenderbuffer: () => {
+				let buffer = this.ctx.createRenderbuffer();
+				let id = this.getNewId(this.renderbuffers);
+				buffer.name = id;
+				this.renderbuffers[id] = buffer;
+				return id;
+			},
+			CreateShader: (shaderType) => {
+				let shader = this.ctx.createShader(shaderType);
+				let id = this.getNewId(this.shaders);
+				shader.name = id;
+				this.shaders[id] = shader;
+				return id;
+			},
+			CreateTexture: () => {
+				let texture = this.ctx.createTexture();
+				if (!texture) {
+					this.recordError(1282)
+					return 0;
+				}
+				let id = this.getNewId(this.textures);
+				texture.name = id;
+				this.textures[id] = texture;
+				return id;
+			},
+			
+			
+			CullFace: (mode) => {
+				this.ctx.cullFace(mode);
+			},
+			
+			
+			DeleteBuffer: (id) => {
+				let obj = this.buffers[id];
+				if (obj && id != 0) {
+					this.ctx.deleteBuffer(obj);
+					this.buffers[id] = null;
+				}
+			},
+			DeleteFramebuffer: (id) => {
+				let obj = this.framebuffers[id];
+				if (obj && id != 0) {
+					this.ctx.deleteFramebuffer(obj);
+					this.framebuffers[id] = null;
+				}
+			},
+			DeleteProgram: (id) => {
+				let obj = this.programs[id];
+				if (obj && id != 0) {
+					this.ctx.deleteProgram(obj);
+					this.programs[id] = null;
+				}
+			},
+			DeleteRenderbuffer: (id) => {
+				let obj = this.renderbuffers[id];
+				if (obj && id != 0) {
+					this.ctx.deleteRenderbuffer(obj);
+					this.renderbuffers[id] = null;
+				}
+			},
+			DeleteShader: (id) => {
+				let obj = this.shaders[id];
+				if (obj && id != 0) {
+					this.ctx.deleteShader(obj);
+					this.shaders[id] = null;
+				}
+			},
+			DeleteTexture: (id) => {
+				let obj = this.textures[id];
+				if (obj && id != 0) {
+					this.ctx.deleteTexture(obj);
+					this.textures[id] = null;
+				}
+			},
+
+
+			DepthFunc: (func) => {
+				this.ctx.depthFunc(func);
+			},
+			DepthMask: (flag) => {
+				this.ctx.depthMask(!!flag);
+			},
+			DepthRange: (zNear, zFar) => {
+				this.ctx.depthRange(zNear, zFar);
+			},
+			DetachShader: (program, shader) => {
+				this.ctx.detachShader(this.programs[program], this.shaders[shader]);
+			},
+			Disable: (cap) => {
+				this.ctx.disable(cap);
+			},
+			DisableVertexAttribArray: (index) => {
+				this.ctx.disableVertexAttribArray(index);
+			},
+			DrawArrays: (mode, first, count) => {
+				this.ctx.drawArrays(mode, first, count);
+			},
+			DrawElements: (mode, count, type, indices) => {
+				this.ctx.drawElements(mode, count, type, indices);
+			},
+			
+			
+			Enable: (cap) => {
+				this.ctx.enable(cap);
+			},
+			EnableVertexAttribArray: (index) => {
+				this.ctx.enableVertexAttribArray(index);
+			},
+			Finish: () => {
+				this.ctx.finish();
+			},
+			Flush: () => {
+				this.ctx.flush();
+			},
+			FramebufferRenderBuffer: (target, attachment, renderbuffertarget, renderbuffer) => {
+				this.ctx.framebufferRenderBuffer(target, attachment, renderbuffertarget, this.renderbuffers[renderbuffer]);
+			},
+			FramebufferTexture2D: (target, attachment, textarget, texture, level) => {
+				this.ctx.framebufferTexture2D(target, attachment, textarget, this.textures[texture], level);
+			},
+			FrontFace: (mode) => {
+				this.ctx.frontFace(mode);
+			},
+			
+				
+			GenerateMipmap: (target) => {
+				this.ctx.generateMipmap(target);
+			},
+			
+			
+			GetAttribLocation: (program, name_ptr, name_len) => {
+				let name = this.mem.loadString(name_ptr, name_len);
+				return this.ctx.getAttribLocation(this.programs[program], name);
+			},
+			
+			
+			
+			GetProgramParameter: (program, pname) => {
+				return this.ctx.getProgramParameter(this.programs[program], pname)
+			},
+			GetProgramInfoLog: (program, buf_ptr, buf_len, length_ptr) => {
+				let log = this.ctx.getProgramInfoLog(this.programs[program]);
+				if (log === null) {
+					log = "(unknown error)";
+				}
+				if (buf_len > 0 && buf_ptr) {
+					let n = Math.min(buf_len, log.length);
+					log = log.substring(0, n);
+					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
+					
+					storeInt(length_ptr, n);
+				}
+			},
+			GetShaderInfoLog: (shader, buf_ptr, buf_len, length_ptr) => {
+				let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
+				if (log === null) {
+					log = "(unknown error)";
+				}
+				if (buf_len > 0 && buf_ptr) {
+					let n = Math.min(buf_len, log.length);
+					log = log.substring(0, n);
+					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
+					
+					storeInt(length_ptr, n);
+				}
+			},
+			GetShaderiv: (shader, pname, p) => {
+				if (p) {
+					if (pname == 35716) {
+						let log = this.ctx.getShaderInfoLog(this.shaders[shader]);
+						if (log === null) {
+							log = "(unknown error)";
+						}
+						storeInt(p, log.length+1);
+					} else if (pname == 35720) {
+						let source = this.ctx.getShaderSource(this.shaders[shader]);
+						let sourceLength = (source === null || source.length == 0) ? 0 : source.length+1;
+						storeInt(p, sourceLength);
+					} else {
+						let param = this.ctx.getShaderParameter(this.shaders[shader], pname);
+						this.mem.storeI32(p, param);
+					}
+				} else {
+					this.recordError(1281);
+				}
+			},
+			
+			
+			GetUniformLocation: (program, name_ptr, name_len) => {
+				let name = this.mem.loadString(name_ptr, name_len);
+				let arrayOffset = 0;
+				if (name.indexOf("]", name.length - 1) !== -1) {
+					let ls = name.lastIndexOf("["),
+					arrayIndex = name.slice(ls + 1, -1);
+					if (arrayIndex.length > 0 && (arrayOffset = parseInt(arrayIndex)) < 0) {
+						return -1;
+					}
+					name = name.slice(0, ls)
+				}
+				var ptable = this.programInfos[program];
+				if (!ptable) {
+					return -1;
+				}
+				var uniformInfo = ptable.uniforms[name];
+				return (uniformInfo && arrayOffset < uniformInfo[0]) ? uniformInfo[1] + arrayOffset : -1
+			},
+			
+			
+			GetVertexAttribOffset: (index, pname) => {
+				return this.ctx.getVertexAttribOffset(index, pname);
+			},
+			
+			
+			Hint: (target, mode) => {
+				this.ctx.hint(target, mode);
+			},
+			
+			
+			IsBuffer:       (buffer)       => this.ctx.isBuffer(this.buffers[buffer]),
+			IsEnabled:      (enabled)      => this.ctx.isEnabled(this.enableds[enabled]),
+			IsFramebuffer:  (framebuffer)  => this.ctx.isFramebuffer(this.framebuffers[framebuffer]),
+			IsProgram:      (program)      => this.ctx.isProgram(this.programs[program]),
+			IsRenderbuffer: (renderbuffer) => this.ctx.isRenderbuffer(this.renderbuffers[renderbuffer]),
+			IsShader:       (shader)       => this.ctx.isShader(this.shaders[shader]),
+			IsTexture:      (texture)      => this.ctx.isTexture(this.textures[texture]),
+			
+			LineWidth: (width) => {
+				this.ctx.lineWidth(width);
+			},
+			LinkProgram: (program) => {
+				this.ctx.linkProgram(this.programs[program]);
+				this.programInfos[program] = null;
+				this.populateUniformTable(program);
+			},
+			PixelStorei: (pname, param) => {
+				this.ctx.pixelStorei(pname, param);
+			},
+			PolygonOffset: (factor, units) => {
+				this.ctx.polygonOffset(factor, units);
+			},
+			
+			
+			ReadnPixels: (x, y, width, height, format, type, bufSize, data) => {
+				this.ctx.readPixels(x, y, width, format, type, this.mem.loadBytes(data, bufSize));
+			},
+			RenderbufferStorage: (target, internalformat, width, height) => {
+				this.ctx.renderbufferStorage(target, internalformat, width, height);
+			},
+			SampleCoverage: (value, invert) => {
+				this.ctx.sampleCoverage(value, !!invert);
+			},
+			Scissor: (x, y, width, height) => {
+				this.ctx.scissor(x, y, width, height);
+			},
+			ShaderSource: (shader, strings_ptr, strings_length) => {
+				let source = this.getSource(shader, strings_ptr, strings_length);
+				this.ctx.shaderSource(this.shaders[shader], source);
+			},
+			
+			StencilFunc: (func, ref, mask) => {
+				this.ctx.stencilFunc(func, ref, mask);
+			},
+			StencilFuncSeparate: (face, func, ref, mask) => {
+				this.ctx.stencilFuncSeparate(face, func, ref, mask);
+			},
+			StencilMask: (mask) => {
+				this.ctx.stencilMask(mask);
+			},
+			StencilMaskSeparate: (face, mask) => {
+				this.ctx.stencilMaskSeparate(face, mask);
+			},
+			StencilOp: (fail, zfail, zpass) => {
+				this.ctx.stencilOp(fail, zfail, zpass);
+			},
+			StencilOpSeparate: (face, fail, zfail, zpass) => {
+				this.ctx.stencilOpSeparate(face, fail, zfail, zpass);
+			},
+			
+			
+			TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
+				if (data) {
+					this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size));
+				} else {
+					this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, null);
+				}
+			},
+			TexParameterf: (target, pname, param) => {
+				this.ctx.texParameterf(target, pname, param);
+			},
+			TexParameteri: (target, pname, param) => {
+				this.ctx.texParameteri(target, pname, param);
+			},
+			TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => {
+				this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, this.mem.loadBytes(data, size));
+			},
+			
+			
+			Uniform1f: (location, v0)             => { this.ctx.uniform1f(this.uniforms[location], v0);             },
+			Uniform2f: (location, v0, v1)         => { this.ctx.uniform2f(this.uniforms[location], v0, v1);         },
+			Uniform3f: (location, v0, v1, v2)     => { this.ctx.uniform3f(this.uniforms[location], v0, v1, v2);     },
+			Uniform4f: (location, v0, v1, v2, v3) => { this.ctx.uniform4f(this.uniforms[location], v0, v1, v2, v3); },
+			
+			Uniform1i: (location, v0)             => { this.ctx.uniform1i(this.uniforms[location], v0);             },
+			Uniform2i: (location, v0, v1)         => { this.ctx.uniform2i(this.uniforms[location], v0, v1);         },
+			Uniform3i: (location, v0, v1, v2)     => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2);     },
+			Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
+			
+			UniformMatrix2fv: (location, addr) => {
+				let array = this.mem.loadF32Array(addr, 2*2);
+				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix3fv: (location, addr) => {
+				let array = this.mem.loadF32Array(addr, 3*3);
+				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix4fv: (location, addr) => {
+				let array = this.mem.loadF32Array(addr, 4*4);
+				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
+			},
+			
+			UseProgram: (program) => {
+				this.ctx.useProgram(this.programs[program]);
+			},
+			ValidateProgram: (program) => {
+				this.ctx.validateProgram(this.programs[program]);
+			},
+			
+			
+			VertexAttrib1f: (index, x) => {
+				this.ctx.vertexAttrib1f(index, x);
+			},
+			VertexAttrib2f: (index, x, y) => {
+				this.ctx.vertexAttrib2f(index, x, y);
+			},
+			VertexAttrib3f: (index, x, y, z) => {
+				this.ctx.vertexAttrib3f(index, x, y, z);
+			},
+			VertexAttrib4f: (index, x, y, z, w) => {
+				this.ctx.vertexAttrib4f(index, x, y, z, w);
+			},
+			VertexAttribPointer: (index, size, type, normalized, stride, ptr) => {
+				this.ctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
+			},
+			
+			Viewport: (x, y, w, h) => {
+				this.ctx.viewport(x, y, w, h);
+			},
+		};
+	}
+	
+	getWebGL2Interface() {
+		return {
+			/* Buffer objects */
+			CopyBufferSubData: (readTarget, writeTarget, readOffset, writeOffset, size) => {
+				this.assertWebGL2();
+				this.ctx.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
+			},
+			GetBufferSubData: (target, srcByteOffset, dst_buffer_ptr, dst_buffer_len, dstOffset, length) => {
+				this.assertWebGL2();
+				this.ctx.getBufferSubData(target, srcByteOffset, this.mem.loadBytes(dst_buffer_ptr, dst_buffer_len), dstOffset, length);
+			},
+			
+			/* Framebuffer objects */
+			BlitFramebuffer: (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) => {
+				this.assertWebGL2();
+				this.ctx.glitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+			},
+			FramebufferTextureLayer: (target, attachment, texture, level, layer) => {
+				this.assertWebGL2();
+				this.ctx.framebufferTextureLayer(target, attachment, this.textures[texture], level, layer);
+			},
+			InvalidateFramebuffer: (target, attachments_ptr, attachments_len) => {
+				this.assertWebGL2();
+				let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
+				this.ctx.invalidateFramebuffer(target, attachments);
+			},
+			InvalidateSubFramebuffer: (target, attachments_ptr, attachments_len, x, y, width, height) => {	
+				this.assertWebGL2();
+				let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
+				this.ctx.invalidateSubFramebuffer(target, attachments, x, y, width, height);
+			},
+			ReadBuffer: (src) => {
+				this.assertWebGL2();
+				this.ctx.readBuffer(src);
+			},
+			
+			/* Renderbuffer objects */
+			RenderbufferStorageMultisample: (target, samples, internalformat, width, height) => {
+				this.assertWebGL2();
+				this.ctx.renderbufferStorageMultisample(target, samples, internalformat, width, height);
+			},
+			
+			/* Texture objects */
+			
+			TexStorage3D: (target, levels, internalformat, width, height, depth) => {
+				this.assertWebGL2();
+				this.ctx.texStorage3D(target, level, internalformat, width, heigh, depth);
+			},
+			TexImage3D: (target, level, internalformat, width, height, depth, border, format, type, size, data) => {
+				this.assertWebGL2();
+				if (data) {
+					this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, this.mem.loadBytes(data, size));
+				} else {
+					this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null);
+				}
+			},
+			TexSubImage3D: (target, level, xoffset, yoffset, width, height, depth, format, type, size, data) => {
+				this.assertWebGL2();
+				this.ctx.texSubImage3D(target, level, xoffset, yoffset, width, height, depth, format, type, this.mem.loadBytes(data, size));
+			},
+			CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => {
+				this.assertWebGL2();
+				if (data) {
+					this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, this.mem.loadBytes(data, imageSize));
+				} else {
+					this.ctx.compressedTexImage3D(target, level, internalformat, width, height, depth, border, null);
+				}
+			},
+			CompressedTexSubImage3D: (target, level, xoffset, yoffset, width, height, depth, format, imageSize, data) => {
+				this.assertWebGL2();
+				if (data) {
+					this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, width, height, depth, format, this.mem.loadBytes(data, imageSize));
+				} else {
+					this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, width, height, depth, format, null);
+				}
+			},
+			
+			CopyTexSubImage3D: (target, level, xoffset, yoffset, zoffset, x, y, width, height) => {
+				this.assertWebGL2();
+				this.ctx.copyTexImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
+			},
+			
+			/* Programs and shaders */
+			GetFragDataLocation: (program, name_ptr, name_len) => {
+				this.assertWebGL2();
+				return this.ctx.getFragDataLocation(this.programs[program], this.mem.loadString(name_ptr, name_len));
+			},
+			
+			/* Uniforms */
+			Uniform1ui: (location, v0) => {
+				this.assertWebGL2();
+				this.ctx.uniform1ui(this.uniforms[location], v0);
+			},
+			Uniform2ui: (location, v0, v1) => {
+				this.assertWebGL2();
+				this.ctx.uniform2ui(this.uniforms[location], v0, v1);
+			},
+			Uniform3ui: (location, v0, v1, v2) => {
+				this.assertWebGL2();
+				this.ctx.uniform3ui(this.uniforms[location], v0, v1, v2);
+			},
+			Uniform4ui: (location, v0, v1, v2, v3) => {
+				this.assertWebGL2();
+				this.ctx.uniform4ui(this.uniforms[location], v0, v1, v2, v3);
+			},
+			
+			UniformMatrix3x2fv: (location, addr) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(addr, 3*2);
+				this.ctx.uniformMatrix3x2fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix4x2fv: (location, addr) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(addr, 4*2);
+				this.ctx.uniformMatrix4x2fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix2x3fv: (location, addr) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(addr, 2*3);
+				this.ctx.uniformMatrix2x3fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix4x3fv: (location, addr) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(addr, 4*3);
+				this.ctx.uniformMatrix4x3fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix2x4fv: (location, addr) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(addr, 2*4);
+				this.ctx.uniformMatrix2x4fv(this.uniforms[location], false, array);
+			},
+			UniformMatrix3x4fv: (location, addr) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(addr, 3*4);
+				this.ctx.uniformMatrix3x4fv(this.uniforms[location], false, array);
+			},
+			
+			/* Vertex attribs */
+			VertexAttribI4i: (index, x, y, z, w) => {
+				this.assertWebGL2();
+				this.ctx.vertexAttribI4i(index, x, y, z, w);
+			}, 
+			VertexAttribI4ui: (index, x, y, z, w) => {
+				this.assertWebGL2();
+				this.ctx.vertexAttribI4ui(index, x, y, z, w);
+			}, 
+			VertexAttribIPointer: (index, size, type, stride, offset) => {
+				this.assertWebGL2();
+				this.ctx.vertexAttribIPointer(index, size, type, stride, offset);
+			}, 
+			
+			/* Writing to the drawing buffer */
+			VertexAttribDivisor: (index, divisor) => {
+				this.assertWebGL2();
+				this.ctx.vertexAttribDivisor(index, divisor);
+			},
+			DrawArraysInstanced: (mode, first, count, instanceCount) => {
+				this.assertWebGL2();
+				this.ctx.drawArraysInstanced(mode, first, count, instanceCount);
+			},
+			DrawElementsInstanced: (mode, count, type, offset, instanceCount) => {
+				this.assertWebGL2();
+				this.ctx.drawElementsInstanced(mode, count, type, offset, instanceCount);
+			},
+			DrawRangeElements: (mode, start, end, count, type, offset) => {
+				this.assertWebGL2();
+				this.ctx.drawRangeElements(mode, start, end, count, type, offset);
+			},
+
+			/* Multiple Render Targets */
+			DrawBuffers: (buffers_ptr, buffers_len) => {
+				this.assertWebGL2();
+				let array = this.mem.loadU32Array(buffers_ptr, buffers_len);
+				this.ctx.drawBuffers(array);
+			},
+			ClearBufferfv: (buffer, drawbuffer, values_ptr, values_len) => {
+				this.assertWebGL2();
+				let array = this.mem.loadF32Array(values_ptr, values_len);
+				this.ctx.clearBufferfv(buffer, drawbuffer, array);
+			},
+			ClearBufferiv: (buffer, drawbuffer, values_ptr, values_len) => {
+				this.assertWebGL2();
+				let array = this.mem.loadI32Array(values_ptr, values_len);
+				this.ctx.clearBufferiv(buffer, drawbuffer, array);
+			},
+			ClearBufferuiv: (buffer, drawbuffer, values_ptr, values_len) => {
+				this.assertWebGL2();
+				let array = this.mem.loadU32Array(values_ptr, values_len);
+				this.ctx.clearBufferuiv(buffer, drawbuffer, array);
+			},
+			ClearBufferfi: (buffer, drawbuffer, depth, stencil) => {
+				this.assertWebGL2();
+				this.ctx.clearBufferfi(buffer, drawbuffer, depth, stencil);
+			},
+
+			/* Query Objects */
+			CreateQuery: () => {
+				this.assertWebGL2();
+				let query = this.ctx.createQuery();
+				let id = this.getNewId(this.queries);
+				query.name = id;
+				this.queries[id] = query;
+				return id;	
+			},
+			DeleteQuery: (id) => {
+				this.assertWebGL2();
+				let obj = this.querys[id];
+				if (obj && id != 0) {
+					this.ctx.deleteQuery(obj);
+					this.querys[id] = null;
+				}
+			},
+			IsQuery: (query) => {
+				this.assertWebGL2();	
+				return this.ctx.isQuery(this.queries[query]);
+			},
+			BeginQuery: (target, query) => {
+				this.assertWebGL2();
+				this.ctx.beginQuery(target, this.queries[query])
+			},
+			EndQuery: (target) => {
+				this.assertWebGL2();
+				this.ctx.endQuery(target);
+			},
+			GetQuery: (target, pname) => {
+				this.assertWebGL2();
+				let query = this.ctx.getQuery(target, pname);
+				if (!query) {
+					return 0;
+				}
+				if (this.queries.indexOf(query) !== -1) {
+					return query.name;
+				}
+				let id = this.getNewId(this.queries);
+				query.name = id;
+				this.queries[id] = query;
+				return id;	
+			},
+			
+			/* Sampler Objects */
+			CreateSampler: () => {
+				this.assertWebGL2();
+				let sampler = this.ctx.createSampler();
+				let id = this.getNewId(this.samplers);
+				sampler.name = id;
+				this.samplers[id] = sampler;
+				return id;	
+			},
+			DeleteSampler: (id) => {
+				this.assertWebGL2();
+				let obj = this.samplers[id];
+				if (obj && id != 0) {
+					this.ctx.deleteSampler(obj);
+					this.samplers[id] = null;
+				}
+			},
+			IsSampler: (sampler) => {
+				this.assertWebGL2();	
+				return this.ctx.isSampler(this.samplers[sampler]);
+			},
+			BindSampler: (unit, sampler) => {
+				this.assertWebGL2();	
+				this.ctx.bindSampler(unit, this.samplers[Sampler]);
+			},
+			SamplerParameteri: (sampler, pname, param) => {
+				this.assertWebGL2();
+				this.ctx.samplerParameteri(this.samplers[sampler], pname, param);
+			},
+			SamplerParameterf: (sampler, pname, param) => {
+				this.assertWebGL2();
+				this.ctx.samplerParameterf(this.samplers[sampler], pname, param);
+			},
+			
+			/* Sync objects */
+			FenceSync: (condition, flags) => {
+				this.assertWebGL2();
+				let sync = this.ctx.fenceSync(condition, flags);
+				let id = this.getNewId(this.syncs);
+				sync.name = id;
+				this.syncs[id] = sync;
+				return id;	
+			},
+			IsSync: (sync) => {
+				this.assertWebGL2();	
+				return this.ctx.isSync(this.syncs[sync]);
+			},
+			DeleteSync: (id) => {
+				this.assertWebGL2();
+				let obj = this.syncs[id];
+				if (obj && id != 0) {
+					this.ctx.deleteSampler(obj);
+					this.syncs[id] = null;
+				}	
+			},
+			ClientWaitSync: (sync, flags, timeout) => {
+				this.assertWebGL2();
+				return this.ctx.clientWaitSync(this.syncs[sync], flags, timeout);
+			},
+			WaitSync: (sync, flags, timeout) => {
+				this.assertWebGL2();
+				this.ctx.waitSync(this.syncs[sync], flags, timeout)	;
+			},
+			
+			
+			/* Transform Feedback */
+			CreateTransformFeedback: () => {
+				this.assertWebGL2();
+				let transformFeedback = this.ctx.createtransformFeedback();
+				let id = this.getNewId(this.transformFeedbacks);
+				transformFeedback.name = id;
+				this.transformFeedbacks[id] = transformFeedback;
+				return id;	
+			},
+			DeleteTransformFeedback: (id)  => {
+				this.assertWebGL2();
+				let obj = this.transformFeedbacks[id];
+				if (obj && id != 0) {
+					this.ctx.deleteTransformFeedback(obj);
+					this.transformFeedbacks[id] = null;
+				}	
+			},
+			IsTransformFeedback: (tf) => {
+				this.assertWebGL2();
+				return this.ctx.isTransformFeedback(this.transformFeedbacks[tf]);
+			},
+			BindTransformFeedback: (target, tf) => {
+				this.assertWebGL2();
+				this.ctx.bindTransformFeedback(target, this.transformFeedbacks[tf]);
+			},
+			BeginTransformFeedback: (primitiveMode) => {
+				this.assertWebGL2();
+				this.ctx.beginTransformFeedback(primitiveMode);
+			},
+			EndTransformFeedback: () => {
+				this.assertWebGL2();
+				this.ctx.endTransformFeedback();
+			},
+			TransformFeedbackVaryings: (program, varyings_ptr, varyings_len, bufferMode) => {
+				this.assertWebGL2();
+				let varyings = [];
+				for (let i = 0; i < varyings_len; i++) {
+					let ptr = this.mem.loadPtr(varyings_ptr + i*STRING_SIZE + 0*4);
+					let len = this.mem.loadPtr(varyings_ptr + i*STRING_SIZE + 1*4);
+					varyings.push(this.mem.loadString(ptr, len));
+				}
+				this.ctx.transformFeedbackVaryings(this.programs[program], varyings, bufferMode);
+			},
+			PauseTransformFeedback: () => {
+				this.assertWebGL2();
+				this.ctx.pauseTransformFeedback();
+			},
+			ResumeTransformFeedback: () => {
+				this.assertWebGL2();
+				this.ctx.resumeTransformFeedback();
+			},
+			
+			
+			/* Uniform Buffer Objects and Transform Feedback Buffers */
+			BindBufferBase: (target, index, buffer) => {
+				this.assertWebGL2();
+				this.ctx.bindBufferBase(target, index, this.buffers[buffer]);
+			},
+			BindBufferRange: (target, index, buffer, offset, size) => {
+				this.assertWebGL2();
+				this.ctx.bindBufferRange(target, index, this.buffers[buffer], offset, size);
+			},
+			GetUniformBlockIndex: (program, uniformBlockName_ptr, uniformBlockName_len) => {
+				this.assertWebGL2();
+				return this.ctx.getUniformBlockIndex(this.programs[program], this.mem.loadString(uniformBlockName_ptr, uniformBlockName_len));
+			},
+			// any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname);
+			GetActiveUniformBlockName: (program, uniformBlockIndex, buf_ptr, buf_len, length_ptr) => {
+				this.assertWebGL2();
+				let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex);
+				
+				let n = Math.min(buf_len, name.length);
+				name = name.substring(0, n);
+				this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(name))
+				storeInt(length_ptr, n);
+			},
+			UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => {
+				this.assertWebGL2();
+				this.ctx.uniformBlockBinding(this.programs[program], uniformBlockIndex, uniformBlockBinding);
+			},
+			
+			/* Vertex Array Objects */
+			CreateVertexArray: () => {
+				this.assertWebGL2();
+				let vao = this.ctx.createVertexArray();
+				let id = this.getNewId(this.vaos);
+				vao.name = id;
+				this.vaos[id] = vao;
+				return id;	
+			},
+			DeleteVertexArray: (id) => {
+				this.assertWebGL2();
+				let obj = this.vaos[id];
+				if (obj && id != 0) {
+					this.ctx.deleteVertexArray(obj);
+					this.vaos[id] = null;
+				}
+			},
+			IsVertexArray: (vertexArray) => {
+				this.assertWebGL2();	
+				return this.ctx.isVertexArray(this.vaos[vertexArray]);
+			},
+			BindVertexArray: (vertexArray) => {
+				this.assertWebGL2();	
+				this.ctx.bindVertexArray(this.vaos[vertexArray]);
+			},
+		};
+	}
+};
+
+
+export {WebGLInterface};

+ 249 - 0
vendor/wasm/WebGL/webgl.odin

@@ -0,0 +1,249 @@
+package webgl
+
+foreign import "webgl"
+
+import glm "core:math/linalg/glsl"
+
+Enum :: distinct u32
+
+Buffer       :: distinct u32
+Framebuffer  :: distinct u32
+Program      :: distinct u32
+Renderbuffer :: distinct u32
+Shader       :: distinct u32
+Texture      :: distinct u32
+
+@(default_calling_convention="c")
+foreign webgl {
+	DrawingBufferWidth  :: proc() -> i32 ---
+	DrawingBufferHeight :: proc() -> i32 ---
+	
+	GetWebGLVersion :: proc(major, minor: ^i32) ---
+	GetESVersion :: proc(major, minor: ^i32) ---
+	
+	GetError :: proc() -> Enum ---
+	
+	IsExtensionSupported :: proc(name: string) -> bool ---
+
+	ActiveTexture      :: proc(x: Enum) ---
+	AttachShader       :: proc(program: Program, shader: Shader) ---
+	BindAttribLocation :: proc(program: Program, index: i32, name: string) ---
+	BindBuffer         :: proc(target: Enum, buffer: Buffer) ---
+	BindFramebuffer    :: proc(target: Enum, buffer: Buffer) ---
+	BindTexture        :: proc(target: Enum, texture: Texture) ---
+	BlendColor         :: proc(red, green, blue, alpha: f32) ---
+	BlendEquation      :: proc(mode: Enum) ---
+	BlendFunc          :: proc(sfactor, dfactor: Enum) ---
+	BlendFuncSeparate  :: proc(srcRGB, dstRGB, srcAlpha, dstAlpha: Enum) ---
+	
+	BufferData    :: proc(target: Enum, size: int, data: rawptr, usage: Enum) ---
+	BufferSubData :: proc(target: Enum, offset: uintptr, size: int, data: rawptr) ---
+
+	Clear         :: proc(bits: Enum) ---
+	ClearColor    :: proc(r, g, b, a: f32) ---
+	ClearDepth    :: proc(x: Enum) ---
+	ClearStencil  :: proc(x: Enum) ---
+	ClearMask     :: proc(r, g, b, a: bool) ---
+	CompileShader :: proc(shader: Shader) ---
+	
+	CompressedTexImage2D    :: proc(target: Enum, level: i32, internalformat: Enum, width, height: i32, border: i32, imageSize: int, data: rawptr) ---
+	CompressedTexSubImage2D :: proc(target: Enum, level: i32, xoffset, yoffset, width, height: i32, format: Enum, imageSize: int, data: rawptr) ---
+	CopyTexImage2D          :: proc(target: Enum, level: i32, internalformat: Enum, x, y, width, height: i32, border: i32) ---
+	CopyTexSubImage2D       :: proc(target: Enum, level: i32, xoffset, yoffset, x, y: i32, width, height: i32) ---
+	
+
+	CreateBuffer       :: proc() -> Buffer ---
+	CreateFramebuffer  :: proc() -> Framebuffer ---
+	CreateProgram      :: proc() -> Program ---
+	CreateRenderbuffer :: proc() -> Renderbuffer ---
+	CreateShader       :: proc(shaderType: Enum) -> Shader ---
+	CreateTexture      :: proc() -> Texture ---
+	
+	CullFace :: proc(mode: Enum) ---
+	
+	DeleteBuffer       :: proc(buffer: Buffer) ---
+	DeleteFramebuffer  :: proc(framebuffer: Framebuffer) ---
+	DeleteProgram      :: proc(program: Program) ---
+	DeleteRenderbuffer :: proc(renderbuffer: Renderbuffer) ---
+	DeleteShader       :: proc(shader: Shader) ---
+	DeleteTexture      :: proc(texture: Texture) ---
+	
+	DepthFunc                :: proc(func: Enum) ---
+	DepthMask                :: proc(flag: bool) ---
+	DepthRange               :: proc(zNear, zFar: f32) ---
+	DetachShader             :: proc(program: Program, shader: Shader) ---
+	Disable                  :: proc(cap: Enum) ---
+	DisableVertexAttribArray :: proc(index: i32) ---
+	DrawArrays               :: proc(mode: Enum, first, count: int) ---
+	DrawElements             :: proc(mode: Enum, count: int, type: Enum, indices: rawptr) ---
+	
+	Enable                  :: proc(cap: Enum) ---
+	EnableVertexAttribArray :: proc(index: i32) ---
+	Finish                  :: proc() ---
+	Flush                   :: proc() ---
+	FramebufferRenderbuffer :: proc(target, attachment, renderbufertarget: Enum, renderbuffer: Renderbuffer) ---
+	FramebufferTexture2D    :: proc(target, attachment, textarget: Enum, texture: Texture, level: i32) ---
+	FrontFace               :: proc(mode: Enum) ---
+	
+	GenerateMipmap :: proc(target: Enum) ---
+	
+	GetAttribLocation     :: proc(program: Program, name: string) -> i32 ---
+	GetUniformLocation    :: proc(program: Program, name: string) -> i32 ---
+	GetVertexAttribOffset :: proc(index: i32, pname: Enum) -> uintptr ---
+	GetProgramParameter   :: proc(program: Program, pname: Enum) -> i32 ---
+
+	Hint :: proc(target: Enum, mode: Enum) ---
+	
+	IsBuffer       :: proc(buffer: Buffer) -> bool ---
+	IsFramebuffer  :: proc(framebuffer: Framebuffer) -> bool ---
+	IsProgram      :: proc(program: Program) -> bool ---
+	IsRenderbuffer :: proc(renderbuffer: Renderbuffer) -> bool ---
+	IsShader       :: proc(shader: Shader) -> bool ---
+	IsTexture      :: proc(texture: Texture) -> bool ---
+	
+	LineWidth     :: proc(width: f32) ---
+	LinkProgram   :: proc(program: Program) ---
+	PixelStorei   :: proc(pname: Enum, param: i32) ---
+	PolygonOffset :: proc(factor: f32, units: f32) ---
+	
+	ReadnPixels         :: proc(x, y, width, height: i32, format: Enum, type: Enum, bufSize: int, data: rawptr) ---
+	RenderbufferStorage :: proc(target: Enum, internalformat: Enum, width, height: i32) ---
+	SampleCoverage      :: proc(value: f32, invert: bool) ---
+	Scissor             :: proc(x, y, width, height: i32) ---
+	ShaderSource        :: proc(shader: Shader, strings: []string) ---
+	
+	StencilFunc         :: proc(func: Enum, ref: i32, mask: u32) ---
+	StencilFuncSeparate :: proc(face, func: Enum, ref: i32, mask: u32) ---
+	StencilMask         :: proc(mask: u32) ---
+	StencilMaskSeparate :: proc(face: Enum, mask: u32) ---
+	StencilOp           :: proc(fail, zfail, zpass: Enum) ---
+	StencilOpSeparate   :: proc(face, fail, zfail, zpass: Enum)	 ---
+	
+	TexImage2D    :: proc(target: Enum, level: i32, internalformat: Enum, width, height: i32, border: i32, format, type: Enum, size: int, data: rawptr) ---
+	TexSubImage2D :: proc(target: Enum, level: i32, xoffset, yoffset, width, height: i32, format, type: Enum, size: int, data: rawptr) ---
+	
+	TexParameterf :: proc(target, pname: Enum, param: f32) ---
+	TexParameteri :: proc(target, pname: Enum, param: i32) ---
+	
+	Uniform1f :: proc(location: i32, v0: f32) ---
+	Uniform2f :: proc(location: i32, v0, v1: f32) ---
+	Uniform3f :: proc(location: i32, v0, v1, v2: f32) ---
+	Uniform4f :: proc(location: i32, v0, v1, v2, v3: f32) ---
+	
+	Uniform1i :: proc(location: i32, v0: i32) ---
+	Uniform2i :: proc(location: i32, v0, v1: i32) ---
+	Uniform3i :: proc(location: i32, v0, v1, v2: i32) ---
+	Uniform4i :: proc(location: i32, v0, v1, v2, v3: i32) ---
+	
+	UseProgram      :: proc(program: Program) ---
+	ValidateProgram :: proc(program: Program) ---
+		
+	VertexAttrib1f      :: proc(index: i32, x: f32) ---
+	VertexAttrib2f      :: proc(index: i32, x, y: f32) ---
+	VertexAttrib3f      :: proc(index: i32, x, y, z: f32) ---
+	VertexAttrib4f      :: proc(index: i32, x, y, z, w: f32) ---
+	VertexAttribPointer :: proc(index: i32, size: int, type: Enum, normalized: bool, stride: int, ptr: uintptr) ---
+	
+	Viewport :: proc(x, y, w, h: i32) ---
+}
+
+Uniform1fv :: proc "c" (location: i32, v: f32)       { Uniform1f(location, v) }
+Uniform2fv :: proc "c" (location: i32, v: glm.vec2)  { Uniform2f(location, v.x, v.y) }
+Uniform3fv :: proc "c" (location: i32, v: glm.vec3)  { Uniform3f(location, v.x, v.y, v.z) }
+Uniform4fv :: proc "c" (location: i32, v: glm.vec4)  { Uniform4f(location, v.x, v.y, v.z, v.w) }
+Uniform1iv :: proc "c" (location: i32, v: i32)       { Uniform1i(location, v) }
+Uniform2iv :: proc "c" (location: i32, v: glm.ivec2) { Uniform2i(location, v.x, v.y) }
+Uniform3iv :: proc "c" (location: i32, v: glm.ivec3) { Uniform3i(location, v.x, v.y, v.z) }
+Uniform4iv :: proc "c" (location: i32, v: glm.ivec4) { Uniform4i(location, v.x, v.y, v.z, v.w) }
+
+VertexAttrib1fv :: proc "c" (index: i32, v: f32)     { VertexAttrib1f(index, v) }
+VertexAttrib2fv :: proc "c" (index: i32, v: glm.vec2){ VertexAttrib2f(index, v.x, v.y) }
+VertexAttrib3fv :: proc "c" (index: i32, v: glm.vec3){ VertexAttrib3f(index, v.x, v.y, v.z) }
+VertexAttrib4fv :: proc "c" (index: i32, v: glm.vec4){ VertexAttrib4f(index, v.x, v.y, v.z, v.w) }
+
+UniformMatrix2fv :: proc "c" (location: i32, m: glm.mat2) {
+	foreign webgl {
+		@(link_name="UniformMatrix2fv")
+		_UniformMatrix2fv :: proc "c" (location: i32, value: [^]f32) ---
+	}
+	value := transmute([2*2]f32)m
+	_UniformMatrix2fv(location, &value[0])
+}
+UniformMatrix3fv :: proc "c" (location: i32, m: glm.mat3) {
+	foreign webgl {
+		@(link_name="UniformMatrix3fv")
+		_UniformMatrix3fv :: proc "c" (location: i32, value: [^]f32) ---
+	}
+	value := transmute([3*3]f32)m
+	_UniformMatrix3fv(location, &value[0])
+}
+UniformMatrix4fv :: proc "c" (location: i32, m: glm.mat4) {
+	foreign webgl {
+		@(link_name="UniformMatrix4fv")
+		_UniformMatrix4fv :: proc "c" (location: i32, value: [^]f32) ---
+	}
+	value := transmute([4*4]f32)m
+	_UniformMatrix4fv(location, &value[0])
+}
+
+GetShaderiv :: proc "c" (shader: Shader, pname: Enum) -> (p: i32) {
+	@(default_calling_convention="c")
+	foreign webgl {
+		@(link_name="GetShaderiv")
+		_GetShaderiv :: proc "c" (shader: Shader, pname: Enum, p: ^i32) ---
+	}
+	_GetShaderiv(shader, pname, &p)
+	return
+}
+
+
+GetProgramInfoLog :: proc "c" (program: Program, buf: []byte) -> string {
+	@(default_calling_convention="c")
+	foreign webgl {
+		@(link_name="GetProgramInfoLog")
+		_GetProgramInfoLog :: proc "c" (program: Program, buf: []byte, length: ^int) ---
+	}
+	
+	length: int
+	_GetProgramInfoLog(program, buf, &length)
+	return string(buf[:length])
+}
+
+GetShaderInfoLog :: proc "c" (shader: Shader, buf: []byte) -> string {
+	@(default_calling_convention="c")
+	foreign webgl {
+		@(link_name="GetShaderInfoLog")
+		_GetShaderInfoLog :: proc "c" (shader: Shader, buf: []byte, length: ^int) ---
+	}
+	
+	length: int
+	_GetShaderInfoLog(shader, buf, &length)
+	return string(buf[:length])
+}
+
+
+
+BufferDataSlice :: proc "c" (target: Enum, slice: $S/[]$E, usage: Enum) {
+	BufferData(target, len(slice)*size_of(E), raw_data(slice), usage)
+}
+BufferSubDataSlice :: proc "c" (target: Enum, offset: uintptr, slice: $S/[]$E) {
+	BufferSubData(target, offset, len(slice)*size_of(E), raw_data(slice), usage)
+}
+
+CompressedTexImage2DSlice :: proc "c" (target: Enum, level: i32, internalformat: Enum, width, height: i32, border: i32, slice: $S/[]$E) {
+	CompressedTexImage2DSlice(target, level, internalformat, width, height, border, len(slice)*size_of(E), raw_data(slice))
+}
+CompressedTexSubImage2DSlice :: proc "c" (target: Enum, level: i32, xoffset, yoffset, width, height: i32, format: Enum, slice: $S/[]$E) {
+	CompressedTexSubImage2DSlice(target, level, level, xoffset, yoffset, width, height, format, len(slice)*size_of(E), raw_data(slice))
+}
+
+ReadPixelsSlice :: proc "c" (x, y, width, height: i32, format: Enum, type: Enum, slice: $S/[]$E) {
+	ReadnPixels(x, y, width, height, format, type, len(slice)*size_of(E), raw_data(slice))
+}
+
+TexImage2DSlice :: proc "c" (target: Enum, level: i32, internalformat: Enum, width, height: i32, border: i32, format, type: Enum, slice: $S/[]$E) {
+	TexImage2D(target, level, internalformat, width, height, border, format, type, len(slice)*size_of(E), raw_data(slice))
+}
+TexSubImage2DSlice :: proc "c" (target: Enum, level: i32, xoffset, yoffset, width, height: i32, format, type: Enum, slice: $S/[]$E) {
+	TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, len(slice)*size_of(E), raw_data(slice))
+}

+ 182 - 0
vendor/wasm/WebGL/webgl2.odin

@@ -0,0 +1,182 @@
+package webgl
+
+foreign import "webgl2"
+
+import glm "core:math/linalg/glsl"
+
+Query             :: distinct u32
+Sampler           :: distinct u32
+Sync              :: distinct u32
+TransformFeedback :: distinct u32
+VertexArrayObject :: distinct u32
+
+IsWebGL2Supported :: proc "c" () -> bool {
+	major, minor: i32
+	GetWebGLVersion(&major, &minor)
+	return major >= 2
+}
+
+@(default_calling_convention="c")
+foreign webgl2 {
+	/* Buffer objects */
+	CopyBufferSubData :: proc(readTarget, writeTarget: Enum, readOffset, writeOffset: int, size: int) ---	
+	GetBufferSubData  :: proc(target: Enum, srcByteOffset: int, dst_buffer: []byte, dstOffset: int = 0, length: int = 0) ---
+	
+	/* Framebuffer objects */
+	BlitFramebuffer          :: proc(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1: i32, mask: u32, filter: Enum) ---
+	FramebufferTextureLayer  :: proc(target: Enum, attachment: Enum, texture: Texture, level: i32, layer: i32) ---
+	InvalidateFramebuffer    :: proc(target: Enum, attachments: []Enum) ---
+	InvalidateSubFramebuffer :: proc(target: Enum, attachments: []Enum, x, y, width, height: i32) ---
+	ReadBuffer               :: proc(src: Enum) ---
+	
+	/* Renderbuffer objects */
+	RenderbufferStorageMultisample :: proc(target: Enum, samples: i32, internalformat: Enum, width, height: i32) ---
+	
+	/* Texture objects */
+	TexStorage3D            :: proc(target: Enum, levels: i32, internalformat: Enum, width, height, depth: i32) ---
+	TexImage3D              :: proc(target: Enum, level: i32, internalformat: Enum, width, height, depth: i32, border: i32, format, type: Enum, size: int, data: rawptr) ---
+	TexSubImage3D           :: proc(target: Enum, level: i32, xoffset, yoffset, width, height, depth: i32, format, type: Enum, size: int, data: rawptr) ---
+	CompressedTexImage3D    :: proc(target: Enum, level: i32, internalformat: Enum, width, height, depth: i32, border: i32, imageSize: int, data: rawptr) ---
+	CompressedTexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset: i32, width, height, depth: i32, format: Enum, imageSize: int, data: rawptr) ---
+	CopyTexSubImage3D       :: proc(target: Enum, level: i32, xoffset, yoffset, zoffset: i32, x, y, width, height: i32) ---
+	
+	/* Programs and shaders */
+	GetFragDataLocation :: proc(program: Program, name: string) -> i32 ---
+	
+	/* Uniforms */
+	Uniform1ui :: proc(location: i32, v0: u32) ---
+	Uniform2ui :: proc(location: i32, v0: u32, v1: u32) ---
+	Uniform3ui :: proc(location: i32, v0: u32, v1: u32, v2: u32) ---
+	Uniform4ui :: proc(location: i32, v0: u32, v1: u32, v2: u32, v3: u32) ---
+
+	/* Vertex attribs */
+	VertexAttribI4i      :: proc(index: i32, x, y, z, w: i32) ---
+	VertexAttribI4ui     :: proc(index: i32, x, y, z, w: u32) ---
+	VertexAttribIPointer :: proc(index: i32, size: int, type: Enum, stride: int, offset: uintptr) ---
+	
+	/* Writing to the drawing buffer */
+	VertexAttribDivisor   :: proc(index: u32, divisor: u32) ---
+	DrawArraysInstanced   :: proc(mode: Enum, first, count: int, instanceCount: int) ---
+	DrawElementsInstanced :: proc(mode: Enum, count: int, type: Enum, offset: int, instanceCount: int) ---
+	DrawRangeElements     :: proc(mode: Enum, start, end, count: int, type: Enum, offset: int) ---
+	
+	/* Multiple Render Targets */
+	DrawBuffers    :: proc(buffers: []Enum) ---
+	ClearBufferfv  :: proc(buffer: Enum, drawbuffer: i32, values: []f32) ---
+	ClearBufferiv  :: proc(buffer: Enum, drawbuffer: i32, values: []i32) ---
+	ClearBufferuiv :: proc(buffer: Enum, drawbuffer: i32, values: []u32) ---
+	ClearBufferfi  :: proc(buffer: Enum, drawbuffer: i32, depth: f32, stencil: i32) ---
+	
+	CreateQuery :: proc() -> Query ---
+	DeleteQuery :: proc(query: Query) ---
+	IsQuery     :: proc(query: Query) -> bool ---
+	BeginQuery  :: proc(target: Enum, query: Query) ---
+	EndQuery    :: proc(target: Enum) ---
+	GetQuery    :: proc(target, pname: Enum) ---
+	
+	CreateSampler     :: proc() -> Sampler ---
+	DeleteSampler     :: proc(sampler: Sampler) ---
+	IsSampler         :: proc(sampler: Sampler) -> bool ---
+	BindSampler       :: proc(unit: Enum, sampler: Sampler) ---
+	SamplerParameteri :: proc(sampler: Sampler, pname: Enum, param: i32) ---
+	SamplerParameterf :: proc(sampler: Sampler, pname: Enum, param: f32) ---
+	
+	FenceSync      :: proc(condition: Enum, flags: u32) -> Sync ---
+	IsSync         :: proc(sync: Sync) -> bool ---
+	DeleteSync     :: proc(sync: Sync) ---
+	ClientWaitSync :: proc(sync: Sync, flags: u32, timeout: u64) ---
+	WaitSync       :: proc(sync: Sync, flags: u32, timeout: i64) ---
+	
+	CreateTransformFeedback   :: proc() -> TransformFeedback ---
+	DeleteTransformFeedback   :: proc(tf: TransformFeedback) ---
+	IsTransformFeedback       :: proc(tf: TransformFeedback) -> bool ---
+	BindTransformFeedback     :: proc(target: Enum, tf: TransformFeedback) ---
+	BeginTransformFeedback    :: proc(primitiveMode: Enum) ---
+	EndTransformFeedback      :: proc() ---
+	TransformFeedbackVaryings :: proc(program: Program, varyings: []string, bufferMode: Enum) ---
+	PauseTransformFeedback    :: proc() ---
+	ResumeTransformFeedback   :: proc() ---
+	
+	BindBufferBase            :: proc(target: Enum, index: i32, buffer: Buffer) ---
+	BindBufferRange           :: proc(target: Enum, index: i32, buffer: Buffer, offset: int, size: int) ---
+	GetUniformBlockIndex      :: proc(program: Program, uniformBlockName: string) -> i32 ---
+	UniformBlockBinding       :: proc(program: Program, uniformBlockIndex: i32, uniformBlockBinding: i32) ---
+	
+	CreateVertexArray :: proc() -> VertexArrayObject ---
+	DeleteVertexArray :: proc(vertexArray: VertexArrayObject) ---
+	IsVertexArray     :: proc(vertexArray: VertexArrayObject) -> bool ---
+	BindVertexArray   :: proc(vertexArray: VertexArrayObject) ---	
+}
+
+GetActiveUniformBlockName :: proc(program: Program, uniformBlockIndex: i32, buf: []byte) -> string {
+	foreign webgl2 {
+		_GetActiveUniformBlockName :: proc(program: Program, uniformBlockIndex: i32, buf: []byte, length: ^int) ---
+	}
+	n: int
+	_GetActiveUniformBlockName(program, uniformBlockIndex, buf, &n)
+	return string(buf[:n])	
+}
+
+
+Uniform1uiv :: proc "c" (location: i32, v: u32) {
+	Uniform1ui(location, v)
+}
+Uniform2uiv :: proc "c" (location: i32, v: glm.uvec2) {
+	Uniform2ui(location, v.x, v.y)
+}
+Uniform3uiv :: proc "c" (location: i32, v: glm.uvec3) {
+	Uniform3ui(location, v.x, v.y, v.z)
+}
+Uniform4uiv :: proc "c" (location: i32, v: glm.uvec4) {
+	Uniform4ui(location, v.x, v.y, v.z, v.w)
+}
+
+UniformMatrix3x2fv :: proc "c" (location: i32, m: glm.mat3x2) {
+	foreign webgl2 {
+		_UniformMatrix3x2fv :: proc "c" (location: i32, addr: [^]f32) ---
+	}
+	array := matrix_flatten(m)
+	_UniformMatrix3x2fv(location, &array[0])
+}
+UniformMatrix4x2fv :: proc "c" (location: i32, m: glm.mat4x2) {
+	foreign webgl2 {
+		_UniformMatrix4x2fv :: proc "c" (location: i32, addr: [^]f32) ---
+	}
+	array := matrix_flatten(m)
+	_UniformMatrix4x2fv(location, &array[0])
+}
+UniformMatrix2x3fv :: proc "c" (location: i32, m: glm.mat2x3) {
+	foreign webgl2 {
+		_UniformMatrix2x3fv :: proc "c" (location: i32, addr: [^]f32) ---
+	}
+	array := matrix_flatten(m)
+	_UniformMatrix2x3fv(location, &array[0])
+}
+UniformMatrix4x3fv :: proc "c" (location: i32, m: glm.mat4x3) {
+	foreign webgl2 {
+		_UniformMatrix4x3fv :: proc "c" (location: i32, addr: [^]f32) ---
+	}
+	array := matrix_flatten(m)
+	_UniformMatrix4x3fv(location, &array[0])
+}
+UniformMatrix2x4fv :: proc "c" (location: i32, m: glm.mat2x4) {
+	foreign webgl2 {
+		_UniformMatrix2x4fv :: proc "c" (location: i32, addr: [^]f32) ---
+	}
+	array := matrix_flatten(m)
+	_UniformMatrix2x4fv(location, &array[0])
+}
+UniformMatrix3x4fv :: proc "c" (location: i32, m: glm.mat3x4) {
+	foreign webgl2 {
+		_UniformMatrix3x4fv :: proc "c" (location: i32, addr: [^]f32) ---
+	}
+	array := matrix_flatten(m)
+	_UniformMatrix3x4fv(location, &array[0])
+}
+
+VertexAttribI4iv :: proc "c" (index: i32, v: glm.ivec4) {
+	VertexAttribI4i(index, v.x, v.y, v.z, v.w)
+}
+VertexAttribI4uiv :: proc "c" (index: i32, v: glm.uvec4) {
+	VertexAttribI4ui(index, v.x, v.y, v.z, v.w)
+}

+ 268 - 0
vendor/wasm/WebGL/webgl2_constants.odin

@@ -0,0 +1,268 @@
+package webgl
+
+READ_BUFFER                                   :: Enum(0x0C02)
+UNPACK_ROW_LENGTH                             :: Enum(0x0CF2)
+UNPACK_SKIP_ROWS                              :: Enum(0x0CF3)
+UNPACK_SKIP_PIXELS                            :: Enum(0x0CF4)
+PACK_ROW_LENGTH                               :: Enum(0x0D02)
+PACK_SKIP_ROWS                                :: Enum(0x0D03)
+PACK_SKIP_PIXELS                              :: Enum(0x0D04)
+COLOR                                         :: Enum(0x1800)
+DEPTH                                         :: Enum(0x1801)
+STENCIL                                       :: Enum(0x1802)
+RED                                           :: Enum(0x1903)
+RGB8                                          :: Enum(0x8051)
+RGBA8                                         :: Enum(0x8058)
+RGB10_A2                                      :: Enum(0x8059)
+TEXTURE_BINDING_3D                            :: Enum(0x806A)
+UNPACK_SKIP_IMAGES                            :: Enum(0x806D)
+UNPACK_IMAGE_HEIGHT                           :: Enum(0x806E)
+TEXTURE_3D                                    :: Enum(0x806F)
+TEXTURE_WRAP_R                                :: Enum(0x8072)
+MAX_3D_TEXTURE_SIZE                           :: Enum(0x8073)
+UNSIGNED_INT_2_10_10_10_REV                   :: Enum(0x8368)
+MAX_ELEMENTS_VERTICES                         :: Enum(0x80E8)
+MAX_ELEMENTS_INDICES                          :: Enum(0x80E9)
+TEXTURE_MIN_LOD                               :: Enum(0x813A)
+TEXTURE_MAX_LOD                               :: Enum(0x813B)
+TEXTURE_BASE_LEVEL                            :: Enum(0x813C)
+TEXTURE_MAX_LEVEL                             :: Enum(0x813D)
+MIN                                           :: Enum(0x8007)
+MAX                                           :: Enum(0x8008)
+DEPTH_COMPONENT24                             :: Enum(0x81A6)
+MAX_TEXTURE_LOD_BIAS                          :: Enum(0x84FD)
+TEXTURE_COMPARE_MODE                          :: Enum(0x884C)
+TEXTURE_COMPARE_FUNC                          :: Enum(0x884D)
+CURRENT_QUERY                                 :: Enum(0x8865)
+QUERY_RESULT                                  :: Enum(0x8866)
+QUERY_RESULT_AVAILABLE                        :: Enum(0x8867)
+STREAM_READ                                   :: Enum(0x88E1)
+STREAM_COPY                                   :: Enum(0x88E2)
+STATIC_READ                                   :: Enum(0x88E5)
+STATIC_COPY                                   :: Enum(0x88E6)
+DYNAMIC_READ                                  :: Enum(0x88E9)
+DYNAMIC_COPY                                  :: Enum(0x88EA)
+MAX_DRAW_BUFFERS                              :: Enum(0x8824)
+DRAW_BUFFER0                                  :: Enum(0x8825)
+DRAW_BUFFER1                                  :: Enum(0x8826)
+DRAW_BUFFER2                                  :: Enum(0x8827)
+DRAW_BUFFER3                                  :: Enum(0x8828)
+DRAW_BUFFER4                                  :: Enum(0x8829)
+DRAW_BUFFER5                                  :: Enum(0x882A)
+DRAW_BUFFER6                                  :: Enum(0x882B)
+DRAW_BUFFER7                                  :: Enum(0x882C)
+DRAW_BUFFER8                                  :: Enum(0x882D)
+DRAW_BUFFER9                                  :: Enum(0x882E)
+DRAW_BUFFER10                                 :: Enum(0x882F)
+DRAW_BUFFER11                                 :: Enum(0x8830)
+DRAW_BUFFER12                                 :: Enum(0x8831)
+DRAW_BUFFER13                                 :: Enum(0x8832)
+DRAW_BUFFER14                                 :: Enum(0x8833)
+DRAW_BUFFER15                                 :: Enum(0x8834)
+MAX_FRAGMENT_UNIFORM_COMPONENTS               :: Enum(0x8B49)
+MAX_VERTEX_UNIFORM_COMPONENTS                 :: Enum(0x8B4A)
+SAMPLER_3D                                    :: Enum(0x8B5F)
+SAMPLER_2D_SHADOW                             :: Enum(0x8B62)
+FRAGMENT_SHADER_DERIVATIVE_HINT               :: Enum(0x8B8B)
+PIXEL_PACK_BUFFER                             :: Enum(0x88EB)
+PIXEL_UNPACK_BUFFER                           :: Enum(0x88EC)
+PIXEL_PACK_BUFFER_BINDING                     :: Enum(0x88ED)
+PIXEL_UNPACK_BUFFER_BINDING                   :: Enum(0x88EF)
+FLOAT_MAT2x3                                  :: Enum(0x8B65)
+FLOAT_MAT2x4                                  :: Enum(0x8B66)
+FLOAT_MAT3x2                                  :: Enum(0x8B67)
+FLOAT_MAT3x4                                  :: Enum(0x8B68)
+FLOAT_MAT4x2                                  :: Enum(0x8B69)
+FLOAT_MAT4x3                                  :: Enum(0x8B6A)
+SRGB                                          :: Enum(0x8C40)
+SRGB8                                         :: Enum(0x8C41)
+SRGB8_ALPHA8                                  :: Enum(0x8C43)
+COMPARE_REF_TO_TEXTURE                        :: Enum(0x884E)
+RGBA32F                                       :: Enum(0x8814)
+RGB32F                                        :: Enum(0x8815)
+RGBA16F                                       :: Enum(0x881A)
+RGB16F                                        :: Enum(0x881B)
+VERTEX_ATTRIB_ARRAY_INTEGER                   :: Enum(0x88FD)
+MAX_ARRAY_TEXTURE_LAYERS                      :: Enum(0x88FF)
+MIN_PROGRAM_TEXEL_OFFSET                      :: Enum(0x8904)
+MAX_PROGRAM_TEXEL_OFFSET                      :: Enum(0x8905)
+MAX_VARYING_COMPONENTS                        :: Enum(0x8B4B)
+TEXTURE_2D_ARRAY                              :: Enum(0x8C1A)
+TEXTURE_BINDING_2D_ARRAY                      :: Enum(0x8C1D)
+R11F_G11F_B10F                                :: Enum(0x8C3A)
+UNSIGNED_INT_10F_11F_11F_REV                  :: Enum(0x8C3B)
+RGB9_E5                                       :: Enum(0x8C3D)
+UNSIGNED_INT_5_9_9_9_REV                      :: Enum(0x8C3E)
+TRANSFORM_FEEDBACK_BUFFER_MODE                :: Enum(0x8C7F)
+MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS    :: Enum(0x8C80)
+TRANSFORM_FEEDBACK_VARYINGS                   :: Enum(0x8C83)
+TRANSFORM_FEEDBACK_BUFFER_START               :: Enum(0x8C84)
+TRANSFORM_FEEDBACK_BUFFER_SIZE                :: Enum(0x8C85)
+TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN         :: Enum(0x8C88)
+RASTERIZER_DISCARD                            :: Enum(0x8C89)
+MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS :: Enum(0x8C8A)
+MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS       :: Enum(0x8C8B)
+INTERLEAVED_ATTRIBS                           :: Enum(0x8C8C)
+SEPARATE_ATTRIBS                              :: Enum(0x8C8D)
+TRANSFORM_FEEDBACK_BUFFER                     :: Enum(0x8C8E)
+TRANSFORM_FEEDBACK_BUFFER_BINDING             :: Enum(0x8C8F)
+RGBA32UI                                      :: Enum(0x8D70)
+RGB32UI                                       :: Enum(0x8D71)
+RGBA16UI                                      :: Enum(0x8D76)
+RGB16UI                                       :: Enum(0x8D77)
+RGBA8UI                                       :: Enum(0x8D7C)
+RGB8UI                                        :: Enum(0x8D7D)
+RGBA32I                                       :: Enum(0x8D82)
+RGB32I                                        :: Enum(0x8D83)
+RGBA16I                                       :: Enum(0x8D88)
+RGB16I                                        :: Enum(0x8D89)
+RGBA8I                                        :: Enum(0x8D8E)
+RGB8I                                         :: Enum(0x8D8F)
+RED_INTEGER                                   :: Enum(0x8D94)
+RGB_INTEGER                                   :: Enum(0x8D98)
+RGBA_INTEGER                                  :: Enum(0x8D99)
+SAMPLER_2D_ARRAY                              :: Enum(0x8DC1)
+SAMPLER_2D_ARRAY_SHADOW                       :: Enum(0x8DC4)
+SAMPLER_CUBE_SHADOW                           :: Enum(0x8DC5)
+UNSIGNED_INT_VEC2                             :: Enum(0x8DC6)
+UNSIGNED_INT_VEC3                             :: Enum(0x8DC7)
+UNSIGNED_INT_VEC4                             :: Enum(0x8DC8)
+INT_SAMPLER_2D                                :: Enum(0x8DCA)
+INT_SAMPLER_3D                                :: Enum(0x8DCB)
+INT_SAMPLER_CUBE                              :: Enum(0x8DCC)
+INT_SAMPLER_2D_ARRAY                          :: Enum(0x8DCF)
+UNSIGNED_INT_SAMPLER_2D                       :: Enum(0x8DD2)
+UNSIGNED_INT_SAMPLER_3D                       :: Enum(0x8DD3)
+UNSIGNED_INT_SAMPLER_CUBE                     :: Enum(0x8DD4)
+UNSIGNED_INT_SAMPLER_2D_ARRAY                 :: Enum(0x8DD7)
+DEPTH_COMPONENT32F                            :: Enum(0x8CAC)
+DEPTH32F_STENCIL8                             :: Enum(0x8CAD)
+FLOAT_32_UNSIGNED_INT_24_8_REV                :: Enum(0x8DAD)
+FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING         :: Enum(0x8210)
+FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE         :: Enum(0x8211)
+FRAMEBUFFER_ATTACHMENT_RED_SIZE               :: Enum(0x8212)
+FRAMEBUFFER_ATTACHMENT_GREEN_SIZE             :: Enum(0x8213)
+FRAMEBUFFER_ATTACHMENT_BLUE_SIZE              :: Enum(0x8214)
+FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE             :: Enum(0x8215)
+FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE             :: Enum(0x8216)
+FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE           :: Enum(0x8217)
+FRAMEBUFFER_DEFAULT                           :: Enum(0x8218)
+UNSIGNED_INT_24_8                             :: Enum(0x84FA)
+DEPTH24_STENCIL8                              :: Enum(0x88F0)
+UNSIGNED_NORMALIZED                           :: Enum(0x8C17)
+DRAW_FRAMEBUFFER_BINDING                      :: FRAMEBUFFER_BINDING /* Same as FRAMEBUFFER_BINDING */
+READ_FRAMEBUFFER                              :: Enum(0x8CA8)
+DRAW_FRAMEBUFFER                              :: Enum(0x8CA9)
+READ_FRAMEBUFFER_BINDING                      :: Enum(0x8CAA)
+RENDERBUFFER_SAMPLES                          :: Enum(0x8CAB)
+FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER          :: Enum(0x8CD4)
+MAX_COLOR_ATTACHMENTS                         :: Enum(0x8CDF)
+COLOR_ATTACHMENT1                             :: Enum(0x8CE1)
+COLOR_ATTACHMENT2                             :: Enum(0x8CE2)
+COLOR_ATTACHMENT3                             :: Enum(0x8CE3)
+COLOR_ATTACHMENT4                             :: Enum(0x8CE4)
+COLOR_ATTACHMENT5                             :: Enum(0x8CE5)
+COLOR_ATTACHMENT6                             :: Enum(0x8CE6)
+COLOR_ATTACHMENT7                             :: Enum(0x8CE7)
+COLOR_ATTACHMENT8                             :: Enum(0x8CE8)
+COLOR_ATTACHMENT9                             :: Enum(0x8CE9)
+COLOR_ATTACHMENT10                            :: Enum(0x8CEA)
+COLOR_ATTACHMENT11                            :: Enum(0x8CEB)
+COLOR_ATTACHMENT12                            :: Enum(0x8CEC)
+COLOR_ATTACHMENT13                            :: Enum(0x8CED)
+COLOR_ATTACHMENT14                            :: Enum(0x8CEE)
+COLOR_ATTACHMENT15                            :: Enum(0x8CEF)
+FRAMEBUFFER_INCOMPLETE_MULTISAMPLE            :: Enum(0x8D56)
+MAX_SAMPLES                                   :: Enum(0x8D57)
+HALF_FLOAT                                    :: Enum(0x140B)
+RG                                            :: Enum(0x8227)
+RG_INTEGER                                    :: Enum(0x8228)
+R8                                            :: Enum(0x8229)
+RG8                                           :: Enum(0x822B)
+R16F                                          :: Enum(0x822D)
+R32F                                          :: Enum(0x822E)
+RG16F                                         :: Enum(0x822F)
+RG32F                                         :: Enum(0x8230)
+R8I                                           :: Enum(0x8231)
+R8UI                                          :: Enum(0x8232)
+R16I                                          :: Enum(0x8233)
+R16UI                                         :: Enum(0x8234)
+R32I                                          :: Enum(0x8235)
+R32UI                                         :: Enum(0x8236)
+RG8I                                          :: Enum(0x8237)
+RG8UI                                         :: Enum(0x8238)
+RG16I                                         :: Enum(0x8239)
+RG16UI                                        :: Enum(0x823A)
+RG32I                                         :: Enum(0x823B)
+RG32UI                                        :: Enum(0x823C)
+VERTEX_ARRAY_BINDING                          :: Enum(0x85B5)
+R8_SNORM                                      :: Enum(0x8F94)
+RG8_SNORM                                     :: Enum(0x8F95)
+RGB8_SNORM                                    :: Enum(0x8F96)
+RGBA8_SNORM                                   :: Enum(0x8F97)
+SIGNED_NORMALIZED                             :: Enum(0x8F9C)
+COPY_READ_BUFFER                              :: Enum(0x8F36)
+COPY_WRITE_BUFFER                             :: Enum(0x8F37)
+COPY_READ_BUFFER_BINDING                      :: COPY_READ_BUFFER /* Same as COPY_READ_BUFFER */
+COPY_WRITE_BUFFER_BINDING                     :: COPY_WRITE_BUFFER /* Same as COPY_WRITE_BUFFER */
+UNIFORM_BUFFER                                :: Enum(0x8A11)
+UNIFORM_BUFFER_BINDING                        :: Enum(0x8A28)
+UNIFORM_BUFFER_START                          :: Enum(0x8A29)
+UNIFORM_BUFFER_SIZE                           :: Enum(0x8A2A)
+MAX_VERTEX_UNIFORM_BLOCKS                     :: Enum(0x8A2B)
+MAX_FRAGMENT_UNIFORM_BLOCKS                   :: Enum(0x8A2D)
+MAX_COMBINED_UNIFORM_BLOCKS                   :: Enum(0x8A2E)
+MAX_UNIFORM_BUFFER_BINDINGS                   :: Enum(0x8A2F)
+MAX_UNIFORM_BLOCK_SIZE                        :: Enum(0x8A30)
+MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS        :: Enum(0x8A31)
+MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS      :: Enum(0x8A33)
+UNIFORM_BUFFER_OFFSET_ALIGNMENT               :: Enum(0x8A34)
+ACTIVE_UNIFORM_BLOCKS                         :: Enum(0x8A36)
+UNIFORM_TYPE                                  :: Enum(0x8A37)
+UNIFORM_SIZE                                  :: Enum(0x8A38)
+UNIFORM_BLOCK_INDEX                           :: Enum(0x8A3A)
+UNIFORM_OFFSET                                :: Enum(0x8A3B)
+UNIFORM_ARRAY_STRIDE                          :: Enum(0x8A3C)
+UNIFORM_MATRIX_STRIDE                         :: Enum(0x8A3D)
+UNIFORM_IS_ROW_MAJOR                          :: Enum(0x8A3E)
+UNIFORM_BLOCK_BINDING                         :: Enum(0x8A3F)
+UNIFORM_BLOCK_DATA_SIZE                       :: Enum(0x8A40)
+UNIFORM_BLOCK_ACTIVE_UNIFORMS                 :: Enum(0x8A42)
+UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES          :: Enum(0x8A43)
+UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER     :: Enum(0x8A44)
+UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER   :: Enum(0x8A46)
+INVALID_INDEX                                 :: Enum(0xFFFFFFFF)
+MAX_VERTEX_OUTPUT_COMPONENTS                  :: Enum(0x9122)
+MAX_FRAGMENT_INPUT_COMPONENTS                 :: Enum(0x9125)
+MAX_SERVER_WAIT_TIMEOUT                       :: Enum(0x9111)
+OBJECT_TYPE                                   :: Enum(0x9112)
+SYNC_CONDITION                                :: Enum(0x9113)
+SYNC_STATUS                                   :: Enum(0x9114)
+SYNC_FLAGS                                    :: Enum(0x9115)
+SYNC_FENCE                                    :: Enum(0x9116)
+SYNC_GPU_COMMANDS_COMPLETE                    :: Enum(0x9117)
+UNSIGNALED                                    :: Enum(0x9118)
+SIGNALED                                      :: Enum(0x9119)
+ALREADY_SIGNALED                              :: Enum(0x911A)
+TIMEOUT_EXPIRED                               :: Enum(0x911B)
+CONDITION_SATISFIED                           :: Enum(0x911C)
+WAIT_FAILED                                   :: Enum(0x911D)
+SYNC_FLUSH_COMMANDS_BIT                       :: Enum(0x00000001)
+VERTEX_ATTRIB_ARRAY_DIVISOR                   :: Enum(0x88FE)
+ANY_SAMPLES_PASSED                            :: Enum(0x8C2F)
+ANY_SAMPLES_PASSED_CONSERVATIVE               :: Enum(0x8D6A)
+SAMPLER_BINDING                               :: Enum(0x8919)
+RGB10_A2UI                                    :: Enum(0x906F)
+INT_2_10_10_10_REV                            :: Enum(0x8D9F)
+TRANSFORM_FEEDBACK                            :: Enum(0x8E22)
+TRANSFORM_FEEDBACK_PAUSED                     :: Enum(0x8E23)
+TRANSFORM_FEEDBACK_ACTIVE                     :: Enum(0x8E24)
+TRANSFORM_FEEDBACK_BINDING                    :: Enum(0x8E25)
+TEXTURE_IMMUTABLE_FORMAT                      :: Enum(0x912F)
+MAX_ELEMENT_INDEX                             :: Enum(0x8D6B)
+TEXTURE_IMMUTABLE_LEVELS                      :: Enum(0x82DF)
+
+TIMEOUT_IGNORED                               :: i64(-1)
+
+/* WebGL-specific enums */
+MAX_CLIENT_WAIT_TIMEOUT_WEBGL                 :: Enum(0x9247)

+ 420 - 0
vendor/wasm/WebGL/webgl_constants.odin

@@ -0,0 +1,420 @@
+package webgl
+
+/* ClearBufferMask */
+DEPTH_BUFFER_BIT               :: Enum(0x00000100)
+STENCIL_BUFFER_BIT             :: Enum(0x00000400)
+COLOR_BUFFER_BIT               :: Enum(0x00004000)
+
+/* BeginMode */
+POINTS                         :: Enum(0x0000)
+LINES                          :: Enum(0x0001)
+LINE_LOOP                      :: Enum(0x0002)
+LINE_STRIP                     :: Enum(0x0003)
+TRIANGLES                      :: Enum(0x0004)
+TRIANGLE_STRIP                 :: Enum(0x0005)
+TRIANGLE_FAN                   :: Enum(0x0006)
+
+/* AlphaFunction (not supported in ES20) */
+/*      NEVER */
+/*      LESS */
+/*      EQUAL */
+/*      LEQUAL */
+/*      GREATER */
+/*      NOTEQUAL */
+/*      GEQUAL */
+/*      ALWAYS */
+
+/* BlendingFactorDest */
+ZERO                           :: Enum(0)
+ONE                            :: Enum(1)
+SRC_COLOR                      :: Enum(0x0300)
+ONE_MINUS_SRC_COLOR            :: Enum(0x0301)
+SRC_ALPHA                      :: Enum(0x0302)
+ONE_MINUS_SRC_ALPHA            :: Enum(0x0303)
+DST_ALPHA                      :: Enum(0x0304)
+ONE_MINUS_DST_ALPHA            :: Enum(0x0305)
+
+/* BlendingFactorSrc */
+/*      ZERO */
+/*      ONE */
+DST_COLOR                      :: Enum(0x0306)
+ONE_MINUS_DST_COLOR            :: Enum(0x0307)
+SRC_ALPHA_SATURATE             :: Enum(0x0308)
+/*      SRC_ALPHA */
+/*      ONE_MINUS_SRC_ALPHA */
+/*      DST_ALPHA */
+/*      ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+FUNC_ADD                       :: Enum(0x8006)
+BLEND_EQUATION                 :: Enum(0x8009)
+BLEND_EQUATION_RGB             :: Enum(0x8009   /* same as BLEND_EQUATION */)
+BLEND_EQUATION_ALPHA           :: Enum(0x883D)
+
+/* BlendSubtract */
+FUNC_SUBTRACT                  :: Enum(0x800A)
+FUNC_REVERSE_SUBTRACT          :: Enum(0x800B)
+
+/* Separate Blend Functions */
+BLEND_DST_RGB                  :: Enum(0x80C8)
+BLEND_SRC_RGB                  :: Enum(0x80C9)
+BLEND_DST_ALPHA                :: Enum(0x80CA)
+BLEND_SRC_ALPHA                :: Enum(0x80CB)
+CONSTANT_COLOR                 :: Enum(0x8001)
+ONE_MINUS_CONSTANT_COLOR       :: Enum(0x8002)
+CONSTANT_ALPHA                 :: Enum(0x8003)
+ONE_MINUS_CONSTANT_ALPHA       :: Enum(0x8004)
+BLEND_COLOR                    :: Enum(0x8005)
+
+/* Buffer Objects */
+ARRAY_BUFFER                   :: Enum(0x8892)
+ELEMENT_ARRAY_BUFFER           :: Enum(0x8893)
+ARRAY_BUFFER_BINDING           :: Enum(0x8894)
+ELEMENT_ARRAY_BUFFER_BINDING   :: Enum(0x8895)
+
+STREAM_DRAW                    :: Enum(0x88E0)
+STATIC_DRAW                    :: Enum(0x88E4)
+DYNAMIC_DRAW                   :: Enum(0x88E8)
+
+BUFFER_SIZE                    :: Enum(0x8764)
+BUFFER_USAGE                   :: Enum(0x8765)
+
+CURRENT_VERTEX_ATTRIB          :: Enum(0x8626)
+
+/* CullFaceMode */
+FRONT                          :: Enum(0x0404)
+BACK                           :: Enum(0x0405)
+FRONT_AND_BACK                 :: Enum(0x0408)
+
+/* DepthFunction */
+/*      NEVER */
+/*      LESS */
+/*      EQUAL */
+/*      LEQUAL */
+/*      GREATER */
+/*      NOTEQUAL */
+/*      GEQUAL */
+/*      ALWAYS */
+
+/* EnableCap */
+/* TEXTURE_2D */
+CULL_FACE                      :: Enum(0x0B44)
+BLEND                          :: Enum(0x0BE2)
+DITHER                         :: Enum(0x0BD0)
+STENCIL_TEST                   :: Enum(0x0B90)
+DEPTH_TEST                     :: Enum(0x0B71)
+SCISSOR_TEST                   :: Enum(0x0C11)
+POLYGON_OFFSET_FILL            :: Enum(0x8037)
+SAMPLE_ALPHA_TO_COVERAGE       :: Enum(0x809E)
+SAMPLE_COVERAGE                :: Enum(0x80A0)
+
+/* ErrorCode */
+NO_ERROR                       :: Enum(0)
+INVALID_ENUM                   :: Enum(0x0500)
+INVALID_VALUE                  :: Enum(0x0501)
+INVALID_OPERATION              :: Enum(0x0502)
+OUT_OF_MEMORY                  :: Enum(0x0505)
+
+/* FrontFaceDirection */
+CW                             :: Enum(0x0900)
+CCW                            :: Enum(0x0901)
+
+/* GetPName */
+LINE_WIDTH                     :: Enum(0x0B21)
+ALIASED_POINT_SIZE_RANGE       :: Enum(0x846D)
+ALIASED_LINE_WIDTH_RANGE       :: Enum(0x846E)
+CULL_FACE_MODE                 :: Enum(0x0B45)
+FRONT_FACE                     :: Enum(0x0B46)
+DEPTH_RANGE                    :: Enum(0x0B70)
+DEPTH_WRITEMASK                :: Enum(0x0B72)
+DEPTH_CLEAR_VALUE              :: Enum(0x0B73)
+DEPTH_FUNC                     :: Enum(0x0B74)
+STENCIL_CLEAR_VALUE            :: Enum(0x0B91)
+STENCIL_FUNC                   :: Enum(0x0B92)
+STENCIL_FAIL                   :: Enum(0x0B94)
+STENCIL_PASS_DEPTH_FAIL        :: Enum(0x0B95)
+STENCIL_PASS_DEPTH_PASS        :: Enum(0x0B96)
+STENCIL_REF                    :: Enum(0x0B97)
+STENCIL_VALUE_MASK             :: Enum(0x0B93)
+STENCIL_WRITEMASK              :: Enum(0x0B98)
+STENCIL_BACK_FUNC              :: Enum(0x8800)
+STENCIL_BACK_FAIL              :: Enum(0x8801)
+STENCIL_BACK_PASS_DEPTH_FAIL   :: Enum(0x8802)
+STENCIL_BACK_PASS_DEPTH_PASS   :: Enum(0x8803)
+STENCIL_BACK_REF               :: Enum(0x8CA3)
+STENCIL_BACK_VALUE_MASK        :: Enum(0x8CA4)
+STENCIL_BACK_WRITEMASK         :: Enum(0x8CA5)
+VIEWPORT                       :: Enum(0x0BA2)
+SCISSOR_BOX                    :: Enum(0x0C10)
+/*      SCISSOR_TEST */
+COLOR_CLEAR_VALUE              :: Enum(0x0C22)
+COLOR_WRITEMASK                :: Enum(0x0C23)
+UNPACK_ALIGNMENT               :: Enum(0x0CF5)
+PACK_ALIGNMENT                 :: Enum(0x0D05)
+MAX_TEXTURE_SIZE               :: Enum(0x0D33)
+MAX_VIEWPORT_DIMS              :: Enum(0x0D3A)
+SUBPIXEL_BITS                  :: Enum(0x0D50)
+RED_BITS                       :: Enum(0x0D52)
+GREEN_BITS                     :: Enum(0x0D53)
+BLUE_BITS                      :: Enum(0x0D54)
+ALPHA_BITS                     :: Enum(0x0D55)
+DEPTH_BITS                     :: Enum(0x0D56)
+STENCIL_BITS                   :: Enum(0x0D57)
+POLYGON_OFFSET_UNITS           :: Enum(0x2A00)
+/*      POLYGON_OFFSET_FILL */
+POLYGON_OFFSET_FACTOR          :: Enum(0x8038)
+TEXTURE_BINDING_2D             :: Enum(0x8069)
+SAMPLE_BUFFERS                 :: Enum(0x80A8)
+SAMPLES                        :: Enum(0x80A9)
+SAMPLE_COVERAGE_VALUE          :: Enum(0x80AA)
+SAMPLE_COVERAGE_INVERT         :: Enum(0x80AB)
+
+/* GetTextureParameter */
+/*      TEXTURE_MAG_FILTER */
+/*      TEXTURE_MIN_FILTER */
+/*      TEXTURE_WRAP_S */
+/*      TEXTURE_WRAP_T */
+
+COMPRESSED_TEXTURE_FORMATS     :: Enum(0x86A3)
+
+/* HintMode */
+DONT_CARE                      :: Enum(0x1100)
+FASTEST                        :: Enum(0x1101)
+NICEST                         :: Enum(0x1102)
+
+/* HintTarget */
+GENERATE_MIPMAP_HINT            :: Enum(0x8192)
+
+/* DataType */
+BYTE                           :: Enum(0x1400)
+UNSIGNED_BYTE                  :: Enum(0x1401)
+SHORT                          :: Enum(0x1402)
+UNSIGNED_SHORT                 :: Enum(0x1403)
+INT                            :: Enum(0x1404)
+UNSIGNED_INT                   :: Enum(0x1405)
+FLOAT                          :: Enum(0x1406)
+
+/* PixelFormat */
+DEPTH_COMPONENT                :: Enum(0x1902)
+ALPHA                          :: Enum(0x1906)
+RGB                            :: Enum(0x1907)
+RGBA                           :: Enum(0x1908)
+LUMINANCE                      :: Enum(0x1909)
+LUMINANCE_ALPHA                :: Enum(0x190A)
+
+/* PixelType */
+/*      UNSIGNED_BYTE */
+UNSIGNED_SHORT_4_4_4_4         :: Enum(0x8033)
+UNSIGNED_SHORT_5_5_5_1         :: Enum(0x8034)
+UNSIGNED_SHORT_5_6_5           :: Enum(0x8363)
+
+/* Shaders */
+FRAGMENT_SHADER                  :: Enum(0x8B30)
+VERTEX_SHADER                    :: Enum(0x8B31)
+MAX_VERTEX_ATTRIBS               :: Enum(0x8869)
+MAX_VERTEX_UNIFORM_VECTORS       :: Enum(0x8DFB)
+MAX_VARYING_VECTORS              :: Enum(0x8DFC)
+MAX_COMBINED_TEXTURE_IMAGE_UNITS :: Enum(0x8B4D)
+MAX_VERTEX_TEXTURE_IMAGE_UNITS   :: Enum(0x8B4C)
+MAX_TEXTURE_IMAGE_UNITS          :: Enum(0x8872)
+MAX_FRAGMENT_UNIFORM_VECTORS     :: Enum(0x8DFD)
+SHADER_TYPE                      :: Enum(0x8B4F)
+DELETE_STATUS                    :: Enum(0x8B80)
+LINK_STATUS                      :: Enum(0x8B82)
+VALIDATE_STATUS                  :: Enum(0x8B83)
+ATTACHED_SHADERS                 :: Enum(0x8B85)
+ACTIVE_UNIFORMS                  :: Enum(0x8B86)
+ACTIVE_ATTRIBUTES                :: Enum(0x8B89)
+SHADING_LANGUAGE_VERSION         :: Enum(0x8B8C)
+CURRENT_PROGRAM                  :: Enum(0x8B8D)
+
+/* StencilFunction */
+NEVER                          :: Enum(0x0200)
+LESS                           :: Enum(0x0201)
+EQUAL                          :: Enum(0x0202)
+LEQUAL                         :: Enum(0x0203)
+GREATER                        :: Enum(0x0204)
+NOTEQUAL                       :: Enum(0x0205)
+GEQUAL                         :: Enum(0x0206)
+ALWAYS                         :: Enum(0x0207)
+
+/* StencilOp */
+/*      ZERO */
+KEEP                           :: Enum(0x1E00)
+REPLACE                        :: Enum(0x1E01)
+INCR                           :: Enum(0x1E02)
+DECR                           :: Enum(0x1E03)
+INVERT                         :: Enum(0x150A)
+INCR_WRAP                      :: Enum(0x8507)
+DECR_WRAP                      :: Enum(0x8508)
+
+/* StringName */
+VENDOR                         :: Enum(0x1F00)
+RENDERER                       :: Enum(0x1F01)
+VERSION                        :: Enum(0x1F02)
+
+/* TextureMagFilter */
+NEAREST                        :: Enum(0x2600)
+LINEAR                         :: Enum(0x2601)
+
+/* TextureMinFilter */
+/*      NEAREST */
+/*      LINEAR */
+NEAREST_MIPMAP_NEAREST         :: Enum(0x2700)
+LINEAR_MIPMAP_NEAREST          :: Enum(0x2701)
+NEAREST_MIPMAP_LINEAR          :: Enum(0x2702)
+LINEAR_MIPMAP_LINEAR           :: Enum(0x2703)
+
+/* TextureParameterName */
+TEXTURE_MAG_FILTER             :: Enum(0x2800)
+TEXTURE_MIN_FILTER             :: Enum(0x2801)
+TEXTURE_WRAP_S                 :: Enum(0x2802)
+TEXTURE_WRAP_T                 :: Enum(0x2803)
+
+/* TextureTarget */
+TEXTURE_2D                     :: Enum(0x0DE1)
+TEXTURE                        :: Enum(0x1702)
+
+TEXTURE_CUBE_MAP               :: Enum(0x8513)
+TEXTURE_BINDING_CUBE_MAP       :: Enum(0x8514)
+TEXTURE_CUBE_MAP_POSITIVE_X    :: Enum(0x8515)
+TEXTURE_CUBE_MAP_NEGATIVE_X    :: Enum(0x8516)
+TEXTURE_CUBE_MAP_POSITIVE_Y    :: Enum(0x8517)
+TEXTURE_CUBE_MAP_NEGATIVE_Y    :: Enum(0x8518)
+TEXTURE_CUBE_MAP_POSITIVE_Z    :: Enum(0x8519)
+TEXTURE_CUBE_MAP_NEGATIVE_Z    :: Enum(0x851A)
+MAX_CUBE_MAP_TEXTURE_SIZE      :: Enum(0x851C)
+
+/* TextureUnit */
+TEXTURE0                       :: Enum(0x84C0)
+TEXTURE1                       :: Enum(0x84C1)
+TEXTURE2                       :: Enum(0x84C2)
+TEXTURE3                       :: Enum(0x84C3)
+TEXTURE4                       :: Enum(0x84C4)
+TEXTURE5                       :: Enum(0x84C5)
+TEXTURE6                       :: Enum(0x84C6)
+TEXTURE7                       :: Enum(0x84C7)
+TEXTURE8                       :: Enum(0x84C8)
+TEXTURE9                       :: Enum(0x84C9)
+TEXTURE10                      :: Enum(0x84CA)
+TEXTURE11                      :: Enum(0x84CB)
+TEXTURE12                      :: Enum(0x84CC)
+TEXTURE13                      :: Enum(0x84CD)
+TEXTURE14                      :: Enum(0x84CE)
+TEXTURE15                      :: Enum(0x84CF)
+TEXTURE16                      :: Enum(0x84D0)
+TEXTURE17                      :: Enum(0x84D1)
+TEXTURE18                      :: Enum(0x84D2)
+TEXTURE19                      :: Enum(0x84D3)
+TEXTURE20                      :: Enum(0x84D4)
+TEXTURE21                      :: Enum(0x84D5)
+TEXTURE22                      :: Enum(0x84D6)
+TEXTURE23                      :: Enum(0x84D7)
+TEXTURE24                      :: Enum(0x84D8)
+TEXTURE25                      :: Enum(0x84D9)
+TEXTURE26                      :: Enum(0x84DA)
+TEXTURE27                      :: Enum(0x84DB)
+TEXTURE28                      :: Enum(0x84DC)
+TEXTURE29                      :: Enum(0x84DD)
+TEXTURE30                      :: Enum(0x84DE)
+TEXTURE31                      :: Enum(0x84DF)
+ACTIVE_TEXTURE                 :: Enum(0x84E0)
+
+/* TextureWrapMode */
+REPEAT                         :: Enum(0x2901)
+CLAMP_TO_EDGE                  :: Enum(0x812F)
+MIRRORED_REPEAT                :: Enum(0x8370)
+
+/* Uniform Types */
+FLOAT_VEC2                     :: Enum(0x8B50)
+FLOAT_VEC3                     :: Enum(0x8B51)
+FLOAT_VEC4                     :: Enum(0x8B52)
+INT_VEC2                       :: Enum(0x8B53)
+INT_VEC3                       :: Enum(0x8B54)
+INT_VEC4                       :: Enum(0x8B55)
+BOOL                           :: Enum(0x8B56)
+BOOL_VEC2                      :: Enum(0x8B57)
+BOOL_VEC3                      :: Enum(0x8B58)
+BOOL_VEC4                      :: Enum(0x8B59)
+FLOAT_MAT2                     :: Enum(0x8B5A)
+FLOAT_MAT3                     :: Enum(0x8B5B)
+FLOAT_MAT4                     :: Enum(0x8B5C)
+SAMPLER_2D                     :: Enum(0x8B5E)
+SAMPLER_CUBE                   :: Enum(0x8B60)
+
+/* Vertex Arrays */
+VERTEX_ATTRIB_ARRAY_ENABLED        :: Enum(0x8622)
+VERTEX_ATTRIB_ARRAY_SIZE           :: Enum(0x8623)
+VERTEX_ATTRIB_ARRAY_STRIDE         :: Enum(0x8624)
+VERTEX_ATTRIB_ARRAY_TYPE           :: Enum(0x8625)
+VERTEX_ATTRIB_ARRAY_NORMALIZED     :: Enum(0x886A)
+VERTEX_ATTRIB_ARRAY_POINTER        :: Enum(0x8645)
+VERTEX_ATTRIB_ARRAY_BUFFER_BINDING :: Enum(0x889F)
+
+/* Read Format */
+IMPLEMENTATION_COLOR_READ_TYPE   :: Enum(0x8B9A)
+IMPLEMENTATION_COLOR_READ_FORMAT :: Enum(0x8B9B)
+
+/* Shader Source */
+COMPILE_STATUS                 :: Enum(0x8B81)
+
+/* Shader Precision-Specified Types */
+LOW_FLOAT                      :: Enum(0x8DF0)
+MEDIUM_FLOAT                   :: Enum(0x8DF1)
+HIGH_FLOAT                     :: Enum(0x8DF2)
+LOW_INT                        :: Enum(0x8DF3)
+MEDIUM_INT                     :: Enum(0x8DF4)
+HIGH_INT                       :: Enum(0x8DF5)
+
+/* Framebuffer Object. */
+FRAMEBUFFER                    :: Enum(0x8D40)
+RENDERBUFFER                   :: Enum(0x8D41)
+
+RGBA4                          :: Enum(0x8056)
+RGB5_A1                        :: Enum(0x8057)
+RGB565                         :: Enum(0x8D62)
+DEPTH_COMPONENT16              :: Enum(0x81A5)
+STENCIL_INDEX                  :: Enum(0x1901)
+STENCIL_INDEX8                 :: Enum(0x8D48)
+DEPTH_STENCIL                  :: Enum(0x84F9)
+
+RENDERBUFFER_WIDTH             :: Enum(0x8D42)
+RENDERBUFFER_HEIGHT            :: Enum(0x8D43)
+RENDERBUFFER_INTERNAL_FORMAT   :: Enum(0x8D44)
+RENDERBUFFER_RED_SIZE          :: Enum(0x8D50)
+RENDERBUFFER_GREEN_SIZE        :: Enum(0x8D51)
+RENDERBUFFER_BLUE_SIZE         :: Enum(0x8D52)
+RENDERBUFFER_ALPHA_SIZE        :: Enum(0x8D53)
+RENDERBUFFER_DEPTH_SIZE        :: Enum(0x8D54)
+RENDERBUFFER_STENCIL_SIZE      :: Enum(0x8D55)
+
+FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           :: Enum(0x8CD0)
+FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           :: Enum(0x8CD1)
+FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         :: Enum(0x8CD2)
+FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE :: Enum(0x8CD3)
+
+COLOR_ATTACHMENT0              :: Enum(0x8CE0)
+DEPTH_ATTACHMENT               :: Enum(0x8D00)
+STENCIL_ATTACHMENT             :: Enum(0x8D20)
+DEPTH_STENCIL_ATTACHMENT       :: Enum(0x821A)
+
+NONE                           :: Enum(0)
+
+FRAMEBUFFER_COMPLETE                      :: Enum(0x8CD5)
+FRAMEBUFFER_INCOMPLETE_ATTACHMENT         :: Enum(0x8CD6)
+FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT :: Enum(0x8CD7)
+FRAMEBUFFER_INCOMPLETE_DIMENSIONS         :: Enum(0x8CD9)
+FRAMEBUFFER_UNSUPPORTED                   :: Enum(0x8CDD)
+
+FRAMEBUFFER_BINDING            :: Enum(0x8CA6)
+RENDERBUFFER_BINDING           :: Enum(0x8CA7)
+MAX_RENDERBUFFER_SIZE          :: Enum(0x84E8)
+
+INVALID_FRAMEBUFFER_OPERATION  :: Enum(0x0506)
+
+/* WebGL-specific enums */
+UNPACK_FLIP_Y_WEBGL            :: Enum(0x9240)
+UNPACK_PREMULTIPLY_ALPHA_WEBGL :: Enum(0x9241)
+CONTEXT_LOST_WEBGL             :: Enum(0x9242)
+UNPACK_COLORSPACE_CONVERSION_WEBGL :: Enum(0x9243)
+BROWSER_DEFAULT_WEBGL          :: Enum(0x9244)

+ 154 - 0
vendor/wasm/js/runtime.js

@@ -0,0 +1,154 @@
+class WasmMemoryInterface {
+	constructor() {	
+		this.memory = null;
+	}
+	
+	setMemory(memory) {
+		this.memory = memory;
+	}
+		
+	get mem() {
+		return new DataView(this.memory.buffer);
+	}
+	
+	
+	loadF32Array(addr, len) {
+		let array = new Float32Array(this.memory.buffer, addr, len);
+		return array;
+	}
+	loadU32Array(addr, len) {
+		let array = new Uint32Array(this.memory.buffer, addr, len);
+		return array;
+	}
+	loadI32Array(addr, len) {
+		let array = new Int32Array(this.memory.buffer, addr, len);
+		return array;
+	}
+	
+	
+	loadU8(addr) { return this.mem.getUint8  (addr, true); }
+	loadI8(addr) { return this.mem.getInt8   (addr, true); }
+	loadU16(addr) { return this.mem.getUint16 (addr, true); }
+	loadI16(addr) { return this.mem.getInt16  (addr, true); }
+	loadU32(addr) { return this.mem.getUint32 (addr, true); }
+	loadI32(addr) { return this.mem.getInt32  (addr, true); }
+	loadU64(addr) {
+		const lo = this.mem.getUint32(addr + 0, true);
+		const hi = this.mem.getUint32(addr + 4, true);
+		return lo + hi*4294967296;
+	};
+	loadI64(addr) {
+		// TODO(bill): loadI64 correctly
+		const lo = this.mem.getUint32(addr + 0, true);
+		const hi = this.mem.getUint32(addr + 4, true);
+		return lo + hi*4294967296;
+	};
+	loadF32(addr)  { return this.mem.getFloat32(addr, true); }
+	loadF64(addr)  { return this.mem.getFloat64(addr, true); }
+	loadInt(addr)  { return this.mem.getInt32  (addr, true); }
+	loadUint(addr) { return this.mem.getUint32 (addr, true); }
+	
+	loadPtr(addr) { return this.loadUint(addr); }
+	
+	loadBytes(ptr, len) {
+		return new Uint8Array(this.memory.buffer, ptr, len);
+	}
+	
+	loadString(ptr, len) {
+		const bytes = this.loadBytes(ptr, len);
+		return new TextDecoder("utf-8").decode(bytes);
+	}
+	
+	storeU8(addr, value)  { this.mem.setUint8  (addr, value, true); }
+	storeI8(addr, value)  { this.mem.setInt8   (addr, value, true); }
+	storeU16(addr, value) { this.mem.setUint16 (addr, value, true); }
+	storeI16(addr, value) { this.mem.setInt16  (addr, value, true); }
+	storeU32(addr, value) { this.mem.setUint32 (addr, value, true); }
+	storeI32(addr, value) { this.mem.setInt32  (addr, value, true); }
+	storeU64(addr, value) {
+		this.mem.setUint32(addr + 0, value, true);
+		this.mem.setUint32(addr + 4, Math.floor(value / 4294967296), true);
+	}
+	storeI64(addr, value) {
+		// TODO(bill): storeI64 correctly
+		this.mem.setUint32(addr + 0, value, true);
+		this.mem.setUint32(addr + 4, Math.floor(value / 4294967296), true);
+	}
+	storeF32(addr, value)  { this.mem.setFloat32(addr, value, true); }
+	storeF64(addr, value)  { this.mem.setFloat64(addr, value, true); }
+	storeInt(addr, value)  { this.mem.setInt32  (addr, value, true); }
+	storeUint(addr, value) { this.mem.setUint32 (addr, value, true); }
+};
+
+function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
+	const MAX_INFO_CONSOLE_LINES = 512;
+	let infoConsoleLines = new Array();
+	const addConsoleLine = (line) => {
+		if (line === undefined) {
+			return;
+		}
+		if (line.endsWith("\n")) {
+			line = line.substring(0, line.length-1);
+		} else if (infoConsoleLines.length > 0) {
+			let prev_line = infoConsoleLines.pop();
+			line = prev_line.concat(line);
+		}
+		infoConsoleLines.push(line);
+		
+		if (infoConsoleLines.length > MAX_INFO_CONSOLE_LINES) {
+			infoConsoleLines.shift();
+		}
+		
+		let data = "";
+		for (let i = 0; i < infoConsoleLines.length; i++) {
+			if (i != 0) {
+				data = data.concat("\n");
+			}
+			data = data.concat(infoConsoleLines[i]);
+		}
+		
+		if (consoleElement !== undefined) {
+			let info = consoleElement;
+			info.innerHTML = data;
+			info.scrollTop = info.scrollHeight;
+		}
+	};
+
+	return {
+		"env": {},
+		"odin_env": {
+			write: (fd, ptr, len) => {
+				const str = wasmMemoryInterface.loadString(ptr, len);
+				if (fd == 1) {
+					addConsoleLine(str);
+					return;
+				} else if (fd == 2) {
+					addConsoleLine(str);
+					return;
+				} else {
+					throw new Error("Invalid fd to 'write'" + stripNewline(str));
+				}
+			},
+			trap: () => { throw new Error() },
+			alert: (ptr, len) => { alert(wasmMemoryInterface.loadString(ptr, len)) },
+			abort: () => { Module.abort() },
+			evaluate: (str_ptr, str_len) => { eval.call(null, wasmMemoryInterface.loadString(str_ptr, str_len)); },
+			
+			time_now: () => {
+				return performance.now() * 1e6;
+			},
+			
+			sqrt:    (x) => Math.sqrt(x),
+			sin:     (x) => Math.sin(x),
+			cos:     (x) => Math.cos(x),
+			pow:     (x) => Math.pow(x),
+			fmuladd: (x, y, z) => x*y + z,
+			ln:      (x) => Math.log(x),
+			exp:     (x) => Math.exp(x),
+			ldexp:   (x) => Math.ldexp(x),
+		},
+	};
+}
+
+
+export {WasmMemoryInterface, odinSetupDefaultImports};