Browse Source

Begin work on Event System for js_wasm32 target

gingerBill 3 years ago
parent
commit
6f1cc3946b

+ 1 - 0
vendor/wasm/README.md

@@ -32,6 +32,7 @@ const runWasm = async (wasm_path, webglCanvasElement, consoleElement) => {
 	const file = await response.arrayBuffer();
 	const file = await response.arrayBuffer();
 	const wasm = await WebAssembly.instantiate(file, imports);
 	const wasm = await WebAssembly.instantiate(file, imports);
 	const exports = wasm.instance.exports;
 	const exports = wasm.instance.exports;
+	wasmMemoryInterface.setExports(exports);
 	wasmMemoryInterface.setMemory(exports.memory);
 	wasmMemoryInterface.setMemory(exports.memory);
 	
 	
 	exports._start();
 	exports._start();

+ 99 - 99
vendor/wasm/WebGL/runtime.js → vendor/wasm/WebGL/runtime.mjs

@@ -23,11 +23,11 @@ class WebGLInterface {
 		this.transformFeedbacks = [];
 		this.transformFeedbacks = [];
 		this.syncs              = [];
 		this.syncs              = [];
 		this.programInfos       = {};
 		this.programInfos       = {};
-		
+
 		if (contextSettings === undefined) {
 		if (contextSettings === undefined) {
 			contextSettings = {antialias: false};
 			contextSettings = {antialias: false};
 		}
 		}
-		
+
 		this.ctx = canvasElement.getContext("webgl2", contextSettings) || canvasElement.getContext("webgl", contextSettings);
 		this.ctx = canvasElement.getContext("webgl2", contextSettings) || canvasElement.getContext("webgl", contextSettings);
 		if (!this.ctx) {
 		if (!this.ctx) {
 			return;
 			return;
@@ -38,11 +38,11 @@ class WebGLInterface {
 			this.ctx_version = 1.0;
 			this.ctx_version = 1.0;
 		}
 		}
 	}
 	}
-	
+
 	get mem() {
 	get mem() {
 		return this.wasmMemoryInterface
 		return this.wasmMemoryInterface
 	}
 	}
-	
+
 	assertWebGL2() {
 	assertWebGL2() {
 		if (this.ctx_version < 2) {
 		if (this.ctx_version < 2) {
 			throw new Error("WebGL2 procedure called in a canvas without a WebGL2 context");
 			throw new Error("WebGL2 procedure called in a canvas without a WebGL2 context");
@@ -95,19 +95,19 @@ class WebGLInterface {
 		}
 		}
 		return source;
 		return source;
 	}
 	}
-	
+
 	getWebGL1Interface() {
 	getWebGL1Interface() {
 		return {
 		return {
 			DrawingBufferWidth:  () => this.ctx.drawingBufferWidth,
 			DrawingBufferWidth:  () => this.ctx.drawingBufferWidth,
 			DrawingBufferHeight: () => this.ctx.drawingBufferHeight,
 			DrawingBufferHeight: () => this.ctx.drawingBufferHeight,
-			
+
 			IsExtensionSupported: (name_ptr, name_len) => {
 			IsExtensionSupported: (name_ptr, name_len) => {
 				let name = this.mem.loadString(name_ptr, name_len);
 				let name = this.mem.loadString(name_ptr, name_len);
 				let extensions = this.ctx.getSupportedExtensions();
 				let extensions = this.ctx.getSupportedExtensions();
 				return extensions.indexOf(name) !== -1
 				return extensions.indexOf(name) !== -1
 			},
 			},
-			
-			
+
+
 			GetError: () => {
 			GetError: () => {
 				let err = this.lastError;
 				let err = this.lastError;
 				this.recordError(0);
 				this.recordError(0);
@@ -116,7 +116,7 @@ class WebGLInterface {
 				}
 				}
 				return this.ctx.getError();
 				return this.ctx.getError();
 			},
 			},
-			
+
 			GetWebGLVersion: (major_ptr, minor_ptr) => {
 			GetWebGLVersion: (major_ptr, minor_ptr) => {
 				let version = this.ctx.getParameter(0x1F02);
 				let version = this.ctx.getParameter(0x1F02);
 				if (version.indexOf("WebGL 2.0") !== -1) {
 				if (version.indexOf("WebGL 2.0") !== -1) {
@@ -124,7 +124,7 @@ class WebGLInterface {
 					this.mem.storeI32(minor_ptr, 0);
 					this.mem.storeI32(minor_ptr, 0);
 					return;
 					return;
 				}
 				}
-				
+
 				this.mem.storeI32(major_ptr, 1);
 				this.mem.storeI32(major_ptr, 1);
 				this.mem.storeI32(minor_ptr, 0);
 				this.mem.storeI32(minor_ptr, 0);
 			},
 			},
@@ -135,12 +135,12 @@ class WebGLInterface {
 					this.mem.storeI32(minor_ptr, 0);
 					this.mem.storeI32(minor_ptr, 0);
 					return;
 					return;
 				}
 				}
-				
+
 				this.mem.storeI32(major_ptr, 2);
 				this.mem.storeI32(major_ptr, 2);
 				this.mem.storeI32(minor_ptr, 0);
 				this.mem.storeI32(minor_ptr, 0);
 			},
 			},
-			
-			
+
+
 			ActiveTexture: (x) => {
 			ActiveTexture: (x) => {
 				this.ctx.activeTexture(x);
 				this.ctx.activeTexture(x);
 			},
 			},
@@ -180,8 +180,8 @@ class WebGLInterface {
 			BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => {
 			BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => {
 				this.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
 				this.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
 			},
 			},
-			
-			
+
+
 			BufferData: (target, size, data, usage) => {
 			BufferData: (target, size, data, usage) => {
 				if (data) {
 				if (data) {
 					this.ctx.bufferData(target, this.mem.loadBytes(data, size), usage);
 					this.ctx.bufferData(target, this.mem.loadBytes(data, size), usage);
@@ -196,8 +196,8 @@ class WebGLInterface {
 					this.ctx.bufferSubData(target, offset, null);
 					this.ctx.bufferSubData(target, offset, null);
 				}
 				}
 			},
 			},
-			
-			
+
+
 			Clear: (x) => {
 			Clear: (x) => {
 				this.ctx.clear(x);
 				this.ctx.clear(x);
 			},
 			},
@@ -216,8 +216,8 @@ class WebGLInterface {
 			CompileShader: (shader) => {
 			CompileShader: (shader) => {
 				this.ctx.compileShader(this.shaders[shader]);
 				this.ctx.compileShader(this.shaders[shader]);
 			},
 			},
-			
-			
+
+
 			CompressedTexImage2D: (target, level, internalformat, width, height, border, imageSize, data) => {
 			CompressedTexImage2D: (target, level, internalformat, width, height, border, imageSize, data) => {
 				if (data) {
 				if (data) {
 					this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, this.mem.loadBytes(data, imageSize));
 					this.ctx.compressedTexImage2D(target, level, internalformat, width, height, border, this.mem.loadBytes(data, imageSize));
@@ -232,15 +232,15 @@ class WebGLInterface {
 					this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, null);
 					this.ctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, null);
 				}
 				}
 			},
 			},
-			
+
 			CopyTexImage2D: (target, level, internalformat, x, y, width, height, border) => {
 			CopyTexImage2D: (target, level, internalformat, x, y, width, height, border) => {
 				this.ctx.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) => {
 			CopyTexSubImage2D: (target, level, xoffset, yoffset, x, y, width, height) => {
 				this.ctx.copyTexImage2D(target, level, xoffset, yoffset, x, y, width, height);
 				this.ctx.copyTexImage2D(target, level, xoffset, yoffset, x, y, width, height);
 			},
 			},
-			
-			
+
+
 			CreateBuffer: () => {
 			CreateBuffer: () => {
 				let buffer = this.ctx.createBuffer();
 				let buffer = this.ctx.createBuffer();
 				if (!buffer) {
 				if (!buffer) {
@@ -291,13 +291,13 @@ class WebGLInterface {
 				this.textures[id] = texture;
 				this.textures[id] = texture;
 				return id;
 				return id;
 			},
 			},
-			
-			
+
+
 			CullFace: (mode) => {
 			CullFace: (mode) => {
 				this.ctx.cullFace(mode);
 				this.ctx.cullFace(mode);
 			},
 			},
-			
-			
+
+
 			DeleteBuffer: (id) => {
 			DeleteBuffer: (id) => {
 				let obj = this.buffers[id];
 				let obj = this.buffers[id];
 				if (obj && id != 0) {
 				if (obj && id != 0) {
@@ -366,8 +366,8 @@ class WebGLInterface {
 			DrawElements: (mode, count, type, indices) => {
 			DrawElements: (mode, count, type, indices) => {
 				this.ctx.drawElements(mode, count, type, indices);
 				this.ctx.drawElements(mode, count, type, indices);
 			},
 			},
-			
-			
+
+
 			Enable: (cap) => {
 			Enable: (cap) => {
 				this.ctx.enable(cap);
 				this.ctx.enable(cap);
 			},
 			},
@@ -389,20 +389,20 @@ class WebGLInterface {
 			FrontFace: (mode) => {
 			FrontFace: (mode) => {
 				this.ctx.frontFace(mode);
 				this.ctx.frontFace(mode);
 			},
 			},
-			
-				
+
+
 			GenerateMipmap: (target) => {
 			GenerateMipmap: (target) => {
 				this.ctx.generateMipmap(target);
 				this.ctx.generateMipmap(target);
 			},
 			},
-			
-			
+
+
 			GetAttribLocation: (program, name_ptr, name_len) => {
 			GetAttribLocation: (program, name_ptr, name_len) => {
 				let name = this.mem.loadString(name_ptr, name_len);
 				let name = this.mem.loadString(name_ptr, name_len);
 				return this.ctx.getAttribLocation(this.programs[program], name);
 				return this.ctx.getAttribLocation(this.programs[program], name);
 			},
 			},
-			
-			
-			
+
+
+
 			GetProgramParameter: (program, pname) => {
 			GetProgramParameter: (program, pname) => {
 				return this.ctx.getProgramParameter(this.programs[program], pname)
 				return this.ctx.getProgramParameter(this.programs[program], pname)
 			},
 			},
@@ -415,7 +415,7 @@ class WebGLInterface {
 					let n = Math.min(buf_len, log.length);
 					let n = Math.min(buf_len, log.length);
 					log = log.substring(0, n);
 					log = log.substring(0, n);
 					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
 					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
-					
+
 					this.mem.storeInt(length_ptr, n);
 					this.mem.storeInt(length_ptr, n);
 				}
 				}
 			},
 			},
@@ -428,7 +428,7 @@ class WebGLInterface {
 					let n = Math.min(buf_len, log.length);
 					let n = Math.min(buf_len, log.length);
 					log = log.substring(0, n);
 					log = log.substring(0, n);
 					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
 					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log))
-					
+
 					this.mem.storeInt(length_ptr, n);
 					this.mem.storeInt(length_ptr, n);
 				}
 				}
 			},
 			},
@@ -452,8 +452,8 @@ class WebGLInterface {
 					this.recordError(1281);
 					this.recordError(1281);
 				}
 				}
 			},
 			},
-			
-			
+
+
 			GetUniformLocation: (program, name_ptr, name_len) => {
 			GetUniformLocation: (program, name_ptr, name_len) => {
 				let name = this.mem.loadString(name_ptr, name_len);
 				let name = this.mem.loadString(name_ptr, name_len);
 				let arrayOffset = 0;
 				let arrayOffset = 0;
@@ -472,18 +472,18 @@ class WebGLInterface {
 				var uniformInfo = ptable.uniforms[name];
 				var uniformInfo = ptable.uniforms[name];
 				return (uniformInfo && arrayOffset < uniformInfo[0]) ? uniformInfo[1] + arrayOffset : -1
 				return (uniformInfo && arrayOffset < uniformInfo[0]) ? uniformInfo[1] + arrayOffset : -1
 			},
 			},
-			
-			
+
+
 			GetVertexAttribOffset: (index, pname) => {
 			GetVertexAttribOffset: (index, pname) => {
 				return this.ctx.getVertexAttribOffset(index, pname);
 				return this.ctx.getVertexAttribOffset(index, pname);
 			},
 			},
-			
-			
+
+
 			Hint: (target, mode) => {
 			Hint: (target, mode) => {
 				this.ctx.hint(target, mode);
 				this.ctx.hint(target, mode);
 			},
 			},
-			
-			
+
+
 			IsBuffer:       (buffer)       => this.ctx.isBuffer(this.buffers[buffer]),
 			IsBuffer:       (buffer)       => this.ctx.isBuffer(this.buffers[buffer]),
 			IsEnabled:      (enabled)      => this.ctx.isEnabled(this.enableds[enabled]),
 			IsEnabled:      (enabled)      => this.ctx.isEnabled(this.enableds[enabled]),
 			IsFramebuffer:  (framebuffer)  => this.ctx.isFramebuffer(this.framebuffers[framebuffer]),
 			IsFramebuffer:  (framebuffer)  => this.ctx.isFramebuffer(this.framebuffers[framebuffer]),
@@ -491,7 +491,7 @@ class WebGLInterface {
 			IsRenderbuffer: (renderbuffer) => this.ctx.isRenderbuffer(this.renderbuffers[renderbuffer]),
 			IsRenderbuffer: (renderbuffer) => this.ctx.isRenderbuffer(this.renderbuffers[renderbuffer]),
 			IsShader:       (shader)       => this.ctx.isShader(this.shaders[shader]),
 			IsShader:       (shader)       => this.ctx.isShader(this.shaders[shader]),
 			IsTexture:      (texture)      => this.ctx.isTexture(this.textures[texture]),
 			IsTexture:      (texture)      => this.ctx.isTexture(this.textures[texture]),
-			
+
 			LineWidth: (width) => {
 			LineWidth: (width) => {
 				this.ctx.lineWidth(width);
 				this.ctx.lineWidth(width);
 			},
 			},
@@ -506,8 +506,8 @@ class WebGLInterface {
 			PolygonOffset: (factor, units) => {
 			PolygonOffset: (factor, units) => {
 				this.ctx.polygonOffset(factor, units);
 				this.ctx.polygonOffset(factor, units);
 			},
 			},
-			
-			
+
+
 			ReadnPixels: (x, y, width, height, format, type, bufSize, data) => {
 			ReadnPixels: (x, y, width, height, format, type, bufSize, data) => {
 				this.ctx.readPixels(x, y, width, format, type, this.mem.loadBytes(data, bufSize));
 				this.ctx.readPixels(x, y, width, format, type, this.mem.loadBytes(data, bufSize));
 			},
 			},
@@ -524,7 +524,7 @@ class WebGLInterface {
 				let source = this.getSource(shader, strings_ptr, strings_length);
 				let source = this.getSource(shader, strings_ptr, strings_length);
 				this.ctx.shaderSource(this.shaders[shader], source);
 				this.ctx.shaderSource(this.shaders[shader], source);
 			},
 			},
-			
+
 			StencilFunc: (func, ref, mask) => {
 			StencilFunc: (func, ref, mask) => {
 				this.ctx.stencilFunc(func, ref, mask);
 				this.ctx.stencilFunc(func, ref, mask);
 			},
 			},
@@ -543,8 +543,8 @@ class WebGLInterface {
 			StencilOpSeparate: (face, fail, zfail, zpass) => {
 			StencilOpSeparate: (face, fail, zfail, zpass) => {
 				this.ctx.stencilOpSeparate(face, fail, zfail, zpass);
 				this.ctx.stencilOpSeparate(face, fail, zfail, zpass);
 			},
 			},
-			
-			
+
+
 			TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
 			TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
 				if (data) {
 				if (data) {
 					this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size));
 					this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size));
@@ -561,18 +561,18 @@ class WebGLInterface {
 			TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => {
 			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));
 				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);             },
 			Uniform1f: (location, v0)             => { this.ctx.uniform1f(this.uniforms[location], v0);             },
 			Uniform2f: (location, v0, v1)         => { this.ctx.uniform2f(this.uniforms[location], v0, v1);         },
 			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);     },
 			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); },
 			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);             },
 			Uniform1i: (location, v0)             => { this.ctx.uniform1i(this.uniforms[location], v0);             },
 			Uniform2i: (location, v0, v1)         => { this.ctx.uniform2i(this.uniforms[location], v0, v1);         },
 			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);     },
 			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); },
 			Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
