| File: | Source/Core/VideoCommon/Src/VertexShaderGen.cpp |
| Location: | line 106, column 5 |
| Description: | Value stored to 'ptr' is never read |
| 1 | // Copyright 2013 Dolphin Emulator Project |
| 2 | // Licensed under GPLv2 |
| 3 | // Refer to the license.txt file included. |
| 4 | |
| 5 | #include <math.h> |
| 6 | #include <locale.h> |
| 7 | |
| 8 | #include "NativeVertexFormat.h" |
| 9 | |
| 10 | #include "BPMemory.h" |
| 11 | #include "CPMemory.h" |
| 12 | #include "LightingShaderGen.h" |
| 13 | #include "VertexShaderGen.h" |
| 14 | #include "VideoConfig.h" |
| 15 | |
| 16 | // Mash together all the inputs that contribute to the code of a generated vertex shader into |
| 17 | // a unique identifier, basically containing all the bits. Yup, it's a lot .... |
| 18 | void GetVertexShaderId(VERTEXSHADERUID *uid, u32 components) |
| 19 | { |
| 20 | memset(uid->values, 0, sizeof(uid->values)); |
| 21 | uid->values[0] = components | |
| 22 | (xfregs.numTexGen.numTexGens << 23) | |
| 23 | (xfregs.numChan.numColorChans << 27) | |
| 24 | (xfregs.dualTexTrans.enabled << 29); |
| 25 | |
| 26 | // TODO: If pixel lighting is enabled, do we even have to bother about storing lighting related registers here? |
| 27 | GetLightingShaderId(&uid->values[1]); |
| 28 | |
| 29 | uid->values[2] |= (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) << 31; |
| 30 | u32 *pcurvalue = &uid->values[3]; |
| 31 | for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) |
| 32 | { |
| 33 | TexMtxInfo tinfo = xfregs.texMtxInfo[i]; |
| 34 | if (tinfo.texgentype != XF_TEXGEN_EMBOSS_MAP1) |
| 35 | tinfo.hex &= 0x7ff; |
| 36 | if (tinfo.texgentype != XF_TEXGEN_REGULAR0) |
| 37 | tinfo.projection = 0; |
| 38 | |
| 39 | u32 val = ((tinfo.hex >> 1) & 0x1ffff); |
| 40 | if (xfregs.dualTexTrans.enabled && tinfo.texgentype == XF_TEXGEN_REGULAR0) |
| 41 | { |
| 42 | // rewrite normalization and post index |
| 43 | val |= ((u32)xfregs.postMtxInfo[i].index << 17) | ((u32)xfregs.postMtxInfo[i].normalize << 23); |
| 44 | } |
| 45 | |
| 46 | switch (i & 3) |
| 47 | { |
| 48 | case 0: pcurvalue[0] |= val; break; |
| 49 | case 1: pcurvalue[0] |= val << 24; pcurvalue[1] = val >> 8; ++pcurvalue; break; |
| 50 | case 2: pcurvalue[0] |= val << 16; pcurvalue[1] = val >> 16; ++pcurvalue; break; |
| 51 | case 3: pcurvalue[0] |= val << 8; ++pcurvalue; break; |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | void GetSafeVertexShaderId(VERTEXSHADERUIDSAFE *uid, u32 components) |
| 57 | { |
| 58 | // Just store all used registers here without caring whether we need all bits or less. |
| 59 | memset(uid->values, 0, sizeof(uid->values)); |
| 60 | u32* ptr = uid->values; |
| 61 | *ptr++ = components; |
| 62 | *ptr++ = xfregs.numTexGen.hex; |
| 63 | *ptr++ = xfregs.numChan.hex; |
| 64 | *ptr++ = xfregs.dualTexTrans.hex; |
| 65 | |
| 66 | for (int i = 0; i < 2; ++i) |
| 67 | { |
| 68 | *ptr++ = xfregs.color[i].hex; |
| 69 | *ptr++ = xfregs.alpha[i].hex; |
| 70 | } |
| 71 | |
| 72 | *ptr++ = g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting; |
| 73 | |
| 74 | for (unsigned int i = 0; i < 8; ++i) |
| 75 | { |
| 76 | *ptr++ = xfregs.texMtxInfo[i].hex; |
| 77 | *ptr++ = xfregs.postMtxInfo[i].hex; |
| 78 | } |
| 79 | _assert_((ptr - uid->values) == uid->GetNumValues()){}; |
| 80 | } |
| 81 | |
| 82 | |
| 83 | void ValidateVertexShaderIDs(API_TYPE api, VERTEXSHADERUIDSAFE old_id, const std::string& old_code, u32 components) |
| 84 | { |
| 85 | if (!g_ActiveConfig.bEnableShaderDebugging) |
| 86 | return; |
| 87 | |
| 88 | VERTEXSHADERUIDSAFE new_id; |
| 89 | GetSafeVertexShaderId(&new_id, components); |
| 90 | |
| 91 | if (!(old_id == new_id)) |
| 92 | { |
| 93 | std::string new_code(GenerateVertexShaderCode(components, api)); |
| 94 | if (old_code != new_code) |
| 95 | { |
| 96 | _assert_(old_id.GetNumValues() == new_id.GetNumValues()){}; |
| 97 | |
| 98 | char msg[8192]; |
| 99 | char* ptr = msg; |
| 100 | ptr += sprintf(ptr, "Vertex shader IDs matched but unique IDs did not!\nUnique IDs (old <-> new):\n"); |
| 101 | const int N = new_id.GetNumValues(); |
| 102 | for (int i = 0; i < N/2; ++i) |
| 103 | ptr += sprintf(ptr, "%02d, %08X %08X | %08X %08X\n", 2*i, old_id.values[2*i], old_id.values[2*i+1], |
| 104 | new_id.values[2*i], new_id.values[2*i+1]); |
| 105 | if (N % 2) |
| 106 | ptr += sprintf(ptr, "%02d, %08X | %08X\n", N-1, old_id.values[N-1], new_id.values[N-1]); |
Value stored to 'ptr' is never read | |
| 107 | |
| 108 | static int num_failures = 0; |
| 109 | char szTemp[MAX_PATH4096]; |
| 110 | sprintf(szTemp, "%svsuid_mismatch_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); |
| 111 | std::ofstream file; |
| 112 | OpenFStream(file, szTemp, std::ios_base::out); |
| 113 | file << msg; |
| 114 | file << "\n\nOld shader code:\n" << old_code; |
| 115 | file << "\n\nNew shader code:\n" << new_code; |
| 116 | file.close(); |
| 117 | |
| 118 | PanicAlert("Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s.", szTemp)MsgAlert(false, WARNING, "Unique pixel shader ID mismatch!\n\nReport this to the devs, along with the contents of %s." , szTemp); |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | |
| 124 | static char text[16384]; |
| 125 | |
| 126 | #define WRITEp+=sprintf p+=sprintf |
| 127 | |
| 128 | char* GenerateVSOutputStruct(char* p, u32 components, API_TYPE ApiType) |
| 129 | { |
| 130 | |
| 131 | // "centroid" attribute is only supported by D3D11 |
| 132 | const char* optCentroid = (ApiType == API_D3D11 ? "centroid" : ""); |
| 133 | |
| 134 | // GLSL makes this ugly |
| 135 | // TODO: Make pretty |
| 136 | WRITEp+=sprintf(p, "struct VS_OUTPUT {\n"); |
| 137 | WRITEp+=sprintf(p, " %s float4 pos %s POSITION;\n", optCentroid, ApiType == API_OPENGL ? ";//" : ":"); |
| 138 | WRITEp+=sprintf(p, " %s float4 colors_0 %s COLOR0;\n", optCentroid, ApiType == API_OPENGL ? ";//" : ":"); |
| 139 | WRITEp+=sprintf(p, " %s float4 colors_1 %s COLOR1;\n", optCentroid, ApiType == API_OPENGL ? ";//" : ":"); |
| 140 | |
| 141 | if (xfregs.numTexGen.numTexGens < 7) |
| 142 | { |
| 143 | for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) |
| 144 | WRITEp+=sprintf(p, " %s float3 tex%d %s TEXCOORD%d;\n", optCentroid, i, ApiType == API_OPENGL ? ";//" : ":", i); |
| 145 | |
| 146 | WRITEp+=sprintf(p, " %s float4 clipPos %s TEXCOORD%d;\n", optCentroid, ApiType == API_OPENGL ? ";//" : ":", xfregs.numTexGen.numTexGens); |
| 147 | |
| 148 | if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 149 | WRITEp+=sprintf(p, " %s float4 Normal %s TEXCOORD%d;\n", optCentroid, ApiType == API_OPENGL ? ";//" : ":", xfregs.numTexGen.numTexGens + 1); |
| 150 | } |
| 151 | else |
| 152 | { |
| 153 | // clip position is in w of first 4 texcoords |
| 154 | if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 155 | { |
| 156 | for (int i = 0; i < 8; ++i) |
| 157 | WRITEp+=sprintf(p, " %s float4 tex%d %s TEXCOORD%d;\n", optCentroid, i, ApiType == API_OPENGL? ";//" : ":", i); |
| 158 | } |
| 159 | else |
| 160 | { |
| 161 | for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) |
| 162 | WRITEp+=sprintf(p, " %s float%d tex%d %s TEXCOORD%d;\n", optCentroid, i < 4 ? 4 : 3 , i, ApiType == API_OPENGL ? ";//" : ":", i); |
| 163 | } |
| 164 | } |
| 165 | WRITEp+=sprintf(p, "};\n"); |
| 166 | |
| 167 | return p; |
| 168 | } |
| 169 | |
| 170 | extern const char* WriteRegister(API_TYPE ApiType, const char *prefix, const u32 num); |
| 171 | extern const char *WriteLocation(API_TYPE ApiType); |
| 172 | |
| 173 | const char *GenerateVertexShaderCode(u32 components, API_TYPE ApiType) |
| 174 | { |
| 175 | setlocale(LC_NUMERIC1, "C"); // Reset locale for compilation |
| 176 | text[sizeof(text) - 1] = 0x7C; // canary |
| 177 | |
| 178 | _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens){}; |
| 179 | _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans){}; |
| 180 | |
| 181 | bool is_d3d = (ApiType & API_D3D9 || ApiType == API_D3D11); |
| 182 | u32 lightMask = 0; |
| 183 | if (xfregs.numChan.numColorChans > 0) |
| 184 | lightMask |= xfregs.color[0].GetFullLightMask() | xfregs.alpha[0].GetFullLightMask(); |
| 185 | if (xfregs.numChan.numColorChans > 1) |
| 186 | lightMask |= xfregs.color[1].GetFullLightMask() | xfregs.alpha[1].GetFullLightMask(); |
| 187 | |
| 188 | char *p = text; |
| 189 | WRITEp+=sprintf(p, "//Vertex Shader: comp:%x, \n", components); |
| 190 | |
| 191 | // uniforms |
| 192 | if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) |
| 193 | WRITEp+=sprintf(p, "layout(std140) uniform VSBlock {\n"); |
| 194 | |
| 195 | WRITEp+=sprintf(p, "%sfloat4 " I_POSNORMALMATRIX"cpnmtx""[6] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_POSNORMALMATRIX0)); |
| 196 | WRITEp+=sprintf(p, "%sfloat4 " I_PROJECTION"cproj""[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_PROJECTION(0 + 6))); |
| 197 | WRITEp+=sprintf(p, "%sfloat4 " I_MATERIALS"cmtrl""[4] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_MATERIALS((0 + 6) + 4))); |
| 198 | WRITEp+=sprintf(p, "%sfloat4 " I_LIGHTS"clights""[40] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_LIGHTS(((0 + 6) + 4) + 4))); |
| 199 | WRITEp+=sprintf(p, "%sfloat4 " I_TEXMATRICES"ctexmtx""[24] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_TEXMATRICES((((0 + 6) + 4) + 4) + 40))); // also using tex matrices |
| 200 | WRITEp+=sprintf(p, "%sfloat4 " I_TRANSFORMMATRICES"ctrmtx""[64] %s;\n", WriteLocation(ApiType),WriteRegister(ApiType, "c", C_TRANSFORMMATRICES(((((0 + 6) + 4) + 4) + 40) + 24))); |
| 201 | WRITEp+=sprintf(p, "%sfloat4 " I_NORMALMATRICES"cnmtx""[32] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_NORMALMATRICES((((((0 + 6) + 4) + 4) + 40) + 24) + 64))); |
| 202 | WRITEp+=sprintf(p, "%sfloat4 " I_POSTTRANSFORMMATRICES"cpostmtx""[64] %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_POSTTRANSFORMMATRICES(((((((0 + 6) + 4) + 4) + 40) + 24) + 64) + 32))); |
| 203 | WRITEp+=sprintf(p, "%sfloat4 " I_DEPTHPARAMS"cDepth"" %s;\n", WriteLocation(ApiType), WriteRegister(ApiType, "c", C_DEPTHPARAMS((((((((0 + 6) + 4) + 4) + 40) + 24) + 64) + 32) + 64))); |
| 204 | |
| 205 | if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) |
| 206 | WRITEp+=sprintf(p, "};\n"); |
| 207 | |
| 208 | p = GenerateVSOutputStruct(p, components, ApiType); |
| 209 | |
| 210 | if(ApiType == API_OPENGL) |
| 211 | { |
| 212 | WRITEp+=sprintf(p, "ATTRIN float4 rawpos; // ATTR%d,\n", SHADER_POSITION_ATTRIB0); |
| 213 | if (components & VB_HAS_POSMTXIDX) |
| 214 | WRITEp+=sprintf(p, "ATTRIN float fposmtx; // ATTR%d,\n", SHADER_POSMTX_ATTRIB1); |
| 215 | if (components & VB_HAS_NRM0) |
| 216 | WRITEp+=sprintf(p, "ATTRIN float3 rawnorm0; // ATTR%d,\n", SHADER_NORM0_ATTRIB2); |
| 217 | if (components & VB_HAS_NRM1) |
| 218 | WRITEp+=sprintf(p, "ATTRIN float3 rawnorm1; // ATTR%d,\n", SHADER_NORM1_ATTRIB3); |
| 219 | if (components & VB_HAS_NRM2) |
| 220 | WRITEp+=sprintf(p, "ATTRIN float3 rawnorm2; // ATTR%d,\n", SHADER_NORM2_ATTRIB4); |
| 221 | |
| 222 | if (components & VB_HAS_COL0) |
| 223 | WRITEp+=sprintf(p, "ATTRIN float4 color0; // ATTR%d,\n", SHADER_COLOR0_ATTRIB5); |
| 224 | if (components & VB_HAS_COL1) |
| 225 | WRITEp+=sprintf(p, "ATTRIN float4 color1; // ATTR%d,\n", SHADER_COLOR1_ATTRIB6); |
| 226 | |
| 227 | for (int i = 0; i < 8; ++i) |
| 228 | { |
| 229 | u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<<i)); |
| 230 | if ((components & (VB_HAS_UV0<<i)) || hastexmtx) |
| 231 | WRITEp+=sprintf(p, "ATTRIN float%d tex%d; // ATTR%d,\n", hastexmtx ? 3 : 2, i, SHADER_TEXTURE0_ATTRIB8 + i); |
| 232 | } |
| 233 | |
| 234 | // Let's set up attributes |
| 235 | if (xfregs.numTexGen.numTexGens < 7) |
| 236 | { |
| 237 | for (int i = 0; i < 8; ++i) |
| 238 | WRITEp+=sprintf(p, "VARYOUT float3 uv%d_2;\n", i); |
| 239 | WRITEp+=sprintf(p, "VARYOUT float4 clipPos_2;\n"); |
| 240 | if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 241 | WRITEp+=sprintf(p, "VARYOUT float4 Normal_2;\n"); |
| 242 | } |
| 243 | else |
| 244 | { |
| 245 | // wpos is in w of first 4 texcoords |
| 246 | if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 247 | { |
| 248 | for (int i = 0; i < 8; ++i) |
| 249 | WRITEp+=sprintf(p, "VARYOUT float4 uv%d_2;\n", i); |
| 250 | } |
| 251 | else |
| 252 | { |
| 253 | for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) |
| 254 | WRITEp+=sprintf(p, "VARYOUT float%d uv%d_2;\n", i < 4 ? 4 : 3 , i); |
| 255 | } |
| 256 | } |
| 257 | WRITEp+=sprintf(p, "VARYOUT float4 colors_02;\n"); |
| 258 | WRITEp+=sprintf(p, "VARYOUT float4 colors_12;\n"); |
| 259 | |
| 260 | WRITEp+=sprintf(p, "void main()\n{\n"); |
| 261 | } |
| 262 | else |
| 263 | { |
| 264 | WRITEp+=sprintf(p, "VS_OUTPUT main(\n"); |
| 265 | |
| 266 | // inputs |
| 267 | if (components & VB_HAS_NRM0) |
| 268 | WRITEp+=sprintf(p, " float3 rawnorm0 : NORMAL0,\n"); |
| 269 | if (components & VB_HAS_NRM1) |
| 270 | { |
| 271 | if (is_d3d) |
| 272 | WRITEp+=sprintf(p, " float3 rawnorm1 : NORMAL1,\n"); |
| 273 | else |
| 274 | WRITEp+=sprintf(p, " float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB3); |
| 275 | } |
| 276 | if (components & VB_HAS_NRM2) |
| 277 | { |
| 278 | if (is_d3d) |
| 279 | WRITEp+=sprintf(p, " float3 rawnorm2 : NORMAL2,\n"); |
| 280 | else |
| 281 | WRITEp+=sprintf(p, " float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB4); |
| 282 | } |
| 283 | if (components & VB_HAS_COL0) |
| 284 | { |
| 285 | WRITEp+=sprintf(p, " float4 color0 : COLOR0,\n"); |
| 286 | } |
| 287 | if (components & VB_HAS_COL1) |
| 288 | { |
| 289 | WRITEp+=sprintf(p, " float4 color1 : COLOR1,\n"); |
| 290 | } |
| 291 | for (int i = 0; i < 8; ++i) |
| 292 | { |
| 293 | u32 hastexmtx = (components & (VB_HAS_TEXMTXIDX0<<i)); |
| 294 | if ((components & (VB_HAS_UV0<<i)) || hastexmtx) |
| 295 | WRITEp+=sprintf(p, " float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i); |
| 296 | } |
| 297 | if (components & VB_HAS_POSMTXIDX) |
| 298 | { |
| 299 | if (is_d3d) |
| 300 | WRITEp+=sprintf(p, " float4 blend_indices : BLENDINDICES,\n"); |
| 301 | else |
| 302 | WRITEp+=sprintf(p, " float fposmtx : ATTR%d,\n", SHADER_POSMTX_ATTRIB1); |
| 303 | } |
| 304 | WRITEp+=sprintf(p, " float4 rawpos : POSITION) {\n"); |
| 305 | } |
| 306 | WRITEp+=sprintf(p, "VS_OUTPUT o;\n"); |
| 307 | |
| 308 | // transforms |
| 309 | if (components & VB_HAS_POSMTXIDX) |
| 310 | { |
| 311 | if (ApiType & API_D3D9) |
| 312 | { |
| 313 | WRITEp+=sprintf(p, "int4 indices = D3DCOLORtoUBYTE4(blend_indices);\n"); |
| 314 | WRITEp+=sprintf(p, "int posmtx = indices.x;\n"); |
| 315 | } |
| 316 | else if (ApiType == API_D3D11) |
| 317 | { |
| 318 | WRITEp+=sprintf(p, "int posmtx = blend_indices.x * 255.0f;\n"); |
| 319 | } |
| 320 | else |
| 321 | { |
| 322 | WRITEp+=sprintf(p, "int posmtx = int(fposmtx);\n"); |
| 323 | } |
| 324 | |
| 325 | WRITEp+=sprintf(p, "float4 pos = float4(dot(" I_TRANSFORMMATRICES"ctrmtx""[posmtx], rawpos), dot(" I_TRANSFORMMATRICES"ctrmtx""[posmtx+1], rawpos), dot(" I_TRANSFORMMATRICES"ctrmtx""[posmtx+2], rawpos), 1);\n"); |
| 326 | |
| 327 | if (components & VB_HAS_NRMALL) { |
| 328 | WRITEp+=sprintf(p, "int normidx = posmtx >= 32 ? (posmtx-32) : posmtx;\n"); |
| 329 | WRITEp+=sprintf(p, "float3 N0 = " I_NORMALMATRICES"cnmtx""[normidx].xyz, N1 = " I_NORMALMATRICES"cnmtx""[normidx+1].xyz, N2 = " I_NORMALMATRICES"cnmtx""[normidx+2].xyz;\n"); |
| 330 | } |
| 331 | |
| 332 | if (components & VB_HAS_NRM0) |
| 333 | WRITEp+=sprintf(p, "float3 _norm0 = normalize(float3(dot(N0, rawnorm0), dot(N1, rawnorm0), dot(N2, rawnorm0)));\n"); |
| 334 | if (components & VB_HAS_NRM1) |
| 335 | WRITEp+=sprintf(p, "float3 _norm1 = float3(dot(N0, rawnorm1), dot(N1, rawnorm1), dot(N2, rawnorm1));\n"); |
| 336 | if (components & VB_HAS_NRM2) |
| 337 | WRITEp+=sprintf(p, "float3 _norm2 = float3(dot(N0, rawnorm2), dot(N1, rawnorm2), dot(N2, rawnorm2));\n"); |
| 338 | } |
| 339 | else |
| 340 | { |
| 341 | WRITEp+=sprintf(p, "float4 pos = float4(dot(" I_POSNORMALMATRIX"cpnmtx""[0], rawpos), dot(" I_POSNORMALMATRIX"cpnmtx""[1], rawpos), dot(" I_POSNORMALMATRIX"cpnmtx""[2], rawpos), 1.0f);\n"); |
| 342 | if (components & VB_HAS_NRM0) |
| 343 | WRITEp+=sprintf(p, "float3 _norm0 = normalize(float3(dot(" I_POSNORMALMATRIX"cpnmtx""[3].xyz, rawnorm0), dot(" I_POSNORMALMATRIX"cpnmtx""[4].xyz, rawnorm0), dot(" I_POSNORMALMATRIX"cpnmtx""[5].xyz, rawnorm0)));\n"); |
| 344 | if (components & VB_HAS_NRM1) |
| 345 | WRITEp+=sprintf(p, "float3 _norm1 = float3(dot(" I_POSNORMALMATRIX"cpnmtx""[3].xyz, rawnorm1), dot(" I_POSNORMALMATRIX"cpnmtx""[4].xyz, rawnorm1), dot(" I_POSNORMALMATRIX"cpnmtx""[5].xyz, rawnorm1));\n"); |
| 346 | if (components & VB_HAS_NRM2) |
| 347 | WRITEp+=sprintf(p, "float3 _norm2 = float3(dot(" I_POSNORMALMATRIX"cpnmtx""[3].xyz, rawnorm2), dot(" I_POSNORMALMATRIX"cpnmtx""[4].xyz, rawnorm2), dot(" I_POSNORMALMATRIX"cpnmtx""[5].xyz, rawnorm2));\n"); |
| 348 | } |
| 349 | |
| 350 | if (!(components & VB_HAS_NRM0)) |
| 351 | WRITEp+=sprintf(p, "float3 _norm0 = float3(0.0f, 0.0f, 0.0f);\n"); |
| 352 | |
| 353 | WRITEp+=sprintf(p, "o.pos = float4(dot(" I_PROJECTION"cproj""[0], pos), dot(" I_PROJECTION"cproj""[1], pos), dot(" I_PROJECTION"cproj""[2], pos), dot(" I_PROJECTION"cproj""[3], pos));\n"); |
| 354 | |
| 355 | WRITEp+=sprintf(p, "float4 mat, lacc;\n" |
| 356 | "float3 ldir, h;\n" |
| 357 | "float dist, dist2, attn;\n"); |
| 358 | |
| 359 | if (xfregs.numChan.numColorChans == 0) |
| 360 | { |
| 361 | if (components & VB_HAS_COL0) |
| 362 | WRITEp+=sprintf(p, "o.colors_0 = color0;\n"); |
| 363 | else |
| 364 | WRITEp+=sprintf(p, "o.colors_0 = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); |
| 365 | } |
| 366 | |
| 367 | // TODO: This probably isn't necessary if pixel lighting is enabled. |
| 368 | p = GenerateLightingShader(p, components, I_MATERIALS"cmtrl", I_LIGHTS"clights", "color", "o.colors_"); |
| 369 | |
| 370 | if (xfregs.numChan.numColorChans < 2) |
| 371 | { |
| 372 | if (components & VB_HAS_COL1) |
| 373 | WRITEp+=sprintf(p, "o.colors_1 = color1;\n"); |
| 374 | else |
| 375 | WRITEp+=sprintf(p, "o.colors_1 = o.colors_0;\n"); |
| 376 | } |
| 377 | // special case if only pos and tex coord 0 and tex coord input is AB11 |
| 378 | // donko - this has caused problems in some games. removed for now. |
| 379 | bool texGenSpecialCase = false; |
| 380 | /*bool texGenSpecialCase = |
| 381 | ((g_VtxDesc.Hex & 0x60600L) == g_VtxDesc.Hex) && // only pos and tex coord 0 |
| 382 | (g_VtxDesc.Tex0Coord != NOT_PRESENT) && |
| 383 | (xfregs.texcoords[0].texmtxinfo.inputform == XF_TEXINPUT_AB11); |
| 384 | */ |
| 385 | |
| 386 | // transform texcoords |
| 387 | WRITEp+=sprintf(p, "float4 coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); |
| 388 | for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) |
| 389 | { |
| 390 | TexMtxInfo& texinfo = xfregs.texMtxInfo[i]; |
| 391 | |
| 392 | WRITEp+=sprintf(p, "{\n"); |
| 393 | WRITEp+=sprintf(p, "coord = float4(0.0f, 0.0f, 1.0f, 1.0f);\n"); |
| 394 | |
| 395 | switch (texinfo.sourcerow) |
| 396 | { |
| 397 | case XF_SRCGEOM_INROW0: |
| 398 | _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ){}; |
| 399 | WRITEp+=sprintf(p, "coord = rawpos;\n"); // pos.w is 1 |
| 400 | break; |
| 401 | case XF_SRCNORMAL_INROW1: |
| 402 | if (components & VB_HAS_NRM0) |
| 403 | { |
| 404 | _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ){}; |
| 405 | WRITEp+=sprintf(p, "coord = float4(rawnorm0.xyz, 1.0f);\n"); |
| 406 | } |
| 407 | break; |
| 408 | case XF_SRCCOLORS_INROW2: |
| 409 | _assert_( texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC0 || texinfo.texgentype == XF_TEXGEN_COLOR_STRGBC1 ){}; |
| 410 | break; |
| 411 | case XF_SRCBINORMAL_T_INROW3: |
| 412 | if (components & VB_HAS_NRM1) |
| 413 | { |
| 414 | _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ){}; |
| 415 | WRITEp+=sprintf(p, "coord = float4(rawnorm1.xyz, 1.0f);\n"); |
| 416 | } |
| 417 | break; |
| 418 | case XF_SRCBINORMAL_B_INROW4: |
| 419 | if (components & VB_HAS_NRM2) |
| 420 | { |
| 421 | _assert_( texinfo.inputform == XF_TEXINPUT_ABC1 ){}; |
| 422 | WRITEp+=sprintf(p, "coord = float4(rawnorm2.xyz, 1.0f);\n"); |
| 423 | } |
| 424 | break; |
| 425 | default: |
| 426 | _assert_(texinfo.sourcerow <= XF_SRCTEX7_INROW){}; |
| 427 | if (components & (VB_HAS_UV0<<(texinfo.sourcerow - XF_SRCTEX0_INROW5)) ) |
| 428 | WRITEp+=sprintf(p, "coord = float4(tex%d.x, tex%d.y, 1.0f, 1.0f);\n", texinfo.sourcerow - XF_SRCTEX0_INROW5, texinfo.sourcerow - XF_SRCTEX0_INROW5); |
| 429 | break; |
| 430 | } |
| 431 | |
| 432 | // first transformation |
| 433 | switch (texinfo.texgentype) |
| 434 | { |
| 435 | case XF_TEXGEN_EMBOSS_MAP1: // calculate tex coords into bump map |
| 436 | |
| 437 | if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) |
| 438 | { |
| 439 | // transform the light dir into tangent space |
| 440 | WRITEp+=sprintf(p, "ldir = normalize(" I_LIGHTS"clights""[5*%d + 3].xyz - pos.xyz);\n", texinfo.embosslightshift); |
| 441 | WRITEp+=sprintf(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); |
| 442 | } |
| 443 | else |
| 444 | { |
| 445 | _assert_(0){}; // should have normals |
| 446 | WRITEp+=sprintf(p, "o.tex%d.xyz = o.tex%d.xyz;\n", i, texinfo.embosssourceshift); |
| 447 | } |
| 448 | |
| 449 | break; |
| 450 | case XF_TEXGEN_COLOR_STRGBC02: |
| 451 | _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW){}; |
| 452 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(o.colors_0.x, o.colors_0.y, 1);\n", i); |
| 453 | break; |
| 454 | case XF_TEXGEN_COLOR_STRGBC13: |
| 455 | _assert_(texinfo.sourcerow == XF_SRCCOLORS_INROW){}; |
| 456 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(o.colors_1.x, o.colors_1.y, 1);\n", i); |
| 457 | break; |
| 458 | case XF_TEXGEN_REGULAR0: |
| 459 | default: |
| 460 | if (components & (VB_HAS_TEXMTXIDX0<<i)) |
| 461 | { |
| 462 | WRITEp+=sprintf(p, "int tmp = int(tex%d.z);\n", i); |
| 463 | if (texinfo.projection == XF_TEXPROJ_STQ1) |
| 464 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES"ctrmtx""[tmp]), dot(coord, " I_TRANSFORMMATRICES"ctrmtx""[tmp+1]), dot(coord, " I_TRANSFORMMATRICES"ctrmtx""[tmp+2]));\n", i); |
| 465 | else |
| 466 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES"ctrmtx""[tmp]), dot(coord, " I_TRANSFORMMATRICES"ctrmtx""[tmp+1]), 1);\n", i); |
| 467 | } |
| 468 | else |
| 469 | { |
| 470 | if (texinfo.projection == XF_TEXPROJ_STQ1) |
| 471 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES"ctexmtx""[%d]), dot(coord, " I_TEXMATRICES"ctexmtx""[%d]), dot(coord, " I_TEXMATRICES"ctexmtx""[%d]));\n", i, 3*i, 3*i+1, 3*i+2); |
| 472 | else |
| 473 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES"ctexmtx""[%d]), dot(coord, " I_TEXMATRICES"ctexmtx""[%d]), 1);\n", i, 3*i, 3*i+1); |
| 474 | } |
| 475 | break; |
| 476 | } |
| 477 | |
| 478 | // CHECKME: does this only work for regular tex gen types? |
| 479 | if (xfregs.dualTexTrans.enabled && texinfo.texgentype == XF_TEXGEN_REGULAR0) |
| 480 | { |
| 481 | const PostMtxInfo& postInfo = xfregs.postMtxInfo[i]; |
| 482 | |
| 483 | int postidx = postInfo.index; |
| 484 | WRITEp+=sprintf(p, "float4 P0 = " I_POSTTRANSFORMMATRICES"cpostmtx""[%d];\n" |
| 485 | "float4 P1 = " I_POSTTRANSFORMMATRICES"cpostmtx""[%d];\n" |
| 486 | "float4 P2 = " I_POSTTRANSFORMMATRICES"cpostmtx""[%d];\n", |
| 487 | postidx&0x3f, (postidx+1)&0x3f, (postidx+2)&0x3f); |
| 488 | |
| 489 | if (texGenSpecialCase) |
| 490 | { |
| 491 | // no normalization |
| 492 | // q of input is 1 |
| 493 | // q of output is unknown |
| 494 | |
| 495 | // multiply by postmatrix |
| 496 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(dot(P0.xy, o.tex%d.xy) + P0.z + P0.w, dot(P1.xy, o.tex%d.xy) + P1.z + P1.w, 0.0f);\n", i, i, i); |
| 497 | } |
| 498 | else |
| 499 | { |
| 500 | if (postInfo.normalize) |
| 501 | WRITEp+=sprintf(p, "o.tex%d.xyz = normalize(o.tex%d.xyz);\n", i, i); |
| 502 | |
| 503 | // multiply by postmatrix |
| 504 | WRITEp+=sprintf(p, "o.tex%d.xyz = float3(dot(P0.xyz, o.tex%d.xyz) + P0.w, dot(P1.xyz, o.tex%d.xyz) + P1.w, dot(P2.xyz, o.tex%d.xyz) + P2.w);\n", i, i, i, i); |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | WRITEp+=sprintf(p, "}\n"); |
| 509 | } |
| 510 | |
| 511 | // clipPos/w needs to be done in pixel shader, not here |
| 512 | if (xfregs.numTexGen.numTexGens < 7) |
| 513 | { |
| 514 | WRITEp+=sprintf(p, "o.clipPos = float4(pos.x,pos.y,o.pos.z,o.pos.w);\n"); |
| 515 | } |
| 516 | else |
| 517 | { |
| 518 | WRITEp+=sprintf(p, "o.tex0.w = pos.x;\n"); |
| 519 | WRITEp+=sprintf(p, "o.tex1.w = pos.y;\n"); |
| 520 | WRITEp+=sprintf(p, "o.tex2.w = o.pos.z;\n"); |
| 521 | WRITEp+=sprintf(p, "o.tex3.w = o.pos.w;\n"); |
| 522 | } |
| 523 | |
| 524 | if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 525 | { |
| 526 | if (xfregs.numTexGen.numTexGens < 7) |
| 527 | { |
| 528 | WRITEp+=sprintf(p, "o.Normal = float4(_norm0.x,_norm0.y,_norm0.z,pos.z);\n"); |
| 529 | } |
| 530 | else |
| 531 | { |
| 532 | WRITEp+=sprintf(p, "o.tex4.w = _norm0.x;\n"); |
| 533 | WRITEp+=sprintf(p, "o.tex5.w = _norm0.y;\n"); |
| 534 | WRITEp+=sprintf(p, "o.tex6.w = _norm0.z;\n"); |
| 535 | if (xfregs.numTexGen.numTexGens < 8) |
| 536 | WRITEp+=sprintf(p, "o.tex7 = pos.xyzz;\n"); |
| 537 | else |
| 538 | WRITEp+=sprintf(p, "o.tex7.w = pos.z;\n"); |
| 539 | } |
| 540 | |
| 541 | if (components & VB_HAS_COL0) |
| 542 | WRITEp+=sprintf(p, "o.colors_0 = color0;\n"); |
| 543 | |
| 544 | if (components & VB_HAS_COL1) |
| 545 | WRITEp+=sprintf(p, "o.colors_1 = color1;\n"); |
| 546 | } |
| 547 | |
| 548 | //write the true depth value, if the game uses depth textures pixel shaders will override with the correct values |
| 549 | //if not early z culling will improve speed |
| 550 | if (is_d3d) |
| 551 | { |
| 552 | WRITEp+=sprintf(p, "o.pos.z = " I_DEPTHPARAMS"cDepth"".x * o.pos.w + o.pos.z * " I_DEPTHPARAMS"cDepth"".y;\n"); |
| 553 | } |
| 554 | else |
| 555 | { |
| 556 | // this results in a scale from -1..0 to -1..1 after perspective |
| 557 | // divide |
| 558 | WRITEp+=sprintf(p, "o.pos.z = o.pos.w + o.pos.z * 2.0f;\n"); |
| 559 | |
| 560 | // Sonic Unleashed puts its final rendering at the near or |
| 561 | // far plane of the viewing frustrum(actually box, they use |
| 562 | // orthogonal projection for that), and we end up putting it |
| 563 | // just beyond, and the rendering gets clipped away. (The |
| 564 | // primitive gets dropped) |
| 565 | WRITEp+=sprintf(p, "o.pos.z = o.pos.z * 1048575.0f/1048576.0f;\n"); |
| 566 | |
| 567 | // the next steps of the OGL pipeline are: |
| 568 | // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology |
| 569 | // clipping to -w_c <= (x_c,y_c,z_c) <= w_c |
| 570 | // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide |
| 571 | // z_w = (f-n)/2*z_d + (n+f)/2 |
| 572 | // z_w now contains the value to go to the 0..1 depth buffer |
| 573 | |
| 574 | //trying to get the correct semantic while not using glDepthRange |
| 575 | //seems to get rather complicated |
| 576 | } |
| 577 | |
| 578 | if (ApiType & API_D3D9) |
| 579 | { |
| 580 | // D3D9 is addressing pixel centers instead of pixel boundaries in clip space. |
| 581 | // Thus we need to offset the final position by half a pixel |
| 582 | WRITEp+=sprintf(p, "o.pos = o.pos + float4(" I_DEPTHPARAMS"cDepth"".z, " I_DEPTHPARAMS"cDepth"".w, 0.f, 0.f);\n"); |
| 583 | } |
| 584 | |
| 585 | if(ApiType == API_OPENGL) |
| 586 | { |
| 587 | // Bit ugly here |
| 588 | // TODO: Make pretty |
| 589 | // Will look better when we bind uniforms in GLSL 1.3 |
| 590 | // clipPos/w needs to be done in pixel shader, not here |
| 591 | |
| 592 | if (xfregs.numTexGen.numTexGens < 7) |
| 593 | { |
| 594 | for (unsigned int i = 0; i < 8; ++i) |
| 595 | { |
| 596 | if(i < xfregs.numTexGen.numTexGens) |
| 597 | WRITEp+=sprintf(p, " uv%d_2.xyz = o.tex%d;\n", i, i); |
| 598 | else |
| 599 | WRITEp+=sprintf(p, " uv%d_2.xyz = float3(0.0f, 0.0f, 0.0f);\n", i); |
| 600 | } |
| 601 | |
| 602 | WRITEp+=sprintf(p, " clipPos_2 = o.clipPos;\n"); |
| 603 | |
| 604 | if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 605 | WRITEp+=sprintf(p, " Normal_2 = o.Normal;\n"); |
| 606 | } |
| 607 | else |
| 608 | { |
| 609 | // clip position is in w of first 4 texcoords |
| 610 | if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) |
| 611 | { |
| 612 | for (int i = 0; i < 8; ++i) |
| 613 | WRITEp+=sprintf(p, " uv%d_2 = o.tex%d;\n", i, i); |
| 614 | } |
| 615 | else |
| 616 | { |
| 617 | for (unsigned int i = 0; i < xfregs.numTexGen.numTexGens; ++i) |
| 618 | WRITEp+=sprintf(p, " uv%d_2%s = o.tex%d;\n", i, i < 4 ? ".xyzw" : ".xyz" , i); |
| 619 | } |
| 620 | } |
| 621 | WRITEp+=sprintf(p, "colors_02 = o.colors_0;\n"); |
| 622 | WRITEp+=sprintf(p, "colors_12 = o.colors_1;\n"); |
| 623 | WRITEp+=sprintf(p, "gl_Position = o.pos;\n"); |
| 624 | WRITEp+=sprintf(p, "}\n"); |
| 625 | } |
| 626 | else |
| 627 | { |
| 628 | WRITEp+=sprintf(p, "return o;\n}\n"); |
| 629 | } |
| 630 | |
| 631 | if (text[sizeof(text) - 1] != 0x7C) |
| 632 | PanicAlert("VertexShader generator - buffer too small, canary has been eaten!")MsgAlert(false, WARNING, "VertexShader generator - buffer too small, canary has been eaten!" ); |
| 633 | setlocale(LC_NUMERIC1, ""); // restore locale |
| 634 | return text; |
| 635 | } |