From 93c81739ba0b21ecbd6ee2fd9fb00b8da99589e3 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 06:43:44 +1100 Subject: [PATCH 1/8] WIP on a separate T&L effects file --- CMakeLists.txt | 1 + GL/draw.c | 52 +------------------ GL/private.h | 11 +++++ GL/state.c | 2 + GL/tnl_effects.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 142 insertions(+), 50 deletions(-) create mode 100644 GL/tnl_effects.c 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); + } +} From 5e2ea815935a00bb9a807373782a3463b68af332 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 07:40:12 +1100 Subject: [PATCH 2/8] Avoid lighting unless needed --- GL/state.c | 3 --- GL/tnl_effects.c | 7 +++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GL/state.c b/GL/state.c index faee889..e247624 100644 --- a/GL/state.c +++ b/GL/state.c @@ -428,7 +428,6 @@ void _glInitContext() { glDisable(GL_DEPTH_TEST); glDisable(GL_TEXTURE_2D); glDisable(GL_FOG); - glDisable(GL_LIGHTING); GLubyte i; for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { @@ -472,7 +471,6 @@ GLAPI void APIENTRY glEnable(GLenum cap) { case GL_LIGHTING: { if(GPUState.lighting_enabled != GL_TRUE) { GPUState.lighting_enabled = GL_TRUE; - GPUState.is_dirty = GL_TRUE; _glTnlUpdateLighting(); } } break; @@ -584,7 +582,6 @@ GLAPI void APIENTRY glDisable(GLenum cap) { case GL_LIGHTING: { if(GPUState.lighting_enabled != GL_FALSE) { GPUState.lighting_enabled = GL_FALSE; - GPUState.is_dirty = GL_TRUE; _glTnlUpdateLighting(); } } break; diff --git a/GL/tnl_effects.c b/GL/tnl_effects.c index 6a20975..2325f5a 100644 --- a/GL/tnl_effects.c +++ b/GL/tnl_effects.c @@ -9,7 +9,10 @@ #include "platform.h" #define MAX_TNL_EFFECTS 3 +#define TNL_EFFECT_NONE 0x00 +#define TNL_EFFECT_VIEW_SPACE 0x01 +typedef void (*TnlEffect)(SubmissionTarget* target); static struct tnl_effect { GLint flags; TnlEffect func; @@ -30,7 +33,7 @@ static void updateEffectList(void) { } } -void _glTnlAddEffect(GLint flags, TnlEffect func) { +static void _glTnlAddEffect(GLint flags, TnlEffect func) { if (TNL_COUNT == MAX_TNL_EFFECTS) return; TNL_EFFECTS[TNL_COUNT].flags = flags; @@ -40,7 +43,7 @@ void _glTnlAddEffect(GLint flags, TnlEffect func) { updateEffectList(); } -void _glTnlRemoveEffect(TnlEffect func) { +static void _glTnlRemoveEffect(TnlEffect func) { int i, j; for (i = TNL_COUNT - 1; i >= 0; i--) { From 9ca7c002bed528ab50149cadd5e7fb0cccb2ff85 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 08:17:56 +1100 Subject: [PATCH 3/8] Slightly optimise matrix code to a single pointer lookup --- GL/matrix.c | 20 +++++++++++--------- GL/private.h | 6 ------ GL/state.c | 1 + 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index f71a624..fdb9df2 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -19,7 +19,7 @@ static Matrix4x4 __attribute__((aligned(32))) VIEWPORT_MATRIX; static Matrix4x4 __attribute__((aligned(32))) PROJECTION_MATRIX; static GLenum MATRIX_MODE = GL_MODELVIEW; -static GLubyte MATRIX_IDX = 0; +static Stack* MATRIX_CUR; static GLboolean NORMAL_DIRTY, PROJECTION_DIRTY; static const Matrix4x4 __attribute__((aligned(32))) IDENTITY = { @@ -54,6 +54,8 @@ void _glInitMatrices() { MEMCPY4(NORMAL_MATRIX, IDENTITY, sizeof(Matrix4x4)); + MATRIX_CUR = MATRIX_STACKS + (GL_MODELVIEW & 0xF); + const VideoMode* vid_mode = GetVideoMode(); glDepthRange(0.0f, 1.0f); @@ -121,30 +123,30 @@ static void OnMatrixChanged() { void APIENTRY glMatrixMode(GLenum mode) { MATRIX_MODE = mode; - MATRIX_IDX = mode & 0xF; + MATRIX_CUR = MATRIX_STACKS + (mode & 0xF); } void APIENTRY glPushMatrix() { - void* top = stack_top(MATRIX_STACKS + MATRIX_IDX); + void* top = stack_top(MATRIX_CUR); assert(top); - void* ret = stack_push(MATRIX_STACKS + MATRIX_IDX, top); + void* ret = stack_push(MATRIX_CUR, top); (void) ret; assert(ret); OnMatrixChanged(); } void APIENTRY glPopMatrix() { - stack_pop(MATRIX_STACKS + MATRIX_IDX); + stack_pop(MATRIX_CUR); OnMatrixChanged(); } void APIENTRY glLoadIdentity() { - stack_replace(MATRIX_STACKS + MATRIX_IDX, IDENTITY); + stack_replace(MATRIX_CUR, IDENTITY); OnMatrixChanged(); } void GL_FORCE_INLINE _glMultMatrix(const Matrix4x4* mat) { - void* top = stack_top(MATRIX_STACKS + MATRIX_IDX); + void* top = stack_top(MATRIX_CUR); UploadMatrix4x4(top); MultiplyMatrix4x4(mat); @@ -220,7 +222,7 @@ void APIENTRY glLoadMatrixf(const GLfloat *m) { static Matrix4x4 __attribute__((aligned(32))) TEMP; memcpy(TEMP, m, sizeof(float) * 16); - stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP); + stack_replace(MATRIX_CUR, TEMP); OnMatrixChanged(); } @@ -309,7 +311,7 @@ void glLoadTransposeMatrixf(const GLfloat *m) { TEMP[M14] = m[11]; TEMP[M15] = m[15]; - stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP); + stack_replace(MATRIX_CUR, TEMP); OnMatrixChanged(); } diff --git a/GL/private.h b/GL/private.h index 032e337..8c32fc2 100644 --- a/GL/private.h +++ b/GL/private.h @@ -485,12 +485,6 @@ 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); diff --git a/GL/state.c b/GL/state.c index e247624..6468a3b 100644 --- a/GL/state.c +++ b/GL/state.c @@ -978,6 +978,7 @@ void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) { case GL_MODELVIEW_MATRIX: MEMCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16); break; + case GL_POLYGON_OFFSET_FACTOR: *params = GPUState.offset_factor; break; From ebdb454a751382d8831f0f1f3d5f72b9fffd8a30 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 08:46:58 +1100 Subject: [PATCH 4/8] Simplify T&L effect code --- GL/matrix.c | 18 +++++++++-- GL/private.h | 3 ++ GL/state.c | 6 ++++ GL/tnl_effects.c | 82 ++++++++++++------------------------------------ 4 files changed, 45 insertions(+), 64 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index fdb9df2..422e3f8 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -31,26 +31,40 @@ static const Matrix4x4 __attribute__((aligned(32))) IDENTITY = { GLfloat NEAR_PLANE_DISTANCE = 0.0f; +Matrix4x4* _glGetModelViewMatrix() { + return (Matrix4x4*) stack_top(&MATRIX_STACKS[0]); +} + Matrix4x4* _glGetProjectionMatrix() { return (Matrix4x4*) stack_top(&MATRIX_STACKS[1]); } -Matrix4x4* _glGetModelViewMatrix() { - return (Matrix4x4*) stack_top(&MATRIX_STACKS[0]); +Matrix4x4* _glGetTextureMatrix() { + return (Matrix4x4*) stack_top(&MATRIX_STACKS[2]); +} + +Matrix4x4* _glGetColorMatrix() { + return (Matrix4x4*) stack_top(&MATRIX_STACKS[3]); } GLenum _glGetMatrixMode() { return MATRIX_MODE; } +GLboolean _glIsIdentity(const Matrix4x4* m) { + return memcmp(m, IDENTITY, sizeof(Matrix4x4)) == 0; +} + void _glInitMatrices() { init_stack(&MATRIX_STACKS[0], sizeof(Matrix4x4), 32); init_stack(&MATRIX_STACKS[1], sizeof(Matrix4x4), 32); init_stack(&MATRIX_STACKS[2], sizeof(Matrix4x4), 32); + init_stack(&MATRIX_STACKS[3], sizeof(Matrix4x4), 32); stack_push(&MATRIX_STACKS[0], IDENTITY); stack_push(&MATRIX_STACKS[1], IDENTITY); stack_push(&MATRIX_STACKS[2], IDENTITY); + stack_push(&MATRIX_STACKS[3], IDENTITY); MEMCPY4(NORMAL_MATRIX, IDENTITY, sizeof(Matrix4x4)); diff --git a/GL/private.h b/GL/private.h index 8c32fc2..a491932 100644 --- a/GL/private.h +++ b/GL/private.h @@ -332,7 +332,10 @@ extern GLfloat HALF_POINT_SIZE; Matrix4x4* _glGetProjectionMatrix(); Matrix4x4* _glGetModelViewMatrix(); +Matrix4x4* _glGetTextureMatrix(); +Matrix4x4* _glGetColorMatrix(); GLenum _glGetMatrixMode(); +GLboolean _glIsIdentity(const Matrix4x4* m); void _glWipeTextureOnFramebuffers(GLuint texture); diff --git a/GL/state.c b/GL/state.c index 6468a3b..88aaad0 100644 --- a/GL/state.c +++ b/GL/state.c @@ -978,6 +978,12 @@ void APIENTRY glGetFloatv(GLenum pname, GLfloat* params) { case GL_MODELVIEW_MATRIX: MEMCPY4(params, _glGetModelViewMatrix(), sizeof(float) * 16); break; + case GL_TEXTURE_MATRIX: + MEMCPY4(params, _glGetTextureMatrix(), sizeof(float) * 16); + break; + case GL_COLOR_MATRIX: + MEMCPY4(params, _glGetColorMatrix(), sizeof(float) * 16); + break; case GL_POLYGON_OFFSET_FACTOR: *params = GPUState.offset_factor; diff --git a/GL/tnl_effects.c b/GL/tnl_effects.c index 2325f5a..97755e1 100644 --- a/GL/tnl_effects.c +++ b/GL/tnl_effects.c @@ -8,55 +8,15 @@ #include "private.h" #include "platform.h" -#define MAX_TNL_EFFECTS 3 -#define TNL_EFFECT_NONE 0x00 -#define TNL_EFFECT_VIEW_SPACE 0x01 - -typedef void (*TnlEffect)(SubmissionTarget* target); -static struct tnl_effect { - GLint flags; - TnlEffect func; -} TNL_EFFECTS[MAX_TNL_EFFECTS]; - -static int TNL_COUNT; -static GLboolean TNL_VIEW; +#define TNL_FX_LIGHTING 0x01 +#define TNL_FX_TEXTURE 0x02 +#define TNL_FX_COLOR 0x04 +static int TNL_EFFECTS; #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; - } -} - -static 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(); -} - -static 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 @@ -65,7 +25,7 @@ void _glTnlLoadMatrix(void) { * If we're not doing lighting though we can optimise by taking * vertices straight to clip-space */ - if(TNL_VIEW) { + if(TNL_EFFECTS & TNL_FX_LIGHTING) { _glMatrixLoadModelView(); } else { _glMatrixLoadModelViewProjection(); @@ -86,21 +46,6 @@ static void transformVertices(SubmissionTarget* target) { } } -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) { @@ -122,8 +67,21 @@ static void lightingEffect(SubmissionTarget* target) { void _glTnlUpdateLighting(void) { if (_glIsLightingEnabled()) { - _glTnlAddEffect(TNL_EFFECT_VIEW_SPACE, lightingEffect); + TNL_EFFECTS |= TNL_FX_LIGHTING; } else { - _glTnlRemoveEffect(lightingEffect); + TNL_EFFECTS &= ~TNL_FX_LIGHTING; + } +} + +void _glTnlApplyEffects(SubmissionTarget* target) { + if (!TNL_EFFECTS) return; + + if (TNL_EFFECTS & TNL_FX_LIGHTING) + lightingEffect(target); + + if (TNL_EFFECTS & TNL_FX_LIGHTING) { + /* OK eye-space work done, now move into clip space */ + _glMatrixLoadProjection(); + transformVertices(target); } } From e3f61f3c78430ba02ba3a54e9e8e883502d5eb1c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 09:33:08 +1100 Subject: [PATCH 5/8] Initial work on texture and colour matrix support --- GL/matrix.c | 16 +++++++++-- GL/private.h | 2 ++ GL/tnl_effects.c | 73 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/GL/matrix.c b/GL/matrix.c index 422e3f8..3e2b10f 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -130,8 +130,20 @@ static void UpdateNormalMatrix() { } static void OnMatrixChanged() { - if(MATRIX_MODE == GL_MODELVIEW) NORMAL_DIRTY = true; - if(MATRIX_MODE == GL_PROJECTION) PROJECTION_DIRTY = true; + switch (MATRIX_MODE) { + case GL_MODELVIEW: + NORMAL_DIRTY = true; + return; + case GL_PROJECTION: + PROJECTION_DIRTY = true; + return; + case GL_TEXTURE: + _glTnlUpdateTextureMatrix(); + return; + case GL_COLOR: + _glTnlUpdateColorMatrix(); + return; + } } diff --git a/GL/private.h b/GL/private.h index a491932..846f421 100644 --- a/GL/private.h +++ b/GL/private.h @@ -492,6 +492,8 @@ void _glTnlLoadMatrix(void); void _glTnlApplyEffects(SubmissionTarget* target); void _glTnlUpdateLighting(void); +void _glTnlUpdateTextureMatrix(void); +void _glTnlUpdateColorMatrix(void); /* This is from KOS pvr_buffers.c */ #define PVR_MIN_Z 0.0001f diff --git a/GL/tnl_effects.c b/GL/tnl_effects.c index 97755e1..440c869 100644 --- a/GL/tnl_effects.c +++ b/GL/tnl_effects.c @@ -8,10 +8,7 @@ #include "private.h" #include "platform.h" -#define TNL_FX_LIGHTING 0x01 -#define TNL_FX_TEXTURE 0x02 -#define TNL_FX_COLOR 0x04 -static int TNL_EFFECTS; +static int TNL_EFFECTS, TNL_LIGHTING, TNL_TEXTURE, TNL_COLOR; #define ITERATE(count) \ GLuint i = count; \ @@ -25,13 +22,17 @@ void _glTnlLoadMatrix(void) { * If we're not doing lighting though we can optimise by taking * vertices straight to clip-space */ - if(TNL_EFFECTS & TNL_FX_LIGHTING) { + if(TNL_LIGHTING) { _glMatrixLoadModelView(); } else { _glMatrixLoadModelViewProjection(); } } +static void updateEffects(void) { + TNL_EFFECTS = TNL_LIGHTING | TNL_TEXTURE | TNL_COLOR; +} + static void transformVertices(SubmissionTarget* target) { TRACE(); @@ -66,20 +67,70 @@ static void lightingEffect(SubmissionTarget* target) { } void _glTnlUpdateLighting(void) { - if (_glIsLightingEnabled()) { - TNL_EFFECTS |= TNL_FX_LIGHTING; - } else { - TNL_EFFECTS &= ~TNL_FX_LIGHTING; + TNL_LIGHTING = _glIsLightingEnabled(); + updateEffects(); +} + + +static void textureEffect(SubmissionTarget* target) { + Matrix4x4* m = _glGetTextureMatrix(); + UploadMatrix4x4(m); + float coords[4]; + + Vertex* it = _glSubmissionTargetStart(target); + uint32_t count = target->count; + + ITERATE(count) { + TransformVertex(it->uv[0], it->uv[1], 0.0f, 1.0f, coords, &coords[3]); + it->uv[0] = coords[0]; + it->uv[1] = coords[1]; + it++; } } +void _glTnlUpdateTextureMatrix(void) { + Matrix4x4* m = _glGetTextureMatrix(); + TNL_TEXTURE = _glIsIdentity(m); + updateEffects(); +} + + +static void colorEffect(SubmissionTarget* target) { + Matrix4x4* m = _glGetColorMatrix(); + UploadMatrix4x4(m); + float coords[4]; + + Vertex* it = _glSubmissionTargetStart(target); + uint32_t count = target->count; + + ITERATE(count) { + TransformVertex(it->bgra[2], it->bgra[1], it->bgra[0], it->bgra[3], coords, &coords[3]); + it->bgra[2] = clamp(coords[0], 0, 255); + it->bgra[1] = clamp(coords[1], 0, 255); + it->bgra[0] = clamp(coords[2], 0, 255); + it->bgra[3] = clamp(coords[3], 0, 255); + it++; + } +} + +void _glTnlUpdateColorMatrix(void) { + Matrix4x4* m = _glGetColorMatrix(); + TNL_COLOR = _glIsIdentity(m); + updateEffects(); +} + + void _glTnlApplyEffects(SubmissionTarget* target) { if (!TNL_EFFECTS) return; - if (TNL_EFFECTS & TNL_FX_LIGHTING) + if (TNL_LIGHTING) lightingEffect(target); + if (TNL_TEXTURE) + textureEffect(target); + if (TNL_COLOR) + colorEffect(target); - if (TNL_EFFECTS & TNL_FX_LIGHTING) { + if (TNL_LIGHTING) { /* OK eye-space work done, now move into clip space */ _glMatrixLoadProjection(); transformVertices(target); From 2669a9266fedd5e048d7c39baa3c1769f1d95e29 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 10:08:55 +1100 Subject: [PATCH 6/8] When texture validation fails, log reason why using INFO_MSG --- GL/texture.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GL/texture.c b/GL/texture.c index 6bcfae1..30c7976 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -1419,14 +1419,14 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm if(format != GL_COLOR_INDEX4_EXT && format != GL_COLOR_INDEX4_TWID_KOS) { /* Abuse determineStride to see if type is valid */ if(_determineStride(GL_RGBA, type) == -1) { - INFO_MSG(""); + INFO_MSG("Unsupported type"); _glKosThrowError(GL_INVALID_ENUM, __func__); return false; } } if(_cleanInternalFormat(internalFormat) == -1) { - INFO_MSG(""); + INFO_MSG("Unsupported internal format"); _glKosThrowError(GL_INVALID_VALUE, __func__); return false; } @@ -1436,7 +1436,7 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm if(level == 0){ if((w < 8 || (w & -w) != w)) { /* Width is not a power of two. Must be!*/ - INFO_MSG(""); + INFO_MSG("Unsupported width"); _glKosThrowError(GL_INVALID_VALUE, __func__); return false; } @@ -1444,7 +1444,7 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm if((h < 8 || (h & -h) != h)) { /* height is not a power of two. Must be!*/ - INFO_MSG(""); + INFO_MSG("Unsupported height"); _glKosThrowError(GL_INVALID_VALUE, __func__); return false; } @@ -1459,7 +1459,7 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm } if(level < 0) { - INFO_MSG(""); + INFO_MSG("Level must be >= 0"); _glKosThrowError(GL_INVALID_VALUE, __func__); return false; } @@ -1472,7 +1472,7 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm } if(border) { - INFO_MSG(""); + INFO_MSG("Border not allowed"); _glKosThrowError(GL_INVALID_VALUE, __func__); return false; } From ff942e804ec3deca773c06068c60bc3d6cb05c60 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 10:52:09 +1100 Subject: [PATCH 7/8] Add texture/color matrix sample --- CMakeLists.txt | 1 + GL/matrix.c | 8 +-- GL/private.h | 1 - GL/tnl_effects.c | 5 +- include/GL/gl.h | 2 + samples/tnl_effects/main.c | 135 +++++++++++++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 samples/tnl_effects/main.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c8fec24..97e9515 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,7 @@ gen_sample(polymark samples/polymark/main.c) gen_sample(cubes samples/cubes/main.cpp) gen_sample(zclip_test tests/zclip/main.cpp) gen_sample(primitive_modes samples/primitive_modes/main.c) +gen_sample(tnl_effects samples/tnl_effects/main.c) if(PLATFORM_DREAMCAST) gen_sample(trimark samples/trimark/main.c) diff --git a/GL/matrix.c b/GL/matrix.c index 3e2b10f..75d4526 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -40,11 +40,11 @@ Matrix4x4* _glGetProjectionMatrix() { } Matrix4x4* _glGetTextureMatrix() { - return (Matrix4x4*) stack_top(&MATRIX_STACKS[2]); + return (Matrix4x4*) stack_top(MATRIX_STACKS + (GL_TEXTURE & 0xF)); } Matrix4x4* _glGetColorMatrix() { - return (Matrix4x4*) stack_top(&MATRIX_STACKS[3]); + return (Matrix4x4*) stack_top(MATRIX_STACKS + (GL_COLOR & 0xF)); } GLenum _glGetMatrixMode() { @@ -461,10 +461,6 @@ void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, DownloadMatrix4x4(stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF))); } -void _glMatrixLoadTexture() { - UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_TEXTURE & 0xF))); -} - void _glMatrixLoadModelView() { UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF))); } diff --git a/GL/private.h b/GL/private.h index 846f421..7fc476a 100644 --- a/GL/private.h +++ b/GL/private.h @@ -321,7 +321,6 @@ void _glInitSubmissionTarget(); void _glMatrixLoadNormal(); void _glMatrixLoadModelView(); void _glMatrixLoadProjection(); -void _glMatrixLoadTexture(); void _glMatrixLoadModelViewProjection(); extern GLfloat DEPTH_RANGE_MULTIPLIER_L; diff --git a/GL/tnl_effects.c b/GL/tnl_effects.c index 440c869..c63722c 100644 --- a/GL/tnl_effects.c +++ b/GL/tnl_effects.c @@ -76,6 +76,7 @@ static void textureEffect(SubmissionTarget* target) { Matrix4x4* m = _glGetTextureMatrix(); UploadMatrix4x4(m); float coords[4]; + float* ptr = (float*)m; Vertex* it = _glSubmissionTargetStart(target); uint32_t count = target->count; @@ -90,7 +91,7 @@ static void textureEffect(SubmissionTarget* target) { void _glTnlUpdateTextureMatrix(void) { Matrix4x4* m = _glGetTextureMatrix(); - TNL_TEXTURE = _glIsIdentity(m); + TNL_TEXTURE = !_glIsIdentity(m); updateEffects(); } @@ -115,7 +116,7 @@ static void colorEffect(SubmissionTarget* target) { void _glTnlUpdateColorMatrix(void) { Matrix4x4* m = _glGetColorMatrix(); - TNL_COLOR = _glIsIdentity(m); + TNL_COLOR = !_glIsIdentity(m); updateEffects(); } diff --git a/include/GL/gl.h b/include/GL/gl.h index c26f456..f6c7f4a 100644 --- a/include/GL/gl.h +++ b/include/GL/gl.h @@ -69,10 +69,12 @@ __BEGIN_DECLS #define GL_MODELVIEW 0x1700 #define GL_PROJECTION 0x1701 #define GL_TEXTURE 0x1702 +#define GL_COLOR 0x1703 /* NOTE: Not the usual value */ #define GL_MODELVIEW_MATRIX 0x0BA6 #define GL_PROJECTION_MATRIX 0x0BA7 #define GL_TEXTURE_MATRIX 0x0BA8 +#define GL_COLOR_MATRIX 0x80B1 /* Depth buffer */ #define GL_NEVER 0x0200 diff --git a/samples/tnl_effects/main.c b/samples/tnl_effects/main.c new file mode 100644 index 0000000..953575a --- /dev/null +++ b/samples/tnl_effects/main.c @@ -0,0 +1,135 @@ +#include +#include +#include + +#ifndef _arch_dreamcast +#include +static SDL_Window* win_handle; +#else +#include +#include +#endif + +static void DrawQuad(float x, float y) { + glBegin(GL_QUADS); + x -= 1.0f; + y -= 1.0f; + glColor3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 0.0f); glVertex2f(x + 0.0f, y + 0.0f); + glColor3f(0.5f, 0.5f, 0.5f); glTexCoord2f(1.0f, 0.0f); glVertex2f(x + 0.3f, y + 0.0f); + glColor3f(0.5f, 0.5f, 0.5f); glTexCoord2f(1.0f, 1.0f); glVertex2f(x + 0.3f, y + 0.3f); + glColor3f(0.5f, 0.5f, 0.5f); glTexCoord2f(0.0f, 1.0f); glVertex2f(x + 0.0f, y + 0.3f); + glEnd(); +} + +static void sample_init() { +#ifdef SDL2_BUILD + SDL_Init(SDL_INIT_EVERYTHING); + win_handle = SDL_CreateWindow("Shapes", 0, 0, 640, 480, SDL_WINDOW_OPENGL); + SDL_GL_CreateContext(win_handle); +#else + glKosInit(); +#endif +} + +static int sample_should_exit() { +#ifndef _arch_dreamcast + SDL_Event event; + while (SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) return 1; + } + return 0; +#else + maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if (!cont) return 0; + + cont_state_t *state = (cont_state_t *)maple_dev_status(cont); + if (!state) return 0; + + return state->buttons & CONT_START; +#endif +} + +#define IMG_SIZE 8 +int main(int argc, char *argv[]) { + sample_init(); + glClearColor(0.2f, 0.2f, 0.2f, 1); + glViewport(0, 0, 640, 480); + glEnable(GL_TEXTURE_2D); + + GLint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + static GLubyte texData[IMG_SIZE * IMG_SIZE * 4]; + for (int y = 0, i = 0; y < IMG_SIZE; y++) + for (int x = 0; x < IMG_SIZE; x++, i += 4) + { + int a = x + y; + texData[i + 0] = (a & 1) ? 0xFF : 0; + texData[i + 1] = (a & 2) ? 0xFF : 0; + texData[i + 2] = (a & 4) ? 0xFF : 0; + texData[i + 3] = 0xFF; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMG_SIZE, IMG_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); + float time = 0.0f; + + while (!sample_should_exit()) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + DrawQuad(0.1f, 0.1f); + + glMatrixMode(GL_TEXTURE); + glTranslatef(time, 0, 0); + DrawQuad(0.5f, 0.1f); + glLoadIdentity(); + + glMatrixMode(GL_TEXTURE); + glTranslatef(0, time, 0); + DrawQuad(0.9f, 0.1f); + glLoadIdentity(); + + glMatrixMode(GL_TEXTURE); + glScalef(time, time * 0.5f, 0); + DrawQuad(1.3f, 0.1f); + glLoadIdentity(); + + glMatrixMode(GL_TEXTURE); + glRotatef(time * 1000, 1, 0, 0); + DrawQuad(1.7f, 0.1f); + glLoadIdentity(); + + glMatrixMode(GL_COLOR); + glTranslatef(time, 0, 0); + DrawQuad(0.1f, 0.5f); + glLoadIdentity(); + + glMatrixMode(GL_COLOR); + glTranslatef(0, time, 0); + DrawQuad(0.5f, 0.5f); + glLoadIdentity(); + + glMatrixMode(GL_COLOR); + glTranslatef(0, 0, time); + DrawQuad(0.9f, 0.5f); + glLoadIdentity(); + + glMatrixMode(GL_COLOR); + glScalef(time, time, time); + DrawQuad(1.3f, 0.5f); + glLoadIdentity(); + + glMatrixMode(GL_COLOR); + glRotatef(time * 1000, 1, 0, 0); + DrawQuad(0.1f, 0.5f); + glLoadIdentity(); + +#ifdef SDL2_BUILD + SDL_GL_SwapWindow(win_handle); +#else + glKosSwapBuffers(); +#endif + time += 0.001f; + } + return 0; +} From 6ce38521c943c3255c71af7712027eac70165d27 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 22 Feb 2025 22:41:49 +1100 Subject: [PATCH 8/8] Fix tnl_effects sample not working at all on native desktop OpenGL --- GL/attributes.c | 2 +- GL/draw.c | 1 - samples/tnl_effects/main.c | 7 +++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/GL/attributes.c b/GL/attributes.c index 8222d2e..3b05e47 100644 --- a/GL/attributes.c +++ b/GL/attributes.c @@ -301,7 +301,7 @@ static ReadAttributeFunc calcReadDiffuseFunc(void) { static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { _GL_UNUSED(input); //memset(out, 0, sizeof(float) * 2); - // memset does 8 byte writes - faster to manually write as uint32 + // memset does 8 individual byte writes - faster to manually write as uint32 uint32_t* dst = (uint32_t*)out; dst[0] = 0; dst[1] = 0; diff --git a/GL/draw.c b/GL/draw.c index 2b9051e..5807ce1 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -367,7 +367,6 @@ static void generateElements( Vertex* output = _glSubmissionTargetStart(target); VertexExtra* ve = aligned_vector_at(target->extras, 0); - float pos[3], w = 1.0f; uint32_t i = first; uint32_t idx = 0; diff --git a/samples/tnl_effects/main.c b/samples/tnl_effects/main.c index 953575a..4f063d5 100644 --- a/samples/tnl_effects/main.c +++ b/samples/tnl_effects/main.c @@ -26,6 +26,7 @@ static void sample_init() { SDL_Init(SDL_INIT_EVERYTHING); win_handle = SDL_CreateWindow("Shapes", 0, 0, 640, 480, SDL_WINDOW_OPENGL); SDL_GL_CreateContext(win_handle); + SDL_GL_SetSwapInterval(1); #else glKosInit(); #endif @@ -71,6 +72,8 @@ int main(int argc, char *argv[]) { texData[i + 3] = 0xFF; } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMG_SIZE, IMG_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); float time = 0.0f; @@ -95,7 +98,7 @@ int main(int argc, char *argv[]) { glLoadIdentity(); glMatrixMode(GL_TEXTURE); - glRotatef(time * 1000, 1, 0, 0); + glRotatef(time * 100, 1, 0, 0); DrawQuad(1.7f, 0.1f); glLoadIdentity(); @@ -120,7 +123,7 @@ int main(int argc, char *argv[]) { glLoadIdentity(); glMatrixMode(GL_COLOR); - glRotatef(time * 1000, 1, 0, 0); + glRotatef(time * 100, 1, 0, 0); DrawQuad(0.1f, 0.5f); glLoadIdentity();