-			
+
 			UniformMatrix2fv: (location, addr) => {
 			UniformMatrix2fv: (location, addr) => {
 				let array = this.mem.loadF32Array(addr, 2*2);
 				let array = this.mem.loadF32Array(addr, 2*2);
 				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
 				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
@@ -585,15 +585,15 @@ class WebGLInterface {
 				let array = this.mem.loadF32Array(addr, 4*4);
 				let array = this.mem.loadF32Array(addr, 4*4);
 				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
 				this.ctx.uniformMatrix4fv(this.uniforms[location], false, array);
 			},
 			},
-			
+
 			UseProgram: (program) => {
 			UseProgram: (program) => {
-				this.ctx.useProgram(this.programs[program]);
+				if (program) this.ctx.useProgram(this.programs[program]);
 			},
 			},
 			ValidateProgram: (program) => {
 			ValidateProgram: (program) => {
-				this.ctx.validateProgram(this.programs[program]);
+				if (program) this.ctx.validateProgram(this.programs[program]);
 			},
 			},
-			
-			
+
+
 			VertexAttrib1f: (index, x) => {
 			VertexAttrib1f: (index, x) => {
 				this.ctx.vertexAttrib1f(index, x);
 				this.ctx.vertexAttrib1f(index, x);
 			},
 			},
@@ -609,13 +609,13 @@ class WebGLInterface {
 			VertexAttribPointer: (index, size, type, normalized, stride, ptr) => {
 			VertexAttribPointer: (index, size, type, normalized, stride, ptr) => {
 				this.ctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
 				this.ctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr);
 			},
 			},
-			
+
 			Viewport: (x, y, w, h) => {
 			Viewport: (x, y, w, h) => {
 				this.ctx.viewport(x, y, w, h);
 				this.ctx.viewport(x, y, w, h);
 			},
 			},
 		};
 		};
 	}
 	}
