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