diff --git a/GL/flush.c b/GL/flush.c index b390697..0d4dd64 100644 --- a/GL/flush.c +++ b/GL/flush.c @@ -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(); diff --git a/GL/private.h b/GL/private.h index 81cb8eb..ebae279 100644 --- a/GL/private.h +++ b/GL/private.h @@ -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); diff --git a/GL/state.c b/GL/state.c index 6dbdca7..d85ffc5 100644 --- a/GL/state.c +++ b/GL/state.c @@ -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"; diff --git a/GL/texture.c b/GL/texture.c index 3c65247..9cb8158 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -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) { diff --git a/include/glkos.h b/include/glkos.h index c0da05c..b809f73 100644 --- a/include/glkos.h +++ b/include/glkos.h @@ -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 diff --git a/samples/paletted_pcx/main.c b/samples/paletted_pcx/main.c index b58f3e9..d98c5da 100644 --- a/samples/paletted_pcx/main.c +++ b/samples/paletted_pcx/main.c @@ -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