Add cAllocMem to cwasm.c which the javascript side can use to allocate memory from an opaque Arena pointer that was passed to it. Used this to implement jsGlGetParameterString, jsGlGetShaderInfoLog, and jsGlGetProgramInfoLog in gl_functions.js. Added NotNull macro and fixed bug in ScratchBegin macro. Added a bool return for App_Initialize which allows us to stop the main loop from beginning (which prevents log spew when something goes wrong)

This commit is contained in:
2025-09-01 21:53:24 -07:00
parent 7c61189d3a
commit b62f0d279b
10 changed files with 135 additions and 18 deletions

View File

@@ -1,6 +1,6 @@
import { appGlobals } from './globals.js'
import { wasmPntrToJsString, wasmPntrAndLengthToJsString } from './wasm_functions.js'
import { wasmPntrToJsString, wasmPntrAndLengthToJsString, jsStringToWasmPntr } from './wasm_functions.js'
export var glObjects = {
buffers: [ null ],
@@ -79,6 +79,43 @@ function verifyParameter(verifyResult, functionName, parameterName, parameterVal
// +--------------------------------------------------------------+
// | WebGL API |
// +--------------------------------------------------------------+
export function jsGlGetError(capability)
{
return appGlobals.glContext.getError();
}
export function jsGlGetParameterBool(parameter)
{
let paramValue = appGlobals.glContext.getParameter(parameter);
if (typeof(paramValue) != "boolean") { console.error("Tried to get GL parameter " + parameter + " as bool when it's actually: " + typeof(paramValue)); return false; }
return paramValue;
}
export function jsGlGetParameterEnum(parameter)
{
let paramValue = appGlobals.glContext.getParameter(parameter);
if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as enum when it's actually: " + typeof(paramValue)); return false; }
return paramValue;
}
export function jsGlGetParameterInt(parameter)
{
let paramValue = appGlobals.glContext.getParameter(parameter);
if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as int when it's actually: " + typeof(paramValue)); return false; }
return paramValue;
}
export function jsGlGetParameterFloat(parameter)
{
let paramValue = appGlobals.glContext.getParameter(parameter);
if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as float when it's actually: " + typeof(paramValue)); return false; }
return paramValue;
}
export function jsGlGetParameterString(arenaPntr, parameter)
{
let paramValue = appGlobals.glContext.getParameter(parameter);
if (typeof(paramValue) != "string") { console.error("Tried to get GL parameter " + parameter + " as string when it's actually: " + typeof(paramValue)); return false; }
let paramValuePntr = jsStringToWasmPntr(arenaPntr, paramValue, true);
return paramValuePntr;
}
export function jsGlEnable(capability)
{
appGlobals.glContext.enable(capability);
@@ -168,7 +205,6 @@ export function jsGlBindTexture(target, textureId)
export function jsGlTexImage2D(target, level, internalFormat, width, height, border, format, type, dataLength, dataPntr)
{
// let dataBuffer = appGlobals.memDataView.buffer.slice(dataPntr, dataPntr + dataLength);
let dataBuffer = new Uint8Array(appGlobals.memDataView.buffer, dataPntr, dataLength);
appGlobals.glContext.texImage2D(target, level, internalFormat, width, height, border, format, type, dataBuffer);
}
@@ -266,6 +302,16 @@ export function jsGlGetShaderParameterInt(shaderId, parameter)
return paramValue;
}
export function jsGlGetShaderInfoLog(arenaPntr, shaderId)
{
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.getShaderInfoLog", "shaderId", shaderId)) { return false; }
let shader = glObjects.shaders[shaderId];
let logString = appGlobals.glContext.getShaderInfoLog(shader);
if (logString.length == 0) { return null; }
let logStringPntr = jsStringToWasmPntr(arenaPntr, logString, true);
return logStringPntr;
}
export function jsGlDeleteProgram(programId)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.deleteProgram", "programId", programId)) { return; }
@@ -296,6 +342,16 @@ export function jsGlLinkProgram(programId)
appGlobals.glContext.linkProgram(program);
}
export function jsGlGetProgramInfoLog(arenaPntr, programId)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.getProgramInfoLog", "programId", programId)) { return false; }
let program = glObjects.programs[programId];
let logString = appGlobals.glContext.getProgramInfoLog(program);
if (logString.length == 0) { return null; }
let logStringPntr = jsStringToWasmPntr(arenaPntr, logString, true);
return logStringPntr;
}
export function jsGlUseProgram(programId)
{
if (!verifyParameter(verifyGlProgramId(programId, true), "gl.useProgram", "programId", programId)) { return; }
@@ -497,6 +553,12 @@ export function jsGlUniformMatrix4fv(locationId, valuesPntr)
// | Functions List |
// +==============================+
export let jsGlFunctions = {
jsGlGetError: jsGlGetError,
jsGlGetParameterBool: jsGlGetParameterBool,
jsGlGetParameterEnum: jsGlGetParameterEnum,
jsGlGetParameterInt: jsGlGetParameterInt,
jsGlGetParameterFloat: jsGlGetParameterFloat,
jsGlGetParameterString: jsGlGetParameterString,
jsGlEnable: jsGlEnable,
jsGlDisable: jsGlDisable,
jsGlBlendFunc: jsGlBlendFunc,
@@ -525,10 +587,12 @@ export let jsGlFunctions = {
jsGlCompileShader: jsGlCompileShader,
jsGlGetShaderParameterBool: jsGlGetShaderParameterBool,
jsGlGetShaderParameterInt: jsGlGetShaderParameterInt,
jsGlGetShaderInfoLog: jsGlGetShaderInfoLog,
jsGlDeleteProgram: jsGlDeleteProgram,
jsGlCreateProgram: jsGlCreateProgram,
jsGlAttachShader: jsGlAttachShader,
jsGlLinkProgram: jsGlLinkProgram,
jsGlGetProgramInfoLog: jsGlGetProgramInfoLog,
jsGlUseProgram: jsGlUseProgram,
jsGlGetProgramParameterBool: jsGlGetProgramParameterBool,
jsGlGetProgramParameterInt: jsGlGetProgramParameterInt,

View File

@@ -10,5 +10,6 @@ export var appGlobals =
glContext: null,
memDataView: null,
wasmModule: null,
textEncoder: null,
textDecoder: null,
};

View File

@@ -26,6 +26,7 @@ function AcquireCanvas(canvasWidth, canvasHeight)
async function LoadWasmModule(wasmFilePath, initialWasmPageCount)
{
appGlobals.textDecoder = new TextDecoder("utf-8");
appGlobals.textEncoder = new TextEncoder("utf-8");
appGlobals.wasmModule = await loadWasmModule(wasmFilePath, { ...jsStdFunctions, ...jsGlFunctions });
appGlobals.memDataView = new DataView(new Uint8Array(appGlobals.wasmModule.exports.memory.buffer).buffer);
let memorySize = appGlobals.wasmModule.exports.memory.buffer.byteLength;
@@ -50,16 +51,23 @@ async function MainLoop()
console.log("Loading WASM Module...");
await LoadWasmModule("app.wasm", 4);
appGlobals.wasmModule.exports.App_Initialize();
let initSuccess = appGlobals.wasmModule.exports.App_Initialize();
console.log("Running!");
function renderFrame(currentTime)
if (initSuccess)
{
let shouldContinue = appGlobals.wasmModule.exports.App_UpdateAndRender(currentTime);
if (shouldContinue) { window.requestAnimationFrame(renderFrame); }
else { appGlobals.wasmModule.exports.App_Close(); }
console.log("Running!");
function renderFrame(currentTime)
{
let shouldContinue = appGlobals.wasmModule.exports.App_UpdateAndRender(currentTime);
if (shouldContinue) { window.requestAnimationFrame(renderFrame); }
else { appGlobals.wasmModule.exports.App_Close(); }
}
window.requestAnimationFrame(renderFrame);
}
else
{
console.error("Initialization failed!");
}
window.requestAnimationFrame(renderFrame);
}
MainLoop();

View File

@@ -40,3 +40,14 @@ export function wasmPntrAndLengthToJsString(ptr, length)
appGlobals.memDataView.buffer.slice(ptr, ptr + length)
);
}
export function jsStringToWasmPntr(arenaPntr, jsString, addNullTerm)
{
let encodedBytes = appGlobals.textEncoder.encode(jsString);
let memPntr = appGlobals.wasmModule.exports.cAllocMem(arenaPntr, encodedBytes.length + (addNullTerm ? 1 : 0), 0);
if (memPntr == 0) { return memPntr; }
const writeArray = new Uint8Array(appGlobals.wasmModule.exports.memory.buffer);
writeArray.set(encodedBytes, memPntr);
if (addNullTerm) { writeArray[encodedBytes.length] = 0; }
return memPntr;
}