-	
+
 	getWebGL2Interface() {
 	getWebGL2Interface() {
 		return {
 		return {
 			/* Buffer objects */
 			/* Buffer objects */
@@ -627,7 +627,7 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.getBufferSubData(target, srcByteOffset, this.mem.loadBytes(dst_buffer_ptr, dst_buffer_len), dstOffset, length);
 				this.ctx.getBufferSubData(target, srcByteOffset, this.mem.loadBytes(dst_buffer_ptr, dst_buffer_len), dstOffset, length);
 			},
 			},
-			
+
 			/* Framebuffer objects */
 			/* Framebuffer objects */
 			BlitFramebuffer: (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) => {
 			BlitFramebuffer: (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -642,7 +642,7 @@ class WebGLInterface {
 				let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
 				let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
 				this.ctx.invalidateFramebuffer(target, attachments);
 				this.ctx.invalidateFramebuffer(target, attachments);
 			},
 			},
-			InvalidateSubFramebuffer: (target, attachments_ptr, attachments_len, x, y, width, height) => {	
+			InvalidateSubFramebuffer: (target, attachments_ptr, attachments_len, x, y, width, height) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
 				let attachments = this.mem.loadU32Array(attachments_ptr, attachments_len);
 				this.ctx.invalidateSubFramebuffer(target, attachments, x, y, width, height);
 				this.ctx.invalidateSubFramebuffer(target, attachments, x, y, width, height);
@@ -651,15 +651,15 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.readBuffer(src);
 				this.ctx.readBuffer(src);
 			},
 			},
-			
+
 			/* Renderbuffer objects */
 			/* Renderbuffer objects */
 			RenderbufferStorageMultisample: (target, samples, internalformat, width, height) => {
 			RenderbufferStorageMultisample: (target, samples, internalformat, width, height) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.renderbufferStorageMultisample(target, samples, internalformat, width, height);
 				this.ctx.renderbufferStorageMultisample(target, samples, internalformat, width, height);
 			},
 			},
-			
+
 			/* Texture objects */
 			/* Texture objects */
-			
+
 			TexStorage3D: (target, levels, internalformat, width, height, depth) => {
 			TexStorage3D: (target, levels, internalformat, width, height, depth) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.texStorage3D(target, level, internalformat, width, heigh, depth);
 				this.ctx.texStorage3D(target, level, internalformat, width, heigh, depth);
@@ -692,18 +692,18 @@ class WebGLInterface {
 					this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, null);
 					this.ctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, null);
 				}
 				}
 			},
 			},
