diff --git a/src/dusk/display/display.c b/src/dusk/display/display.c index 35ede95..19bae08 100644 --- a/src/dusk/display/display.c +++ b/src/dusk/display/display.c @@ -61,17 +61,17 @@ errorret_t displayInit(void) { 7,7,7,7,7,7,7,7 }; - errorChain(textureInit( - &PALETTE_TEXTURE, - 8, 8, - TEXTURE_FORMAT_PALETTE, - (texturedata_t){ - .paletted = { - .indices = indices, - .palette = &PALETTES[0] - } - } - )); + // errorChain(textureInit( + // &PALETTE_TEXTURE, + // 8, 8, + // TEXTURE_FORMAT_PALETTE, + // (texturedata_t){ + // .paletted = { + // .indices = indices, + // .palette = &PALETTES[0] + // } + // } + // )); errorChain(textureInit( &UNCOMPRESSED_TEXTURE, diff --git a/src/duskdolphin/display/mesh/meshdolphin.c b/src/duskdolphin/display/mesh/meshdolphin.c index 022bde2..abce460 100644 --- a/src/duskdolphin/display/mesh/meshdolphin.c +++ b/src/duskdolphin/display/mesh/meshdolphin.c @@ -47,8 +47,6 @@ errorret_t meshDrawDolphin( assertTrue(offsetof(meshvertex_t, uv) == 4, "uv offset wrong"); assertTrue(offsetof(meshvertex_t, pos) == 12, "pos offset wrong"); - textureDolphinUploadTEV(); - DCFlushRange( (void*)&mesh->vertices[vertexOffset], sizeof(meshvertex_t) * vertexCount diff --git a/src/duskdolphin/display/shader/shaderdolphin.c b/src/duskdolphin/display/shader/shaderdolphin.c index 9b2eb95..87c348a 100644 --- a/src/duskdolphin/display/shader/shaderdolphin.c +++ b/src/duskdolphin/display/shader/shaderdolphin.c @@ -77,6 +77,88 @@ errorret_t shaderSetMatrixDolphin( errorOk(); } +errorret_t shaderSetTextureDolphin( + shaderdolphin_t *shader, + const char_t *name, + texture_t *texture +) { + assertNotNull(shader, "Shader must not be null"); + assertNotNull(name, "Uniform name must not be null"); + assertStrLenMin(name, 1, "Uniform name cannot be empty"); + + if(texture == NULL) { + // GX_SetNumChans(0); + GX_SetNumChans(1); + GX_SetChanCtrl( + GX_COLOR0A0, + GX_DISABLE, + GX_SRC_REG, + GX_SRC_VTX, + GX_LIGHTNULL, + GX_DF_NONE, + GX_AF_NONE + ); + GX_SetChanAmbColor(GX_COLOR0A0, (GXColor){ 0, 0, 0, 0 }); + GX_SetChanMatColor(GX_COLOR0A0, (GXColor){ 255, 255, 255, 255 }); + + GX_SetNumTexGens(0); + + GX_SetNumTevStages(1); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + + GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + + errorOk(); + } + + // Add channel for vertex color + GX_LoadTexObj(&texture->texObj, GX_TEXMAP0); + 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 + ); + + // 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->format) { + case TEXTURE_FORMAT_RGBA: + // One TEV stage: vertex color * texture color + GX_SetNumTevStages(1); + GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); + GX_SetTevOrder( + GX_TEVSTAGE0, + GX_TEXCOORD0, + GX_TEXMAP0, + GX_COLOR0A0 + ); + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + break; + + default: + assertUnreachable("Unknown texture format in meshDraw"); + break; + } + + errorOk(); +} + errorret_t shaderDisposeDolphin(shaderdolphin_t *shader) { assertNotNull(shader, "Shader must not be null"); diff --git a/src/duskdolphin/display/shader/shaderdolphin.h b/src/duskdolphin/display/shader/shaderdolphin.h index c8c8a6e..f64e8a5 100644 --- a/src/duskdolphin/display/shader/shaderdolphin.h +++ b/src/duskdolphin/display/shader/shaderdolphin.h @@ -6,7 +6,7 @@ */ #pragma once -#include "error/error.h" +#include "display/texture/texture.h" typedef struct { mat4 view; @@ -66,6 +66,20 @@ errorret_t shaderSetMatrixDolphin( mat4 matrix ); +/** + * Sets a texture uniform in the dolphin shader. Basically does nothing. + * + * @param shader Shader to set the texture in. + * @param name Name of the uniform to set. + * @param texture Texture to set. + * @return Error code if failure. + */ +errorret_t shaderSetTextureDolphin( + shaderdolphin_t *shader, + const char_t *name, + texture_t *texture +); + /** * Disposes a dolphin shader. Basically does nothing. * diff --git a/src/duskdolphin/display/shader/shaderplatform.h b/src/duskdolphin/display/shader/shaderplatform.h index 5e7eb35..dab85d6 100644 --- a/src/duskdolphin/display/shader/shaderplatform.h +++ b/src/duskdolphin/display/shader/shaderplatform.h @@ -14,5 +14,5 @@ typedef shaderdefinitiondolphin_t shaderdefinitionplatform_t; #define shaderInitPlatform shaderInitDolphin #define shaderBindPlatform shaderBindDolphin #define shaderSetMatrixPlatform shaderSetMatrixDolphin -// #define shaderSetTexturePlatform shaderSetTextureDolphin +#define shaderSetTexturePlatform shaderSetTextureDolphin #define shaderDisposePlatform shaderDisposeDolphin \ No newline at end of file diff --git a/src/duskdolphin/display/texture/texturedolphin.c b/src/duskdolphin/display/texture/texturedolphin.c index 5b429f7..2721975 100644 --- a/src/duskdolphin/display/texture/texturedolphin.c +++ b/src/duskdolphin/display/texture/texturedolphin.c @@ -7,6 +7,7 @@ #include "display/texture/texture.h" #include "assert/assert.h" +#include "util/memory.h" errorret_t textureInitDolphin( texturedolphin_t *texture, @@ -15,191 +16,178 @@ errorret_t textureInitDolphin( const textureformatdolphin_t format, const texturedata_t data ) { - // switch(format) { - // case TEXTURE_FORMAT_RGBA: - // assertTrue( - // (width % 4) == 0 && (height % 4) == 0, - // "RGB5A3 requires w/h multiple of 4 (or pad)" - // ); + switch(format) { + case TEXTURE_FORMAT_RGBA: { + size_t rgbaSize = width * height * sizeof(uint8_t) * 4; - // // 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"); + // Dolphin takes the RGBA data as 4x4 tiled layout. + texture->rgba = memoryAllocate(rgbaSize); + + for(uint32_t y = 0; y < height; ++y) { + for(uint32_t x = 0; x < width; ++x) { + const int src = y * width + x; - // 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 inTile = ((y & 3) << 2) + (x & 3); + const int tileBase = tileIndex * 64; - // 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; + color_t col = data.rgbaColors[src]; + + // AR plane + texture->rgba[tileBase + inTile * 2 + 0] = col.a; + texture->rgba[tileBase + inTile * 2 + 1] = col.r; + + // GB plane + texture->rgba[tileBase + 32 + inTile * 2 + 0] = col.g; + texture->rgba[tileBase + 32 + inTile * 2 + 1] = col.b; + } + } + DCFlushRange(texture->rgba, rgbaSize); + GX_InitTexObj( + &texture->texObj, + texture->rgba, + width, height, + format, + GX_REPEAT, GX_REPEAT, + 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_RGB4A3: { + assertUnreachable("RGB4A3 texture format not yet implemented"); + } + + case TEXTURE_FORMAT_RGB5: { + assertUnreachable("RGB5 texture format not yet implemented"); + } + + // assertTrue( + // (width % 4) == 0 && (height % 4) == 0, + // "RGB4A3 requires w/h multiple of 4 (or pad)" + // ); + + // // Convert to RGB4A3 format + // size_t rgbaSize = width * height * sizeof(u16); + // texture->rgba = (u16*)memalign(32, rgbaSize); + // assertNotNull(texture->rgba, "Failed to allocate texture RGBA data"); + + // 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]; + // color4b_t col = data.rgbaColors[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; - // } - // } + // 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; + // } + // } - // DCFlushRange(texture->rgba, rgbaSize); - // GX_InitTexObj( - // &texture->texObj, - // texture->rgba, - // width, height, - // GX_TF_RGB5A3, - // GX_REPEAT, GX_REPEAT, - // GX_FALSE - // ); + // DCFlushRange(texture->rgba, rgbaSize); + // GX_InitTexObj( + // &texture->texObj, + // texture->rgba, + // width, height, + // GX_TF_RGB5A3, + // GX_REPEAT, GX_REPEAT, + // GX_FALSE + // ); - // DCFlushRange(texture->rgba, rgbaSize); - // GX_InvalidateTexAll(); + // 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; + // GX_InitTexObjLOD( + // &texture->texObj, + // GX_NEAR, GX_NEAR, + // 0.0f, 0.0f, 0.0f, + // GX_FALSE, + // GX_FALSE, + // GX_ANISO_1 + // ); - // case TEXTURE_FORMAT_PALETTE: { - // // Not supported, convert to RGBA using lookup - // color_t* formatted = memoryAllocate(width * height * sizeof(color_t)); - // for(int32_t i = 0; i < width * height; i++) { - // uint8_t index = data.palette.data[i]; - // assertTrue( - // index < data.palette.palette->colorCount, - // "Palette index out of range" - // ); - // formatted[i] = data.palette.palette->colors[index]; - // } + case TEXTURE_FORMAT_PALETTE: { + assertUnreachable("Paletted textures not yet implemented for Dolphin"); + break; + } - // textureInit( - // texture, width, height, TEXTURE_FORMAT_RGBA, - // (texturedata_t){ - // .rgba = { .colors = formatted } - // } - // ); - // memoryFree(formatted); - // break; - // } - - // default: - // assertUnreachable("Unsupported texture format for Dolphin"); - // break; - // } - - // texture->ready = true; - - errorOk(); -} - -errorret_t textureBindDolphin(texturedolphin_t *texture) { - if(texture == NULL) { - GX_SetNumChans(0); - errorOk(); + default: { + assertUnreachable("Unsupported texture format for Dolphin"); + break; + } } - - GX_SetNumChans(1); - GX_LoadTexObj(&texture->texObj, GX_TEXMAP0); + errorOk(); } + errorret_t textureDisposeDolphin(texturedolphin_t *texture) { - errorOk(); -} + switch(texture->format) { + case TEXTURE_FORMAT_RGBA: { + if(texture->rgba) { + memoryFree(texture->rgba); + texture->rgba = NULL; + } + break; + } -void textureDolphinUploadTEV(void) { - if(TEXTURE_BOUND == NULL) { - GX_SetNumChans(1); - GX_SetChanCtrl( - GX_COLOR0A0, - GX_DISABLE, - GX_SRC_REG, - GX_SRC_VTX, - GX_LIGHTNULL, - GX_DF_NONE, - GX_AF_NONE - ); - GX_SetChanAmbColor(GX_COLOR0A0, (GXColor){0, 0, 0, 0}); - GX_SetChanMatColor(GX_COLOR0A0, (GXColor){255, 255, 255, 255}); - - GX_SetNumTexGens(0); - - GX_SetNumTevStages(1); - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0); - GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); - - GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); - GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + case TEXTURE_FORMAT_RGB4A3: { + assertUnreachable("RGB4A3 texture format not yet implemented"); + } - return; - } + case TEXTURE_FORMAT_RGB5: { + assertUnreachable("RGB5 texture format not yet implemented"); + } - // 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 - ); - - // 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_SetTevOp(GX_TEVSTAGE0, GX_MODULATE); - GX_SetTevOrder( - GX_TEVSTAGE0, - GX_TEXCOORD0, - GX_TEXMAP0, - GX_COLOR0A0 - ); - GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); - GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + case TEXTURE_FORMAT_PALETTE: { + assertUnreachable("Paletted textures not yet implemented for Dolphin"); break; + } - default: - assertUnreachable("Unknown texture format in meshDraw"); + default: { + assertUnreachable("Unsupported texture format for Dolphin"); break; + } } + errorOk(); } \ No newline at end of file diff --git a/src/duskdolphin/display/texture/texturedolphin.h b/src/duskdolphin/display/texture/texturedolphin.h index 311e2d8..e2beb80 100644 --- a/src/duskdolphin/display/texture/texturedolphin.h +++ b/src/duskdolphin/display/texture/texturedolphin.h @@ -13,6 +13,8 @@ typedef union texturedata_u texturedata_t; typedef enum { TEXTURE_FORMAT_RGBA = GX_TF_RGBA8, TEXTURE_FORMAT_PALETTE = GX_TF_CI8, + TEXTURE_FORMAT_RGB4A3 = GX_TF_RGB5A3, + TEXTURE_FORMAT_RGB5 = GX_TF_RGB565, } textureformatdolphin_t; typedef struct { @@ -20,6 +22,11 @@ typedef struct { textureformatdolphin_t format; int32_t width; int32_t height; + + union { + uint8_t *rgba; + // u16 *rgba; + }; } texturedolphin_t; /** @@ -54,10 +61,4 @@ errorret_t textureBindDolphin(texturedolphin_t *texture); * @param texture The texture to dispose. * @return An error if the texture failed to dispose, otherwise success. */ -errorret_t textureDisposeDolphin(texturedolphin_t *texture); - -/** - * Internal method that uploads the texture environment variables to the GPU - * for rendering. This is basically uploading the shader information. - */ -void textureDolphinUploadTEV(void); \ No newline at end of file +errorret_t textureDisposeDolphin(texturedolphin_t *texture); \ No newline at end of file