diff --git a/CMakeLists.txt b/CMakeLists.txt index e416cdd..c8fec24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ set( GL/matrix.c GL/state.c GL/texture.c + GL/tnl_effects.c GL/util.c GL/alloc/alloc.c ${CMAKE_CURRENT_BINARY_DIR}/version.c diff --git a/GL/draw.c b/GL/draw.c index f39e00e..2b9051e 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -598,37 +598,6 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei } } -static void transform(SubmissionTarget* target) { - TRACE(); - - /* Perform modelview transform, storing W */ - Vertex* it = _glSubmissionTargetStart(target); - int count = target->count; - - for(int i = 0; i < count; ++i, ++it) { - TransformVertex(it->xyz[0], it->xyz[1], it->xyz[2], it->w, - it->xyz, &it->w); - } -} - -static void mat_transform_normal3(VertexExtra* extra, const uint32_t count) { - ITERATE(count) { - TransformNormalNoMod(extra->nxyz, extra->nxyz); - extra++; - } -} - -static void light(SubmissionTarget* target) { - /* Perform lighting calculations and manipulate the colour */ - Vertex* vertex = _glSubmissionTargetStart(target); - VertexExtra* extra = aligned_vector_at(target->extras, 0); - - _glMatrixLoadNormal(); - mat_transform_normal3(extra, target->count); - - _glPerformLighting(vertex, extra, target->count); -} - GL_FORCE_INLINE int _calc_pvr_face_culling() { if(!_glIsCullingEnabled()) { return GPU_CULLING_SMALL; @@ -850,28 +819,11 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL _glGPUStateMarkClean(); } - /* If we're lighting, then we need to do some work in - * eye-space, so we only transform vertices by the modelview - * matrix, and then later multiply by projection. - * - * If we're not doing lighting though we can optimise by taking - * vertices straight to clip-space */ - - if(_glIsLightingEnabled()) { - _glMatrixLoadModelView(); - } else { - _glMatrixLoadModelViewProjection(); - } + _glTnlLoadMatrix(); generate(target, mode, first, count, (GLubyte*) indices, type); - if(_glIsLightingEnabled()){ - light(target); - - /* OK eye-space work done, now move into clip space */ - _glMatrixLoadProjection(); - transform(target); - } + _glTnlApplyEffects(target); // /* // Now, if multitexturing is enabled, we want to send exactly the same vertices again, except: diff --git a/GL/private.h b/GL/private.h index 35707fd..032e337 100644 --- a/GL/private.h +++ b/GL/private.h @@ -485,6 +485,17 @@ void _glGPUStateMarkDirty(); #define SCENE_AMBIENT_MASK 16 +#define TNL_EFFECT_NONE 0x00 +#define TNL_EFFECT_VIEW_SPACE 0x01 +typedef void (*TnlEffect)(SubmissionTarget* target); + +void _glTnlAddEffect(GLint flags, TnlEffect func); +void _glTnlRemoveEffect(TnlEffect func); +void _glTnlLoadMatrix(void); +void _glTnlApplyEffects(SubmissionTarget* target); + +void _glTnlUpdateLighting(void); + /* This is from KOS pvr_buffers.c */ #define PVR_MIN_Z 0.0001f diff --git a/GL/state.c b/GL/state.c index cac3fba..faee889 100644 --- a/GL/state.c +++ b/GL/state.c @@ -473,6 +473,7 @@ GLAPI void APIENTRY glEnable(GLenum cap) { if(GPUState.lighting_enabled != GL_TRUE) { GPUState.lighting_enabled = GL_TRUE; GPUState.is_dirty = GL_TRUE; + _glTnlUpdateLighting(); } } break; case GL_FOG: @@ -584,6 +585,7 @@ GLAPI void APIENTRY glDisable(GLenum cap) { if(GPUState.lighting_enabled != GL_FALSE) { GPUState.lighting_enabled = GL_FALSE; GPUState.is_dirty = GL_TRUE; + _glTnlUpdateLighting(); } } break; case GL_FOG: diff --git a/GL/tnl_effects.c b/GL/tnl_effects.c new file mode 100644 index 0000000..6a20975 --- /dev/null +++ b/GL/tnl_effects.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include + +#include "private.h" +#include "platform.h" + +#define MAX_TNL_EFFECTS 3 + +static struct tnl_effect { + GLint flags; + TnlEffect func; +} TNL_EFFECTS[MAX_TNL_EFFECTS]; + +static int TNL_COUNT; +static GLboolean TNL_VIEW; + +#define ITERATE(count) \ + GLuint i = count; \ + while(i--) + +static void updateEffectList(void) { + TNL_VIEW = GL_FALSE; + + ITERATE(TNL_COUNT) { + if (TNL_EFFECTS[i].flags == TNL_EFFECT_VIEW_SPACE) TNL_VIEW = true; + } +} + +void _glTnlAddEffect(GLint flags, TnlEffect func) { + if (TNL_COUNT == MAX_TNL_EFFECTS) return; + + TNL_EFFECTS[TNL_COUNT].flags = flags; + TNL_EFFECTS[TNL_COUNT].func = func; + + TNL_COUNT++; + updateEffectList(); +} + +void _glTnlRemoveEffect(TnlEffect func) { + int i, j; + + for (i = TNL_COUNT - 1; i >= 0; i--) { + if (TNL_EFFECTS[i].func != func) continue; + + for(j = i; j < TNL_COUNT - 1; j++) { + TNL_EFFECTS[j] = TNL_EFFECTS[j + 1]; + } + TNL_COUNT--; + } + updateEffectList(); +} + +void _glTnlLoadMatrix(void) { + /* If we're lighting, then we need to do some work in + * eye-space, so we only transform vertices by the modelview + * matrix, and then later multiply by projection. + * + * If we're not doing lighting though we can optimise by taking + * vertices straight to clip-space */ + + if(TNL_VIEW) { + _glMatrixLoadModelView(); + } else { + _glMatrixLoadModelViewProjection(); + } +} + +static void transformVertices(SubmissionTarget* target) { + TRACE(); + + /* Perform modelview transform, storing W */ + Vertex* it = _glSubmissionTargetStart(target); + uint32_t count = target->count; + + ITERATE(count) { + TransformVertex(it->xyz[0], it->xyz[1], it->xyz[2], it->w, + it->xyz, &it->w); + it++; + } +} + +void _glTnlApplyEffects(SubmissionTarget* target) { + if (!TNL_COUNT) return; + + struct tnl_effect* e = TNL_EFFECTS; + ITERATE(TNL_COUNT) { + e->func(target); + e++; + } + + if (!TNL_VIEW) return; + /* OK eye-space work done, now move into clip space */ + _glMatrixLoadProjection(); + transformVertices(target); +} + + +static void mat_transform_normal3(VertexExtra* extra, const uint32_t count) { + ITERATE(count) { + TransformNormalNoMod(extra->nxyz, extra->nxyz); + extra++; + } +} + +static void lightingEffect(SubmissionTarget* target) { + /* Perform lighting calculations and manipulate the colour */ + Vertex* vertex = _glSubmissionTargetStart(target); + VertexExtra* extra = aligned_vector_at(target->extras, 0); + + _glMatrixLoadNormal(); + mat_transform_normal3(extra, target->count); + + _glPerformLighting(vertex, extra, target->count); +} + +void _glTnlUpdateLighting(void) { + if (_glIsLightingEnabled()) { + _glTnlAddEffect(TNL_EFFECT_VIEW_SPACE, lightingEffect); + } else { + _glTnlRemoveEffect(lightingEffect); + } +}