-			
+
 			CopyTexSubImage3D: (target, level, xoffset, yoffset, zoffset, x, y, width, height) => {
 			CopyTexSubImage3D: (target, level, xoffset, yoffset, zoffset, x, y, width, height) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.copyTexImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
 				this.ctx.copyTexImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
 			},
 			},
-			
+
 			/* Programs and shaders */
 			/* Programs and shaders */
 			GetFragDataLocation: (program, name_ptr, name_len) => {
 			GetFragDataLocation: (program, name_ptr, name_len) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				return this.ctx.getFragDataLocation(this.programs[program], this.mem.loadString(name_ptr, name_len));
 				return this.ctx.getFragDataLocation(this.programs[program], this.mem.loadString(name_ptr, name_len));
 			},
 			},
-			
+
 			/* Uniforms */
 			/* Uniforms */
 			Uniform1ui: (location, v0) => {
 			Uniform1ui: (location, v0) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -721,7 +721,7 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.uniform4ui(this.uniforms[location], v0, v1, v2, v3);
 				this.ctx.uniform4ui(this.uniforms[location], v0, v1, v2, v3);
 			},
 			},
-			
+
 			UniformMatrix3x2fv: (location, addr) => {
 			UniformMatrix3x2fv: (location, addr) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				let array = this.mem.loadF32Array(addr, 3*2);
 				let array = this.mem.loadF32Array(addr, 3*2);
@@ -752,21 +752,21 @@ class WebGLInterface {
 				let array = this.mem.loadF32Array(addr, 3*4);
 				let array = this.mem.loadF32Array(addr, 3*4);
 				this.ctx.uniformMatrix3x4fv(this.uniforms[location], false, array);
 				this.ctx.uniformMatrix3x4fv(this.uniforms[location], false, array);
 			},
 			},
-			
+
 			/* Vertex attribs */
 			/* Vertex attribs */
 			VertexAttribI4i: (index, x, y, z, w) => {
 			VertexAttribI4i: (index, x, y, z, w) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.vertexAttribI4i(index, x, y, z, w);
 				this.ctx.vertexAttribI4i(index, x, y, z, w);
-			}, 
+			},
 			VertexAttribI4ui: (index, x, y, z, w) => {
 			VertexAttribI4ui: (index, x, y, z, w) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.vertexAttribI4ui(index, x, y, z, w);
 				this.ctx.vertexAttribI4ui(index, x, y, z, w);
-			}, 
+			},
 			VertexAttribIPointer: (index, size, type, stride, offset) => {
 			VertexAttribIPointer: (index, size, type, stride, offset) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.vertexAttribIPointer(index, size, type, stride, offset);
 				this.ctx.vertexAttribIPointer(index, size, type, stride, offset);
-			}, 
-			
+			},
+
 			/* Writing to the drawing buffer */
 			/* Writing to the drawing buffer */
 			VertexAttribDivisor: (index, divisor) => {
 			VertexAttribDivisor: (index, divisor) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -818,7 +818,7 @@ class WebGLInterface {
 				let id = this.getNewId(this.queries);
 				let id = this.getNewId(this.queries);
 				query.name = id;
 				query.name = id;
 				this.queries[id] = query;
 				this.queries[id] = query;
-				return id;	
+				return id;
 			},
 			},
 			DeleteQuery: (id) => {
 			DeleteQuery: (id) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -829,7 +829,7 @@ class WebGLInterface {
 				}
 				}
 			},
 			},
 			IsQuery: (query) => {
 			IsQuery: (query) => {
-				this.assertWebGL2();	
+				this.assertWebGL2();
 				return this.ctx.isQuery(this.queries[query]);
 				return this.ctx.isQuery(this.queries[query]);
 			},
 			},
 			BeginQuery: (target, query) => {
 			BeginQuery: (target, query) => {
@@ -852,9 +852,9 @@ class WebGLInterface {
 				let id = this.getNewId(this.queries);
 				let id = this.getNewId(this.queries);
 				query.name = id;
 				query.name = id;
 				this.queries[id] = query;
 				this.queries[id] = query;
-				return id;	
+				return id;
 			},
 			},
-			
+
 			/* Sampler Objects */
 			/* Sampler Objects */
 			CreateSampler: () => {
 			CreateSampler: () => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -862,7 +862,7 @@ class WebGLInterface {
 				let id = this.getNewId(this.samplers);
 				let id = this.getNewId(this.samplers);
 				sampler.name = id;
 				sampler.name = id;
 				this.samplers[id] = sampler;
 				this.samplers[id] = sampler;
-				return id;	
+				return id;
 			},
 			},
 			DeleteSampler: (id) => {
 			DeleteSampler: (id) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -873,11 +873,11 @@ class WebGLInterface {
 				}
 				}
 			},
 			},
 			IsSampler: (sampler) => {
 			IsSampler: (sampler) => {
-				this.assertWebGL2();	
+				this.assertWebGL2();
 				return this.ctx.isSampler(this.samplers[sampler]);
 				return this.ctx.isSampler(this.samplers[sampler]);
 			},
 			},
 			BindSampler: (unit, sampler) => {
 			BindSampler: (unit, sampler) => {
-				this.assertWebGL2();	
+				this.assertWebGL2();
 				this.ctx.bindSampler(unit, this.samplers[Sampler]);
 				this.ctx.bindSampler(unit, this.samplers[Sampler]);
 			},
 			},
 			SamplerParameteri: (sampler, pname, param) => {
 			SamplerParameteri: (sampler, pname, param) => {
@@ -888,7 +888,7 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.samplerParameterf(this.samplers[sampler], pname, param);
 				this.ctx.samplerParameterf(this.samplers[sampler], pname, param);
 			},
 			},
