Fixed alpha textures properly on PSP
This commit is contained in:
@@ -74,7 +74,7 @@ if(ENABLE_TESTS)
|
|||||||
${DUSK_LIBRARY_TARGET_NAME}
|
${DUSK_LIBRARY_TARGET_NAME}
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
set(DUSK_BINARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
set(DUSK_LIBRARY_TARGET_NAME "${DUSK_BINARY_TARGET_NAME}" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
|
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "assetpaletteimage.h"
|
#include "assetpaletteimage.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "display/texture.h"
|
#include "display/texture.h"
|
||||||
|
#include "display/palette/palettelist.h"
|
||||||
|
|
||||||
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
||||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||||
@@ -20,6 +21,9 @@ errorret_t assetPaletteImageLoad(void *data, void *output) {
|
|||||||
assetData->width = le32toh(assetData->width);
|
assetData->width = le32toh(assetData->width);
|
||||||
assetData->height = le32toh(assetData->height);
|
assetData->height = le32toh(assetData->height);
|
||||||
|
|
||||||
|
const palette_t *pal = PALETTE_LIST[assetData->paletteIndex];
|
||||||
|
assertNotNull(pal, "Palette index is out of bounds");
|
||||||
|
|
||||||
textureInit(
|
textureInit(
|
||||||
texture,
|
texture,
|
||||||
assetData->width,
|
assetData->width,
|
||||||
@@ -27,7 +31,7 @@ errorret_t assetPaletteImageLoad(void *data, void *output) {
|
|||||||
TEXTURE_FORMAT_PALETTE,
|
TEXTURE_FORMAT_PALETTE,
|
||||||
(texturedata_t){
|
(texturedata_t){
|
||||||
.palette = {
|
.palette = {
|
||||||
.palette = assetData->paletteIndex,
|
.palette = pal,
|
||||||
.data = assetData->palette
|
.data = assetData->palette
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
|
#include "util/string.h"
|
||||||
#include "display/palette/palettelist.h"
|
#include "display/palette/palettelist.h"
|
||||||
|
|
||||||
const texture_t *TEXTURE_BOUND = NULL;
|
const texture_t *TEXTURE_BOUND = NULL;
|
||||||
@@ -55,70 +56,35 @@ void textureInit(
|
|||||||
assertNotNull(data.alpha.data, "Alpha texture data cannot be NULL");
|
assertNotNull(data.alpha.data, "Alpha texture data cannot be NULL");
|
||||||
#if PSP
|
#if PSP
|
||||||
// PSP kinda broken with alpha textures, so we convert it to paletted
|
// PSP kinda broken with alpha textures, so we convert it to paletted
|
||||||
// texture here.
|
// texture here. We also crunch the amount of alpha values.
|
||||||
uint8_t colorCount = 0;
|
#define PSP_ALPHA_PALETTE_CRUNCH 4
|
||||||
uint8_t alphas[UINT8_MAX] = { 0 };
|
#define PSP_ALPHA_PALETTE_COUNT (256 / PSP_ALPHA_PALETTE_CRUNCH)
|
||||||
uint8_t colorIndex[width * height];
|
|
||||||
|
color_t paletteColors[PSP_ALPHA_PALETTE_COUNT];
|
||||||
|
for(uint8_t i = 0; i < PSP_ALPHA_PALETTE_COUNT; i++) {
|
||||||
|
paletteColors[i].r = 0xFF;
|
||||||
|
paletteColors[i].g = 0xFF;
|
||||||
|
paletteColors[i].b = 0xFF;
|
||||||
|
paletteColors[i].a = i * PSP_ALPHA_PALETTE_CRUNCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate indexes, crunching the alpha values to fit.
|
||||||
|
uint8_t indexes[width * height];
|
||||||
for(int32_t i = 0; i < width * height; i++) {
|
for(int32_t i = 0; i < width * height; i++) {
|
||||||
uint8_t alpha = data.alpha.data[i];
|
uint8_t alpha = data.alpha.data[i] / PSP_ALPHA_PALETTE_CRUNCH;;
|
||||||
|
indexes[i] = alpha;
|
||||||
// Already in the palette?
|
|
||||||
bool_t exists = false;
|
|
||||||
uint8_t j = 0;
|
|
||||||
for(j = 0; j < colorCount; j++) {
|
|
||||||
if(alphas[j] != alpha) continue;
|
|
||||||
exists = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if found use existing index, otherwise add to palette
|
|
||||||
if(exists) {
|
|
||||||
colorIndex[i] = j;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Should never happen given the format, but just in case:
|
|
||||||
assertTrue(
|
|
||||||
colorCount < UINT8_MAX,
|
|
||||||
"Too many unique alpha values for paletted texture"
|
|
||||||
);
|
|
||||||
colorIndex[i] = colorCount;
|
|
||||||
alphas[colorCount] = alpha;
|
|
||||||
colorCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad color count to power of two for PSP
|
palette_t palette = {
|
||||||
uint8_t paddedColorCount = mathNextPowTwo(colorCount);
|
.colorCount = PSP_ALPHA_PALETTE_COUNT,
|
||||||
printf(
|
.colors = paletteColors
|
||||||
"Converted alpha texture to paletted format with %u unique alpha values (padded to %u)\n",
|
};
|
||||||
colorCount, paddedColorCount
|
|
||||||
);
|
|
||||||
|
|
||||||
// Create a palette with the unique alpha values
|
return textureInit(
|
||||||
texture->palette = (color4b_t*)memoryAllocate(
|
texture, width, height, TEXTURE_FORMAT_PALETTE,
|
||||||
sizeof(color4b_t) * paddedColorCount
|
(texturedata_t){
|
||||||
);
|
.palette = { .palette = &palette, .data = indexes }
|
||||||
memoryZero(texture->palette, sizeof(color4b_t) * paddedColorCount);
|
}
|
||||||
for(uint8_t i = 0; i < colorCount; i++) {
|
|
||||||
texture->palette[i].r = 0;
|
|
||||||
texture->palette[i].g = 0;
|
|
||||||
texture->palette[i].b = 0;
|
|
||||||
texture->palette[i].a = alphas[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Uploading paletted texture to GPU\n");
|
|
||||||
texture->format = TEXTURE_FORMAT_PALETTE;
|
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D,
|
|
||||||
0, GL_COLOR_INDEX8_EXT,
|
|
||||||
width, height,
|
|
||||||
0, GL_COLOR_INDEX8_EXT,
|
|
||||||
GL_UNSIGNED_BYTE, (void*)colorIndex
|
|
||||||
);
|
|
||||||
glColorTableEXT(
|
|
||||||
GL_TEXTURE_2D, GL_RGBA, paddedColorCount, GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE, (const void*)texture->palette
|
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
glTexImage2D(
|
glTexImage2D(
|
||||||
@@ -131,14 +97,9 @@ void textureInit(
|
|||||||
|
|
||||||
case TEXTURE_FORMAT_PALETTE:
|
case TEXTURE_FORMAT_PALETTE:
|
||||||
assertNotNull(data.palette.data, "Palette texture data cannot be NULL");
|
assertNotNull(data.palette.data, "Palette texture data cannot be NULL");
|
||||||
assertTrue(
|
assertNotNull(data.palette.palette, "Palette cannot be NULL");
|
||||||
data.palette.palette < PALETTE_LIST_COUNT,
|
|
||||||
"Palette index out of range"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get and validate the palette.
|
// Get and validate the palette.
|
||||||
const palette_t *pal = PALETTE_LIST[data.palette.palette];
|
|
||||||
assertNotNull(pal, "Palette cannot be NULL");
|
|
||||||
GLenum err = glGetError();
|
GLenum err = glGetError();
|
||||||
if(err != GL_NO_ERROR) {
|
if(err != GL_NO_ERROR) {
|
||||||
assertUnreachable("GL Error before setting color table");
|
assertUnreachable("GL Error before setting color table");
|
||||||
@@ -153,10 +114,14 @@ void textureInit(
|
|||||||
GLint mask = 0;
|
GLint mask = 0;
|
||||||
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||||
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
||||||
GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
GLint numExtens = 0;
|
||||||
for(GLint i=0; i<n; ++i) {
|
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtens);
|
||||||
|
for(GLint i = 0; i < numExtens; ++i) {
|
||||||
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
if(e && strcmp(e, "GL_EXT_paletted_texture")==0) { havePalTex = true; break; }
|
if(!e) continue;
|
||||||
|
if(stringCompare(e, "GL_EXT_paletted_texture") != 0) continue;
|
||||||
|
havePalTex = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
||||||
@@ -170,10 +135,10 @@ void textureInit(
|
|||||||
for(int32_t i = 0; i < width * height; i++) {
|
for(int32_t i = 0; i < width * height; i++) {
|
||||||
uint8_t index = data.palette.data[i];
|
uint8_t index = data.palette.data[i];
|
||||||
assertTrue(
|
assertTrue(
|
||||||
index < pal->colorCount,
|
index < data.palette.palette->colorCount,
|
||||||
"Palette index out of range"
|
"Palette index out of range"
|
||||||
);
|
);
|
||||||
formatted[i] = pal->colors[index];
|
formatted[i] = data.palette.palette->colors[index];
|
||||||
}
|
}
|
||||||
glTexImage2D(
|
glTexImage2D(
|
||||||
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||||
@@ -184,7 +149,8 @@ void textureInit(
|
|||||||
#if PSP
|
#if PSP
|
||||||
// PSP requires the color table itself to be a power of two
|
// PSP requires the color table itself to be a power of two
|
||||||
assertTrue(
|
assertTrue(
|
||||||
pal->colorCount == mathNextPowTwo(pal->colorCount),
|
data.palette.palette->colorCount ==
|
||||||
|
mathNextPowTwo(data.palette.palette->colorCount),
|
||||||
"Palette color count must be a power of 2 for PSP"
|
"Palette color count must be a power of 2 for PSP"
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
@@ -198,8 +164,8 @@ void textureInit(
|
|||||||
);
|
);
|
||||||
|
|
||||||
glColorTableEXT(
|
glColorTableEXT(
|
||||||
GL_TEXTURE_2D, GL_RGBA, pal->colorCount, GL_RGBA,
|
GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA,
|
||||||
GL_UNSIGNED_BYTE, (const void*)pal->colors
|
GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,12 +359,6 @@ void textureDispose(texture_t *texture) {
|
|||||||
|
|
||||||
#if DISPLAY_SDL2
|
#if DISPLAY_SDL2
|
||||||
glDeleteTextures(1, &texture->id);
|
glDeleteTextures(1, &texture->id);
|
||||||
#if PSP
|
|
||||||
if(texture->palette) {
|
|
||||||
memoryFree(texture->palette);
|
|
||||||
texture->palette = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#elif DOLPHIN
|
#elif DOLPHIN
|
||||||
switch(texture->format) {
|
switch(texture->format) {
|
||||||
case TEXTURE_FORMAT_RGBA:
|
case TEXTURE_FORMAT_RGBA:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "display/color.h"
|
#include "display/color.h"
|
||||||
#include "display/displaydefs.h"
|
#include "display/displaydefs.h"
|
||||||
|
#include "display/palette/palette.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
#if DISPLAY_SDL2
|
#if DISPLAY_SDL2
|
||||||
@@ -24,9 +25,6 @@ typedef enum {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
#if DISPLAY_SDL2
|
#if DISPLAY_SDL2
|
||||||
GLuint id;
|
GLuint id;
|
||||||
#if PSP
|
|
||||||
color4b_t *palette;
|
|
||||||
#endif
|
|
||||||
#elif DOLPHIN
|
#elif DOLPHIN
|
||||||
GXTexObj texObj;
|
GXTexObj texObj;
|
||||||
union {
|
union {
|
||||||
@@ -47,7 +45,7 @@ typedef union {
|
|||||||
} rgba;
|
} rgba;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t palette;
|
const palette_t *palette;
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
} palette;
|
} palette;
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,9 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <sys/endian.h>
|
#include <sys/endian.h>
|
||||||
#else
|
#else
|
||||||
#define le32toh(x) (x)
|
#ifndef le32toh
|
||||||
|
#define le32toh(x) (x)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef bool bool_t;
|
typedef bool bool_t;
|
||||||
|
|||||||
Reference in New Issue
Block a user