Set up a basic "front-end" for the webassembly module to be tested locally from a data folder (I use python -m http.server). The WebAssembly application is now responsible for all setup/rendering through the WebGL2 context.

This commit is contained in:
2025-09-01 12:13:56 -07:00
parent cca61ea163
commit b548b7bb26
14 changed files with 1416 additions and 14 deletions

236
data/gl_functions.js Normal file
View File

@@ -0,0 +1,236 @@
import { appGlobals } from './globals.js'
import { wasmPntrToJsString, wasmPntrAndLengthToJsString } from './wasm_functions.js'
export var glObjects = {
buffers: [ null ],
vaos: [ null ],
shaders: [ null ],
programs: [ null ],
};
// +--------------------------------------------------------------+
// | Helpers |
// +--------------------------------------------------------------+
export function verifyGlBufferId(bufferId, allowZero)
{
if (typeof(bufferId) != "number") { return "BufferId is not a number!"; }
if (bufferId == 0) { return allowZero ? null : "BufferId is 0!"; }
if (glObjects == null || glObjects.buffers == null) { return "Buffers array has not been initialized yet!"; }
if (bufferId >= glObjects.buffers.length) { return "BufferId is too high!"; }
if (glObjects.buffers[bufferId] == null) { return "BufferId is for a destroyed vertBuffer!"; }
return null;
}
export function verifyGlVaoId(vaoId, allowZero)
{
if (typeof(vaoId) != "number") { return "VaoId is not a number!"; }
if (vaoId == 0) { return allowZero ? null : "VaoId is 0!"; }
if (glObjects == null || glObjects.vaos == null) { return "Vaos array has not been initialized yet!"; }
if (vaoId >= glObjects.vaos.length) { return "VaoId is too high!"; }
if (glObjects.vaos[vaoId] == null) { return "VaoId is for a destroyed array!"; }
return null;
}
export function verifyGlShaderId(shaderId, allowZero)
{
if (typeof(shaderId) != "number") { return "ShaderId is not a number!"; }
if (shaderId == 0) { return allowZero ? null : "ShaderId is 0!"; }
if (glObjects == null || glObjects.shaders == null) { return "Shaders array has not been initialized yet!"; }
if (shaderId >= glObjects.shaders.length) { return "ShaderId is too high!"; }
if (glObjects.shaders[shaderId] == null) { return "ShaderId is for a destroyed shader!"; }
return null;
}
export function verifyGlProgramId(programId, allowZero)
{
if (typeof(programId) != "number") { return "ProgramId is not a number!"; }
if (programId == 0) { return allowZero ? null : "ProgramId is 0!"; }
if (glObjects == null || glObjects.programs == null) { return "Programs array has not been initialized yet!"; }
if (programId >= glObjects.programs.length) { return "ProgramId is too high!"; }
if (glObjects.programs[programId] == null) { return "ProgramId is for a destroyed program!"; }
return null;
}
export function verifyParameter(verifyResult, functionName, parameterName, parameterValue)
{
if (verifyResult == null) { return true; }
console.error("Invalid argument \"" + parameterName + "\" passed to " + functionName + ": " + verifyResult);
console.error("Argument value: " + parameterValue);
return false;
}
// +--------------------------------------------------------------+
// | WebGL API |
// +--------------------------------------------------------------+
export function jsGlCreateBuffer()
{
let newBuffer = appGlobals.glContext.createBuffer();
let newBufferId = glObjects.buffers.length;
glObjects.buffers.push(newBuffer);
return newBufferId;
}
export function jsGlBindBuffer(bufferType, bufferId)
{
if (!verifyParameter(verifyGlBufferId(bufferId, true), "gl.bindBuffer", "bufferId", bufferId)) { return; }
let buffer = glObjects.buffers[bufferId];
appGlobals.glContext.bindBuffer(bufferType, buffer);
}
export function jsGlBufferData(bufferType, dataLength, dataPntr, usageHint)
{
let dataArray = appGlobals.memDataView.buffer.slice(dataPntr, dataPntr + dataLength)
appGlobals.glContext.bufferData(bufferType, dataArray, usageHint);
}
export function jsGlCreateVertexArray()
{
let newVao = appGlobals.glContext.createVertexArray();
let newVaoId = glObjects.vaos.length;
glObjects.vaos.push(newVao);
return newVaoId;
}
export function jsGlBindVertexArray(vaoId)
{
if (!verifyParameter(verifyGlVaoId(vaoId, true), "gl.bindVertexArray", "vaoId", vaoId)) { return; }
let vao = glObjects.vaos[vaoId];
appGlobals.glContext.bindVertexArray(vao);
}
export function jsGlEnableVertexAttribArray(location)
{
appGlobals.glContext.enableVertexAttribArray(location);
}
export function jsGlVertexAttribPointer(attribLocation, componentCount, componentType, normalized, stride, offset)
{
appGlobals.glContext.vertexAttribPointer(attribLocation, componentCount, componentType, normalized, stride, offset);
}
export function jsGlCreateShader(shaderType)
{
let newShader = appGlobals.glContext.createShader(shaderType);
let newShaderId = glObjects.shaders.length;
glObjects.shaders.push(newShader);
return newShaderId;
}
export function jsGlShaderSource(shaderId, sourceLength, sourcePntr)
{
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.shaderSource", "shaderId", shaderId)) { return; }
let shader = glObjects.shaders[shaderId];
let sourceStr = wasmPntrAndLengthToJsString(sourcePntr, sourceLength);
appGlobals.glContext.shaderSource(shader, sourceStr);
}
export function jsGlCompileShader(shaderId)
{
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.compileShader", "shaderId", shaderId)) { return; }
let shader = glObjects.shaders[shaderId];
appGlobals.glContext.compileShader(shader);
}
export function jsGlGetShaderParameterBool(shaderId, parameter)
{
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.getShaderParameter", "shaderId", shaderId)) { return false; }
let shader = glObjects.shaders[shaderId];
let paramValue = appGlobals.glContext.getShaderParameter(shader, 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 jsGlGetShaderParameterInt(shaderId, parameter)
{
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.getShaderParameter", "shaderId", shaderId)) { return false; }
let shader = glObjects.shaders[shaderId];
let paramValue = appGlobals.glContext.getShaderParameter(shader, parameter);
if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as number when it's actually: " + typeof(paramValue)); return false; }
return paramValue;
}
export function jsGlCreateProgram()
{
let newProgram = appGlobals.glContext.createProgram();
let newProgramId = glObjects.programs.length;
glObjects.programs.push(newProgram);
return newProgramId;
}
export function jsGlAttachShader(programId, shaderId)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.attachShader", "programId", programId)) { return; }
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.attachShader", "shaderId", shaderId)) { return; }
let program = glObjects.programs[programId];
let shader = glObjects.shaders[shaderId];
appGlobals.glContext.attachShader(program, shader);
}
export function jsGlLinkProgram(programId)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.linkProgram", "programId", programId)) { return; }
let program = glObjects.programs[programId];
appGlobals.glContext.linkProgram(program);
}
export function jsGlUseProgram(programId)
{
if (!verifyParameter(verifyGlProgramId(programId, true), "gl.useProgram", "programId", programId)) { return; }
let program = glObjects.programs[programId];
appGlobals.glContext.useProgram(program);
}
export function jsGlGetProgramParameterBool(programId, parameter)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.getProgramParameter", "programId", programId)) { return false; }
let program = glObjects.programs[programId];
let paramValue = appGlobals.glContext.getProgramParameter(program, 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 jsGlGetProgramParameterInt(programId, parameter)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.getProgramParameter", "programId", programId)) { return false; }
let program = glObjects.programs[programId];
let paramValue = appGlobals.glContext.getProgramParameter(program, parameter);
if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as number when it's actually: " + typeof(paramValue)); return false; }
return paramValue;
}
export function jsGlClearColor(rValue, gValue, bValue, aValue)
{
appGlobals.glContext.clearColor(rValue, gValue, bValue, aValue);
}
export function jsGlClear(bufferBits)
{
appGlobals.glContext.clear(bufferBits);
}
export function jsGlDrawArrays(geometryType, startIndex, count)
{
appGlobals.glContext.drawArrays(geometryType, startIndex, count);
}
export let jsGlFunctions = {
jsGlCreateBuffer: jsGlCreateBuffer,
jsGlBindBuffer: jsGlBindBuffer,
jsGlBufferData: jsGlBufferData,
jsGlCreateVertexArray: jsGlCreateVertexArray,
jsGlBindVertexArray: jsGlBindVertexArray,
jsGlEnableVertexAttribArray: jsGlEnableVertexAttribArray,
jsGlVertexAttribPointer: jsGlVertexAttribPointer,
jsGlCreateShader: jsGlCreateShader,
jsGlShaderSource: jsGlShaderSource,
jsGlCompileShader: jsGlCompileShader,
jsGlGetShaderParameterBool: jsGlGetShaderParameterBool,
jsGlGetShaderParameterInt: jsGlGetShaderParameterInt,
jsGlCreateProgram: jsGlCreateProgram,
jsGlAttachShader: jsGlAttachShader,
jsGlLinkProgram: jsGlLinkProgram,
jsGlUseProgram: jsGlUseProgram,
jsGlGetProgramParameterBool: jsGlGetProgramParameterBool,
jsGlGetProgramParameterInt: jsGlGetProgramParameterInt,
jsGlClearColor: jsGlClearColor,
jsGlClear: jsGlClear,
jsGlDrawArrays: jsGlDrawArrays,
};
//TODO: string getShaderInfoLog(shaderId)
//TODO: string getProgramInfoLog(programId)