-			
+
 			/* Sync objects */
 			/* Sync objects */
 			FenceSync: (condition, flags) => {
 			FenceSync: (condition, flags) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -896,10 +896,10 @@ class WebGLInterface {
 				let id = this.getNewId(this.syncs);
 				let id = this.getNewId(this.syncs);
 				sync.name = id;
 				sync.name = id;
 				this.syncs[id] = sync;
 				this.syncs[id] = sync;
-				return id;	
+				return id;
 			},
 			},
 			IsSync: (sync) => {
 			IsSync: (sync) => {
-				this.assertWebGL2();	
+				this.assertWebGL2();
 				return this.ctx.isSync(this.syncs[sync]);
 				return this.ctx.isSync(this.syncs[sync]);
 			},
 			},
 			DeleteSync: (id) => {
 			DeleteSync: (id) => {
@@ -908,7 +908,7 @@ class WebGLInterface {
 				if (obj && id != 0) {
 				if (obj && id != 0) {
 					this.ctx.deleteSampler(obj);
 					this.ctx.deleteSampler(obj);
 					this.syncs[id] = null;
 					this.syncs[id] = null;
-				}	
+				}
 			},
 			},
 			ClientWaitSync: (sync, flags, timeout) => {
 			ClientWaitSync: (sync, flags, timeout) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -918,8 +918,8 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.waitSync(this.syncs[sync], flags, timeout)	;
 				this.ctx.waitSync(this.syncs[sync], flags, timeout)	;
 			},
 			},
-			
-			
+
+
 			/* Transform Feedback */
 			/* Transform Feedback */
 			CreateTransformFeedback: () => {
 			CreateTransformFeedback: () => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -927,7 +927,7 @@ class WebGLInterface {
 				let id = this.getNewId(this.transformFeedbacks);
 				let id = this.getNewId(this.transformFeedbacks);
 				transformFeedback.name = id;
 				transformFeedback.name = id;
 				this.transformFeedbacks[id] = transformFeedback;
 				this.transformFeedbacks[id] = transformFeedback;
-				return id;	
+				return id;
 			},
 			},
 			DeleteTransformFeedback: (id)  => {
 			DeleteTransformFeedback: (id)  => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -935,7 +935,7 @@ class WebGLInterface {
 				if (obj && id != 0) {
 				if (obj && id != 0) {
 					this.ctx.deleteTransformFeedback(obj);
 					this.ctx.deleteTransformFeedback(obj);
 					this.transformFeedbacks[id] = null;
 					this.transformFeedbacks[id] = null;
-				}	
+				}
 			},
 			},
 			IsTransformFeedback: (tf) => {
 			IsTransformFeedback: (tf) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -971,8 +971,8 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.resumeTransformFeedback();
 				this.ctx.resumeTransformFeedback();
 			},
 			},
-			
-			
+
+
 			/* Uniform Buffer Objects and Transform Feedback Buffers */
 			/* Uniform Buffer Objects and Transform Feedback Buffers */
 			BindBufferBase: (target, index, buffer) => {
 			BindBufferBase: (target, index, buffer) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -990,7 +990,7 @@ class WebGLInterface {
 			GetActiveUniformBlockName: (program, uniformBlockIndex, buf_ptr, buf_len, length_ptr) => {
 			GetActiveUniformBlockName: (program, uniformBlockIndex, buf_ptr, buf_len, length_ptr) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex);
 				let name = this.ctx.getActiveUniformBlockName(this.programs[program], uniformBlockIndex);
-				
+
 				let n = Math.min(buf_len, name.length);
 				let n = Math.min(buf_len, name.length);
 				name = name.substring(0, n);
 				name = name.substring(0, n);
 				this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(name))
 				this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(name))
@@ -1000,7 +1000,7 @@ class WebGLInterface {
 				this.assertWebGL2();
 				this.assertWebGL2();
 				this.ctx.uniformBlockBinding(this.programs[program], uniformBlockIndex, uniformBlockBinding);
 				this.ctx.uniformBlockBinding(this.programs[program], uniformBlockIndex, uniformBlockBinding);
 			},
 			},
-			
+
 			/* Vertex Array Objects */
 			/* Vertex Array Objects */
 			CreateVertexArray: () => {
 			CreateVertexArray: () => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -1008,7 +1008,7 @@ class WebGLInterface {
 				let id = this.getNewId(this.vaos);
 				let id = this.getNewId(this.vaos);
 				vao.name = id;
 				vao.name = id;
 				this.vaos[id] = vao;
 				this.vaos[id] = vao;
-				return id;	
+				return id;
 			},
 			},
 			DeleteVertexArray: (id) => {
 			DeleteVertexArray: (id) => {
 				this.assertWebGL2();
 				this.assertWebGL2();
@@ -1019,11 +1019,11 @@ class WebGLInterface {
 				}
 				}
 			},
 			},
 			IsVertexArray: (vertexArray) => {
 			IsVertexArray: (vertexArray) => {
-				this.assertWebGL2();	
+				this.assertWebGL2();
 				return this.ctx.isVertexArray(this.vaos[vertexArray]);
 				return this.ctx.isVertexArray(this.vaos[vertexArray]);
 			},
 			},
 			BindVertexArray: (vertexArray) => {
 			BindVertexArray: (vertexArray) => {
-				this.assertWebGL2();	
+				this.assertWebGL2();
 				this.ctx.bindVertexArray(this.vaos[vertexArray]);
 				this.ctx.bindVertexArray(this.vaos[vertexArray]);
 			},
 			},
 		};
 		};
