Alpha textures
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -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);
|
||||
void textureDispose(texture_t *texture);
|
||||
|
||||
#if DOLPHIN
|
||||
/**
|
||||
* Uploads the TEV settings for the currently bound texture.
|
||||
*/
|
||||
void textureDolphinUploadTEV();
|
||||
#endif
|
||||
Reference in New Issue
Block a user