Added an asynchronous resource loading mechanism through App_GetResourcePath and App_ResourceLoaded. Added stb_image.h and used it to parse a .png file loaded from the server and upload it to app.testTexture. There is some ugliness around the edges images with transparency, probably caused by something pre-multiplied alpha related.

This commit is contained in:
2025-09-02 11:43:19 -07:00
parent 1a9775d670
commit f2d590be13
7 changed files with 8166 additions and 1 deletions

View File

@@ -38,12 +38,94 @@ r32 OscillateBy(u64 timeSource, r32 min, r32 max, u64 periodMs, u64 offset)
return min + (max - min) * lerpValue;
}
// +--------------------------------------------------------------+
// | Load Resources |
// +--------------------------------------------------------------+
WASM_EXPORT(App_GetResourcePath) const char* App_GetResourcePath(int resourceIndex)
{
switch (resourceIndex)
{
case 0: return "icon_64.png";
default: return nullptr;
}
}
WASM_EXPORT(App_ResourceLoaded) void App_ResourceLoaded(int resourceIndex, int fileSize, u8* fileBytes)
{
switch (resourceIndex)
{
case 0:
{
PrintLine_D("Got resource %d bytes: %p %02X %02X %02X %02X", fileSize, fileBytes, fileBytes[0], fileBytes[1], fileBytes[2], fileBytes[3]);
ScratchBegin(scratch); //NOTE: stbi_load_from_memory implicitly allocates from the first scratch arena
int imageWidth = 0;
int imageHeight = 0;
int imageChannelCount = 0;
stbi_uc* textureBytes = stbi_load_from_memory(fileBytes, fileSize, &imageWidth, &imageHeight, &imageChannelCount, 4);
if (textureBytes != nullptr)
{
PrintLine_D("Parsed image: %p %dx%d %d channel(s)", textureBytes, imageWidth, imageHeight, imageChannelCount);
//We need to reverse the rows of pixels so the image is not upside-down
//TODO: Replace with GL_UNPACK_FLIP_Y_WEBGL
u32 rowWidth = imageWidth * sizeof(u32);
u8* tempRowBuffer = AllocArray(u8, scratch, rowWidth);
for (int yIndex = 0; yIndex < imageHeight/2; yIndex++)
{
memcpy(tempRowBuffer, &textureBytes[yIndex * rowWidth], rowWidth);
memcpy(&textureBytes[yIndex * rowWidth], &textureBytes[(imageHeight-1 - yIndex) * rowWidth], rowWidth);
memcpy(&textureBytes[(imageHeight-1 - yIndex) * rowWidth], tempRowBuffer, rowWidth);
}
#if 0
for (int yIndex = 0; yIndex < imageHeight; yIndex++)
{
for (int xIndex = 0; xIndex < imageWidth; xIndex++)
{
u8* pixelPntr = &textureBytes[((yIndex * imageWidth) + xIndex) * sizeof(u32)];
r32 alpha = (pixelPntr[3]/255.0f);
pixelPntr[0] = (u8)((pixelPntr[0]/255.0f) * alpha * 255.0f);
pixelPntr[1] = (u8)((pixelPntr[1]/255.0f) * alpha * 255.0f);
pixelPntr[2] = (u8)((pixelPntr[2]/255.0f) * alpha * 255.0f);
}
}
#endif
if (app.testTexture != 0) { jsGlDeleteTexture(app.testTexture); }
app.testTexture = jsGlCreateTexture();
jsGlActiveTexture(GL_TEXTURE0);
jsGlBindTexture(GL_TEXTURE_2D, app.testTexture);
// jsGlPixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1);
// jsGlPixelStorei(GL_UNPACK_FLIP_Y_WEBGL, true);
jsGlTexImage2D(
GL_TEXTURE_2D, //bound texture type
0, //image level
GL_RGBA, //internal format
imageWidth, //image width
imageHeight, //image height
0, //border
GL_RGBA, //format
GL_UNSIGNED_BYTE, //type
imageWidth*imageHeight*sizeof(u32), //dataLength
textureBytes //dataPntr
);
jsGlTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
jsGlTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
jsGlTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
jsGlTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
jsGlGenerateMipmap(GL_TEXTURE_2D);
}
else { PrintLine_E("Failed to parse %d byte image using stb_image.h!", fileSize); }
ScratchEnd(scratch);
} break;
}
}
// +--------------------------------------------------------------+
// | Initialize |
// +--------------------------------------------------------------+
WASM_EXPORT(App_Initialize) bool App_Initialize()
{
InitializeCWasm(Kilobytes(128));
InitializeCWasm(Megabytes(2));
memset(&app, 0x00, sizeof(app));
#if 0
@@ -60,6 +142,10 @@ WASM_EXPORT(App_Initialize) bool App_Initialize()
PrintLine_D("GL_VERSION: \"%s\"", jsGlGetParameterString(scratch, GL_VERSION));
PrintLine_D("GL_VENDOR: \"%s\"", jsGlGetParameterString(scratch, GL_VENDOR));
jsGlEnable(GL_BLEND);
jsGlBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
jsGlBlendEquation(GL_FUNC_ADD);
r32 positions[] = {
0.0, 0.0,
1.0, 0.0,