diff --git a/CWasm.sublime-project b/CWasm.sublime-project index f221065..e06e498 100644 --- a/CWasm.sublime-project +++ b/CWasm.sublime-project @@ -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)", diff --git a/cwasm_webgl_js_imports.h b/cwasm_webgl_js_imports.h index 151963d..12eebd5 100644 --- a/cwasm_webgl_js_imports.h +++ b/cwasm_webgl_js_imports.h @@ -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); diff --git a/data/gl_functions.js b/data/gl_functions.js index 1f62e37..5087d85 100644 --- a/data/gl_functions.js +++ b/data/gl_functions.js @@ -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) diff --git a/data/main.js b/data/main.js index 1bfd46c..e505096 100644 --- a/data/main.js +++ b/data/main.js @@ -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); } diff --git a/test_app.c b/test_app.c index 234506d..fbb1b50 100644 --- a/test_app.c +++ b/test_app.c @@ -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"