working immediate mode renderer with triangles
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Mar 2021 02:32:58 +0000 (20:32 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Mar 2021 02:32:58 +0000 (20:32 -0600)
build.sh
lib/immediate_renderer.onyx
lib/shaders/immediate_fragment.glsl
lib/shaders/immediate_vertex.glsl
site/imgui.mjs [new file with mode: 0644]
site/index.html [new file with mode: 0644]
site/webgl.mjs [new file with mode: 0644]
test/basic.onyx

index f75d1e53e1c544c7ead0ee5c802a346cac15b15d..93ea467187cadc39c150569805aac7cea8768c37 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -1,3 +1,3 @@
 #!/bin/sh
 
-onyx -r js -V --use-post-mvp-features test/basic.onyx -o imgui.wasm
+onyx -r js -V --use-post-mvp-features test/basic.onyx -o site/imgui.wasm
index 5c3528d2250cb7ff91067bddd84f45ea1b0946bd..4ade840307f5840410289d06ceeb6b4e96eac52c 100644 (file)
@@ -40,6 +40,9 @@ Immediate_Renderer :: struct {
 
     clear_color : Color4;
 
+    vertex_array  : gl.GLVertexArrayObject;
+    vertex_buffer : gl.GLBuffer;
+
     // Needs to be a multiple of 3!!
     Default_Max_Verticies :: 1023;
 
@@ -54,8 +57,32 @@ Immediate_Renderer :: struct {
         vertex_source   := #file_contents "lib/shaders/immediate_vertex.glsl";
         fragment_source := #file_contents "lib/shaders/immediate_fragment.glsl";
         shader = Shader.make_from_source(vertex_source, fragment_source);
+        gl.useProgram(shader.program);
 
         verticies = memory.make_slice(Immediate_Vertex, max_verticies);
+        memory.set(verticies.data, 0, verticies.count * sizeof Immediate_Vertex);
+
+        vertex_array = gl.createVertexArray();
+        gl.bindVertexArray(vertex_array);
+        defer gl.bindVertexArray(-1);
+
+        vertex_buffer = gl.createBuffer();
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
+        gl.bufferData(gl.ARRAY_BUFFER, cast(gl.GLsizei) (max_verticies * sizeof Immediate_Vertex), gl.STREAM_DRAW);
+        
+        // Position
+        gl.enableVertexAttribArray(0);
+        gl.vertexAttribPointer(0, 2, gl.FLOAT, false, sizeof Immediate_Vertex, 0);
+
+        // Color
+        gl.enableVertexAttribArray(1);
+        gl.vertexAttribPointer(1, 4, gl.FLOAT, false, sizeof Immediate_Vertex, 2 * sizeof f32);
+
+        // Texture
+        // gl.enableVertexAttribArray(2);
+        // gl.vertexAttribPointer(2, 2, gl.FLOAT, false, sizeof Immediate_Vertex, 6 * sizeof f32);
+
+        gl.bindBuffer(gl.ARRAY_BUFFER, -1);
     }
 
     // As a small note, I love the pattern matching style of programming that
@@ -79,7 +106,12 @@ Immediate_Renderer :: struct {
     }
 
     flush :: (use ir: ^Immediate_Renderer) {
+        gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
+        gl.bufferSubData(gl.ARRAY_BUFFER, 0, .{ count = vertex_count * sizeof Immediate_Vertex, data = ~~verticies.data });
+        gl.bindBuffer(gl.ARRAY_BUFFER, -1);
+
         gl.useProgram(shader.program);
+        gl.bindVertexArray(vertex_array);
         gl.drawArrays(gl.TRIANGLES, 0, vertex_count);
 
         vertex_count = 0;
@@ -97,7 +129,7 @@ Immediate_Renderer :: struct {
 immediate_renderer : Immediate_Renderer;
 
 immediate_renderer_init :: () {
-    immediate_renderer = Immediate_Renderer.make();
+    Immediate_Renderer.init(^immediate_renderer);
 }
 
 immediate_vertex :: proc {
index 37bdf802e0a9b5c8dc17ab301ab085fe2a291064..c2186dc567b5752b645ec63a4d7b4014846b6d1f 100644 (file)
@@ -2,13 +2,10 @@
 
 precision mediump float;
 
-uniform sampler2D u_texture;
-
 in vec4 v_color;
-in vec2 v_texture;
 
 out vec4 fragColor;
 
 void main() {
-    fragColor = v_color + vec4(v_texture, 0, 0) * 0;
-}
\ No newline at end of file
+    fragColor = v_color;
+}
index e8531edec04909829363580c91b9b477cdf69cf4..c1b47e7188483c7135678fe643d92f289764afc8 100644 (file)
@@ -2,17 +2,11 @@
 
 layout(location = 0) in vec2 a_vertex;
 layout(location = 1) in vec4 a_color;
-layout(location = 2) in vec2 a_texture;
-
-uniform mat4 u_view;
-uniform mat4 u_world;
 
 out vec4 v_color;
-out vec4 v_texture;
 
 void main() {
-    gl_Position = u_view * u_world * vec4(a_vertex, 0, 1);
+    gl_Position = vec4(a_vertex, 0, 1);
 
     v_color = a_color;
-    v_texture = v_texture;
-}
\ No newline at end of file
+}
diff --git a/site/imgui.mjs b/site/imgui.mjs
new file mode 100644 (file)
index 0000000..1df95fe
--- /dev/null
@@ -0,0 +1,108 @@
+import { WebGL_Wasm } from "./webgl.mjs"
+
+let wasm_instance;
+
+function push_event_to_buffer(esp, event_size, event_kind, data) {
+    let WASM_U32 = new Uint32Array(wasm_instance.exports.memory.buffer);
+
+    if (WASM_U32[esp] >= WASM_U32[esp + 1]) {
+        console.log("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];
+    }
+}
+
+
+let event_module = {
+    setup(esp, event_size) {
+        // Indicies into a Uint32Array are not based on bytes,
+        // but on the index.
+        esp /= 4;
+
+        document.addEventListener("keydown", (ev) => {
+            if (ev.isComposing || ev.keyCode === 229) return;
+            push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode ]);
+        });
+
+        document.addEventListener("keyup", (ev) => {
+            if (ev.isComposing || ev.keyCode === 229) return;
+            push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode ]);
+        });
+
+        document.addEventListener("mousedown", (ev) => {
+            push_event_to_buffer(esp, event_size, 0x01, [ ev.clientX, ev.clientY, ev.button ]);
+        });
+
+        document.addEventListener("mouseup", (ev) => {
+            push_event_to_buffer(esp, event_size, 0x02, [ ev.clientX, ev.clientY, ev.button ]);
+        });
+
+        document.addEventListener("mousemove", (ev) => {
+            push_event_to_buffer(esp, event_size, 0x03, [ ev.clientX, ev.clientY, -1 ]);
+        });
+
+        document.addEventListener("wheel", (ev) => {
+            push_event_to_buffer(esp, event_size, 0x07, [ ev.clientX, ev.clientY, ev.deltaY >= 0 ? 0x04 : 0x03 ]);
+        });
+
+        window.addEventListener("resize", (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;
+        };
+    },
+}
+
+let import_obj = {
+    host: {
+        print_str(ptr, len) {
+            let buffer = new Uint8Array(wasm_instance.exports.memory.buffer, ptr, len);
+            let string = new TextDecoder().decode(buffer);
+            console.log(string);
+        },
+
+        exit() { debugger; },
+
+        debug() { debugger; },
+
+        start_loop() {
+            let loop = () => {
+                wasm_instance.exports.loop();
+                window.requestAnimationFrame(loop);
+            };
+
+            window.requestAnimationFrame(loop);
+        },
+    },
+
+    gl: WebGL_Wasm,
+    event: event_module,
+}
+
+window.onload = () => {
+    fetch("imgui.wasm")
+    .then(res => res.arrayBuffer())
+    .then(res => WebAssembly.instantiate(res, import_obj))
+    .then(({ module, instance }) => {
+        wasm_instance = instance
+        WebGL_Wasm.memory = wasm_instance.exports.memory
+
+        console.log(module, instance)
+
+        wasm_instance.exports._start()
+    })
+}
diff --git a/site/index.html b/site/index.html
new file mode 100644 (file)
index 0000000..e77e58e
--- /dev/null
@@ -0,0 +1,21 @@
+<html>
+    <head>
+        <title>IMGUI</title>
+
+        <style>
+        html, body, canvas {
+            margin: 0;
+            padding: 0;
+            width: 100%;
+            height: 100%;
+            overflow: hidden;
+        }
+        </style>
+
+        <script type="module" src="imgui.mjs"></script>
+    </head>
+
+    <body>
+        <canvas id="imgui-canvas">This browser does not support the Canvas API.</canvas>
+    </body>
+</html>
diff --git a/site/webgl.mjs b/site/webgl.mjs
new file mode 100644 (file)
index 0000000..1236539
--- /dev/null
@@ -0,0 +1,301 @@
+let programs = [];
+let shaders = [];
+let buffers = [];
+let framebuffers = [];
+let renderbuffers = [];
+let textures = [];
+let uniformlocs = [];
+let vertexArrays = [];
+let canvas = null;
+let gl = null;
+
+let WebGL_Wasm = {
+    memory: null,
+
+    init(name, namelen) {
+        const decoder = new TextDecoder();
+        const str = new Uint8Array(WebGL_Wasm.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;
+    },
+
+    setSize(width, height) {
+        canvas.width = width;
+        canvas.height = height;
+    },
+
+    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) {
+        if (vertexArray == -1) {
+            gl.bindVertexArray(null);
+        } else {
+            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(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.meory.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(WebGL_Wasm.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(WebGL_Wasm.memory.buffer, attachdata, attachlen);
+        gl.invalidateFramebuffer(target, attacements);
+    },
+    invalidateSubFramebuffer(target, attachdata, attachlen, x, y, width, height) {
+        const attachments = new Int32Array(WebGL_Wasm.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(WebGL_Wasm.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); },
+    shaderSource(shader, source, sourcelen) {
+        const decoder = new TextDecoder();
+        const str = new Int8Array(WebGL_Wasm.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 DataView(WebGL_Wasm.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(WebGL_Wasm.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(WebGL_Wasm.memory.buffer, valueptr, 4);
+        gl.uniformMatrix2fv(uniformlocs[loc], transpose, data);
+    },
+    uniformMatrix3(loc, transpose, valueptr) {
+        const data = new Float32Array(WebGL_Wasm.memory.buffer, valueptr, 9);
+        gl.uniformMatrix3fv(uniformlocs[loc], transpose, data);
+    },
+    uniformMatrix4(loc, transpose, valueptr) {
+        const data = new Float32Array(WebGL_Wasm.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); },
+    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); },
+};
+
+export { WebGL_Wasm };
+
index 21b38252ccfa62969a0cb97efb38f473f20b571e..a95ad5fdd2988ee1f0e4756a648d174a664883f6 100644 (file)
 use package core
 use package imgui as imgui
 use package imgui.events as events
+use package gl as gl
+
+init :: () {
+    events.init();
+
+    gl.init("imgui-canvas"); 
+    imgui.immediate_renderer_init();
+}
 
 poll_events :: () {
     use events.DomEventKind;
 
     event: events.Event;
     while events.poll(^event) do switch event.kind {
+        case Resize {
+            println("The window was resized!");
+
+            gl.setSize(event.resize.width, event.resize.height);
+            gl.viewport(0, 0, event.resize.width, event.resize.height);
+        }
+
         case MouseDown {
             println("The mouse was pressed!");
             printf("Specifically, the %i button.\n", event.mouse.button);
@@ -27,28 +42,46 @@ poll_events :: () {
     }
 }
 
+t := 0.0f
+
 update :: () {
+    t += 1.0 / 60.0;
 }
 
 draw :: () {
+    gl.clearColor(0, 0, 0, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+
     use imgui;
+    defer immediate_flush();
+
+    x := math.cos(t);
+    y := math.sin(t);
+
+    immediate_vertex(.{ 0, 0 }, color=.{ 1, 1, 1, 1 });
+    immediate_vertex(.{ x, -y });
+    immediate_vertex(.{ y, x });
 
-    immediate_vertex(.{ 0, 0 }, color=.{ 1, 0, 0, 1 });
-    immediate_vertex(.{ 1, 0 });
-    immediate_vertex(.{ 0, 1 });
+    if cast(u32) t % 2 == 0 {
+        immediate_vertex(.{ 0, 0 },     color=.{ 1, 0, 0, 1 });
+        immediate_vertex(.{ -1.0f, 0 }, color=.{ 0, 1, 0, 1 });
+        immediate_vertex(.{ 0, -1.0f }, color=.{ 0, 0, 1, 1 });
+    }
 }
 
-loop :: () {
+loop :: () -> void #export {
     poll_events();
 
     update();
     draw();
 }
 
+
 main :: (args: [] cstr) {
     println("Hey! We got here!");
 
-    events.init();
+    init();
 
-    imgui.immediate_renderer_init();
+    start_loop :: () -> void #foreign "host" "start_loop" ---
+    start_loop();
 }