diff --git a/GL/draw.c b/GL/draw.c index 9b0bfd0..be58241 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -13,9 +13,12 @@ GLuint ENABLED_VERTEX_ATTRIBUTES = 0; GLuint FAST_PATH_ENABLED = GL_FALSE; static GLubyte ACTIVE_CLIENT_TEXTURE = 0; +static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; extern inline GLuint _glRecalcFastPath(); +extern GLboolean AUTOSORT_ENABLED; + #define ITERATE(count) \ GLuint i = count; \ while(i--) @@ -116,8 +119,6 @@ static void _readVertexData3ui3f(const GLubyte* in, 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; 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) { - const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; - float* output = (float*) out; 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) { - const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; float* output = (float*) out; 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 * vertices straight to clip-space */ - if(LIGHTING_ENABLED) { + if(_glIsLightingEnabled()) { _glMatrixLoadModelView(); } else { _glMatrixLoadModelViewProjection(); @@ -1152,7 +1150,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL transform(target); } - if(LIGHTING_ENABLED){ + if(_glIsLightingEnabled()){ light(target); /* OK eye-space work done, now move into clip space */ diff --git a/GL/lighting.c b/GL/lighting.c index 8218228..c63defd 100644 --- a/GL/lighting.c +++ b/GL/lighting.c @@ -12,126 +12,107 @@ * multiplier ends up less than this value */ #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; - -#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) { +void _glPrecalcLightingValues(GLuint mask) { /* Pre-calculate lighting values */ GLshort i; + Material* material = _glActiveMaterial(); + if(mask & AMBIENT_MASK) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { - LIGHTS[i].ambientMaterial[0] = LIGHTS[i].ambient[0] * MATERIAL.ambient[0]; - LIGHTS[i].ambientMaterial[1] = LIGHTS[i].ambient[1] * MATERIAL.ambient[1]; - LIGHTS[i].ambientMaterial[2] = LIGHTS[i].ambient[2] * MATERIAL.ambient[2]; - LIGHTS[i].ambientMaterial[3] = LIGHTS[i].ambient[3] * MATERIAL.ambient[3]; + LightSource* light = _glLightAt(i); + + light->ambientMaterial[0] = light->ambient[0] * material->ambient[0]; + 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) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { - LIGHTS[i].diffuseMaterial[0] = LIGHTS[i].diffuse[0] * MATERIAL.diffuse[0]; - LIGHTS[i].diffuseMaterial[1] = LIGHTS[i].diffuse[1] * MATERIAL.diffuse[1]; - LIGHTS[i].diffuseMaterial[2] = LIGHTS[i].diffuse[2] * MATERIAL.diffuse[2]; - LIGHTS[i].diffuseMaterial[3] = LIGHTS[i].diffuse[3] * MATERIAL.diffuse[3]; + LightSource* light = _glLightAt(i); + + light->diffuseMaterial[0] = light->diffuse[0] * material->diffuse[0]; + 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) { for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { - LIGHTS[i].specularMaterial[0] = LIGHTS[i].specular[0] * MATERIAL.specular[0]; - LIGHTS[i].specularMaterial[1] = LIGHTS[i].specular[1] * MATERIAL.specular[1]; - LIGHTS[i].specularMaterial[2] = LIGHTS[i].specular[2] * MATERIAL.specular[2]; - LIGHTS[i].specularMaterial[3] = LIGHTS[i].specular[3] * MATERIAL.specular[3]; + LightSource* light = _glLightAt(i); + + light->specularMaterial[0] = light->specular[0] * material->specular[0]; + 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 * the base colour. */ 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]); - 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]); + GLfloat* scene_ambient = _glLightModelSceneAmbient(); + + material->baseColour[0] = MATH_fmac(scene_ambient[0], material->ambient[0], material->emissive[0]); + 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) { glLightModelfv(pname, ¶m); } @@ -143,11 +124,11 @@ void APIENTRY glLightModeli(GLenum pname, const GLint param) { void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) { switch(pname) { case GL_LIGHT_MODEL_AMBIENT: { - for(int i = 0; i < 4; ++i) SCENE_AMBIENT[i] = params[i]; + _glSetLightModelSceneAmbient(params); _glPrecalcLightingValues(SCENE_AMBIENT_MASK); } break; case GL_LIGHT_MODEL_LOCAL_VIEWER: - VIEWER_IN_EYE_COORDINATES = (*params) ? GL_TRUE : GL_FALSE; + _glSetLightModelViewerInEyeCoordinates((*params) ? GL_TRUE : GL_FALSE); break; case GL_LIGHT_MODEL_TWO_SIDE: /* Not implemented */ @@ -159,10 +140,10 @@ void APIENTRY glLightModelfv(GLenum pname, const GLfloat *params) { void APIENTRY glLightModeliv(GLenum pname, const GLint* params) { switch(pname) { case GL_LIGHT_MODEL_COLOR_CONTROL: - COLOR_CONTROL = *params; + _glSetLightModelColorControl(*params); break; case GL_LIGHT_MODEL_LOCAL_VIEWER: - VIEWER_IN_EYE_COORDINATES = (*params) ? GL_TRUE : GL_FALSE; + _glSetLightModelViewerInEyeCoordinates((*params) ? GL_TRUE : GL_FALSE); break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); @@ -173,6 +154,7 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) { GLubyte idx = light & 0xF; if(idx >= MAX_GLDC_LIGHTS) { + _glKosThrowError(GL_INVALID_VALUE, __func__); return; } @@ -180,33 +162,35 @@ void APIENTRY glLightfv(GLenum light, GLenum pname, const GLfloat *params) { (pname == GL_DIFFUSE) ? DIFFUSE_MASK : (pname == GL_SPECULAR) ? SPECULAR_MASK : 0; + LightSource* l = _glLightAt(idx); + switch(pname) { case GL_AMBIENT: - memcpy(LIGHTS[idx].ambient, params, sizeof(GLfloat) * 4); + memcpy(l->ambient, params, sizeof(GLfloat) * 4); break; case GL_DIFFUSE: - memcpy(LIGHTS[idx].diffuse, params, sizeof(GLfloat) * 4); + memcpy(l->diffuse, params, sizeof(GLfloat) * 4); break; case GL_SPECULAR: - memcpy(LIGHTS[idx].specular, params, sizeof(GLfloat) * 4); + memcpy(l->specular, params, sizeof(GLfloat) * 4); break; case GL_POSITION: { _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? } else { - TransformVec3(LIGHTS[idx].position); + TransformVec3(l->position); } } break; case GL_SPOT_DIRECTION: { - LIGHTS[idx].spot_direction[0] = params[0]; - LIGHTS[idx].spot_direction[1] = params[1]; - LIGHTS[idx].spot_direction[2] = params[2]; + l->spot_direction[0] = params[0]; + l->spot_direction[1] = params[1]; + l->spot_direction[2] = params[2]; } break; case GL_CONSTANT_ATTENUATION: case GL_LINEAR_ATTENUATION: @@ -227,24 +211,26 @@ void APIENTRY glLightf(GLenum light, GLenum pname, GLfloat param) { GLubyte idx = light & 0xF; if(idx >= MAX_GLDC_LIGHTS) { + _glKosThrowError(GL_INVALID_VALUE, __func__); return; } + LightSource* l = _glLightAt(idx); switch(pname) { case GL_CONSTANT_ATTENUATION: - LIGHTS[idx].constant_attenuation = param; + l->constant_attenuation = param; break; case GL_LINEAR_ATTENUATION: - LIGHTS[idx].linear_attenuation = param; + l->linear_attenuation = param; break; case GL_QUADRATIC_ATTENUATION: - LIGHTS[idx].quadratic_attenuation = param; + l->quadratic_attenuation = param; break; case GL_SPOT_EXPONENT: - LIGHTS[idx].spot_exponent = param; + l->spot_exponent = param; break; case GL_SPOT_CUTOFF: - LIGHTS[idx].spot_cutoff = param; + l->spot_cutoff = param; break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); @@ -257,7 +243,7 @@ void APIENTRY glMaterialf(GLenum face, GLenum pname, const GLfloat param) { 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) { @@ -270,25 +256,27 @@ void APIENTRY glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { return; } + Material* material = _glActiveMaterial(); + switch(pname) { case GL_SHININESS: glMaterialf(face, pname, *params); break; case GL_AMBIENT: - vec4cpy(MATERIAL.ambient, params); + vec4cpy(material->ambient, params); break; case GL_DIFFUSE: - vec4cpy(MATERIAL.diffuse, params); + vec4cpy(material->diffuse, params); break; case GL_SPECULAR: - vec4cpy(MATERIAL.specular, params); + vec4cpy(material->specular, params); break; case GL_EMISSION: - vec4cpy(MATERIAL.emissive, params); + vec4cpy(material->emissive, params); break; case GL_AMBIENT_AND_DIFFUSE: { - vec4cpy(MATERIAL.ambient, params); - vec4cpy(MATERIAL.diffuse, params); + vec4cpy(material->ambient, params); + vec4cpy(material->diffuse, params); } break; case GL_COLOR_INDEXES: default: { @@ -318,12 +306,13 @@ void APIENTRY glColorMaterial(GLenum face, GLenum mode) { return; } - COLOR_MATERIAL_MASK = (mode == GL_AMBIENT) ? AMBIENT_MASK: + GLenum mask = (mode == GL_AMBIENT) ? AMBIENT_MASK: (mode == GL_DIFFUSE) ? DIFFUSE_MASK: (mode == GL_AMBIENT_AND_DIFFUSE) ? AMBIENT_MASK | DIFFUSE_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) { @@ -336,44 +325,68 @@ GL_FORCE_INLINE void bgra_to_float(const uint8_t* input, GLfloat* output) { } void _glUpdateColourMaterialA(const GLubyte* argb) { + Material* material = _glActiveMaterial(); + float colour[4]; bgra_to_float(argb, colour); - vec4cpy(MATERIAL.ambient, colour); - _glPrecalcLightingValues(COLOR_MATERIAL_MASK); + vec4cpy(material->ambient, colour); + GLenum mask = _glColorMaterialMode(); + _glPrecalcLightingValues(mask); } void _glUpdateColourMaterialD(const GLubyte* argb) { + Material* material = _glActiveMaterial(); + float colour[4]; bgra_to_float(argb, colour); - vec4cpy(MATERIAL.diffuse, colour); - _glPrecalcLightingValues(COLOR_MATERIAL_MASK); + vec4cpy(material->diffuse, colour); + + GLenum mask = _glColorMaterialMode(); + _glPrecalcLightingValues(mask); } void _glUpdateColourMaterialE(const GLubyte* argb) { + Material* material = _glActiveMaterial(); + float colour[4]; bgra_to_float(argb, colour); - vec4cpy(MATERIAL.emissive, colour); - _glPrecalcLightingValues(COLOR_MATERIAL_MASK); + vec4cpy(material->emissive, colour); + + GLenum mask = _glColorMaterialMode(); + _glPrecalcLightingValues(mask); } void _glUpdateColourMaterialAD(const GLubyte* argb) { + Material* material = _glActiveMaterial(); + float colour[4]; bgra_to_float(argb, colour); - vec4cpy(MATERIAL.ambient, colour); - vec4cpy(MATERIAL.diffuse, colour); - _glPrecalcLightingValues(COLOR_MATERIAL_MASK); + vec4cpy(material->ambient, colour); + vec4cpy(material->diffuse, colour); + + GLenum mask = _glColorMaterialMode(); + _glPrecalcLightingValues(mask); } 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() { - 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() { - 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 LdotN, float NdotH) { - float FI = (MATERIAL.exponent) ? - faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f; + Material* material = _glActiveMaterial(); + LightSource* light = _glLightAt(lid); + + float FI = (material->exponent) ? + faster_pow((LdotN != 0.0f) * NdotH, material->exponent) : 1.0f; #define _PROCESS_COMPONENT(X) \ - final[X] += (LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \ - + (FI * LIGHTS[lid].specularMaterial[X]); \ + final[X] += (LdotN * light->diffuseMaterial[X] + light->ambientMaterial[X]) \ + + (FI * light->specularMaterial[X]); \ _PROCESS_COMPONENT(0); _PROCESS_COMPONENT(1); @@ -426,12 +442,15 @@ GL_FORCE_INLINE void _glLightVertexPoint( float* final, uint8_t lid, float LdotN, float NdotH, float att) { - float FI = (MATERIAL.exponent) ? - faster_pow((LdotN != 0.0f) * NdotH, MATERIAL.exponent) : 1.0f; + Material* material = _glActiveMaterial(); + LightSource* light = _glLightAt(lid); + + float FI = (material->exponent) ? + faster_pow((LdotN != 0.0f) * NdotH, material->exponent) : 1.0f; #define _PROCESS_COMPONENT(X) \ - final[X] += ((LdotN * LIGHTS[lid].diffuseMaterial[X] + LIGHTS[lid].ambientMaterial[X]) \ - + (FI * LIGHTS[lid].specularMaterial[X])) * att; \ + final[X] += ((LdotN * light->diffuseMaterial[X] + light->ambientMaterial[X]) \ + + (FI * light->specularMaterial[X])) * att; \ _PROCESS_COMPONENT(0); _PROCESS_COMPONENT(1); @@ -444,6 +463,8 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count GLubyte i; GLuint j; + Material* material = _glActiveMaterial(); + Vertex* vertex = vertices; EyeSpaceData* data = es; @@ -451,7 +472,8 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count void (*updateColourMaterial)(const GLubyte*) = NULL; if(_glIsColorMaterialEnabled()) { - switch(COLOR_MATERIAL_MODE) { + GLenum mode = _glColorMaterialMode(); + switch(mode) { case GL_AMBIENT: updateColourMaterial = _glUpdateColourMaterialA; break; @@ -474,10 +496,10 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count } /* Copy the base colour across */ - vec4cpy(data->finalColour, MATERIAL.baseColour); + vec4cpy(data->finalColour, material->baseColour); } - if(!ENABLED_LIGHT_COUNT) { + if(!_glEnabledLightCount()) { return; } @@ -495,15 +517,17 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count const float Nz = data->n[2]; for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { - if(!LIGHTS[i].isEnabled) { + LightSource* light = _glLightAt(i); + + if(!light->isEnabled) { continue; } - float Lx = LIGHTS[i].position[0] - vertex->xyz[0]; - float Ly = LIGHTS[i].position[1] - vertex->xyz[1]; - float Lz = LIGHTS[i].position[2] - vertex->xyz[2]; + float Lx = light->position[0] - vertex->xyz[0]; + float Ly = light->position[1] - vertex->xyz[1]; + float Lz = light->position[2] - vertex->xyz[2]; - if(LIGHTS[i].isDirectional) { + if(light->isDirectional) { float Hx = (Lx + 0); float Hy = (Ly + 0); float Hz = (Lz + 1); @@ -532,9 +556,9 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count VEC3_LENGTH(Lx, Ly, Lz, D); float att = ( - LIGHTS[i].constant_attenuation + ( - LIGHTS[i].linear_attenuation * D - ) + (LIGHTS[i].quadratic_attenuation * D * D) + light->constant_attenuation + ( + light->linear_attenuation * D + ) + (light->quadratic_attenuation * D * D) ); /* Anything over the attenuation threshold will diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 78e1772..da16cce 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -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; } -static uint32_t *d; // SQ target - -GL_FORCE_INLINE void _glSubmitHeaderOrVertex(const Vertex* v) { +GL_FORCE_INLINE void _glSubmitHeaderOrVertex(uint32_t* d, const Vertex* v) { #ifndef NDEBUG gl_assert(!isnan(v->xyz[2])); 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) { + static const float E [] = { + 0.00001f, -0.00001f + }; + /* Clipping time! */ const float d0 = v1->w + v1->xyz[2]; const float d1 = v2->w + v2->xyz[2]; - - const float epsilon = (d0 < d1) ? -0.00001f : 0.00001f; + const float epsilon = E[d0 < d1]; float t = MATH_Fast_Divide(d0, (d0 - d1)) + epsilon; @@ -182,28 +183,27 @@ GL_FORCE_INLINE void ShiftRotateTriangle() { #define SPAN_SORT_CFG 0x005F8030 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); - /* Prep store queues */ - d = (uint32_t*) SQ_BASE_ADDRESS; - + uint32_t *d = (uint32_t*) SQ_BASE_ADDRESS; *PVR_LMMODE0 = 0x0; /* Enable 64bit mode */ + Vertex __attribute__((aligned(32))) tmp; + /* Perform perspective divide on each vertex */ 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) { PREFETCH(vertex + 1); if(glIsVertex(vertex->flags)) { _glPerspectiveDivideVertex(vertex, h); } - _glSubmitHeaderOrVertex(vertex); + _glSubmitHeaderOrVertex(d, vertex); } /* Wait for both store queues to complete */ @@ -221,25 +221,22 @@ void SceneListSubmit(void* src, int n) { #endif for(int i = 0; i < n; ++i, ++vertex) { - PREFETCH(vertex + 1); - - bool is_last_in_strip = glIsLastVertex(vertex->flags); + PREFETCH(vertex + 12); /* Wait until we fill the triangle */ if(tri_count < 3) { - if(likely(glIsVertex(vertex->flags))) { + if(glIsVertex(vertex->flags)) { + ++strip_count; triangle[tri_count].v = vertex; triangle[tri_count].visible = vertex->xyz[2] >= -vertex->w; - tri_count++; - strip_count++; + if(++tri_count < 3) { + continue; + } } else { /* We hit a header */ tri_count = 0; strip_count = 0; - _glSubmitHeaderOrVertex(vertex); - } - - if(tri_count < 3) { + _glSubmitHeaderOrVertex(d, vertex); continue; } } @@ -250,199 +247,189 @@ void SceneListSubmit(void* src, int n) { /* If we got here, then triangle contains 3 vertices */ 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; - } + /* Clipping time! - ShiftRotateTriangle(); + There are 6 distinct possibilities when clipping a triangle. 3 of them result + in another triangle, 3 of them result in a quadrilateral. - } else if(visible_mask) { - /* Clipping time! + Assuming you iterate the edges of the triangle in order, and create a new *visible* + vertex when you cross the plane, and discard vertices behind the plane, then the only + difference between the two cases is that the final two vertices that need submitting have + to be reversed. - There are 6 distinct possibilities when clipping a triangle. 3 of them result - in another triangle, 3 of them result in a quadrilateral. + 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. + */ - Assuming you iterate the edges of the triangle in order, and create a new *visible* - vertex when you cross the plane, and discard vertices behind the plane, then the only - difference between the two cases is that the final two vertices that need submitting have - to be reversed. +#define SUBMIT_QUEUED() \ + if(strip_count > 3) { \ + tmp = *(vertex - 2); \ + /* 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); \ + } - 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. - */ -#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 */ + bool is_last_in_strip = glIsLastVertex(vertex->flags); + + switch(visible_mask) { + case 1: { + SUBMIT_QUEUED(); + /* 0, 0a, 2a */ + tmp = *triangle[0].v; + tmp.flags = GPU_CMD_VERTEX; _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glSubmitHeaderOrVertex(d, &tmp); - tmp = *(vertex - 1); + _glClipEdge(triangle[0].v, triangle[1].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); + + _glClipEdge(triangle[2].v, triangle[0].v, &tmp); tmp.flags = GPU_CMD_VERTEX_EOL; _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } + _glSubmitHeaderOrVertex(d, &tmp); + } break; + case 2: { + SUBMIT_QUEUED(); + /* 0a, 1, 1a */ + _glClipEdge(triangle[0].v, triangle[1].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - switch(visible_mask) { - case 1: { - /* 0, 0a, 2a */ - tmp = *triangle[0].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + tmp = *triangle[1].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[0].v, triangle[1].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[1].v, triangle[2].v, &tmp); + tmp.flags = GPU_CMD_VERTEX_EOL; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); + } break; + case 3: { + SUBMIT_QUEUED(); + /* 0, 1, 2a, 1a */ + tmp = *triangle[0].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[2].v, triangle[0].v, &tmp); - tmp.flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } break; - case 2: { - /* 0a, 1, 1a */ - _glClipEdge(triangle[0].v, triangle[1].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + tmp = *triangle[1].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - tmp = *triangle[1].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[2].v, triangle[0].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[1].v, triangle[2].v, &tmp); - tmp.flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } break; - case 3: { - /* 0, 1, 2a, 1a */ - tmp = *triangle[0].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[1].v, triangle[2].v, &tmp); + tmp.flags = GPU_CMD_VERTEX_EOL; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); + } break; + case 4: { + SUBMIT_QUEUED(); + /* 1a, 2, 2a */ + _glClipEdge(triangle[1].v, triangle[2].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - tmp = *triangle[1].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + tmp = *triangle[2].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[2].v, triangle[0].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[2].v, triangle[0].v, &tmp); + tmp.flags = GPU_CMD_VERTEX_EOL; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); + } break; + case 5: { + SUBMIT_QUEUED(); + /* 0, 0a, 2, 1a */ + tmp = *triangle[0].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[1].v, triangle[2].v, &tmp); - tmp.flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } break; - case 4: { - /* 1a, 2, 2a */ - _glClipEdge(triangle[1].v, triangle[2].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[0].v, triangle[1].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - tmp = *triangle[2].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + tmp = *triangle[2].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[2].v, triangle[0].v, &tmp); - tmp.flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } break; - case 5: { - /* 0, 0a, 2, 1a */ - tmp = *triangle[0].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[1].v, triangle[2].v, &tmp); + tmp.flags = GPU_CMD_VERTEX_EOL; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); + } break; + case 6: { + SUBMIT_QUEUED(); + /* 0a, 1, 2a, 2 */ + _glClipEdge(triangle[0].v, triangle[1].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[0].v, triangle[1].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + tmp = *triangle[1].v; + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - tmp = *triangle[2].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + _glClipEdge(triangle[2].v, triangle[0].v, &tmp); + tmp.flags = GPU_CMD_VERTEX; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); - _glClipEdge(triangle[1].v, triangle[2].v, &tmp); - tmp.flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } break; - case 6: { - /* 0a, 1, 2a, 2 */ - _glClipEdge(triangle[0].v, triangle[1].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + tmp = *triangle[2].v; + tmp.flags = GPU_CMD_VERTEX_EOL; + _glPerspectiveDivideVertex(&tmp, h); + _glSubmitHeaderOrVertex(d, &tmp); + } break; + case 7: { + /* All the vertices are visible! We divide and submit v0, then shift */ + _glPerspectiveDivideVertex(vertex - 2, h); + _glSubmitHeaderOrVertex(d, vertex - 2); - tmp = *triangle[1].v; - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); + 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; + } - _glClipEdge(triangle[2].v, triangle[0].v, &tmp); - tmp.flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - - tmp = *triangle[2].v; - tmp.flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(&tmp, h); - _glSubmitHeaderOrVertex(&tmp); - } break; - default: - break; - } - - /* If this was the last in the strip, we don't need to - submit anything else, we just wipe the tri_count */ - if(is_last_in_strip) { - tri_count = 0; - strip_count = 0; - } else { ShiftRotateTriangle(); - strip_count = 2; - } - } else { - /* Invisible? Move to the next in the strip */ + continue; + } break; + case 0: + default: + break; + } - if(is_last_in_strip) { - tri_count = 0; - strip_count = 0; - } - strip_count = 2; + /* If this was the last in the strip, we don't need to + submit anything else, we just wipe the tri_count */ + if(is_last_in_strip) { + tri_count = 0; + strip_count = 0; + } else { ShiftRotateTriangle(); + strip_count = 2; } } diff --git a/GL/private.h b/GL/private.h index 9fa45cf..f728d05 100644 --- a/GL/private.h +++ b/GL/private.h @@ -354,26 +354,17 @@ void _glSetInternalPaletteFormat(GLenum val); GLboolean _glIsSharedTexturePaletteEnabled(); void _glApplyColorTable(TexturePalette *palette); -extern GLboolean BLEND_ENABLED; -extern GLboolean ALPHA_TEST_ENABLED; -extern GLboolean AUTOSORT_ENABLED; - -GL_FORCE_INLINE GLboolean _glIsBlendingEnabled() { - return BLEND_ENABLED; -} - -GL_FORCE_INLINE GLboolean _glIsAlphaTestEnabled() { - return ALPHA_TEST_ENABLED; -} +GLboolean _glIsBlendingEnabled(); +GLboolean _glIsAlphaTestEnabled(); extern PolyList OP_LIST; extern PolyList PT_LIST; extern PolyList TR_LIST; GL_FORCE_INLINE PolyList* _glActivePolyList() { - if(BLEND_ENABLED) { + if(_glIsBlendingEnabled()) { return &TR_LIST; - } else if(ALPHA_TEST_ENABLED) { + } else if(_glIsAlphaTestEnabled()) { return &PT_LIST; } else { return &OP_LIST; @@ -383,13 +374,9 @@ GL_FORCE_INLINE PolyList* _glActivePolyList() { GLboolean _glIsMipmapComplete(const TextureObject* obj); GLubyte* _glGetMipmapLocation(const TextureObject* obj, GLuint level); GLuint _glGetMipmapLevelCount(const TextureObject* obj); - -extern GLboolean ZNEAR_CLIPPING_ENABLED; - -extern GLboolean LIGHTING_ENABLED; GLboolean _glIsLightingEnabled(); -void _glEnableLight(GLubyte light, unsigned char value); +void _glEnableLight(GLubyte light, GLboolean value); GLboolean _glIsColorMaterialEnabled(); GLboolean _glIsNormalizeEnabled(); @@ -513,10 +500,30 @@ GLuint _glUsedTextureMemory(); GLuint _glFreeContiguousTextureMemory(); 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_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 */ #define PVR_MIN_Z 0.0001f diff --git a/GL/state.c b/GL/state.c index a302157..393aaec 100644 --- a/GL/state.c +++ b/GL/state.c @@ -10,64 +10,176 @@ PolyContext *_glGetPVRContext() { return &GL_CONTEXT; } + +static struct { + GLboolean is_dirty; + /* 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; -static GLboolean COLOR_MATERIAL_ENABLED = GL_FALSE; + GLenum depth_func; + GLboolean depth_test_enabled; + GLenum cull_face; + 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 { + GLint x; + GLint y; + GLsizei width; + GLsizei height; + GLboolean applied; + } scissor_rect; -GLboolean LIGHTING_ENABLED = GL_FALSE; + GLenum blend_sfactor; + GLenum blend_dfactor; + GLboolean blend_enabled; + GLfloat offset_factor; + GLfloat offset_units; -/* Is the shared texture palette enabled? */ -static GLboolean SHARED_PALETTE_ENABLED = GL_FALSE; + GLfloat scene_ambient[4]; + GLboolean viewer_in_eye_coords; + GLenum color_control; + GLenum color_material_mode; + GLenum color_material_mask; -GLboolean ALPHA_TEST_ENABLED = GL_FALSE; - -static GLboolean POLYGON_OFFSET_ENABLED = GL_FALSE; - -static GLboolean NORMALIZE_ENABLED = GL_FALSE; - -static struct { - GLint x; - GLint y; - GLsizei width; - GLsizei height; - GLboolean applied; -} SCISSOR_RECT = { - 0, 0, 640, 480, false + 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() { - return SHARED_PALETTE_ENABLED; + return GPUState.shared_palette_enabled; +} + +GLboolean _glNearZClippingEnabled() { + return GPUState.znear_clipping_enabled; } void _glApplyScissor(bool force); static int _calc_pvr_face_culling() { - if(!CULLING_ENABLED) { + if(!GPUState.culling_enabled) { return GPU_CULLING_SMALL; } else { - if(CULL_FACE == GL_BACK) { - return (FRONT_FACE == GL_CW) ? GPU_CULLING_CCW : GPU_CULLING_CW; + if(GPUState.cull_face == GL_BACK) { + return (GPUState.front_face == GL_CW) ? GPU_CULLING_CCW : GPU_CULLING_CW; } 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() { - if(!DEPTH_TEST_ENABLED) { + if(!GPUState.depth_test_enabled) { return GPU_DEPTHCMP_ALWAYS; } - switch(DEPTH_FUNC) { + switch(GPUState.depth_func) { case GL_NEVER: return GPU_DEPTHCMP_NEVER; 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() { - return NORMALIZE_ENABLED; + return GPUState.normalize_enabled; } static int _calcPVRBlendFactor(GLenum factor) { @@ -125,14 +231,14 @@ static int _calcPVRBlendFactor(GLenum factor) { } 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; } else { context->gen.alpha = GPU_ALPHA_DISABLE; } - context->blend.src = _calcPVRBlendFactor(BLEND_SFACTOR); - context->blend.dst = _calcPVRBlendFactor(BLEND_DFACTOR); + context->blend.src = _calcPVRBlendFactor(GPUState.blend_sfactor); + context->blend.dst = _calcPVRBlendFactor(GPUState.blend_dfactor); } GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func) { @@ -167,7 +273,7 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) { 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; GLboolean enableMipmaps = GL_FALSE; @@ -262,11 +368,11 @@ void _glUpdatePVRTextureContext(PolyContext *context, GLshort textureUnit) { } GLboolean _glIsLightingEnabled() { - return LIGHTING_ENABLED; + return GPUState.lighting_enabled; } GLboolean _glIsColorMaterialEnabled() { - return COLOR_MATERIAL_ENABLED; + return GPUState.color_material_enabled; } static GLfloat CLEAR_COLOUR[3]; @@ -281,10 +387,10 @@ void _glInitContext() { const VideoMode* mode = GetVideoMode(); - SCISSOR_RECT.x = 0; - SCISSOR_RECT.y = 0; - SCISSOR_RECT.width = mode->width; - SCISSOR_RECT.height = mode->height; + GPUState.scissor_rect.x = 0; + GPUState.scissor_rect.y = 0; + GPUState.scissor_rect.width = mode->width; + GPUState.scissor_rect.height = mode->height; glClearDepth(1.0f); glDepthFunc(GL_LESS); @@ -310,20 +416,24 @@ void _glInitContext() { } GLAPI void APIENTRY glEnable(GLenum cap) { + GLboolean was_dirty = GPUState.is_dirty; + + GPUState.is_dirty = GL_TRUE; + switch(cap) { case GL_TEXTURE_2D: TEXTURES_ENABLED[_glGetActiveTexture()] = GL_TRUE; break; case GL_CULL_FACE: { - CULLING_ENABLED = GL_TRUE; + GPUState.cull_face = GL_TRUE; GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); } break; case GL_DEPTH_TEST: { - DEPTH_TEST_ENABLED = GL_TRUE; + GPUState.depth_test_enabled = GL_TRUE; GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); } break; case GL_BLEND: { - BLEND_ENABLED = GL_TRUE; + GPUState.blend_enabled = GL_TRUE; _updatePVRBlend(&GL_CONTEXT); } break; case GL_SCISSOR_TEST: { @@ -331,20 +441,20 @@ GLAPI void APIENTRY glEnable(GLenum cap) { _glApplyScissor(false); } break; case GL_LIGHTING: { - LIGHTING_ENABLED = GL_TRUE; + GPUState.lighting_enabled = GL_TRUE; } break; case GL_FOG: GL_CONTEXT.gen.fog_type = GPU_FOG_TABLE; break; case GL_COLOR_MATERIAL: - COLOR_MATERIAL_ENABLED = GL_TRUE; + GPUState.color_material_enabled = GL_TRUE; break; case GL_SHARED_TEXTURE_PALETTE_EXT: { - SHARED_PALETTE_ENABLED = GL_TRUE; + GPUState.shared_palette_enabled = GL_TRUE; } break; case GL_ALPHA_TEST: { - ALPHA_TEST_ENABLED = GL_TRUE; + GPUState.alpha_test_enabled = GL_TRUE; _updatePVRBlend(&GL_CONTEXT); } break; case GL_LIGHT0: @@ -355,59 +465,64 @@ GLAPI void APIENTRY glEnable(GLenum cap) { case GL_LIGHT5: case GL_LIGHT6: case GL_LIGHT7: - _glEnableLight(cap & 0xF, GL_TRUE); + _glLightAt(cap & 0xF)->isEnabled = GL_TRUE; + _glRecalcEnabledLights(); break; case GL_NEARZ_CLIPPING_KOS: - ZNEAR_CLIPPING_ENABLED = GL_TRUE; + GPUState.znear_clipping_enabled = GL_TRUE; break; case GL_POLYGON_OFFSET_POINT: case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_FILL: - POLYGON_OFFSET_ENABLED = GL_TRUE; + GPUState.polygon_offset_enabled = GL_TRUE; break; case GL_NORMALIZE: - NORMALIZE_ENABLED = GL_TRUE; + GPUState.normalize_enabled = GL_TRUE; break; default: + GPUState.is_dirty = was_dirty; break; } } GLAPI void APIENTRY glDisable(GLenum cap) { + GLboolean was_dirty = GPUState.is_dirty; + GPUState.is_dirty = GL_TRUE; + switch(cap) { case GL_TEXTURE_2D: { TEXTURES_ENABLED[_glGetActiveTexture()] = GL_FALSE; } break; case GL_CULL_FACE: { - CULLING_ENABLED = GL_FALSE; + GPUState.culling_enabled = GL_FALSE; GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); } break; case GL_DEPTH_TEST: { - DEPTH_TEST_ENABLED = GL_FALSE; + GPUState.depth_test_enabled = GL_FALSE; GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); } break; case GL_BLEND: - BLEND_ENABLED = GL_FALSE; + GPUState.blend_enabled = GL_FALSE; _updatePVRBlend(&GL_CONTEXT); break; case GL_SCISSOR_TEST: { GL_CONTEXT.gen.clip_mode = GPU_USERCLIP_DISABLE; } break; case GL_LIGHTING: { - LIGHTING_ENABLED = GL_FALSE; + GPUState.lighting_enabled = GL_FALSE; } break; case GL_FOG: GL_CONTEXT.gen.fog_type = GPU_FOG_DISABLE; break; case GL_COLOR_MATERIAL: - COLOR_MATERIAL_ENABLED = GL_FALSE; + GPUState.color_material_enabled = GL_FALSE; break; case GL_SHARED_TEXTURE_PALETTE_EXT: { - SHARED_PALETTE_ENABLED = GL_FALSE; + GPUState.shared_palette_enabled = GL_FALSE; } break; case GL_ALPHA_TEST: { - ALPHA_TEST_ENABLED = GL_FALSE; + GPUState.alpha_test_enabled = GL_FALSE; } break; case GL_LIGHT0: case GL_LIGHT1: @@ -420,17 +535,18 @@ GLAPI void APIENTRY glDisable(GLenum cap) { _glEnableLight(cap & 0xF, GL_FALSE); break; case GL_NEARZ_CLIPPING_KOS: - ZNEAR_CLIPPING_ENABLED = GL_FALSE; + GPUState.znear_clipping_enabled = GL_FALSE; break; case GL_POLYGON_OFFSET_POINT: case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_FILL: - POLYGON_OFFSET_ENABLED = GL_FALSE; + GPUState.polygon_offset_enabled = GL_FALSE; break; case GL_NORMALIZE: - NORMALIZE_ENABLED = GL_FALSE; + GPUState.normalize_enabled = GL_FALSE; break; default: + GPUState.is_dirty = was_dirty; break; } } @@ -481,7 +597,8 @@ GLAPI void APIENTRY glDepthMask(GLboolean flag) { } 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(); } @@ -502,12 +619,14 @@ GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode) { /* Culling */ 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(); } 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(); } @@ -522,8 +641,9 @@ GLAPI void APIENTRY glShadeModel(GLenum mode) { /* Blending */ GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) { - BLEND_SFACTOR = sfactor; - BLEND_DFACTOR = dfactor; + GPUState.blend_sfactor = sfactor; + GPUState.blend_dfactor = dfactor; + GPUState.is_dirty = GL_TRUE; _updatePVRBlend(&GL_CONTEXT); } @@ -547,8 +667,9 @@ void glLineWidth(GLfloat width) { } void glPolygonOffset(GLfloat factor, GLfloat units) { - OFFSET_FACTOR = factor; - OFFSET_UNITS = units; + GPUState.offset_factor = factor; + GPUState.offset_units = units; + GPUState.is_dirty = GL_TRUE; } 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) { - if(SCISSOR_RECT.x == x && - SCISSOR_RECT.y == y && - SCISSOR_RECT.width == width && - SCISSOR_RECT.height == height) { + + if(GPUState.scissor_rect.x == x && + GPUState.scissor_rect.y == y && + GPUState.scissor_rect.width == width && + GPUState.scissor_rect.height == height) { return; } - SCISSOR_RECT.x = x; - SCISSOR_RECT.y = y; - SCISSOR_RECT.width = width; - SCISSOR_RECT.height = height; - SCISSOR_RECT.applied = false; + GPUState.scissor_rect.x = x; + GPUState.scissor_rect.y = y; + GPUState.scissor_rect.width = width; + GPUState.scissor_rect.height = height; + GPUState.scissor_rect.applied = false; + GPUState.is_dirty = GL_TRUE; // FIXME: do we need this? _glApplyScissor(false); } @@ -623,7 +746,7 @@ void _glApplyScissor(bool force) { } /* Don't apply if we already applied - nothing changed */ - if(SCISSOR_RECT.applied && !force) { + if(GPUState.scissor_rect.applied && !force) { return; } @@ -633,27 +756,31 @@ void _glApplyScissor(bool force) { const VideoMode* vid_mode = GetVideoMode(); - GLsizei scissor_width = MAX(MIN(SCISSOR_RECT.width, vid_mode->width), 0); - GLsizei scissor_height = MAX(MIN(SCISSOR_RECT.height, vid_mode->height), 0); + GLsizei scissor_width = MAX(MIN(GPUState.scissor_rect.width, vid_mode->width), 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 */ - miny = (vid_mode->height - scissor_height) - SCISSOR_RECT.y; - maxx = (scissor_width + SCISSOR_RECT.x); + miny = (vid_mode->height - scissor_height) - GPUState.scissor_rect.y; + maxx = (scissor_width + GPUState.scissor_rect.x); maxy = (scissor_height + miny); /* load command structure while mapping screen coords to TA tiles */ c.flags = GPU_CMD_USERCLIP; 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); - c.ex = CLAMP((maxx / 32) - 1, 0, vid_mode->width / 32); - c.ey = CLAMP((maxy / 32) - 1, 0, vid_mode->height / 32); + + uint16_t vw = vid_mode->width >> 5; + uint16_t vh = vid_mode->height >> 5; + + 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(&_glPunchThruPolyList()->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) { @@ -671,19 +798,19 @@ void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) { GLboolean APIENTRY glIsEnabled(GLenum cap) { switch(cap) { case GL_DEPTH_TEST: - return DEPTH_TEST_ENABLED; + return GPUState.depth_test_enabled; case GL_SCISSOR_TEST: return GL_CONTEXT.gen.clip_mode == GPU_USERCLIP_INSIDE; case GL_CULL_FACE: - return CULLING_ENABLED; + return GPUState.culling_enabled; case GL_LIGHTING: - return LIGHTING_ENABLED; + return GPUState.lighting_enabled; case GL_BLEND: - return BLEND_ENABLED; + return GPUState.blend_enabled; case GL_POLYGON_OFFSET_POINT: case GL_POLYGON_OFFSET_LINE: case GL_POLYGON_OFFSET_FILL: - return POLYGON_OFFSET_ENABLED; + return GPUState.polygon_offset_enabled; } return GL_FALSE; @@ -738,10 +865,10 @@ void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) { MEMCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16); break; case GL_POLYGON_OFFSET_FACTOR: - *params = OFFSET_FACTOR; + *params = GPUState.offset_factor; break; case GL_POLYGON_OFFSET_UNITS: - *params = OFFSET_UNITS; + *params = GPUState.offset_units; break; default: _glKosThrowError(GL_INVALID_ENUM, __func__); @@ -758,13 +885,13 @@ void APIENTRY glGetIntegerv(GLenum pname, GLint *params) { *params = (_glGetBoundTexture()) ? _glGetBoundTexture()->index : 0; break; case GL_DEPTH_FUNC: - *params = DEPTH_FUNC; + *params = GPUState.depth_func; break; case GL_BLEND_SRC: - *params = BLEND_SFACTOR; + *params = GPUState.blend_sfactor; break; case GL_BLEND_DST: - *params = BLEND_DFACTOR; + *params = GPUState.blend_dfactor; break; case GL_MAX_TEXTURE_SIZE: *params = MAX_TEXTURE_SIZE;