@@ -1031,4 +1031,4 @@ class WebGLInterface {
 };
 };
 
 
 
 
-export {WebGLInterface};
+export {WebGLInterface};

+ 22 - 0
vendor/wasm/js/dom.odin

@@ -0,0 +1,22 @@
+//+build js wasm32
+package wasm_js_interface
+
+foreign import dom_lib "odin_dom"
+
+@(default_calling_convention="contextless")
+foreign dom_lib {
+	get_element_value_f64    :: proc(id: string) -> f64 ---
+	get_element_min_max      :: proc(id: string) -> (min, max: f64) ---
+	set_element_value        :: proc(id: string, value: f64) ---
+}
+
+get_element_value_string :: proc(id: string, buf: []byte) -> string {
+	@(default_calling_convention="contextless")
+	foreign dom_lib {
+		@(link_name="get_element_value_string")
+		_get_element_value_string :: proc(id: string, buf: []byte) -> int ---
+	}
+	n := _get_element_value_string(id, buf)
+	return string(buf[:n])
+
+}

+ 320 - 0
vendor/wasm/js/events.odin

@@ -0,0 +1,320 @@
+//+build js wasm32
+package wasm_js_interface
+
+foreign import dom_lib "odin_dom"
+
+Event_Kind :: enum u32 {
+	Invalid,
+
+	Load,
+	Unload,
+	Error,
+	Resize,
+	Visibility_Change,
+	Fullscreen_Change,
+	Fullscreen_Error,
+
+	Click,
+	Double_Click,
+	Mouse_Move,
+	Mouse_Over,
+	Mouse_Out,
+	Mouse_Up,
+	Mouse_Down,
+
+	Key_Up,
+	Key_Down,
+	Key_Press,
+
+	Scroll,
+	Wheel,
+
+	Focus,
+	Submit,
+	Blur,
+	Change,
+	Select,
+
+	Animation_Start,
+	Animation_End,
+	Animation_Iteration,
+	Animation_Cancel,
+
+	Copy,
+	Cut,
+	Paste,
+
+	// Drag,
+	// Drag_Start,
+	// Drag_End,
+	// Drag_Enter,
+	// Drag_Leave,
+	// Drag_Over,
+	// Drop,
+
+	Pointer_Cancel,
+	Pointer_Down,
+	Pointer_Enter,
+	Pointer_Leave,
+	Pointer_Move,
+	Pointer_Over,
+	Pointer_Up,
+	Got_Pointer_Capture,
+	Lost_Pointer_Capture,
+	Pointer_Lock_Change,
+	Pointer_Lock_Error,
+
+	Selection_Change,
+	Selection_Start,
+
+	Touch_Cancel,
+	Touch_End,
+	Touch_Move,
+	Touch_Start,
+
+	Transition_Start,
+	Transition_End,
+	Transition_Run,
+	Transition_Cancel,
+
+}
+event_kind_string := [Event_Kind]string{
+	.Invalid = "",
+
+	.Load         = "load",
+	.Unload       = "unload",
+	.Error        = "error",
+	.Resize       = "resize",
+	.Visibility_Change = "visibilitychange",
+	.Fullscreen_Change = "fullscreenchange",
+	.Fullscreen_Error  = "fullscreenerror",
+
+	.Click        = "click",
+	.Double_Click = "dblclick",
+	.Mouse_Move   = "mousemove",
+	.Mouse_Over   = "mouseover",
+	.Mouse_Out    = "mouseout",
+	.Mouse_Up     = "mouseup",
+	.Mouse_Down   = "mousedown",
+
+	.Key_Up       = "keyup",
+	.Key_Down     = "keydown",
+	.Key_Press    = "keypress",
+
+	.Scroll = "scroll",
+	.Wheel = "wheel",
+
+	.Focus        = "focus",
+	.Submit       = "submit",
+	.Blur         = "blur",
+	.Change       = "change",
+	.Select       = "select",
+
+	.Animation_Start     = "animationstart",
+	.Animation_End       = "animationend",
+	.Animation_Iteration = "animationiteration",
+	.Animation_Cancel    = "animationcancel",
+
+	.Copy   = "copy",
+	.Cut    = "cut",
+	.Paste  = "paste",
+
+	// .Drag,       = "drag",
+	// .Drag_Start, = "dragstart",
+	// .Drag_End,   = "dragend",
+	// .Drag_Enter, = "dragenter",
+	// .Drag_Leave, = "dragleave",
+	// .Drag_Over,  = "dragover",
+	// .Drop,       = "drop",
+
+	.Pointer_Cancel       = "pointercancel",
+	.Pointer_Down         = "pointerdown",
+	.Pointer_Enter        = "pointerenter",
+	.Pointer_Leave        = "pointerleave",
+	.Pointer_Move         = "pointermove",
+	.Pointer_Over         = "pointerover",
+	.Pointer_Up           = "pointerup",
+	.Got_Pointer_Capture  = "gotpointercapture",
+	.Lost_Pointer_Capture = "lostpointercapture",
+	.Pointer_Lock_Change  = "pointerlockchange",
+	.Pointer_Lock_Error   = "pointerlockerror",
+
+	.Selection_Change = "selectionchange",
+	.Selection_Start  = "selectionstart",
+
+	.Transition_Start  = "transitionstart",
+	.Transition_End    = "transitionend",
+	.Transition_Run    = "transitionrun",
+	.Transition_Cancel = "transitioncancel",
+
+	.Touch_Cancel = "touchcancel",
+	.Touch_End    = "touchend",
+	.Touch_Move   = "touchmove",
+	.Touch_Start  = "touchstart",
+}
+
+Delta_Mode :: enum u32 {
+	Pixel = 0,
+	Line  = 1,
+	Page  = 2,
+}
+
+Key_Location :: enum u8 {
+	Standard = 0,
+	Left     = 1,
+	Right    = 2,
+	Numpad   = 3,
+}
+
+KEYBOARD_MAX_KEY_SIZE :: 16
+KEYBOARD_MAX_CODE_SIZE :: 16
+
+Event_Target_Kind :: enum u32 {
+	Element  = 0,
+	Document = 1,
+	Window   = 2,
+}
+
+Event_Phase :: enum u8 {
+	None            = 0,
+	Capturing_Phase = 1,
+	At_Target       = 2,
+	Bubbling_Phase  = 3,
+}
+
+
+Event :: struct {
+	kind:                 Event_Kind,
+	target_kind:          Event_Target_Kind,
+	current_target_kind:  Event_Target_Kind,
+	id:           string,
+	timestamp:    f64,
+
+	phase:        Event_Phase,
+	bubbles:      bool,
+	cancelable:   bool,
+	composed:     bool,
+	is_composing: bool,
+	is_trusted:   bool,
+
+	using data: struct #raw_union #align 8 {
+		scroll: struct {
+			delta: [2]f64,
+		},
+		visibility_change: struct {
+			is_visible: bool,
+		},
+		wheel: struct {
+			delta: [3]f64,
+			delta_mode: Delta_Mode,
+		},
+
+		key: struct {
+			key:  string,
+			code: string,
+			location: Key_Location,
+
+			ctrl:   bool,
+			shift:  bool,
+			alt:    bool,
+			meta:   bool,
+
+			repeat: bool,
+
+			_key_buf:  [KEYBOARD_MAX_KEY_SIZE]byte,
+			_code_buf: [KEYBOARD_MAX_KEY_SIZE]byte,
+		},
+
+		mouse: struct {
+			screen:    [2]i64,
+			client:    [2]i64,
+			offset:    [2]i64,
+			page:      [2]i64,
+			movement:  [2]i64,
+			using pos: [2]i64,
+
+			ctrl:   bool,
+			shift:  bool,
+			alt:    bool,
+			meta:   bool,
+
+			button:  i16,
+			buttons: bit_set[0..<16; u16],
+		},
+	},
+
+
+	user_data: rawptr,
+	callback: proc(e: Event),
+}
+
+@(default_calling_convention="contextless")
+foreign dom_lib {
+	event_stop_propagation           :: proc() ---
+	event_stop_immediate_propagation :: proc() ---
+	event_prevent_default            :: proc() ---
+}
+
+add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
+	@(default_calling_convention="contextless")
+	foreign dom_lib {
+		@(link_name="add_event_listener")
+		_add_event_listener :: proc(id: string, name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
+	}
+	// TODO: Pointer_Lock_Change etc related stuff for all different browsers
+	return _add_event_listener(id, event_kind_string[kind], kind, user_data, callback, use_capture)
+}
+
+remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
+	@(default_calling_convention="contextless")
+	foreign dom_lib {
+		@(link_name="remove_event_listener")
+		_remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool ---
+	}
+	return _remove_event_listener(id, event_kind_string[kind], user_data, callback)
+}
+
+add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
+	@(default_calling_convention="contextless")
+	foreign dom_lib {
+		@(link_name="add_window_event_listener")
+		_add_window_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
+	}
+	return _add_window_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture)
+}
+
+remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool {
+	@(default_calling_convention="contextless")
+	foreign dom_lib {
+		@(link_name="remove_window_event_listener")
+		_remove_window_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool ---
+	}
+	return _remove_window_event_listener(event_kind_string[kind], user_data, callback)
+}
+
+remove_event_listener_from_event :: proc(e: Event) -> bool {
+	if e.id == "" {
+		return remove_window_event_listener(e.kind, e.user_data, e.callback)
+	}
+	return remove_event_listener(e.id, e.kind, e.user_data, e.callback)
+}
+
+
+
+
+@(export, link_name="odin_dom_do_event_callback")
+do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) {
+	@(default_calling_convention="contextless")
+	foreign dom_lib {
+		init_event_raw :: proc(e: ^Event) ---
+	}
+
+	if callback != nil {
+		event := Event{
+			user_data = user_data,
+			callback  = callback,
+		}
+		init_event_raw(&event)
+		callback(event)
+	}
+}

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

