forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			542 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			542 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								// Includes snippets from https://surma.dev/things/c-to-webassembly/ and https://developer.mozilla.org/en-US/docs/WebAssembly/Using_the_JavaScript_API -->
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let memory = null;
							 | 
						||
| 
								 | 
							
								let heapu8 = null;
							 | 
						||
| 
								 | 
							
								let heapu16 = null;
							 | 
						||
| 
								 | 
							
								let heapu32 = null;
							 | 
						||
| 
								 | 
							
								let heapi32 = null;
							 | 
						||
| 
								 | 
							
								let heapf32 = null;
							 | 
						||
| 
								 | 
							
								let mod = null;
							 | 
						||
| 
								 | 
							
								let instance = null;
							 | 
						||
| 
								 | 
							
								let audio_thread_started = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function create_thread(func) {
							 | 
						||
| 
								 | 
							
									console.log('Creating thread');
							 | 
						||
| 
								 | 
							
									const thread_starter = new Worker('thread_starter.js');
							 | 
						||
| 
								 | 
							
									const arr = new Uint8Array(memory.buffer, func, 256);
							 | 
						||
| 
								 | 
							
									let str = '';
							 | 
						||
| 
								 | 
							
									for (let i = 0; arr[i] != 0; ++i) {
							 | 
						||
| 
								 | 
							
										str += String.fromCharCode(arr[i]);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									thread_starter.postMessage({ mod, memory, func: str });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								async function start_audio_thread() {
							 | 
						||
| 
								 | 
							
									const audioContext = new AudioContext();
							 | 
						||
| 
								 | 
							
									await audioContext.audioWorklet.addModule('audio-thread.js');
							 | 
						||
| 
								 | 
							
									const audioThreadNode = new AudioWorkletNode(audioContext, 'audio-thread', { processorOptions: { mod, memory }});
							 | 
						||
| 
								 | 
							
									audioThreadNode.port.onmessage = (message) => {
							 | 
						||
| 
								 | 
							
										console.log(message.data);
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									audioThreadNode.connect(audioContext.destination);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function read_string(ptr) {
							 | 
						||
| 
								 | 
							
									let str = '';
							 | 
						||
| 
								 | 
							
									for (let i = 0; heapu8[ptr + i] != 0; ++i) {
							 | 
						||
| 
								 | 
							
										str += String.fromCharCode(heapu8[ptr + i]);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return str;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function write_string(ptr, str) {
							 | 
						||
| 
								 | 
							
									for (let i = 0; i < str.length; ++i) {
							 | 
						||
| 
								 | 
							
										heapu8[ptr + i] = str.charCodeAt(i);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									heapu8[ptr + str.length] = 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								async function init() {
							 | 
						||
| 
								 | 
							
									let wasm_bytes = null;
							 | 
						||
| 
								 | 
							
									await fetch("./ShaderTest.wasm").then(res => res.arrayBuffer()).then(buffer => wasm_bytes = new Uint8Array(buffer));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Read memory size from wasm file
							 | 
						||
| 
								 | 
							
									let memory_size = 0;
							 | 
						||
| 
								 | 
							
									let i = 8;
							 | 
						||
| 
								 | 
							
									while (i < wasm_bytes.length) {
							 | 
						||
| 
								 | 
							
										function read_leb() {
							 | 
						||
| 
								 | 
							
											let result = 0;
							 | 
						||
| 
								 | 
							
											let shift = 0;
							 | 
						||
| 
								 | 
							
											while (true) {
							 | 
						||
| 
								 | 
							
												let byte = wasm_bytes[i++];
							 | 
						||
| 
								 | 
							
												result |= (byte & 0x7f) << shift;
							 | 
						||
| 
								 | 
							
												if ((byte & 0x80) == 0) return result;
							 | 
						||
| 
								 | 
							
												shift += 7;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										let type = read_leb()
							 | 
						||
| 
								 | 
							
										let length = read_leb()
							 | 
						||
| 
								 | 
							
										if (type == 6) {
							 | 
						||
| 
								 | 
							
											read_leb(); // count
							 | 
						||
| 
								 | 
							
											i++; // gtype
							 | 
						||
| 
								 | 
							
											i++; // mutable
							 | 
						||
| 
								 | 
							
											read_leb(); // opcode
							 | 
						||
| 
								 | 
							
											memory_size = read_leb() / 65536 + 1;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										i += length;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									memory = new WebAssembly.Memory({ initial: memory_size, maximum: memory_size, shared: true });
							 | 
						||
| 
								 | 
							
									heapu8 = new Uint8Array(memory.buffer);
							 | 
						||
| 
								 | 
							
									heapu16 = new Uint16Array(memory.buffer);
							 | 
						||
| 
								 | 
							
									heapu32 = new Uint32Array(memory.buffer);
							 | 
						||
| 
								 | 
							
									heapi32 = new Int32Array(memory.buffer);
							 | 
						||
| 
								 | 
							
									heapf32 = new Float32Array(memory.buffer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const kanvas = document.getElementById('kanvas');
							 | 
						||
| 
								 | 
							
									const gl = kanvas.getContext('webgl2', { antialias: false, alpha: false });
							 | 
						||
| 
								 | 
							
									// gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
							 | 
						||
| 
								 | 
							
									gl.getExtension("EXT_color_buffer_float");
							 | 
						||
| 
								 | 
							
									gl.getExtension("OES_texture_float_linear");
							 | 
						||
| 
								 | 
							
									gl.getExtension("OES_texture_half_float_linear");
							 | 
						||
| 
								 | 
							
									gl.getExtension("EXT_texture_filter_anisotropic");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									let file_buffer = null;
							 | 
						||
| 
								 | 
							
									let file_buffer_pos = 0;
							 | 
						||
| 
								 | 
							
									let gl_programs = [null];
							 | 
						||
| 
								 | 
							
									let gl_shaders = [null];
							 | 
						||
| 
								 | 
							
									let gl_buffers = [null];
							 | 
						||
| 
								 | 
							
									let gl_framebuffers = [null];
							 | 
						||
| 
								 | 
							
									let gl_renderbuffers = [null];
							 | 
						||
| 
								 | 
							
									let gl_textures = [null];
							 | 
						||
| 
								 | 
							
									let gl_locations = [null];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const result = await WebAssembly.instantiate(
							 | 
						||
| 
								 | 
							
										wasm_bytes, {
							 | 
						||
| 
								 | 
							
											env: { memory },
							 | 
						||
| 
								 | 
							
											imports: {
							 | 
						||
| 
								 | 
							
												create_thread,
							 | 
						||
| 
								 | 
							
												glViewport: function(x, y, width, height) {
							 | 
						||
| 
								 | 
							
													gl.viewport(x, y, width, height);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glScissor: function(x, y, width, height) {
							 | 
						||
| 
								 | 
							
													gl.scissor(x, y, width, height);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetIntegerv: function(pname, data) {
							 | 
						||
| 
								 | 
							
													if (pname == 2) { // GL_MAJOR_VERSION
							 | 
						||
| 
								 | 
							
														heapu32[data / 4] = 3;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													else {
							 | 
						||
| 
								 | 
							
														heapu32[data / 4] = gl.getParameter(pname);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetFloatv: function(pname, data) {
							 | 
						||
| 
								 | 
							
													heapf32[data / 4] = gl.getParameter(pname);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetString: function(name) {
							 | 
						||
| 
								 | 
							
													// return gl.getParameter(name);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDrawElements: function(mode, count, type, offset) {
							 | 
						||
| 
								 | 
							
													gl.drawElements(mode, count, type, offset);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDrawElementsInstanced: function(mode, count, type, indices, instancecount) {
							 | 
						||
| 
								 | 
							
													gl.drawElementsInstanced(mode, count, type, indices, instancecount);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glVertexAttribDivisor: function(index, divisor) {
							 | 
						||
| 
								 | 
							
													gl.vertexAttribDivisor(index, divisor);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBindFramebuffer: function(target, framebuffer) {
							 | 
						||
| 
								 | 
							
													gl.bindFramebuffer(target, gl_framebuffers[framebuffer]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glFramebufferTexture2D: function(target, attachment, textarget, texture, level) {
							 | 
						||
| 
								 | 
							
													gl.framebufferTexture2D(target, attachment, textarget, gl_textures[texture], level);
							 | 
						||
| 
								 | 
							
													if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
							 | 
						||
| 
								 | 
							
														console.log("Incomplete framebuffer");
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGenFramebuffers: function(n, framebuffers) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl_framebuffers.push(gl.createFramebuffer());
							 | 
						||
| 
								 | 
							
														heapu32[framebuffers / 4 + i] = gl_framebuffers.length - 1;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGenRenderbuffers: function(n, renderbuffers) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl_renderbuffers.push(gl.createRenderbuffer());
							 | 
						||
| 
								 | 
							
														heapu32[renderbuffers / 4 + i] = gl_renderbuffers.length - 1;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBindRenderbuffer: function(target, renderbuffer) {
							 | 
						||
| 
								 | 
							
													gl.bindRenderbuffer(target, gl_renderbuffers[renderbuffer]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glRenderbufferStorage: function(target, internalformat, width, height) {
							 | 
						||
| 
								 | 
							
													gl.renderbufferStorage(target, internalformat, width, height)
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) {
							 | 
						||
| 
								 | 
							
													gl.framebufferRenderbuffer(target, attachment, renderbuffertarget, gl_renderbuffers[renderbuffer]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glReadPixels: function(x, y, width, height, format, type, data) {
							 | 
						||
| 
								 | 
							
													let pixels = type == gl.FLOAT ? heapf32.subarray(data / 4) : heapu8.subarray(data);
							 | 
						||
| 
								 | 
							
													gl.readPixels(x, y, width, height, format, type, pixels);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, type, pixels) {
							 | 
						||
| 
								 | 
							
													gl.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, heapu8.subarray(pixels));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glEnable: function(cap) {
							 | 
						||
| 
								 | 
							
													gl.enable(cap);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDisable: function(cap) {
							 | 
						||
| 
								 | 
							
													gl.disable(cap);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glColorMask: function(red, green, blue, alpha) {
							 | 
						||
| 
								 | 
							
													gl.colorMask(red, green, blue, alpha);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glClearColor: function(red, green, blue, alpha) {
							 | 
						||
| 
								 | 
							
													gl.clearColor(red, green, blue, alpha);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDepthMask: function(flag) {
							 | 
						||
| 
								 | 
							
													gl.depthMask(flag);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glClearDepthf: function(depth) {
							 | 
						||
| 
								 | 
							
													gl.clearDepth(depth);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glStencilMask: function(mask) {
							 | 
						||
| 
								 | 
							
													gl.stencilMask(mask);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glClearStencil: function(s) {
							 | 
						||
| 
								 | 
							
													gl.clearStencil(s);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glClear: function(mask) {
							 | 
						||
| 
								 | 
							
													gl.clear(mask);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBindBuffer: function(target, buffer) {
							 | 
						||
| 
								 | 
							
													gl.bindBuffer(target, gl_buffers[buffer]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUseProgram: function(program) {
							 | 
						||
| 
								 | 
							
													gl.useProgram(gl_programs[program]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glStencilMaskSeparate: function(face, mask) {
							 | 
						||
| 
								 | 
							
													gl.stencilMaskSeparate(face, mask);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glStencilOpSeparate: function(face, fail, zfail, zpass) {
							 | 
						||
| 
								 | 
							
													gl.stencilOpSeparate(face, fail, zfail, zpass);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glStencilFuncSeparate: function(face, func, ref, mask) {
							 | 
						||
| 
								 | 
							
													gl.stencilFuncSeparate(face, func, ref, mask);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDepthFunc: function(func) {
							 | 
						||
| 
								 | 
							
													gl.depthFunc(func);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glCullFace: function(mode) {
							 | 
						||
| 
								 | 
							
													gl.cullFace(mode);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBlendFuncSeparate: function(src_rgb, dst_rgb, src_alpha, dst_alpha) {
							 | 
						||
| 
								 | 
							
													gl.blendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBlendEquationSeparate: function(mode_rgb, mode_alpha) {
							 | 
						||
| 
								 | 
							
													gl.blendEquationSeparate(mode_rgb, mode_alpha);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGenBuffers: function(n, buffers) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl_buffers.push(gl.createBuffer());
							 | 
						||
| 
								 | 
							
														heapu32[buffers / 4 + i] = gl_buffers.length - 1;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBufferData: function(target, size, data, usage) {
							 | 
						||
| 
								 | 
							
													gl.bufferData(target, heapu8.subarray(data, data + Number(size)), usage);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glCreateProgram: function() {
							 | 
						||
| 
								 | 
							
													gl_programs.push(gl.createProgram());
							 | 
						||
| 
								 | 
							
													return gl_programs.length - 1;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glAttachShader: function(program, shader) {
							 | 
						||
| 
								 | 
							
													gl.attachShader(gl_programs[program], gl_shaders[shader]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBindAttribLocation: function(program, index, name) {
							 | 
						||
| 
								 | 
							
													gl.bindAttribLocation(gl_programs[program], index, read_string(name));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glLinkProgram: function(program) {
							 | 
						||
| 
								 | 
							
													gl.linkProgram(gl_programs[program]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetProgramiv: function(program, pname, params) {
							 | 
						||
| 
								 | 
							
													heapu32[params / 4] = gl.getProgramParameter(gl_programs[program], pname);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetProgramInfoLog: function(program) {
							 | 
						||
| 
								 | 
							
													console.log(gl.getProgramInfoLog(gl_programs[program]));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glCreateShader: function(type) {
							 | 
						||
| 
								 | 
							
													gl_shaders.push(gl.createShader(type));
							 | 
						||
| 
								 | 
							
													return gl_shaders.length - 1;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glShaderSource: function(shader, count, source, length) {
							 | 
						||
| 
								 | 
							
													gl.shaderSource(gl_shaders[shader], read_string(heapu32[source / 4]));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glCompileShader: function(shader) {
							 | 
						||
| 
								 | 
							
													gl.compileShader(gl_shaders[shader]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetShaderiv: function(shader, pname, params) {
							 | 
						||
| 
								 | 
							
													heapu32[params / 4] = gl.getShaderParameter(gl_shaders[shader], pname);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetShaderInfoLog: function(shader) {
							 | 
						||
| 
								 | 
							
													console.log(gl.getShaderInfoLog(gl_shaders[shader]));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBufferSubData: function(target, offset, size, data) {
							 | 
						||
| 
								 | 
							
													gl.bufferSubData(target, Number(offset), heapu8.subarray(data, data + Number(size)), 0);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glEnableVertexAttribArray: function(index) {
							 | 
						||
| 
								 | 
							
													gl.enableVertexAttribArray(index);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glVertexAttribPointer: function(index, size, type, normalized, stride, offset) {
							 | 
						||
| 
								 | 
							
													gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDisableVertexAttribArray: function(index) {
							 | 
						||
| 
								 | 
							
													gl.disableVertexAttribArray(index);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetUniformLocation: function(program, name) {
							 | 
						||
| 
								 | 
							
													gl_locations.push(gl.getUniformLocation(gl_programs[program], read_string(name)));
							 | 
						||
| 
								 | 
							
													return gl_locations.length - 1;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform1i: function(location, v0) {
							 | 
						||
| 
								 | 
							
													gl.uniform1i(gl_locations[location], v0);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform2i: function(location, v0, v1) {
							 | 
						||
| 
								 | 
							
													gl.uniform2i(gl_locations[location], v0, v1);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform3i: function(location, v0, v1, v2) {
							 | 
						||
| 
								 | 
							
													gl.uniform3i(gl_locations[location], v0, v1, v2);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform4i: function(location, v0, v1, v2, v3) {
							 | 
						||
| 
								 | 
							
													gl.uniform4i(gl_locations[location], v0, v1, v2, v3);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform1iv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													gl.uniform1iv(gl_locations[location], count, heapi32.subarray(value / 4));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform2iv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													gl.uniform2iv(gl_locations[location], count, heapi32.subarray(value / 4));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform3iv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													gl.uniform3iv(gl_locations[location], count, heapi32.subarray(value / 4));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform4iv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													gl.uniform4iv(gl_locations[location], count, heapi32.subarray(value / 4));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform1f: function(location, v0) {
							 | 
						||
| 
								 | 
							
													gl.uniform1f(gl_locations[location], v0);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform2f: function(location, v0, v1) {
							 | 
						||
| 
								 | 
							
													gl.uniform2f(gl_locations[location], v0, v1);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform3f: function(location, v0, v1, v2) {
							 | 
						||
| 
								 | 
							
													gl.uniform3f(gl_locations[location], v0, v1, v2);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform4f: function(location, v0, v1, v2, v3) {
							 | 
						||
| 
								 | 
							
													gl.uniform4f(gl_locations[location], v0, v1, v2, v3);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform1fv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													var f32 = new Float32Array(memory.buffer, value, count);
							 | 
						||
| 
								 | 
							
													gl.uniform1fv(gl_locations[location], f32);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform2fv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													var f32 = new Float32Array(memory.buffer, value, count * 2);
							 | 
						||
| 
								 | 
							
													gl.uniform2fv(gl_locations[location], f32);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform3fv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													var f32 = new Float32Array(memory.buffer, value, count * 3);
							 | 
						||
| 
								 | 
							
													gl.uniform3fv(gl_locations[location], f32);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniform4fv: function(location, count, value) {
							 | 
						||
| 
								 | 
							
													var f32 = new Float32Array(memory.buffer, value, count * 4);
							 | 
						||
| 
								 | 
							
													gl.uniform4fv(gl_locations[location], f32);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniformMatrix3fv: function(location, count, transpose, value) {
							 | 
						||
| 
								 | 
							
													var f32 = new Float32Array(memory.buffer, value, 3 * 3);
							 | 
						||
| 
								 | 
							
													gl.uniformMatrix3fv(gl_locations[location], transpose, f32);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glUniformMatrix4fv: function(location, count, transpose, value) {
							 | 
						||
| 
								 | 
							
													var f32 = new Float32Array(memory.buffer, value, 4 * 4);
							 | 
						||
| 
								 | 
							
													gl.uniformMatrix4fv(gl_locations[location], transpose, f32);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glTexParameterf: function(target, pname, param) {
							 | 
						||
| 
								 | 
							
													gl.texParameterf(target, pname, param);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glActiveTexture: function(texture) {
							 | 
						||
| 
								 | 
							
													gl.activeTexture(texture);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glBindTexture: function(target, texture) {
							 | 
						||
| 
								 | 
							
													gl.bindTexture(target, gl_textures[texture]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glTexParameteri: function(target, pname, param) {
							 | 
						||
| 
								 | 
							
													gl.texParameteri(target, pname, param);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGetActiveUniform: function(program, index, bufSize, length, size, type, name) {
							 | 
						||
| 
								 | 
							
													let u = gl.getActiveUniform(gl_programs[program], index);
							 | 
						||
| 
								 | 
							
													heapu32[size / 4] = u.size;
							 | 
						||
| 
								 | 
							
													heapu32[type / 4] = u.type;
							 | 
						||
| 
								 | 
							
													write_string(name, u.name);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGenTextures: function(n, textures) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl_textures.push(gl.createTexture());
							 | 
						||
| 
								 | 
							
														heapu32[textures / 4 + i] = gl_textures.length - 1;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glTexImage2D: function(target, level, internalformat, width, height, border, format, type, data) {
							 | 
						||
| 
								 | 
							
													let pixels = type == gl.FLOAT ? heapf32.subarray(data / 4) :
							 | 
						||
| 
								 | 
							
																 type == gl.UNSIGNED_INT ? heapu32.subarray(data / 4) :
							 | 
						||
| 
								 | 
							
																 type == gl.UNSIGNED_SHORT ? heapu16.subarray(data / 2) :
							 | 
						||
| 
								 | 
							
																 type == gl.HALF_FLOAT ? heapu16.subarray(data / 2) : heapu8.subarray(data);
							 | 
						||
| 
								 | 
							
													gl.texImage2D(target, level, internalformat, width, height, border, format, type, pixels);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glPixelStorei: function(pname, param) {
							 | 
						||
| 
								 | 
							
													gl.pixelStorei(pname, param);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glCompressedTexImage2D: function(target, level, internalformat, width, height, border, imageSize, data) {
							 | 
						||
| 
								 | 
							
													gl.compressedTexImage2D(target, level, internalformat, width, height, border, imageSize, heapu8.subarray(data));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDrawBuffers: function(n, bufs) {
							 | 
						||
| 
								 | 
							
													let ar = [];
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														ar.push(gl.COLOR_ATTACHMENT0 + i);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													gl.drawBuffers(ar);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glGenerateMipmap: function(target) {
							 | 
						||
| 
								 | 
							
													gl.generateMipmap(target);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glFlush: function() {
							 | 
						||
| 
								 | 
							
													gl.flush();
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDeleteBuffers: function(n, buffers) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl.deleteBuffer(gl_buffers[heapu32[buffers / 4 + i]]);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDeleteTextures: function(n, textures) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl.deleteTexture(gl_textures[heapu32[textures / 4 + i]]);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDeleteFramebuffers: function(n, framebuffers) {
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < n; ++i) {
							 | 
						||
| 
								 | 
							
														gl.deleteFramebuffer(gl_framebuffers[heapu32[framebuffers / 4 + i]]);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDeleteProgram: function(program) {
							 | 
						||
| 
								 | 
							
													gl.deleteProgram(gl_programs[program]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												glDeleteShader: function(shader) {
							 | 
						||
| 
								 | 
							
													gl.deleteShader(gl_shaders[shader]);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_fprintf: function(format) {
							 | 
						||
| 
								 | 
							
													console.log(read_string(format));
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_fopen: function(filename) {
							 | 
						||
| 
								 | 
							
													const req = new XMLHttpRequest();
							 | 
						||
| 
								 | 
							
													req.open("GET", read_string(filename), false);
							 | 
						||
| 
								 | 
							
													req.overrideMimeType("text/plain; charset=x-user-defined");
							 | 
						||
| 
								 | 
							
													req.send();
							 | 
						||
| 
								 | 
							
													let str = req.response;
							 | 
						||
| 
								 | 
							
													file_buffer_pos = 0;
							 | 
						||
| 
								 | 
							
													file_buffer = new ArrayBuffer(str.length);
							 | 
						||
| 
								 | 
							
													let buf_view = new Uint8Array(file_buffer);
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < str.length; ++i) {
							 | 
						||
| 
								 | 
							
														buf_view[i] = str.charCodeAt(i);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													return 1;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_ftell: function(stream) {
							 | 
						||
| 
								 | 
							
													return file_buffer_pos;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_fseek: function(stream, offset, origin) {
							 | 
						||
| 
								 | 
							
													file_buffer_pos = offset;
							 | 
						||
| 
								 | 
							
													if (origin == 1) file_buffer_pos += file_buffer.byteLength; // SEEK_END
							 | 
						||
| 
								 | 
							
													return 0;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_fread: function(ptr, size, count, stream) {
							 | 
						||
| 
								 | 
							
													let buf_view = new Uint8Array(file_buffer);
							 | 
						||
| 
								 | 
							
													for (let i = 0; i < count; ++i) {
							 | 
						||
| 
								 | 
							
														heapu8[ptr + i] = buf_view[file_buffer_pos++];
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													return count;
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_time: function() {
							 | 
						||
| 
								 | 
							
													return window.performance.now();
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_pow: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.pow(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_floor: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.floor(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_sin: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.sin(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_cos: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.cos(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_tan: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.tan(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_log: function(base, exponent) {
							 | 
						||
| 
								 | 
							
													return Math.log(base, exponent);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_exp: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.exp(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_sqrt: function(x) {
							 | 
						||
| 
								 | 
							
													return Math.sqrt(x);
							 | 
						||
| 
								 | 
							
												},
							 | 
						||
| 
								 | 
							
												js_eval: function(str) {
							 | 
						||
| 
								 | 
							
													(1, eval)(read_string(str));
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									mod = result.module;
							 | 
						||
| 
								 | 
							
									instance = result.instance;
							 | 
						||
| 
								 | 
							
									instance.exports._start();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function update() {
							 | 
						||
| 
								 | 
							
										instance.exports._update();
							 | 
						||
| 
								 | 
							
										window.requestAnimationFrame(update);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									window.requestAnimationFrame(update);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('click', (event) => {
							 | 
						||
| 
								 | 
							
										if (!audio_thread_started) {
							 | 
						||
| 
								 | 
							
											start_audio_thread();
							 | 
						||
| 
								 | 
							
											audio_thread_started = true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('contextmenu', (event) => {
							 | 
						||
| 
								 | 
							
										event.preventDefault();
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('mousedown', (event) => {
							 | 
						||
| 
								 | 
							
										instance.exports._mousedown(event.button, event.clientX, event.clientY);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('mouseup', (event) => {
							 | 
						||
| 
								 | 
							
										instance.exports._mouseup(event.button, event.clientX, event.clientY);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('mousemove', (event) => {
							 | 
						||
| 
								 | 
							
										instance.exports._mousemove(event.clientX, event.clientY);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('wheel', (event) => {
							 | 
						||
| 
								 | 
							
										instance.exports._wheel(event.deltaY);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('keydown', (event) => {
							 | 
						||
| 
								 | 
							
										if (event.repeat) {
							 | 
						||
| 
								 | 
							
											event.preventDefault();
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										instance.exports._keydown(event.keyCode);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kanvas.addEventListener('keyup', (event) => {
							 | 
						||
| 
								 | 
							
										if (event.repeat) {
							 | 
						||
| 
								 | 
							
											event.preventDefault();
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										instance.exports._keyup(event.keyCode);
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								init();
							 |