Files
CWasm/test_app.c

218 lines
7.4 KiB
C

/*
File: test_app.c
Author: Taylor Robbins
Date: 08\28\2025
Description:
** When no other application is present, this serves as a simple test case for the CWasm layer
*/
#include "cwasm.c"
struct
{
GlId positionBuffer;
GlId colorBuffer;
GlId vao;
GlId vertexShader;
GlId fragmentShader;
GlId testShader;
GlId testUniformLocation;
GlId worldMatrixLocation;
GlId viewMatrixLocation;
GlId projMatrixLocation;
u32 frameIndex;
r64 prevProgramTimeR64;
} app;
static const char* VertexShaderCodeStr;
static const char* FragmentShaderCodeStr;
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.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);
jsGlBufferData(GL_ARRAY_BUFFER, sizeof(positions), &positions[0], GL_STATIC_DRAW);
u8 colors[] = {
// R , G , B
255, 0, 0, // red
0, 255, 0, // green
0, 0, 255 // blue
};
app.colorBuffer = jsGlCreateBuffer();
jsGlBindBuffer(GL_ARRAY_BUFFER, app.colorBuffer);
jsGlBufferData(GL_ARRAY_BUFFER, sizeof(colors), &colors[0], GL_STATIC_DRAW);
app.vao = jsGlCreateVertexArray();
jsGlBindVertexArray(app.vao); // start "recording"
// position attribute data
jsGlBindBuffer(GL_ARRAY_BUFFER, app.positionBuffer);
jsGlEnableVertexAttribArray(0);
jsGlVertexAttribPointer(
0, // attrib location
2, // components per element: vec2 for our postition data
GL_FLOAT, // buffer data type: we have Float32Array
false, // whether the data is normalized to 0.0 1.0 range in shaders
0, // stride, not important atm
0 // offset, not important atm
);
// color attribute data
jsGlBindBuffer(GL_ARRAY_BUFFER, app.colorBuffer);
jsGlEnableVertexAttribArray(1);
jsGlVertexAttribPointer(
1, // attrib location
3, // components per element:
GL_UNSIGNED_BYTE, // we have Uint8Array
true, // the 0..255 is normalized into 0.0...1.0 in shaders
0,
0
);
jsGlBindVertexArray(0); // end "recording"
app.vertexShader = jsGlCreateShader(GL_VERTEX_SHADER);
jsGlShaderSource(app.vertexShader, (int)strlen(VertexShaderCodeStr), VertexShaderCodeStr);
jsGlCompileShader(app.vertexShader);
if (!jsGlGetShaderParameterBool(app.vertexShader, GL_COMPILE_STATUS)) { WriteLine_E("Failed to compile vertex shader!"); } //TODO: jsGlGetShaderInfoLog
app.fragmentShader = jsGlCreateShader(GL_FRAGMENT_SHADER);
jsGlShaderSource(app.fragmentShader, (int)strlen(FragmentShaderCodeStr), FragmentShaderCodeStr);
jsGlCompileShader(app.fragmentShader);
if (!jsGlGetShaderParameterBool(app.fragmentShader, GL_COMPILE_STATUS)) { WriteLine_E("Failed to compile fragment shader!"); } //TODO: jsGlGetShaderInfoLog
app.testShader = jsGlCreateProgram();
jsGlAttachShader(app.testShader, app.vertexShader);
jsGlAttachShader(app.testShader, app.fragmentShader);
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);
}
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;
}
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
3 // number of vertices to draw
);
app.frameIndex++;
app.prevProgramTimeR64 = programTimeR64;
}
static const char* VertexShaderCodeStr = "#version 300 es\n"
"// ^^^\n"
"// the version definition has to be the first line in\n"
"// the string.\n"
"\n"
"// sets the precision level for all float and vec\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"
"// the important bit is the location=0\n"
"layout(location=0) in vec2 aPos;\n"
"\n"
"// this is the color attrib at index: 1\n"
"layout(location=1) in vec3 aCol;\n"
"\n"
"// this is the interpolate color which is\n"
"// passed to the fragment shader\n"
"out vec3 vCol;\n"
"\n"
"void main(){\n"
" vCol = aCol; // just pass through the value \n"
" \n"
" // vertex position for the shader program\n"
" // always a vec4 value\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"
"// essentially the color of the output pixel\n"
"out vec4 outCol;\n"
"\n"
"void main(){\n"
" outCol = vec4(vec3(vCol.r * TestUniform[0], vCol.g * TestUniform[1], vCol.b * TestUniform[2]), 1.0);\n"
"}\n";