@@ -1,154 +0,0 @@
-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};

+ 372 - 0
vendor/wasm/js/runtime.mjs

@@ -0,0 +1,372 @@
+class WasmMemoryInterface {
+	constructor() {
+		this.memory = null;
+		this.exports = null;
+	}
+
+	setMemory(memory) {
+		this.memory = memory;
+	}
+
+	setExports(exports) {
+		this.exports = exports;
+		this.listenerMap = {};
+	}
+
+	get mem() {
+		return new DataView(this.memory.buffer);
+	}
+
+
+	loadF32Array(addr, len) {
+		let array = new Float32Array(this.memory.buffer, addr, len);
+		return array;
+	}
+	loadF64Array(addr, len) {
+		let array = new Float64Array(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;
+		}
+	};
+
+	let event_temp_data = {};
+
+	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),
+		},
+		"odin_dom": {
+			init_event_raw: (ep) => {
+				const W = 4;
+				let offset = ep;
+				let off = (amount, alignment) => {
+					if (alignment === undefined) {
+						alignment = amount;
+					}
+					if (offset % alignment != 0) {
+						offset += alignment - (offset%alignment);
+					}
+					let x = offset;
+					offset += amount;
+					return x;
+				};
+
+				let wmi = wasmMemoryInterface;
+
+				let e = event_temp_data.event;
+
+				wmi.storeU32(off(4), event_temp_data.name_code);
+				if (e.target == document) {
+					wmi.storeU32(off(4), 1);
+				} else if (e.target == window) {
+					wmi.storeU32(off(4), 2);
+				} else {
+					wmi.storeU32(off(4), 0);
+				}
+				if (e.currentTarget == document) {
+					wmi.storeU32(off(4), 1);
+				} else if (e.currentTarget == window) {
+					wmi.storeU32(off(4), 2);
+				} else {
+					wmi.storeU32(off(4), 0);
+				}
+
+				wmi.storeUint(off(W), event_temp_data.id_ptr);
+				wmi.storeUint(off(W), event_temp_data.id_len);
+
+				wmi.storeF64(off(8), e.timeStamp*1e-3);
+
+				wmi.storeU8(off(1), e.eventPhase);
+				wmi.storeU8(off(1), !!e.bubbles);
+				wmi.storeU8(off(1), !!e.cancelable);
+				wmi.storeU8(off(1), !!e.composed);
+				wmi.storeU8(off(1), !!e.isComposing);
+				wmi.storeU8(off(1), !!e.isTrusted);
+
+				off(0, 8);
+				if (e instanceof MouseEvent) {
+					wmi.storeI64(off(8), e.screenX);
+					wmi.storeI64(off(8), e.screenY);
+					wmi.storeI64(off(8), e.clientX);
+					wmi.storeI64(off(8), e.clientY);
+					wmi.storeI64(off(8), e.offsetX);
+					wmi.storeI64(off(8), e.offsetY);
+					wmi.storeI64(off(8), e.pageX);
+					wmi.storeI64(off(8), e.pageY);
+					wmi.storeI64(off(8), e.movementX);
+					wmi.storeI64(off(8), e.movementY);
+					wmi.storeI64(off(8), e.x);
+					wmi.storeI64(off(8), e.y);
+
+					wmi.storeU8(off(1), !!e.ctrlKey);
+					wmi.storeU8(off(1), !!e.shiftKey);
+					wmi.storeU8(off(1), !!e.altKey);
+					wmi.storeU8(off(1), !!e.metaKey);
+
+					wmi.storeI16(off(2), e.button);
+					wmi.storeU16(off(2), e.buttons);
+				} else if (e instanceof KeyboardEvent) {
+					let keyOffset = off(W*2, W);
+					let codeOffet = off(W*2, W);
+					wmi.storeU8(off(1), e.location);
+
+					wmi.storeU8(off(1), !!e.ctrlKey);
+					wmi.storeU8(off(1), !!e.shiftKey);
+					wmi.storeU8(off(1), !!e.altKey);
+					wmi.storeU8(off(1), !!e.metaKey);
+
+					wmi.storeU8(off(1), !!e.repeat);
+				} else if (e instanceof WheelEvent) {
+					wmi.storeF64(off(8), e.deltaX);
+					wmi.storeF64(off(8), e.deltaY);
+					wmi.storeF64(off(8), e.deltaZ);
+					wmi.storeU32(off(4), e.deltaMode);
+				} else if (e instanceof Event) {
+					if ('scrollX' in e) {
+						wmi.storeF64(off(8), e.scrollX);
+						wmi.storeF64(off(8), e.scrollY);
+					}
+				}
+			},
+
+			add_event_listener: (id_ptr, id_len, name_ptr, name_len, name_code, data, callback, use_capture) => {
+				let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+				let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+				let element = document.getElementById(id);
+				if (element == undefined) {
+					return false;
+				}
+
+				let listener = (e) => {
+					const odin_ctx = wasmMemoryInterface.exports.default_context_ptr();
+					event_temp_data.id_ptr = id_ptr;
+					event_temp_data.id_len = id_len;
+					event_temp_data.event = e;
+					event_temp_data.name_code = name_code;
+					// console.log(e);
+					wasmMemoryInterface.exports.odin_dom_do_event_callback(data, callback, odin_ctx);
+				};
+				wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
+				element.addEventListener(name, listener, !!use_capture);
+				return true;
+			},
+
+			remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback) => {
+				let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+				let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+				let element = document.getElementById(id);
+				if (element == undefined) {
+					return false;
+				}
+
+				let listener = wasmMemoryInterface.listenerMap[{data: data, callback: callback}];
+				if (listener == undefined) {
+					return false;
+				}
+				element.removeEventListener(name, listener);
+				return true;
+			},
+
+
+			add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
+				let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+				let element = window;
+				let listener = (e) => {
+					const odin_ctx = wasmMemoryInterface.exports.default_context_ptr();
+					event_temp_data.id_ptr = 0;
+					event_temp_data.id_len = 0;
+					event_temp_data.event = e;
+					event_temp_data.name_code = name_code;
+					// console.log(e);
+					wasmMemoryInterface.exports.odin_dom_do_event_callback(data, callback, odin_ctx);
+				};
+				wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener;
+				element.addEventListener(name, listener, !!use_capture);
+				return true;
+			},
+
+			remove_window_event_listener: (name_ptr, name_len, data, callback) => {
+				let name = wasmMemoryInterface.loadString(name_ptr, name_len);
+				let element = window;
+				let listener = wasmMemoryInterface.listenerMap[{data: data, callback: callback}];
+				if (listener == undefined) {
+					return false;
+				}
+				element.removeEventListener(name, listener);
+				return true;
+			},
+
+			event_stop_propagation: () => {
+				if (event_temp_data && event_temp_data.event) {
+					event_temp_data.event.eventStopPropagation();
+				}
+			},
+			event_stop_immediate_propagation: () => {
+				if (event_temp_data && event_temp_data.event) {
+					event_temp_data.event.eventStopImmediatePropagation();
+				}
+			},
+			event_prevent_default: () => {
+				if (event_temp_data && event_temp_data.event) {
+					event_temp_data.event.eventPreventDefault();
+				}
+			},
+
+			get_element_value_f64: (id_ptr, id_len) => {
+				let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+				let element = document.getElementById(id);
+				return element.value;
+			},
+			get_element_value_string: (id_ptr, id_len, buf_ptr, buf_len) => {
+				let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+				let element = document.getElementById(id);
+				let str = element.value;
+				if (buf_len > 0 && buf_ptr) {
+					let n = Math.min(buf_len, str.length);
+					str = str.substring(0, n);
+					this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(str))
+					return n;
+				}
+				return 0;
+			},
+			get_element_min_max: (ptr_array2_f64, id_ptr, id_len) => {
+				let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+				let element = document.getElementById(id);
+				let values = wasmMemoryInterface.loadF64Array(ptr_array2_f64, 2);
+				values[0] = element.min;
+				values[1] = element.max;
+			},
+			set_element_value: (id_ptr, id_len, value) => {
+				let id = wasmMemoryInterface.loadString(id_ptr, id_len);
+				document.getElementById(id).value = value;
+			},
+		},
+	};
+}
+
+
+export {WasmMemoryInterface, odinSetupDefaultImports};

+ 63 - 0
vendor/wasm/loader/loader.mjs

@@ -0,0 +1,63 @@
+import {WasmMemoryInterface, odinSetupDefaultImports} from "../js/runtime.mjs";
+import {WebGLInterface} from "../WebGL/runtime.mjs";
+
+export async function runWasmCanvas(wasmPath, webglCanvasElement, consoleElement, extraForeignImports) {
+	let wasmMemoryInterface = new WasmMemoryInterface();
+
+	let imports = odinSetupDefaultImports(wasmMemoryInterface, consoleElement);
+	let exports = {};
+
+	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();
+	}
+
+	if (extraForeignImports !== undefined) {
+		imports = {
+			...imports,
+			...extraForeignImports,
+		};
+	}
+
+	const response = await fetch(wasmPath);
+	const file = await response.arrayBuffer();
+	const wasm = await WebAssembly.instantiate(file, imports);
+	exports = wasm.instance.exports;
+	wasmMemoryInterface.setExports(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);
+	}
+
+	exports._end();
+
+	return;
+};
+
+
+export {runWasmCanvas};