From ec24e554ba2aa1081ab54e459eddc56683dd5ff1 Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Wed, 13 Nov 2024 21:53:35 +0300 Subject: [PATCH 1/4] arrays: reduce code duplication for setting up the vertex format --- src/arrays.cpp | 35 ++++++++++++++++++++++------------- src/arrays.h | 6 ++---- src/call_lists.c | 22 +++++++--------------- src/gc_gl.c | 26 ++------------------------ 4 files changed, 33 insertions(+), 56 deletions(-) diff --git a/src/arrays.cpp b/src/arrays.cpp index 36a0fc5..a045916 100644 --- a/src/arrays.cpp +++ b/src/arrays.cpp @@ -438,24 +438,33 @@ void _ogx_array_reader_init(OgxArrayReader *reader, type, vertex_attribute); } -void _ogx_array_reader_setup_draw_start() +static inline VertexReaderBase *get_reader(OgxArrayReader *reader) { - GX_ClearVtxDesc(); - s_num_tex_arrays = 0; + return reinterpret_cast(reader); } -void _ogx_array_reader_setup_draw(OgxArrayReader *reader) +void _ogx_arrays_setup_draw(bool has_normals, uint8_t num_colors, + uint8_t tex_unit_mask) { - VertexReaderBase *r = reinterpret_cast(reader); - r->setup_draw(); -} + GX_ClearVtxDesc(); + s_num_tex_arrays = 0; -void _ogx_array_reader_setup_draw_color(OgxArrayReader *reader, - bool dup_color) -{ - VertexReaderBase *r = reinterpret_cast(reader); - r->enable_duplicate_color(dup_color); - r->setup_draw(); + get_reader(&glparamstate.vertex_array)->setup_draw(); + if (has_normals) { + get_reader(&glparamstate.normal_array)->setup_draw(); + } + if (num_colors > 0) { + VertexReaderBase *r = get_reader(&glparamstate.color_array); + r->enable_duplicate_color(num_colors > 1); + r->setup_draw(); + } + if (tex_unit_mask) { + for (int i = 0; i < MAX_TEXTURE_UNITS; i++) { + if (tex_unit_mask & (1 << i)) { + get_reader(&glparamstate.texcoord_array[i])->setup_draw(); + } + } + } } void _ogx_array_reader_enable_dup_color(OgxArrayReader *reader, diff --git a/src/arrays.h b/src/arrays.h index ba64e31..6692f1e 100644 --- a/src/arrays.h +++ b/src/arrays.h @@ -48,10 +48,8 @@ void _ogx_array_reader_init(OgxArrayReader *reader, uint8_t vertex_attribute, const void *data, int num_components, GLenum type, int stride); -void _ogx_array_reader_setup_draw_start(); -void _ogx_array_reader_setup_draw(OgxArrayReader *reader); -void _ogx_array_reader_setup_draw_color(OgxArrayReader *reader, - bool dup_color); +void _ogx_arrays_setup_draw(bool has_normals, uint8_t num_colors, + uint8_t tex_unit_mask); void _ogx_array_reader_enable_dup_color(OgxArrayReader *reader, bool dup_color); void _ogx_array_reader_process_element(OgxArrayReader *reader, int index); diff --git a/src/call_lists.c b/src/call_lists.c index 9a3a5b7..a4b475b 100644 --- a/src/call_lists.c +++ b/src/call_lists.c @@ -229,20 +229,17 @@ static void execute_draw_geometry_list(struct DrawGeometry *dg) } } - _ogx_array_reader_setup_draw_start(); - _ogx_array_reader_setup_draw(&glparamstate.vertex_array); - if (dg->cs.normal_enabled) { - _ogx_array_reader_setup_draw(&glparamstate.normal_array); - } else { + _ogx_arrays_setup_draw(dg->cs.normal_enabled, + dg->cs.color_enabled ? 2 : 0, + dg->cs.texcoord_enabled); + if (!dg->cs.normal_enabled) { GX_SetVtxDesc(GX_VA_NRM, GX_INDEX8); GX_SetArray(GX_VA_NRM, s_current_normal, 12); floatcpy(s_current_normal, glparamstate.imm_mode.current_normal, 3); /* Not needed on Dolphin, but it is on a Wii */ DCStoreRange(s_current_normal, 12); } - if (dg->cs.color_enabled) { - _ogx_array_reader_setup_draw_color(&glparamstate.color_array, true); - } else { + if (!dg->cs.color_enabled) { GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX8); GX_SetVtxDesc(GX_VA_CLR1, GX_INDEX8); s_current_color = current_color; @@ -251,13 +248,8 @@ static void execute_draw_geometry_list(struct DrawGeometry *dg) DCStoreRange(&s_current_color, 4); } - for (int i = 0; i < MAX_TEXTURE_UNITS; i++) { - /* It makes no sense to use a fixed texture coordinates for all vertices, - * so we won't add them unless they are enabled. */ - if (dg->cs.texcoord_enabled & (1 << i)) { - _ogx_array_reader_setup_draw(&glparamstate.texcoord_array[i]); - } - } + /* It makes no sense to use a fixed texture coordinates for all vertices, + * so we won't add them unless they are enabled. */ GX_InvVtxCache(); diff --git a/src/gc_gl.c b/src/gc_gl.c index 22c36bd..756f10a 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -2296,18 +2296,7 @@ static void draw_elements_general(DrawMode gxmode, int count, GLenum type, const GLvoid *indices, int ne, int color_provide, int texen) { - _ogx_array_reader_setup_draw_start(); - _ogx_array_reader_setup_draw(&glparamstate.vertex_array); - if (ne) - _ogx_array_reader_setup_draw(&glparamstate.normal_array); - if (color_provide) - _ogx_array_reader_setup_draw_color(&glparamstate.color_array, - color_provide == 2); - for (int tex = 0; tex < MAX_TEXTURE_UNITS; tex++) { - if (texen & (1 << tex)) { - _ogx_array_reader_setup_draw(&glparamstate.texcoord_array[tex]); - } - } + _ogx_arrays_setup_draw(ne, color_provide, texen); // Invalidate vertex data as may have been modified by the user GX_InvVtxCache(); @@ -2488,18 +2477,7 @@ void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indic static void draw_arrays_general(DrawMode gxmode, int first, int count, int ne, int color_provide, int texen) { - _ogx_array_reader_setup_draw_start(); - _ogx_array_reader_setup_draw(&glparamstate.vertex_array); - if (ne) - _ogx_array_reader_setup_draw(&glparamstate.normal_array); - if (color_provide) - _ogx_array_reader_setup_draw_color(&glparamstate.color_array, - color_provide == 2); - for (int tex = 0; tex < MAX_TEXTURE_UNITS; tex++) { - if (texen & (1 << tex)) { - _ogx_array_reader_setup_draw(&glparamstate.texcoord_array[tex]); - } - } + _ogx_arrays_setup_draw(ne, color_provide, texen); // Invalidate vertex data as may have been modified by the user GX_InvVtxCache(); From 37114475cd98c6375f1272d4183f7efbbadf5f75 Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Wed, 13 Nov 2024 22:40:37 +0300 Subject: [PATCH 2/4] arrays: add one more function to reduce code duplication --- src/arrays.cpp | 29 +++++++++++++++++++++++++++++ src/arrays.h | 1 + src/gc_gl.c | 34 ++-------------------------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/arrays.cpp b/src/arrays.cpp index a045916..50eff57 100644 --- a/src/arrays.cpp +++ b/src/arrays.cpp @@ -39,6 +39,9 @@ POSSIBILITY OF SUCH DAMAGE. #include static char s_num_tex_arrays = 0; +static bool s_has_normals = false; +static uint8_t s_num_colors = 0; +static uint8_t s_tex_unit_mask = 0; struct GxVertexFormat { uint8_t attribute; @@ -465,6 +468,32 @@ void _ogx_arrays_setup_draw(bool has_normals, uint8_t num_colors, } } } + + s_has_normals = has_normals; + s_num_colors = num_colors; + s_tex_unit_mask = tex_unit_mask; +} + +void _ogx_arrays_process_element(int index) +{ + get_reader(&glparamstate.vertex_array)->process_element(index); + + if (s_has_normals) { + get_reader(&glparamstate.normal_array)->process_element(index); + } + + if (s_num_colors) { + get_reader(&glparamstate.color_array)->process_element(index); + } + + if (s_tex_unit_mask) { + for (int i = 0; i < MAX_TEXTURE_UNITS; i++) { + if (s_tex_unit_mask & (1 << i)) { + get_reader(&glparamstate.texcoord_array[i])-> + process_element(index); + } + } + } } void _ogx_array_reader_enable_dup_color(OgxArrayReader *reader, diff --git a/src/arrays.h b/src/arrays.h index 6692f1e..934fb46 100644 --- a/src/arrays.h +++ b/src/arrays.h @@ -50,6 +50,7 @@ void _ogx_array_reader_init(OgxArrayReader *reader, int num_components, GLenum type, int stride); void _ogx_arrays_setup_draw(bool has_normals, uint8_t num_colors, uint8_t tex_unit_mask); +void _ogx_arrays_process_element(int index); void _ogx_array_reader_enable_dup_color(OgxArrayReader *reader, bool dup_color); void _ogx_array_reader_process_element(OgxArrayReader *reader, int index); diff --git a/src/gc_gl.c b/src/gc_gl.c index 756f10a..6997691 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -2310,22 +2310,7 @@ static void draw_elements_general(DrawMode gxmode, int count, GLenum type, GX_Begin(gxmode.mode, GX_VTXFMT0, count + loop); for (int i = 0; i < count + loop; i++) { int index = read_index(indices, type, i % count); - _ogx_array_reader_process_element(&glparamstate.vertex_array, index); - - if (ne) { - _ogx_array_reader_process_element(&glparamstate.normal_array, index); - } - - if (color_provide) { - _ogx_array_reader_process_element(&glparamstate.color_array, index); - } - - for (int tex = 0; tex < MAX_TEXTURE_UNITS; tex++) { - if (texen & (1 << tex)) { - _ogx_array_reader_process_element( - &glparamstate.texcoord_array[tex], index); - } - } + _ogx_arrays_process_element(index); } GX_End(); } @@ -2487,22 +2472,7 @@ static void draw_arrays_general(DrawMode gxmode, int first, int count, int ne, int i; for (i = 0; i < count + loop; i++) { int j = i % count + first; - _ogx_array_reader_process_element(&glparamstate.vertex_array, j); - - if (ne) { - _ogx_array_reader_process_element(&glparamstate.normal_array, j); - } - - if (color_provide) { - _ogx_array_reader_process_element(&glparamstate.color_array, j); - } - - for (int tex = 0; tex < MAX_TEXTURE_UNITS; tex++) { - if (texen & (1 << tex)) { - _ogx_array_reader_process_element( - &glparamstate.texcoord_array[tex], j); - } - } + _ogx_arrays_process_element(j); } GX_End(); } From 4718909d88dcb632bb2072a1aae2efe55265c1d0 Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Fri, 15 Nov 2024 18:54:28 +0300 Subject: [PATCH 3/4] drawing: setup TEV stages *after* initializing the vertex arrays The registers to be used as texture input coordinates will (in the following commit) computed when setting up the vertex arrays, so this operation must happen before setting up the TEV (which uses those registers). This small refactoring also reduces some code duplication. --- src/gc_gl.c | 102 +++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 62 deletions(-) diff --git a/src/gc_gl.c b/src/gc_gl.c index 6997691..df55b92 100644 --- a/src/gc_gl.c +++ b/src/gc_gl.c @@ -89,8 +89,7 @@ static uint8_t s_zbuffer_texels[2 * 32] ATTRIBUTE_ALIGN(32); extern int _ogx_functions_c; void *_ogx_force_proctable = &_ogx_functions_c; -static void draw_arrays_general(DrawMode gxmode, int first, int count, int ne, - int color_provide, int texen); +static void draw_arrays_general(DrawMode gxmode, int first, int count); static inline void update_modelview_matrix() { @@ -2283,21 +2282,17 @@ static void flat_draw_geometry(void *cb_data) { OgxDrawData *data = cb_data; + _ogx_arrays_setup_draw(false, /* no normals */ + false, /* no color */ + false /* no texturing */); /* TODO: we could use C++ templates here too, to build more effective * drawing functions that only process the data we need. */ - draw_arrays_general(data->gxmode, data->first, data->count, - false, /* no normals */ - false, /* no color */ - false /* no texturing */); - GX_End(); + draw_arrays_general(data->gxmode, data->first, data->count); } static void draw_elements_general(DrawMode gxmode, int count, GLenum type, - const GLvoid *indices, - int ne, int color_provide, int texen) + const GLvoid *indices) { - _ogx_arrays_setup_draw(ne, color_provide, texen); - // Invalidate vertex data as may have been modified by the user GX_InvVtxCache(); @@ -2326,13 +2321,13 @@ static void flat_draw_elements(void *cb_data) { OgxDrawElementsData *data = cb_data; + _ogx_arrays_setup_draw(false, /* no normals */ + false, /* no color */ + false /* no texturing */); + /* TODO: we could use C++ templates here too, to build more effective * drawing functions that only process the data we need. */ - draw_elements_general(data->gxmode, data->count, data->type, data->indices, - false, /* no normals */ - false, /* no color */ - false /* no texturing */); - GX_End(); + draw_elements_general(data->gxmode, data->count, data->type, data->indices); } void glArrayElement(GLint i) @@ -2363,6 +2358,30 @@ void glArrayElement(GLint i) } } +static bool setup_draw() +{ + _ogx_efb_set_content_type(OGX_EFB_SCENE); + + uint8_t texen = glparamstate.cs.texcoord_enabled & glparamstate.texture_enabled; + uint8_t color_provide = 0; + if (glparamstate.cs.color_enabled && + (!glparamstate.lighting.enabled || glparamstate.lighting.color_material_enabled)) { // Vertex colouring + if (glparamstate.lighting.enabled) + color_provide = 2; // Lighting requires two color channels + else + color_provide = 1; + } + _ogx_arrays_setup_draw(glparamstate.cs.normal_enabled, color_provide, texen); + + /* Note that _ogx_setup_render_stages() uses some information from the + * vertex arrays computed by _ogx_arrays_setup_draw(), so it must be called + * after it. */ + bool should_draw = _ogx_setup_render_stages(); + if (!should_draw) return false; + _ogx_apply_state(); + return true; +} + void glDrawArrays(GLenum mode, GLint first, GLsizei count) { DrawMode gxmode = _ogx_draw_mode(mode); @@ -2374,8 +2393,6 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count) /* If VBOs are in use, make sure their data has been updated */ ppcsync(); - bool should_draw = true; - int texen = glparamstate.cs.texcoord_enabled; if (glparamstate.stencil.enabled) { _ogx_gpu_resources_push(); OgxDrawData draw_data = { gxmode, first, count }; @@ -2383,28 +2400,11 @@ void glDrawArrays(GLenum mode, GLint first, GLsizei count) _ogx_gpu_resources_pop(); } - _ogx_efb_set_content_type(OGX_EFB_SCENE); _ogx_gpu_resources_push(); - should_draw = _ogx_setup_render_stages(); - _ogx_apply_state(); - - /* When not building a display list, we can optimize the drawing by - * avoiding passing texture coordinates if texturing is not enabled. - */ - texen = texen & glparamstate.texture_enabled; + bool should_draw = setup_draw(); if (should_draw) { - int color_provide = 0; - if (glparamstate.cs.color_enabled && - (!glparamstate.lighting.enabled || glparamstate.lighting.color_material_enabled)) { // Vertex colouring - if (glparamstate.lighting.enabled) - color_provide = 2; // Lighting requires two color channels - else - color_provide = 1; - } - - draw_arrays_general(gxmode, first, count, glparamstate.cs.normal_enabled, - color_provide, texen); + draw_arrays_general(gxmode, first, count); glparamstate.draw_count++; } @@ -2422,8 +2422,6 @@ void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indic /* If VBOs are in use, make sure their data has been updated */ ppcsync(); - bool should_draw = true; - int texen = glparamstate.cs.texcoord_enabled; if (glparamstate.stencil.enabled) { _ogx_gpu_resources_push(); OgxDrawElementsData draw_data = { gxmode, count, type, indices }; @@ -2431,39 +2429,19 @@ void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indic _ogx_gpu_resources_pop(); } - _ogx_efb_set_content_type(OGX_EFB_SCENE); - _ogx_gpu_resources_push(); - should_draw = _ogx_setup_render_stages(); - _ogx_apply_state(); - /* When not building a display list, we can optimize the drawing by - * avoiding passing texture coordinates if texturing is not enabled. - */ - texen = texen & glparamstate.texture_enabled; + bool should_draw = setup_draw(); if (should_draw) { - int color_provide = 0; - if (glparamstate.cs.color_enabled && - (!glparamstate.lighting.enabled || glparamstate.lighting.color_material_enabled)) { // Vertex colouring - if (glparamstate.lighting.enabled) - color_provide = 2; // Lighting requires two color channels - else - color_provide = 1; - } - - draw_elements_general(gxmode, count, type, indices, - glparamstate.cs.normal_enabled, color_provide, texen); + draw_elements_general(gxmode, count, type, indices); glparamstate.draw_count++; } _ogx_gpu_resources_pop(); } -static void draw_arrays_general(DrawMode gxmode, int first, int count, int ne, - int color_provide, int texen) +static void draw_arrays_general(DrawMode gxmode, int first, int count) { - _ogx_arrays_setup_draw(ne, color_provide, texen); - // Invalidate vertex data as may have been modified by the user GX_InvVtxCache(); From fc73521a30b2a22f5cbdc0293cd96b79010c3d1f Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Thu, 14 Nov 2024 18:00:03 +0300 Subject: [PATCH 4/4] arrays: allow using positions and normals as texture coordinate inputs The GX_VA_TEX* formats only allow up to two components in the texture input coordinates (s and t), but OpenGL applications can provide up to four, along with a texture matrix to transform them. While we are not able to support this general case (not easily, at least!), we can handle the case where the array with the texture input coordinates is the same passed for the positional or normal attributes, because in that case we can skip re-uploading these coordinates at all and can setup the TEV to read texture coordinates from GX_TG_POS or GX_TG_NRM and transform them with the given matrix. This works well with Neverball, which passes the same array of positions as texture coordinates when it needs to apply the ball shadow to the object lying under the ball. --- src/arrays.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++---- src/arrays.h | 1 + src/texture_unit.c | 24 ++++++++++++++---------- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/arrays.cpp b/src/arrays.cpp index 50eff57..d41d27b 100644 --- a/src/arrays.cpp +++ b/src/arrays.cpp @@ -163,6 +163,11 @@ struct VertexReaderBase { this->dup_color = dup_color; } + void set_tex_coord_source(uint8_t source) { tex_coord_source = source; } + bool has_same_data(VertexReaderBase *other) const { + return data == other->data && stride == other->stride; + } + virtual void process_element(int index) = 0; virtual void read_color(int index, GXColor *color) = 0; @@ -174,6 +179,7 @@ struct VertexReaderBase { const char *data; uint16_t stride; bool dup_color; + uint8_t tex_coord_source; VboType vbo; }; @@ -452,26 +458,53 @@ void _ogx_arrays_setup_draw(bool has_normals, uint8_t num_colors, GX_ClearVtxDesc(); s_num_tex_arrays = 0; - get_reader(&glparamstate.vertex_array)->setup_draw(); + VertexReaderBase *vertex_reader = get_reader(&glparamstate.vertex_array); + vertex_reader->setup_draw(); + + VertexReaderBase *normal_reader = nullptr; if (has_normals) { - get_reader(&glparamstate.normal_array)->setup_draw(); + normal_reader = get_reader(&glparamstate.normal_array); + normal_reader->setup_draw(); } if (num_colors > 0) { VertexReaderBase *r = get_reader(&glparamstate.color_array); r->enable_duplicate_color(num_colors > 1); r->setup_draw(); } + + int sent_tex_arrays = 0; + s_tex_unit_mask = 0; if (tex_unit_mask) { for (int i = 0; i < MAX_TEXTURE_UNITS; i++) { if (tex_unit_mask & (1 << i)) { - get_reader(&glparamstate.texcoord_array[i])->setup_draw(); + VertexReaderBase *r = get_reader(&glparamstate.texcoord_array[i]); + /* See if the data array is the same as the positional or + * normal array. This is not just an optimization, it's + * actually needed because GX only supports up to two input + * coordinates for GX_VA_TEXx, but the client might provide + * three (along with an appropriate texture matrix). So, at + * least in those cases where these arrays coincide, we can + * support having three texture input coordinates. */ + if (r->has_same_data(vertex_reader)) { + r->set_tex_coord_source(GX_TG_POS); + } else if (normal_reader && + r->has_same_data(normal_reader)) { + r->set_tex_coord_source(GX_TG_NRM); + } else { + /* We could go on and check if this array has the same data + * of another texture array sent earlier in this same loop, + * but let's leave this optimisation for later. */ + r->setup_draw(); + r->set_tex_coord_source(GX_TG_TEX0 + sent_tex_arrays++); + s_tex_unit_mask |= (1 << i); + } } } } s_has_normals = has_normals; s_num_colors = num_colors; - s_tex_unit_mask = tex_unit_mask; + /* s_tex_unit_mask has been set in the loop above */ } void _ogx_arrays_process_element(int index) @@ -509,6 +542,11 @@ void _ogx_array_reader_process_element(OgxArrayReader *reader, int index) r->process_element(index); } +uint8_t _ogx_array_reader_get_tex_coord_source(OgxArrayReader *reader) +{ + return get_reader(reader)->tex_coord_source; +} + void _ogx_array_reader_read_pos3f(OgxArrayReader *reader, int index, float *pos) { diff --git a/src/arrays.h b/src/arrays.h index 934fb46..f104d86 100644 --- a/src/arrays.h +++ b/src/arrays.h @@ -54,6 +54,7 @@ void _ogx_arrays_process_element(int index); void _ogx_array_reader_enable_dup_color(OgxArrayReader *reader, bool dup_color); void _ogx_array_reader_process_element(OgxArrayReader *reader, int index); +uint8_t _ogx_array_reader_get_tex_coord_source(OgxArrayReader *reader); void _ogx_array_reader_read_pos3f(OgxArrayReader *reader, int index, float *pos); diff --git a/src/texture_unit.c b/src/texture_unit.c index 58ce64e..c4a3186 100644 --- a/src/texture_unit.c +++ b/src/texture_unit.c @@ -447,10 +447,6 @@ void _ogx_setup_texture_stages(u8 raster_reg_index, u8 channel) u8 prev_rgb = raster_rgb; u8 prev_alpha = raster_alpha; - /* This variable holds the number of enabled texture units for which the - * client provided texture coordinates (not generated, but literally a - * GX_VA_TEX* array was specified). */ - int units_with_coordinates = 0; for (int tex = 0; tex < MAX_TEXTURE_UNITS; tex++) { if (!(glparamstate.texture_enabled & (1 << tex))) continue; @@ -461,7 +457,8 @@ void _ogx_setup_texture_stages(u8 raster_reg_index, u8 channel) glparamstate.cs.texcoord_enabled & (1 << tex); u8 input_coordinates; if (has_texture_coordinates) { - input_coordinates = GX_TG_TEX0 + units_with_coordinates++; + input_coordinates = _ogx_array_reader_get_tex_coord_source( + &glparamstate.texcoord_array[tex]); } else if (!tu->gen_enabled) { warning("Skipping texture unit, since coordinates are missing."); continue; @@ -476,12 +473,19 @@ void _ogx_setup_texture_stages(u8 raster_reg_index, u8 channel) prev_rgb, prev_alpha, raster_rgb, raster_alpha, channel); - setup_texture_stage_matrix(tu, dtt_matrix); - if (tu->gen_enabled) { - setup_texture_gen(tu, tex_coord, dtt_matrix, input_coordinates); + if (input_coordinates == GX_TG_POS || input_coordinates == GX_TG_NRM) { + u8 matrix_src = GX_TEXMTX0 + _ogx_gpu_resources->texmtx_first++ * 3; + GX_LoadTexMtxImm(tu->matrix[tu->matrix_index], matrix_src, GX_MTX2x4); + GX_SetTexCoordGen(tex_coord, GX_TG_MTX2x4, + input_coordinates, matrix_src); } else { - GX_SetTexCoordGen2(tex_coord, GX_TG_MTX2x4, input_coordinates, - GX_IDENTITY, FALSE, dtt_matrix); + setup_texture_stage_matrix(tu, dtt_matrix); + if (tu->gen_enabled) { + setup_texture_gen(tu, tex_coord, dtt_matrix, input_coordinates); + } else { + GX_SetTexCoordGen2(tex_coord, GX_TG_MTX2x4, input_coordinates, + GX_IDENTITY, FALSE, dtt_matrix); + } } /* All texture stages after the first one get their vertex color from