Implement mipmap generation for paletted textures

This commit is contained in:
Luke Benstead 2019-09-26 09:17:07 +01:00
parent 08ba39f6d1
commit 2c5b71b2b0
3 changed files with 94 additions and 67 deletions

View File

@ -111,27 +111,27 @@ static inline GLubyte B1555(GLushort v) {
return (v & MASK) << 3;
}
static inline GLuint A4444(GLuint v) {
static inline GLubyte A4444(GLushort v) {
const GLuint MASK = (0xF << 12);
return (v & MASK) >> 12;
}
static inline GLuint R4444(GLuint v) {
static inline GLubyte R4444(GLushort v) {
const GLuint MASK = (0xF << 8);
return (v & MASK) >> 8;
}
static inline GLuint G4444(GLuint v) {
static inline GLubyte G4444(GLushort v) {
const GLuint MASK = (0xF << 4);
return (v & MASK) >> 4;
}
static inline GLuint B4444(GLuint v) {
static inline GLubyte B4444(GLushort v) {
const GLuint MASK = (0xF << 0);
return (v & MASK) >> 0;
}
static inline GLubyte R565(GLshort v) {
static inline GLubyte R565(GLushort v) {
const GLuint MASK = (31 << 11);
return (v & MASK) >> 8;
}
@ -149,7 +149,19 @@ static inline GLubyte B565(GLushort v) {
GLboolean _glCalculateAverageTexel(GLuint pvrFormat, const GLubyte* src1, const GLubyte* src2, const GLubyte* src3, const GLubyte* src4, GLubyte* t) {
GLuint a, r, g, b;
if((pvrFormat & PVR_TXRFMT_RGB565) == PVR_TXRFMT_RGB565) {
GLubyte format = ((pvrFormat & (1 << 27)) | (pvrFormat & (1 << 26))) >> 26;
const GLubyte ARGB1555 = 0;
const GLubyte ARGB4444 = 1;
const GLubyte RGB565 = 2;
if((pvrFormat & PVR_TXRFMT_PAL8BPP) == PVR_TXRFMT_PAL8BPP) {
/* Paletted... all we can do really is just pick one of the
* 4 texels.. unless we want to change the palette (bad) or
* pick the closest available colour (slow, and probably bad)
*/
*t = *src1;
} else if(format == RGB565) {
GLushort* s1 = (GLushort*) src1;
GLushort* s2 = (GLushort*) src2;
GLushort* s3 = (GLushort*) src3;
@ -165,44 +177,44 @@ GLboolean _glCalculateAverageTexel(GLuint pvrFormat, const GLubyte* src1, const
b /= 4;
*d1 = PACK_RGB565(r, g, b);
} else if(format == ARGB4444) {
GLushort* s1 = (GLushort*) src1;
GLushort* s2 = (GLushort*) src2;
GLushort* s3 = (GLushort*) src3;
GLushort* s4 = (GLushort*) src4;
GLushort* d1 = (GLushort*) t;
a = A4444(*s1) + A4444(*s2) + A4444(*s3) + A4444(*s4);
r = R4444(*s1) + R4444(*s2) + R4444(*s3) + R4444(*s4);
g = G4444(*s1) + G4444(*s2) + G4444(*s3) + G4444(*s4);
b = B4444(*s1) + B4444(*s2) + B4444(*s3) + B4444(*s4);
a /= 4;
r /= 4;
g /= 4;
b /= 4;
*d1 = PACK_ARGB4444(a, r, g, b);
} else {
if((pvrFormat & PVR_TXRFMT_ARGB4444) == PVR_TXRFMT_ARGB4444) {
GLushort* s1 = (GLushort*) src1;
GLushort* s2 = (GLushort*) src2;
GLushort* s3 = (GLushort*) src3;
GLushort* s4 = (GLushort*) src4;
GLushort* d1 = (GLushort*) t;
assert(format == ARGB1555);
a = A4444(*s1) + A4444(*s2) + A4444(*s3) + A4444(*s4);
r = R4444(*s1) + R4444(*s2) + R4444(*s3) + R4444(*s4);
g = G4444(*s1) + G4444(*s2) + G4444(*s3) + G4444(*s4);
b = B4444(*s1) + B4444(*s2) + B4444(*s3) + B4444(*s4);
GLushort* s1 = (GLushort*) src1;
GLushort* s2 = (GLushort*) src2;
GLushort* s3 = (GLushort*) src3;
GLushort* s4 = (GLushort*) src4;
GLushort* d1 = (GLushort*) t;
a /= 4;
r /= 4;
g /= 4;
b /= 4;
a = A1555(*s1) + A1555(*s2) + A1555(*s3) + A1555(*s4);
r = R1555(*s1) + R1555(*s2) + R1555(*s3) + R1555(*s4);
g = G1555(*s1) + G1555(*s2) + G1555(*s3) + G1555(*s4);
b = B1555(*s1) + B1555(*s2) + B1555(*s3) + B1555(*s4);
*d1 = PACK_ARGB4444(a, r, g, b);
} else {
GLushort* s1 = (GLushort*) src1;
GLushort* s2 = (GLushort*) src2;
GLushort* s3 = (GLushort*) src3;
GLushort* s4 = (GLushort*) src4;
GLushort* d1 = (GLushort*) t;
a /= 4;
r /= 4;
g /= 4;
b /= 4;
a = A1555(*s1) + A1555(*s2) + A1555(*s3) + A1555(*s4);
r = R1555(*s1) + R1555(*s2) + R1555(*s3) + R1555(*s4);
g = G1555(*s1) + G1555(*s2) + G1555(*s3) + G1555(*s4);
b = B1555(*s1) + B1555(*s2) + B1555(*s3) + B1555(*s4);
a /= 4;
r /= 4;
g /= 4;
b /= 4;
*d1 = PACK_ARGB1555((GLubyte) a, (GLubyte) r, (GLubyte) g, (GLubyte) b);
}
*d1 = PACK_ARGB1555((GLubyte) a, (GLubyte) r, (GLubyte) g, (GLubyte) b);
}
return GL_TRUE;
@ -227,10 +239,10 @@ GLboolean _glGenerateMipmapTwiddled(const GLuint pvrFormat, const GLubyte* prevD
* are next to each other. By averaging them we just basically shrink
* the reverse Ns so each reverse N becomes the next level down... if that makes sense!? */
GLubyte* s1 = &prevData[i * stride];
GLubyte* s2 = s1 + stride;
GLubyte* s3 = s2 + stride;
GLubyte* s4 = s3 + stride;
const GLubyte* s1 = &prevData[i * stride];
const GLubyte* s2 = s1 + stride;
const GLubyte* s3 = s2 + stride;
const GLubyte* s4 = s3 + stride;
GLubyte* t = &thisData[j * stride];
assert(s4 < prevData + (lastHeight * lastWidth * stride));
@ -242,10 +254,6 @@ GLboolean _glGenerateMipmapTwiddled(const GLuint pvrFormat, const GLubyte* prevD
return GL_TRUE;
}
GLboolean _glGenerateMipmap(const GLuint pvrFormat, const GLubyte* prevData, GLuint thisWidth, GLuint thisHeight, GLubyte* thisData) {
return GL_TRUE;
}
void APIENTRY glGenerateMipmapEXT(GLenum target) {
if(target != GL_TEXTURE_2D) {
_glKosThrowError(GL_INVALID_OPERATION, __func__);
@ -268,7 +276,25 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
return;
}
if(_glIsMipmapComplete(tex)) {
if((tex->color & PVR_TXRFMT_NONTWIDDLED) == PVR_TXRFMT_NONTWIDDLED) {
/* glTexImage2D should twiddle internally textures in nearly all cases
* so this error is unlikely */
fprintf(stderr, "[GL ERROR] Mipmaps are only supported on twiddled textures\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
GLboolean complete = _glIsMipmapComplete(tex);
if(!complete && tex->isCompressed) {
fprintf(stderr, "[GL ERROR] Generating mipmaps for compressed textures is not yet supported\n");
_glKosThrowError(GL_INVALID_OPERATION, __func__);
_glKosPrintError();
return;
}
if(complete) {
/* Nothing to do */
return;
}
@ -287,11 +313,7 @@ void APIENTRY glGenerateMipmapEXT(GLenum target) {
GLuint thisWidth = (prevWidth > 1) ? prevWidth / 2 : 1;
GLuint thisHeight = (prevHeight > 1) ? prevHeight / 2 : 1;
if((tex->color & PVR_TXRFMT_TWIDDLED) == PVR_TXRFMT_TWIDDLED) {
_glGenerateMipmapTwiddled(tex->color, prevData, thisWidth, thisHeight, thisData);
} else {
_glGenerateMipmap(tex->color, prevData, thisWidth, thisHeight, thisData);
}
_glGenerateMipmapTwiddled(tex->color, prevData, thisWidth, thisHeight, thisData);
tex->mipmap |= (1 << i);

View File

@ -31,7 +31,7 @@ static TexturePalette* _initTexturePalette() {
TexturePalette* palette = (TexturePalette*) malloc(sizeof(TexturePalette));
assert(palette);
sq_clr(palette, (sizeof(TexturePalette) & 0xfffffffc) + 4);
memset(palette, 0x0, sizeof(TexturePalette));
palette->bank = -1;
return palette;
}
@ -165,39 +165,39 @@ static GLuint _glGetMipmapDataOffset(TextureObject* obj, GLuint level) {
}
if(obj->isPaletted){
switch(size >> level) {
switch(size >> level){
case 1024:
offset = 0x15556;
offset = 0x55558;
break;
case 512:
offset = 0x05556;
offset = 0x15558;
break;
case 256:
offset = 0x01556;
offset = 0x05558;
break;
case 128:
offset = 0x00556;
offset = 0x01558;
break;
case 64:
offset = 0x00156;
offset = 0x00558;
break;
case 32:
offset = 0x00056;
offset = 0x00158;
break;
case 16:
offset = 0x00016;
offset = 0x00058;
break;
case 8:
offset = 0x00006;
offset = 0x00018;
break;
case 4:
offset = 0x00002;
offset = 0x00008;
break;
case 2:
offset = 0x00001;
offset = 0x00004;
break;
case 1:
offset = 0x00000;
offset = 0x00003;
break;
}
} else {
@ -1026,6 +1026,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
if(format == GL_COLOR_INDEX) {
/* Don't convert color indexes */
needsConversion = GL_FALSE;
if(type == GL_UNSIGNED_BYTE_TWID_KOS) {
needsTwiddling = GL_FALSE;
}
} else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && internalFormat == GL_RGBA) {
needsConversion = GL_FALSE;
} else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_1_5_5_5_REV && internalFormat == GL_RGBA) {

View File

@ -123,6 +123,7 @@ 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.
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1->width, image1->height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE_TWID_KOS, image1->data);
glGenerateMipmapEXT(GL_TEXTURE_2D);
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -130,7 +131,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG
{
LoadGLTextures();
glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing