4bpp texture palette support, modified paletted_pcx sampled (USE_16C_PALETTE)

This commit is contained in:
OzzyOuzo 2021-11-18 12:04:46 +02:00
parent 37110ba47f
commit 148962254a
4 changed files with 311 additions and 10 deletions

View File

@ -238,7 +238,12 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank);
context->txr.format |= GPUPaletteSelect8BPP(palette->bank);
} else {
context->txr.format |= GPUPaletteSelect8BPP((tx1->palette) ? tx1->palette->bank : 0);
if (tx1->palette->size != 16){
context->txr.format |= GPUPaletteSelect8BPP((tx1->palette) ? tx1->palette->bank : 0);
}
else{
context->txr.format |= GPUPaletteSelect4BPP((tx1->palette) ? tx1->palette->bank : 0);
}
}
}

View File

@ -139,6 +139,41 @@ static void GPUTextureTwiddle8PPP(void* src, void* dst, uint32_t w, uint32_t h)
}
}
static void GPUTextureTwiddle4PPP(void* src, void* dst, uint32_t w, uint32_t h) {
uint32_t x, y, yout, min, mask;
min = MIN(w, h);
mask = min - 1;
uint8 * pixels;
uint16 * vtex;
pixels = (uint8 *) src;
vtex = (uint16*)dst;
for (y=0; y<h; y += 2) {
yout = y;
for (x=0; x<w; x += 2) {
//Ozzy note: if x alignment is wrong just use version commented instead (possible error)
#if 1
vtex[TWIDOUT((x&mask)/2, (yout&mask)/2) +
(x/min + yout/min)*min*min/4] =
vtex[TWIDOUT((x&mask)/2, (yout&mask)/2) +
(x/min + yout/min)*min*min/4] =
((pixels[(x+y*w) >>1]&15)<<8) | ((pixels[(x+(y+1)*w) >>1]&15)<<12) |
((pixels[(x+y*w) >>1]>>4)<<0) | ((pixels[(x+(y+1)*w) >>1]>>4)<<4);
#else
vtex[TWIDOUT((x&mask)/2, (yout&mask)/2) +
(x/min + yout/min)*min*min/4] =
(pixels[(x+y*w) >>1]&15) | ((pixels[(x+(y+1)*w) >>1]&15)<<4) |
((pixels[(x+y*w) >>1]>>4)<<8) | ((pixels[(x+(y+1)*w) >>1]>>4)<<12);
#endif
}
}
}
static void GPUTextureTwiddle16BPP(void * src, void* dst, uint32_t w, uint32_t h) {
uint32_t x, y, yout, min, mask;
@ -188,6 +223,7 @@ void _glApplyColorTable(TexturePalette* src) {
GLushort i;
GLushort offset = src->size * src->bank;
for(i = 0; i < src->width; ++i) {
GLubyte* entry = &src->data[i * 4];
if(INTERNAL_PALETTE_FORMAT == GL_RGBA8) {
@ -925,6 +961,7 @@ static TextureConversionFunc _determineConversion(GLint internalFormat, GLenum f
}
} break;
case GL_RGBA8: {
if(type == GL_UNSIGNED_BYTE && format == GL_RGBA) {
return _rgba8888_to_rgba8888;
} else if (type == GL_BYTE && format == GL_RGBA) {
@ -1071,7 +1108,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
return;
}
} else {
if(internalFormat != GL_COLOR_INDEX8_EXT) {
if(internalFormat != GL_COLOR_INDEX8_EXT && internalFormat != GL_COLOR_INDEX4_EXT) {
INFO_MSG("");
_glKosThrowError(GL_INVALID_ENUM, __func__);
return;
@ -1129,7 +1166,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
return;
}
GLboolean isPaletted = (internalFormat == GL_COLOR_INDEX8_EXT) ? GL_TRUE : GL_FALSE;
GLboolean isPaletted = (internalFormat == GL_COLOR_INDEX8_EXT || internalFormat == GL_COLOR_INDEX4_EXT) ? GL_TRUE : GL_FALSE;
/* Calculate the format that we need to convert the data to */
GLuint pvr_format = _determinePVRFormat(internalFormat, type);
@ -1161,6 +1198,11 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
GLint destStride = isPaletted ? 1 : 2;
GLuint bytes = (width * height * destStride);
//special case 4bpp
if(internalFormat == GL_COLOR_INDEX4_EXT){
bytes >>= 1;
}
if(!active->data) {
assert(active);
assert(width);
@ -1302,8 +1344,14 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
if(internalFormat == GL_COLOR_INDEX8_EXT) {
GPUTextureTwiddle8PPP((void*) pixels, targetData, width, height);
} else {
GPUTextureTwiddle16BPP((void*) pixels, targetData, width, height);
}
else{
if(internalFormat == GL_COLOR_INDEX4_EXT) {
GPUTextureTwiddle4PPP((void*) pixels, targetData, width, height);
}
else {
GPUTextureTwiddle16BPP((void*) pixels, targetData, width, height);
}
}
/* We make sure we remove nontwiddled and add twiddled. We could always
@ -1487,7 +1535,7 @@ GLAPI void APIENTRY glColorTableEXT(GLenum target, GLenum internalFormat, GLsize
}
palette->data = (GLubyte*) malloc(width * 4);
palette->format = format;
palette->format = format; //Ozzy:was previously forcing to GL_RGBA for testing.
palette->width = width;
palette->size = (width > 16) ? 256 : 16;
assert(palette->size == 16 || palette->size == 256);

View File

@ -19,19 +19,24 @@
KOS_INIT_ROMDISK(romdisk);
#endif
/* using 4bpp textures from BMP files instead of 8bpp from PCX files */
#define USE_16C_PALETTE
/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
int textures[3];
typedef struct {
unsigned int height;
unsigned int width;
unsigned int palette_width;
uint32_t height;
uint32_t width;
uint32_t palette_width;
char* palette;
char* data;
} Image;
#ifndef USE_16C_PALETTE
#pragma pack(push)
#pragma pack(1)
@ -135,11 +140,234 @@ int LoadPalettedPCX(const char* filename, Image* image) {
return 1;
}
#else
#define BMP_BI_RGB 0L
#define BMP_BI_UNCOMPRESSED 0L
#define BMP_BI_RLE8 1L
#define BMP_BI_RLE4 2L
#define BMP_BI_BITFIELDS 3L
#pragma pack(push)
#pragma pack(1)
typedef struct BITMAP_FILE_HEADER
{
uint16_t Type;
uint32_t Size;
uint16_t Reserved1;
uint16_t Reserved2;
uint32_t OffBits;
} BITMAP_FILE_HEADER;
typedef struct BITMAP_INFO_HEADER
{
uint32_t Size;
int32_t Width;
int32_t Height;
uint16_t Planes;
uint16_t BitCount;
uint32_t Compression;
uint32_t SizeImage;
int32_t XPelsPerMeter;
int32_t YPelsPerMeter;
uint32_t ClrUsed;
uint32_t ClrImportant;
} BITMAP_INFO_HEADER;
typedef struct RGB_QUAD
{
uint8_t Blue;
uint8_t Green;
uint8_t Red;
uint8_t Reserved;
} RGB_QUAD;
typedef struct BITMAP_INFO
{
BITMAP_INFO_HEADER Header;
RGB_QUAD Colors[1];
} BITMAP_INFO;
#pragma pack(pop)
/* some global variables used to load a 4bpp BMP file */
static BITMAP_FILE_HEADER BmpFileHeader;
static BITMAP_INFO_HEADER BmpInfoHeader;
static RGB_QUAD BmpRgbQuad[256];
static uint8_t BmpPal[256 * 3];
int BMP_Infos(FILE *pFile, uint32_t *width, uint32_t *height)
{
if (!pFile)
return 0;
if (fread(&BmpFileHeader.Type, 1, 2, pFile) != 2)
return 0;
if (fread(&BmpFileHeader.Size, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpFileHeader.Reserved1, 1, 2, pFile) != 2)
return 0;
if (fread(&BmpFileHeader.Reserved2, 1, 2, pFile) != 2)
return 0;
if (fread(&BmpFileHeader.OffBits, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.Size, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.Width, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.Height, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.Planes, 1, 2, pFile) != 2)
return 0;
if (fread(&BmpInfoHeader.BitCount, 1, 2, pFile) != 2)
return 0;
if (fread(&BmpInfoHeader.Compression, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.SizeImage, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.XPelsPerMeter, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.YPelsPerMeter, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.ClrUsed, 1, 4, pFile) != 4)
return 0;
if (fread(&BmpInfoHeader.ClrImportant, 1, 4, pFile) != 4)
return 0;
*width = (uint32_t)BmpInfoHeader.Width;
*height = (uint32_t)BmpInfoHeader.Height;
return 1;
}
int BMP_GetPalette(FILE *pFile)
{
int32_t i,bitCount;
if (BmpInfoHeader.BitCount == 4) {
if (!BmpInfoHeader.ClrImportant) {
BmpInfoHeader.ClrImportant = 16;
}
bitCount = BmpInfoHeader.ClrImportant * sizeof(RGB_QUAD);
if (fread(BmpRgbQuad, 1, bitCount, pFile) != bitCount){
return 0;
}
for (i = 0; i < BmpInfoHeader.ClrImportant; i++) {
BmpPal[i * 3] = (uint8_t)BmpRgbQuad[i].Red;
BmpPal[i * 3 + 1] = (uint8_t)BmpRgbQuad[i].Green;
BmpPal[i * 3 + 2] = (uint8_t)BmpRgbQuad[i].Blue;
}
return 1;
}
return 0;
}
/* maybe not the best BMP loader... */
int BMP_Depack(FILE *pFile,char *pZone)
{
char PadRead[4];
int32_t i, j, Offset, PadSize, pix, c;
if (BmpInfoHeader.Compression != BMP_BI_RGB)
return 0;
PadSize = (BmpInfoHeader.Width & 3);
PadSize = (4 - (BmpInfoHeader.Width & 3)) & 3;
for (i = BmpInfoHeader.Height - 1; (i > -1); i--) {
Offset = i * BmpInfoHeader.Width / 2;
if (PadSize < 4) {
for (j = 0; (j < BmpInfoHeader.Width / 2); j++) {
if (!fread(&c, 1, 1, pFile)) {
return 0;
}
pZone[Offset + j] = c;
}
}
if (PadSize) {
if (fread(PadRead, PadSize, 1, pFile) != PadSize) {
return 0;
}
}
}
if (i != -1) {
return 0;
}
return 1;
}
int LoadPalettedBMP(const char* filename, Image* image)
{
FILE *fp;
uint32_t bytes;
if (filename == NULL || image == NULL) {
printf("Invalid NULL argument\n");
return 0;
}
fp = fopen(filename, "rb");
if (fp == NULL) {
printf("Unable to open file\n");
return 0;
}
if (!BMP_Infos(fp, &image->width, &image->height)) {
printf("Error reading BMP:%s header\n",filename);
return 0;
}
if (!BMP_GetPalette(fp)) {
printf("Only 16c BMP are supported for this sample");
return 0;
}
/* store palette information */
image->palette = BmpPal;
image->palette_width = 16;
bytes = sizeof(char) * image->width * image->height;
/* 4bpp is half byte size*/
bytes >>= 1;
image->data = (char*)malloc(bytes);
if (image->data == NULL) {
printf("Error allocating image data");
return 0;
}
if (!BMP_Depack(fp, image->data)) {
printf("Error depacking BMP:%s",filename);
return 0;
}
fclose(fp);
return 1;
}
#endif
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {
// Load Texture
Image image1, image2;
#ifndef USE_16C_PALETTE
if(!LoadPalettedPCX("/rd/NeHe.pcx", &image1)) {
exit(1);
}
@ -147,6 +375,15 @@ void LoadGLTextures() {
if(!LoadPalettedPCX("/rd/NeHe-Alpha.pcx", &image2)) {
exit(1);
}
#else
if (!LoadPalettedBMP("/rd/NeHe.bmp", &image1)) {
exit(1);
}
if (!LoadPalettedBMP("/rd/NeHe-Alpha.bmp", &image2)) {
exit(1);
}
#endif
glEnable(GL_SHARED_TEXTURE_PALETTE_EXT);
@ -173,7 +410,11 @@ void LoadGLTextures() {
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
#ifndef USE_16C_PALETTE
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1.width, image1.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image1.data);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX4_EXT, image1.width, image1.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image1.data);
#endif
glBindTexture(GL_TEXTURE_2D, textures[1]); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); // scale linearly when image bigger than texture
@ -184,7 +425,11 @@ void LoadGLTextures() {
// 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
// border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
#ifndef USE_16C_PALETTE
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1.width, image1.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image1.data);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX4_EXT, image1.width, image1.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image1.data);
#endif
glBindTexture(GL_TEXTURE_2D, textures[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -199,8 +444,11 @@ void LoadGLTextures() {
}
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, image2.palette_width, GL_RGBA, GL_UNSIGNED_BYTE, new_palette);
#ifndef USE_16C_PALETTE
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image2.width, image2.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image2.data);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX4_EXT, image2.width, image2.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image2.data);
#endif
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 64 KiB