From 1ce78dd9b411e520345faeca26288f322532919c Mon Sep 17 00:00:00 2001
From: iwubcode <iwubcode@users.noreply.github.com>
Date: Fri, 14 Feb 2025 22:44:49 -0600
Subject: [PATCH] VideoCommon: move texcoord calculations to accessible
 functions in VertexShaderGen

---
 Source/Core/VideoCommon/VertexShaderGen.cpp | 146 +++++++++++---------
 1 file changed, 80 insertions(+), 66 deletions(-)

diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp
index 4a46834c14..5512b0f1c4 100644
--- a/Source/Core/VideoCommon/VertexShaderGen.cpp
+++ b/Source/Core/VideoCommon/VertexShaderGen.cpp
@@ -74,6 +74,81 @@ VertexShaderUid GetVertexShaderUid()
   return out;
 }
 
+void WriteTexCoordTransforms(APIType api_type, const ShaderHostConfig& host_config,
+                             const vertex_shader_uid_data* uid_data, ShaderCode& out)
+{
+  for (u32 i = 0; i < uid_data->numTexGens; ++i)
+  {
+    auto& texinfo = uid_data->texMtxInfo[i];
+    out.Write("vec3 dolphin_transform_texcoord{}(vec4 coord)\n", i);
+    out.Write("{{\n");
+    if (texinfo.texgentype != TexGenType::Regular)
+    {
+      out.Write("\treturn vec3(coord.xyz);\n");
+    }
+    else
+    {
+      out.Write("\tvec3 result;\n");
+      if ((uid_data->components & (VB_HAS_TEXMTXIDX0 << i)) != 0)
+      {
+        out.Write("\tint tmp = int(rawtex{}.z);\n", i);
+        if (static_cast<TexSize>((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ)
+        {
+          out.Write("\tresult = vec3(dot(coord, " I_TRANSFORMMATRICES
+                    "[tmp]), dot(coord, " I_TRANSFORMMATRICES
+                    "[tmp+1]), dot(coord, " I_TRANSFORMMATRICES "[tmp+2]));\n");
+        }
+        else
+        {
+          out.Write("\tresult = vec3(dot(coord, " I_TRANSFORMMATRICES
+                    "[tmp]), dot(coord, " I_TRANSFORMMATRICES "[tmp+1]), 1);\n");
+        }
+      }
+      else
+      {
+        if (static_cast<TexSize>((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ)
+        {
+          out.Write("\tresult = vec3(dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES
+                    "[{}]), dot(coord, " I_TEXMATRICES "[{}]));\n",
+                    3 * i, 3 * i + 1, 3 * i + 2);
+        }
+        else
+        {
+          out.Write("\tresult = vec3(dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES
+                    "[{}]), 1);\n",
+                    3 * i, 3 * i + 1);
+        }
+      }
+      // CHECKME: does this only work for regular tex gen types?
+      if (uid_data->dualTexTrans_enabled)
+      {
+        auto& postInfo = uid_data->postMtxInfo[i];
+
+        out.Write("\tvec4 P0 = " I_POSTTRANSFORMMATRICES "[{}];\n"
+                  "\tvec4 P1 = " I_POSTTRANSFORMMATRICES "[{}];\n"
+                  "\tvec4 P2 = " I_POSTTRANSFORMMATRICES "[{}];\n",
+                  postInfo.index & 0x3f, (postInfo.index + 1) & 0x3f, (postInfo.index + 2) & 0x3f);
+
+        if (postInfo.normalize)
+          out.Write("\tresult = normalize(result);\n");
+
+        // multiply by postmatrix
+        out.Write("\tresult = vec3(dot(P0.xyz, result) + P0.w, dot(P1.xyz, result) + "
+                  "P1.w, dot(P2.xyz, result) + P2.w);\n");
+      }
+
+      // When q is 0, the GameCube appears to have a special case
+      // This can be seen in devkitPro's neheGX Lesson08 example for Wii
+      // Makes differences in Rogue Squadron 3 (Hoth sky) and The Last Story (shadow culling)
+      // TODO: check if this only affects XF_TEXGEN_REGULAR
+      out.Write("\tif(result.z == 0.0f)\n"
+                "\t\tresult.xy = clamp(result.xy / 2.0f, vec2(-1.0f,-1.0f), vec2(1.0f,1.0f));\n");
+      out.Write("\treturn result;\n");
+    }
+    out.Write("}}\n\n");
+  }
+}
+
 ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config,
                                     const vertex_shader_uid_data* uid_data)
 {
@@ -260,6 +335,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
     }
   }
 
+  WriteTexCoordTransforms(api_type, host_config, uid_data, out);
+
   out.Write("void main()\n{{\n");
 
   if (uid_data->vs_expand != VSExpand::None)
@@ -434,73 +511,10 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
       out.Write("o.tex{}.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i);
       break;
     case TexGenType::Regular:
-    default:
-      if ((uid_data->components & (VB_HAS_TEXMTXIDX0 << i)) != 0)
-      {
-        out.Write("int tmp = int(rawtex{}.z);\n", i);
-        if (static_cast<TexSize>((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ)
-        {
-          out.Write("o.tex{}.xyz = float3(dot(coord, " I_TRANSFORMMATRICES
-                    "[tmp]), dot(coord, " I_TRANSFORMMATRICES
-                    "[tmp+1]), dot(coord, " I_TRANSFORMMATRICES "[tmp+2]));\n",
-                    i);
-        }
-        else
-        {
-          out.Write("o.tex{}.xyz = float3(dot(coord, " I_TRANSFORMMATRICES
-                    "[tmp]), dot(coord, " I_TRANSFORMMATRICES "[tmp+1]), 1);\n",
-                    i);
-        }
-      }
-      else
-      {
-        if (static_cast<TexSize>((uid_data->texMtxInfo_n_projection >> i) & 1) == TexSize::STQ)
-        {
-          out.Write("o.tex{}.xyz = float3(dot(coord, " I_TEXMATRICES
-                    "[{}]), dot(coord, " I_TEXMATRICES "[{}]), dot(coord, " I_TEXMATRICES
-                    "[{}]));\n",
-                    i, 3 * i, 3 * i + 1, 3 * i + 2);
-        }
-        else
-        {
-          out.Write("o.tex{}.xyz = float3(dot(coord, " I_TEXMATRICES
-                    "[{}]), dot(coord, " I_TEXMATRICES "[{}]), 1);\n",
-                    i, 3 * i, 3 * i + 1);
-        }
-      }
+      out.Write("o.tex{0}.xyz = dolphin_transform_texcoord{0}(coord);\n", i);
       break;
-    }
-
-    // CHECKME: does this only work for regular tex gen types?
-    if (uid_data->dualTexTrans_enabled && texinfo.texgentype == TexGenType::Regular)
-    {
-      auto& postInfo = uid_data->postMtxInfo[i];
-
-      out.Write("float4 P0 = " I_POSTTRANSFORMMATRICES "[{}];\n"
-                "float4 P1 = " I_POSTTRANSFORMMATRICES "[{}];\n"
-                "float4 P2 = " I_POSTTRANSFORMMATRICES "[{}];\n",
-                postInfo.index & 0x3f, (postInfo.index + 1) & 0x3f, (postInfo.index + 2) & 0x3f);
-
-      if (postInfo.normalize)
-        out.Write("o.tex{}.xyz = normalize(o.tex{}.xyz);\n", i, i);
-
-      // multiply by postmatrix
-      out.Write(
-          "o.tex{0}.xyz = float3(dot(P0.xyz, o.tex{0}.xyz) + P0.w, dot(P1.xyz, o.tex{0}.xyz) + "
-          "P1.w, dot(P2.xyz, o.tex{0}.xyz) + P2.w);\n",
-          i);
-    }
-
-    // When q is 0, the GameCube appears to have a special case
-    // This can be seen in devkitPro's neheGX Lesson08 example for Wii
-    // Makes differences in Rogue Squadron 3 (Hoth sky) and The Last Story (shadow culling)
-    // TODO: check if this only affects XF_TEXGEN_REGULAR
-    if (texinfo.texgentype == TexGenType::Regular)
-    {
-      out.Write(
-          "if(o.tex{0}.z == 0.0f)\n"
-          "\to.tex{0}.xy = clamp(o.tex{0}.xy / 2.0f, float2(-1.0f,-1.0f), float2(1.0f,1.0f));\n",
-          i);
+    default:
+      ASSERT(false);
     }
 
     out.Write("}}\n");