diff --git a/gl-api.h b/gl-api.h index a7d619e..d1974b6 100644 --- a/gl-api.h +++ b/gl-api.h @@ -28,7 +28,7 @@ typedef struct { typedef struct { GLushort width; GLushort height; - GLuint color; + GLuint color; /* This is the PVR texture format */ GLubyte env; GLubyte filter; GLubyte mip_map; diff --git a/gl-cap.c b/gl-cap.c index 33c4afb..d7bb017 100644 --- a/gl-cap.c +++ b/gl-cap.c @@ -228,7 +228,7 @@ void APIENTRY glGetFloatv(GLenum pname, GLfloat *params) { const GLbyte *glGetString(GLenum name) { switch(name) { case GL_VENDOR: - return "KallistiOS"; + return "KallistiOS / Kazade"; case GL_RENDERER: return "PowerVR2 CLX2 100mHz"; @@ -237,7 +237,7 @@ const GLbyte *glGetString(GLenum name) { return "KGL 1.x"; case GL_EXTENSIONS: - return "GL_ARB_framebuffer_object, GL_ARB_multitexture"; + return "GL_ARB_framebuffer_object, GL_ARB_multitexture, GL_ARB_texture_rg"; } return "GL_KOS_ERROR: ENUM Unsupported\n"; diff --git a/gl-texture.c b/gl-texture.c index d3b4b49..dcf2f56 100644 --- a/gl-texture.c +++ b/gl-texture.c @@ -197,12 +197,12 @@ void APIENTRY glCompressedTexImage2D(GLenum target, if(border) _glKosThrowError(GL_INVALID_VALUE, "glCompressedTexImage2D"); - if(internalformat != GL_UNSIGNED_SHORT_5_6_5_VQ) - if(internalformat != GL_UNSIGNED_SHORT_5_6_5_VQ_TWID) - if(internalformat != GL_UNSIGNED_SHORT_4_4_4_4_VQ) - if(internalformat != GL_UNSIGNED_SHORT_4_4_4_4_VQ_TWID) - if(internalformat != GL_UNSIGNED_SHORT_1_5_5_5_VQ) - if(internalformat != GL_UNSIGNED_SHORT_1_5_5_5_VQ_TWID) + if(internalformat != GL_UNSIGNED_SHORT_5_6_5_VQ_EXT) + if(internalformat != GL_UNSIGNED_SHORT_5_6_5_VQ_TWID_EXT) + if(internalformat != GL_UNSIGNED_SHORT_4_4_4_4_VQ_EXT) + if(internalformat != GL_UNSIGNED_SHORT_4_4_4_4_VQ_TWID_EXT) + if(internalformat != GL_UNSIGNED_SHORT_1_5_5_5_VQ_EXT) + if(internalformat != GL_UNSIGNED_SHORT_1_5_5_5_VQ_TWID_EXT) _glKosThrowError(GL_INVALID_OPERATION, "glCompressedTexImage2D"); if(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE] == NULL) @@ -228,6 +228,160 @@ void APIENTRY glCompressedTexImage2D(GLenum target, sq_cpy(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data, data, imageSize); } +static GLint _cleanInternalFormat(GLint internalFormat) { + switch (internalFormat) { + case GL_ALPHA: +/* case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16:*/ + return GL_ALPHA; + case 1: + case GL_LUMINANCE: +/* case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16:*/ + return GL_LUMINANCE; + case 2: + case GL_LUMINANCE_ALPHA: +/* case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: */ + return GL_LUMINANCE_ALPHA; +/* case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return GL_INTENSITY; */ + case 3: + return GL_RGB; + case GL_RGB: +/* case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: */ + return GL_RGB; + case 4: + return GL_RGBA; + case GL_RGBA: +/* case GL_RGBA2: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: */ + return GL_RGBA; + + /* Support ARB_texture_rg */ + case GL_RED: +/* case GL_R8: + case GL_R16: + case GL_RED: + case GL_COMPRESSED_RED: */ + return GL_RED; +/* case GL_RG: + case GL_RG8: + case GL_RG16: + case GL_COMPRESSED_RG: + return GL_RG;*/ + default: + return -1; + } +} + +static GLuint _determinePVRFormat(GLint internalFormat, GLenum type) { + /* Given a cleaned internalFormat, return the Dreamcast format + * that can hold it + */ + switch(internalFormat) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + /* OK so if we have something that requires alpha, we return 4444 unless + * the type was already 1555 (1-bit alpha) in which case we return that + */ + return (type == GL_UNSIGNED_SHORT_1_5_5_5_REV) ? + PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED : + PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED; + case GL_RED: + case GL_RGB: + /* No alpha? Return RGB565 which is the best we can do without using palettes */ + return PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED; + default: + return 0; + } +} + + +typedef void (*TextureConversionFunc)(GLbyte*, GLshort*); + +static void _rgba8888_to_argb4444(GLbyte* source, GLshort* dest) { + *dest = ( + (source[3] & 0x11110000) << 8 | + (source[0] & 0x11110000) << 4 | + (source[1] & 0x11110000) | + (source[2] & 0x11110000) >> 4 + ); +} + +static void _rgb888_to_rgb565(GLbyte* source, GLshort* dest) { + *dest = ((source[0] & 0b11111000) << 8) | ((source[1] & 0b11111100) << 3) | (source[2] >> 3); +} + +static void _r8_to_rgb565(GLbyte* source, GLshort* dest) { + *dest = (source[0] & 0b11111000) << 8; +} + +static TextureConversionFunc _determineConversion(GLint pvr_format, GLenum format, GLenum type) { + switch(pvr_format) { + case PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED: { + if(type == GL_UNSIGNED_BYTE && format == GL_RGB) { + return _rgb888_to_rgb565; + } else if(type == GL_UNSIGNED_BYTE && format == GL_RED) { + return _r8_to_rgb565; + } + } break; + case PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED: { + if(type == GL_UNSIGNED_BYTE && format == GL_RGBA) { + return _rgba8888_to_argb4444; + } + } break; + default: + break; + } + + return 0; +} + +static GLint _determineStride(GLenum format, GLenum type) { + switch(type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (format == GL_RED) ? 1 : (format == GL_RGB) ? 3 : 4; + case GL_UNSIGNED_SHORT: + return (format == GL_RED) ? 2 : (format == GL_RGB) ? 6 : 8; + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + return 2; + } + + return -1; +} + + void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *data) { @@ -238,9 +392,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(format != GL_RGBA) _glKosThrowError(GL_INVALID_ENUM, "glTexImage2D"); - if(internalFormat != GL_RGB) - if(internalFormat != GL_RGBA) - _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + internalFormat = _cleanInternalFormat(internalFormat); + if(internalFormat == -1) { + _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); + } GLint w = width; if(w == 0 || (w & -w) != w) { @@ -260,9 +415,6 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(border) _glKosThrowError(GL_INVALID_VALUE, "glTexImage2D"); - if(format != internalFormat) - _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D"); - if(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE] == NULL) _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D"); @@ -271,12 +423,15 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, return; } + /* Calculate the format that we need to convert the data to */ + GLuint pvr_format = _determinePVRFormat(internalFormat, type); + if(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data) { /* pre-existing texture - check if changed */ if(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->width != width || GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->height != height || GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->mip_map != level || - GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->color != type) { + GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->color != pvr_format) { /* changed - free old texture memory */ pvr_mem_free(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data); GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data = NULL; @@ -290,58 +445,59 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->width = width; GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->height = height; GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->mip_map = level; - GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->color = type; + GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->color = pvr_format; GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data = pvr_mem_malloc(bytes); } - if(data) { - switch(type) { - case GL_BYTE: /* Texture Formats that need conversion for PVR */ - case GL_UNSIGNED_BYTE: - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_FLOAT: { - uint16 *tex; + /* Let's assume we need to convert */ + GLboolean needsConversion = GL_TRUE; - tex = (uint16 *)malloc(width * height * sizeof(uint16)); + /* + * 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) { + needsConversion = GL_FALSE; + } else if(format == GL_BGRA && type == GL_UNSIGNED_SHORT_1_5_5_5_REV && internalFormat == GL_RGBA) { + needsConversion = GL_FALSE; + } else if(format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 && internalFormat == GL_RGB) { + needsConversion = GL_FALSE; + } - if(!tex) { - _glKosThrowError(GL_OUT_OF_MEMORY, "glTexImage2D"); - _glKosPrintError(); - return; - } + if(!data) { + /* No data? Do nothing! */ + return; + } else if(!needsConversion) { + /* No conversion? Just copy the data, and the pvr_format is correct */ + sq_cpy(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data, data, bytes); + return; + } else { + TextureConversionFunc convert = _determineConversion( + internalFormat, + format, + type + ); - switch(internalFormat) { - case GL_RGB: - _glKosPixelConvertRGB(type, width, height, (void *)data, tex); - GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->color = (PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED); - sq_cpy(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data, tex, bytes); - break; + if(!convert) { + _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D"); + return; + } - case GL_RGBA: - _glKosPixelConvertRGBA(type, width, height, (void *)data, tex); - GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->color = (PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED); - sq_cpy(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data, tex, bytes); - break; - } + GLshort* dest = GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data; + GLbyte* source = data; + GLint stride = _determineStride(format, type); - free(tex); - } - break; + if(stride == -1) { + _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D"); + return; + } - case GL_UNSIGNED_SHORT_5_6_5: /* Texture Formats that do not need conversion */ - case GL_UNSIGNED_SHORT_5_6_5_TWID: - case GL_UNSIGNED_SHORT_1_5_5_5: - case GL_UNSIGNED_SHORT_1_5_5_5_TWID: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_TWID: - sq_cpy(GL_KOS_TEXTURE_UNIT[GL_KOS_ACTIVE_TEXTURE]->data, data, bytes); - break; + for(GLuint i = 0; i < bytes; ++i) { + convert(source, dest); - default: /* Unsupported Texture Format */ - _glKosThrowError(GL_INVALID_OPERATION, "glTexImage2D"); - break; + dest++; + source += stride; } } } diff --git a/include/gl.h b/include/gl.h index e3e45f3..d475934 100644 --- a/include/gl.h +++ b/include/gl.h @@ -334,52 +334,43 @@ __BEGIN_DECLS /* GL KOS Texture Matrix Enable Bit */ #define GL_KOS_TEXTURE_MATRIX 0x002F -/* GL KOS Texture Color Modes */ -#define GL_UNSIGNED_SHORT_5_6_5 (PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_5_6_5_REV (PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_5_5_5_1 (PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_5_5_5_1_REV (PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_1_5_5_5 (PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_1_5_5_5_REV (PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_4_4_4_4 (PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_4_4_4_4_REV (PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED) +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#define GL_UNSIGNED_SHORT_5_6_5_TWID (PVR_TXRFMT_RGB565) -#define GL_UNSIGNED_SHORT_5_6_5_REV_TWID (PVR_TXRFMT_RGB565) -#define GL_UNSIGNED_SHORT_5_5_5_1_TWID (PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_5_5_5_1_REV_TWID (PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_1_5_5_5_TWID (PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID (PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_4_4_4_4_TWID (PVR_TXRFMT_ARGB4444) -#define GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID (PVR_TXRFMT_ARGB4444) +/* + * Dreamcast specific compressed + twiddled formats. + * We use constants from the range 0xEEE0 onwards + * to avoid trampling any real GL constants (this is in the middle of the + * any_vendor_future_use range defined in the GL enum.spec file. +*/ +#define GL_UNSIGNED_SHORT_5_6_5_TWID_EXT 0xEEE0 +#define GL_UNSIGNED_SHORT_5_5_5_1_TWID_EXT 0XEEE1 +#define GL_UNSIGNED_SHORT_1_5_5_5_TWID_EXT 0xEEE2 +#define GL_UNSIGNED_SHORT_4_4_4_4_TWID_EXT 0xEEE3 -#define GL_UNSIGNED_SHORT_5_6_5_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_5_6_5_REV_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_RGB565 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_5_5_5_1_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_5_5_5_1_REV_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_1_5_5_5_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_1_5_5_5_REV_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_4_4_4_4_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED) -#define GL_UNSIGNED_SHORT_4_4_4_4_REV_VQ (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED) +#define GL_UNSIGNED_SHORT_5_6_5_VQ_EXT 0xEEE4 +#define GL_UNSIGNED_SHORT_5_5_5_1_VQ_EXT 0xEEE5 +#define GL_UNSIGNED_SHORT_1_5_5_5_VQ_EXT 0xEEE6 +#define GL_UNSIGNED_SHORT_4_4_4_4_VQ_EXT 0xEEE7 -#define GL_UNSIGNED_SHORT_5_6_5_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_RGB565) -#define GL_UNSIGNED_SHORT_5_6_5_REV_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_RGB565) -#define GL_UNSIGNED_SHORT_5_5_5_1_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_5_5_5_1_REV_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_1_5_5_5_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_1_5_5_5_REV_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB1555) -#define GL_UNSIGNED_SHORT_4_4_4_4_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB4444) -#define GL_UNSIGNED_SHORT_4_4_4_4_REV_VQ_TWID (PVR_TXRFMT_VQ_ENABLE | PVR_TXRFMT_ARGB4444) - -#define GL_RGB565_TWID (PVR_TXRFMT_RGB565 | PVR_TXRFMT_TWIDDLED) -#define GL_ARGB1555_TWID (PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_TWIDDLED) -#define GL_ARGB4444_TWID (PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_TWIDDLED) +#define GL_UNSIGNED_SHORT_5_6_5_VQ_TWID_EXT 0xEEE8 +#define GL_UNSIGNED_SHORT_5_5_5_1_VQ_TWID_EXT 0xEEE9 +#define GL_UNSIGNED_SHORT_1_5_5_5_VQ_TWID_EXT 0xEEEA +#define GL_UNSIGNED_SHORT_4_4_4_4_VQ_TWID_EXT 0xEEEB +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A +#define GL_BGRA 0x80E1 #define GLbyte char #define GLshort short