Added some more WebGL functions to gl_functions.js. Made the test_app render something more interesting. Added a bool return from App_UpdateAndRender which allows it to request that the application loop ends.

This commit is contained in:
2025-09-01 19:21:47 -07:00
parent 42cf6d9e9f
commit 81f5457b61
5 changed files with 150 additions and 29 deletions

View File

@@ -109,12 +109,21 @@
"void jsGlAttachShader(GlId programId, GlId shaderId)",
"void jsGlBindBuffer(GlEnum bufferType, GlId bufferId)",
"void jsGlBindVertexArray(GlId vaoId)",
"void jsGlBlendFunc(GlEnum srcFactor, GlEnum dstFactor)",
"void jsGlBlendFuncSeparate(GlEnum srcRGB, GlEnum dstRGB, GlEnum srcAlpha, GlEnum dstAlpha)",
"void jsGlBufferData(GlEnum bufferType, u32 dataLength, const void* dataPntr, GlEnum usageHint)",
"void jsGlClear(int bufferBits)",
"void jsGlClearColor(r32 rValue, r32 gValue, r32 bValue, r32 aValue)",
"void jsGlCompileShader(GlId shaderId)",
"void jsGlDeleteBuffer(GlId bufferId)",
"void jsGlDeleteProgram(GlId programId)",
"void jsGlDeleteShader(GlId shaderId)",
"void jsGlDepthFunc(GlEnum depthFunc)",
"void jsGlDisable(GlEnum capability)",
"void jsGlDrawArrays(GlEnum geometryType, int startIndex, int count)",
"void jsGlEnable(GlEnum capability)",
"void jsGlEnableVertexAttribArray(GlEnum location)",
"void jsGlFrontFace(GlEnum cullMode)",
"void jsGlLinkProgram(GlId programId)",
"void jsGlShaderSource(GlId shaderId, int sourceLength, const char* sourcePntr)",
"void jsGlUniform1f(int location, r32 value)",

View File

@@ -10,6 +10,13 @@ Date: 09\01\2025
typedef int GlId; // Really this is just an index into a javascript array that holds the real reference to the WebGL object
typedef int GlEnum;
MAYBE_EXTERN_C void jsGlEnable(GlEnum capability);
MAYBE_EXTERN_C void jsGlDisable(GlEnum capability);
MAYBE_EXTERN_C void jsGlBlendFunc(GlEnum srcFactor, GlEnum dstFactor);
MAYBE_EXTERN_C void jsGlBlendFuncSeparate(GlEnum srcRGB, GlEnum dstRGB, GlEnum srcAlpha, GlEnum dstAlpha);
MAYBE_EXTERN_C void jsGlDepthFunc(GlEnum depthFunc);
MAYBE_EXTERN_C void jsGlFrontFace(GlEnum cullMode);
MAYBE_EXTERN_C void jsGlDeleteBuffer(GlId bufferId);
MAYBE_EXTERN_C GlId jsGlCreateBuffer();
MAYBE_EXTERN_C void jsGlBindBuffer(GlEnum bufferType, GlId bufferId);
MAYBE_EXTERN_C void jsGlBufferData(GlEnum bufferType, u32 dataLength, const void* dataPntr, GlEnum usageHint);
@@ -17,11 +24,13 @@ MAYBE_EXTERN_C GlId jsGlCreateVertexArray();
MAYBE_EXTERN_C void jsGlBindVertexArray(GlId vaoId);
MAYBE_EXTERN_C void jsGlEnableVertexAttribArray(GlEnum location);
MAYBE_EXTERN_C void jsGlVertexAttribPointer(GlEnum attribLocation, int componentCount, GlEnum componentType, bool normalized, int stride, int offset);
MAYBE_EXTERN_C void jsGlDeleteShader(GlId shaderId);
MAYBE_EXTERN_C GlId jsGlCreateShader(GlEnum shaderType);
MAYBE_EXTERN_C void jsGlShaderSource(GlId shaderId, int sourceLength, const char* sourcePntr);
MAYBE_EXTERN_C void jsGlCompileShader(GlId shaderId);
MAYBE_EXTERN_C bool jsGlGetShaderParameterBool(GlId shaderId, GlEnum parameter);
MAYBE_EXTERN_C int jsGlGetShaderParameterInt(GlId shaderId, GlEnum parameter);
MAYBE_EXTERN_C void jsGlDeleteProgram(GlId programId);
MAYBE_EXTERN_C GlId jsGlCreateProgram();
MAYBE_EXTERN_C void jsGlAttachShader(GlId programId, GlId shaderId);
MAYBE_EXTERN_C void jsGlLinkProgram(GlId programId);
@@ -29,6 +38,8 @@ MAYBE_EXTERN_C void jsGlUseProgram(GlId programId);
MAYBE_EXTERN_C bool jsGlGetProgramParameterBool(GlId programId, GlEnum parameter);
MAYBE_EXTERN_C int jsGlGetProgramParameterInt(GlId programId, GlEnum parameter);
MAYBE_EXTERN_C void jsGlClearColor(r32 rValue, r32 gValue, r32 bValue, r32 aValue);
MAYBE_EXTERN_C void jsGlClearDepth(r32 depth);
MAYBE_EXTERN_C void jsGlClearStencil(r32 stencilValue);
MAYBE_EXTERN_C void jsGlClear(int bufferBits);
MAYBE_EXTERN_C void jsGlDrawArrays(GlEnum geometryType, int startIndex, int count);
MAYBE_EXTERN_C GlId jsGlGetUniformLocation(GlId programId, int nameLength, const char* namePntr);

