starting ui work
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 3 Jul 2021 03:22:10 +0000 (22:22 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 3 Jul 2021 03:22:10 +0000 (22:22 -0500)
build.sh
site/index.html [new file with mode: 0644]
site/js/decompiler.js [new file with mode: 0644]
site/js/js_events.js [new file with mode: 0644]
site/js/onyx-loader.js [new file with mode: 0644]
site/js/webgl2.js [new file with mode: 0644]
src/build.onyx
src/main.onyx
src/test_console.onyx [new file with mode: 0644]

index 714b2bf141431b7ebcd1c0617b89095cd69e6a7f..64aa8986f765f78e1b874aae8ddc4f44a4d05613 100755 (executable)
--- 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 (file)
index 0000000..0d1d02b
--- /dev/null
@@ -0,0 +1,26 @@
+<html>
+    <head>
+        <title>Wasm-32 Decompiler</title>
+
+        <style>
+        html, body, canvas {
+            margin: 0;
+            padding: 0;
+            width: 100%;
+            height: 100%;
+            overflow: hidden;
+            background-color: black;
+        }
+        </style>
+
+        <script type="application/onyx" src="analyzer.wasm"></script>
+        <script type="text/javascript" src="js/webgl2.js"></script>
+        <script type="text/javascript" src="js/js_events.js"></script>
+        <script type="text/javascript" src="js/decompiler.js"></script>
+        <script type="text/javascript" src="js/onyx-loader.js"></script>
+    </head>
+
+    <body>
+        <canvas id="main_canvas">This browser does not support the Canvas API.</canvas>
+    </body>
+</html>
diff --git a/site/js/decompiler.js b/site/js/decompiler.js
new file mode 100644 (file)
index 0000000..3027307
--- /dev/null
@@ -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 (file)
index 0000000..4ff47d3
--- /dev/null
@@ -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 (file)
index 0000000..a48a38a
--- /dev/null
@@ -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 (file)
index 0000000..bd53399
--- /dev/null
@@ -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); },
+});
index 43e4702911fce9ee8e486c86a3f495c5af2dd67f..e11d1adae73c05f3b7b15bac8553756edf6687b1 100644 (file)
@@ -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"
index 48635c29c8c43e3d1f42a147a2b98d9fe9811e06..bf0ad7e3063e351c8a269a65cfa20ced95c3f139 100644 (file)
 
 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 (file)
index 0000000..3b0a60b
--- /dev/null
@@ -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);
+}