var lumenarium_wasm_module = null; var lumenarium_wasm_instance = null; var WASM_PAGE_SIZE = 65536; function wasm_mem_get_u8_arr(inst, ptr, size) { let view = new Uint8Array(inst.exports.memory.buffer, ptr, size); return view; } function wasm_read_string(inst, ptr, len) { let view = wasm_mem_get_u8_arr(inst, ptr, len); let string = ''; for (let i = 0; i < len; i++) { string += String.fromCharCode(view[i]); } return string; } function wasm_write_bytes(inst, src, ptr, len) { let view = wasm_mem_get_u8_arr(inst, ptr, len); for (let i = 0; i < len; i++) view[i] = src[i]; } function wasm_get_proc(inst, proc_ptr) { let result = inst.exports.__indirect_function_table.get(proc_ptr); return result; } function fract (v) { return v % 1; } function u32_to_byte_array_32 (v) { let result = [0, 0, 0, 0]; result[0] = (v & 0xff); result[1] = (((v - result[0]) >> 8 ) & 0xff); result[2] = (((v - result[1]) >> 16) & 0xff); result[3] = (((v - result[2]) >> 24) & 0xff); return result; } function byte_array_32_to_u32 (arr) { // NOTE(PS): the '>>>' operators in this function deal with the fact // that bit shift operators convert numbers to s32's. The >>> just // converts them back to u32s let r0 = ((arr[0] & 0xff) << 0 ); let r1 = ((arr[1] & 0xff) << 8 ); let r2 = ((arr[2] & 0xff) << 16); let r3 = (((arr[3] & 0xff) << 24) >>> 0); let result = (r0 | r1 | r2 | r3) >>> 0; return result; } function put_u32 (ptr, value) { let src = u32_to_byte_array_32(value); wasm_write_bytes(lumenarium_wasm_instance, src, ptr, 4); } var lumenarium_wasm_imports = { memset: (dst, size, value) => { let view_dst = wasm_mem_get_u8_arr(lumenarium_wasm_instance, dst, size); for (let i = 0; i < size; i++) { view_dst[i] = value; } }, memcpy: (dst, src, size) => { let view_dst = wasm_mem_get_u8_arr(lumenarium_wasm_instance, dst, size); let view_src = wasm_mem_get_u8_arr(lumenarium_wasm_instance, src, size); for (let i = 0; i < size; i++) { view_dst[i] = view_src[i]; } }, wasm_assert_always: (file, file_len, line) => { let file_str = wasm_read_string(lumenarium_wasm_instance, file, file_len); console.assert(false, "At: " + file_str + "::" + line); }, wasm_get_memory_size: () => { return instance.exports.memory.buffer.byteLength; }, wasm_mem_grow: (new_size) => { let pages = new_size / WASM_PAGE_SIZE; let pages_rem = fract(pages); if (pages_rem > 0) pages = Math.floor(pages) + 1; let size_before = lumenarium_wasm_instance.exports.memory.buffer.byteLength; let old_page_count = lumenarium_wasm_instance.exports.memory.grow(pages); console.log("mem_grow\n", "req size: ", new_size, "\n", "old size: ", (old_page_count * WASM_PAGE_SIZE), "\n", "old size: ", size_before, "\n", "grew by: ", (pages * WASM_PAGE_SIZE), "\n", "new size: ", lumenarium_wasm_instance.exports.memory.buffer.byteLength, ""); }, wasm_performance_now: () => { return performance.now(); }, wasm_sleep: (milliseconds) => { let start = Date.now(); for (let at = Date.now(); (at - start) < milliseconds; at = Date.now()) {} }, wasm_fetch: async (file_path, file_path_len, dest, dest_size) => { let path = wasm_read_string(lumenarium_wasm_instance, file_path, file_path_len); fetch(path) .then(async (res) => { // TODO(PS): success checking let reader = res.body.getReader(); let read_res = { done: false }; let view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, dest, dest_size); let last_write = 0; while (!read_res.done) { read_res = await reader.read(); if (read_res.done) break; let len = read_res.value.length; let write_end = last_write + len; for (let i = last_write; i < write_end; i++) { view[i] = read_res.value[i - last_write]; } last_write = write_end + 1; } }); return 0; }, wasm_request_animation_frame: (cb) => { let cb_proc = wasm_get_proc(lumenarium_wasm_instance, cb); window.requestAnimationFrame(cb_proc); }, print: (str_base, len) => { let string = wasm_read_string(lumenarium_wasm_instance, str_base, len); console.log(string); }, wasm_get_canvas_dim: (w_ptr, h_ptr) => { const canvas = document.querySelector("#gl_canvas"); let w_view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, w_ptr, 4); let w = canvas.width; let wb = u32_to_byte_array_32(w); for (let i = 0; i < 4; i++) w_view[i] = wb[i]; let h_view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, h_ptr, 4); let h = canvas.height; let hb = u32_to_byte_array_32(h); for (let i = 0; i < 4; i++) h_view[i] = hb[i]; }, }; /////////////////////////////////////// // Web GL Imports let gl = null; let gl_error = false; function glErrorReport(outer_args) { const err = gl.getError(); if (err == gl.NO_ERROR) return; gl_error = true; let msg = ""; switch (err) { case gl.NO_ERROR: { msg = "NO_ERROR"; } break; case gl.INVALID_ENUM: { msg = "INVALID_ENUM"; } break; case gl.INVALID_VALUE: { msg = "INVALID_VALUE"; } break; case gl.INVALID_OPERATION: { msg = "INVALID_OPERATION"; } break; case gl.INVALID_FRAMEBUFFER_OPERATION: { msg = "INVALID_FRAMEBUFFER_OPERATION"; } break; case gl.OUT_OF_MEMORY: { msg = "OUT_OF_MEMORY"; } break; case gl.CONTEXT_LOST_WEBGL: { msg = "CONTEXT_LOST_WEBGL"; } break; default: { msg = "Uknown error"; } break; } console.error(`WebGL Error: ${msg} ${err}`, outer_args); } // NOTE(PS): it seems like its not enough to set // the values of imports to gl.function // ie. imports.glClearColor = gl.clearColor // instead we need to wrap them for some reason. // Not sure why function glClearColor (r, g, b, a) { return gl.clearColor(r,g,b,a); } function glEnable(v) { const r = gl.enable(v); glErrorReport(arguments); return r; } function glDisable(v) { const r = gl.disable(v); glErrorReport(arguments); return r; } function glBlendFunc(a,b) { const r = gl.blendFunc(a,b); glErrorReport(arguments); return r; } function glViewport(xmin, ymin, xmax, ymax) { return gl.viewport(xmin,ymin,xmax,ymax); } function glDepthFunc(v) { const r = gl.depthFunc(v); glErrorReport(arguments); return r; } function glClear(mask) { const r = gl.clear(mask); glErrorReport(arguments); return r; } let glBuffers = []; let glShaders = []; let glPrograms = []; let glTextures = []; function gl_get_managed_resource(arr, id) { if (id == 0) return null; return arr[id - 1]; } function gl_get_buffer(id) { return gl_get_managed_resource(glBuffers, id); } function gl_get_shader(id) { return gl_get_managed_resource(glShaders, id); } function gl_get_program(id) { return gl_get_managed_resource(glPrograms, id); } function gl_get_texture(id) { return gl_get_managed_resource(glTextures, id); } function glCreateBuffer() { let buffer = gl.createBuffer(); glErrorReport(arguments); let new_len = glBuffers.push(buffer); return new_len; } function glBindBuffer(buffer_kind, buffer_id) { const r = gl.bindBuffer(buffer_kind, gl_get_buffer(buffer_id)); glErrorReport(arguments); return r; } function glBufferData(target, size, ptr, usage) { let data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, size); const r = gl.bufferData(target, data, usage); glErrorReport(arguments); return r; } function glCreateShader(kind) { let shader = gl.createShader(kind); glErrorReport(arguments); let new_len = glShaders.push(shader); return new_len; } function glShaderSource(shader_id, shader_code, shader_code_len) { let str = wasm_read_string(lumenarium_wasm_instance, shader_code, shader_code_len); const r = gl.shaderSource(gl_get_shader(shader_id), str); glErrorReport(arguments); return r; } function glCompileShader(shader_id) { let s = gl_get_shader(shader_id); let r = gl.compileShader(s); glErrorReport(arguments); let m = gl.getShaderInfoLog(s); glErrorReport(arguments); if (m.length > 0) { console.error("glCompileShader: \n\n" + m); } } function glCreateProgram() { let prog = gl.createProgram(); glErrorReport(arguments); let new_len = glPrograms.push(prog); return new_len; } function glAttachShader(program, shader) { let s = gl_get_shader(shader); let p = gl_get_program(program); const r = gl.attachShader(p, s); glErrorReport(arguments); return r; } function glLinkProgram(program) { let p = gl_get_program(program); gl.linkProgram(p); if (!gl.getProgramParameter(p, gl.LINK_STATUS)) { var info = gl.getProgramInfoLog(p); console.error("Failed to compile WebGL program. \n\n"+info); } } function glUseProgram(program) { let p = gl_get_program(program); const r = gl.useProgram(p); glErrorReport(arguments); return r; } function glGetAttribLocation(program, name, name_len) { let str = wasm_read_string(lumenarium_wasm_instance, name, name_len); const r = gl.getAttribLocation(gl_get_program(program), str); glErrorReport(arguments); return r; } function glVertexAttribPointer(attr, size, type, normalized, stride, pointer) { const r = gl.vertexAttribPointer(attr, size, type, normalized, stride, pointer); glErrorReport(arguments); return r; } function glEnableVertexAttribArray(index) { const r = gl.enableVertexAttribArray(index); glErrorReport(arguments); return r; } function glDrawElements(type, index_count, ele_type, indices) { const r = gl.drawElements(type, index_count, ele_type, indices); glErrorReport(arguments); return r; } function glGenTextures(count, ids_ptr, ids_size) { for (let i = 0; i < count; i++) { const tex = gl.createTexture(); glErrorReport(arguments); let new_len = glTextures.push(tex); put_u32(ids_ptr + (i * 4), new_len); } } function glBindTexture(slot, id) { let tex = gl_get_texture(id); const r = gl.bindTexture(slot, tex); glErrorReport(arguments); return r; } function glTexParameteri(slot, param, value) { const r = gl.texParameteri(slot, param, value); glErrorReport(arguments); return r; } function glTexImage2D(target, level, internalformat, width, height, border, format, type, data_ptr, data_size) { const data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, data_ptr, data_size); const r = gl.texImage2D(target, level, internalformat, width, height, border, format, type, data); glErrorReport(arguments); return r; } function glTexSubImage2D(target, level, offsetx, offsety, width, height, format, type, data_ptr, data_size) { const data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, data_ptr, data_size); const r = gl.texSubImage2D(target, level, offsetx, offsety, width, height, format, type, data); glErrorReport(arguments); return r; } function webgl_add_imports (canvas_selector, imports) { const canvas = document.querySelector(canvas_selector); if (!canvas) return console.error("no canvas"); gl = canvas.getContext("webgl2"); if (gl === null) return console.error("no webgl ctx"); imports.glHadError = () => { return gl_error; }; imports.glClearColor = glClearColor; imports.glEnable = glEnable; imports.glDisable = glDisable; imports.glBlendFunc = glBlendFunc; imports.glViewport = glViewport; imports.glDepthFunc = glDepthFunc; imports.glClear = glClear; imports.glCreateBuffer = glCreateBuffer; imports.glBindBuffer = glBindBuffer; imports.glBufferData = glBufferData; imports.glCreateShader = glCreateShader; imports.glShaderSource = glShaderSource; imports.glCompileShader = glCompileShader; imports.glCreateProgram = glCreateProgram; imports.glAttachShader = glAttachShader; imports.glLinkProgram = glLinkProgram; imports.glUseProgram = glUseProgram; imports.glGetAttribLocation = glGetAttribLocation; imports.glVertexAttribPointer = glVertexAttribPointer; imports.glEnableVertexAttribArray = glEnableVertexAttribArray; imports.glDrawElements = glDrawElements; imports.glGenTextures = glGenTextures; imports.glBindTexture = glBindTexture; imports.glTexParameteri = glTexParameteri; imports.glTexImage2D = glTexImage2D; imports.glTexSubImage2D = glTexSubImage2D; imports.glBindTexture = glBindTexture; return imports; }