Merge branch 'ext-paletted-texture' into 'master'
Initial implementation of GL_EXT_paletted_texture See merge request simulant/GLdc!26
This commit is contained in:
commit
3d5b257e1b
11
GL/private.h
11
GL/private.h
|
@ -41,6 +41,14 @@ typedef struct {
|
|||
AlignedVector vector;
|
||||
} PolyList;
|
||||
|
||||
typedef struct {
|
||||
/* Palette data is always stored in RAM as RGBA8888 and packed as ARGB8888
|
||||
* when uploaded to the PVR */
|
||||
GLubyte* data;
|
||||
GLushort width;
|
||||
GLenum format;
|
||||
} TexturePalette;
|
||||
|
||||
typedef struct {
|
||||
GLushort width;
|
||||
GLushort height;
|
||||
|
@ -57,6 +65,9 @@ typedef struct {
|
|||
GLenum magFilter;
|
||||
|
||||
GLboolean isCompressed;
|
||||
GLboolean isPaletted;
|
||||
|
||||
TexturePalette* palette;
|
||||
} TextureObject;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -601,7 +601,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";
|
||||
return "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg, GL_EXT_paletted_texture";
|
||||
}
|
||||
|
||||
return "GL_KOS_ERROR: ENUM Unsupported\n";
|
||||
|
|
292
GL/texture.c
292
GL/texture.c
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../include/glext.h"
|
||||
#include "../include/glkos.h"
|
||||
|
@ -17,6 +19,28 @@ static GLubyte ACTIVE_TEXTURE = 0;
|
|||
|
||||
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 void _glApplyColorTable() {
|
||||
TextureObject* active = getBoundTexture();
|
||||
|
||||
if(!active) {
|
||||
return; //? Unload the palette? Make White?
|
||||
}
|
||||
|
||||
if(!active->palette || !active->palette->data) {
|
||||
return;
|
||||
}
|
||||
|
||||
pvr_set_pal_format(PVR_PAL_ARGB8888);
|
||||
|
||||
GLushort i = 0;
|
||||
for(; i < active->palette->width; ++i) {
|
||||
GLubyte* entry = &active->palette->data[i * 4];
|
||||
pvr_set_pal_entry(i, PACK_ARGB8888(entry[3], entry[1], entry[2], entry[0]));
|
||||
}
|
||||
}
|
||||
|
||||
GLubyte _glGetActiveTexture() {
|
||||
return ACTIVE_TEXTURE;
|
||||
}
|
||||
|
@ -141,6 +165,9 @@ void APIENTRY glGenTextures(GLsizei n, GLuint *textures) {
|
|||
txr->mipmapCount = 0;
|
||||
txr->minFilter = GL_NEAREST;
|
||||
txr->magFilter = GL_NEAREST;
|
||||
txr->palette = NULL;
|
||||
txr->isCompressed = GL_FALSE;
|
||||
txr->isPaletted = GL_FALSE;
|
||||
|
||||
*textures = id;
|
||||
|
||||
|
@ -166,6 +193,16 @@ void APIENTRY glDeleteTextures(GLsizei n, GLuint *textures) {
|
|||
txr->data = NULL;
|
||||
}
|
||||
|
||||
if(txr->palette && txr->palette->data) {
|
||||
free(txr->palette->data);
|
||||
txr->palette->data = NULL;
|
||||
}
|
||||
|
||||
if(txr->palette) {
|
||||
free(txr->palette);
|
||||
txr->palette = NULL;
|
||||
}
|
||||
|
||||
named_array_release(&TEXTURE_OBJECTS, *textures++);
|
||||
}
|
||||
}
|
||||
|
@ -181,6 +218,9 @@ void APIENTRY glBindTexture(GLenum target, GLuint texture) {
|
|||
|
||||
if(texture) {
|
||||
TEXTURE_UNITS[ACTIVE_TEXTURE] = (TextureObject*) named_array_get(&TEXTURE_OBJECTS, texture);
|
||||
|
||||
// If this is a paletted texture, we need to reapply the color table
|
||||
_glApplyColorTable();
|
||||
} else {
|
||||
TEXTURE_UNITS[ACTIVE_TEXTURE] = NULL;
|
||||
}
|
||||
|
@ -245,13 +285,13 @@ void APIENTRY glCompressedTexImage2DARB(GLenum target,
|
|||
GLint w = width;
|
||||
if(w < 8 || (w & -w) != w) {
|
||||
/* Width is not a power of two. Must be!*/
|
||||
_glKosThrowError(GL_INVALID_VALUE, "glTexImage2D");
|
||||
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
||||
}
|
||||
|
||||
GLint h = height;
|
||||
if(h < 8 || (h & -h) != h) {
|
||||
/* Height is not a power of two. Must be!*/
|
||||
_glKosThrowError(GL_INVALID_VALUE, "glTexImage2D");
|
||||
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
||||
}
|
||||
|
||||
if(level || border) {
|
||||
|
@ -332,6 +372,8 @@ void APIENTRY glCompressedTexImage2DARB(GLenum target,
|
|||
|
||||
static GLint _cleanInternalFormat(GLint internalFormat) {
|
||||
switch (internalFormat) {
|
||||
case GL_COLOR_INDEX8_EXT:
|
||||
return GL_COLOR_INDEX8_EXT;
|
||||
case GL_ALPHA:
|
||||
/* case GL_ALPHA4:
|
||||
case GL_ALPHA8:
|
||||
|
@ -363,24 +405,24 @@ static GLint _cleanInternalFormat(GLint internalFormat) {
|
|||
case 3:
|
||||
return GL_RGB;
|
||||
case GL_RGB:
|
||||
/* case GL_R3_G3_B2:
|
||||
/* case GL_R3_G3_B2: */
|
||||
case GL_RGB4:
|
||||
case GL_RGB5:
|
||||
case GL_RGB8:
|
||||
case GL_RGB10:
|
||||
case GL_RGB12:
|
||||
case GL_RGB16: */
|
||||
case GL_RGB16:
|
||||
return GL_RGB;
|
||||
case 4:
|
||||
return GL_RGBA;
|
||||
case GL_RGBA:
|
||||
/* case GL_RGBA2:
|
||||
case GL_RGBA2:
|
||||
case GL_RGBA4:
|
||||
case GL_RGB5_A1:
|
||||
case GL_RGBA8:
|
||||
case GL_RGB10_A2:
|
||||
case GL_RGBA12:
|
||||
case GL_RGBA16: */
|
||||
case GL_RGBA16:
|
||||
return GL_RGBA;
|
||||
|
||||
/* Support ARB_texture_rg */
|
||||
|
@ -450,33 +492,69 @@ static GLuint _determinePVRFormat(GLint internalFormat, GLenum type) {
|
|||
case GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS:
|
||||
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;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef void (*TextureConversionFunc)(const GLubyte*, GLushort*);
|
||||
typedef void (*TextureConversionFunc)(const GLubyte*, GLubyte*);
|
||||
|
||||
static void _rgba8888_to_argb4444(const GLubyte* source, GLushort* dest) {
|
||||
*dest = (source[3] & 0xF0) << 8 | (source[0] & 0xF0) << 4 | (source[1] & 0xF0) | (source[2] & 0xF0) >> 4;
|
||||
static inline void _rgba8888_to_argb4444(const GLubyte* source, GLubyte* dest) {
|
||||
*((GLushort*) dest) = (source[3] & 0xF0) << 8 | (source[0] & 0xF0) << 4 | (source[1] & 0xF0) | (source[2] & 0xF0) >> 4;
|
||||
}
|
||||
|
||||
static void _rgb888_to_rgb565(const GLubyte* source, GLushort* dest) {
|
||||
*dest = ((source[0] & 0b11111000) << 8) | ((source[1] & 0b11111100) << 3) | (source[2] >> 3);
|
||||
static inline void _rgba8888_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
||||
/* Noop */
|
||||
GLubyte* dst = (GLubyte*) dest;
|
||||
dst[0] = source[0];
|
||||
dst[1] = source[1];
|
||||
dst[2] = source[2];
|
||||
dst[3] = source[3];
|
||||
}
|
||||
|
||||
static void _rgba8888_to_a000(const GLubyte* source, GLushort* dest) {
|
||||
*dest = ((source[3] & 0b11111000) << 8);
|
||||
static inline void _rgb888_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
||||
/* Noop */
|
||||
GLubyte* dst = (GLubyte*) dest;
|
||||
dst[0] = source[0];
|
||||
dst[1] = source[1];
|
||||
dst[2] = source[2];
|
||||
dst[3] = 255;
|
||||
}
|
||||
|
||||
static void _r8_to_rgb565(const GLubyte* source, GLushort* dest) {
|
||||
*dest = (source[0] & 0b11111000) << 8;
|
||||
static inline void _rgb888_to_rgb565(const GLubyte* source, GLubyte* dest) {
|
||||
*((GLushort*) dest) = ((source[0] & 0b11111000) << 8) | ((source[1] & 0b11111100) << 3) | (source[2] >> 3);
|
||||
}
|
||||
|
||||
static void _rgba4444_to_argb4444(const GLubyte* source, GLushort* dest) {
|
||||
static inline void _rgba8888_to_a000(const GLubyte* source, GLubyte* dest) {
|
||||
*((GLushort*) dest) = ((source[3] & 0b11111000) << 8);
|
||||
}
|
||||
|
||||
static inline void _r8_to_rgb565(const GLubyte* source, GLubyte* dest) {
|
||||
*((GLushort*) dest) = (source[0] & 0b11111000) << 8;
|
||||
}
|
||||
|
||||
static inline void _rgba4444_to_argb4444(const GLubyte* source, GLubyte* dest) {
|
||||
GLushort* src = (GLushort*) source;
|
||||
*dest = ((*src & 0x000F) << 12) | *src >> 4;
|
||||
*((GLushort*) dest) = ((*src & 0x000F) << 12) | *src >> 4;
|
||||
}
|
||||
|
||||
static inline void _rgba4444_to_rgba8888(const GLubyte* source, GLubyte* dest) {
|
||||
GLushort src = *((GLushort*) source);
|
||||
GLubyte* dst = (GLubyte*) dest;
|
||||
|
||||
dst[0] = ((src & 0xF000) >> 12) * 2;
|
||||
dst[1] = ((src & 0x0F00) >> 8) * 2;
|
||||
dst[2] = ((src & 0x00F0) >> 4) * 2;
|
||||
dst[3] = ((src & 0x000F)) * 2;
|
||||
}
|
||||
|
||||
static inline void _i8_to_i8(const GLubyte* source, GLubyte* dest) {
|
||||
/* For indexes */
|
||||
GLubyte* dst = (GLubyte*) dest;
|
||||
*dst = *source;
|
||||
}
|
||||
|
||||
static TextureConversionFunc _determineConversion(GLint internalFormat, GLenum format, GLenum type) {
|
||||
|
@ -512,6 +590,30 @@ static TextureConversionFunc _determineConversion(GLint internalFormat, GLenum f
|
|||
return _rgba4444_to_argb4444;
|
||||
}
|
||||
} break;
|
||||
case GL_RGBA8: {
|
||||
if(type == GL_UNSIGNED_BYTE && format == GL_RGBA) {
|
||||
return _rgba8888_to_rgba8888;
|
||||
} else if (type == GL_BYTE && format == GL_RGBA) {
|
||||
return _rgba8888_to_rgba8888;
|
||||
} else if(type == GL_UNSIGNED_BYTE && format == GL_RGB) {
|
||||
return _rgb888_to_rgba8888;
|
||||
} else if (type == GL_BYTE && format == GL_RGB) {
|
||||
return _rgb888_to_rgba8888;
|
||||
} else if(type == GL_UNSIGNED_SHORT_4_4_4_4 && format == GL_RGBA) {
|
||||
return _rgba4444_to_rgba8888;
|
||||
}
|
||||
} break;
|
||||
case GL_COLOR_INDEX8_EXT:
|
||||
if(format == GL_COLOR_INDEX) {
|
||||
switch(type) {
|
||||
case GL_BYTE:
|
||||
case GL_UNSIGNED_BYTE:
|
||||
return _i8_to_i8;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported conversion: %x -> %x, %x\n", internalFormat, format, type);
|
||||
break;
|
||||
|
@ -525,6 +627,7 @@ static GLboolean _isSupportedFormat(GLenum format) {
|
|||
case GL_RGB:
|
||||
case GL_RGBA:
|
||||
case GL_BGRA:
|
||||
case GL_COLOR_INDEX:
|
||||
return GL_TRUE;
|
||||
default:
|
||||
return GL_FALSE;
|
||||
|
@ -556,18 +659,24 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
_glKosThrowError(GL_INVALID_ENUM, "glTexImage2D");
|
||||
}
|
||||
|
||||
if(!_isSupportedFormat(format)) {
|
||||
_glKosThrowError(GL_INVALID_ENUM, "glTexImage2D");
|
||||
}
|
||||
if(format != GL_COLOR_INDEX) {
|
||||
if(!_isSupportedFormat(format)) {
|
||||
_glKosThrowError(GL_INVALID_ENUM, "glTexImage2D");
|
||||
}
|
||||
|
||||
/* Abuse determineStride to see if type is valid */
|
||||
if(_determineStride(GL_RGBA, type) == -1) {
|
||||
_glKosThrowError(GL_INVALID_ENUM, "glTexImage2D");
|
||||
}
|
||||
/* Abuse determineStride to see if type is valid */
|
||||
if(_determineStride(GL_RGBA, type) == -1) {
|
||||
_glKosThrowError(GL_INVALID_ENUM, "glTexImage2D");
|
||||
}
|
||||
|
||||
internalFormat = _cleanInternalFormat(internalFormat);
|
||||
if(internalFormat == -1) {
|
||||
_glKosThrowError(GL_INVALID_VALUE, "glTexImage2D");
|
||||
internalFormat = _cleanInternalFormat(internalFormat);
|
||||
if(internalFormat == -1) {
|
||||
_glKosThrowError(GL_INVALID_VALUE, "glTexImage2D");
|
||||
}
|
||||
} else {
|
||||
if(internalFormat != GL_COLOR_INDEX8_EXT) {
|
||||
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
GLint w = width;
|
||||
|
@ -594,6 +703,13 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
_glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D");
|
||||
}
|
||||
|
||||
GLboolean isPaletted = (internalFormat == GL_COLOR_INDEX8_EXT) ? GL_TRUE : GL_FALSE;
|
||||
|
||||
if(isPaletted && level > 0) {
|
||||
/* Paletted textures can't have mipmaps */
|
||||
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
||||
}
|
||||
|
||||
if(_glKosHasError()) {
|
||||
_glKosPrintError();
|
||||
return;
|
||||
|
@ -618,20 +734,34 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
}
|
||||
}
|
||||
|
||||
GLuint bytes = (width * height * sizeof(GLushort));
|
||||
/* All colour formats are represented as shorts internally. Paletted textures
|
||||
* are represented by byte indexes (which look up into a color table)
|
||||
*/
|
||||
GLint destStride = isPaletted ? 1 : 2;
|
||||
GLuint bytes = (width * height * destStride);
|
||||
|
||||
if(!active->data) {
|
||||
assert(active);
|
||||
assert(width);
|
||||
assert(height);
|
||||
assert(destStride);
|
||||
|
||||
/* need texture memory */
|
||||
active->width = width;
|
||||
active->height = height;
|
||||
active->color = pvr_format;
|
||||
/* Set the required mipmap count */
|
||||
active->mipmapCount = _glGetMipmapLevelCount(active);
|
||||
active->dataStride = sizeof(GLshort);
|
||||
active->dataStride = destStride;
|
||||
|
||||
GLuint size = _glGetMipmapDataSize(active);
|
||||
assert(size);
|
||||
|
||||
active->data = pvr_mem_malloc(size);
|
||||
assert(active->data);
|
||||
|
||||
active->isCompressed = GL_FALSE;
|
||||
active->isPaletted = isPaletted;
|
||||
}
|
||||
|
||||
/* Mark this level as set in the mipmap bitmask */
|
||||
|
@ -644,7 +774,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
* These are the only formats where the source format passed in matches the pvr format.
|
||||
* Note the REV formats + GL_BGRA will reverse to ARGB which is what the PVR supports
|
||||
*/
|
||||
if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && internalFormat == GL_RGBA) {
|
||||
if(format == GL_COLOR_INDEX) {
|
||||
/* Don't convert color indexes */
|
||||
needsConversion = 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) {
|
||||
needsConversion = GL_FALSE;
|
||||
|
@ -659,6 +792,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
}
|
||||
|
||||
GLubyte* targetData = _glGetMipmapLocation(active, level);
|
||||
assert(targetData);
|
||||
|
||||
if(!data) {
|
||||
/* No data? Do nothing! */
|
||||
|
@ -679,7 +813,7 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
return;
|
||||
}
|
||||
|
||||
GLushort* dest = (GLushort*) targetData;
|
||||
GLubyte* dest = (GLubyte*) targetData;
|
||||
const GLubyte* source = data;
|
||||
|
||||
GLint stride = _determineStride(format, type);
|
||||
|
@ -691,10 +825,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
|
|||
|
||||
/* Perform the conversion */
|
||||
GLuint i;
|
||||
for(i = 0; i < bytes; i += 2) {
|
||||
for(i = 0; i < bytes; i += destStride) {
|
||||
convert(source, dest);
|
||||
|
||||
dest++;
|
||||
dest += destStride;
|
||||
source += stride;
|
||||
}
|
||||
}
|
||||
|
@ -769,3 +903,95 @@ void APIENTRY glTexParameteri(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, 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};
|
||||
|
||||
if(_glCheckValidEnum(target, validTargets, __func__) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_glCheckValidEnum(internalFormat, validInternalFormats, __func__) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_glCheckValidEnum(format, validFormats, __func__) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(_glCheckValidEnum(type, validTypes, __func__) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only allow up to 256 colours in a palette */
|
||||
if(width > 256 || width == 0) {
|
||||
_glKosThrowError(GL_INVALID_VALUE, __func__);
|
||||
_glKosPrintError();
|
||||
return;
|
||||
}
|
||||
|
||||
GLuint sourceStride = _determineStride(format, type);
|
||||
|
||||
TextureConversionFunc convert = _determineConversion(
|
||||
GL_RGBA8, /* We always store palettes in this format */
|
||||
format,
|
||||
type
|
||||
);
|
||||
|
||||
if(!convert) {
|
||||
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
||||
_glKosPrintError();
|
||||
return;
|
||||
}
|
||||
|
||||
TextureObject* active = getBoundTexture();
|
||||
if(active->palette) {
|
||||
free(active->palette->data);
|
||||
active->palette->data = NULL;
|
||||
} else {
|
||||
active->palette = (TexturePalette*) malloc(sizeof(TexturePalette));
|
||||
}
|
||||
|
||||
active->palette->data = (GLubyte*) malloc(width * 4);
|
||||
active->palette->format = format;
|
||||
active->palette->width = width;
|
||||
|
||||
GLubyte* src = (GLubyte*) data;
|
||||
GLubyte* dst = (GLubyte*) active->palette->data;
|
||||
|
||||
/* Transform and copy the source palette to the texture */
|
||||
GLushort i = 0;
|
||||
for(; i < width; ++i) {
|
||||
convert(src, dst);
|
||||
|
||||
src += sourceStride;
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
/* Apply the palette immediately, we'll also do this when binding the texture */
|
||||
_glApplyColorTable();
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY glColorSubTableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data) {
|
||||
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
||||
_glKosPrintError();
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *data) {
|
||||
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
||||
_glKosPrintError();
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY glGetColorTableParameterivEXT(GLenum target, GLenum pname, GLint *params) {
|
||||
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
||||
_glKosPrintError();
|
||||
}
|
||||
|
||||
GLAPI void APIENTRY glGetColorTableParameterfvEXT(GLenum target, GLenum pname, GLfloat *params) {
|
||||
_glKosThrowError(GL_INVALID_OPERATION, __func__);
|
||||
_glKosPrintError();
|
||||
}
|
||||
|
||||
|
|
15
include/gl.h
15
include/gl.h
|
@ -339,6 +339,7 @@ __BEGIN_DECLS
|
|||
#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
|
||||
#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
|
||||
|
||||
#define GL_COLOR_INDEX 0x1900
|
||||
#define GL_RED 0x1903
|
||||
#define GL_GREEN 0x1904
|
||||
#define GL_BLUE 0x1905
|
||||
|
@ -349,6 +350,20 @@ __BEGIN_DECLS
|
|||
#define GL_LUMINANCE_ALPHA 0x190A
|
||||
#define GL_BGRA 0x80E1
|
||||
|
||||
#define GL_RGB4 0x804F
|
||||
#define GL_RGB5 0x8050
|
||||
#define GL_RGB8 0x8051
|
||||
#define GL_RGB10 0x8052
|
||||
#define GL_RGB12 0x8053
|
||||
#define GL_RGB16 0x8054
|
||||
#define GL_RGBA2 0x8055
|
||||
#define GL_RGBA4 0x8056
|
||||
#define GL_RGB5_A1 0x8057
|
||||
#define GL_RGBA8 0x8058
|
||||
#define GL_RGB10_A2 0x8059
|
||||
#define GL_RGBA12 0x805A
|
||||
#define GL_RGBA16 0x805B
|
||||
|
||||
#define GLbyte char
|
||||
#define GLshort short
|
||||
#define GLint int
|
||||
|
|
|
@ -134,6 +134,31 @@ GLAPI void APIENTRY glGenerateMipmapEXT(GLenum target);
|
|||
GLAPI GLenum APIENTRY glCheckFramebufferStatusEXT(GLenum target);
|
||||
GLAPI GLboolean APIENTRY glIsFramebufferEXT(GLuint framebuffer);
|
||||
|
||||
/* ext_paletted_texture */
|
||||
#define GL_COLOR_INDEX1_EXT 0x80E2
|
||||
#define GL_COLOR_INDEX2_EXT 0x80E3
|
||||
#define GL_COLOR_INDEX4_EXT 0x80E4
|
||||
#define GL_COLOR_INDEX8_EXT 0x80E5
|
||||
#define GL_COLOR_INDEX12_EXT 0x80E6
|
||||
#define GL_COLOR_INDEX16_EXT 0x80E7
|
||||
|
||||
#define GL_COLOR_TABLE_FORMAT_EXT 0x80D8
|
||||
#define GL_COLOR_TABLE_WIDTH_EXT 0x80D9
|
||||
#define GL_COLOR_TABLE_RED_SIZE_EXT 0x80DA
|
||||
#define GL_COLOR_TABLE_GREEN_SIZE_EXT 0x80DB
|
||||
#define GL_COLOR_TABLE_BLUE_SIZE_EXT 0x80DC
|
||||
#define GL_COLOR_TABLE_ALPHA_SIZE_EXT 0x80DD
|
||||
#define GL_COLOR_TABLE_LUMINANCE_SIZE_EXT 0x80DE
|
||||
#define GL_COLOR_TABLE_INTENSITY_SIZE_EXT 0x80DF
|
||||
|
||||
#define GL_TEXTURE_INDEX_SIZE_EXT 0x80ED
|
||||
|
||||
GLAPI void APIENTRY glColorTableEXT(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data);
|
||||
GLAPI void APIENTRY glColorSubTableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
|
||||
GLAPI void APIENTRY glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *data);
|
||||
GLAPI void APIENTRY glGetColorTableParameterivEXT(GLenum target, GLenum pname, GLint *params);
|
||||
GLAPI void APIENTRY glGetColorTableParameterfvEXT(GLenum target, GLenum pname, GLfloat *params);
|
||||
|
||||
/* Loads VQ compressed texture from SH4 RAM into PVR VRAM */
|
||||
/* internalformat must be one of the following constants:
|
||||
GL_UNSIGNED_SHORT_5_6_5_VQ
|
||||
|
|
|
@ -22,3 +22,4 @@ all:
|
|||
$(KOS_MAKE) -C quadmark all
|
||||
$(KOS_MAKE) -C trimark all
|
||||
$(KOS_MAKE) -C multitexture_arrays all
|
||||
$(KOS_MAKE) -C paletted all
|
||||
|
|
29
samples/paletted/Makefile
Normal file
29
samples/paletted/Makefile
Normal file
|
@ -0,0 +1,29 @@
|
|||
TARGET = paletted.elf
|
||||
OBJS = main.o
|
||||
|
||||
all: rm-elf $(TARGET)
|
||||
|
||||
include $(KOS_BASE)/Makefile.rules
|
||||
|
||||
clean:
|
||||
-rm -f $(TARGET) $(OBJS) romdisk.*
|
||||
|
||||
rm-elf:
|
||||
-rm -f $(TARGET) romdisk.*
|
||||
|
||||
$(TARGET): $(OBJS) romdisk.o
|
||||
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
|
||||
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
|
||||
|
||||
romdisk.img:
|
||||
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
|
||||
|
||||
romdisk.o: romdisk.img
|
||||
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
|
||||
|
||||
run: $(TARGET)
|
||||
$(KOS_LOADER) $(TARGET)
|
||||
|
||||
dist:
|
||||
rm -f $(OBJS) romdisk.o romdisk.img
|
||||
$(KOS_STRIP) $(TARGET)
|
236
samples/paletted/main.c
Normal file
236
samples/paletted/main.c
Normal file
|
@ -0,0 +1,236 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gl.h"
|
||||
#include "glext.h"
|
||||
#include "glu.h"
|
||||
#include "glkos.h"
|
||||
|
||||
extern uint8 romdisk[];
|
||||
KOS_INIT_ROMDISK(romdisk);
|
||||
|
||||
/* floats for x rotation, y rotation, z rotation */
|
||||
float xrot, yrot, zrot;
|
||||
/* storage for one texture */
|
||||
int texture[1];
|
||||
|
||||
typedef struct {
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
unsigned int palette_width;
|
||||
char* palette;
|
||||
char* data;
|
||||
} Image;
|
||||
|
||||
int LoadPalettedTex(const char* filename, Image* image) {
|
||||
struct {
|
||||
char id[4]; // 'DTEX'
|
||||
short width;
|
||||
short height;
|
||||
int type;
|
||||
int size;
|
||||
} header;
|
||||
|
||||
FILE* filein = NULL;
|
||||
filein = fopen(filename, "rb");
|
||||
if(!filein) {
|
||||
printf("Unable to open file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fread(&header, sizeof(header), 1, filein);
|
||||
|
||||
if((header.type & (7 << 27)) >> 27 != 6) {
|
||||
printf("Not PAL8BPP format\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
image->width = header.width;
|
||||
image->height = header.height;
|
||||
image->data = (char*) malloc(sizeof(char) * header.size);
|
||||
|
||||
fread(image->data, header.size, sizeof(char), filein);
|
||||
fclose(filein);
|
||||
|
||||
char palette_filename[100];
|
||||
|
||||
strcpy(palette_filename, filename);
|
||||
strcat(palette_filename, ".pal");
|
||||
|
||||
filein = fopen(palette_filename, "rb");
|
||||
if(!filename) {
|
||||
printf("Unable to open the palette file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct {
|
||||
char id[4];
|
||||
int numcolors;
|
||||
} palette_header;
|
||||
fread(&palette_header, sizeof(palette_header), 1, filein);
|
||||
|
||||
image->palette = (unsigned int*) malloc(sizeof(unsigned int) * palette_header.numcolors);
|
||||
image->palette_width = palette_header.numcolors;
|
||||
|
||||
fread(image->palette, sizeof(unsigned int), palette_header.numcolors, filein);
|
||||
|
||||
unsigned int i = 0;
|
||||
for(; i < palette_header.numcolors; ++i) {
|
||||
unsigned int* p = (unsigned int*) image->palette;
|
||||
|
||||
// Swap the colours around from ARGB to RGBA
|
||||
char r = (p[i] & 0x00FF0000) >> 16;
|
||||
char g = (p[i] & 0x0000FF00) >> 8;
|
||||
char b = (p[i] & 0x000000FF);
|
||||
char a = (p[i] & 0xFF000000) >> 24;
|
||||
|
||||
image->palette[i * 4] = r;
|
||||
image->palette[i * 4 + 1] = g;
|
||||
image->palette[i * 4 + 2] = b;
|
||||
image->palette[i * 4 + 3] = a;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load Bitmaps And Convert To Textures
|
||||
void LoadGLTextures() {
|
||||
// Load Texture
|
||||
Image *image1;
|
||||
|
||||
// allocate space for texture
|
||||
image1 = (Image *) malloc(sizeof(Image));
|
||||
if (image1 == NULL) {
|
||||
printf("Error allocating space for image");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!LoadPalettedTex("/rd/NeHe.tex", image1)) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Create Texture
|
||||
glGenTextures(1, &texture[0]);
|
||||
glBindTexture(GL_TEXTURE_2D, texture[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
|
||||
|
||||
glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, image1->palette_width, GL_RGBA, GL_UNSIGNED_BYTE, image1->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. */
|
||||
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
|
||||
{
|
||||
LoadGLTextures();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
|
||||
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
|
||||
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity(); // Reset The Projection Matrix
|
||||
|
||||
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
|
||||
void ReSizeGLScene(int Width, int Height)
|
||||
{
|
||||
if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small
|
||||
Height = 1;
|
||||
|
||||
glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
|
||||
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.
|
||||
|
||||
glBegin(GL_QUADS); // begin drawing a cube
|
||||
|
||||
// Front Face (note that the texture's corners have to match the quad's corners)
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad
|
||||
|
||||
// Back Face
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Left Of The Texture and Quad
|
||||
|
||||
// Top Face
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad
|
||||
|
||||
// Bottom Face
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Top Right Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Left Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
|
||||
|
||||
// Right face
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Right Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad
|
||||
|
||||
// Left Face
|
||||
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad
|
||||
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad
|
||||
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad
|
||||
|
||||
glEnd(); // done with the polygon.
|
||||
|
||||
xrot+=1.5f; // X Axis Rotation
|
||||
yrot+=1.5f; // Y Axis Rotation
|
||||
zrot+=1.5f; // Z Axis Rotation
|
||||
//
|
||||
// swap buffers to display, since we're double buffered.
|
||||
glKosSwapBuffers();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
glKosInit();
|
||||
|
||||
InitGL(640, 480);
|
||||
ReSizeGLScene(640, 480);
|
||||
|
||||
while(1) {
|
||||
DrawGLScene();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
BIN
samples/paletted/romdisk/NeHe.bmp
Normal file
BIN
samples/paletted/romdisk/NeHe.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
BIN
samples/paletted/romdisk/NeHe.tex
Normal file
BIN
samples/paletted/romdisk/NeHe.tex
Normal file
Binary file not shown.
BIN
samples/paletted/romdisk/NeHe.tex.pal
Normal file
BIN
samples/paletted/romdisk/NeHe.tex.pal
Normal file
Binary file not shown.
0
samples/paletted/romdisk/PLACEHOLDER
Normal file
0
samples/paletted/romdisk/PLACEHOLDER
Normal file
Loading…
Reference in New Issue
Block a user