View File

@@ -69,6 +69,40 @@ function verifyParameter(verifyResult, functionName, parameterName, parameterVal
// +--------------------------------------------------------------+
// | WebGL API |
// +--------------------------------------------------------------+
export function jsGlEnable(capability)
{
appGlobals.glContext.enable(capability);
}
export function jsGlDisable(capability)
{
appGlobals.glContext.disable(capability);
}
export function jsGlBlendFunc(srcFactor, dstFactor)
{
appGlobals.glContext.blendFunc(srcFactor, dstFactor);
}
export function jsGlBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
{
appGlobals.glContext.blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
}
export function jsGlDepthFunc(depthFunc)
{
appGlobals.glContext.depthFunc(depthFunc);
}
export function jsGlFrontFace(cullMode)
{
appGlobals.glContext.frontFace(cullMode);
}
export function jsGlDeleteBuffer(bufferId)
{
if (!verifyParameter(verifyGlBufferId(bufferId, false), "gl.deleteBuffer", "bufferId", bufferId)) { return; }
appGlobals.glContext.deleteBuffer(glObjects.buffers[bufferId]);
glObjects.buffers[bufferId] = null;
}
export function jsGlCreateBuffer()
{
let newBuffer = appGlobals.glContext.createBuffer();
@@ -98,6 +132,7 @@ export function jsGlCreateVertexArray()
return newVaoId;
}
//TODO: jsGlDeleteVertexArray?
export function jsGlBindVertexArray(vaoId)
{
if (!verifyParameter(verifyGlVaoId(vaoId, true), "gl.bindVertexArray", "vaoId", vaoId)) { return; }
@@ -115,6 +150,12 @@ export function jsGlVertexAttribPointer(attribLocation, componentCount, componen
appGlobals.glContext.vertexAttribPointer(attribLocation, componentCount, componentType, normalized, stride, offset);
}
export function jsGlDeleteShader(shaderId)
{
if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.deleteShader", "shaderId", shaderId)) { return; }
appGlobals.glContext.deleteShader(glObjects.shaders[shaderId]);
glObjects.shaders[shaderId] = null;
}
export function jsGlCreateShader(shaderType)
{
let newShader = appGlobals.glContext.createShader(shaderType);
@@ -155,6 +196,12 @@ export function jsGlGetShaderParameterInt(shaderId, parameter)
return paramValue;
}
export function jsGlDeleteProgram(programId)
{
if (!verifyParameter(verifyGlProgramId(programId, false), "gl.deleteProgram", "programId", programId)) { return; }
appGlobals.glContext.deleteShader(glObjects.programs[programId]);
glObjects.programs[programId] = null;
}
export function jsGlCreateProgram()
{
let newProgram = appGlobals.glContext.createProgram();
@@ -207,6 +254,14 @@ export function jsGlClearColor(rValue, gValue, bValue, aValue)
{
appGlobals.glContext.clearColor(rValue, gValue, bValue, aValue);
}
export function jsGlClearDepth(depth)
{
appGlobals.glContext.clearDepth(depth);
}
export function jsGlClearStencil(stencilValue)
{
appGlobals.glContext.clearStencil(stencilValue);
}
export function jsGlClear(bufferBits)
{
@@ -360,6 +415,13 @@ export function jsGlUniformMatrix4fv(locationId, valuesPntr)
}
export let jsGlFunctions = {
jsGlEnable: jsGlEnable,
jsGlDisable: jsGlDisable,
jsGlBlendFunc: jsGlBlendFunc,
jsGlBlendFuncSeparate: jsGlBlendFuncSeparate,
jsGlDepthFunc: jsGlDepthFunc,
jsGlFrontFace: jsGlFrontFace,
jsGlDeleteBuffer: jsGlDeleteBuffer,
jsGlCreateBuffer: jsGlCreateBuffer,
jsGlBindBuffer: jsGlBindBuffer,
jsGlBufferData: jsGlBufferData,
@@ -367,11 +429,13 @@ export let jsGlFunctions = {
jsGlBindVertexArray: jsGlBindVertexArray,
jsGlEnableVertexAttribArray: jsGlEnableVertexAttribArray,
jsGlVertexAttribPointer: jsGlVertexAttribPointer,
jsGlDeleteShader: jsGlDeleteShader,
jsGlCreateShader: jsGlCreateShader,
jsGlShaderSource: jsGlShaderSource,
jsGlCompileShader: jsGlCompileShader,
jsGlGetShaderParameterBool: jsGlGetShaderParameterBool,
jsGlGetShaderParameterInt: jsGlGetShaderParameterInt,
jsGlDeleteProgram: jsGlDeleteProgram,
jsGlCreateProgram: jsGlCreateProgram,
jsGlAttachShader: jsGlAttachShader,
jsGlLinkProgram: jsGlLinkProgram,
@@ -379,6 +443,8 @@ export let jsGlFunctions = {
jsGlGetProgramParameterBool: jsGlGetProgramParameterBool,
jsGlGetProgramParameterInt: jsGlGetProgramParameterInt,
jsGlClearColor: jsGlClearColor,
jsGlClearDepth: jsGlClearDepth,
jsGlClearStencil: jsGlClearStencil,
jsGlClear: jsGlClear,
jsGlDrawArrays: jsGlDrawArrays,
jsGlGetUniformLocation: jsGlGetUniformLocation,
@@ -403,5 +469,9 @@ export let jsGlFunctions = {
jsGlUniformMatrix4fv: jsGlUniformMatrix4fv,
};
//TODO: deleteTexture(webglObjects.textures[textureId])
//TODO: texImage2D(target, level, internalformat, width, height, border, format, type, dataBuffer)
//TODO: generateMipmap(target)
//TODO: string getShaderInfoLog(shaderId)
//TODO: string getProgramInfoLog(programId)

View File

@@ -59,8 +59,9 @@ async function MainLoop()
console.log("Running!");
function renderFrame(currentTime)
{
appGlobals.wasmModule.exports.App_UpdateAndRender(currentTime);
window.requestAnimationFrame(renderFrame);
let shouldContinue = appGlobals.wasmModule.exports.App_UpdateAndRender(currentTime);
if (shouldContinue) { window.requestAnimationFrame(renderFrame); }
else { appGlobals.wasmModule.exports.App_Close(); }
}
window.requestAnimationFrame(renderFrame);
}

View File

@@ -28,6 +28,15 @@ struct
static const char* VertexShaderCodeStr;
static const char* FragmentShaderCodeStr;
r32 OscillateBy(u64 timeSource, r32 min, r32 max, u64 periodMs, u64 offset)
{
r32 lerpValue = (sinf((((timeSource + offset) % periodMs) / (r32)periodMs) * 2*Pi32) + 1.0f) / 2.0f;
return min + (max - min) * lerpValue;
}
// +--------------------------------------------------------------+
// | Initialize |
// +--------------------------------------------------------------+
WASM_EXPORT(App_Initialize) void App_Initialize()
{
InitializeCWasm(Kilobytes(128));
@@ -113,14 +122,25 @@ WASM_EXPORT(App_Initialize) void App_Initialize()
app.projMatrixLocation = jsGlGetUniformLocation(app.testShader, (int)strlen(projMatrixName), projMatrixName);
}
r32 OscillateBy(u64 timeSource, r32 min, r32 max, u64 periodMs, u64 offset)
// +--------------------------------------------------------------+
// | Close |
// +--------------------------------------------------------------+
WASM_EXPORT(App_Close) void App_Close()
{
r32 lerpValue = (sinf((((timeSource + offset) % periodMs) / (r32)periodMs) * 2*Pi32) + 1.0f) / 2.0f;
return min + (max - min) * lerpValue;
//TODO: Delete vao
jsGlDeleteProgram(app.testShader);
jsGlDeleteShader(app.vertexShader);
jsGlDeleteShader(app.fragmentShader);
jsGlDeleteBuffer(app.positionBuffer);
jsGlDeleteBuffer(app.colorBuffer);
}
WASM_EXPORT(App_UpdateAndRender) void App_UpdateAndRender(r64 programTimeR64)
// +--------------------------------------------------------------+
// | Update and Render |
// +--------------------------------------------------------------+
WASM_EXPORT(App_UpdateAndRender) bool App_UpdateAndRender(r64 programTimeR64)
{
bool shouldContinue = true;
r64 timeScaleR64 = (programTimeR64 - app.prevProgramTimeR64) / (1000.0 / 60.0);
if (fabs(timeScaleR64 - 1.0) < 0.001) { timeScaleR64 = 1.0; }
if (timeScaleR64 > 4.0) { timeScaleR64 = 4.0; }
@@ -130,43 +150,53 @@ WASM_EXPORT(App_UpdateAndRender) void App_UpdateAndRender(r64 programTimeR64)
u64 programTime = (u64)programTimeR64;
u64 elapsedMs = programTime - (u64)app.prevProgramTimeR64;
// jsGlClearColor(OscillateBy(programTime, 0.0f, 1.0f, 3700, 1500), OscillateBy(programTime, 0.0f, 1.0f, 5300, 2000), OscillateBy(programTime, 0.0f, 1.0f, 2300, 500), 1.0f);
jsGlClearColor(32/255.0f, 32/255.0f, 32/255.0f, 1.0f);
jsGlClear(GL_COLOR_BUFFER_BIT);
jsGlBindVertexArray(app.vao); // our vertex array object
jsGlUseProgram(app.testShader); // our shader program
r32 identityMatrix[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
r32 worldMatrix[] = {
OscillateBy(programTime, 0.9f, 1.1f, 3000, 0), 0.0f, 0.0f, OscillateBy(programTime, -0.1f, 0.1f, 3000, 0),
0.0f, OscillateBy(programTime, 0.9f, 1.1f, 3000, 1500), 0.0f, OscillateBy(programTime, -0.1f, 0.1f, 3000, 750),
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
jsGlClearColor(OscillateBy(programTime, 0.0f, 1.0f, 3700, 1500), OscillateBy(programTime, 0.0f, 1.0f, 5300, 2000), OscillateBy(programTime, 0.0f, 1.0f, 2300, 500), 1.0f);
jsGlClear(GL_COLOR_BUFFER_BIT);
jsGlBindVertexArray(app.vao); // our vertex array object
jsGlUseProgram(app.testShader); // our shader program
r32 uniformValues[] = {
OscillateBy(programTime, 0.0f, 1.0f, 2000, 0),
OscillateBy(programTime, 0.0f, 1.0f, 2000, 1200),
OscillateBy(programTime, 0.0f, 1.0f, 2000, 700),
};
jsGlUniform1fv(app.testUniformLocation, ArrayCount(uniformValues), &uniformValues[0]);
jsGlUniformMatrix4fv(app.worldMatrixLocation, &worldMatrix[0]);
jsGlUniformMatrix4fv(app.viewMatrixLocation, &identityMatrix[0]);
jsGlUniformMatrix4fv(app.projMatrixLocation, &identityMatrix[0]);
jsGlDrawArrays(
GL_TRIANGLES, // drawing mode
0, // index of the first vertex to draw
3 // number of vertices to draw
);
const u64 numTris = 75;
for (u64 tIndex = 0; tIndex < numTris; tIndex++)
{
r32 uniformValues[] = {
OscillateBy(programTime, 0.0f, 1.0f, 2000, 0 + tIndex*(2000/numTris)),
OscillateBy(programTime, 0.0f, 1.0f, 2000, 1200 + tIndex*(2000/numTris)),
OscillateBy(programTime, 0.0f, 1.0f, 2000, 700 + tIndex*(2000/numTris)),
};
jsGlUniform1fv(app.testUniformLocation, ArrayCount(uniformValues), &uniformValues[0]);
r32 offsetX = OscillateBy(programTime, -0.1f, 0.1f, 3000, 0 + tIndex*(3000/numTris));
r32 offsetY = OscillateBy(programTime, -0.1f, 0.1f, 3000, 750 + tIndex*(3000/numTris));
r32 scaleX = OscillateBy(programTime, 0.9f - tIndex*(0.9f/numTris), 1.1f - tIndex*(0.9f/numTris), 3000, 0 + tIndex*(3000/numTris));
r32 scaleY = OscillateBy(programTime, 0.9f - tIndex*(0.9f/numTris), 1.1f - tIndex*(0.9f/numTris), 3000, 1500 + tIndex*(3000/numTris));
r32 worldMatrix[] = {
scaleX, 0.0f, 0.0f, offsetX,
0.0f, scaleY, 0.0f, offsetY,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
jsGlUniformMatrix4fv(app.worldMatrixLocation, &worldMatrix[0]);
jsGlDrawArrays(GL_TRIANGLES, 0, 3);
}
app.frameIndex++;
app.prevProgramTimeR64 = programTimeR64;
return shouldContinue;
}
// +--------------------------------------------------------------+
// | Shaders |
// +--------------------------------------------------------------+
static const char* VertexShaderCodeStr = "#version 300 es\n"
"// ^^^\n"
"// the version definition has to be the first line in\n"