2018-08-14 08:49:31 +00:00
|
|
|
#include <stddef.h>
|
2018-05-11 14:39:28 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <dc/pvr.h>
|
|
|
|
#include <dc/vec3f.h>
|
|
|
|
#include <dc/video.h>
|
|
|
|
|
2018-05-05 19:38:55 +00:00
|
|
|
#include "../include/gl.h"
|
2018-08-07 19:46:26 +00:00
|
|
|
#include "../include/glext.h"
|
2018-08-01 10:32:07 +00:00
|
|
|
#include "../include/glkos.h"
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
#include "private.h"
|
2018-05-05 19:38:55 +00:00
|
|
|
|
|
|
|
static pvr_poly_cxt_t GL_CONTEXT;
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
pvr_poly_cxt_t* _glGetPVRContext() {
|
2018-05-11 14:39:28 +00:00
|
|
|
return &GL_CONTEXT;
|
|
|
|
}
|
|
|
|
|
2018-05-05 19:38:55 +00:00
|
|
|
/* We can't just use the GL_CONTEXT for this state as the two
|
|
|
|
* GL states are combined, so we store them separately and then
|
|
|
|
* calculate the appropriate PVR state from them. */
|
|
|
|
static GLenum CULL_FACE = GL_BACK;
|
|
|
|
static GLenum FRONT_FACE = GL_CCW;
|
|
|
|
static GLboolean CULLING_ENABLED = GL_FALSE;
|
2018-08-22 08:24:49 +00:00
|
|
|
static GLboolean COLOR_MATERIAL_ENABLED = GL_FALSE;
|
2018-05-05 19:38:55 +00:00
|
|
|
|
2020-05-08 06:19:56 +00:00
|
|
|
static GLboolean LIGHTING_ENABLED = GL_FALSE;
|
|
|
|
|
2019-02-21 21:58:31 +00:00
|
|
|
/* Is the shared texture palette enabled? */
|
|
|
|
static GLboolean SHARED_PALETTE_ENABLED = GL_FALSE;
|
|
|
|
|
2019-03-10 17:53:58 +00:00
|
|
|
static GLboolean ALPHA_TEST_ENABLED = GL_FALSE;
|
|
|
|
|
2020-03-05 20:04:44 +00:00
|
|
|
static GLboolean POLYGON_OFFSET_ENABLED = GL_FALSE;
|
|
|
|
|
2019-11-18 17:39:09 +00:00
|
|
|
static GLboolean NORMALIZE_ENABLED = GL_FALSE;
|
2019-03-10 17:53:58 +00:00
|
|
|
|
2019-02-21 21:58:31 +00:00
|
|
|
GLboolean _glIsSharedTexturePaletteEnabled() {
|
|
|
|
return SHARED_PALETTE_ENABLED;
|
|
|
|
}
|
|
|
|
|
2018-05-05 19:38:55 +00:00
|
|
|
static int _calc_pvr_face_culling() {
|
|
|
|
if(!CULLING_ENABLED) {
|
|
|
|
return PVR_CULLING_NONE;
|
|
|
|
} else {
|
|
|
|
if(CULL_FACE == GL_BACK) {
|
|
|
|
return (FRONT_FACE == GL_CW) ? PVR_CULLING_CCW : PVR_CULLING_CW;
|
|
|
|
} else {
|
|
|
|
return (FRONT_FACE == GL_CCW) ? PVR_CULLING_CCW : PVR_CULLING_CW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLenum DEPTH_FUNC = GL_LESS;
|
|
|
|
static GLboolean DEPTH_TEST_ENABLED = GL_FALSE;
|
|
|
|
|
|
|
|
static int _calc_pvr_depth_test() {
|
|
|
|
if(!DEPTH_TEST_ENABLED) {
|
2018-05-11 14:39:28 +00:00
|
|
|
return PVR_DEPTHCMP_ALWAYS;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
switch(DEPTH_FUNC) {
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_NEVER:
|
2018-05-11 14:39:28 +00:00
|
|
|
return PVR_DEPTHCMP_NEVER;
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_LESS:
|
2020-04-06 19:50:26 +00:00
|
|
|
return PVR_DEPTHCMP_GREATER;
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_EQUAL:
|
2018-05-11 14:39:28 +00:00
|
|
|
return PVR_DEPTHCMP_EQUAL;
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_LEQUAL:
|
2020-04-06 19:50:26 +00:00
|
|
|
return PVR_DEPTHCMP_GEQUAL;
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_GREATER:
|
2020-04-06 19:50:26 +00:00
|
|
|
return PVR_DEPTHCMP_LESS;
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_NOTEQUAL:
|
2018-05-11 14:39:28 +00:00
|
|
|
return PVR_DEPTHCMP_NOTEQUAL;
|
2018-05-05 19:38:55 +00:00
|
|
|
case GL_GEQUAL:
|
2020-04-06 19:50:26 +00:00
|
|
|
return PVR_DEPTHCMP_LEQUAL;
|
2018-05-05 19:38:55 +00:00
|
|
|
break;
|
|
|
|
case GL_ALWAYS:
|
|
|
|
default:
|
2018-05-11 14:39:28 +00:00
|
|
|
return PVR_DEPTHCMP_ALWAYS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLenum BLEND_SFACTOR = GL_ONE;
|
|
|
|
static GLenum BLEND_DFACTOR = GL_ZERO;
|
|
|
|
static GLboolean BLEND_ENABLED = GL_FALSE;
|
|
|
|
|
2020-03-05 20:04:44 +00:00
|
|
|
static GLfloat OFFSET_FACTOR = 0.0f;
|
|
|
|
static GLfloat OFFSET_UNITS = 0.0f;
|
|
|
|
|
2019-11-18 17:39:09 +00:00
|
|
|
GLboolean _glIsNormalizeEnabled() {
|
|
|
|
return NORMALIZE_ENABLED;
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
GLboolean _glIsBlendingEnabled() {
|
2018-05-11 14:39:28 +00:00
|
|
|
return BLEND_ENABLED;
|
|
|
|
}
|
|
|
|
|
2019-03-10 17:53:58 +00:00
|
|
|
GLboolean _glIsAlphaTestEnabled() {
|
|
|
|
return ALPHA_TEST_ENABLED;
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
static int _calcPVRBlendFactor(GLenum factor) {
|
|
|
|
switch(factor) {
|
|
|
|
case GL_ZERO:
|
|
|
|
return PVR_BLEND_ZERO;
|
|
|
|
case GL_SRC_ALPHA:
|
|
|
|
return PVR_BLEND_SRCALPHA;
|
|
|
|
case GL_DST_COLOR:
|
|
|
|
return PVR_BLEND_DESTCOLOR;
|
|
|
|
case GL_DST_ALPHA:
|
|
|
|
return PVR_BLEND_DESTALPHA;
|
|
|
|
case GL_ONE_MINUS_DST_COLOR:
|
|
|
|
return PVR_BLEND_INVDESTCOLOR;
|
|
|
|
case GL_ONE_MINUS_SRC_ALPHA:
|
|
|
|
return PVR_BLEND_INVSRCALPHA;
|
|
|
|
case GL_ONE_MINUS_DST_ALPHA:
|
|
|
|
return PVR_BLEND_INVDESTALPHA;
|
|
|
|
case GL_ONE:
|
2018-05-12 20:01:51 +00:00
|
|
|
return PVR_BLEND_ONE;
|
2018-05-11 14:39:28 +00:00
|
|
|
default:
|
2019-03-13 15:14:09 +00:00
|
|
|
fprintf(stderr, "Invalid blend mode: %u\n", (unsigned int) factor);
|
2018-05-11 14:39:28 +00:00
|
|
|
return PVR_BLEND_ONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _updatePVRBlend(pvr_poly_cxt_t* context) {
|
|
|
|
if(BLEND_ENABLED) {
|
|
|
|
context->gen.alpha = PVR_ALPHA_ENABLE;
|
|
|
|
} else {
|
|
|
|
context->gen.alpha = PVR_ALPHA_DISABLE;
|
|
|
|
}
|
2019-09-06 08:35:57 +00:00
|
|
|
|
|
|
|
context->blend.src = _calcPVRBlendFactor(BLEND_SFACTOR);
|
|
|
|
context->blend.dst = _calcPVRBlendFactor(BLEND_DFACTOR);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 15:14:09 +00:00
|
|
|
GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) {
|
2018-08-22 08:24:49 +00:00
|
|
|
GLubyte found = 0;
|
|
|
|
while(*values != 0) {
|
|
|
|
if(*values == param) {
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
values++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!found) {
|
|
|
|
_glKosThrowError(GL_INVALID_ENUM, func);
|
|
|
|
_glKosPrintError();
|
|
|
|
return GL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:04:44 +00:00
|
|
|
GLboolean TEXTURES_ENABLED [] = {GL_FALSE, GL_FALSE};
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
void _glUpdatePVRTextureContext(pvr_poly_cxt_t* context, GLshort textureUnit) {
|
2019-03-03 19:06:01 +00:00
|
|
|
const TextureObject *tx1 = (textureUnit == 0) ? _glGetTexture0() : _glGetTexture1();
|
2018-08-14 08:49:31 +00:00
|
|
|
|
2019-09-06 08:35:57 +00:00
|
|
|
/* Disable all texturing to start with */
|
|
|
|
context->txr.enable = PVR_TEXTURE_DISABLE;
|
|
|
|
context->txr2.enable = PVR_TEXTURE_DISABLE;
|
|
|
|
context->txr2.alpha = PVR_TXRALPHA_DISABLE;
|
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
if(!TEXTURES_ENABLED[textureUnit] || !tx1) {
|
2018-05-11 14:39:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-30 10:07:04 +00:00
|
|
|
context->txr.alpha = (BLEND_ENABLED) ? PVR_TXRALPHA_ENABLE : PVR_TXRALPHA_DISABLE;
|
|
|
|
|
2018-08-09 08:32:29 +00:00
|
|
|
GLuint filter = PVR_FILTER_NEAREST;
|
|
|
|
GLboolean enableMipmaps = GL_FALSE;
|
|
|
|
|
|
|
|
switch(tx1->minFilter) {
|
|
|
|
case GL_NEAREST_MIPMAP_LINEAR:
|
|
|
|
case GL_NEAREST_MIPMAP_NEAREST:
|
|
|
|
case GL_LINEAR_MIPMAP_LINEAR:
|
|
|
|
case GL_LINEAR_MIPMAP_NEAREST:
|
|
|
|
enableMipmaps = GL_TRUE;
|
|
|
|
break;
|
2018-08-14 08:49:31 +00:00
|
|
|
default:
|
|
|
|
enableMipmaps = GL_FALSE;
|
|
|
|
break;
|
2018-08-09 08:32:29 +00:00
|
|
|
}
|
|
|
|
|
2018-08-20 07:34:54 +00:00
|
|
|
/* FIXME: If you disable mipmaps on a compressed mipmapped texture
|
|
|
|
* you get corruption and I don't know why, so we force mipmapping for now */
|
|
|
|
if(tx1->isCompressed && _glIsMipmapComplete(tx1)) {
|
|
|
|
enableMipmaps = GL_TRUE;
|
|
|
|
}
|
|
|
|
|
2020-03-05 20:04:44 +00:00
|
|
|
if(tx1->height != tx1->width){
|
|
|
|
enableMipmaps = GL_FALSE;
|
|
|
|
}
|
|
|
|
|
2018-08-09 08:32:29 +00:00
|
|
|
if(enableMipmaps) {
|
|
|
|
if(tx1->minFilter == GL_LINEAR_MIPMAP_NEAREST) {
|
|
|
|
filter = PVR_FILTER_TRILINEAR1;
|
|
|
|
} else if(tx1->minFilter == GL_LINEAR_MIPMAP_LINEAR) {
|
|
|
|
filter = PVR_FILTER_TRILINEAR2;
|
|
|
|
} else if(tx1->minFilter == GL_NEAREST_MIPMAP_LINEAR) {
|
|
|
|
filter = PVR_FILTER_BILINEAR;
|
|
|
|
} else {
|
|
|
|
filter = PVR_FILTER_NEAREST;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(tx1->minFilter == GL_LINEAR && tx1->magFilter == GL_LINEAR) {
|
|
|
|
filter = PVR_FILTER_BILINEAR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
/* If we don't have complete mipmaps, and yet mipmapping was enabled, we disable texturing.
|
|
|
|
* This is effectively what standard GL does (it renders a white texture)
|
|
|
|
*/
|
|
|
|
if(!_glIsMipmapComplete(tx1) && enableMipmaps) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tx1->data) {
|
2018-05-11 14:39:28 +00:00
|
|
|
context->txr.enable = PVR_TEXTURE_ENABLE;
|
2018-08-09 08:32:29 +00:00
|
|
|
context->txr.filter = filter;
|
2018-05-11 14:39:28 +00:00
|
|
|
context->txr.width = tx1->width;
|
|
|
|
context->txr.height = tx1->height;
|
2020-03-05 20:04:44 +00:00
|
|
|
context->txr.mipmap = enableMipmaps;
|
|
|
|
context->txr.mipmap_bias = tx1->mipmap_bias;
|
2019-09-24 14:47:23 +00:00
|
|
|
|
|
|
|
if(enableMipmaps) {
|
|
|
|
context->txr.base = tx1->data;
|
|
|
|
} else {
|
|
|
|
context->txr.base = tx1->data + tx1->baseDataOffset;
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
context->txr.format = tx1->color;
|
2019-03-10 11:18:56 +00:00
|
|
|
|
|
|
|
if(tx1->isPaletted) {
|
|
|
|
if(_glIsSharedTexturePaletteEnabled()) {
|
2019-03-10 20:18:11 +00:00
|
|
|
TexturePalette* palette = _glGetSharedPalette(tx1->shared_bank);
|
2019-04-01 08:57:33 +00:00
|
|
|
context->txr.format |= PVR_TXRFMT_8BPP_PAL(palette->bank);
|
2019-03-10 11:18:56 +00:00
|
|
|
} else {
|
|
|
|
context->txr.format |= PVR_TXRFMT_8BPP_PAL((tx1->palette) ? tx1->palette->bank : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
context->txr.env = tx1->env;
|
|
|
|
context->txr.uv_flip = PVR_UVFLIP_NONE;
|
|
|
|
context->txr.uv_clamp = tx1->uv_clamp;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-03 19:06:01 +00:00
|
|
|
GLboolean _glIsLightingEnabled() {
|
2018-05-12 13:05:54 +00:00
|
|
|
return LIGHTING_ENABLED;
|
|
|
|
}
|
|
|
|
|
2018-08-22 08:24:49 +00:00
|
|
|
GLboolean _glIsColorMaterialEnabled() {
|
|
|
|
return COLOR_MATERIAL_ENABLED;
|
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
static GLfloat CLEAR_COLOUR[3];
|
|
|
|
|
2018-09-15 10:45:38 +00:00
|
|
|
void _glInitContext() {
|
2018-05-11 14:39:28 +00:00
|
|
|
memset(&GL_CONTEXT, 0, sizeof(pvr_poly_cxt_t));
|
|
|
|
|
|
|
|
GL_CONTEXT.list_type = PVR_LIST_OP_POLY;
|
|
|
|
GL_CONTEXT.fmt.color = PVR_CLRFMT_ARGBPACKED;
|
|
|
|
GL_CONTEXT.fmt.uv = PVR_UVFMT_32BIT;
|
|
|
|
GL_CONTEXT.gen.color_clamp = PVR_CLRCLAMP_DISABLE;
|
|
|
|
|
2020-03-24 13:58:44 +00:00
|
|
|
glClearDepth(1.0f);
|
2018-05-05 19:38:55 +00:00
|
|
|
glDepthFunc(GL_LESS);
|
|
|
|
glDepthMask(GL_TRUE);
|
2018-05-11 14:39:28 +00:00
|
|
|
glFrontFace(GL_CCW);
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
glClearColor(0, 0, 0, 0);
|
2018-05-05 19:38:55 +00:00
|
|
|
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
2018-05-20 15:37:45 +00:00
|
|
|
glDisable(GL_FOG);
|
2018-05-12 13:05:54 +00:00
|
|
|
glDisable(GL_LIGHTING);
|
2018-05-20 15:37:45 +00:00
|
|
|
|
2018-05-14 16:10:53 +00:00
|
|
|
GLubyte i;
|
|
|
|
for(i = 0; i < MAX_LIGHTS; ++i) {
|
2018-05-12 13:05:54 +00:00
|
|
|
glDisable(GL_LIGHT0 + i);
|
|
|
|
}
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glEnable(GLenum cap) {
|
|
|
|
switch(cap) {
|
|
|
|
case GL_TEXTURE_2D:
|
2018-08-14 08:49:31 +00:00
|
|
|
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_TRUE;
|
2018-05-05 19:38:55 +00:00
|
|
|
break;
|
|
|
|
case GL_CULL_FACE: {
|
|
|
|
CULLING_ENABLED = GL_TRUE;
|
|
|
|
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
|
|
|
|
} break;
|
|
|
|
case GL_DEPTH_TEST: {
|
|
|
|
DEPTH_TEST_ENABLED = GL_TRUE;
|
|
|
|
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
|
|
|
|
} break;
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_BLEND: {
|
|
|
|
BLEND_ENABLED = GL_TRUE;
|
|
|
|
_updatePVRBlend(&GL_CONTEXT);
|
|
|
|
} break;
|
|
|
|
case GL_SCISSOR_TEST: {
|
|
|
|
GL_CONTEXT.gen.clip_mode = PVR_USERCLIP_INSIDE;
|
|
|
|
} break;
|
2018-05-12 13:05:54 +00:00
|
|
|
case GL_LIGHTING: {
|
|
|
|
LIGHTING_ENABLED = GL_TRUE;
|
|
|
|
} break;
|
2018-05-20 15:37:45 +00:00
|
|
|
case GL_FOG:
|
|
|
|
GL_CONTEXT.gen.fog_type = PVR_FOG_TABLE;
|
|
|
|
break;
|
2018-08-22 08:24:49 +00:00
|
|
|
case GL_COLOR_MATERIAL:
|
|
|
|
COLOR_MATERIAL_ENABLED = GL_TRUE;
|
|
|
|
break;
|
2019-03-03 18:54:25 +00:00
|
|
|
case GL_SHARED_TEXTURE_PALETTE_EXT: {
|
2019-02-21 21:58:31 +00:00
|
|
|
SHARED_PALETTE_ENABLED = GL_TRUE;
|
2019-03-03 18:54:25 +00:00
|
|
|
}
|
2019-02-21 21:58:31 +00:00
|
|
|
break;
|
2019-03-10 17:53:58 +00:00
|
|
|
case GL_ALPHA_TEST: {
|
|
|
|
ALPHA_TEST_ENABLED = GL_TRUE;
|
|
|
|
} break;
|
2018-05-12 13:05:54 +00:00
|
|
|
case GL_LIGHT0:
|
|
|
|
case GL_LIGHT1:
|
|
|
|
case GL_LIGHT2:
|
|
|
|
case GL_LIGHT3:
|
|
|
|
case GL_LIGHT4:
|
|
|
|
case GL_LIGHT5:
|
|
|
|
case GL_LIGHT6:
|
|
|
|
case GL_LIGHT7:
|
2020-05-08 06:19:56 +00:00
|
|
|
_glEnableLight(cap & 0xF, GL_TRUE);
|
2018-05-12 13:05:54 +00:00
|
|
|
break;
|
2018-08-01 10:32:07 +00:00
|
|
|
case GL_NEARZ_CLIPPING_KOS:
|
2019-03-03 19:06:01 +00:00
|
|
|
_glEnableClipping(GL_TRUE);
|
2018-08-01 10:32:07 +00:00
|
|
|
break;
|
2020-03-05 20:04:44 +00:00
|
|
|
case GL_POLYGON_OFFSET_POINT:
|
|
|
|
case GL_POLYGON_OFFSET_LINE:
|
|
|
|
case GL_POLYGON_OFFSET_FILL:
|
|
|
|
POLYGON_OFFSET_ENABLED = GL_TRUE;
|
|
|
|
break;
|
2019-11-18 17:39:09 +00:00
|
|
|
case GL_NORMALIZE:
|
|
|
|
NORMALIZE_ENABLED = GL_TRUE;
|
|
|
|
break;
|
2018-05-11 14:39:28 +00:00
|
|
|
default:
|
|
|
|
break;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glDisable(GLenum cap) {
|
|
|
|
switch(cap) {
|
|
|
|
case GL_TEXTURE_2D: {
|
2018-08-14 08:49:31 +00:00
|
|
|
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_FALSE;
|
2018-05-05 19:38:55 +00:00
|
|
|
} break;
|
|
|
|
case GL_CULL_FACE: {
|
|
|
|
CULLING_ENABLED = GL_FALSE;
|
|
|
|
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
|
|
|
|
} break;
|
|
|
|
case GL_DEPTH_TEST: {
|
|
|
|
DEPTH_TEST_ENABLED = GL_FALSE;
|
|
|
|
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
|
|
|
|
} break;
|
2018-05-11 14:39:28 +00:00
|
|
|
case GL_BLEND:
|
|
|
|
BLEND_ENABLED = GL_FALSE;
|
|
|
|
_updatePVRBlend(&GL_CONTEXT);
|
|
|
|
break;
|
|
|
|
case GL_SCISSOR_TEST: {
|
|
|
|
GL_CONTEXT.gen.clip_mode = PVR_USERCLIP_DISABLE;
|
|
|
|
} break;
|
2018-05-12 13:05:54 +00:00
|
|
|
case GL_LIGHTING: {
|
|
|
|
LIGHTING_ENABLED = GL_FALSE;
|
|
|
|
} break;
|
2018-05-20 15:37:45 +00:00
|
|
|
case GL_FOG:
|
|
|
|
GL_CONTEXT.gen.fog_type = PVR_FOG_DISABLE;
|
|
|
|
break;
|
2018-08-22 08:24:49 +00:00
|
|
|
case GL_COLOR_MATERIAL:
|
|
|
|
COLOR_MATERIAL_ENABLED = GL_FALSE;
|
|
|
|
break;
|
2019-03-03 18:54:25 +00:00
|
|
|
case GL_SHARED_TEXTURE_PALETTE_EXT: {
|
2019-02-21 21:58:31 +00:00
|
|
|
SHARED_PALETTE_ENABLED = GL_FALSE;
|
2019-03-03 18:54:25 +00:00
|
|
|
}
|
2019-02-21 21:58:31 +00:00
|
|
|
break;
|
2019-03-10 17:53:58 +00:00
|
|
|
case GL_ALPHA_TEST: {
|
|
|
|
ALPHA_TEST_ENABLED = GL_FALSE;
|
|
|
|
} break;
|
2018-05-12 13:05:54 +00:00
|
|
|
case GL_LIGHT0:
|
|
|
|
case GL_LIGHT1:
|
|
|
|
case GL_LIGHT2:
|
|
|
|
case GL_LIGHT3:
|
|
|
|
case GL_LIGHT4:
|
|
|
|
case GL_LIGHT5:
|
|
|
|
case GL_LIGHT6:
|
|
|
|
case GL_LIGHT7:
|
2020-05-08 06:19:56 +00:00
|
|
|
_glEnableLight(cap & 0xF, GL_FALSE);
|
2018-05-12 13:05:54 +00:00
|
|
|
break;
|
2018-08-01 10:32:07 +00:00
|
|
|
case GL_NEARZ_CLIPPING_KOS:
|
2019-03-03 19:06:01 +00:00
|
|
|
_glEnableClipping(GL_FALSE);
|
2018-08-01 10:32:07 +00:00
|
|
|
break;
|
2020-03-05 20:04:44 +00:00
|
|
|
case GL_POLYGON_OFFSET_POINT:
|
|
|
|
case GL_POLYGON_OFFSET_LINE:
|
|
|
|
case GL_POLYGON_OFFSET_FILL:
|
|
|
|
POLYGON_OFFSET_ENABLED = GL_FALSE;
|
|
|
|
break;
|
2019-11-18 17:39:09 +00:00
|
|
|
case GL_NORMALIZE:
|
|
|
|
NORMALIZE_ENABLED = GL_FALSE;
|
|
|
|
break;
|
2018-05-11 14:39:28 +00:00
|
|
|
default:
|
|
|
|
break;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear Caps */
|
|
|
|
GLAPI void APIENTRY glClear(GLuint mode) {
|
2018-05-11 14:39:28 +00:00
|
|
|
if(mode & GL_COLOR_BUFFER_BIT) {
|
|
|
|
pvr_set_bg_color(CLEAR_COLOUR[0], CLEAR_COLOUR[1], CLEAR_COLOUR[2]);
|
|
|
|
}
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
2018-05-11 14:39:28 +00:00
|
|
|
if(r > 1) r = 1;
|
|
|
|
if(g > 1) g = 1;
|
|
|
|
if(b > 1) b = 1;
|
|
|
|
if(a > 1) a = 1;
|
|
|
|
|
|
|
|
CLEAR_COLOUR[0] = r * a;
|
|
|
|
CLEAR_COLOUR[1] = g * a;
|
|
|
|
CLEAR_COLOUR[2] = b * a;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Depth Testing */
|
|
|
|
GLAPI void APIENTRY glClearDepthf(GLfloat depth) {
|
2020-03-24 13:58:44 +00:00
|
|
|
glClearDepth(depth);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glClearDepth(GLfloat depth) {
|
2020-03-24 13:58:44 +00:00
|
|
|
/* We reverse because using invW means that farther Z == lower number */
|
|
|
|
pvr_set_zclip(1.0f - depth);
|
2019-03-10 12:19:41 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 20:05:40 +00:00
|
|
|
GLAPI void APIENTRY glDrawBuffer(GLenum mode) {
|
2020-03-05 20:04:44 +00:00
|
|
|
_GL_UNUSED(mode);
|
2019-03-10 20:05:40 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-03-10 12:19:41 +00:00
|
|
|
GLAPI void APIENTRY glReadBuffer(GLenum mode) {
|
2020-03-05 20:04:44 +00:00
|
|
|
_GL_UNUSED(mode);
|
2018-05-05 19:38:55 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glDepthMask(GLboolean flag) {
|
|
|
|
GL_CONTEXT.depth.write = (flag == GL_TRUE) ? PVR_DEPTHWRITE_ENABLE : PVR_DEPTHWRITE_DISABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glDepthFunc(GLenum func) {
|
|
|
|
DEPTH_FUNC = func;
|
|
|
|
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Hints */
|
|
|
|
/* Currently Supported Capabilities:
|
2018-05-20 15:16:53 +00:00
|
|
|
GL_PERSPECTIVE_CORRECTION_HINT - This will Enable on the PVR */
|
2018-05-05 19:38:55 +00:00
|
|
|
GLAPI void APIENTRY glHint(GLenum target, GLenum mode) {
|
2018-05-20 15:16:53 +00:00
|
|
|
if(target == GL_PERSPECTIVE_CORRECTION_HINT && mode == GL_NICEST) {
|
|
|
|
// FIXME: enable supersampling
|
|
|
|
}
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Culling */
|
|
|
|
GLAPI void APIENTRY glFrontFace(GLenum mode) {
|
|
|
|
FRONT_FACE = mode;
|
2018-05-11 14:39:28 +00:00
|
|
|
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glCullFace(GLenum mode) {
|
|
|
|
CULL_FACE = mode;
|
2018-05-11 14:39:28 +00:00
|
|
|
GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-09-08 19:53:28 +00:00
|
|
|
GLenum _glGetShadeModel() {
|
|
|
|
return (GL_CONTEXT.gen.shading == PVR_SHADE_FLAT) ? GL_FLAT : GL_SMOOTH;
|
|
|
|
}
|
|
|
|
|
2018-05-05 19:38:55 +00:00
|
|
|
/* Shading - Flat or Goraud */
|
|
|
|
GLAPI void APIENTRY glShadeModel(GLenum mode) {
|
2018-05-11 14:39:28 +00:00
|
|
|
GL_CONTEXT.gen.shading = (mode == GL_SMOOTH) ? PVR_SHADE_GOURAUD : PVR_SHADE_FLAT;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Blending */
|
|
|
|
GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) {
|
2018-05-11 14:39:28 +00:00
|
|
|
BLEND_SFACTOR = sfactor;
|
|
|
|
BLEND_DFACTOR = dfactor;
|
|
|
|
_updatePVRBlend(&GL_CONTEXT);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-10 17:53:58 +00:00
|
|
|
#define PT_ALPHA_REF 0x011c
|
|
|
|
|
|
|
|
GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref) {
|
2019-03-13 15:14:09 +00:00
|
|
|
GLint validFuncs[] = {
|
2019-03-10 17:53:58 +00:00
|
|
|
GL_GREATER,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
if(_glCheckValidEnum(func, validFuncs, __func__) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLubyte val = (GLubyte)(ref * 255.0f);
|
|
|
|
PVR_SET(PT_ALPHA_REF, val);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void glLineWidth(GLfloat width) {
|
2020-03-05 20:04:44 +00:00
|
|
|
_GL_UNUSED(width);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void glPolygonOffset(GLfloat factor, GLfloat units) {
|
2020-03-05 20:04:44 +00:00
|
|
|
OFFSET_FACTOR = factor;
|
|
|
|
OFFSET_UNITS = units;
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void glGetTexParameteriv(GLenum target, GLenum pname, GLint *params) {
|
2020-03-05 20:04:44 +00:00
|
|
|
_GL_UNUSED(target);
|
|
|
|
_GL_UNUSED(pname);
|
|
|
|
_GL_UNUSED(params);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
|
2020-03-05 20:04:44 +00:00
|
|
|
_GL_UNUSED(red);
|
|
|
|
_GL_UNUSED(green);
|
|
|
|
_GL_UNUSED(blue);
|
|
|
|
_GL_UNUSED(alpha);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
void glPixelStorei(GLenum pname, GLint param) {
|
2020-03-05 20:04:44 +00:00
|
|
|
_GL_UNUSED(pname);
|
|
|
|
_GL_UNUSED(param);
|
2018-05-11 14:39:28 +00:00
|
|
|
}
|
2018-05-05 19:38:55 +00:00
|
|
|
|
2018-08-22 08:24:49 +00:00
|
|
|
|
2018-05-11 14:39:28 +00:00
|
|
|
/* Setup the hardware user clip rectangle.
|
|
|
|
|
|
|
|
The minimum clip rectangle is a 32x32 area which is dependent on the tile
|
|
|
|
size use by the tile accelerator. The PVR swithes off rendering to tiles
|
|
|
|
outside or inside the defined rectangle dependant upon the 'clipmode'
|
|
|
|
bits in the polygon header.
|
|
|
|
|
|
|
|
Clip rectangles therefore must have a size that is some multiple of 32.
|
|
|
|
|
|
|
|
glScissor(0, 0, 32, 32) allows only the 'tile' in the lower left
|
|
|
|
hand corner of the screen to be modified and glScissor(0, 0, 0, 0)
|
|
|
|
disallows modification to all 'tiles' on the screen.
|
|
|
|
*/
|
|
|
|
void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
|
|
|
|
/*!!! FIXME: Shouldn't this be added to *all* lists? */
|
2019-03-03 19:02:25 +00:00
|
|
|
PVRTileClipCommand *c = aligned_vector_extend(&_glActivePolyList()->vector, 1);
|
2018-05-11 14:39:28 +00:00
|
|
|
|
|
|
|
GLint miny, maxx, maxy;
|
2020-03-05 20:04:44 +00:00
|
|
|
GLsizei gl_scissor_width = MAX( MIN(width, vid_mode->width), 0 );
|
|
|
|
GLsizei gl_scissor_height = MAX( MIN(height, vid_mode->height), 0 );
|
2018-05-11 14:39:28 +00:00
|
|
|
|
|
|
|
/* force the origin to the lower left-hand corner of the screen */
|
|
|
|
miny = (vid_mode->height - gl_scissor_height) - y;
|
|
|
|
maxx = (gl_scissor_width + x);
|
|
|
|
maxy = (gl_scissor_height + miny);
|
|
|
|
|
|
|
|
/* load command structure while mapping screen coords to TA tiles */
|
|
|
|
c->flags = PVR_CMD_USERCLIP;
|
|
|
|
c->d1 = c->d2 = c->d3 = 0;
|
|
|
|
c->sx = CLAMP(x / 32, 0, vid_mode->width / 32);
|
|
|
|
c->sy = CLAMP(miny / 32, 0, vid_mode->height / 32);
|
|
|
|
c->ex = CLAMP((maxx / 32) - 1, 0, vid_mode->width / 32);
|
|
|
|
c->ey = CLAMP((maxy / 32) - 1, 0, vid_mode->height / 32);
|
2018-05-05 19:38:55 +00:00
|
|
|
}
|
2018-05-11 14:39:28 +00:00
|
|
|
|
2018-05-12 13:39:20 +00:00
|
|
|
GLboolean APIENTRY glIsEnabled(GLenum cap) {
|
|
|
|
switch(cap) {
|
|
|
|
case GL_DEPTH_TEST:
|
|
|
|
return DEPTH_TEST_ENABLED;
|
|
|
|
case GL_SCISSOR_TEST:
|
|
|
|
return GL_CONTEXT.gen.clip_mode == PVR_USERCLIP_INSIDE;
|
|
|
|
case GL_CULL_FACE:
|
|
|
|
return CULLING_ENABLED;
|
|
|
|
case GL_LIGHTING:
|
|
|
|
return LIGHTING_ENABLED;
|
|
|
|
case GL_BLEND:
|
|
|
|
return BLEND_ENABLED;
|
2020-03-05 20:04:44 +00:00
|
|
|
case GL_POLYGON_OFFSET_POINT:
|
|
|
|
case GL_POLYGON_OFFSET_LINE:
|
|
|
|
case GL_POLYGON_OFFSET_FILL:
|
|
|
|
return POLYGON_OFFSET_ENABLED;
|
2018-05-12 13:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
|
2018-08-07 19:46:26 +00:00
|
|
|
static GLenum COMPRESSED_FORMATS [] = {
|
|
|
|
GL_COMPRESSED_ARGB_1555_VQ_KOS,
|
|
|
|
GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS,
|
|
|
|
GL_COMPRESSED_ARGB_4444_VQ_KOS,
|
|
|
|
GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS,
|
|
|
|
GL_COMPRESSED_RGB_565_VQ_KOS,
|
|
|
|
GL_COMPRESSED_RGB_565_VQ_TWID_KOS
|
|
|
|
};
|
|
|
|
|
2020-03-05 20:04:44 +00:00
|
|
|
static GLuint NUM_COMPRESSED_FORMATS = sizeof(COMPRESSED_FORMATS) / sizeof(GLenum);
|
2018-08-07 19:46:26 +00:00
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
void APIENTRY glGetBooleanv(GLenum pname, GLboolean* params) {
|
2019-03-29 08:47:55 +00:00
|
|
|
GLuint enabledAttrs = *_glGetEnabledAttributes();
|
2018-08-21 15:08:06 +00:00
|
|
|
GLuint activeClientTexture = _glGetActiveClientTexture();
|
|
|
|
|
2018-08-14 08:49:31 +00:00
|
|
|
switch(pname) {
|
|
|
|
case GL_TEXTURE_2D:
|
|
|
|
*params = TEXTURES_ENABLED[_glGetActiveTexture()];
|
|
|
|
break;
|
2018-08-21 15:08:06 +00:00
|
|
|
case GL_VERTEX_ARRAY:
|
|
|
|
*params = (enabledAttrs & VERTEX_ENABLED_FLAG) == VERTEX_ENABLED_FLAG;
|
|
|
|
break;
|
|
|
|
case GL_COLOR_ARRAY:
|
|
|
|
*params = (enabledAttrs & DIFFUSE_ENABLED_FLAG) == DIFFUSE_ENABLED_FLAG;
|
|
|
|
break;
|
|
|
|
case GL_NORMAL_ARRAY:
|
|
|
|
*params = (enabledAttrs & NORMAL_ENABLED_FLAG) == NORMAL_ENABLED_FLAG;
|
|
|
|
break;
|
|
|
|
case GL_TEXTURE_COORD_ARRAY: {
|
|
|
|
if(activeClientTexture == 0) {
|
|
|
|
*params = (enabledAttrs & UV_ENABLED_FLAG) == UV_ENABLED_FLAG;
|
|
|
|
} else {
|
|
|
|
*params = (enabledAttrs & ST_ENABLED_FLAG) == ST_ENABLED_FLAG;
|
|
|
|
}
|
|
|
|
} break;
|
2018-08-14 08:49:31 +00:00
|
|
|
default:
|
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
|
|
|
_glKosPrintError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 08:46:13 +00:00
|
|
|
void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) {
|
|
|
|
switch(pname) {
|
|
|
|
case GL_PROJECTION_MATRIX:
|
2020-03-05 20:04:44 +00:00
|
|
|
memcpy4(params, _glGetProjectionMatrix(), sizeof(float) * 16);
|
2019-02-28 08:46:13 +00:00
|
|
|
break;
|
2019-03-10 12:30:39 +00:00
|
|
|
case GL_MODELVIEW_MATRIX:
|
2020-03-05 20:04:44 +00:00
|
|
|
memcpy4(params, _glGetModelViewMatrix(), sizeof(float) * 16);
|
|
|
|
break;
|
|
|
|
case GL_POLYGON_OFFSET_FACTOR:
|
|
|
|
*params = OFFSET_FACTOR;
|
|
|
|
break;
|
|
|
|
case GL_POLYGON_OFFSET_UNITS:
|
|
|
|
*params = OFFSET_UNITS;
|
2019-03-10 12:30:39 +00:00
|
|
|
break;
|
2019-02-28 08:46:13 +00:00
|
|
|
default:
|
2020-03-05 20:04:44 +00:00
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2019-02-28 08:46:13 +00:00
|
|
|
_glKosPrintError();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-12 13:39:20 +00:00
|
|
|
void APIENTRY glGetIntegerv(GLenum pname, GLint *params) {
|
|
|
|
switch(pname) {
|
|
|
|
case GL_MAX_LIGHTS:
|
|
|
|
*params = MAX_LIGHTS;
|
|
|
|
break;
|
|
|
|
case GL_TEXTURE_BINDING_2D:
|
2020-02-29 09:47:58 +00:00
|
|
|
*params = (_glGetBoundTexture()) ? _glGetBoundTexture()->index : 0;
|
2018-05-12 13:39:20 +00:00
|
|
|
break;
|
2018-08-04 20:00:26 +00:00
|
|
|
case GL_DEPTH_FUNC:
|
|
|
|
*params = DEPTH_FUNC;
|
|
|
|
break;
|
|
|
|
case GL_BLEND_SRC:
|
|
|
|
*params = BLEND_SFACTOR;
|
|
|
|
break;
|
|
|
|
case GL_BLEND_DST:
|
|
|
|
*params = BLEND_DFACTOR;
|
|
|
|
break;
|
2018-08-07 07:45:24 +00:00
|
|
|
case GL_MAX_TEXTURE_SIZE:
|
|
|
|
*params = MAX_TEXTURE_SIZE;
|
|
|
|
break;
|
2018-08-07 19:46:26 +00:00
|
|
|
case GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB:
|
|
|
|
*params = NUM_COMPRESSED_FORMATS;
|
|
|
|
break;
|
2018-08-19 20:10:42 +00:00
|
|
|
case GL_ACTIVE_TEXTURE:
|
|
|
|
*params = GL_TEXTURE0 + _glGetActiveTexture();
|
|
|
|
break;
|
2018-08-21 14:50:59 +00:00
|
|
|
case GL_CLIENT_ACTIVE_TEXTURE:
|
|
|
|
*params = GL_TEXTURE0 + _glGetActiveClientTexture();
|
|
|
|
break;
|
2018-08-07 19:46:26 +00:00
|
|
|
case GL_COMPRESSED_TEXTURE_FORMATS_ARB: {
|
|
|
|
GLuint i = 0;
|
|
|
|
for(; i < NUM_COMPRESSED_FORMATS; ++i) {
|
|
|
|
params[i] = COMPRESSED_FORMATS[i];
|
|
|
|
}
|
|
|
|
} break;
|
2018-05-12 13:39:20 +00:00
|
|
|
default:
|
2020-03-05 20:04:44 +00:00
|
|
|
_glKosThrowError(GL_INVALID_ENUM, __func__);
|
2018-05-12 13:39:20 +00:00
|
|
|
_glKosPrintError();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-05-19 12:43:22 +00:00
|
|
|
|
2019-03-13 15:14:09 +00:00
|
|
|
const GLubyte *glGetString(GLenum name) {
|
2018-05-19 12:43:22 +00:00
|
|
|
switch(name) {
|
|
|
|
case GL_VENDOR:
|
2019-03-13 15:14:09 +00:00
|
|
|
return (const GLubyte*) "KallistiOS / Kazade";
|
2018-05-19 12:43:22 +00:00
|
|
|
|
|
|
|
case GL_RENDERER:
|
2019-03-13 15:14:09 +00:00
|
|
|
return (const GLubyte*) "PowerVR2 CLX2 100mHz";
|
2018-05-19 12:43:22 +00:00
|
|
|
|
|
|
|
case GL_VERSION:
|
2019-03-30 07:15:50 +00:00
|
|
|
return (const GLubyte*) "1.2 (partial) - GLdc 1.1";
|
2018-05-19 12:43:22 +00:00
|
|
|
|
|
|
|
case GL_EXTENSIONS:
|
2019-11-18 17:39:09 +00:00
|
|
|
return (const GLubyte*) "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, GL_ARB_vertex_array_bgra, GL_ARB_vertex_type_2_10_10_10_rev";
|
2018-05-19 12:43:22 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 15:14:09 +00:00
|
|
|
return (const GLubyte*) "GL_KOS_ERROR: ENUM Unsupported\n";
|
2018-05-19 12:43:22 +00:00
|
|
|
}
|