From 0a675e969b53be05aceeeacac26edfb41cb7b794 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 2 Jul 2021 22:22:10 -0500 Subject: [PATCH] starting ui work --- build.sh | 17 ++- site/index.html | 26 ++++ site/js/decompiler.js | 31 +++++ site/js/js_events.js | 112 ++++++++++++++++ site/js/onyx-loader.js | 47 +++++++ site/js/webgl2.js | 291 +++++++++++++++++++++++++++++++++++++++++ src/build.onyx | 9 +- src/main.onyx | 123 ++++++++++++----- src/test_console.onyx | 57 ++++++++ 9 files changed, 675 insertions(+), 38 deletions(-) create mode 100644 site/index.html create mode 100644 site/js/decompiler.js create mode 100644 site/js/js_events.js create mode 100644 site/js/onyx-loader.js create mode 100644 site/js/webgl2.js create mode 100644 src/test_console.onyx diff --git a/build.sh b/build.sh index 714b2bf..64aa898 100755 --- a/build.sh +++ b/build.sh @@ -1,10 +1,23 @@ +#!/bin/sh +TARGET=site/analyzer.wasm ONYX_MODULE_DIRECTORY=/home/brendan/dev/c/onyx +# Copy relative javascript modules from Onyx source directory +cp "$ONYX_MODULE_DIRECTORY/bin/onyx-loader.js" ./site/js/onyx-loader.js +cp "$ONYX_MODULE_DIRECTORY/modules/webgl2/webgl2.js" ./site/js/webgl2.js +cp "$ONYX_MODULE_DIRECTORY/modules/js_events/js_events.js" ./site/js/js_events.js + FLAGS= -[ ! -z "$DEBUG" ] && FLAGS=--print-function-mappings +[ ! -z "$DEBUG" ] && FLAGS=--print-function-mappings + +RUNTIME=js +[ ! -z "$CONSOLE" ] && RUNTIME=wasi -onyx -V --no-colors $FLAGS \ +onyx --no-colors $FLAGS -r $RUNTIME \ + --use-post-mvp-features \ -I $ONYX_MODULE_DIRECTORY \ + --doc docs/source_reference \ + -o $TARGET \ src/build.onyx diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..0d1d02b --- /dev/null +++ b/site/index.html @@ -0,0 +1,26 @@ + + + Wasm-32 Decompiler + + + + + + + + + + + + This browser does not support the Canvas API. + + diff --git a/site/js/decompiler.js b/site/js/decompiler.js new file mode 100644 index 0000000..3027307 --- /dev/null +++ b/site/js/decompiler.js @@ -0,0 +1,31 @@ + +window.ONYX_MODULES = window.ONYX_MODULES || []; + +window.ONYX_MODULES.push({ + module_name: "decompiler", + + start_loop: function() { + var loop = function(dt) { + window.ONYX_INSTANCE.exports.loop(); + window.requestAnimationFrame(loop); + }; + + window.requestAnimationFrame(loop); + }, + + time_now: function() { + return Date.now(); + }, + + alert: function(strptr, strlen) { + const decoder = new TextDecoder(); + const data = new Uint8Array(window.ONYX_MEMORY.buffer, strptr, strlen); + const str = decoder.decode(data); + + window.alert(str); + }, + + refresh: function() { + window.location.reload(true); + } +}); diff --git a/site/js/js_events.js b/site/js/js_events.js new file mode 100644 index 0000000..4ff47d3 --- /dev/null +++ b/site/js/js_events.js @@ -0,0 +1,112 @@ +window.ONYX_MODULES = window.ONYX_MODULES || []; + +function push_event_to_buffer(esp, event_size, event_kind, data) { + let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer); + + if (WASM_U32[esp] >= WASM_U32[esp + 1]) { + console.log("Event buffer full!"); + return; + } + + WASM_U32[esp] += 1; + + let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2; + WASM_U32[event_idx] = event_kind; + WASM_U32[event_idx + 1] = Date.now(); + + for (let i = 0; i < data.length; i++) { + WASM_U32[event_idx + 2 + i] = data[i]; + } +} + +window.ONYX_MODULES.push({ + module_name: "js_events", + + setup: function(esp, event_size) { + // Indicies into a Uint32Array are not based on bytes, + // but on the index. + esp /= 4; + + document.addEventListener("keydown", function (ev) { + if (ev.isComposing || ev.keyCode === 229) return; + ev.preventDefault(); + + // NOTE: These modifiers need to match in js_events.onyx. + var modifiers = 0x0000; + if (ev.ctrlKey) modifiers |= 0x01; + if (ev.altKey) modifiers |= 0x02; + if (ev.metaKey) modifiers |= 0x04; + if (ev.shiftKey) modifiers |= 0x08; + + push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode, modifiers ]); + + var keyname = ev.code; + let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer); + let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2; + + let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer); + + for (var i = 0; i < keyname.length; i++) { + WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i); + } + + WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length; + return false; + }); + + document.addEventListener("keyup", function (ev) { + if (ev.isComposing || ev.keyCode === 229) return; + ev.preventDefault(); + + // NOTE: These modifiers need to match in js_events.onyx. + var modifiers = 0x0000; + if (ev.ctrlKey) modifiers |= 0x01; + if (ev.altKey) modifiers |= 0x02; + if (ev.metaKey) modifiers |= 0x04; + if (ev.shiftKey) modifiers |= 0x08; + + push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode, modifiers ]); + + var keyname = ev.code; + let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer); + let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2; + + let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer); + + for (var i = 0; i < keyname.length; i++) { + WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i); + } + + WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length; + + return false; + }); + + document.addEventListener("mousedown", function (ev) { + push_event_to_buffer(esp, event_size, 0x01, [ ev.clientX, ev.clientY, ev.button ]); + }); + + document.addEventListener("mouseup", function (ev) { + push_event_to_buffer(esp, event_size, 0x02, [ ev.clientX, ev.clientY, ev.button ]); + }); + + document.addEventListener("mousemove", function (ev) { + push_event_to_buffer(esp, event_size, 0x03, [ ev.clientX, ev.clientY, -1 ]); + }); + + document.addEventListener("wheel", function (ev) { + push_event_to_buffer(esp, event_size, 0x07, [ ev.clientX, ev.clientY, ev.deltaY >= 0 ? 0x04 : 0x03 ]); + }); + + window.addEventListener("resize", function (ev) { + push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]); + }); + + push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]); + + document.oncontextmenu = (e) => { + e.preventDefault = true; + return false; + }; + }, +}); diff --git a/site/js/onyx-loader.js b/site/js/onyx-loader.js new file mode 100644 index 0000000..a48a38a --- /dev/null +++ b/site/js/onyx-loader.js @@ -0,0 +1,47 @@ + +window.ONYX_MODULES = window.ONYX_MODULES || []; +window.ONYX_MEMORY = null; +window.ONYX_INSTANCE = null; + +window.ONYX_MODULES.push({ + module_name: "host", + + print_str: function(ptr, len) { + var buffer = new Uint8Array(ONYX_MEMORY.buffer, ptr, len); + var string = new TextDecoder().decode(buffer); + console.log(string); + }, + + exit: function() { debugger; } +}); + +function launch_onyx_program(script_path, call_start) { + fetch(script_path) + .then(function(res) { return res.arrayBuffer(); }) + .then(function(wasm_code) { + var import_object = {}; + + for (var i = 0; i < window.ONYX_MODULES.length; i++) { + import_object[window.ONYX_MODULES[i].module_name] = window.ONYX_MODULES[i]; + } + + return WebAssembly.instantiate(wasm_code, import_object); + }) + .then(function(wasm_module) { + window.ONYX_MEMORY = wasm_module.instance.exports.memory; + window.ONYX_INSTANCE = wasm_module.instance; + + wasm_module.instance.exports._start(); + }); +} + +window.onload = function() { + var script_tags = document.getElementsByTagName("script"); + + for (var i = 0; i < script_tags.length; i++) { + if (script_tags[i].getAttribute("type") == "application/onyx") { + // @ROBUSTNESS: It should be configurable which function is called on start up of a Onyx WASM module. + launch_onyx_program(script_tags[i].getAttribute("src"), true); + } + } +}; diff --git a/site/js/webgl2.js b/site/js/webgl2.js new file mode 100644 index 0000000..bd53399 --- /dev/null +++ b/site/js/webgl2.js @@ -0,0 +1,291 @@ +window.ONYX_MODULES = window.ONYX_MODULES || []; + +var programs = []; +var shaders = []; +var buffers = []; +var framebuffers = []; +var renderbuffers = []; +var textures = []; +var uniformlocs = []; +var vertexArrays = []; +var canvas = null; +var gl = null; + +window.ONYX_MODULES.push({ + module_name: "gl", + + init(name, namelen) { + const decoder = new TextDecoder(); + const str = new Uint8Array(window.ONYX_MEMORY.buffer, name, namelen); + const canvasname = decoder.decode(str); + + canvas = document.getElementById(canvasname); + if (canvas == null) return 0; + + gl = canvas.getContext("webgl2"); + if (gl == null) return 0; + + return 1; + }, + + activeTexture(texture) { gl.activeTexture(texture); }, + attachShader(program, shader) { gl.attachShader(programs[program], shaders[shader]); return programs[program]; }, + bindAttribLocation(program, index, name, namelen) { console.log("NOT IMPLEMENTED!"); }, + bindBuffer(target, buffer) { + if (buffer == -1) { + gl.bindBuffer(target, null); + } else { + gl.bindBuffer(target, buffers[buffer]); + } + }, + bindFramebuffer(target, framebuffer) { gl.bindFramebuffer(target, framebuffers[framebuffer]); }, + bindRenderbuffer(target, renderbuffer) { gl.bindRenderbuffer(target, renderbuffers[renderbuffer]); }, + bindTexture(target, texture) { gl.bindTexture(target, textures[texture]); }, + bindVertexArray(vertexArray) { gl.bindVertexArray(vertexArrays[vertexArray]); }, + + blendColor(red, green, blue, alpha) { gl.blendColor(red, green, blue, alpha); }, + blendEquation(mode) { gl.blendEquation(mode); }, + blendEquationSeparate(modeRGB, modeAlpha) { gl.blendEquationSeparate(modeRGB, modeAlpha); }, + blendFunc(sfactor, dfactor) { gl.blendFunc(sfactor, dfactor); }, + blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) { gl.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); }, + + blitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, mask, filter) { + gl.blitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1, mask, filter); + }, + + bufferDataWithData(target, bufferdata, bufferlen, usage) { + const data = new DataView(window.ONYX_MEMORY.buffer, bufferdata, bufferlen); + gl.bufferData(target, data, usage); + }, + + bufferDataNoData(target, size, usage) { gl.bufferData(target, size, usage); }, + bufferSubData(target, offset, bufferdata, bufferlen) { + const data = new DataView(window.ONYX_MEMORY.buffer, bufferdata, bufferlen); + gl.bufferSubData(target, offset, data); + }, + canvasSize(width, height) { + canvas.width = width; + canvas.height = height; + }, + checkFrameBufferStatus(target) { return gl.checkFrameBufferStatus(target); }, + clear(bit) { gl.clear(bit); }, + clearColor(r, g, b, a) { gl.clearColor(r, g, b, a); }, + clearDepth(depth) { gl.clearDepth(depth); }, + clearStencil(stencil) { gl.clearStencil(stencil); }, + colorMask(r, g, b, a) { gl.colorMask(r, g, b, a); }, + compileShader(shader) { gl.compileShader(shaders[shader]); }, + compressedTexImage2D(target, level, internalformat, width, height, border, data, datalen) { + const pixels = new DataView(window.ONYX_MEMORY.buffer, data, datalen); + gl.compressedTexImage2D(target, level, internalformat, width, height, border, pixels); + }, + compressedTexSubImage2D(target, level, internalformat, xoff, yoff, width, height, format, data, datalen) { + const pixels = new DataView(window.ONYX_MEMORY.buffer, data, datalen); + gl.compressedSubTexImage2D(target, level, internalformat, xoff, yoff, width, height, format, pixels); + }, + copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) { gl.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); }, + copyTexImage2D(target, level, internalforamt, x, y, width, height, border) { + gl.copyTexImage2D(target, level, internalforamt, x, y, width, height, border); + }, + copyTexSubImage2D(target, level, xoff, yoff, x, y, width, height) { + gl.copyTexSubImage2D(target, level, xoff, yoff, x, y, width, height); + }, + createBuffer() { + const buf = gl.createBuffer(); + if (buf == null) return -1; + + buffers.push(buf); + return buffers.length - 1; + }, + createFramebuffer() { + const buf = gl.createFramebuffer(); + if (buf == null) return -1; + + framebuffers.push(buf); + return framebuffers.length - 1; + }, + createProgram() { + const prog = gl.createProgram(); + if (prog == null) return -1; + + programs.push(prog); + return programs.length - 1; + }, + createRenderbuffer() { + const buf = gl.createRenderbuffer(); + if (buf == null) return -1; + + renderbuffers.push(buf); + return renderbuffers.length - 1; + }, + createShader(type) { + const shader = gl.createShader(type); + if (shader == null) return -1; + + shaders.push(shader); + return shaders.length - 1; + }, + createTexture() { + const texture = gl.createTexture(); + if (texture == null) return -1; + + textures.push(texture); + return textures.length - 1; + }, + createVertexArray() { + const vao = gl.createVertexArray(); + if (vao == null) return -1; + + vertexArrays.push(vao); + return vertexArrays.length - 1; + }, + cullFace(mode) { gl.cullFace(mode); }, + deleteBuffer(buffer) { gl.deleteBuffer(buffers[buffer]); }, + deleteFramebuffer(framebuffer) { gl.deleteFramebuffer(framebuffers[framebuffer]); }, + deleteProgram(program) { gl.deleteProgram(programs[program]); }, + deleteRenderbuffer(renderbuffer) { gl.deleteRenderbuffer(renderbuffers[renderbuffer]); }, + deleteShader(shader) { gl.deleteShader(shaders[shader]); }, + deleteTexture(texture) { gl.deleteTexture(textures[texture]); }, + deleteVertexArray(vertexArray) { gl.deleteVertexArray(vertexArrays[vertexArray]); }, + depthFunc(func) { gl.depthFunc(func); }, + depthMask(flag) { gl.depthMask(flag); }, + depthRange(znear, zfar) { gl.depthRange(znear, zfar); }, + detachShader(program, shader) { gl.detachShader(programs[program], shaders[shader]); }, + disable(cap) { gl.disable(cap); }, + disableVertexAttribArray(index) { gl.disableVertexAttribArray(index); }, + drawArrays(mode, first, count) { gl.drawArrays(mode, first, count); }, + drawArraysInstanced(mode, first, count, instanceCount) { gl.drawArraysInstanced(mode, first, count, instanceCount); }, + drawElements(mode, count, type, offset) { gl.drawElements(mode, count, type, offset); }, + drawElementsInstanced(mode, count, type, offset, instanceCount) { gl.drawElementsInstanced(mode, count, type, offset, instanceCount); }, + enable(cap) { gl.enable(cap); }, + enableVertexAttribArray(index) { gl.enableVertexAttribArray(index); }, + finish() { gl.finish(); }, + flush() { gl.flush(); }, + framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer) { + gl.framebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffers[renderbuffer]); + }, + framebufferTexture2D(target, attachment, texttarget, texture, level) { + gl.framebufferTexture2D(target, attachment, texttarget, textures[texture], level); + }, + framebufferTextureLayer(target, attachment, texture, level, layer) { gl.framebufferTextureLayer(target, attachment, textures[texture], level, layer); }, + frontFace(mode) { gl.frontFace(mode); }, + generateMipmap(target) { gl.generateMipmap(target); }, + getActiveAttrib(program, index, out) { + const loc = gl.getActiveAttrib(programs[program], index); + const data = new Int32Array(window.ONYX_MEMORY.buffer, out, 2); + data[0] = loc.size; + data[1] = loc.type; + }, + getActiveUniform(program, index, out) { + const loc = gl.getActiveUniform(programs[program], index); + const data = new Int32Array(window.ONYX_MEMORY.buffer, out, 2); + data[0] = loc.size; + data[1] = loc.type; + }, + // getAttachedShaders() { console.log("NOT IMPLEMENTED!"); }, + getAttribLocation(program, name, namelen) { + const decoder = new TextDecoder(); + const str = new Uint8Array(window.ONYX_MEMORY.buffer, name, namelen); + const attribname = decoder.decode(str); + + return gl.getAttribLocation(programs[program], attribname); + }, + // getBufferParameter() { console.log("NOT IMPLEMENTED!"); }, + getBufferSubData(target, srcbyteoffset, dstbufferdata, dstbufferlen, dstoffset, length) { + const dst = new DataView(window.ONYX_MEMORY.buffer, dstbufferdata, dstbufferlen); + gl.getBufferSubData(target, srcbyteoffset, dst, dstoffset, length); + }, + getError() { return gl.getError(); }, + getInternalformatParameter(target, internalformat, pname) { return gl.getInternalformatParameter(target, internalformat, pname); }, + // many of the 'gets() { console.log("NOT IMPLEMENTED!"); }, + getShaderParameter(shader, param) { return gl.getShaderParameter(shaders[shader], param); }, + getProgramParameter(program, param) { return gl.getProgramParameter(programs[program], param); }, + getUniformLocation(program, name, namelen) { + const decoder = new TextDecoder(); + const str = new Int8Array(window.ONYX_MEMORY.buffer, name, namelen); + const uniname = decoder.decode(str); + + uniformlocs.push(gl.getUniformLocation(programs[program], uniname)); + return uniformlocs.length - 1; + }, + getVertexAttribOffset(index, pname) { return gl.getVertexAttribOffset(index, pname); }, + hint(target, mode) { gl.hint(target, mode); }, + isEnabled(cap) { return gl.isEnabled(cap); }, + invalidateFramebuffer(target, attachdata, attachlen) { + const attachments = new Int32Array(window.ONYX_MEMORY.buffer, attachdata, attachlen); + gl.invalidateFramebuffer(target, attacements); + }, + invalidateSubFramebuffer(target, attachdata, attachlen, x, y, width, height) { + const attachments = new Int32Array(window.ONYX_MEMORY.buffer, attachdata, attachlen); + gl.invalidateFramebuffer(target, attacements, x, y, width, height); + }, + lineWidth(width) { gl.lineWidth(width); }, + linkProgram(program) { gl.linkProgram(programs[program]); }, + pixelStorei(pname, param) { gl.pixelStorei(pname, param); }, + polygonOffset(factor, units) { gl.polygonOffset(factor, units); }, + printProgramInfoLog(program) { console.log(gl.getProgramInfoLog(programs[program])); }, + printShaderInfoLog(shader) { console.log(gl.getShaderInfoLog(shaders[shader])); }, + readPixels(x, y, width, height, format, type, pixels, pixelslen) { + const pixeldata = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen); + gl.readPixels(x, y, width, height, format, type, pixeldata); + }, + readBuffer(src) { gl.readBuffer(src); }, + renderbufferStorageMultisample(target, samples, internalforamt, width, height) { + gl.renderbufferStorageMultisample(target, samples, internalforamt, width, height); + }, + sampleCoverage(value, invert) { gl.sampleCoverage(value, invert); }, + scissor(x, y, width, height) { gl.scissor(x, y, width, height); }, + setSize(width, height) { canvas.width = width; canvas.height = height; }, + shaderSource(shader, source, sourcelen) { + const decoder = new TextDecoder(); + const str = new Int8Array(window.ONYX_MEMORY.buffer, source, sourcelen); + const sourcedata = decoder.decode(str); + + gl.shaderSource(shaders[shader], sourcedata); + }, + stencilFunc(func, ref, mask) { gl.stencilFunc(func, ref, mask); }, + stencilFuncSeparate(face, func, ref, mask) { gl.stencilFuncSeparate(face, func, ref, mask); }, + stencilMask(mask) { gl.stencilMask(mask); }, + stencilMaskSeparate(face, mask) { gl.stencilMaskSeparate(face, mask); }, + stencilOp(fail, zfail, mask) { gl.stencilOp(fail, zfail, mask); }, + stencilOpSeparate(face, fail, zfail, zpass) { gl.stencilOpSeparate(face, fail, zfail, zpass); }, + texImage2D(target, level, internalforamt, width, height, border, format, type, pixels, pixelslen) { + const data = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen); + gl.texImage2D(target, level, internalforamt, width, height, border, format, type, data); + }, + texParameterf(target, pname, param) { gl.texParameterf(target, pname, param); }, + texParameteri(target, pname, param) { gl.texParameteri(target, pname, param); }, + texSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels, pixelslen) { + const data = new Uint8Array(window.ONYX_MEMORY.buffer, pixels, pixelslen); + gl.texSubImage2D(target, level, xoff, yoff, width, height, format, type, data); + }, + uniform1f(loc, x) { gl.uniform1f(uniformlocs[loc], x); }, + uniform1i(loc, x) { gl.uniform1i(uniformlocs[loc], x); }, + uniform2f(loc, x, y) { gl.uniform2f(uniformlocs[loc], x, y); }, + uniform2i(loc, x, y) { gl.uniform2i(uniformlocs[loc], x, y); }, + uniform3f(loc, x, y, z) { gl.uniform3f(uniformlocs[loc], x, y, z); }, + uniform3i(loc, x, y, z) { gl.uniform3i(uniformlocs[loc], x, y, z); }, + uniform4f(loc, x, y, z, w) { gl.uniform4f(uniformlocs[loc], x, y, z, w); }, + uniform4i(loc, x, y, z, w) { gl.uniform4i(uniformlocs[loc], x, y, z, w); }, + uniformMatrix2(loc, transpose, valueptr) { + const data = new Float32Array(window.ONYX_MEMORY.buffer, valueptr, 4); + gl.uniformMatrix2fv(uniformlocs[loc], transpose, data); + }, + uniformMatrix3(loc, transpose, valueptr) { + const data = new Float32Array(window.ONYX_MEMORY.buffer, valueptr, 9); + gl.uniformMatrix3fv(uniformlocs[loc], transpose, data); + }, + uniformMatrix4(loc, transpose, valueptr) { + const data = new Float32Array(window.ONYX_MEMORY.buffer, valueptr, 16); + gl.uniformMatrix4fv(uniformlocs[loc], transpose, data); + }, + useProgram(program) { gl.useProgram(programs[program]); }, + validateProgram(program) { gl.validateProgram(program[program]); }, + vertexAttrib1f(idx, x) { gl.vertexAttrib1f(idx, x); }, + vertexAttrib2f(idx, x, y) { gl.vertexAttrib2f(idx, x, y); }, + vertexAttrib3f(idx, x, y, z) { gl.vertexAttrib3f(idx, x, y, z); }, + vertexAttrib4f(idx, x, y, z, w) { gl.vertexAttrib4f(idx, x, y, z, w); }, + vertexAttribIPointer(idx, size, type, stride, offset) { gl.vertexAttribIPointer(idx, size, type, stride, offset); }, + vertexAttribPointer(idx, size, type, normalized, stride, offset) { gl.vertexAttribPointer(idx, size, type, normalized, stride, offset); }, + vertexAttribDivisor(idx, divisor) { gl.vertexAttribDivisor(idx, divisor); }, + viewport(x, y, width, height) { gl.viewport(x, y, width, height); }, +}); diff --git a/src/build.onyx b/src/build.onyx index 43e4702..e11d1ad 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -7,6 +7,13 @@ #load "modules/webgl2/module" #load "modules/immediate_mode/module" #load "modules/ui/module" + #load "modules/js_events/module" + #load "modules/bmfont/module" + + #load "src/main" +} + +#if (package runtime).Runtime == (package runtime).Runtime_Wasi { + #load "src/test_console" } -#load "src/main" diff --git a/src/main.onyx b/src/main.onyx index 48635c2..bf0ad7e 100644 --- a/src/main.onyx +++ b/src/main.onyx @@ -1,53 +1,106 @@ use package core -#private_file wasm :: package wasm_utils + +#private_file events :: package js_events +#private_file gl :: package gl +#private_file gfx :: package immediate_mode +#private_file ui :: package ui main :: (args: [] cstr) { - - wasm_data := #file_contents "data/test.wasm"; - - wasm_binary := wasm.load(wasm_data); - for ^entry: wasm_binary.sections.entries { - printf("Section: {}\nOffset: {}\n", entry.key, entry.value); - } + init(); + + start_loop :: () -> void #foreign "decompiler" "start_loop" --- + start_loop(); +} + +init :: () { + gl.init("main_canvas"); + events.init(); + gfx.immediate_renderer_init(); + + ui.init_ui(); + + gl.enable(gl.BLEND); + gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); +} + +last_time := 0; +#export "loop" () { + time_now :: () -> i32 #foreign "decompiler" "time_now" --- - wasm_sections := wasm.parse_sections(^wasm_binary, context.allocator); - printf("Types:\n{p}\n", wasm_sections.type_section); - printf("Imports:\n{p}\n", wasm_sections.import_section); - printf("Exports:\n{p}\n", wasm_sections.export_section); - printf("Code:\n{}\n", wasm_sections.code_section); + if last_time == 0 do last_time = time_now(); - // type_section := wasm.parse_type_section(^wasm_binary); - // printf("Types:\n{}\n", type_section); + now := time_now(); + dt := cast(f32) (now - last_time) / 1000.0f; + last_time = now; - // import_section := wasm.parse_import_section(^wasm_binary); - // printf("Imports:\n{p}\n", import_section); + poll_events(); + update(dt); + draw(); +} + +@Temporary window_width := 0 +@Temporary window_height := 0 + +poll_events :: () { + for event: events.consume() { + switch event.kind { + case .MouseDown do switch event.mouse.button { + case .Left do ui.button_pressed(.Left); + case .Right do ui.button_pressed(.Right); + } - // export_section := wasm.parse_export_section(^wasm_binary); - // printf("Exports:\n{p}\n", export_section); + case .MouseUp do switch event.mouse.button { + case .Left do ui.button_released(.Left); + case .Right do ui.button_released(.Right); + } - // function_section := wasm.parse_function_section(^wasm_binary); - // printf("Functions:\n{p}\n", function_section); + case .MouseMove do ui.update_mouse_position(~~ event.mouse.pos_x, ~~ event.mouse.pos_y); - // start_function := wasm.parse_start_section(^wasm_binary); - // printf("Start function: {}\n", start_function); + case .KeyDown, .KeyUp { + modifiers : ui.Keyboard_State.Key_State.Modifiers; + if event.keyboard.modifiers & .CTRL do modifiers |= .CTRL; + if event.keyboard.modifiers & .ALT do modifiers |= .ALT; + if event.keyboard.modifiers & .META do modifiers |= .META; + if event.keyboard.modifiers & .SHIFT do modifiers |= .SHIFT; - // memory_section := wasm.parse_memory_section(^wasm_binary); - // printf("Memories:\n{p}\n", memory_section); + if event.kind == .KeyDown { + ui.key_down(event.keyboard.keycode, modifiers); @KeycodeIsWrong // .keycode is apparently not browser independent... - // table_section := wasm.parse_table_section(^wasm_binary); - // printf("Tables:\n{p}\n", table_section); + if event.keyboard->get_name() == "F5" { + refresh :: () -> void #foreign "decompiler" "refresh" --- + refresh(); + } - // global_section := wasm.parse_global_section(^wasm_binary); - // printf("Globals:\n{p}\n", global_section); + } else { + ui.key_up(event.keyboard.keycode, modifiers); @KeycodeIsWrong // see above + } + } - // element_section := wasm.parse_element_section(^wasm_binary); - // printf("Elements:\n{p}\n", element_section); + case .Resize { + window_width = event.resize.width; + window_height = event.resize.height; - // data_section := wasm.parse_data_section(^wasm_binary); - // for e: data_section do printf("Data: {} {} {}\n", e.memory_index, e.offset, e.data.count); + gl.setSize(event.resize.width, event.resize.height); + gl.viewport(0, 0, event.resize.width, event.resize.height); + gfx.use_ortho_projection(0, ~~window_width, 0, ~~window_height); + } + } + } +} - // code_section := wasm.parse_code_section(^wasm_binary); - // printf("Code:\n{p}\n", code_section.count); +update :: (dt: f32) { } +red := 1.0f; +draw :: () { + gl.clearColor(red, 0, 0, 1); + gl.clear(gl.COLOR_BUFFER_BIT); + + if ui.button(.{ 100, 100, 300, 200 }, "Test") { + red = math.abs(1 - red); + } + + gfx.flush(); + ui.clear_buttons(); +} diff --git a/src/test_console.onyx b/src/test_console.onyx new file mode 100644 index 0000000..3b0a60b --- /dev/null +++ b/src/test_console.onyx @@ -0,0 +1,57 @@ +#if (package runtime).Runtime != (package runtime).Runtime_Wasi { + #error "This file should only be included in the 'wasi' runtime." +} + +use package core +#private_file wasm :: package wasm_utils + +// Testing running on the console +main :: (args: [] cstr) { + + wasm_data := #file_contents "data/test.wasm"; + + wasm_binary := wasm.load(wasm_data); + for ^entry: wasm_binary.sections.entries { + printf("Section: {}\nOffset: {}\n", entry.key, entry.value); + } + + wasm_sections := wasm.parse_sections(^wasm_binary, context.allocator); + defer wasm.free_sections(^wasm_sections); + printf("Types:\n{p}\n", wasm_sections.type_section); + printf("Imports:\n{p}\n", wasm_sections.import_section); + printf("Exports:\n{p}\n", wasm_sections.export_section); + // printf("Code:\n{}\n", wasm_sections.code_section); + + // type_section := wasm.parse_type_section(^wasm_binary); + // printf("Types:\n{}\n", type_section); + + // import_section := wasm.parse_import_section(^wasm_binary); + // printf("Imports:\n{p}\n", import_section); + + // export_section := wasm.parse_export_section(^wasm_binary); + // printf("Exports:\n{p}\n", export_section); + + // function_section := wasm.parse_function_section(^wasm_binary); + // printf("Functions:\n{p}\n", function_section); + + // start_function := wasm.parse_start_section(^wasm_binary); + // printf("Start function: {}\n", start_function); + + // memory_section := wasm.parse_memory_section(^wasm_binary); + // printf("Memories:\n{p}\n", memory_section); + + // table_section := wasm.parse_table_section(^wasm_binary); + // printf("Tables:\n{p}\n", table_section); + + // global_section := wasm.parse_global_section(^wasm_binary); + // printf("Globals:\n{p}\n", global_section); + + // element_section := wasm.parse_element_section(^wasm_binary); + // printf("Elements:\n{p}\n", element_section); + + // data_section := wasm.parse_data_section(^wasm_binary); + // for e: data_section do printf("Data: {} {} {}\n", e.memory_index, e.offset, e.data.count); + + // code_section := wasm.parse_code_section(^wasm_binary); + // printf("Code:\n{p}\n", code_section.count); +} -- 2.25.1