From 42cf6d9e9fcc22a95bdc76b9861795a1feecf374 Mon Sep 17 00:00:00 2001 From: Taylor Robbins Date: Mon, 1 Sep 2025 18:50:14 -0700 Subject: [PATCH] Added a bunch of WebGL functions related to shader uniforms to gl_functions.js --- CWasm.sublime-project | 20 +++++ cwasm.c | 7 -- cwasm.h | 17 ++++ cwasm_webgl_js_imports.h | 20 +++++ data/gl_functions.js | 181 +++++++++++++++++++++++++++++++++++++-- data/main.js | 26 ++---- test_app.c | 83 ++++++++++++++++-- 7 files changed, 315 insertions(+), 39 deletions(-) diff --git a/CWasm.sublime-project b/CWasm.sublime-project index e425227..f221065 100644 --- a/CWasm.sublime-project +++ b/CWasm.sublime-project @@ -96,6 +96,7 @@ "GlId jsGlCreateProgram()", "GlId jsGlCreateShader(GlEnum shaderType)", "GlId jsGlCreateVertexArray()", + "GlId jsGlGetUniformLocation(GlId programId, int nameLength, const char* namePntr)", "bool jsGlGetProgramParameterBool(GlId programId, GlEnum parameter)", "bool jsGlGetShaderParameterBool(GlId shaderId, GlEnum parameter)", "inline void* ReallocMem(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize)", @@ -116,6 +117,25 @@ "void jsGlEnableVertexAttribArray(GlEnum location)", "void jsGlLinkProgram(GlId programId)", "void jsGlShaderSource(GlId shaderId, int sourceLength, const char* sourcePntr)", + "void jsGlUniform1f(int location, r32 value)", + "void jsGlUniform1fv(GlId locationId, int valuesCount, const r32* valuesPntr)", + "void jsGlUniform1i(GlId locationId, int value)", + "void jsGlUniform1iv(GlId locationId, int valuesCount, const int* valuesPntr)", + "void jsGlUniform2f(int location, r32 value0, r32 value1)", + "void jsGlUniform2fv(GlId locationId, int valuesCount, const r32* valuesPntr)", + "void jsGlUniform2i(GlId locationId, int value0, int value1)", + "void jsGlUniform2iv(GlId locationId, int valuesCount, const int* valuesPntr)", + "void jsGlUniform3f(int location, r32 value0, r32 value1, r32 value2)", + "void jsGlUniform3fv(GlId locationId, int valuesCount, const r32* valuesPntr)", + "void jsGlUniform3i(GlId locationId, int value0, int value1, int value2)", + "void jsGlUniform3iv(GlId locationId, int valuesCount, const int* valuesPntr)", + "void jsGlUniform4f(int location, r32 value0, r32 value1, r32 value2, r32 value3)", + "void jsGlUniform4fv(GlId locationId, int valuesCount, const r32* valuesPntr)", + "void jsGlUniform4i(GlId locationId, int value0, int value1, int value2, int value3)", + "void jsGlUniform4iv(GlId locationId, int valuesCount, const int* valuesPntr)", + "void jsGlUniformMatrix2fv(GlId locationId, const r32* valuesPntr)", + "void jsGlUniformMatrix3fv(GlId locationId, const r32* valuesPntr)", + "void jsGlUniformMatrix4fv(GlId locationId, const r32* valuesPntr)", "void jsGlUseProgram(GlId programId)", "void jsGlVertexAttribPointer(GlEnum attribLocation, int componentCount, GlEnum componentType, bool normalized, int stride, int offset)", "void* AllocMemUnaligned(Arena* arena, u32 numBytes)", diff --git a/cwasm.c b/cwasm.c index c8637c6..927466d 100644 --- a/cwasm.c +++ b/cwasm.c @@ -18,12 +18,5 @@ Description: void InitializeCWasm(u32 scratchArenasSize) { - // CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Warning, true, "Hello\nWorld!"); - Write_D("Hello\nWorld!"); - PrintLine_I(" Fuzzy %u Bunnies!\n%s", 31415926, "What"); - WriteLine_D(""); - WriteLine_W("When"); - Write_D("\n"); - WriteLine_E("Where"); InitGlobalArenas(scratchArenasSize); } diff --git a/cwasm.h b/cwasm.h index 688abd3..1163c1a 100644 --- a/cwasm.h +++ b/cwasm.h @@ -130,6 +130,23 @@ Description: #define AssertMsg(condition, message) sizeof(condition) #endif +//Actual Value of Pi: 3.1415926535897932384626433832795... +#define Pi64 3.14159265358979311599796346854 //accurate to 15 digits +#define Pi32 3.1415927410125732421875f //accurate to 6 digits +#define QuarterPi64 (Pi64/4.0) +#define ThirdPi64 (Pi64/3.0) +#define HalfPi64 (Pi64/2.0) +#define ThreeHalfsPi64 (Pi64*(3.0/2.0)) +#define TwoPi64 (2*Pi64) +#define QuarterPi32 (Pi32/4.0f) +#define ThirdPi32 (Pi32/3.0f) +#define HalfPi32 (Pi32/2.0f) +#define ThreeHalfsPi32 (Pi32*(3.0f/2.0f)) +#define TwoPi32 (2*Pi32) +//Actual Value of e: 2.7182818284590452353602874713526... +#define e64 2.71828182845904509079559829843 //accurate to 15 digits +#define e32 2.71828174591064453125f //accurate to 6 digits + // +--------------------------------------------------------------+ // | Standard Includes | // +--------------------------------------------------------------+ diff --git a/cwasm_webgl_js_imports.h b/cwasm_webgl_js_imports.h index da0da59..151963d 100644 --- a/cwasm_webgl_js_imports.h +++ b/cwasm_webgl_js_imports.h @@ -31,5 +31,25 @@ 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 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); +MAYBE_EXTERN_C void jsGlUniform1f(GlId locationId, r32 value); +MAYBE_EXTERN_C void jsGlUniform2f(GlId locationId, r32 value0, r32 value1); +MAYBE_EXTERN_C void jsGlUniform3f(GlId locationId, r32 value0, r32 value1, r32 value2); +MAYBE_EXTERN_C void jsGlUniform4f(GlId locationId, r32 value0, r32 value1, r32 value2, r32 value3); +MAYBE_EXTERN_C void jsGlUniform1fv(GlId locationId, int valuesCount, const r32* valuesPntr); +MAYBE_EXTERN_C void jsGlUniform2fv(GlId locationId, int valuesCount, const r32* valuesPntr); //TODO: Change valuesPntr to v2* +MAYBE_EXTERN_C void jsGlUniform3fv(GlId locationId, int valuesCount, const r32* valuesPntr); //TODO: Change valuesPntr to v3* +MAYBE_EXTERN_C void jsGlUniform4fv(GlId locationId, int valuesCount, const r32* valuesPntr); //TODO: Change valuesPntr to v4* +MAYBE_EXTERN_C void jsGlUniform1i(GlId locationId, int value); +MAYBE_EXTERN_C void jsGlUniform2i(GlId locationId, int value0, int value1); +MAYBE_EXTERN_C void jsGlUniform3i(GlId locationId, int value0, int value1, int value2); +MAYBE_EXTERN_C void jsGlUniform4i(GlId locationId, int value0, int value1, int value2, int value3); +MAYBE_EXTERN_C void jsGlUniform1iv(GlId locationId, int valuesCount, const int* valuesPntr); +MAYBE_EXTERN_C void jsGlUniform2iv(GlId locationId, int valuesCount, const int* valuesPntr); //TODO: Change valuesPntr to v2i* +MAYBE_EXTERN_C void jsGlUniform3iv(GlId locationId, int valuesCount, const int* valuesPntr); //TODO: Change valuesPntr to v3i* +MAYBE_EXTERN_C void jsGlUniform4iv(GlId locationId, int valuesCount, const int* valuesPntr); //TODO: Change valuesPntr to v4i* +MAYBE_EXTERN_C void jsGlUniformMatrix2fv(GlId locationId, const r32* valuesPntr); //TODO: Change valuesPntr to mat2* +MAYBE_EXTERN_C void jsGlUniformMatrix3fv(GlId locationId, const r32* valuesPntr); //TODO: Change valuesPntr to mat3* +MAYBE_EXTERN_C void jsGlUniformMatrix4fv(GlId locationId, const r32* valuesPntr); //TODO: Change valuesPntr to mat4* #endif // _CWASM_WEBGL_JS_IMPORTS_H diff --git a/data/gl_functions.js b/data/gl_functions.js index 34e6323..1f62e37 100644 --- a/data/gl_functions.js +++ b/data/gl_functions.js @@ -7,12 +7,13 @@ export var glObjects = { vaos: [ null ], shaders: [ null ], programs: [ null ], + uniformLocations: [ null ], }; // +--------------------------------------------------------------+ // | Helpers | // +--------------------------------------------------------------+ -export function verifyGlBufferId(bufferId, allowZero) +function verifyGlBufferId(bufferId, allowZero) { if (typeof(bufferId) != "number") { return "BufferId is not a number!"; } if (bufferId == 0) { return allowZero ? null : "BufferId is 0!"; } @@ -21,7 +22,7 @@ export function verifyGlBufferId(bufferId, allowZero) if (glObjects.buffers[bufferId] == null) { return "BufferId is for a destroyed vertBuffer!"; } return null; } -export function verifyGlVaoId(vaoId, allowZero) +function verifyGlVaoId(vaoId, allowZero) { if (typeof(vaoId) != "number") { return "VaoId is not a number!"; } if (vaoId == 0) { return allowZero ? null : "VaoId is 0!"; } @@ -30,7 +31,7 @@ export function verifyGlVaoId(vaoId, allowZero) if (glObjects.vaos[vaoId] == null) { return "VaoId is for a destroyed array!"; } return null; } -export function verifyGlShaderId(shaderId, allowZero) +function verifyGlShaderId(shaderId, allowZero) { if (typeof(shaderId) != "number") { return "ShaderId is not a number!"; } if (shaderId == 0) { return allowZero ? null : "ShaderId is 0!"; } @@ -39,7 +40,7 @@ export function verifyGlShaderId(shaderId, allowZero) if (glObjects.shaders[shaderId] == null) { return "ShaderId is for a destroyed shader!"; } return null; } -export function verifyGlProgramId(programId, allowZero) +function verifyGlProgramId(programId, allowZero) { if (typeof(programId) != "number") { return "ProgramId is not a number!"; } if (programId == 0) { return allowZero ? null : "ProgramId is 0!"; } @@ -48,7 +49,16 @@ export function verifyGlProgramId(programId, allowZero) if (glObjects.programs[programId] == null) { return "ProgramId is for a destroyed program!"; } return null; } -export function verifyParameter(verifyResult, functionName, parameterName, parameterValue) +function verifyGlUniformLocationId(locationId, allowZero) +{ + if (typeof(locationId) != "number") { return "LocationId is not a number!"; } + if (locationId == 0) { return allowZero ? null : "LocationId is 0!"; } + if (glObjects == null || glObjects.uniformLocations == null) { return "Locations array has not been initialized yet!"; } + if (locationId >= glObjects.uniformLocations.length) { return "LocationId is too high!"; } + if (glObjects.uniformLocations[locationId] == null) { return "LocationId is for a destroyed program!"; } + return null; +} +function verifyParameter(verifyResult, functionName, parameterName, parameterValue) { if (verifyResult == null) { return true; } console.error("Invalid argument \"" + parameterName + "\" passed to " + functionName + ": " + verifyResult); @@ -208,6 +218,147 @@ export function jsGlDrawArrays(geometryType, startIndex, count) appGlobals.glContext.drawArrays(geometryType, startIndex, count); } +export function jsGlGetUniformLocation(programId, nameLength, namePntr) +{ + if (!verifyParameter(verifyGlProgramId(programId, false), "gl.getUniformLocation", "programId", programId)) { return false; } + let program = glObjects.programs[programId]; + let nameStr = wasmPntrAndLengthToJsString(namePntr, nameLength); + let newLocation = appGlobals.glContext.getUniformLocation(program, nameStr); + let newLocationId = glObjects.uniformLocations.length; + glObjects.uniformLocations.push(newLocation); + return newLocationId; +} + +export function jsGlUniform1f(locationId, value) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform1f", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform1f(location, value); +} +export function jsGlUniform2f(locationId, value0, value1) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform2f", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform2f(location, value0, value1); +} +export function jsGlUniform3f(locationId, value0, value1, value2) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform3f", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform3f(location, value0, value1, value2); +} +export function jsGlUniform4f(locationId, value0, value1, value2, value3) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform4f", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform4f(location, value0, value1, value2, value3); +} + +export function jsGlUniform1fv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform1fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount); + appGlobals.glContext.uniform1fv(location, valuesArray); +} +export function jsGlUniform2fv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform2fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount*2); + appGlobals.glContext.uniform2fv(location, valuesArray); +} +export function jsGlUniform3fv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform3fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount*3); + appGlobals.glContext.uniform3fv(location, valuesArray); +} +export function jsGlUniform4fv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform4fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount*4); + appGlobals.glContext.uniform4fv(location, valuesArray); +} + +export function jsGlUniform1i(locationId, value) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform1i", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform1i(location, value); +} +export function jsGlUniform2i(locationId, value0, value1) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform2i", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform2i(location, value0, value1); +} +export function jsGlUniform3i(locationId, value0, value1, value2) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform3i", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform3i(location, value0, value1, value2); +} +export function jsGlUniform4i(locationId, value0, value1, value2, value3) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform4i", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + appGlobals.glContext.uniform4i(location, value0, value1, value2, value3); +} + +export function jsGlUniform1iv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform1iv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Int32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount); + appGlobals.glContext.uniform1iv(location, valuesArray); +} +export function jsGlUniform2iv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform2iv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Int32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount*2); + appGlobals.glContext.uniform2iv(location, valuesArray); +} +export function jsGlUniform3iv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform3iv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Int32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount*3); + appGlobals.glContext.uniform3iv(location, valuesArray); +} +export function jsGlUniform4iv(locationId, valuesCount, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniform4iv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Int32Array(appGlobals.memDataView.buffer, valuesPntr, valuesCount*4); + appGlobals.glContext.uniform4iv(location, valuesArray); +} + +export function jsGlUniformMatrix2fv(locationId, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniformMatrix2fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, 2*2); + appGlobals.glContext.uniformMatrix2fv(location, false, valuesArray); +} +export function jsGlUniformMatrix3fv(locationId, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniformMatrix3fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, 3*3); + appGlobals.glContext.uniformMatrix3fv(location, false, valuesArray); +} +export function jsGlUniformMatrix4fv(locationId, valuesPntr) +{ + if (!verifyParameter(verifyGlUniformLocationId(locationId, false), "gl.uniformMatrix4fv", "locationId", locationId)) { return false; } + let location = glObjects.uniformLocations[locationId]; + let valuesArray = new Float32Array(appGlobals.memDataView.buffer, valuesPntr, 4*4); + appGlobals.glContext.uniformMatrix4fv(location, false, valuesArray); +} + export let jsGlFunctions = { jsGlCreateBuffer: jsGlCreateBuffer, jsGlBindBuffer: jsGlBindBuffer, @@ -230,6 +381,26 @@ export let jsGlFunctions = { jsGlClearColor: jsGlClearColor, jsGlClear: jsGlClear, jsGlDrawArrays: jsGlDrawArrays, + jsGlGetUniformLocation: jsGlGetUniformLocation, + jsGlUniform1f: jsGlUniform1f, + jsGlUniform2f: jsGlUniform2f, + jsGlUniform3f: jsGlUniform3f, + jsGlUniform4f: jsGlUniform4f, + jsGlUniform1fv: jsGlUniform1fv, + jsGlUniform2fv: jsGlUniform2fv, + jsGlUniform3fv: jsGlUniform3fv, + jsGlUniform4fv: jsGlUniform4fv, + jsGlUniform1i: jsGlUniform1i, + jsGlUniform2i: jsGlUniform2i, + jsGlUniform3i: jsGlUniform3i, + jsGlUniform4i: jsGlUniform4i, + jsGlUniform1iv: jsGlUniform1iv, + jsGlUniform2iv: jsGlUniform2iv, + jsGlUniform3iv: jsGlUniform3iv, + jsGlUniform4iv: jsGlUniform4iv, + jsGlUniformMatrix2fv: jsGlUniformMatrix2fv, + jsGlUniformMatrix3fv: jsGlUniformMatrix3fv, + jsGlUniformMatrix4fv: jsGlUniformMatrix4fv, }; //TODO: string getShaderInfoLog(shaderId) diff --git a/data/main.js b/data/main.js index 3401367..1bfd46c 100644 --- a/data/main.js +++ b/data/main.js @@ -21,33 +21,21 @@ function AcquireCanvas(canvasWidth, canvasHeight) // canvasContainer = document.getElementById("canvas_container"); // console.assert(canvasContainer != null, "Couldn't find canvas container DOM element!"); appGlobals.canvas = canvas; - return canvas; } -function CreateGlContext(canvas) +function CreateGlContext() { - var canvasContextGl = canvas.getContext("webgl2"); + var canvasContextGl = appGlobals.canvas.getContext("webgl2"); if (canvasContextGl === null) { console.error("Unable to initialize WebGL render context. Your browser or machine may not support it :("); return null; } // console.dir(canvasContextGl); appGlobals.glContext = canvasContextGl; - return canvasContextGl; } async function LoadWasmModule(wasmFilePath, initialWasmPageCount) { appGlobals.textDecoder = new TextDecoder("utf-8"); - - let wasmEnvironment = - { - ...jsStdFunctions, - ...jsGlFunctions, - }; - appGlobals.wasmModule = await loadWasmModule(wasmFilePath, wasmEnvironment); - + appGlobals.wasmModule = await loadWasmModule(wasmFilePath, { ...jsStdFunctions, ...jsGlFunctions }); appGlobals.memDataView = new DataView(new Uint8Array(appGlobals.wasmModule.exports.memory.buffer).buffer); - // let heapBaseAddress = appGlobals.wasmModule.exports.__heap_base.value; - // console.log("__heap_base = " + heapBaseAddress); - let memorySize = appGlobals.wasmModule.exports.memory.buffer.byteLength; let numMemoryPagesAfterLoad = memorySize / WASM_MEMORY_PAGE_SIZE; if ((memorySize % WASM_MEMORY_PAGE_SIZE) != 0) @@ -61,17 +49,17 @@ async function LoadWasmModule(wasmFilePath, initialWasmPageCount) async function MainLoop() { console.log("Initializing WebGL Canvas..."); - var canvas = AcquireCanvas(600, 400); - var glContext = CreateGlContext(canvas); + AcquireCanvas(600, 400); + CreateGlContext(); console.log("Loading WASM Module..."); await LoadWasmModule("app.wasm", 4); appGlobals.wasmModule.exports.App_Initialize(); console.log("Running!"); - function renderFrame() + function renderFrame(currentTime) { - appGlobals.wasmModule.exports.App_UpdateAndRender(); + appGlobals.wasmModule.exports.App_UpdateAndRender(currentTime); window.requestAnimationFrame(renderFrame); } window.requestAnimationFrame(renderFrame); diff --git a/test_app.c b/test_app.c index 8dc2916..234506d 100644 --- a/test_app.c +++ b/test_app.c @@ -16,8 +16,13 @@ struct GlId vertexShader; GlId fragmentShader; GlId testShader; + GlId testUniformLocation; + GlId worldMatrixLocation; + GlId viewMatrixLocation; + GlId projMatrixLocation; u32 frameIndex; + r64 prevProgramTimeR64; } app; static const char* VertexShaderCodeStr; @@ -27,12 +32,21 @@ WASM_EXPORT(App_Initialize) void App_Initialize() { InitializeCWasm(Kilobytes(128)); + #if 0 + Write_D("Hello\nWorld!"); + PrintLine_I(" Fuzzy %u Bunnies!\n%s", 31415926, "What"); + WriteLine_D(""); + WriteLine_W("When"); + Write_D("\n"); + WriteLine_E("Where"); + #endif + memset(&app, 0x00, sizeof(app)); r32 positions[] = { - -0.9, -0.79, // left bottom corner - 1.0, -1.0, // right bottom corner - 0.0, 1.0 // center top corner + -0.7, -0.7, // left bottom corner + 0.7, -0.7, // right bottom corner + 0.0, 0.7 // center top corner }; app.positionBuffer = jsGlCreateBuffer(); jsGlBindBuffer(GL_ARRAY_BUFFER, app.positionBuffer); @@ -88,15 +102,61 @@ WASM_EXPORT(App_Initialize) void App_Initialize() jsGlLinkProgram(app.testShader); // also debug the program status if (!jsGlGetProgramParameterBool(app.testShader, GL_LINK_STATUS)) { WriteLine_E("Failed to link shader program!"); } //TODO: jsGlGetProgramInfoLog + + const char* uniformName = "TestUniform"; + app.testUniformLocation = jsGlGetUniformLocation(app.testShader, (int)strlen(uniformName), uniformName); + const char* worldMatrixName = "WorldMatrix"; + app.worldMatrixLocation = jsGlGetUniformLocation(app.testShader, (int)strlen(worldMatrixName), worldMatrixName); + const char* viewMatrixName = "ViewMatrix"; + app.viewMatrixLocation = jsGlGetUniformLocation(app.testShader, (int)strlen(viewMatrixName), viewMatrixName); + const char* projMatrixName = "ProjMatrix"; + app.projMatrixLocation = jsGlGetUniformLocation(app.testShader, (int)strlen(projMatrixName), projMatrixName); } -WASM_EXPORT(App_UpdateAndRender) void App_UpdateAndRender() +r32 OscillateBy(u64 timeSource, r32 min, r32 max, u64 periodMs, u64 offset) { - r32 time = app.frameIndex * (1000.0f/60.0f); - jsGlClearColor(sinf(time * 0.0005f + 1.5f)/2 + 0.5f, sinf(time * 0.0013f + 2.3f)/2 + 0.5f, sinf(time * 0.0007f + 3.7f)/2 + 0.5f, 1.0f); + r32 lerpValue = (sinf((((timeSource + offset) % periodMs) / (r32)periodMs) * 2*Pi32) + 1.0f) / 2.0f; + return min + (max - min) * lerpValue; +} + +WASM_EXPORT(App_UpdateAndRender) void App_UpdateAndRender(r64 programTimeR64) +{ + 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; } + if (timeScaleR64 < 0.0) { timeScaleR64 = 0.0; } + r32 timeScale = (r32)timeScaleR64; + r32 programTimef = (r32)programTimeR64; + u64 programTime = (u64)programTimeR64; + u64 elapsedMs = programTime - (u64)app.prevProgramTimeR64; + + 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 @@ -104,6 +164,7 @@ WASM_EXPORT(App_UpdateAndRender) void App_UpdateAndRender() ); app.frameIndex++; + app.prevProgramTimeR64 = programTimeR64; } static const char* VertexShaderCodeStr = "#version 300 es\n" @@ -115,6 +176,10 @@ static const char* VertexShaderCodeStr = "#version 300 es\n" "// data types\n" "precision highp float;\n" "\n" +"uniform mat4 WorldMatrix;\n" +"uniform mat4 ViewMatrix;\n" +"uniform mat4 ProjMatrix;\n" +"\n" "// this is the vertex attribute at index 0\n" "// which we defined in the vertex array object.\n" "// we can use any name for this in the glsl code\n" @@ -133,12 +198,14 @@ static const char* VertexShaderCodeStr = "#version 300 es\n" " \n" " // vertex position for the shader program\n" " // always a vec4 value\n" -" gl_Position = vec4(aPos, 0.0, 1.0);\n" +" gl_Position = ((vec4(aPos, 0.0, 1.0) * WorldMatrix) * ViewMatrix) * ProjMatrix;\n" "}\n"; static const char* FragmentShaderCodeStr = "#version 300 es\n" "precision highp float;\n" "\n" +"uniform float TestUniform[3];\n" +"\n" "in vec3 vCol; // the data from vertex shader\n" "\n" "// fragment output value\n" @@ -146,5 +213,5 @@ static const char* FragmentShaderCodeStr = "#version 300 es\n" "out vec4 outCol;\n" "\n" "void main(){\n" -" outCol = vec4(vCol, 1.0);\n" +" outCol = vec4(vec3(vCol.r * TestUniform[0], vCol.g * TestUniform[1], vCol.b * TestUniform[2]), 1.0);\n" "}\n";