Add support for multiple shared palettes

This commit is contained in:
Luke Benstead 2019-03-10 11:18:56 +00:00
parent 864dc45d10
commit 259a82e69f
6 changed files with 155 additions and 85 deletions

View File

@ -96,10 +96,6 @@ void APIENTRY glKosSwapBuffers() {
profiler_push(__func__);
/* We only want to apply the colour table *at most* once per frame
* so it's best we do it here */
_glApplyColorTable();
pvr_wait_ready();
pvr_scene_begin();

View File

@ -70,6 +70,9 @@ typedef struct {
GLboolean isPaletted;
TexturePalette* palette;
/* When using the shared palette, this is the bank (0-3) */
GLushort shared_bank;
} TextureObject;
typedef struct {
@ -142,9 +145,10 @@ TextureObject* _glGetTexture1();
TextureObject* _glGetBoundTexture();
GLubyte _glGetActiveTexture();
GLuint _glGetActiveClientTexture();
TexturePalette* _glGetSharedPalette(GLshort bank);
GLboolean _glIsSharedTexturePaletteEnabled();
void _glApplyColorTable();
void _glApplyColorTable(TexturePalette *palette);
GLboolean _glIsBlendingEnabled();
GLboolean _glIsMipmapComplete(const TextureObject* obj);

View File

@ -214,6 +214,15 @@ void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) {
context->txr.height = tx1->height;
context->txr.base = tx1->data;
context->txr.format = tx1->color;
if(tx1->isPaletted) {
if(_glIsSharedTexturePaletteEnabled()) {
context->txr.format |= PVR_TXRFMT_8BPP_PAL(_glGetSharedPalette(tx1->shared_bank)->bank);
} else {
context->txr.format |= PVR_TXRFMT_8BPP_PAL((tx1->palette) ? tx1->palette->bank : 0);
}
}
context->txr.env = tx1->env;
context->txr.uv_flip = PVR_UVFLIP_NONE;
context->txr.uv_clamp = tx1->uv_clamp;
@ -628,7 +637,7 @@ const GLbyte *glGetString(GLenum name) {
return "GLdc 1.x";
case GL_EXTENSIONS:
return "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_EXT_paletted_texture, GL_EXT_shared_texture_palette";
return "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_EXT_paletted_texture, GL_EXT_shared_texture_palette, GL_KOS_multiple_shared_palette";
}
return "GL_KOS_ERROR: ENUM Unsupported\n";

View File

@ -18,14 +18,12 @@ static TextureObject* TEXTURE_UNITS[MAX_TEXTURE_UNITS] = {NULL, NULL};
static NamedArray TEXTURE_OBJECTS;
static GLubyte ACTIVE_TEXTURE = 0;
static TexturePalette* SHARED_PALETTE = NULL;
static TexturePalette* SHARED_PALETTES[4] = {NULL, NULL, NULL, NULL};
static GLuint _determinePVRFormat(GLint internalFormat, GLenum type, GLshort bank);
static GLuint _determinePVRFormat(GLint internalFormat, GLenum type);
#define PACK_ARGB8888(a,r,g,b) ( ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) )
static TexturePalette* last_bound_palette = NULL;
static GLboolean BANKS_USED[4]; // Each time a 256 colour bank is used, this is set to true
static GLboolean SUBBANKS_USED[4][16]; // 4 counts of the used 16 colour banks within the 256 ones
@ -97,51 +95,28 @@ static void _glReleasePaletteSlot(GLshort slot, GLushort size) {
}
}
TexturePalette* _glGetSharedPalette(GLshort bank) {
assert(bank >= 0 && bank < 4);
return SHARED_PALETTES[bank];
}
void _glApplyColorTable() {
void _glApplyColorTable(TexturePalette* src) {
/*
* FIXME:
*
* - Different palette formats (GL_RGB -> PVR_PAL_RGB565)
*/
TexturePalette* src = NULL;
if(_glIsSharedTexturePaletteEnabled()) {
src = SHARED_PALETTE;
assert(src);
/* Don't apply a palette if we haven't uploaded one yet */
if(!src->data) {
return;
}
} else {
TextureObject* active = _glGetBoundTexture();
if(!active) {
return; //? Unload the palette? Make White?
}
if(!active->palette || !active->palette->data) {
return;
}
src = active->palette;
}
/* Don't reapply the palette if it was the last one we applied */
if(src == last_bound_palette) {
if(!src || !src->data) {
return;
}
last_bound_palette = src;
pvr_set_pal_format(PVR_PAL_ARGB8888);
GLushort i = 0;
for(; i < src->width; ++i) {
GLushort i;
GLushort offset = src->size * src->bank;
for(i = 0; i < src->width; ++i) {
GLubyte* entry = &src->data[i * 4];
pvr_set_pal_entry(i, PACK_ARGB8888(entry[3], entry[0], entry[1], entry[2]));
pvr_set_pal_entry(offset + i, PACK_ARGB8888(entry[3], entry[0], entry[1], entry[2]));
}
}
@ -225,7 +200,11 @@ GLubyte _glInitTextures() {
// Reserve zero so that it is never given to anyone as an ID!
named_array_reserve(&TEXTURE_OBJECTS, 0);
SHARED_PALETTE = _initTexturePalette();
SHARED_PALETTES[0] = _initTexturePalette();
SHARED_PALETTES[1] = _initTexturePalette();
SHARED_PALETTES[2] = _initTexturePalette();
SHARED_PALETTES[3] = _initTexturePalette();
return 1;
}
@ -272,6 +251,9 @@ static void _glInitializeTextureObject(TextureObject* txr, unsigned int id) {
txr->palette = NULL;
txr->isCompressed = GL_FALSE;
txr->isPaletted = GL_FALSE;
/* Always default to the first shared bank */
txr->shared_bank = 0;
}
void APIENTRY glGenTextures(GLsizei n, GLuint *textures) {
@ -474,8 +456,7 @@ void APIENTRY glCompressedTexImage2DARB(GLenum target,
active->height = height;
active->color = _determinePVRFormat(
internalFormat,
internalFormat , /* Doesn't matter (see determinePVRFormat) */
0
internalFormat /* Doesn't matter (see determinePVRFormat) */
);
active->mipmapCount = _glGetMipmapLevelCount(active);
active->mipmap = (mipmapped) ? ~0 : (1 << level); /* Set only a single bit if this wasn't mipmapped otherwise set all */
@ -563,7 +544,7 @@ static GLint _cleanInternalFormat(GLint internalFormat) {
}
}
static GLuint _determinePVRFormat(GLint internalFormat, GLenum type, GLshort bank) {
static GLuint _determinePVRFormat(GLint internalFormat, GLenum type) {
/* Given a cleaned internalFormat, return the Dreamcast format
* that can hold it
*/
@ -614,7 +595,7 @@ static GLuint _determinePVRFormat(GLint internalFormat, GLenum type, GLshort ban
case GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS:
return PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_TWIDDLED | PVR_TXRFMT_VQ_ENABLE;
case GL_COLOR_INDEX8_EXT:
return PVR_TXRFMT_PAL8BPP | PVR_TXRFMT_TWIDDLED | PVR_TXRFMT_8BPP_PAL(bank);
return PVR_TXRFMT_PAL8BPP | PVR_TXRFMT_TWIDDLED;
default:
return 0;
}
@ -857,7 +838,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
}
/* Calculate the format that we need to convert the data to */
GLuint pvr_format = _determinePVRFormat(internalFormat, type, 0);
GLuint pvr_format = _determinePVRFormat(internalFormat, type);
TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE];
@ -1067,6 +1048,11 @@ void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) {
break;
}
break;
case GL_SHARED_TEXTURE_BANK_KOS:
active->shared_bank = param;
break;
default:
break;
}
}
@ -1077,7 +1063,16 @@ void APIENTRY glTexParameterf(GLenum target, GLenum pname, GLint param) {
}
GLAPI void APIENTRY glColorTableEXT(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data) {
GLenum validTargets[] = {GL_TEXTURE_2D, GL_SHARED_TEXTURE_PALETTE_EXT, 0};
GLenum validTargets[] = {
GL_TEXTURE_2D,
GL_SHARED_TEXTURE_PALETTE_EXT,
GL_SHARED_TEXTURE_PALETTE_0_KOS,
GL_SHARED_TEXTURE_PALETTE_1_KOS,
GL_SHARED_TEXTURE_PALETTE_2_KOS,
GL_SHARED_TEXTURE_PALETTE_3_KOS,
0
};
GLenum validInternalFormats[] = {GL_RGB8, GL_RGBA8, 0};
GLenum validFormats[] = {GL_RGB, GL_RGBA, 0};
GLenum validTypes[] = {GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, 0};
@ -1123,8 +1118,15 @@ GLAPI void APIENTRY glColorTableEXT(GLenum target, GLenum internalFormat, GLsize
TexturePalette* palette = NULL;
if(target == GL_SHARED_TEXTURE_PALETTE_EXT) {
palette = SHARED_PALETTE;
/* Custom extension - allow uploading to one of 4 custom palettes */
if(target == GL_SHARED_TEXTURE_PALETTE_EXT || target == GL_SHARED_TEXTURE_PALETTE_0_KOS) {
palette = SHARED_PALETTES[0];
} else if(target == GL_SHARED_TEXTURE_PALETTE_1_KOS) {
palette = SHARED_PALETTES[1];
} else if(target == GL_SHARED_TEXTURE_PALETTE_2_KOS) {
palette = SHARED_PALETTES[2];
} else if(target == GL_SHARED_TEXTURE_PALETTE_3_KOS) {
palette = SHARED_PALETTES[3];
} else {
TextureObject* active = _glGetBoundTexture();
if(!active->palette) {
@ -1179,9 +1181,7 @@ GLAPI void APIENTRY glColorTableEXT(GLenum target, GLenum internalFormat, GLsize
dst += 4;
}
/* Colour table might have changed the active palette, so wipe last_bound_palette before reapplying */
last_bound_palette = NULL;
_glApplyColorTable(palette);
}
GLAPI void APIENTRY glColorSubTableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) {

View File

@ -38,6 +38,32 @@ __BEGIN_DECLS
GLAPI void APIENTRY glKosSwapBuffers();
/*
* CUSTOM EXTENSION multiple_shared_palette_KOS
*
* This extension allows using up to 4 different shared palettes
* with ColorTableEXT. The following constants are provided
* to use as targets for ColorTableExt:
*
* - SHARED_TEXTURE_PALETTE_0_KOS
* - SHARED_TEXTURE_PALETTE_1_KOS
* - SHARED_TEXTURE_PALETTE_2_KOS
* - SHARED_TEXTURE_PALETTE_3_KOS
*
* In this use case SHARED_TEXTURE_PALETTE_0_KOS is interchangable with SHARED_TEXTURE_PALETTE_EXT
* (both refer to the first shared palette).
*
* To select which palette a texture uses, a new pname is accepted by TexParameteri: SHARED_TEXTURE_BANK_KOS
* by default textures use shared palette 0.
*/
#define GL_SHARED_TEXTURE_PALETTE_0_KOS 0xEEFC
#define GL_SHARED_TEXTURE_PALETTE_1_KOS 0xEEFD
#define GL_SHARED_TEXTURE_PALETTE_2_KOS 0xEEFE
#define GL_SHARED_TEXTURE_PALETTE_3_KOS 0xEEFF
/* Pass to glTexParameteri to set the shared bank */
#define GL_SHARED_TEXTURE_BANK_KOS 0xEF00
__END_DECLS

View File

@ -14,8 +14,8 @@ KOS_INIT_ROMDISK(romdisk);
/* floats for x rotation, y rotation, z rotation */
float xrot, yrot, zrot;
/* storage for one texture */
int texture[1];
int textures[2];
typedef struct {
unsigned int height;
@ -131,32 +131,50 @@ int LoadPalettedPCX(const char* filename, Image* image) {
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {
// Load Texture
Image *image1;
Image image1;
// allocate space for texture
image1 = (Image *) malloc(sizeof(Image));
if (image1 == NULL) {
printf("Error allocating space for image");
exit(0);
}
if (!LoadPalettedPCX("/rd/NeHe.pcx", image1)) {
if (!LoadPalettedPCX("/rd/NeHe.pcx", &image1)) {
exit(1);
}
glEnable(GL_SHARED_TEXTURE_PALETTE_EXT);
glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA8, image1->palette_width, GL_RGB, GL_UNSIGNED_BYTE, image1->palette);
/* First palette */
glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA8, image1.palette_width, GL_RGB, GL_UNSIGNED_BYTE, image1.palette);
char* inversed_palette = (char*) malloc(sizeof(char) * image1.palette_width * 3);
GLuint i;
for(i = 0; i < image1.palette_width; i++) {
/* Swap red and green */
inversed_palette[i * 3] = image1.palette[(i * 3) + 1];
inversed_palette[(i * 3) + 1] = image1.palette[(i * 3)];
inversed_palette[(i * 3) + 2] = image1.palette[(i * 3) + 2];
}
glColorTableEXT(GL_SHARED_TEXTURE_PALETTE_1_KOS, GL_RGBA8, image1.palette_width, GL_RGB, GL_UNSIGNED_BYTE, inversed_palette);
// Create Texture
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]); // 2d texture (x and y size)
glGenTextures(2, textures);
glBindTexture(GL_TEXTURE_2D, textures[0]); // 2d texture (x and y size)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); // scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); // scale linearly when image smalled than texture
// 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, image1->data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, image1.width, image1.height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, image1.data);
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
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); // scale linearly when image smalled than texture
/* Texture-specific palette! */
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, image1.palette_width, GL_RGB, GL_UNSIGNED_BYTE, inversed_palette);
// 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, image1.data);
}
/* A general OpenGL initialization function. Sets all of the initial parameters. */
@ -193,21 +211,7 @@ void ReSizeGLScene(int Width, int Height)
glMatrixMode(GL_MODELVIEW);
}
/* The main drawing function. */
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(0.0f,0.0f,-5.0f); // move 5 units into the screen.
glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis
glRotatef(yrot,0.0f,1.0f,0.0f); // Rotate On The Y Axis
glRotatef(zrot,0.0f,0.0f,1.0f); // Rotate On The Z Axis
glBindTexture(GL_TEXTURE_2D, texture[0]); // choose the texture to use.
void DrawPolygon() {
glBegin(GL_QUADS); // begin drawing a cube
// Front Face (note that the texture's corners have to match the quad's corners)
@ -247,6 +251,37 @@ void DrawGLScene()
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
glEnd(); // done with the polygon.
}
/* The main drawing function. */
void DrawGLScene()
{
static GLuint switch_counter = 0;
static GLuint current_bank = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(-1.5f,0.0f,-5.0f); // move 5 units into the screen.
glPushMatrix();
glRotatef(xrot,1.0f,0.0f,0.0f); // Rotate On The X Axis
glRotatef(yrot,0.0f,1.0f,0.0f); // Rotate On The Y Axis
glRotatef(zrot,0.0f,0.0f,1.0f); // Rotate On The Z Axis
glBindTexture(GL_TEXTURE_2D, textures[0]); // choose the texture to use.
if(switch_counter++ > 200) {
switch_counter = 0;
current_bank = !current_bank;
glTexParameteri(GL_TEXTURE_2D, GL_SHARED_TEXTURE_BANK_KOS, current_bank);
}
DrawPolygon();
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, textures[1]);
glTranslatef(3.0, 0, 0);
DrawPolygon();
xrot+=1.5f; // X Axis Rotation
yrot+=1.5f; // Y Axis Rotation