Refactor state management

This commit is contained in:
Luke Benstead 2023-03-07 10:19:09 +00:00
parent c195d471e1
commit 8beb295c6b
5 changed files with 615 additions and 472 deletions

View File

@ -13,9 +13,12 @@ GLuint ENABLED_VERTEX_ATTRIBUTES = 0;
GLuint FAST_PATH_ENABLED = GL_FALSE; GLuint FAST_PATH_ENABLED = GL_FALSE;
static GLubyte ACTIVE_CLIENT_TEXTURE = 0; static GLubyte ACTIVE_CLIENT_TEXTURE = 0;
static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f;
extern inline GLuint _glRecalcFastPath(); extern inline GLuint _glRecalcFastPath();
extern GLboolean AUTOSORT_ENABLED;
#define ITERATE(count) \ #define ITERATE(count) \
GLuint i = count; \ GLuint i = count; \
while(i--) while(i--)
@ -116,8 +119,6 @@ static void _readVertexData3ui3f(const GLubyte* in, GLubyte* out) {
static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) { static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) {
const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f;
float* output = (float*) out; float* output = (float*) out;
output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE;
@ -138,8 +139,6 @@ static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) {
} }
static void _readVertexData2ub3f(const GLubyte* input, GLubyte* out) { static void _readVertexData2ub3f(const GLubyte* input, GLubyte* out) {
const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f;
float* output = (float*) out; float* output = (float*) out;
output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE;
@ -173,7 +172,6 @@ static void _readVertexData2ui2f(const GLubyte* in, GLubyte* out) {
} }
static void _readVertexData2ub2f(const GLubyte* input, GLubyte* out) { static void _readVertexData2ub2f(const GLubyte* input, GLubyte* out) {
const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f;
float* output = (float*) out; float* output = (float*) out;
output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE;
@ -1137,7 +1135,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL
* If we're not doing lighting though we can optimise by taking * If we're not doing lighting though we can optimise by taking
* vertices straight to clip-space */ * vertices straight to clip-space */
if(LIGHTING_ENABLED) { if(_glIsLightingEnabled()) {
_glMatrixLoadModelView(); _glMatrixLoadModelView();
} else { } else {
_glMatrixLoadModelViewProjection(); _glMatrixLoadModelViewProjection();
@ -1152,7 +1150,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL
transform(target); transform(target);
} }
if(LIGHTING_ENABLED){ if(_glIsLightingEnabled()){
light(target); light(target);
/* OK eye-space work done, now move into clip space */ /* OK eye-space work done, now move into clip space */

View File

@ -12,126 +12,107 @@
* multiplier ends up less than this value */ * multiplier ends up less than this value */
#define ATTENUATION_THRESHOLD 100.0f #define ATTENUATION_THRESHOLD 100.0f
static GLfloat SCENE_AMBIENT [] = {0.2f, 0.2f, 0.2f, 1.0f};
static GLboolean VIEWER_IN_EYE_COORDINATES = GL_TRUE;
static GLenum COLOR_CONTROL = GL_SINGLE_COLOR;
static GLenum COLOR_MATERIAL_MODE = GL_AMBIENT_AND_DIFFUSE; void _glPrecalcLightingValues(GLuint mask) {
#define AMBIENT_MASK 1
#define DIFFUSE_MASK 2
#define EMISSION_MASK 4
#define SPECULAR_MASK 8
#define SCENE_AMBIENT_MASK 16
static GLenum COLOR_MATERIAL_MASK = AMBIENT_MASK | DIFFUSE_MASK;
static LightSource LIGHTS[MAX_GLDC_LIGHTS];
static GLuint ENABLED_LIGHT_COUNT = 0;
static Material MATERIAL;
GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask);
static void recalcEnabledLights() {
GLubyte i;
ENABLED_LIGHT_COUNT = 0;
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
if(LIGHTS[i].isEnabled) {
ENABLED_LIGHT_COUNT++;
}
}
}
void _glInitLights() {
static GLfloat ONE [] = {1.0f, 1.0f, 1.0f, 1.0f};
static GLfloat ZERO [] = {0.0f, 0.0f, 0.0f, 1.0f};
static GLfloat PARTIAL [] = {0.2f, 0.2f, 0.2f, 1.0f};
static GLfloat MOSTLY [] = {0.8f, 0.8f, 0.8f, 1.0f};
memcpy(MATERIAL.ambient, PARTIAL, sizeof(GLfloat) * 4);
memcpy(MATERIAL.diffuse, MOSTLY, sizeof(GLfloat) * 4);
memcpy(MATERIAL.specular, ZERO, sizeof(GLfloat) * 4);
memcpy(MATERIAL.emissive, ZERO, sizeof(GLfloat) * 4);
MATERIAL.exponent = 0.0f;
GLubyte i;
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
memcpy(LIGHTS[i].ambient, ZERO, sizeof(GLfloat) * 4);
memcpy(LIGHTS[i].diffuse, ONE, sizeof(GLfloat) * 4);
memcpy(LIGHTS[i].specular, ONE, sizeof(GLfloat) * 4);
if(i > 0) {
memcpy(LIGHTS[i].diffuse, ZERO, sizeof(GLfloat) * 4);
memcpy(LIGHTS[i].specular, ZERO, sizeof(GLfloat) * 4);
}
LIGHTS[i].position[0] = LIGHTS[i].position[1] = LIGHTS[i].position[3] = 0.0f;
LIGHTS[i].position[2] = 1.0f;
LIGHTS[i].isDirectional = GL_TRUE;
LIGHTS[i].isEnabled = GL_FALSE;
LIGHTS[i].spot_direction[0] = LIGHTS[i].spot_direction[1] = 0.0f;
LIGHTS[i].spot_direction[2] = -1.0f;
LIGHTS[i].spot_exponent = 0.0f;
LIGHTS[i].spot_cutoff = 180.0f;
LIGHTS[i].constant_attenuation = 1.0f;
LIGHTS[i].linear_attenuation = 0.0f;
LIGHTS[i].quadratic_attenuation = 0.0f;
}
_glPrecalcLightingValues(~0);
recalcEnabledLights();
}
void _glEnableLight(GLubyte light, GLboolean value) {
LIGHTS[light].isEnabled = value;
recalcEnabledLights();
}
GL_FORCE_INLINE void _glPrecalcLightingValues(GLuint mask) {
/* Pre-calculate lighting values */ /* Pre-calculate lighting values */
GLshort i; GLshort i;
Material* material = _glActiveMaterial();
if(mask & AMBIENT_MASK) { if(mask & AMBIENT_MASK) {
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LIGHTS[i].ambientMaterial[0] = LIGHTS[i].ambient[0] * MATERIAL.ambient[0]; LightSource* light = _glLightAt(i);
LIGHTS[i].ambientMaterial[1] = LIGHTS[i].ambient[1] * MATERIAL.ambient[1];
LIGHTS[i].ambientMaterial[2] = LIGHTS[i].ambient[2] * MATERIAL.ambient[2]; light->ambientMaterial[0] = light->ambient[0] * material->ambient[0];
LIGHTS[i].ambientMaterial[3] = LIGHTS[i].ambient[3] * MATERIAL.ambient[3]; light->ambientMaterial[1] = light->ambient[1] * material->ambient[1];
light->ambientMaterial[2] = light->ambient[2] * material->ambient[2];
light->ambientMaterial[3] = light->ambient[3] * material->ambient[3];
} }
} }
if(mask & DIFFUSE_MASK) { if(mask & DIFFUSE_MASK) {
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LIGHTS[i].diffuseMaterial[0] = LIGHTS[i].diffuse[0] * MATERIAL.diffuse[0]; LightSource* light = _glLightAt(i);
LIGHTS[i].diffuseMaterial[1] = LIGHTS[i].diffuse[1] * MATERIAL.diffuse[1];
LIGHTS[i].diffuseMaterial[2] = LIGHTS[i].diffuse[2] * MATERIAL.diffuse[2]; light->diffuseMaterial[0] = light->diffuse[0] * material->diffuse[0];
LIGHTS[i].diffuseMaterial[3] = LIGHTS[i].diffuse[3] * MATERIAL.diffuse[3]; light->diffuseMaterial[1] = light->diffuse[1] * material->diffuse[1];
light->diffuseMaterial[2] = light->diffuse[2] * material->diffuse[2];
light->diffuseMaterial[3] = light->diffuse[3] * material->diffuse[3];
} }
} }
if(mask & SPECULAR_MASK) { if(mask & SPECULAR_MASK) {
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LIGHTS[i].specularMaterial[0] = LIGHTS[i].specular[0] * MATERIAL.specular[0]; LightSource* light = _glLightAt(i);
LIGHTS[i].specularMaterial[1] = LIGHTS[i].specular[1] * MATERIAL.specular[1];
LIGHTS[i].specularMaterial[2] = LIGHTS[i].specular[2] * MATERIAL.specular[2]; light->specularMaterial[0] = light->specular[0] * material->specular[0];
LIGHTS[i].specularMaterial[3] = LIGHTS[i].specular[3] * MATERIAL.specular[3]; light->specularMaterial[1] = light->specular[1] * material->specular[1];
light->specularMaterial[2] = light->specular[2] * material->specular[2];
light->specularMaterial[3] = light->specular[3] * material->specular[3];
} }
} }
/* If ambient or emission are updated, we need to update /* If ambient or emission are updated, we need to update
* the base colour. */ * the base colour. */
if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) { if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) {
MATERIAL.baseColour[0] = MATH_fmac(SCENE_AMBIENT[0], MATERIAL.ambient[0], MATERIAL.emissive[0]); GLfloat* scene_ambient = _glLightModelSceneAmbient();
MATERIAL.baseColour[1] = MATH_fmac(SCENE_AMBIENT[1], MATERIAL.ambient[1], MATERIAL.emissive[1]);
MATERIAL.baseColour[2] = MATH_fmac(SCENE_AMBIENT[2], MATERIAL.ambient[2], MATERIAL.emissive[2]); material->baseColour[0] = MATH_fmac(scene_ambient[0], material->ambient[0], material->emissive[0]);
MATERIAL.baseColour[3] = MATH_fmac(SCENE_AMBIENT[3], MATERIAL.ambient[3], MATERIAL.emissive[3]); material->baseColour[1] = MATH_fmac(scene_ambient[1], material->ambient[1], material->emissive[1]);
material->baseColour[2] = MATH_fmac(scene_ambient[2], material->ambient[2], material->emissive[2]);
material->baseColour[3] = MATH_fmac(scene_ambient[3], material->ambient[3], material->emissive[3]);
} }
} }
void _glInitLights() {
Material* material = _glActiveMaterial();
static GLfloat ONE [] = {1.0f, 1.0f, 1.0f, 1.0f};
static GLfloat ZERO [] = {0.0f, 0.0f, 0.0f, 1.0f};
static GLfloat PARTIAL [] = {0.2f, 0.2f, 0.2f, 1.0f};
static GLfloat MOSTLY [] = {0.8f, 0.8f, 0.8f, 1.0f};
memcpy(material->ambient, PARTIAL, sizeof(GLfloat) * 4);
memcpy(material->diffuse, MOSTLY, sizeof(GLfloat) * 4);
memcpy(material->specular, ZERO, sizeof(GLfloat) * 4);
memcpy(material->emissive, ZERO, sizeof(GLfloat) * 4);
material->exponent = 0.0f;
GLubyte i;
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
LightSource* light = _glLightAt(i);
memcpy(light->ambient, ZERO, sizeof(GLfloat) * 4);
memcpy(light->diffuse, ONE, sizeof(GLfloat) * 4);
memcpy(light->specular, ONE, sizeof(GLfloat) * 4);
if(i > 0) {
memcpy(light->diffuse, ZERO, sizeof(GLfloat) * 4);
memcpy(light->specular, ZERO, sizeof(GLfloat) * 4);
}
light->position[0] = light->position[1] = light->position[3] = 0.0f;
light->position[2] = 1.0f;
light->isDirectional = GL_TRUE;
light->isEnabled = GL_FALSE;
light->spot_direction[0] = light->spot_direction[1] = 0.0f;
light->spot_direction[2] = -1.0f;
light->spot_exponent = 0.0f;
light->spot_cutoff = 180.0f;
light->constant_attenuation = 1.0f;
light->linear_attenuation = 0.0f;
light->quadratic_attenuation = 0.0f;
}
_glPrecalcLightingValues(~0);
_glRecalcEnabledLights();
}
void APIENTRY glLightModelf(GLenum pname, const GLfloat param) { void APIENTRY glLightModelf(GLenum pname, const GLfloat param) {
glLightModelfv(pname, &param); glLightModelfv(pname, &param);
} }
@ -143,11 +124,11 @@ void APIENTRY glLightModeli(GLenum pname, const GLint param) {
void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) { void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) {
switch(pname) { switch(pname) {
case GL_LIGHT_MODEL_AMBIENT: { case GL_LIGHT_MODEL_AMBIENT: {
for(int i = 0; i < 4; ++i) SCENE_AMBIENT[i] = params[i]; _glSetLightModelSceneAmbient(params);
_glPrecalcLightingValues(SCENE_AMBIENT_MASK); _glPrecalcLightingValues(SCENE_AMBIENT_MASK);
} break; } break;
case GL_LIGHT_MODEL_LOCAL_VIEWER: case GL_LIGHT_MODEL_LOCAL_VIEWER:
VIEWER_IN_EYE_COORDINATES = (*params) ? GL_TRUE : GL_FALSE; _glSetLightModelViewerInEyeCoordinates((*params) ? GL_TRUE : GL_FALSE);
break; break;
case GL_LIGHT_MODEL_TWO_SIDE: case GL_LIGHT_MODEL_TWO_SIDE:
/* Not implemented */ /* Not implemented */
@ -159,10 +140,10 @@ void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) {
void APIENTRY glLightModeliv(GLenum pname, const GLint* params) { void APIENTRY glLightModeliv(GLenum pname, const GLint* params) {
switch(pname) { switch(pname) {
case GL_LIGHT_MODEL_COLOR_CONTROL: case GL_LIGHT_MODEL_COLOR_CONTROL:
COLOR_CONTROL = *params; _glSetLightModelColorControl(*params);
break; break;
case GL_LIGHT_MODEL_LOCAL_VIEWER: case GL_LIGHT_MODEL_LOCAL_VIEWER:
VIEWER_IN_EYE_COORDINATES = (*params) ? GL_TRUE : GL_FALSE; _glSetLightModelViewerInEyeCoordinates((*params) ? GL_TRUE : GL_FALSE);
break; break;
default: default:
_glKosThrowError(GL_INVALID_ENUM, __func__); _glKosThrowError(GL_INVALID_ENUM, __func__);
@ -173,6 +154,7 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) {
GLubyte idx = light & 0xF; GLubyte idx = light & 0xF;
if(idx >= MAX_GLDC_LIGHTS) { if(idx >= MAX_GLDC_LIGHTS) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
return; return;
} }
@ -180,33 +162,35 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) {
(pname == GL_DIFFUSE) ? DIFFUSE_MASK : (pname == GL_DIFFUSE) ? DIFFUSE_MASK :
(pname == GL_SPECULAR) ? SPECULAR_MASK : 0; (pname == GL_SPECULAR) ? SPECULAR_MASK : 0;
LightSource* l = _glLightAt(idx);
switch(pname) { switch(pname) {
case GL_AMBIENT: case GL_AMBIENT:
memcpy(LIGHTS[idx].ambient, params, sizeof(GLfloat) * 4); memcpy(l->ambient, params, sizeof(GLfloat) * 4);
break; break;
case GL_DIFFUSE: case GL_DIFFUSE:
memcpy(LIGHTS[idx].diffuse, params, sizeof(GLfloat) * 4); memcpy(l->diffuse, params, sizeof(GLfloat) * 4);
break; break;
case GL_SPECULAR: case GL_SPECULAR:
memcpy(LIGHTS[idx].specular, params, sizeof(GLfloat) * 4); memcpy(l->specular, params, sizeof(GLfloat) * 4);
break; break;
case GL_POSITION: { case GL_POSITION: {
_glMatrixLoadModelView(); _glMatrixLoadModelView();
memcpy(LIGHTS[idx].position, params, sizeof(GLfloat) * 4); memcpy(l->position, params, sizeof(GLfloat) * 4);
LIGHTS[idx].isDirectional = params[3] == 0.0f; l->isDirectional = params[3] == 0.0f;
if(LIGHTS[idx].isDirectional) { if(l->isDirectional) {
//FIXME: Do we need to rotate directional lights? //FIXME: Do we need to rotate directional lights?
} else { } else {
TransformVec3(LIGHTS[idx].position); TransformVec3(l->position);
} }
} }
break; break;
case GL_SPOT_DIRECTION: { case GL_SPOT_DIRECTION: {
LIGHTS[idx].spot_direction[0] = params[0]; l->spot_direction[0] = params[0];
LIGHTS[idx].spot_direction[1] = params[1]; l->spot_direction[1] = params[1];
LIGHTS[idx].spot_direction[2] = params[2]; l->spot_direction[2] = params[2];
} break; } break;
case GL_CONSTANT_ATTENUATION: case GL_CONSTANT_ATTENUATION:
case GL_LINEAR_ATTENUATION: case GL_LINEAR_ATTENUATION:
@ -227,24 +211,26 @@ void APIENTRY glLightf(GLenum light, GLenum pname, GLfloat param) {
GLubyte idx = light & 0xF; GLubyte idx = light & 0xF;
if(idx >= MAX_GLDC_LIGHTS) { if(idx >= MAX_GLDC_LIGHTS) {
_glKosThrowError(GL_INVALID_VALUE, __func__);
return; return;
} }
LightSource* l = _glLightAt(idx);
switch(pname) { switch(pname) {
case GL_CONSTANT_ATTENUATION: case GL_CONSTANT_ATTENUATION:
LIGHTS[idx].constant_attenuation = param; l->constant_attenuation = param;
break; break;
case GL_LINEAR_ATTENUATION: case GL_LINEAR_ATTENUATION:
LIGHTS[idx].linear_attenuation = param; l->linear_attenuation = param;
break; break;
case GL_QUADRATIC_ATTENUATION: case GL_QUADRATIC_ATTENUATION:
LIGHTS[idx].quadratic_attenuation = param; l->quadratic_attenuation = param;
break; break;
case GL_SPOT_EXPONENT: case GL_SPOT_EXPONENT:
LIGHTS[idx].spot_exponent = param; l->spot_exponent = param;
break; break;
case GL_SPOT_CUTOFF: case GL_SPOT_CUTOFF:
LIGHTS[idx].spot_cutoff = param; l->spot_cutoff = param;
break; break;
default: default:
_glKosThrowError(GL_INVALID_ENUM, __func__); _glKosThrowError(GL_INVALID_ENUM, __func__);
@ -257,7 +243,7 @@ void APIENTRY glMaterialf(GLenum face, GLenum pname, const GLfloat param) {
return; return;
} }
MATERIAL.exponent = _MIN(param, 128); /* 128 is the max according to the GL spec */ _glActiveMaterial()->exponent = _MIN(param, 128); /* 128 is the max according to the GL spec */
} }
void APIENTRY glMateriali(GLenum face, GLenum pname, const GLint param) { void APIENTRY glMateriali(GLenum face, GLenum pname, const GLint param) {
@ -270,25 +256,27 @@ void APIENTRY glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) {
return; return;
} }
Material* material = _glActiveMaterial();
switch(pname) { switch(pname) {
case GL_SHININESS: case GL_SHININESS:
glMaterialf(face, pname, *params); glMaterialf(face, pname, *params);
break; break;
case GL_AMBIENT: case GL_AMBIENT:
vec4cpy(MATERIAL.ambient, params); vec4cpy(material->ambient, params);
break; break;
case GL_DIFFUSE: case GL_DIFFUSE:
vec4cpy(MATERIAL.diffuse, params); vec4cpy(material->diffuse, params);
break; break;
case GL_SPECULAR: case GL_SPECULAR:
vec4cpy(MATERIAL.specular, params); vec4cpy(material->specular, params);
break; break;
case GL_EMISSION: case GL_EMISSION:
vec4cpy(MATERIAL.emissive, params); vec4cpy(material->emissive, params);
break; break;
case GL_AMBIENT_AND_DIFFUSE: { case GL_AMBIENT_AND_DIFFUSE: {
vec4cpy(MATERIAL.ambient, params); vec4cpy(material->ambient, params);
vec4cpy(MATERIAL.diffuse, params); vec4cpy(material->diffuse, params);
} break; } break;
case GL_COLOR_INDEXES: case GL_COLOR_INDEXES:
default: { default: {
@ -318,12 +306,13 @@ void APIENTRY glColorMaterial(GLenum face, GLenum mode) {
return; return;
} }
COLOR_MATERIAL_MASK = (mode == GL_AMBIENT) ? AMBIENT_MASK: GLenum mask = (mode == GL_AMBIENT) ? AMBIENT_MASK:
(mode == GL_DIFFUSE) ? DIFFUSE_MASK: (mode == GL_DIFFUSE) ? DIFFUSE_MASK:
(mode == GL_AMBIENT_AND_DIFFUSE) ? AMBIENT_MASK | DIFFUSE_MASK: (mode == GL_AMBIENT_AND_DIFFUSE) ? AMBIENT_MASK | DIFFUSE_MASK:
(mode == GL_EMISSION) ? EMISSION_MASK : SPECULAR_MASK; (mode == GL_EMISSION) ? EMISSION_MASK : SPECULAR_MASK;
COLOR_MATERIAL_MODE = mode; _glSetColorMaterialMask(mask);
_glSetColorMaterialMode(mode);
} }
GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) { GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) {
@ -336,44 +325,68 @@ GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) {
} }
void _glUpdateColourMaterialA(const GLubyte* argb) { void _glUpdateColourMaterialA(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4]; float colour[4];
bgra_to_float(argb, colour); bgra_to_float(argb, colour);
vec4cpy(MATERIAL.ambient, colour); vec4cpy(material->ambient, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK); GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
} }
void _glUpdateColourMaterialD(const GLubyte* argb) { void _glUpdateColourMaterialD(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4]; float colour[4];
bgra_to_float(argb, colour); bgra_to_float(argb, colour);
vec4cpy(MATERIAL.diffuse, colour); vec4cpy(material->diffuse, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
} }
void _glUpdateColourMaterialE(const GLubyte* argb) { void _glUpdateColourMaterialE(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4]; float colour[4];
bgra_to_float(argb, colour); bgra_to_float(argb, colour);
vec4cpy(MATERIAL.emissive, colour); vec4cpy(material->emissive, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
} }
void _glUpdateColourMaterialAD(const GLubyte* argb) { void _glUpdateColourMaterialAD(const GLubyte* argb) {
Material* material = _glActiveMaterial();
float colour[4]; float colour[4];
bgra_to_float(argb, colour); bgra_to_float(argb, colour);
vec4cpy(MATERIAL.ambient, colour); vec4cpy(material->ambient, colour);
vec4cpy(MATERIAL.diffuse, colour); vec4cpy(material->diffuse, colour);
_glPrecalcLightingValues(COLOR_MATERIAL_MASK);
GLenum mask = _glColorMaterialMode();
_glPrecalcLightingValues(mask);
} }
GL_FORCE_INLINE GLboolean isDiffuseColorMaterial() { GL_FORCE_INLINE GLboolean isDiffuseColorMaterial() {
return (COLOR_MATERIAL_MODE == GL_DIFFUSE || COLOR_MATERIAL_MODE == GL_AMBIENT_AND_DIFFUSE); GLenum mode = _glColorMaterialMode();
return (
mode == GL_DIFFUSE ||
mode == GL_AMBIENT_AND_DIFFUSE
);
} }
GL_FORCE_INLINE GLboolean isAmbientColorMaterial() { GL_FORCE_INLINE GLboolean isAmbientColorMaterial() {
return (COLOR_MATERIAL_MODE == GL_AMBIENT || COLOR_MATERIAL_MODE == GL_AMBIENT_AND_DIFFUSE); GLenum mode = _glColorMaterialMode();
return (
mode == GL_AMBIENT ||
mode == GL_AMBIENT_AND_DIFFUSE
);
} }
GL_FORCE_INLINE GLboolean isSpecularColorMaterial() { GL_FORCE_INLINE GLboolean isSpecularColorMaterial() {
return (COLOR_MATERIAL_MODE == GL_SPECULAR); GLenum mode = _glColorMaterialMode();
return (mode == GL_SPECULAR);
} }
/* /*
@ -408,12 +421,15 @@ GL_FORCE_INLINE void _glLightVertexDirectional(
float* final, uint8_t lid, float* final, uint8_t lid,
float LdotN, float NdotH) { float LdotN, float NdotH) {
float FI = (MATERIAL.exponent) ? Material* material = _glActiveMaterial();
faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f; LightSource* light = _glLightAt(lid);
float FI = (material->exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, material->exponent) : 1.0f;
#define _PROCESS_COMPONENT(X) \ #define _PROCESS_COMPONENT(X) \
final[X] += (LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \ final[X] += (LdotN * light->diffuseMaterial[X] + light->ambientMaterial[X]) \
+ (FI * LIGHTS[lid].specularMaterial[X]); \ + (FI * light->specularMaterial[X]); \
_PROCESS_COMPONENT(0); _PROCESS_COMPONENT(0);
_PROCESS_COMPONENT(1); _PROCESS_COMPONENT(1);
@ -426,12 +442,15 @@ GL_FORCE_INLINE void _glLightVertexPoint(
float* final, uint8_t lid, float* final, uint8_t lid,
float LdotN, float NdotH, float att) { float LdotN, float NdotH, float att) {
float FI = (MATERIAL.exponent) ? Material* material = _glActiveMaterial();
faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f; LightSource* light = _glLightAt(lid);
float FI = (material->exponent) ?
faster_pow((LdotN != 0.0f) * NdotH, material->exponent) : 1.0f;
#define _PROCESS_COMPONENT(X) \ #define _PROCESS_COMPONENT(X) \
final[X] += ((LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \ final[X] += ((LdotN * light->diffuseMaterial[X] + light->ambientMaterial[X]) \
+ (FI * LIGHTS[lid].specularMaterial[X])) * att; \ + (FI * light->specularMaterial[X])) * att; \
_PROCESS_COMPONENT(0); _PROCESS_COMPONENT(0);
_PROCESS_COMPONENT(1); _PROCESS_COMPONENT(1);
@ -444,6 +463,8 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
GLubyte i; GLubyte i;
GLuint j; GLuint j;
Material* material = _glActiveMaterial();
Vertex* vertex = vertices; Vertex* vertex = vertices;
EyeSpaceData* data = es; EyeSpaceData* data = es;
@ -451,7 +472,8 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
void (*updateColourMaterial)(const GLubyte*) = NULL; void (*updateColourMaterial)(const GLubyte*) = NULL;
if(_glIsColorMaterialEnabled()) { if(_glIsColorMaterialEnabled()) {
switch(COLOR_MATERIAL_MODE) { GLenum mode = _glColorMaterialMode();
switch(mode) {
case GL_AMBIENT: case GL_AMBIENT:
updateColourMaterial = _glUpdateColourMaterialA; updateColourMaterial = _glUpdateColourMaterialA;
break; break;
@ -474,10 +496,10 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
} }
/* Copy the base colour across */ /* Copy the base colour across */
vec4cpy(data->finalColour, MATERIAL.baseColour); vec4cpy(data->finalColour, material->baseColour);
} }
if(!ENABLED_LIGHT_COUNT) { if(!_glEnabledLightCount()) {
return; return;
} }
@ -495,15 +517,17 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
const float Nz = data->n[2]; const float Nz = data->n[2];
for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) {
if(!LIGHTS[i].isEnabled) { LightSource* light = _glLightAt(i);
if(!light->isEnabled) {
continue; continue;
} }
float Lx = LIGHTS[i].position[0] - vertex->xyz[0]; float Lx = light->position[0] - vertex->xyz[0];
float Ly = LIGHTS[i].position[1] - vertex->xyz[1]; float Ly = light->position[1] - vertex->xyz[1];
float Lz = LIGHTS[i].position[2] - vertex->xyz[2]; float Lz = light->position[2] - vertex->xyz[2];
if(LIGHTS[i].isDirectional) { if(light->isDirectional) {
float Hx = (Lx + 0); float Hx = (Lx + 0);
float Hy = (Ly + 0); float Hy = (Ly + 0);
float Hz = (Lz + 1); float Hz = (Lz + 1);
@ -532,9 +556,9 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count
VEC3_LENGTH(Lx, Ly, Lz, D); VEC3_LENGTH(Lx, Ly, Lz, D);
float att = ( float att = (
LIGHTS[i].constant_attenuation + ( light->constant_attenuation + (
LIGHTS[i].linear_attenuation * D light->linear_attenuation * D
) + (LIGHTS[i].quadratic_attenuation * D * D) ) + (light->quadratic_attenuation * D * D)
); );
/* Anything over the attenuation threshold will /* Anything over the attenuation threshold will

View File

@ -74,9 +74,7 @@ GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) {
vertex->xyz[2] = (vertex->w == 1.0f) ? _glFastInvert(1.0001f + vertex->xyz[2]) : f; vertex->xyz[2] = (vertex->w == 1.0f) ? _glFastInvert(1.0001f + vertex->xyz[2]) : f;
} }
static uint32_t *d; // SQ target GL_FORCE_INLINE void _glSubmitHeaderOrVertex(uint32_t* d, const Vertex* v) {
GL_FORCE_INLINE void _glSubmitHeaderOrVertex(const Vertex* v) {
#ifndef NDEBUG #ifndef NDEBUG
gl_assert(!isnan(v->xyz[2])); gl_assert(!isnan(v->xyz[2]));
gl_assert(!isnan(v->w)); gl_assert(!isnan(v->w));
@ -123,11 +121,14 @@ GL_FORCE_INLINE void interpolateColour(const uint8_t* v1, const uint8_t* v2, con
} }
GL_FORCE_INLINE void _glClipEdge(const Vertex* v1, const Vertex* v2, Vertex* vout) { GL_FORCE_INLINE void _glClipEdge(const Vertex* v1, const Vertex* v2, Vertex* vout) {
static const float E [] = {
0.00001f, -0.00001f
};
/* Clipping time! */ /* Clipping time! */
const float d0 = v1->w + v1->xyz[2]; const float d0 = v1->w + v1->xyz[2];
const float d1 = v2->w + v2->xyz[2]; const float d1 = v2->w + v2->xyz[2];
const float epsilon = E[d0 < d1];
const float epsilon = (d0 < d1) ? -0.00001f : 0.00001f;
float t = MATH_Fast_Divide(d0, (d0 - d1)) + epsilon; float t = MATH_Fast_Divide(d0, (d0 - d1)) + epsilon;
@ -182,28 +183,27 @@ GL_FORCE_INLINE void ShiftRotateTriangle() {
#define SPAN_SORT_CFG 0x005F8030 #define SPAN_SORT_CFG 0x005F8030
void SceneListSubmit(void* src, int n) { void SceneListSubmit(void* src, int n) {
Vertex __attribute__((aligned(32))) tmp; const float h = GetVideoMode()->height;
/* Do everything, everywhere, all at once */
PVR_SET(SPAN_SORT_CFG, 0x0); PVR_SET(SPAN_SORT_CFG, 0x0);
/* Prep store queues */ uint32_t *d = (uint32_t*) SQ_BASE_ADDRESS;
d = (uint32_t*) SQ_BASE_ADDRESS;
*PVR_LMMODE0 = 0x0; /* Enable 64bit mode */ *PVR_LMMODE0 = 0x0; /* Enable 64bit mode */
Vertex __attribute__((aligned(32))) tmp;
/* Perform perspective divide on each vertex */ /* Perform perspective divide on each vertex */
Vertex* vertex = (Vertex*) src; Vertex* vertex = (Vertex*) src;
const float h = GetVideoMode()->height; if(!_glNearZClippingEnabled()) {
/* Prep store queues */
if(!ZNEAR_CLIPPING_ENABLED) {
for(int i = 0; i < n; ++i, ++vertex) { for(int i = 0; i < n; ++i, ++vertex) {
PREFETCH(vertex + 1); PREFETCH(vertex + 1);
if(glIsVertex(vertex->flags)) { if(glIsVertex(vertex->flags)) {
_glPerspectiveDivideVertex(vertex, h); _glPerspectiveDivideVertex(vertex, h);
} }
_glSubmitHeaderOrVertex(vertex); _glSubmitHeaderOrVertex(d, vertex);
} }
/* Wait for both store queues to complete */ /* Wait for both store queues to complete */
@ -221,25 +221,22 @@ void SceneListSubmit(void* src, int n) {
#endif #endif
for(int i = 0; i < n; ++i, ++vertex) { for(int i = 0; i < n; ++i, ++vertex) {
PREFETCH(vertex + 1); PREFETCH(vertex + 12);
bool is_last_in_strip = glIsLastVertex(vertex->flags);
/* Wait until we fill the triangle */ /* Wait until we fill the triangle */
if(tri_count < 3) { if(tri_count < 3) {
if(likely(glIsVertex(vertex->flags))) { if(glIsVertex(vertex->flags)) {
++strip_count;
triangle[tri_count].v = vertex; triangle[tri_count].v = vertex;
triangle[tri_count].visible = vertex->xyz[2] >= -vertex->w; triangle[tri_count].visible = vertex->xyz[2] >= -vertex->w;
tri_count++; if(++tri_count < 3) {
strip_count++; continue;
}
} else { } else {
/* We hit a header */ /* We hit a header */
tri_count = 0; tri_count = 0;
strip_count = 0; strip_count = 0;
_glSubmitHeaderOrVertex(vertex); _glSubmitHeaderOrVertex(d, vertex);
}
if(tri_count < 3) {
continue; continue;
} }
} }
@ -250,26 +247,7 @@ void SceneListSubmit(void* src, int n) {
/* If we got here, then triangle contains 3 vertices */ /* If we got here, then triangle contains 3 vertices */
int visible_mask = triangle[0].visible | (triangle[1].visible << 1) | (triangle[2].visible << 2); int visible_mask = triangle[0].visible | (triangle[1].visible << 1) | (triangle[2].visible << 2);
if(visible_mask == 7) {
#if CLIP_DEBUG
printf("Visible\n");
#endif
/* All the vertices are visible! We divide and submit v0, then shift */
_glPerspectiveDivideVertex(vertex - 2, h);
_glSubmitHeaderOrVertex(vertex - 2);
if(is_last_in_strip) {
_glPerspectiveDivideVertex(vertex - 1, h);
_glSubmitHeaderOrVertex(vertex - 1);
_glPerspectiveDivideVertex(vertex, h);
_glSubmitHeaderOrVertex(vertex);
tri_count = 0;
strip_count = 0;
}
ShiftRotateTriangle();
} else if(visible_mask) {
/* Clipping time! /* Clipping time!
There are 6 distinct possibilities when clipping a triangle. 3 of them result There are 6 distinct possibilities when clipping a triangle. 3 of them result
@ -283,144 +261,163 @@ void SceneListSubmit(void* src, int n) {
Unfortunately we have to copy vertices here, because if we persp-divide a vertex it may Unfortunately we have to copy vertices here, because if we persp-divide a vertex it may
be used in a subsequent triangle in the strip and would end up being double divided. be used in a subsequent triangle in the strip and would end up being double divided.
*/ */
#if CLIP_DEBUG
printf("Clip: %d, SC: %d\n", visible_mask, strip_count);
printf("%d, %d, %d\n", triangle[0].v - (Vertex*) src - 1, triangle[1].v - (Vertex*) src - 1, triangle[2].v - (Vertex*) src - 1);
#endif
Vertex tmp;
if(strip_count > 3) {
#if CLIP_DEBUG
printf("Flush\n");
#endif
tmp = *(vertex - 2);
/* If we had triangles ahead of this one, submit and finalize */
_glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp);
tmp = *(vertex - 1); #define SUBMIT_QUEUED() \
tmp.flags = GPU_CMD_VERTEX_EOL; if(strip_count > 3) { \
_glPerspectiveDivideVertex(&tmp, h); tmp = *(vertex - 2); \
_glSubmitHeaderOrVertex(&tmp); /* If we had triangles ahead of this one, submit and finalize */ \
_glPerspectiveDivideVertex(&tmp, h); \
_glSubmitHeaderOrVertex(d, &tmp); \
tmp = *(vertex - 1); \
tmp.flags = GPU_CMD_VERTEX_EOL; \
_glPerspectiveDivideVertex(&tmp, h); \
_glSubmitHeaderOrVertex(d, &tmp); \
} }
bool is_last_in_strip = glIsLastVertex(vertex->flags);
switch(visible_mask) { switch(visible_mask) {
case 1: { case 1: {
SUBMIT_QUEUED();
/* 0, 0a, 2a */ /* 0, 0a, 2a */
tmp = *triangle[0].v; tmp = *triangle[0].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[0].v, triangle[1].v, &tmp); _glClipEdge(triangle[0].v, triangle[1].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[2].v, triangle[0].v, &tmp); _glClipEdge(triangle[2].v, triangle[0].v, &tmp);
tmp.flags = GPU_CMD_VERTEX_EOL; tmp.flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
} break; } break;
case 2: { case 2: {
SUBMIT_QUEUED();
/* 0a, 1, 1a */ /* 0a, 1, 1a */
_glClipEdge(triangle[0].v, triangle[1].v, &tmp); _glClipEdge(triangle[0].v, triangle[1].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
tmp = *triangle[1].v; tmp = *triangle[1].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[1].v, triangle[2].v, &tmp); _glClipEdge(triangle[1].v, triangle[2].v, &tmp);
tmp.flags = GPU_CMD_VERTEX_EOL; tmp.flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
} break; } break;
case 3: { case 3: {
SUBMIT_QUEUED();
/* 0, 1, 2a, 1a */ /* 0, 1, 2a, 1a */
tmp = *triangle[0].v; tmp = *triangle[0].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
tmp = *triangle[1].v; tmp = *triangle[1].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[2].v, triangle[0].v, &tmp); _glClipEdge(triangle[2].v, triangle[0].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[1].v, triangle[2].v, &tmp); _glClipEdge(triangle[1].v, triangle[2].v, &tmp);
tmp.flags = GPU_CMD_VERTEX_EOL; tmp.flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
} break; } break;
case 4: { case 4: {
SUBMIT_QUEUED();
/* 1a, 2, 2a */ /* 1a, 2, 2a */
_glClipEdge(triangle[1].v, triangle[2].v, &tmp); _glClipEdge(triangle[1].v, triangle[2].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
tmp = *triangle[2].v; tmp = *triangle[2].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[2].v, triangle[0].v, &tmp); _glClipEdge(triangle[2].v, triangle[0].v, &tmp);
tmp.flags = GPU_CMD_VERTEX_EOL; tmp.flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
} break; } break;
case 5: { case 5: {
SUBMIT_QUEUED();
/* 0, 0a, 2, 1a */ /* 0, 0a, 2, 1a */
tmp = *triangle[0].v; tmp = *triangle[0].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[0].v, triangle[1].v, &tmp); _glClipEdge(triangle[0].v, triangle[1].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
tmp = *triangle[2].v; tmp = *triangle[2].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[1].v, triangle[2].v, &tmp); _glClipEdge(triangle[1].v, triangle[2].v, &tmp);
tmp.flags = GPU_CMD_VERTEX_EOL; tmp.flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
} break; } break;
case 6: { case 6: {
SUBMIT_QUEUED();
/* 0a, 1, 2a, 2 */ /* 0a, 1, 2a, 2 */
_glClipEdge(triangle[0].v, triangle[1].v, &tmp); _glClipEdge(triangle[0].v, triangle[1].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
tmp = *triangle[1].v; tmp = *triangle[1].v;
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
_glClipEdge(triangle[2].v, triangle[0].v, &tmp); _glClipEdge(triangle[2].v, triangle[0].v, &tmp);
tmp.flags = GPU_CMD_VERTEX; tmp.flags = GPU_CMD_VERTEX;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
tmp = *triangle[2].v; tmp = *triangle[2].v;
tmp.flags = GPU_CMD_VERTEX_EOL; tmp.flags = GPU_CMD_VERTEX_EOL;
_glPerspectiveDivideVertex(&tmp, h); _glPerspectiveDivideVertex(&tmp, h);
_glSubmitHeaderOrVertex(&tmp); _glSubmitHeaderOrVertex(d, &tmp);
} break; } break;
case 7: {
/* All the vertices are visible! We divide and submit v0, then shift */
_glPerspectiveDivideVertex(vertex - 2, h);
_glSubmitHeaderOrVertex(d, vertex - 2);
if(is_last_in_strip) {
_glPerspectiveDivideVertex(vertex - 1, h);
_glSubmitHeaderOrVertex(d, vertex - 1);
_glPerspectiveDivideVertex(vertex, h);
_glSubmitHeaderOrVertex(d, vertex);
tri_count = 0;
strip_count = 0;
}
ShiftRotateTriangle();
continue;
} break;
case 0:
default: default:
break; break;
} }
@ -434,16 +431,6 @@ void SceneListSubmit(void* src, int n) {
ShiftRotateTriangle(); ShiftRotateTriangle();
strip_count = 2; strip_count = 2;
} }
} else {
/* Invisible? Move to the next in the strip */
if(is_last_in_strip) {
tri_count = 0;
strip_count = 0;
}
strip_count = 2;
ShiftRotateTriangle();
}
} }
/* Wait for both store queues to complete */ /* Wait for both store queues to complete */

View File

@ -354,26 +354,17 @@ void _glSetInternalPaletteFormat(GLenum val);
GLboolean _glIsSharedTexturePaletteEnabled(); GLboolean _glIsSharedTexturePaletteEnabled();
void _glApplyColorTable(TexturePalette *palette); void _glApplyColorTable(TexturePalette *palette);
extern GLboolean BLEND_ENABLED; GLboolean _glIsBlendingEnabled();
extern GLboolean ALPHA_TEST_ENABLED; GLboolean _glIsAlphaTestEnabled();
extern GLboolean AUTOSORT_ENABLED;
GL_FORCE_INLINE GLboolean _glIsBlendingEnabled() {
return BLEND_ENABLED;
}
GL_FORCE_INLINE GLboolean _glIsAlphaTestEnabled() {
return ALPHA_TEST_ENABLED;
}
extern PolyList OP_LIST; extern PolyList OP_LIST;
extern PolyList PT_LIST; extern PolyList PT_LIST;
extern PolyList TR_LIST; extern PolyList TR_LIST;
GL_FORCE_INLINE PolyList* _glActivePolyList() { GL_FORCE_INLINE PolyList* _glActivePolyList() {
if(BLEND_ENABLED) { if(_glIsBlendingEnabled()) {
return &TR_LIST; return &TR_LIST;
} else if(ALPHA_TEST_ENABLED) { } else if(_glIsAlphaTestEnabled()) {
return &PT_LIST; return &PT_LIST;
} else { } else {
return &OP_LIST; return &OP_LIST;
@ -383,13 +374,9 @@ GL_FORCE_INLINE PolyList* _glActivePolyList() {
GLboolean _glIsMipmapComplete(const TextureObject* obj); GLboolean _glIsMipmapComplete(const TextureObject* obj);
GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level); GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level);
GLuint _glGetMipmapLevelCount(const TextureObject* obj); GLuint _glGetMipmapLevelCount(const TextureObject* obj);
extern GLboolean ZNEAR_CLIPPING_ENABLED;
extern GLboolean LIGHTING_ENABLED;
GLboolean _glIsLightingEnabled(); GLboolean _glIsLightingEnabled();
void _glEnableLight(GLubyte light, unsigned char value); void _glEnableLight(GLubyte light, GLboolean value);
GLboolean _glIsColorMaterialEnabled(); GLboolean _glIsColorMaterialEnabled();
GLboolean _glIsNormalizeEnabled(); GLboolean _glIsNormalizeEnabled();
@ -513,10 +500,30 @@ GLuint _glUsedTextureMemory();
GLuint _glFreeContiguousTextureMemory(); GLuint _glFreeContiguousTextureMemory();
void _glApplyScissor(bool force); void _glApplyScissor(bool force);
void _glSetColorMaterialMask(GLenum mask);
void _glSetColorMaterialMode(GLenum mode);
GLenum _glColorMaterialMode();
Material* _glActiveMaterial();
void _glSetLightModelViewerInEyeCoordinates(GLboolean v);
void _glSetLightModelSceneAmbient(const GLfloat* v);
void _glSetLightModelColorControl(GLint v);
GLuint _glEnabledLightCount();
void _glRecalcEnabledLights();
GLfloat* _glLightModelSceneAmbient();
LightSource* _glLightAt(GLuint i);
GLboolean _glNearZClippingEnabled();
#define MAX_GLDC_TEXTURE_UNITS 2 #define MAX_GLDC_TEXTURE_UNITS 2
#define MAX_GLDC_LIGHTS 8 #define MAX_GLDC_LIGHTS 8
#define AMBIENT_MASK 1
#define DIFFUSE_MASK 2
#define EMISSION_MASK 4
#define SPECULAR_MASK 8
#define SCENE_AMBIENT_MASK 16
/* This is from KOS pvr_buffers.c */ /* This is from KOS pvr_buffers.c */
#define PVR_MIN_Z 0.0001f #define PVR_MIN_Z 0.0001f

View File

@ -10,64 +10,176 @@ PolyContext *_glGetPVRContext() {
return &GL_CONTEXT; return &GL_CONTEXT;
} }
static struct {
GLboolean is_dirty;
/* We can't just use the GL_CONTEXT for this state as the two /* 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 * GL states are combined, so we store them separately and then
* calculate the appropriate PVR state from them. */ * calculate the appropriate PVR state from them. */
static GLenum CULL_FACE = GL_BACK; GLenum depth_func;
static GLenum FRONT_FACE = GL_CCW; GLboolean depth_test_enabled;
static GLboolean CULLING_ENABLED = GL_FALSE; GLenum cull_face;
static GLboolean COLOR_MATERIAL_ENABLED = GL_FALSE; GLenum front_face;
GLboolean culling_enabled;
GLboolean color_material_enabled;
GLboolean znear_clipping_enabled;
GLboolean lighting_enabled;
GLboolean shared_palette_enabled;
GLboolean alpha_test_enabled;
GLboolean polygon_offset_enabled;
GLboolean normalize_enabled;;
GLboolean ZNEAR_CLIPPING_ENABLED = GL_TRUE; struct {
GLboolean LIGHTING_ENABLED = GL_FALSE;
/* Is the shared texture palette enabled? */
static GLboolean SHARED_PALETTE_ENABLED = GL_FALSE;
GLboolean ALPHA_TEST_ENABLED = GL_FALSE;
static GLboolean POLYGON_OFFSET_ENABLED = GL_FALSE;
static GLboolean NORMALIZE_ENABLED = GL_FALSE;
static struct {
GLint x; GLint x;
GLint y; GLint y;
GLsizei width; GLsizei width;
GLsizei height; GLsizei height;
GLboolean applied; GLboolean applied;
} SCISSOR_RECT = { } scissor_rect;
0, 0, 640, 480, false
GLenum blend_sfactor;
GLenum blend_dfactor;
GLboolean blend_enabled;
GLfloat offset_factor;
GLfloat offset_units;
GLfloat scene_ambient[4];
GLboolean viewer_in_eye_coords;
GLenum color_control;
GLenum color_material_mode;
GLenum color_material_mask;
LightSource lights[MAX_GLDC_LIGHTS];
GLuint enabled_light_count;
Material material;
} GPUState = {
GL_TRUE,
GL_LESS,
GL_FALSE,
GL_BACK,
GL_CCW,
GL_FALSE,
GL_FALSE,
GL_TRUE,
GL_FALSE,
GL_FALSE,
GL_FALSE,
GL_FALSE,
GL_FALSE,
{0, 0, 640, 480, false},
GL_ONE,
GL_ZERO,
GL_FALSE,
0.0f,
0.0f,
{0.2f, 0.2f, 0.2f, 1.0f},
GL_TRUE,
GL_SINGLE_COLOR,
GL_AMBIENT_AND_DIFFUSE,
AMBIENT_MASK | DIFFUSE_MASK,
{0},
0,
{0}
}; };
Material* _glActiveMaterial() {
return &GPUState.material;
}
LightSource* _glLightAt(GLuint i) {
assert(i < MAX_GLDC_LIGHTS);
return &GPUState.lights[i];
}
void _glEnableLight(GLubyte light, GLboolean value) {
GPUState.lights[light].isEnabled = value;
}
GLuint _glEnabledLightCount() {
return GPUState.enabled_light_count;
}
GLfloat* _glLightModelSceneAmbient() {
return GPUState.scene_ambient;
}
GLboolean _glIsBlendingEnabled() {
return GPUState.blend_enabled;
}
GLboolean _glIsAlphaTestEnabled() {
return GPUState.alpha_test_enabled;
}
void _glRecalcEnabledLights() {
GLubyte i;
GPUState.enabled_light_count = 0;
for(int i = 0; i < MAX_GLDC_LIGHTS; ++i) {
if(_glLightAt(i)->isEnabled) {
GPUState.enabled_light_count++;
}
}
}
void _glSetLightModelViewerInEyeCoordinates(GLboolean v) {
GPUState.viewer_in_eye_coords = v;
}
void _glSetLightModelSceneAmbient(const GLfloat* v) {
vec4cpy(GPUState.scene_ambient, v);
}
void _glSetLightModelColorControl(GLint v) {
GPUState.color_control = v;
}
GLenum _glColorMaterialMask() {
return GPUState.color_material_mask;
}
void _glSetColorMaterialMask(GLenum mask) {
GPUState.color_material_mask = mask;
}
void _glSetColorMaterialMode(GLenum mode) {
GPUState.color_material_mode = mode;
}
GLenum _glColorMaterialMode() {
return GPUState.color_material_mode;
}
GLboolean _glIsSharedTexturePaletteEnabled() { GLboolean _glIsSharedTexturePaletteEnabled() {
return SHARED_PALETTE_ENABLED; return GPUState.shared_palette_enabled;
}
GLboolean _glNearZClippingEnabled() {
return GPUState.znear_clipping_enabled;
} }
void _glApplyScissor(bool force); void _glApplyScissor(bool force);
static int _calc_pvr_face_culling() { static int _calc_pvr_face_culling() {
if(!CULLING_ENABLED) { if(!GPUState.culling_enabled) {
return GPU_CULLING_SMALL; return GPU_CULLING_SMALL;
} else { } else {
if(CULL_FACE == GL_BACK) { if(GPUState.cull_face == GL_BACK) {
return (FRONT_FACE == GL_CW) ? GPU_CULLING_CCW : GPU_CULLING_CW; return (GPUState.front_face == GL_CW) ? GPU_CULLING_CCW : GPU_CULLING_CW;
} else { } else {
return (FRONT_FACE == GL_CCW) ? GPU_CULLING_CCW : GPU_CULLING_CW; return (GPUState.front_face == GL_CCW) ? GPU_CULLING_CCW : GPU_CULLING_CW;
} }
} }
} }
static GLenum DEPTH_FUNC = GL_LESS;
static GLboolean DEPTH_TEST_ENABLED = GL_FALSE;
static int _calc_pvr_depth_test() { static int _calc_pvr_depth_test() {
if(!DEPTH_TEST_ENABLED) { if(!GPUState.depth_test_enabled) {
return GPU_DEPTHCMP_ALWAYS; return GPU_DEPTHCMP_ALWAYS;
} }
switch(DEPTH_FUNC) { switch(GPUState.depth_func) {
case GL_NEVER: case GL_NEVER:
return GPU_DEPTHCMP_NEVER; return GPU_DEPTHCMP_NEVER;
case GL_LESS: case GL_LESS:
@ -89,15 +201,9 @@ static int _calc_pvr_depth_test() {
} }
} }
static GLenum BLEND_SFACTOR = GL_ONE;
static GLenum BLEND_DFACTOR = GL_ZERO;
GLboolean BLEND_ENABLED = GL_FALSE;
static GLfloat OFFSET_FACTOR = 0.0f;
static GLfloat OFFSET_UNITS = 0.0f;
GLboolean _glIsNormalizeEnabled() { GLboolean _glIsNormalizeEnabled() {
return NORMALIZE_ENABLED; return GPUState.normalize_enabled;
} }
static int _calcPVRBlendFactor(GLenum factor) { static int _calcPVRBlendFactor(GLenum factor) {
@ -125,14 +231,14 @@ static int _calcPVRBlendFactor(GLenum factor) {
} }
static void _updatePVRBlend(PolyContext* context) { static void _updatePVRBlend(PolyContext* context) {
if(BLEND_ENABLED || ALPHA_TEST_ENABLED) { if(GPUState.blend_enabled || GPUState.alpha_test_enabled) {
context->gen.alpha = GPU_ALPHA_ENABLE; context->gen.alpha = GPU_ALPHA_ENABLE;
} else { } else {
context->gen.alpha = GPU_ALPHA_DISABLE; context->gen.alpha = GPU_ALPHA_DISABLE;
} }
context->blend.src = _calcPVRBlendFactor(BLEND_SFACTOR); context->blend.src = _calcPVRBlendFactor(GPUState.blend_sfactor);
context->blend.dst = _calcPVRBlendFactor(BLEND_DFACTOR); context->blend.dst = _calcPVRBlendFactor(GPUState.blend_dfactor);
} }
GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) { GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) {
@ -167,7 +273,7 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
return; return;
} }
context->txr.alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? GPU_TXRALPHA_ENABLE : GPU_TXRALPHA_DISABLE; context->txr.alpha = (GPUState.blend_enabled || GPUState.alpha_test_enabled) ? GPU_TXRALPHA_ENABLE : GPU_TXRALPHA_DISABLE;
GLuint filter = GPU_FILTER_NEAREST; GLuint filter = GPU_FILTER_NEAREST;
GLboolean enableMipmaps = GL_FALSE; GLboolean enableMipmaps = GL_FALSE;
@ -262,11 +368,11 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) {
} }
GLboolean _glIsLightingEnabled() { GLboolean _glIsLightingEnabled() {
return LIGHTING_ENABLED; return GPUState.lighting_enabled;
} }
GLboolean _glIsColorMaterialEnabled() { GLboolean _glIsColorMaterialEnabled() {
return COLOR_MATERIAL_ENABLED; return GPUState.color_material_enabled;
} }
static GLfloat CLEAR_COLOUR[3]; static GLfloat CLEAR_COLOUR[3];
@ -281,10 +387,10 @@ void _glInitContext() {
const VideoMode* mode = GetVideoMode(); const VideoMode* mode = GetVideoMode();
SCISSOR_RECT.x = 0; GPUState.scissor_rect.x = 0;
SCISSOR_RECT.y = 0; GPUState.scissor_rect.y = 0;
SCISSOR_RECT.width = mode->width; GPUState.scissor_rect.width = mode->width;
SCISSOR_RECT.height = mode->height; GPUState.scissor_rect.height = mode->height;
glClearDepth(1.0f); glClearDepth(1.0f);
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS);
@ -310,20 +416,24 @@ void _glInitContext() {
} }
GLAPI void APIENTRY glEnable(GLenum cap) { GLAPI void APIENTRY glEnable(GLenum cap) {
GLboolean was_dirty = GPUState.is_dirty;
GPUState.is_dirty = GL_TRUE;
switch(cap) { switch(cap) {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_TRUE; TEXTURES_ENABLED[_glGetActiveTexture()] = GL_TRUE;
break; break;
case GL_CULL_FACE: { case GL_CULL_FACE: {
CULLING_ENABLED = GL_TRUE; GPUState.cull_face = GL_TRUE;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
} break; } break;
case GL_DEPTH_TEST: { case GL_DEPTH_TEST: {
DEPTH_TEST_ENABLED = GL_TRUE; GPUState.depth_test_enabled = GL_TRUE;
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
} break; } break;
case GL_BLEND: { case GL_BLEND: {
BLEND_ENABLED = GL_TRUE; GPUState.blend_enabled = GL_TRUE;
_updatePVRBlend(&GL_CONTEXT); _updatePVRBlend(&GL_CONTEXT);
} break; } break;
case GL_SCISSOR_TEST: { case GL_SCISSOR_TEST: {
@ -331,20 +441,20 @@ GLAPI void APIENTRY glEnable(GLenum cap) {
_glApplyScissor(false); _glApplyScissor(false);
} break; } break;
case GL_LIGHTING: { case GL_LIGHTING: {
LIGHTING_ENABLED = GL_TRUE; GPUState.lighting_enabled = GL_TRUE;
} break; } break;
case GL_FOG: case GL_FOG:
GL_CONTEXT.gen.fog_type = GPU_FOG_TABLE; GL_CONTEXT.gen.fog_type = GPU_FOG_TABLE;
break; break;
case GL_COLOR_MATERIAL: case GL_COLOR_MATERIAL:
COLOR_MATERIAL_ENABLED = GL_TRUE; GPUState.color_material_enabled = GL_TRUE;
break; break;
case GL_SHARED_TEXTURE_PALETTE_EXT: { case GL_SHARED_TEXTURE_PALETTE_EXT: {
SHARED_PALETTE_ENABLED = GL_TRUE; GPUState.shared_palette_enabled = GL_TRUE;
} }
break; break;
case GL_ALPHA_TEST: { case GL_ALPHA_TEST: {
ALPHA_TEST_ENABLED = GL_TRUE; GPUState.alpha_test_enabled = GL_TRUE;
_updatePVRBlend(&GL_CONTEXT); _updatePVRBlend(&GL_CONTEXT);
} break; } break;
case GL_LIGHT0: case GL_LIGHT0:
@ -355,59 +465,64 @@ GLAPI void APIENTRY glEnable(GLenum cap) {
case GL_LIGHT5: case GL_LIGHT5:
case GL_LIGHT6: case GL_LIGHT6:
case GL_LIGHT7: case GL_LIGHT7:
_glEnableLight(cap & 0xF, GL_TRUE); _glLightAt(cap & 0xF)->isEnabled = GL_TRUE;
_glRecalcEnabledLights();
break; break;
case GL_NEARZ_CLIPPING_KOS: case GL_NEARZ_CLIPPING_KOS:
ZNEAR_CLIPPING_ENABLED = GL_TRUE; GPUState.znear_clipping_enabled = GL_TRUE;
break; break;
case GL_POLYGON_OFFSET_POINT: case GL_POLYGON_OFFSET_POINT:
case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_LINE:
case GL_POLYGON_OFFSET_FILL: case GL_POLYGON_OFFSET_FILL:
POLYGON_OFFSET_ENABLED = GL_TRUE; GPUState.polygon_offset_enabled = GL_TRUE;
break; break;
case GL_NORMALIZE: case GL_NORMALIZE:
NORMALIZE_ENABLED = GL_TRUE; GPUState.normalize_enabled = GL_TRUE;
break; break;
default: default:
GPUState.is_dirty = was_dirty;
break; break;
} }
} }
GLAPI void APIENTRY glDisable(GLenum cap) { GLAPI void APIENTRY glDisable(GLenum cap) {
GLboolean was_dirty = GPUState.is_dirty;
GPUState.is_dirty = GL_TRUE;
switch(cap) { switch(cap) {
case GL_TEXTURE_2D: { case GL_TEXTURE_2D: {
TEXTURES_ENABLED[_glGetActiveTexture()] = GL_FALSE; TEXTURES_ENABLED[_glGetActiveTexture()] = GL_FALSE;
} break; } break;
case GL_CULL_FACE: { case GL_CULL_FACE: {
CULLING_ENABLED = GL_FALSE; GPUState.culling_enabled = GL_FALSE;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
} break; } break;
case GL_DEPTH_TEST: { case GL_DEPTH_TEST: {
DEPTH_TEST_ENABLED = GL_FALSE; GPUState.depth_test_enabled = GL_FALSE;
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
} break; } break;
case GL_BLEND: case GL_BLEND:
BLEND_ENABLED = GL_FALSE; GPUState.blend_enabled = GL_FALSE;
_updatePVRBlend(&GL_CONTEXT); _updatePVRBlend(&GL_CONTEXT);
break; break;
case GL_SCISSOR_TEST: { case GL_SCISSOR_TEST: {
GL_CONTEXT.gen.clip_mode = GPU_USERCLIP_DISABLE; GL_CONTEXT.gen.clip_mode = GPU_USERCLIP_DISABLE;
} break; } break;
case GL_LIGHTING: { case GL_LIGHTING: {
LIGHTING_ENABLED = GL_FALSE; GPUState.lighting_enabled = GL_FALSE;
} break; } break;
case GL_FOG: case GL_FOG:
GL_CONTEXT.gen.fog_type = GPU_FOG_DISABLE; GL_CONTEXT.gen.fog_type = GPU_FOG_DISABLE;
break; break;
case GL_COLOR_MATERIAL: case GL_COLOR_MATERIAL:
COLOR_MATERIAL_ENABLED = GL_FALSE; GPUState.color_material_enabled = GL_FALSE;
break; break;
case GL_SHARED_TEXTURE_PALETTE_EXT: { case GL_SHARED_TEXTURE_PALETTE_EXT: {
SHARED_PALETTE_ENABLED = GL_FALSE; GPUState.shared_palette_enabled = GL_FALSE;
} }
break; break;
case GL_ALPHA_TEST: { case GL_ALPHA_TEST: {
ALPHA_TEST_ENABLED = GL_FALSE; GPUState.alpha_test_enabled = GL_FALSE;
} break; } break;
case GL_LIGHT0: case GL_LIGHT0:
case GL_LIGHT1: case GL_LIGHT1:
@ -420,17 +535,18 @@ GLAPI void APIENTRY glDisable(GLenum cap) {
_glEnableLight(cap & 0xF, GL_FALSE); _glEnableLight(cap & 0xF, GL_FALSE);
break; break;
case GL_NEARZ_CLIPPING_KOS: case GL_NEARZ_CLIPPING_KOS:
ZNEAR_CLIPPING_ENABLED = GL_FALSE; GPUState.znear_clipping_enabled = GL_FALSE;
break; break;
case GL_POLYGON_OFFSET_POINT: case GL_POLYGON_OFFSET_POINT:
case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_LINE:
case GL_POLYGON_OFFSET_FILL: case GL_POLYGON_OFFSET_FILL:
POLYGON_OFFSET_ENABLED = GL_FALSE; GPUState.polygon_offset_enabled = GL_FALSE;
break; break;
case GL_NORMALIZE: case GL_NORMALIZE:
NORMALIZE_ENABLED = GL_FALSE; GPUState.normalize_enabled = GL_FALSE;
break; break;
default: default:
GPUState.is_dirty = was_dirty;
break; break;
} }
} }
@ -481,7 +597,8 @@ GLAPI void APIENTRY glDepthMask(GLboolean flag) {
} }
GLAPI void APIENTRY glDepthFunc(GLenum func) { GLAPI void APIENTRY glDepthFunc(GLenum func) {
DEPTH_FUNC = func; GPUState.depth_func = func;
GPUState.is_dirty = GL_TRUE;
GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); GL_CONTEXT.depth.comparison = _calc_pvr_depth_test();
} }
@ -502,12 +619,14 @@ GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode) {
/* Culling */ /* Culling */
GLAPI void APIENTRY glFrontFace(GLenum mode) { GLAPI void APIENTRY glFrontFace(GLenum mode) {
FRONT_FACE = mode; GPUState.front_face = mode;
GPUState.is_dirty = GL_TRUE;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
} }
GLAPI void APIENTRY glCullFace(GLenum mode) { GLAPI void APIENTRY glCullFace(GLenum mode) {
CULL_FACE = mode; GPUState.cull_face = mode;
GPUState.is_dirty = GL_TRUE;
GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); GL_CONTEXT.gen.culling = _calc_pvr_face_culling();
} }
@ -522,8 +641,9 @@ GLAPI void APIENTRY glShadeModel(GLenum mode) {
/* Blending */ /* Blending */
GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) { GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) {
BLEND_SFACTOR = sfactor; GPUState.blend_sfactor = sfactor;
BLEND_DFACTOR = dfactor; GPUState.blend_dfactor = dfactor;
GPUState.is_dirty = GL_TRUE;
_updatePVRBlend(&GL_CONTEXT); _updatePVRBlend(&GL_CONTEXT);
} }
@ -547,8 +667,9 @@ void glLineWidth(GLfloat width) {
} }
void glPolygonOffset(GLfloat factor, GLfloat units) { void glPolygonOffset(GLfloat factor, GLfloat units) {
OFFSET_FACTOR = factor; GPUState.offset_factor = factor;
OFFSET_UNITS = units; GPUState.offset_units = units;
GPUState.is_dirty = GL_TRUE;
} }
void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) { void glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {
@ -577,18 +698,20 @@ void glPixelStorei(GLenum pname, GLint param) {
void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
if(SCISSOR_RECT.x == x &&
SCISSOR_RECT.y == y && if(GPUState.scissor_rect.x == x &&
SCISSOR_RECT.width == width && GPUState.scissor_rect.y == y &&
SCISSOR_RECT.height == height) { GPUState.scissor_rect.width == width &&
GPUState.scissor_rect.height == height) {
return; return;
} }
SCISSOR_RECT.x = x; GPUState.scissor_rect.x = x;
SCISSOR_RECT.y = y; GPUState.scissor_rect.y = y;
SCISSOR_RECT.width = width; GPUState.scissor_rect.width = width;
SCISSOR_RECT.height = height; GPUState.scissor_rect.height = height;
SCISSOR_RECT.applied = false; GPUState.scissor_rect.applied = false;
GPUState.is_dirty = GL_TRUE; // FIXME: do we need this?
_glApplyScissor(false); _glApplyScissor(false);
} }
@ -623,7 +746,7 @@ void _glApplyScissor(bool force) {
} }
/* Don't apply if we already applied - nothing changed */ /* Don't apply if we already applied - nothing changed */
if(SCISSOR_RECT.applied && !force) { if(GPUState.scissor_rect.applied && !force) {
return; return;
} }
@ -633,27 +756,31 @@ void _glApplyScissor(bool force) {
const VideoMode* vid_mode = GetVideoMode(); const VideoMode* vid_mode = GetVideoMode();
GLsizei scissor_width = MAX(MIN(SCISSOR_RECT.width, vid_mode->width), 0); GLsizei scissor_width = MAX(MIN(GPUState.scissor_rect.width, vid_mode->width), 0);
GLsizei scissor_height = MAX(MIN(SCISSOR_RECT.height, vid_mode->height), 0); GLsizei scissor_height = MAX(MIN(GPUState.scissor_rect.height, vid_mode->height), 0);
/* force the origin to the lower left-hand corner of the screen */ /* force the origin to the lower left-hand corner of the screen */
miny = (vid_mode->height - scissor_height) - SCISSOR_RECT.y; miny = (vid_mode->height - scissor_height) - GPUState.scissor_rect.y;
maxx = (scissor_width + SCISSOR_RECT.x); maxx = (scissor_width + GPUState.scissor_rect.x);
maxy = (scissor_height + miny); maxy = (scissor_height + miny);
/* load command structure while mapping screen coords to TA tiles */ /* load command structure while mapping screen coords to TA tiles */
c.flags = GPU_CMD_USERCLIP; c.flags = GPU_CMD_USERCLIP;
c.d1 = c.d2 = c.d3 = 0; c.d1 = c.d2 = c.d3 = 0;
c.sx = CLAMP(SCISSOR_RECT.x / 32, 0, vid_mode->width / 32);
c.sy = CLAMP(miny / 32, 0, vid_mode->height / 32); uint16_t vw = vid_mode->width >> 5;
c.ex = CLAMP((maxx / 32) - 1, 0, vid_mode->width / 32); uint16_t vh = vid_mode->height >> 5;
c.ey = CLAMP((maxy / 32) - 1, 0, vid_mode->height / 32);
c.sx = CLAMP(GPUState.scissor_rect.x >> 5, 0, vw);
c.sy = CLAMP(miny >> 5, 0, vh);
c.ex = CLAMP((maxx >> 5) - 1, 0, vw);
c.ey = CLAMP((maxy >> 5) - 1, 0, vh);
aligned_vector_push_back(&_glOpaquePolyList()->vector, &c, 1); aligned_vector_push_back(&_glOpaquePolyList()->vector, &c, 1);
aligned_vector_push_back(&_glPunchThruPolyList()->vector, &c, 1); aligned_vector_push_back(&_glPunchThruPolyList()->vector, &c, 1);
aligned_vector_push_back(&_glTransparentPolyList()->vector, &c, 1); aligned_vector_push_back(&_glTransparentPolyList()->vector, &c, 1);
SCISSOR_RECT.applied = true; GPUState.scissor_rect.applied = true;
} }
void glStencilFunc(GLenum func, GLint ref, GLuint mask) { void glStencilFunc(GLenum func, GLint ref, GLuint mask) {
@ -671,19 +798,19 @@ void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) {
GLboolean APIENTRY glIsEnabled(GLenum cap) { GLboolean APIENTRY glIsEnabled(GLenum cap) {
switch(cap) { switch(cap) {
case GL_DEPTH_TEST: case GL_DEPTH_TEST:
return DEPTH_TEST_ENABLED; return GPUState.depth_test_enabled;
case GL_SCISSOR_TEST: case GL_SCISSOR_TEST:
return GL_CONTEXT.gen.clip_mode == GPU_USERCLIP_INSIDE; return GL_CONTEXT.gen.clip_mode == GPU_USERCLIP_INSIDE;
case GL_CULL_FACE: case GL_CULL_FACE:
return CULLING_ENABLED; return GPUState.culling_enabled;
case GL_LIGHTING: case GL_LIGHTING:
return LIGHTING_ENABLED; return GPUState.lighting_enabled;
case GL_BLEND: case GL_BLEND:
return BLEND_ENABLED; return GPUState.blend_enabled;
case GL_POLYGON_OFFSET_POINT: case GL_POLYGON_OFFSET_POINT:
case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_LINE:
case GL_POLYGON_OFFSET_FILL: case GL_POLYGON_OFFSET_FILL:
return POLYGON_OFFSET_ENABLED; return GPUState.polygon_offset_enabled;
} }
return GL_FALSE; return GL_FALSE;
@ -738,10 +865,10 @@ void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) {
MEMCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16); MEMCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16);
break; break;
case GL_POLYGON_OFFSET_FACTOR: case GL_POLYGON_OFFSET_FACTOR:
*params = OFFSET_FACTOR; *params = GPUState.offset_factor;
break; break;
case GL_POLYGON_OFFSET_UNITS: case GL_POLYGON_OFFSET_UNITS:
*params = OFFSET_UNITS; *params = GPUState.offset_units;
break; break;
default: default:
_glKosThrowError(GL_INVALID_ENUM, __func__); _glKosThrowError(GL_INVALID_ENUM, __func__);
@ -758,13 +885,13 @@ void APIENTRY glGetIntegerv(GLenum pname, GLint *params) {
*params = (_glGetBoundTexture()) ? _glGetBoundTexture()->index : 0; *params = (_glGetBoundTexture()) ? _glGetBoundTexture()->index : 0;
break; break;
case GL_DEPTH_FUNC: case GL_DEPTH_FUNC:
*params = DEPTH_FUNC; *params = GPUState.depth_func;
break; break;
case GL_BLEND_SRC: case GL_BLEND_SRC:
*params = BLEND_SFACTOR; *params = GPUState.blend_sfactor;
break; break;
case GL_BLEND_DST: case GL_BLEND_DST:
*params = BLEND_DFACTOR; *params = GPUState.blend_dfactor;
break; break;
case GL_MAX_TEXTURE_SIZE: case GL_MAX_TEXTURE_SIZE:
*params = MAX_TEXTURE_SIZE; *params = MAX_TEXTURE_SIZE;