diff --git a/CMakeLists.txt b/CMakeLists.txt index da19778..93c0dd7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ find_package(Python3 COMPONENTS Interpreter REQUIRED) if(NOT DEFINED DUSK_TARGET_SYSTEM) set(DUSK_TARGET_SYSTEM "linux") + # set(DUSK_TARGET_SYSTEM "psp") endif() # Toolchains diff --git a/src/display/display.c b/src/display/display.c index a7d8e34..a220f7d 100644 --- a/src/display/display.c +++ b/src/display/display.c @@ -193,22 +193,33 @@ errorret_t displayUpdate(void) { ); errorChain(sceneRender()); - color_t colors[4 * 4] = { - COLOR_RED_4B, COLOR_GREEN_4B, COLOR_BLUE_4B, COLOR_YELLOW_4B, - COLOR_CYAN_4B, COLOR_MAGENTA_4B, COLOR_WHITE_4B, COLOR_BLACK_4B, - COLOR_ORANGE_4B, COLOR_PURPLE_4B, COLOR_GRAY_4B, COLOR_BROWN_4B, - COLOR_PINK_4B, COLOR_LIME_4B, COLOR_NAVY_4B, COLOR_TEAL_4B + texture_t texture; + + // color_t colors[4 * 4] = { + // COLOR_RED_4B, COLOR_GREEN_4B, COLOR_BLUE_4B, COLOR_YELLOW_4B, + // COLOR_CYAN_4B, COLOR_MAGENTA_4B, COLOR_WHITE_4B, COLOR_BLACK_4B, + // COLOR_ORANGE_4B, COLOR_PURPLE_4B, COLOR_GRAY_4B, COLOR_BROWN_4B, + // COLOR_PINK_4B, COLOR_LIME_4B, COLOR_NAVY_4B, COLOR_TEAL_4B + // }; + // texturedata_t data = { + // .rgba = { .colors = colors } + // }; + // textureInit(&texture, 4, 4, TEXTURE_FORMAT_RGBA, data); + + uint8_t alphaData[8 * 4] = { + 255, 255, 255, 255, 255, 255, 255, 255, + 0, 0, 255, 0, 0, 255, 0, 0, + 255, 255, 255, 255, 255, 255, 255, 255, + 0, 0, 0, 255, 255, 0, 0, 0, }; texturedata_t data = { - .rgba = { .colors = colors } + .alpha = { .data = alphaData } }; + textureInit(&texture, 8, 4, TEXTURE_FORMAT_ALPHA, data); camera_t camera; cameraInit(&camera); - texture_t texture; - textureInit(&texture, 4, 4, TEXTURE_FORMAT_RGBA, data); - cameraPushMatrix(&camera); spriteBatchClear(); spriteBatchPush( @@ -221,7 +232,6 @@ errorret_t displayUpdate(void) { ); spriteBatchFlush(); cameraPopMatrix(); - textureDispose(&texture); // Render UI // uiRender(); @@ -245,6 +255,7 @@ errorret_t displayUpdate(void) { // if(DISPLAY.screenMode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); #endif + textureDispose(&texture); // For now, we just return an OK error. errorOk(); diff --git a/src/display/mesh/mesh.c b/src/display/mesh/mesh.c index a14bcfb..5ee8deb 100644 --- a/src/display/mesh/mesh.c +++ b/src/display/mesh/mesh.c @@ -9,6 +9,10 @@ #include "util/memory.h" #include "assert/assert.h" +#if DOLPHIN + #include "display/texture.h" +#endif + void meshInit( mesh_t *mesh, const meshprimitivetype_t primitiveType, @@ -90,40 +94,8 @@ void meshDraw( GX_SetArray(GX_VA_POS, &mesh->vertices[offset].pos[0], stride); GX_SetArray(GX_VA_CLR0, &mesh->vertices[offset].color, stride); GX_SetArray(GX_VA_TEX0, &mesh->vertices[offset].uv[0], stride); - - // GX_SetNumChans(1);// How many color channels are used - // GX_SetNumTexGens(0);// How many texture coordinate generators are used - // GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0); - // GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); - - // Basically the shader setup - GX_SetNumChans(1); - GX_SetChanCtrl( - GX_COLOR0A0,// Store in color channel 0 - GX_DISABLE,// Lighting disabled - GX_SRC_REG,// Ambient color? - GX_SRC_VTX,// Material color? - GX_LIGHTNULL,// Light Mask - GX_DF_NONE,// Diffuse function - GX_AF_NONE// Attenuation function - ); - - GX_SetNumTexGens(1); - GX_SetTexCoordGen( - GX_TEXCOORD0, - GX_TG_MTX2x4, - GX_TG_TEX0, - GX_IDENTITY - ); - - - GX_SetTevOrder( - GX_TEVSTAGE0, - GX_TEXCOORD0, - GX_TEXMAP0, - GX_COLOR0A0 - ); - GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + + textureDolphinUploadTEV(); GX_Begin(mesh->primitiveType, GX_VTXFMT0, (uint16_t)count); for(u16 i = 0; i < (u16)count; ++i) { diff --git a/src/display/texture.c b/src/display/texture.c index 8965398..7c923b3 100644 --- a/src/display/texture.c +++ b/src/display/texture.c @@ -147,69 +147,139 @@ void textureInit( texture->ready = true; #elif DOLPHIN - assertTrue((width % 4) == 0 && (height % 4) == 0, "RGB5A3 requires w/h multiple of 4 (or pad)"); - // Convert to RGB5A3 format - size_t rgbaSize = width * height * sizeof(u16); - texture->rgba = (u16*)memalign(32, rgbaSize); + texture->format = format; - for(uint32_t y = 0; y < height; ++y) { - for(uint32_t x = 0; x < width; ++x) { - const int src = y * width + x; + switch(format) { + case TEXTURE_FORMAT_RGBA: + assertTrue( + (width % 4) == 0 && (height % 4) == 0, + "RGB5A3 requires w/h multiple of 4 (or pad)" + ); - const int tileX = x >> 2; - const int tileY = y >> 2; - const int tilesPerRow = width >> 2; - const int tileIndex = tileY * tilesPerRow + tileX; - const int tileBaseWords = tileIndex * 16; - const int inTile = ((y & 3) << 2) + (x & 3); - const int dest = tileBaseWords + inTile; - - color4b_t col = data.rgba.colors[src]; + // Convert to RGB5A3 format + size_t rgbaSize = width * height * sizeof(u16); + texture->rgba = (u16*)memalign(32, rgbaSize); + assertNotNull(texture->rgba, "Failed to allocate texture RGBA data"); - u16 outCol; - if(col.a < 255) { - // 0AAA RRRR GGGG BBBB - outCol = ( - (0u << 15) | - ((u16)(col.a >> 5) << 12) | - ((u16)(col.r >> 4) << 8) | - ((u16)(col.g >> 4) << 4) | - ((u16)(col.b >> 4) << 0) - ); - } else { - // 1RRRR RRGG GGGB BBBB - outCol = ( - (1u << 15) | - ((u16)(col.r >> 3) << 10) | - ((u16)(col.g >> 3) << 5) | - ((u16)(col.b >> 3) << 0) - ); + for(uint32_t y = 0; y < height; ++y) { + for(uint32_t x = 0; x < width; ++x) { + const int src = y * width + x; + + const int tileX = x >> 2; + const int tileY = y >> 2; + const int tilesPerRow = width >> 2; + const int tileIndex = tileY * tilesPerRow + tileX; + const int tileBaseWords = tileIndex * 16; + const int inTile = ((y & 3) << 2) + (x & 3); + const int dest = tileBaseWords + inTile; + + color4b_t col = data.rgba.colors[src]; + + u16 outCol; + if(col.a < 255) { + // 0AAA RRRR GGGG BBBB + outCol = ( + (0u << 15) | + ((u16)(col.a >> 5) << 12) | + ((u16)(col.r >> 4) << 8) | + ((u16)(col.g >> 4) << 4) | + ((u16)(col.b >> 4) << 0) + ); + } else { + // 1RRRR RRGG GGGB BBBB + outCol = ( + (1u << 15) | + ((u16)(col.r >> 3) << 10) | + ((u16)(col.g >> 3) << 5) | + ((u16)(col.b >> 3) << 0) + ); + } + texture->rgba[dest] = outCol; + } } - texture->rgba[dest] = outCol; - } + + DCFlushRange(texture->rgba, rgbaSize); + GX_InitTexObj( + &texture->texObj, + texture->rgba, + width, height, + GX_TF_RGB5A3, + GX_CLAMP, GX_CLAMP, + GX_FALSE + ); + + DCFlushRange(texture->rgba, rgbaSize); + GX_InvalidateTexAll(); + + GX_InitTexObjLOD( + &texture->texObj, + GX_NEAR, GX_NEAR, + 0.0f, 0.0f, 0.0f, + GX_FALSE, + GX_FALSE, + GX_ANISO_1 + ); + break; + + case TEXTURE_FORMAT_ALPHA: + assertTrue( + (width % 4) == 0 && (height % 4) == 0, + "GX_TF_I8 requires w/h multiple of 4 (or pad)" + ); + + // 1 byte per pixel (I8), GX expects 4x4 tiled layout + const size_t alphaSize = (size_t)width * (size_t)height; + + texture->alpha = (u8*)memalign(32, alphaSize); + assertNotNull(texture->alpha, "Failed to allocate alpha texture data"); + + const u32 tilesPerRow = ((u32)width) >> 3; // /8 + + for (u32 y = 0; y < (u32)height; ++y) { + const u32 tileY = y >> 2; // /4 + const u32 inTileY = (y & 3) << 3; // (y%4)*8 + + for (u32 x = 0; x < (u32)width; ++x) { + const u32 srcI = y * (u32)width + x; + const u8 srcA = data.alpha.data[srcI]; // linear input + + const u32 tileX = x >> 3; // /8 + const u32 tileIndex = tileY * tilesPerRow + tileX; + + const u32 tileBase = tileIndex * 32; // 8*4*1 = 32 bytes per tile + const u32 inTile = inTileY + (x & 7); // (y%4)*8 + (x%8) + + texture->alpha[tileBase + inTile] = 0xFF - srcA;// Fixes inverted alpha. + } + } + + // Flush CPU cache so GX sees the swizzled I8 texture data + DCFlushRange(texture->alpha, alphaSize); + + // Initialize GX texture object with swizzled data + GX_InitTexObj( + &texture->texObj, + texture->alpha, + width, height, + GX_TF_I8, + GX_CLAMP, GX_CLAMP, + GX_FALSE + ); + + GX_InitTexObjLOD( + &texture->texObj, + GX_NEAR, GX_NEAR, + 0.0f, 0.0f, 0.0f, + GX_FALSE, + GX_FALSE, + GX_ANISO_1 + ); + break; + + default: + assertUnreachable("Unsupported texture format for Dolphin"); + break; } - DCFlushRange(texture->rgba, rgbaSize); - - GX_InitTexObj( - &texture->texObj, - texture->rgba, - width, height, - GX_TF_RGB5A3, - GX_CLAMP, GX_CLAMP, - GX_FALSE - ); - - DCFlushRange(texture->rgba, rgbaSize); - GX_InvalidateTexAll(); - - GX_InitTexObjLOD( - &texture->texObj, - GX_NEAR, GX_NEAR, - 0.0f, 0.0f, 0.0f, - GX_FALSE, - GX_FALSE, - GX_ANISO_1 - ); texture->ready = true; #endif @@ -238,7 +308,6 @@ void textureBind(texture_t *texture) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #elif DOLPHIN GX_LoadTexObj(&texture->texObj, GX_TEXMAP0); - #endif TEXTURE_BOUND = texture; } @@ -254,10 +323,126 @@ void textureDispose(texture_t *texture) { #if DISPLAY_SDL2 glDeleteTextures(1, &texture->id); #elif DOLPHIN - if(texture->rgba) { - free(texture->rgba); - texture->rgba = NULL; + switch(texture->format) { + case TEXTURE_FORMAT_RGBA: + free(texture->rgba); + break; + + case TEXTURE_FORMAT_ALPHA: + free(texture->alpha); + break; + + default: + break; } + memoryZero(texture, sizeof(texture_t)); #endif -} \ No newline at end of file +} + +#if DOLPHIN + void textureDolphinUploadTEV() { + // Add channel for vertex color + GX_SetNumChans(1); + GX_SetChanCtrl( + GX_COLOR0A0,// Store in color channel 0 + GX_DISABLE,// Lighting disabled + GX_SRC_REG,// Ambient color? + GX_SRC_VTX,// Material color? + GX_LIGHTNULL,// Light Mask + GX_DF_NONE,// Diffuse function + GX_AF_NONE// Attenuation function + ); + + if(!TEXTURE_BOUND) { + GX_SetNumTexGens(0); + GX_SetNumTevStages(1); + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + return; + } + + // One set of UVs + GX_SetNumTexGens(1); + GX_SetTexCoordGen( + GX_TEXCOORD0, + GX_TG_MTX2x4, + GX_TG_TEX0, + GX_IDENTITY + ); + + // Basically the shader setup + switch(TEXTURE_BOUND->format) { + case TEXTURE_FORMAT_RGBA: + // One TEV stage: vertex color * texture color + GX_SetNumTevStages(1); + GX_SetTevOrder( + GX_TEVSTAGE0, + GX_TEXCOORD0, + GX_TEXMAP0, + GX_COLOR0A0 + ); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + break; + + case TEXTURE_FORMAT_ALPHA: + // One TEV stage: vertex color * texture color + GX_SetNumTevStages(1); + GX_SetTevOrder( + GX_TEVSTAGE0, + GX_TEXCOORD0, + GX_TEXMAP0, + GX_COLOR0A0 + ); + + // Color = vertex color + GX_SetTevColorIn( + GX_TEVSTAGE0, + GX_CC_RASC, + GX_CC_ZERO, + GX_CC_ZERO, + GX_CC_ZERO + ); + GX_SetTevColorOp( + GX_TEVSTAGE0, + GX_TEV_ADD, + GX_TB_ZERO, + GX_CS_SCALE_1, + GX_TRUE, + GX_TEVPREV + ); + + // Alpha = vertex alpha * I8 intensity + GX_SetTevAlphaIn( + GX_TEVSTAGE0, + GX_CA_RASA, + GX_CA_ZERO, + GX_CA_TEXA, + GX_CA_ZERO + ); + GX_SetTevAlphaOp( + GX_TEVSTAGE0, + GX_TEV_ADD, + GX_TB_ZERO, + GX_CS_SCALE_1, + GX_TRUE, + GX_TEVPREV + ); + + GX_SetBlendMode( + GX_BM_BLEND, + GX_BL_SRCALPHA, + GX_BL_INVSRCALPHA, + GX_LO_CLEAR + ); + + GX_SetColorUpdate(GX_TRUE); + GX_SetAlphaUpdate(GX_TRUE); + + break; + + default: + assertUnreachable("Unknown texture format in meshDraw"); + break; + } + } +#endif \ No newline at end of file diff --git a/src/display/texture.h b/src/display/texture.h index c040457..edc133a 100644 --- a/src/display/texture.h +++ b/src/display/texture.h @@ -26,9 +26,10 @@ typedef struct { GLuint id; #elif DOLPHIN GXTexObj texObj; - + textureformat_t format; union { u16 *rgba; + u8 *alpha; }; #endif @@ -83,4 +84,11 @@ void textureBind(texture_t *texture); * * @param texture The texture to dispose. */ -void textureDispose(texture_t *texture); \ No newline at end of file +void textureDispose(texture_t *texture); + +#if DOLPHIN + /** + * Uploads the TEV settings for the currently bound texture. + */ + void textureDolphinUploadTEV(); +#endif \ No newline at end of file