aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralaric <alaric@netmythos.org>2024-04-14 21:07:25 -0700
committeralaric <alaric@netmythos.org>2024-04-14 21:07:25 -0700
commit72b43b36111f21d4625dfdb33b67a963ce23bcb8 (patch)
treed39fc68ca624302b2dda6f1e8e2a5dfbaa5fa1d7
parent4c4b5a6ae33c363b0f0a21ee3de136aae99919d9 (diff)
downloadengine-72b43b36111f21d4625dfdb33b67a963ce23bcb8.tar.gz
engine-72b43b36111f21d4625dfdb33b67a963ce23bcb8.zip
Make game loading more easily applicable to a variety of web shells
-rw-r--r--build.zig1
-rw-r--r--src/engine.zig12
-rw-r--r--src/shell/engine.js126
-rw-r--r--src/shell/shell.html136
-rw-r--r--src/shell/webgl.js866
-rw-r--r--src/wasm.zig12
6 files changed, 733 insertions, 420 deletions
diff --git a/build.zig b/build.zig
index e440f75..0281a93 100644
--- a/build.zig
+++ b/build.zig
@@ -6,6 +6,7 @@ pub fn build(b: *std.Build) void {
const shell = b.addNamedWriteFiles("shell");
_ = shell.addCopyFile(.{ .path = "src/shell/shell.html" }, "index.html");
+ _ = shell.addCopyFile(.{ .path = "src/shell/engine.js" }, "engine.js");
_ = shell.addCopyFile(.{ .path = "src/shell/webgl.js" }, "webgl.js");
b.install_tls.step.dependOn(&shell.step);
diff --git a/src/engine.zig b/src/engine.zig
index bc39f55..b807326 100644
--- a/src/engine.zig
+++ b/src/engine.zig
@@ -4,6 +4,7 @@ const root = @import("root");
pub const math = @import("math.zig");
pub const webgl = @import("webgl.zig");
+pub const wasm = @import("wasm.zig");
pub const matrix = @import("matrix.zig");
pub const random = @import("random.zig");
pub const input = @import("input.zig");
@@ -14,7 +15,6 @@ comptime {
@compileError("This engine only supports wasm32-freestanding as its target");
}
- const wasm = @import("wasm.zig");
_ = wasm;
}
}
@@ -38,6 +38,8 @@ pub const Color = struct {
b: f32 = 0,
a: f32 = 1,
+ pub const black: Color = Color.fromVec(.{ 0, 0, 0, 1 });
+ pub const white: Color = Color.fromVec(.{ 1, 1, 1, 1 });
pub const red: Color = Color.fromVec(.{ 1, 0, 0, 1 });
pub const green: Color = Color.fromVec(.{ 0, 1, 0, 1 });
pub const blue: Color = Color.fromVec(.{ 0, 0, 1, 1 });
@@ -66,6 +68,14 @@ pub const Color = struct {
const out = l + (r - l) * e;
return Color.fromVec(out);
}
+
+ pub fn lerp(lhs: Color, rhs: Color, pct: f32) Color {
+ const l = lhs.toVec();
+ const r = rhs.toVec();
+ const e: @Vector(4, f32) = @splat(pct);
+ const out = l + (r - l) * e;
+ return Color.fromVec(out);
+ }
};
pub const Cursor = enum(u8) {
diff --git a/src/shell/engine.js b/src/shell/engine.js
new file mode 100644
index 0000000..31371f8
--- /dev/null
+++ b/src/shell/engine.js
@@ -0,0 +1,126 @@
+const createEngineCtx = (canvas) => {
+ this.canvas = canvas;
+ this.memory = null;
+ this.last_frame_time = Date.now();
+
+ const specialKeymaps = {
+ "Shift": 0xE000,
+ };
+
+
+ canvas.onbeforeunload = function (e) {
+ // Cancel the event
+ e.preventDefault();
+
+ // Chrome requires returnValue to be set
+ e.returnValue = 'Really want to quit the game?';
+ };
+
+ const registerInputEvents = (obj) => {
+ const canvas = this.canvas;
+ const mouseHandler = (ev) => {
+ obj.instance.exports.mouseEvent(ev.x, ev.y, ev.movementX, ev.movementY, ev.buttons);
+ };
+
+ const keyHandler = (is_pressed) => {
+ return (ev) => {
+ //TODO: Do something for special keycodes, which don't have normal codepoints
+ var codepoint = 0xFFFD;
+ const chars = new TextEncoder().encode(ev.key);
+ if (specialKeymaps[ev.key]) {
+ codepoint = specialKeymaps[ev.key];
+ } else if (chars.length <= 4) {
+ const inter = new Uint8Array(4);
+ inter.set(chars);
+ const num = new Uint32Array(inter);
+ codepoint = num[0];
+ }
+ obj.instance.exports.keyEvent(codepoint, is_pressed, ev.repeat);
+ };
+ };
+
+ canvas.oncontextmenu = (ev) => { return false; };
+ canvas.addEventListener("mousedown", mouseHandler);
+ canvas.addEventListener("mouseup", mouseHandler);
+ canvas.addEventListener("pointermove", mouseHandler);
+ canvas.addEventListener("keydown", keyHandler(true));
+ canvas.addEventListener("keyup", keyHandler(false));
+ };
+
+ this.writeString = (str, pointer, length) => {
+ if (!memory) {
+ return null;
+ }
+
+ const l = Math.min(length, str.length);
+ const from = new TextEncoder().encode(str.slice(0, l));
+ const to = new Uint8Array(memory.buffer, pointer, length);
+ to.set(from);
+ return l;
+ };
+
+ this.readString = (pointer, length) => {
+ if (!memory) {
+ return null;
+ }
+
+ // Memory in WASM is one big buffer. We can read a string from the
+ // Zig/WASM space if we know the pointer and length.
+ return new TextDecoder().decode(
+ new Uint8Array(memory.buffer, pointer, length),
+ );
+ };
+
+ const rand = () => {
+ return Math.random();
+ };
+
+ const consoleLog = (ptr, len) => {
+ console.log(this.readString(ptr, len));
+ }
+
+ const cursors = {
+ 0: "default",
+ 1: "grab",
+ 2: "grabbing",
+ };
+ const setCursor = (c_idx) => {
+ const c = cursors[c_idx];
+ if (c) {
+ canvas.style.cursor = c;
+ }
+ };
+
+ const webgl = createWebglBindings(this, canvas);
+
+ this.importObject = {
+ env: {
+ ...webgl,
+ consoleLog,
+ rand,
+ setCursor,
+ },
+ };
+
+ this.wasmCallback = (obj) => {
+ this.memory = obj.instance.exports.memory;
+ registerInputEvents(obj);
+ obj.instance.exports.init();
+
+ const update = obj.instance.exports.update;
+ function step() {
+ const canvas_style = window.getComputedStyle(canvas);
+ canvas.width = parseFloat(canvas_style.getPropertyValue("width"));
+ canvas.height = parseFloat(canvas_style.getPropertyValue("height"));
+ const time = Date.now();
+ const elapsed = time - this.last_frame_time;
+ update(elapsed / 1000);
+ this.last_frame_time = time;
+ window.requestAnimationFrame(step);
+ }
+
+ window.requestAnimationFrame(step);
+ };
+ return this;
+};
+
diff --git a/src/shell/shell.html b/src/shell/shell.html
index d0faf3a..69d4448 100644
--- a/src/shell/shell.html
+++ b/src/shell/shell.html
@@ -27,139 +27,13 @@
<body>
<canvas id="app-canvas" tabindex="0"></canvas>
<script src="webgl.js"></script>
+ <script src="engine.js"></script>
<script>
- let memory = null;
- let last_frame_time = Date.now();
+ const canvas = document.getElementById("app-canvas");
+ const engineCtx = createEngineCtx(canvas);
- const writeString = (str, pointer, length) => {
- if (!memory) {
- return null;
- }
-
- const l = Math.min(length, str.length);
- const from = new TextEncoder().encode(str.slice(0, l));
- const to = new Uint8Array(memory.buffer, pointer, length);
- to.set(from);
- return l;
- };
-
- const readString = (pointer, length) => {
- if (!memory) {
- return null;
- }
-
- // Memory in WASM is one big buffer. We can read a string from the
- // Zig/WASM space if we know the pointer and length.
- return new TextDecoder().decode(
- new Uint8Array(memory.buffer, pointer, length),
- );
- };
-
-
- const consoleLog = (ptr, len) => {
- console.log(readString(ptr, len));
- }
-
- const rand = () => {
- return Math.random();
- };
-
- const loadTexture = (ptr, len, tex_id, ret_ptr) => {
- const path = readString(ptr, len);
- var image = new Image();
- image.src = path;
- console.log("loading ", path);
- image.addEventListener('load', function() {
- const ret_list = new Uint32Array(memory.buffer, ret_ptr, 3);
- ret_list[0] = 1;
- ret_list[1] = image.width;
- ret_list[2] = image.height;
- console.log(path, " loaded");
- const tex = glTextures.get(tex_id);
- gfx_ctx.bindTexture(gfx_ctx.TEXTURE_2D, tex);
- gfx_ctx.texImage2D(gfx_ctx.TEXTURE_2D, 0, gfx_ctx.RGBA, gfx_ctx.RGBA, gfx_ctx.UNSIGNED_BYTE, image);
- gfx_ctx.generateMipmap(gfx_ctx.TEXTURE_2D);
- });
- };
-
- canvas.onbeforeunload = function (e) {
- // Cancel the event
- e.preventDefault();
-
- // Chrome requires returnValue to be set
- e.returnValue = 'Really want to quit the game?';
- };
-
- const cursors = {
- 0: "default",
- 1: "grab",
- 2: "grabbing",
- };
- const setCursor = (c_idx) => {
- const c = cursors[c_idx];
- if (c) {
- canvas.style.cursor = c;
- }
- };
-
- const importObject = {
- env: {
- ...webgl,
- consoleLog,
- rand,
- loadTexture,
- setCursor,
- },
- };
-
- const registerInputEvents = (obj) => {
- const mouseHandler = (ev) => {
- obj.instance.exports.mouseEvent(ev.x, ev.y, ev.movementX, ev.movementY, ev.buttons);
- };
-
- const keyHandler = (is_pressed) => {
- return (ev) => {
- //TODO: Do something for special keycodes, which don't have normal codepoints
- var codepoint = 0xFFFD;
- if (ev.key.length <= 4) {
- const chars = new TextEncoder().encode(ev.key);
- const inter = new Uint8Array(4);
- inter.set(chars);
- const num = new Uint32Array(inter);
- codepoint = num[0];
- }
- obj.instance.exports.keyEvent(codepoint, is_pressed, ev.repeat);
- };
- };
-
- canvas.oncontextmenu = (ev) => { return false; };
- canvas.addEventListener("mousedown", mouseHandler);
- canvas.addEventListener("mouseup", mouseHandler);
- canvas.addEventListener("pointermove", mouseHandler);
- canvas.addEventListener("keydown", keyHandler(true));
- canvas.addEventListener("keyup", keyHandler(false));
- };
-
- WebAssembly.instantiateStreaming(fetch("bin/game.wasm"), importObject).then(
- (obj) => {
- memory = obj.instance.exports.memory;
- registerInputEvents(obj);
- obj.instance.exports.init();
-
- const update = obj.instance.exports.update;
- function step() {
- const canvas_style = window.getComputedStyle(canvas);
- canvas.width = parseFloat(canvas_style.getPropertyValue("width"));
- canvas.height = parseFloat(canvas_style.getPropertyValue("height"));
- const time = Date.now();
- const elapsed = time - last_frame_time;
- update(elapsed / 1000);
- last_frame_time = time;
- window.requestAnimationFrame(step);
- }
-
- window.requestAnimationFrame(step);
- }
+ WebAssembly.instantiateStreaming(fetch("bin/game.wasm"), engineCtx.importObject).then(
+ engineCtx.wasmCallback
);
</script>
</body>
diff --git a/src/shell/webgl.js b/src/shell/webgl.js
index 49b864c..f58ba03 100644
--- a/src/shell/webgl.js
+++ b/src/shell/webgl.js
@@ -1,288 +1,578 @@
-const canvas = document.getElementById("app-canvas");
-const gfx_ctx = canvas.getContext("webgl2");
-if (gfx_ctx === null) {
- alert("There was a problem initializing WebGL. Your browser or machine may not support it.");
-}
-
-let next_id = 0;
-const getId = () => {
- next_id += 1;
- return next_id - 1;
-};
-
-const glBuffers = new Map();
-const glShaders = new Map();
-const glPrograms = new Map();
-const glVertexArrays = new Map();
-const glUniformLocations = new Map();
-const glTextures = new Map();
-
-const attachShader = (program_id, shader_id) => {
- const program = glPrograms.get(program_id);
- const shader = glShaders.get(shader_id);
- gfx_ctx.attachShader(program, shader);
-};
-
-const blendFunc = (sfactor, dfactor) => {
- gfx_ctx.blendFunc(sfactor, dfactor);
-};
-
-const bindBuffer = (target, id) => {
- gfx_ctx.bindBuffer(target, glBuffers.get(id));
-};
-
-const bufferData = (target, ptr, len, usage) => {
- const floats = new Float32Array(memory.buffer, ptr, len);
- gfx_ctx.bufferData(target, floats, usage);
-};
-
-const bindVertexArray = (vao) => {
- gfx_ctx.bindVertexArray(glVertexArrays.get(vao));
-};
-
-const createVertexArray = () => {
- const id = getId();
- glVertexArrays.set(id, gfx_ctx.createVertexArray());
- return id;
-};
-
-const clearColor = (r, g, b, a) => {
- gfx_ctx.clearColor(r, g, b, a);
-};
-
-const clear = (mask) => {
- gfx_ctx.clear(mask);
-};
-
-const createBuffer = () => {
- const id = getId();
- glBuffers.set(id, gfx_ctx.createBuffer());
- return id;
-};
-
-const createShader = (type) => {
- const id = getId();
- glShaders.set(id, gfx_ctx.createShader(type));
- return id;
-};
-
-const compileShader = (shader) => {
- gfx_ctx.compileShader(glShaders.get(shader));
-};
-
-const createProgram = (type) => {
- const id = getId();
- glPrograms.set(id, gfx_ctx.createProgram());
- return id;
-};
-
-const deleteShader = (shader) => {
- gfx_ctx.deleteShader(glShaders.get(shader));
-};
-
-const deleteProgram = (program) => {
- gfx_ctx.deleteProgram(glPrograms.get(program));
-};
-
-const enable = (cap) => {
- gfx_ctx.enable(cap);
-};
-
-
-const enableVertexAttribArray = (attrib_location) => {
- gfx_ctx.enableVertexAttribArray(attrib_location);
-};
-
-const getShaderParameter = (shader, info) => {
- return gfx_ctx.getShaderParameter(glShaders.get(shader), info);
-};
-
-const getShaderInfoLog = (shader, ptr, len) => {
- const msg = gfx_ctx.getShaderInfoLog(glShaders.get(shader));
- const r = writeString(msg, ptr, len);
- return r;
-};
-
-const getProgramParameter = (program_id, info) => {
- const program = glPrograms.get(program_id);
- return gfx_ctx.getProgramParameter(program, info);
-};
-
-const getProgramInfoLog = (program, ptr, len) => {
- const msg = gfx_ctx.getProgramInfoLog(glPrograms.get(program));
- const r = writeString(msg, ptr, len);
- return r;
-};
-
-const getAttribLocation = (program, ptr, len) => {
- const attrib = readString(ptr, len);
- return gfx_ctx.getAttribLocation(glPrograms.get(program), attrib);
-};
-
-const getUniformLocation = (program, ptr, len) => {
- const uniform = readString(ptr, len);
- const loc = gfx_ctx.getUniformLocation(glPrograms.get(program), uniform);
- if (!loc) console.log("Uniform ", uniform, " could not be found");
- if (!loc) return -1;
-
- const id = getId();
- glUniformLocations.set(id, loc);
- return id;
-};
-
-const linkProgram = (program) => {
- gfx_ctx.linkProgram(glPrograms.get(program));
-};
-
-const shaderSource = (shader, ptr, len) => {
- const source = readString(ptr, len);
- gfx_ctx.shaderSource(glShaders.get(shader), source);
-};
-
-const useProgram = (prog) => {
- gfx_ctx.useProgram(glPrograms.get(prog));
-};
-
-const uniform1i = (location, v0) => {
- gfx_ctx.uniform1i(glUniformLocations.get(location), v0);
-};
-
-const uniform1f = (location, v0) => {
- gfx_ctx.uniform1f(glUniformLocations.get(location), v0);
-};
-
-const uniform2i = (location, v0, v1) => {
- gfx_ctx.uniform2i(glUniformLocations.get(location), v0, v1);
-};
-
-const uniform2f = (location, v0, v1) => {
- gfx_ctx.uniform2f(glUniformLocations.get(location), v0, v1);
-};
-
-const uniform3f = (location, v0, v1, v2) => {
- gfx_ctx.uniform3f(glUniformLocations.get(location), v0, v1, v2);
-};
-
-const uniform4f = (location, v0, v1, v2, v3) => {
- gfx_ctx.uniform4f(glUniformLocations.get(location), v0, v1, v2, v3);
-};
-
-const uniformMatrix3fv = (location, ptr) => {
- const u = glUniformLocations.get(location);
- const floats = new Float32Array(memory.buffer, ptr, 9);
-
- gfx_ctx.uniformMatrix3fv(glUniformLocations.get(location), false, floats);
-};
-
-const uniformMatrix4fv = (location, ptr) => {
- const u = glUniformLocations.get(location);
- const floats = new Float32Array(memory.buffer, ptr, 16);
-
- gfx_ctx.uniformMatrix4fv(glUniformLocations.get(location), false, floats);
-};
-
-const vertexAttribPointer = (loc, size, type, normalize, stride, offset) => {
- gfx_ctx.vertexAttribPointer(loc, size, type, normalize, stride, offset);
-};
-
-const viewport = (x, y, width, height) => {
- gfx_ctx.viewport(x, y, width, height);
-};
-
-const drawArrays = (mode, first, count) => {
- gfx_ctx.drawArrays(mode, first, count);
-};
-
-const createTexture = () => {
- const id = getId();
- glTextures.set(id, gfx_ctx.createTexture());
- return id;
-};
-
-const bindTexture = (target, tex_id) => {
- const texture = glTextures.get(tex_id);
- gfx_ctx.bindTexture(target, texture);
-};
-
-const texImage2D = (target, level, interal_format,
- width, height, border, format,
- data_type, ptr, count, offset) => {
- const data = new Uint8Array(memory.buffer, ptr, count);
- gfx_ctx.texImage2D(target, level, interal_format, width, height, border, format, data_type, data, offset);
-};
-
-const activeTexture = (tex_id) => {
- gfx_ctx.activeTexture(tex_id);
-};
-
-const vertexAttribDivisor = (loc, divisor) => {
- gfx_ctx.vertexAttribDivisor(loc, divisor);
-};
-
-const drawArraysInstanced = (mode, first, count, instanceCount) => {
- gfx_ctx.drawArraysInstanced(mode, first, count, instanceCount);
-};
-
-const getScreenWidth = () => {
- return gfx_ctx.drawingBufferWidth;
-};
-
-const getScreenHeight = () => {
- return gfx_ctx.drawingBufferHeight;
-};
-
-const webgl = {
- bindBuffer,
- blendFunc,
- bufferData,
-
- createShader,
- clear,
- clearColor,
- createBuffer,
-
- enable,
-
- shaderSource,
- compileShader,
- getShaderParameter,
- deleteShader,
- getShaderInfoLog,
-
- createProgram,
- deleteProgram,
- attachShader,
- linkProgram,
- getProgramParameter,
- getProgramInfoLog,
- useProgram,
-
- getAttribLocation,
- getUniformLocation,
- createVertexArray,
- bindVertexArray,
- enableVertexAttribArray,
- vertexAttribPointer,
- viewport,
- drawArrays,
-
- uniform1i,
- uniform1f,
- uniform2i,
- uniform2f,
- uniform3f,
- uniform4f,
- uniformMatrix3fv,
- uniformMatrix4fv,
-
- createTexture,
- bindTexture,
- texImage2D,
- activeTexture,
-
- vertexAttribDivisor,
- drawArraysInstanced,
-
- getScreenWidth,
- getScreenHeight,
-};
+const createWebglBindings = (engine, canvas) => {
+ const gfx_ctx = canvas.getContext("webgl2");
+ if (gfx_ctx === null) {
+ alert("There was a problem initializing WebGL. Your browser or machine may not support it.");
+ }
+
+ let next_id = 0;
+ const getId = () => {
+ next_id += 1;
+ return next_id - 1;
+ };
+
+ const glBuffers = new Map();
+ const glShaders = new Map();
+ const glPrograms = new Map();
+ const glVertexArrays = new Map();
+ const glUniformLocations = new Map();
+ const glTextures = new Map();
+
+ const attachShader = (program_id, shader_id) => {
+ const program = glPrograms.get(program_id);
+ const shader = glShaders.get(shader_id);
+ gfx_ctx.attachShader(program, shader);
+ };
+
+ const blendFunc = (sfactor, dfactor) => {
+ gfx_ctx.blendFunc(sfactor, dfactor);
+ };
+
+ const bindBuffer = (target, id) => {
+ gfx_ctx.bindBuffer(target, glBuffers.get(id));
+ };
+
+ const bufferData = (target, ptr, len, usage) => {
+ const floats = new Float32Array(memory.buffer, ptr, len);
+ gfx_ctx.bufferData(target, floats, usage);
+ };
+
+ const bindVertexArray = (vao) => {
+ gfx_ctx.bindVertexArray(glVertexArrays.get(vao));
+ };
+
+ const createVertexArray = () => {
+ const id = getId();
+ glVertexArrays.set(id, gfx_ctx.createVertexArray());
+ return id;
+ };
+
+ const clearColor = (r, g, b, a) => {
+ gfx_ctx.clearColor(r, g, b, a);
+ };
+
+ const clear = (mask) => {
+ gfx_ctx.clear(mask);
+ };
+
+ const createBuffer = () => {
+ const id = getId();
+ glBuffers.set(id, gfx_ctx.createBuffer());
+ return id;
+ };
+
+ const createShader = (type) => {
+ const id = getId();
+ glShaders.set(id, gfx_ctx.createShader(type));
+ return id;
+ };
+
+ const compileShader = (shader) => {
+ gfx_ctx.compileShader(glShaders.get(shader));
+ };
+
+ const createProgram = (type) => {
+ const id = getId();
+ glPrograms.set(id, gfx_ctx.createProgram());
+ return id;
+ };
+
+ const deleteShader = (shader) => {
+ gfx_ctx.deleteShader(glShaders.get(shader));
+ };
+
+ const deleteProgram = (program) => {
+ gfx_ctx.deleteProgram(glPrograms.get(program));
+ };
+
+ const enable = (cap) => {
+ gfx_ctx.enable(cap);
+ };
+
+
+ const enableVertexAttribArray = (attrib_location) => {
+ gfx_ctx.enableVertexAttribArray(attrib_location);
+ };
+
+ const getShaderParameter = (shader, info) => {
+ return gfx_ctx.getShaderParameter(glShaders.get(shader), info);
+ };
+
+ const getShaderInfoLog = (shader, ptr, len) => {
+ const msg = gfx_ctx.getShaderInfoLog(glShaders.get(shader));
+ const r = engine.writeString(msg, ptr, len);
+ return r;
+ };
+
+ const getProgramParameter = (program_id, info) => {
+ const program = glPrograms.get(program_id);
+ return gfx_ctx.getProgramParameter(program, info);
+ };
+
+ const getProgramInfoLog = (program, ptr, len) => {
+ const msg = gfx_ctx.getProgramInfoLog(glPrograms.get(program));
+ const r = engine.writeString(msg, ptr, len);
+ return r;
+ };
+
+ const getAttribLocation = (program, ptr, len) => {
+ const attrib = engine.readString(ptr, len);
+ return gfx_ctx.getAttribLocation(glPrograms.get(program), attrib);
+ };
+
+ const getUniformLocation = (program, ptr, len) => {
+ const uniform = engine.readString(ptr, len);
+ const loc = gfx_ctx.getUniformLocation(glPrograms.get(program), uniform);
+ if (!loc) console.log("Uniform ", uniform, " could not be found");
+ if (!loc) return -1;
+
+ const id = getId();
+ glUniformLocations.set(id, loc);
+ return id;
+ };
+
+ const linkProgram = (program) => {
+ gfx_ctx.linkProgram(glPrograms.get(program));
+ };
+
+ const shaderSource = (shader, ptr, len) => {
+ const source = engine.readString(ptr, len);
+ gfx_ctx.shaderSource(glShaders.get(shader), source);
+ };
+
+ const useProgram = (prog) => {
+ gfx_ctx.useProgram(glPrograms.get(prog));
+ };
+
+ const uniform1i = (location, v0) => {
+ gfx_ctx.uniform1i(glUniformLocations.get(location), v0);
+ };
+
+ const uniform1f = (location, v0) => {
+ gfx_ctx.uniform1f(glUniformLocations.get(location), v0);
+ };
+
+ const uniform2i = (location, v0, v1) => {
+ gfx_ctx.uniform2i(glUniformLocations.get(location), v0, v1);
+ };
+
+ const uniform2f = (location, v0, v1) => {
+ gfx_ctx.uniform2f(glUniformLocations.get(location), v0, v1);
+ };
+
+ const uniform3f = (location, v0, v1, v2) => {
+ gfx_ctx.uniform3f(glUniformLocations.get(location), v0, v1, v2);
+ };
+
+ const uniform4f = (location, v0, v1, v2, v3) => {
+ gfx_ctx.uniform4f(glUniformLocations.get(location), v0, v1, v2, v3);
+ };
+
+ const uniformMatrix3fv = (location, ptr) => {
+ const u = glUniformLocations.get(location);
+ const floats = new Float32Array(memory.buffer, ptr, 9);
+
+ gfx_ctx.uniformMatrix3fv(glUniformLocations.get(location), false, floats);
+ };
+
+ const uniformMatrix4fv = (location, ptr) => {
+ const u = glUniformLocations.get(location);
+ const floats = new Float32Array(memory.buffer, ptr, 16);
+
+ gfx_ctx.uniformMatrix4fv(glUniformLocations.get(location), false, floats);
+ };
+
+ const vertexAttribPointer = (loc, size, type, normalize, stride, offset) => {
+ gfx_ctx.vertexAttribPointer(loc, size, type, normalize, stride, offset);
+ };
+
+ const viewport = (x, y, width, height) => {
+ gfx_ctx.viewport(x, y, width, height);
+ };
+
+ const drawArrays = (mode, first, count) => {
+ gfx_ctx.drawArrays(mode, first, count);
+ };
+
+ const createTexture = () => {
+ const id = getId();
+ glTextures.set(id, gfx_ctx.createTexture());
+ return id;
+ };
+
+ const bindTexture = (target, tex_id) => {
+ const texture = glTextures.get(tex_id);
+ gfx_ctx.bindTexture(target, texture);
+ };
+
+ const texImage2D = (target, level, interal_format,
+ width, height, border, format,
+ data_type, ptr, count, offset) => {
+ const data = new Uint8Array(memory.buffer, ptr, count);
+ gfx_ctx.texImage2D(target, level, interal_format, width, height, border, format, data_type, data, offset);
+ };
+
+ const activeTexture = (tex_id) => {
+ gfx_ctx.activeTexture(tex_id);
+ };
+
+ const vertexAttribDivisor = (loc, divisor) => {
+ gfx_ctx.vertexAttribDivisor(loc, divisor);
+ };
+
+ const drawArraysInstanced = (mode, first, count, instanceCount) => {
+ gfx_ctx.drawArraysInstanced(mode, first, count, instanceCount);
+ };
+
+ const getScreenWidth = () => {
+ return gfx_ctx.drawingBufferWidth;
+ };
+
+ const getScreenHeight = () => {
+ return gfx_ctx.drawingBufferHeight;
+ };
+
+ return {
+ bindBuffer,
+ blendFunc,
+ bufferData,
+
+ createShader,
+ clear,
+ clearColor,
+ createBuffer,
+
+ enable,
+
+ shaderSource,
+ compileShader,
+ getShaderParameter,
+ deleteShader,
+ getShaderInfoLog,
+
+ createProgram,
+ deleteProgram,
+ attachShader,
+ linkProgram,
+ getProgramParameter,
+ getProgramInfoLog,
+ useProgram,
+
+ getAttribLocation,
+ getUniformLocation,
+ createVertexArray,
+ bindVertexArray,
+ enableVertexAttribArray,
+ vertexAttribPointer,
+ viewport,
+ drawArrays,
+
+ uniform1i,
+ uniform1f,
+ uniform2i,
+ uniform2f,
+ uniform3f,
+ uniform4f,
+ uniformMatrix3fv,
+ uniformMatrix4fv,
+
+ createTexture,
+ bindTexture,
+ texImage2D,
+ activeTexture,
+
+ vertexAttribDivisor,
+ drawArraysInstanced,
+
+ getScreenWidth,
+ getScreenHeight,
+ };
+};
+
+//const canvas = document.getElementById("app-canvas");
+//const gfx_ctx = canvas.getContext("webgl2");
+//if (gfx_ctx === null) {
+ // alert("There was a problem initializing WebGL. Your browser or machine may not support it.");
+ //}
+//
+ //let next_id = 0;
+//const getId = () => {
+ // next_id += 1;
+ // return next_id - 1;
+ //};
+//
+ //const glBuffers = new Map();
+//const glShaders = new Map();
+//const glPrograms = new Map();
+//const glVertexArrays = new Map();
+//const glUniformLocations = new Map();
+//const glTextures = new Map();
+//
+ //const attachShader = (program_id, shader_id) => {
+ // const program = glPrograms.get(program_id);
+ // const shader = glShaders.get(shader_id);
+ // gfx_ctx.attachShader(program, shader);
+ //};
+//
+ //const blendFunc = (sfactor, dfactor) => {
+ // gfx_ctx.blendFunc(sfactor, dfactor);
+ //};
+//
+ //const bindBuffer = (target, id) => {
+ // gfx_ctx.bindBuffer(target, glBuffers.get(id));
+ //};
+//
+ //const bufferData = (target, ptr, len, usage) => {
+ // const floats = new Float32Array(memory.buffer, ptr, len);
+ // gfx_ctx.bufferData(target, floats, usage);
+ //};
+//
+ //const bindVertexArray = (vao) => {
+ // gfx_ctx.bindVertexArray(glVertexArrays.get(vao));
+ //};
+//
+ //const createVertexArray = () => {
+ // const id = getId();
+ // glVertexArrays.set(id, gfx_ctx.createVertexArray());
+ // return id;
+ //};
+//
+ //const clearColor = (r, g, b, a) => {
+ // gfx_ctx.clearColor(r, g, b, a);
+ //};
+//
+ //const clear = (mask) => {
+ // gfx_ctx.clear(mask);
+ //};
+//
+ //const createBuffer = () => {
+ // const id = getId();
+ // glBuffers.set(id, gfx_ctx.createBuffer());
+ // return id;
+ //};
+//
+ //const createShader = (type) => {
+ // const id = getId();
+ // glShaders.set(id, gfx_ctx.createShader(type));
+ // return id;
+ //};
+//
+ //const compileShader = (shader) => {
+ // gfx_ctx.compileShader(glShaders.get(shader));
+ //};
+//
+ //const createProgram = (type) => {
+ // const id = getId();
+ // glPrograms.set(id, gfx_ctx.createProgram());
+ // return id;
+ //};
+//
+ //const deleteShader = (shader) => {
+ // gfx_ctx.deleteShader(glShaders.get(shader));
+ //};
+//
+ //const deleteProgram = (program) => {
+ // gfx_ctx.deleteProgram(glPrograms.get(program));
+ //};
+//
+ //const enable = (cap) => {
+ // gfx_ctx.enable(cap);
+ //};
+//
+ //
+ //const enableVertexAttribArray = (attrib_location) => {
+ // gfx_ctx.enableVertexAttribArray(attrib_location);
+ //};
+//
+ //const getShaderParameter = (shader, info) => {
+ // return gfx_ctx.getShaderParameter(glShaders.get(shader), info);
+ //};
+//
+ //const getShaderInfoLog = (shader, ptr, len) => {
+ // const msg = gfx_ctx.getShaderInfoLog(glShaders.get(shader));
+ // const r = writeString(msg, ptr, len);
+ // return r;
+ //};
+//
+ //const getProgramParameter = (program_id, info) => {
+ // const program = glPrograms.get(program_id);
+ // return gfx_ctx.getProgramParameter(program, info);
+ //};
+//
+ //const getProgramInfoLog = (program, ptr, len) => {
+ // const msg = gfx_ctx.getProgramInfoLog(glPrograms.get(program));
+ // const r = writeString(msg, ptr, len);
+ // return r;
+ //};
+//
+ //const getAttribLocation = (program, ptr, len) => {
+ // const attrib = readString(ptr, len);
+ // return gfx_ctx.getAttribLocation(glPrograms.get(program), attrib);
+ //};
+//
+ //const getUniformLocation = (program, ptr, len) => {
+ // const uniform = readString(ptr, len);
+ // const loc = gfx_ctx.getUniformLocation(glPrograms.get(program), uniform);
+ // if (!loc) console.log("Uniform ", uniform, " could not be found");
+ // if (!loc) return -1;
+ //
+ // const id = getId();
+ // glUniformLocations.set(id, loc);
+ // return id;
+ //};
+//
+ //const linkProgram = (program) => {
+ // gfx_ctx.linkProgram(glPrograms.get(program));
+ //};
+//
+ //const shaderSource = (shader, ptr, len) => {
+ // const source = readString(ptr, len);
+ // gfx_ctx.shaderSource(glShaders.get(shader), source);
+ //};
+//
+ //const useProgram = (prog) => {
+ // gfx_ctx.useProgram(glPrograms.get(prog));
+ //};
+//
+ //const uniform1i = (location, v0) => {
+ // gfx_ctx.uniform1i(glUniformLocations.get(location), v0);
+ //};
+//
+ //const uniform1f = (location, v0) => {
+ // gfx_ctx.uniform1f(glUniformLocations.get(location), v0);
+ //};
+//
+ //const uniform2i = (location, v0, v1) => {
+ // gfx_ctx.uniform2i(glUniformLocations.get(location), v0, v1);
+ //};
+//
+ //const uniform2f = (location, v0, v1) => {
+ // gfx_ctx.uniform2f(glUniformLocations.get(location), v0, v1);
+ //};
+//
+ //const uniform3f = (location, v0, v1, v2) => {
+ // gfx_ctx.uniform3f(glUniformLocations.get(location), v0, v1, v2);
+ //};
+//
+ //const uniform4f = (location, v0, v1, v2, v3) => {
+ // gfx_ctx.uniform4f(glUniformLocations.get(location), v0, v1, v2, v3);
+ //};
+//
+ //const uniformMatrix3fv = (location, ptr) => {
+ // const u = glUniformLocations.get(location);
+ // const floats = new Float32Array(memory.buffer, ptr, 9);
+ //
+ // gfx_ctx.uniformMatrix3fv(glUniformLocations.get(location), false, floats);
+ //};
+//
+ //const uniformMatrix4fv = (location, ptr) => {
+ // const u = glUniformLocations.get(location);
+ // const floats = new Float32Array(memory.buffer, ptr, 16);
+ //
+ // gfx_ctx.uniformMatrix4fv(glUniformLocations.get(location), false, floats);
+ //};
+//
+ //const vertexAttribPointer = (loc, size, type, normalize, stride, offset) => {
+ // gfx_ctx.vertexAttribPointer(loc, size, type, normalize, stride, offset);
+ //};
+//
+ //const viewport = (x, y, width, height) => {
+ // gfx_ctx.viewport(x, y, width, height);
+ //};
+//
+ //const drawArrays = (mode, first, count) => {
+ // gfx_ctx.drawArrays(mode, first, count);
+ //};
+//
+ //const createTexture = () => {
+ // const id = getId();
+ // glTextures.set(id, gfx_ctx.createTexture());
+ // return id;
+ //};
+//
+ //const bindTexture = (target, tex_id) => {
+ // const texture = glTextures.get(tex_id);
+ // gfx_ctx.bindTexture(target, texture);
+ //};
+//
+ //const texImage2D = (target, level, interal_format,
+ // width, height, border, format,
+ // data_type, ptr, count, offset) => {
+ // const data = new Uint8Array(memory.buffer, ptr, count);
+ // gfx_ctx.texImage2D(target, level, interal_format, width, height, border, format, data_type, data, offset);
+ //};
+//
+ //const activeTexture = (tex_id) => {
+ // gfx_ctx.activeTexture(tex_id);
+ //};
+//
+ //const vertexAttribDivisor = (loc, divisor) => {
+ // gfx_ctx.vertexAttribDivisor(loc, divisor);
+ //};
+//
+ //const drawArraysInstanced = (mode, first, count, instanceCount) => {
+ // gfx_ctx.drawArraysInstanced(mode, first, count, instanceCount);
+ //};
+//
+ //const getScreenWidth = () => {
+ // return gfx_ctx.drawingBufferWidth;
+ //};
+//
+ //const getScreenHeight = () => {
+ // return gfx_ctx.drawingBufferHeight;
+ //};
+//
+ //const webgl = {
+ // bindBuffer,
+ // blendFunc,
+ // bufferData,
+ //
+ // createShader,
+ // clear,
+ // clearColor,
+ // createBuffer,
+ //
+ // enable,
+ //
+ // shaderSource,
+ // compileShader,
+ // getShaderParameter,
+ // deleteShader,
+ // getShaderInfoLog,
+ //
+ // createProgram,
+ // deleteProgram,
+ // attachShader,
+ // linkProgram,
+ // getProgramParameter,
+ // getProgramInfoLog,
+ // useProgram,
+ //
+ // getAttribLocation,
+ // getUniformLocation,
+ // createVertexArray,
+ // bindVertexArray,
+ // enableVertexAttribArray,
+ // vertexAttribPointer,
+ // viewport,
+ // drawArrays,
+ //
+ // uniform1i,
+ // uniform1f,
+ // uniform2i,
+ // uniform2f,
+ // uniform3f,
+ // uniform4f,
+ // uniformMatrix3fv,
+ // uniformMatrix4fv,
+ //
+ // createTexture,
+ // bindTexture,
+ // texImage2D,
+ // activeTexture,
+ //
+ // vertexAttribDivisor,
+ // drawArraysInstanced,
+ //
+ // getScreenWidth,
+ // getScreenHeight,
+ //};
diff --git a/src/wasm.zig b/src/wasm.zig
index e1ddaab..b149d60 100644
--- a/src/wasm.zig
+++ b/src/wasm.zig
@@ -36,6 +36,18 @@ export fn mouseEvent(
} });
}
+/// Javascript always fills the event.key property. For keys that can be represented
+/// in text, it simply fills the value with the text representation of that key,
+/// but for special keys like Alt, Shift, and others, it fills the key property with
+/// a string with the name of the key (???? Psychotic.) So the web shell converts
+/// those string representations to values in the private use area of unicode codepoints.
+///
+/// Those representations are then repeated here. In the event that the codepoint
+/// property is used for user text input, these values should be filtered out somehow.
+pub const SpecialKeyCodepoints = enum(u32) {
+ shift = 0xE000,
+};
+
export fn keyEvent(codepoint: u32, is_press: bool, is_repeat: bool) void {
handleInput(.{ .key = .{
.codepoint = codepoint,