From 5c17f155262a6b6fa322d5e463f8c03348afc609 Mon Sep 17 00:00:00 2001 From: Damian Tarnawski Date: Sun, 14 Jan 2024 22:48:43 +0100 Subject: [PATCH] Add some shaders and frame loop going --- .vscode/extensions.json | 7 +- example/index.js | 54 ++++++++------- example/main.odin | 119 ++++++++++++++++++++++++++++++++-- example/shader_fragment.glsl | 11 ++++ example/shader_vertex.glsl | 20 ++++++ example/types.d.ts | 5 ++ example/types.js | 1 + main.js | 18 ++--- package.json | 2 +- pnpm-lock.yaml | 8 +-- wasm/dom/dom.js | 2 +- wasm/dom/types.d.ts | 2 +- wasm/env.js | 2 +- wasm/ls/local_storage.js | 2 +- wasm/runtime.js | 14 ++-- wasm/types.d.ts | 2 +- wasm/webgl/interface.js | 82 ++++++++++++++++++++--- wasm/webgl/types.d.ts | 4 +- wasm/webgl/webgl.js | 47 +++++++------- wasm/webgl/webgl2.js | 6 +- wasm/webgl/webgl_helpers.odin | 8 ++- 21 files changed, 319 insertions(+), 97 deletions(-) create mode 100644 example/shader_fragment.glsl create mode 100644 example/shader_vertex.glsl create mode 100644 example/types.d.ts create mode 100644 example/types.js diff --git a/.vscode/extensions.json b/.vscode/extensions.json index ca1d005..9d7354f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,8 @@ { - "recommendations": ["danielgavin.ols", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint"] + "recommendations": [ + "danielgavin.ols", + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "raczzalan.webgl-glsl-editor" + ] } diff --git a/example/index.js b/example/index.js index fd76948..5416b3e 100644 --- a/example/index.js +++ b/example/index.js @@ -2,15 +2,15 @@ import * as wasm from "../wasm/runtime.js" import {IS_DEV, WEB_SOCKET_PORT, MESSAGE_RELOAD, WASM_FILENAME} from "./_config.js" +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import * as t from "./types.js" + if (IS_DEV) { wasm.enableConsole() - const socket = new WebSocket("ws://localhost:" + WEB_SOCKET_PORT) - - socket.addEventListener("message", event => { - if (event.data === MESSAGE_RELOAD) { - location.reload() - } + /* Hot Reload */ + new WebSocket("ws://localhost:" + WEB_SOCKET_PORT).addEventListener("message", event => { + event.data === MESSAGE_RELOAD && location.reload() }) } @@ -20,25 +20,33 @@ document.body.addEventListener("lol", () => { console.log("lol event has been received") }) -/* To test scroll events */ -document.body.style.minHeight = "200vh" - -const wasm_instance = wasm.zeroWasmInstance() -const webgl_state = wasm.webgl.makeWebGLInterface() +const wasm_state = wasm.makeWasmState() +const webgl_state = wasm.webgl.makeWebGLState() -const response = await fetch(WASM_FILENAME) -const file = await response.arrayBuffer() -const source_instance = await WebAssembly.instantiate(file, { +const wasm_file = await fetch(WASM_FILENAME).then(r => r.arrayBuffer()) +const src_instance = await WebAssembly.instantiate(wasm_file, { env: {}, // TODO - odin_env: wasm.env.makeOdinEnv(wasm_instance), - odin_ls: wasm.ls.makeOdinLS(wasm_instance), - odin_dom: wasm.dom.makeOdinDOM(wasm_instance), - webgl: wasm.webgl.makeOdinWebGL(webgl_state, wasm_instance), + odin_env: wasm.env.makeOdinEnv(wasm_state), + odin_ls: wasm.ls.makeOdinLS(wasm_state), + odin_dom: wasm.dom.makeOdinDOM(wasm_state), + webgl: wasm.webgl.makeOdinWebGL(webgl_state, wasm_state), }) -wasm.initWasmInstance(wasm_instance, source_instance.instance.exports) -console.log("Exports", wasm_instance.exports) -console.log("Memory", wasm_instance.memory) +wasm.initWasmState(wasm_state, src_instance) +const exports = /** @type {t.WasmExports} */ (wasm_state.exports) -wasm_instance.exports._start() -wasm_instance.exports._end() +exports._start() +const odin_ctx = exports.default_context_ptr() +exports._end() + +void requestAnimationFrame(prev_time => { + /** @type {FrameRequestCallback} */ + const frame = time => { + const delta = (time - prev_time) * 0.001 + prev_time = time + exports.frame(delta, odin_ctx) + void requestAnimationFrame(frame) + } + + void requestAnimationFrame(frame) +}) diff --git a/example/main.odin b/example/main.odin index e2f8860..cf2c843 100644 --- a/example/main.odin +++ b/example/main.odin @@ -1,12 +1,18 @@ package main -import "../wasm" -import "../wasm/dom" -import "../wasm/webgl" import "core:fmt" import "core:mem" +import "core:runtime" import "core:strings" +import "../wasm" +import "../wasm/dom" +import "../wasm/webgl" + +shader_fragment := #load("shader_fragment.glsl", string) +shader_vertex := #load("shader_vertex.glsl", string) + + main :: proc() { test_buf, err := wasm.page_alloc(2) context.allocator = mem.arena_allocator(&{data = test_buf}) @@ -16,10 +22,6 @@ main :: proc() { fmt.print("Hello, WebAssembly!\n") fmt.eprint("Hello, Error!\n\ttest\nbyebye!\n") - // Make sure that this matches the id of your canvas. - webgl.SetCurrentContextById("canvas") - webgl.ClearColor(1, 0, 0, 1) - webgl.Clear(webgl.COLOR_BUFFER_BIT) dom.add_window_event_listener(.Scroll, {}, proc(e: dom.Event) { fmt.println("Scroll event!", e.data.scroll.delta) @@ -30,4 +32,107 @@ main :: proc() { dom.add_window_event_listener(.Visibility_Change, {}, proc(e: dom.Event) { fmt.println("Visibility_Change event!", e.data.visibility_change.is_visible) }) + + + // Make sure that this matches the id of your canvas. + if ok := webgl.SetCurrentContextById("canvas"); !ok { + fmt.println("Failed to set current context!") + return + } + + program, program_ok := webgl.CreateProgramFromStrings({shader_vertex}, {shader_fragment}) + if !program_ok { + fmt.println("Failed to create program!") + return + } + webgl.UseProgram(program) + + + a_position = webgl.GetAttribLocation(program, "a_position") + a_color = webgl.GetAttribLocation(program, "a_color") + u_resolution = webgl.GetUniformLocation(program, "u_resolution") + + webgl.EnableVertexAttribArray(a_position) + webgl.EnableVertexAttribArray(a_color) + + + positions_buffer = webgl.CreateBuffer() + colors_buffer = webgl.CreateBuffer() +} + +a_position: i32 +a_color: i32 +u_resolution: i32 + +positions_buffer: webgl.Buffer +colors_buffer: webgl.Buffer + +iteration: i32 + +// odinfmt: disable +colors := [?]u8 { + 255, 0, 0, 255, + 0, 255, 0, 255, + 0, 0, 255, 255, + + 255, 0, 0, 255, + 0, 255, 0, 255, + 0, 0, 255, 255, +} +// odinfmt: enable + +@(export) +frame :: proc "c" (delta: f32, ctx: ^runtime.Context) { + context = ctx^ + + err := webgl.GetError() + if err != webgl.NO_ERROR { + fmt.println("WebGL error:", err) + return + } + + iteration += 2 + if iteration > 200 { + iteration = 0 + } + + H: f32 : 100 + W: f32 : 200 + x := f32(iteration) + // odinfmt: disable + positions := [?]f32 { + 10+x, 20+x, + W+x, 20+x, + 10+x, H+x, + + 10+x, H+x, + W+x, 20+x, + W+x, H+x, + } + // odinfmt: enable + + + webgl.BindBuffer(webgl.ARRAY_BUFFER, positions_buffer) + webgl.BufferDataSlice(webgl.ARRAY_BUFFER, positions[:], webgl.STATIC_DRAW) + + // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) + webgl.VertexAttribPointer(a_position, 2, webgl.FLOAT, false, 0, 0) + + // bind, and fill color buffer + webgl.BindBuffer(webgl.ARRAY_BUFFER, colors_buffer) + webgl.BufferDataSlice(webgl.ARRAY_BUFFER, colors[:], webgl.STATIC_DRAW) + webgl.VertexAttribPointer(a_color, 4, webgl.UNSIGNED_BYTE, true, 0, 0) + + // set the resolution + webgl.Uniform2f(u_resolution, 640, 480) + + // Tell WebGL how to convert from clip space to pixels + webgl.Viewport(0, 0, 640, 480) + + // Clear the canvas + webgl.ClearColor(0, 0, 0, 0) + webgl.Clear(webgl.COLOR_BUFFER_BIT) + + // draw + webgl.DrawArrays(webgl.TRIANGLES, 0, 6) // 2 triangles, 6 vertices } diff --git a/example/shader_fragment.glsl b/example/shader_fragment.glsl new file mode 100644 index 0000000..5aa6f98 --- /dev/null +++ b/example/shader_fragment.glsl @@ -0,0 +1,11 @@ +// fragment shaders don't have a default precision so we need +// to pick one. mediump is a good default +precision mediump float; + +// color varying received from vertex shader +varying vec4 v_color; + +void main() { + // gl_FragColor is a special variable a fragment shader is responsible for setting + gl_FragColor = v_color; +} diff --git a/example/shader_vertex.glsl b/example/shader_vertex.glsl new file mode 100644 index 0000000..e8ee40e --- /dev/null +++ b/example/shader_vertex.glsl @@ -0,0 +1,20 @@ +// an attribute will receive data from a buffer +attribute vec2 a_position; +attribute vec4 a_color; +uniform vec2 u_resolution; +// color to pass to the fragment shader +// value in fragment shader will be interpolated +varying vec4 v_color; + +void main() { + // from pixels to 0->1 then to 0->2 then to -1->+1 (clipspace) + vec2 clip_space = (a_position / u_resolution) * 2.0 - 1.0; + + gl_Position = vec4(clip_space * vec2(1, -1), 0, 1); + + // Convert from clip space to color space. + // Clip space goes -1.0 to +1.0 + // Color space goes from 0.0 to 1.0 + // v_color = 1.0 - (gl_Position * 0.5 + 0.5); + v_color = a_color; +} diff --git a/example/types.d.ts b/example/types.d.ts new file mode 100644 index 0000000..84a24ae --- /dev/null +++ b/example/types.d.ts @@ -0,0 +1,5 @@ +import * as wasm from "../wasm/runtime.js" + +export interface WasmExports extends wasm.OdinExports { + frame: (time: number, ctx_ptr: number) => void +} diff --git a/example/types.js b/example/types.js new file mode 100644 index 0000000..336ce12 --- /dev/null +++ b/example/types.js @@ -0,0 +1 @@ +export {} diff --git a/main.js b/main.js index 7385928..8f1f8d0 100644 --- a/main.js +++ b/main.js @@ -387,9 +387,7 @@ function falseFn() { */ function unsafePromiseToError(promise) { return promise.then( - // eslint-disable-next-line @nothing-but/no-return-to-void result => result, - // eslint-disable-next-line @nothing-but/no-return-to-void error => error, ) } @@ -406,13 +404,13 @@ function childProcessToPromise(/** @type {child_process.ChildProcess} */ child) }) } -/** - * @param {number} ms - * @returns {Promise} - */ -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)) -} +// /** +// * @param {number} ms +// * @returns {Promise} +// */ +// function sleep(ms) { +// return new Promise(resolve => setTimeout(resolve, ms)) +// } /** @returns {string} */ function toWebFilepath(/** @type {string} */ path) { @@ -429,7 +427,6 @@ function fileExists(/** @type {string} */ filepath) { * @returns {Promise} */ function ensureEmptyDir(dirpath) { - // eslint-disable-next-line @nothing-but/no-return-to-void return fsp.rm(dirpath, {recursive: true, force: true}).then(() => fsp.mkdir(dirpath)) } @@ -459,7 +456,6 @@ async function copyDirContents(src, dest) { * @returns {Promise} */ function copyDir(src, dest) { - // eslint-disable-next-line @nothing-but/no-return-to-void return fsp.mkdir(dest).then(() => copyDirContents(src, dest)) } diff --git a/package.json b/package.json index 115116d..383e741 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "build-test": "pnpm run build && pnpm run typecheck:server && pnpm run typecheck:example && pnpm run lint && pnpm run test" }, "devDependencies": { - "@nothing-but/eslint-plugin": "^0.1.4", + "@nothing-but/eslint-plugin": "^0.1.5", "@total-typescript/ts-reset": "^0.5.1", "@types/node": "^20.10.7", "@types/ws": "^8.5.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6d9452..abdc819 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: devDependencies: '@nothing-but/eslint-plugin': - specifier: ^0.1.4 - version: 0.1.4(eslint@8.56.0)(typescript@5.3.3) + specifier: ^0.1.5 + version: 0.1.5(eslint@8.56.0)(typescript@5.3.3) '@total-typescript/ts-reset': specifier: ^0.5.1 version: 0.5.1 @@ -952,8 +952,8 @@ packages: fastq: 1.16.0 dev: true - /@nothing-but/eslint-plugin@0.1.4(eslint@8.56.0)(typescript@5.3.3): - resolution: {integrity: sha512-AJUDU0N4o93JEgA/JNrm+TPvl5uEUxjQCd61FTzuSHgYicTENllV/TIMnv8JtwuS3gvEI32yY20QJFH8Osnklg==} + /@nothing-but/eslint-plugin@0.1.5(eslint@8.56.0)(typescript@5.3.3): + resolution: {integrity: sha512-cX7b35d9OmpNc2QxKGWEjUx3N9kAur/RWuJ2SthRsq1ytVF4vmxlHz7rL3AaL+k7i39aNCSY4QQLy2LkD91E9g==} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 typescript: ~5.2.0 diff --git a/wasm/dom/dom.js b/wasm/dom/dom.js index d6a6ad9..7cda8a7 100644 --- a/wasm/dom/dom.js +++ b/wasm/dom/dom.js @@ -22,7 +22,7 @@ function targetToKind(target) { const KEYBOARD_MAX_KEY_SIZE = 16 const KEYBOARD_MAX_CODE_SIZE = 16 -/** @param {import("../types.js").WasmInstance} _wasm */ +/** @param {import("../types.js").WasmState} _wasm */ export function makeOdinDOM(_wasm) { const wasm = /** @type {import("./types.js").OdinDOMInstance} */ (_wasm) diff --git a/wasm/dom/types.d.ts b/wasm/dom/types.d.ts index bfa4e69..027bb93 100644 --- a/wasm/dom/types.d.ts +++ b/wasm/dom/types.d.ts @@ -4,6 +4,6 @@ export interface OdinDOMExports extends wasm.OdinExports { odin_dom_do_event_callback: (data: number, callback: number, ctx_ptr: number) => void } -export interface OdinDOMInstance extends wasm.WasmInstance { +export interface OdinDOMInstance extends wasm.WasmState { exports: OdinDOMExports } diff --git a/wasm/env.js b/wasm/env.js index 4ad93df..715b3f3 100644 --- a/wasm/env.js +++ b/wasm/env.js @@ -46,7 +46,7 @@ function writeToConsole(fd, str) { } } -/** @param {import("./types.js").WasmInstance} wasm */ +/** @param {import("./types.js").WasmState} wasm */ export function makeOdinEnv(wasm) { return { /** diff --git a/wasm/ls/local_storage.js b/wasm/ls/local_storage.js index f85dd69..c227331 100644 --- a/wasm/ls/local_storage.js +++ b/wasm/ls/local_storage.js @@ -1,6 +1,6 @@ import * as mem from "../memory.js" -/** @param {import("../types.js").WasmInstance} wasm */ +/** @param {import("../types.js").WasmState} wasm */ export function makeOdinLS(wasm) { return { /** diff --git a/wasm/runtime.js b/wasm/runtime.js index 0a5e2c6..9027b93 100644 --- a/wasm/runtime.js +++ b/wasm/runtime.js @@ -14,8 +14,8 @@ export * as webgl from "./webgl/index.js" export * from "./types.js" export * from "./console.js" -/** @returns {import("./types.js").WasmInstance} */ -export function zeroWasmInstance() { +/** @returns {import("./types.js").WasmState} */ +export function makeWasmState() { return { exports: /** @type {any} */ (null), memory: /** @type {any} */ (null), @@ -25,10 +25,10 @@ export function zeroWasmInstance() { /** * Init a wasm instance with exports and memory from instanciated wasm module exports * - * @param {import("./types.js").WasmInstance} instance - * @param {WebAssembly.Exports} exports + * @param {import("./types.js").WasmState} state + * @param {WebAssembly.WebAssemblyInstantiatedSource} src_instance */ -export function initWasmInstance(instance, exports) { - instance.exports = /** @type {import("./types.js").OdinExports} */ (exports) - instance.memory = instance.exports.memory +export function initWasmState(state, src_instance) { + state.exports = /** @type {import("./types.js").OdinExports} */ (src_instance.instance.exports) + state.memory = state.exports.memory } diff --git a/wasm/types.d.ts b/wasm/types.d.ts index 070f4a0..7d95ade 100644 --- a/wasm/types.d.ts +++ b/wasm/types.d.ts @@ -6,7 +6,7 @@ export interface OdinExports extends WebAssembly.Exports { } /** The Odin WebAssembly instance. */ -export interface WasmInstance { +export interface WasmState { exports: OdinExports memory: WebAssembly.Memory } diff --git a/wasm/webgl/interface.js b/wasm/webgl/interface.js index 9768e70..b5fd5a7 100644 --- a/wasm/webgl/interface.js +++ b/wasm/webgl/interface.js @@ -3,8 +3,8 @@ import * as mem from "../memory.js" // eslint-disable-next-line @typescript-eslint/no-unused-vars import * as t from "./types.js" -/** @returns {t.WebGLInterface} */ -export function makeWebGLInterface() { +/** @returns {t.WebGLState} */ +export function makeWebGLState() { return { element: null, /* will be set later, most of the time we want to assert that it's not null */ @@ -34,8 +34,8 @@ export const INVALID_VALUE = 0x0501 export const INVALID_OPERATION = 0x0502 /** - * @param {t.WebGLInterface} webgl - * @param {?} element + * @param {t.WebGLState} webgl + * @param {HTMLElement | null} element * @param {WebGLContextAttributes | undefined} context_settings * @returns {boolean} */ @@ -56,15 +56,15 @@ export function setCurrentContext(webgl, element, context_settings) { } /** - * @param {t.WebGLInterface} webgl + * @param {t.WebGLState} webgl * @returns {number} */ export function newId(webgl) { return webgl.id_counter++ } /** - * @param {t.WebGLInterface} webgl - * @param {number} error_code + * @param {t.WebGLState} webgl + * @param {number} error_code * @returns {void} */ export function recordError(webgl, error_code) { @@ -73,8 +73,8 @@ export function recordError(webgl, error_code) { } } /** - * @param {t.WebGLInterface} webgl - * @param {number} program_id + * @param {t.WebGLState} webgl + * @param {number} program_id * @returns {void} */ export function populateUniformTable(webgl, program_id) { @@ -132,3 +132,67 @@ export function getSource(buffer, strings_ptr, strings_length) { } return source } + +// /** +// * @param {WebGL2RenderingContext} gl +// * @param {number} type +// * @param {string} source +// * @returns {WebGLShader | Error} +// */ +// export function makeShader(gl, type, source) { +// const shader = gl.createShader(type) +// if (!shader) return new Error("failed to create gl shader") + +// gl.shaderSource(shader, source) +// gl.compileShader(shader) + +// const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS) +// if (!success) { +// const log = gl.getShaderInfoLog(shader) +// gl.deleteShader(shader) +// return new Error(log || "failed to compile shader") +// } + +// return shader +// } + +// /** +// * @param {WebGL2RenderingContext} gl +// * @param {string} source +// * @returns {WebGLShader | Error} +// */ +// export function makeVertexShader(gl, source) { +// return makeShader(gl, gl.VERTEX_SHADER, source) +// } +// /** +// * @param {WebGL2RenderingContext} gl +// * @param {string} source +// * @returns {WebGLShader | Error} +// */ +// export function makeFragmentShader(gl, source) { +// return makeShader(gl, gl.FRAGMENT_SHADER, source) +// } + +// /** +// * @param {WebGL2RenderingContext} gl +// * @param {WebGLShader[]} shaders +// * @returns {WebGLProgram | Error} +// */ +// export function makeProgram(gl, shaders) { +// const program = gl.createProgram() +// if (!program) return new Error("failed to create gl program") + +// for (const shader of shaders) { +// gl.attachShader(program, shader) +// } +// gl.linkProgram(program) + +// const success = gl.getProgramParameter(program, gl.LINK_STATUS) +// if (!success) { +// const log = gl.getProgramInfoLog(program) +// gl.deleteProgram(program) +// return new Error(log || "failed to link program") +// } + +// return program +// } diff --git a/wasm/webgl/types.d.ts b/wasm/webgl/types.d.ts index e1fbaf8..a550c26 100644 --- a/wasm/webgl/types.d.ts +++ b/wasm/webgl/types.d.ts @@ -11,7 +11,7 @@ export interface ProgramInfo { } // prettier-ignore -export interface WebGLInterface { +export interface WebGLState { element : HTMLCanvasElement | null, ctx : WebGLRenderingContext | WebGL2RenderingContext, version : 1 | 2, @@ -34,7 +34,7 @@ export interface WebGLInterface { transform_feedbacks : ArrayRecord, syncs : ArrayRecord } -export interface WebGL2Interface extends WebGLInterface { +export interface WebGL2State extends WebGLState { ctx: WebGL2RenderingContext version: 2 } diff --git a/wasm/webgl/webgl.js b/wasm/webgl/webgl.js index f9e0949..58465c1 100644 --- a/wasm/webgl/webgl.js +++ b/wasm/webgl/webgl.js @@ -14,11 +14,11 @@ import { INVALID_OPERATION, } from "./interface.js" -/** @typedef{import("../types.js").WasmInstance}WasmInstance */ +/** @typedef{import("../types.js").WasmState}WasmInstance */ /** - * @param {t.WebGLInterface} webgl - * @param {WasmInstance} wasm + * @param {t.WebGLState} webgl + * @param {WasmInstance} wasm * @returns WebGL bindings for Odin. */ export function makeOdinWebGL(webgl, wasm) { @@ -95,13 +95,13 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} name_len * @returns {boolean} */ - IsExtensionSupported(name_ptr, name_len) { + IsExtensionSupported: (name_ptr, name_len) => { const name = mem.load_string_raw(wasm.memory.buffer, name_ptr, name_len) const extensions = webgl.ctx.getSupportedExtensions() return extensions ? extensions.indexOf(name) !== -1 : false }, /** @returns {number} */ - GetError() { + GetError: () => { if (webgl.last_error) { const err = webgl.last_error webgl.last_error = 0 @@ -114,7 +114,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} minor_ptr * @returns {void} */ - GetWebGLVersion(major_ptr, minor_ptr) { + GetWebGLVersion: (major_ptr, minor_ptr) => { const data = new DataView(wasm.memory.buffer) mem.store_i32(data, major_ptr, webgl.version) mem.store_i32(data, minor_ptr, 0) @@ -124,7 +124,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} minor_ptr * @returns {void} */ - GetESVersion(major_ptr, minor_ptr) { + GetESVersion: (major_ptr, minor_ptr) => { const major = webgl.ctx.getParameter(0x1f02 /*VERSION*/).indexOf("OpenGL ES 3.0") !== -1 ? 3 : 2 const data = new DataView(wasm.memory.buffer) @@ -135,20 +135,21 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} texture * @returns {void} */ - ActiveTexture(texture) { + ActiveTexture: texture => { webgl.ctx.activeTexture(texture) }, /** @returns {void} */ - AttachShader(/** @type {number} */ program, /** @type {number} */ shader) { + AttachShader: (/** @type {number} */ program, /** @type {number} */ shader) => { webgl.ctx.attachShader(webgl.programs[program], webgl.shaders[shader]) }, - /** @returns {void} */ - BindAttribLocation( - /** @type {number} */ program, - /** @type {number} */ index, - /** @type {number} */ name_ptr, - /** @type {number} */ name_len, - ) { + /** + * @param {number} program + * @param {number} index + * @param {number} name_ptr + * @param {number} name_len + * @returns {void} + */ + BindAttribLocation: (program, index, name_ptr, name_len) => { const name = mem.load_string_raw(wasm.memory.buffer, name_ptr, name_len) webgl.ctx.bindAttribLocation(webgl.programs[program], index, name) }, @@ -157,7 +158,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} buffer * @returns {void} */ - BindBuffer(target, buffer) { + BindBuffer: (target, buffer) => { /* https://gist.github.com/floooh/ae2250dce2dfd700eb959b802d7d247a#file-clear-emsc-js-L985 */ @@ -190,7 +191,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} framebuffer * @returns {void} */ - BindFramebuffer(target, framebuffer) { + BindFramebuffer: (target, framebuffer) => { webgl.ctx.bindFramebuffer(target, framebuffer ? webgl.framebuffers[framebuffer] : null) }, /** @@ -198,7 +199,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} texture * @returns {void} */ - BindTexture(target, texture) { + BindTexture: (target, texture) => { webgl.ctx.bindTexture(target, texture ? webgl.textures[texture] : null) }, /** @@ -208,14 +209,14 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} a * @returns {void} */ - BlendColor(r, g, b, a) { + BlendColor: (r, g, b, a) => { webgl.ctx.blendColor(r, g, b, a) }, /** * @param {number} mode * @returns {void} */ - BlendEquation(mode) { + BlendEquation: mode => { webgl.ctx.blendEquation(mode) }, /** @@ -223,7 +224,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} dfactor * @returns {void} */ - BlendFunc(sfactor, dfactor) { + BlendFunc: (sfactor, dfactor) => { webgl.ctx.blendFunc(sfactor, dfactor) }, /** @@ -233,7 +234,7 @@ export function makeOdinWebGL(webgl, wasm) { * @param {number} dstAlpha * @returns {void} */ - BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) { + BlendFuncSeparate: (srcRGB, dstRGB, srcAlpha, dstAlpha) => { webgl.ctx.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha) }, /** diff --git a/wasm/webgl/webgl2.js b/wasm/webgl/webgl2.js index 9233c77..5631e9f 100644 --- a/wasm/webgl/webgl2.js +++ b/wasm/webgl/webgl2.js @@ -7,10 +7,10 @@ import {EMPTY_U8_ARRAY, INVALID_OPERATION, newId, recordError} from "./interface /** @returns WebGL 2 bindings for Odin */ export function makeOdinWegGL2( - /** @type {t.WebGLInterface} */ _webgl, - /** @type {import("../types.js").WasmInstance} */ wasm, + /** @type {t.WebGLState} */ _webgl, + /** @type {import("../types.js").WasmState} */ wasm, ) { - const webgl = /** @type {t.WebGL2Interface} */ (_webgl) + const webgl = /** @type {t.WebGL2State} */ (_webgl) return { /* diff --git a/wasm/webgl/webgl_helpers.odin b/wasm/webgl/webgl_helpers.odin index 854e924..0a11399 100644 --- a/wasm/webgl/webgl_helpers.odin +++ b/wasm/webgl/webgl_helpers.odin @@ -9,7 +9,13 @@ package webgl import "core:fmt" -CreateProgramFromStrings :: proc(vs_sources, fs_sources: []string) -> (program: Program, ok: bool) { +@(require_results) +CreateProgramFromStrings :: proc( + vs_sources, fs_sources: []string, +) -> ( + program: Program, + ok: bool, +) #optional_ok { ok = true log: [1024]byte