diff --git a/GPU/GLES/ShaderManager.cpp b/GPU/GLES/ShaderManager.cpp index b89d27e0ef..7221985236 100644 --- a/GPU/GLES/ShaderManager.cpp +++ b/GPU/GLES/ShaderManager.cpp @@ -54,6 +54,9 @@ Shader::Shader(const char *code, uint32_t shaderType) { ERROR_LOG(G3D, "Info log: %s\n", infoLog); ERROR_LOG(G3D, "Shader source:\n%s\n", (const char *)code); Reporting::ReportMessage("Error in shader compilation: info: %s / code: %s", infoLog, (const char *)code); +#ifdef SHADERLOG + OutputDebugString(infoLog); +#endif } else { DEBUG_LOG(G3D, "Compiled shader:\n%s\n", (const char *)code); } @@ -102,11 +105,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs) u_view = glGetUniformLocation(program, "u_view"); u_world = glGetUniformLocation(program, "u_world"); u_texmtx = glGetUniformLocation(program, "u_texmtx"); - for (int i = 0; i < 8; i++) { - char name[64]; - sprintf(name, "u_bone%i", i); - u_bone[i] = glGetUniformLocation(program, name); - } + u_bone = glGetUniformLocation(program, "u_bone"); + numBones = gstate.getNumBoneWeights(); // Lighting, texturing u_ambient = glGetUniformLocation(program, "u_ambient"); @@ -141,8 +141,8 @@ LinkedShader::LinkedShader(Shader *vs, Shader *fs) a_color1 = glGetAttribLocation(program, "a_color1"); a_texcoord = glGetAttribLocation(program, "a_texcoord"); a_normal = glGetAttribLocation(program, "a_normal"); - a_weight0123 = glGetAttribLocation(program, "a_weight0123"); - a_weight4567 = glGetAttribLocation(program, "a_weight4567"); + a_weight0123 = glGetAttribLocation(program, "a_w1"); + a_weight4567 = glGetAttribLocation(program, "a_w2"); glUseProgram(program); @@ -317,9 +317,13 @@ void LinkedShader::updateUniforms() { if (u_texmtx != -1 && (dirtyUniforms & DIRTY_TEXMATRIX)) { SetMatrix4x3(u_texmtx, gstate.tgenMatrix); } - for (int i = 0; i < 8; i++) { - if (u_bone[i] != -1 && (dirtyUniforms & (DIRTY_BONEMATRIX0 << i))) { - SetMatrix4x3(u_bone[i], gstate.boneMatrix + 12 * i); + + // TODO: Could even set all bones in one go if they're all dirty. + if (u_bone != -1) { + for (int i = 0; i < numBones; i++) { + if (dirtyUniforms & (DIRTY_BONEMATRIX0 << i)) { + SetMatrix4x3(u_bone + i, gstate.boneMatrix + 12 * i); + } } } diff --git a/GPU/GLES/ShaderManager.h b/GPU/GLES/ShaderManager.h index d7ab680e93..b4a7fdf25a 100644 --- a/GPU/GLES/ShaderManager.h +++ b/GPU/GLES/ShaderManager.h @@ -54,7 +54,8 @@ public: int u_view; int u_texmtx; int u_world; - int u_bone[8]; + int u_bone; // array, size is numBones + int numBones; // Fragment processing inputs int u_alphacolorref; diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index 777c69b8d6..9fb2c54110 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -106,25 +106,25 @@ void ComputeVertexShaderID(VertexShaderID *id, int prim) { } static const char * const boneWeightAttrDecl[8] = { - "attribute mediump float a_weight0123;\n", - "attribute mediump vec2 a_weight0123;\n", - "attribute mediump vec3 a_weight0123;\n", - "attribute mediump vec4 a_weight0123;\n", - "attribute mediump vec4 a_weight0123;\nattribute mediump float a_weight4567;\n", - "attribute mediump vec4 a_weight0123;\nattribute mediump vec2 a_weight4567;\n", - "attribute mediump vec4 a_weight0123;\nattribute mediump vec3 a_weight4567;\n", - "attribute mediump vec4 a_weight0123;\nattribute mediump vec4 a_weight4567;\n", + "attribute mediump float a_w1;\n", + "attribute mediump vec2 a_w1;\n", + "attribute mediump vec3 a_w1;\n", + "attribute mediump vec4 a_w1;\n", + "attribute mediump vec4 a_w1;\nattribute mediump float a_w2;\n", + "attribute mediump vec4 a_w1;\nattribute mediump vec2 a_w2;\n", + "attribute mediump vec4 a_w1;\nattribute mediump vec3 a_w2;\n", + "attribute mediump vec4 a_w1;\nattribute mediump vec4 a_w2;\n", }; static const char * const boneWeightAttr[8] = { - "a_weight0123.x", - "a_weight0123.y", - "a_weight0123.z", - "a_weight0123.w", - "a_weight4567.x", - "a_weight4567.y", - "a_weight4567.z", - "a_weight4567.w", + "a_w1.x", + "a_w1.y", + "a_w1.z", + "a_w1.w", + "a_w2.x", + "a_w2.y", + "a_w2.z", + "a_w2.w", }; enum DoLightComputation { @@ -135,8 +135,13 @@ enum DoLightComputation { void GenerateVertexShader(int prim, char *buffer) { char *p = buffer; + WRITE(p, "precision highp float;\n"); + +#define USE_FOR_LOOP + #if defined(USING_GLES2) WRITE(p, "precision highp float;\n"); + #elif !defined(FORCE_OPENGL_2_0) WRITE(p, "#version 110\n"); // Remove lowp/mediump in non-mobile implementations @@ -220,9 +225,7 @@ void GenerateVertexShader(int prim, char *buffer) { WRITE(p, "uniform mediump mat4 u_texmtx;\n"); if ((vertType & GE_VTYPE_WEIGHT_MASK) != GE_VTYPE_WEIGHT_NONE) { int numBones = 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); - for (int i = 0; i < numBones; i++) { - WRITE(p, "uniform mediump mat4 u_bone%i;\n", i); - } + WRITE(p, "uniform mediump mat4 u_bone[%i];\n", numBones); } if (gstate.isLightingEnabled()) { WRITE(p, "uniform lowp vec4 u_ambient;\n"); @@ -301,19 +304,44 @@ void GenerateVertexShader(int prim, char *buffer) { WRITE(p, " vec3 worldnormal = vec3(0.0, 0.0, 1.0);\n"); int numWeights = 1 + ((vertType & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT); - static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f}; - float factor = rescale[(vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT]; + +#ifdef USE_FOR_LOOP + + // To loop through the weights, we unfortunately need to put them in a float array. + // GLSL ES sucks - no way to directly initialize an array! + switch (numWeights) { + case 1: WRITE(p, " float w[1]; w[0] = a_w1;\n"); break; + case 2: WRITE(p, " float w[2]; w[0] = a_w1.x; w[1] = a_w1.y;\n"); break; + case 3: WRITE(p, " float w[3]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z;\n"); break; + case 4: WRITE(p, " float w[4]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w;\n"); break; + case 5: WRITE(p, " float w[5]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2;\n"); break; + case 6: WRITE(p, " float w[6]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y;\n"); break; + case 7: WRITE(p, " float w[7]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y; w[6] = a_w2.z;\n"); break; + case 8: WRITE(p, " float w[8]; w[0] = a_w1.x; w[1] = a_w1.y; w[2] = a_w1.z; w[3] = a_w1.w; w[4] = a_w2.x; w[5] = a_w2.y; w[6] = a_w2.z; w[7] = a_w2.w;\n"); break; + } + + WRITE(p, " for (int i = 0; i < %i; i++) {\n", numWeights); + WRITE(p, " worldpos += w[i] * (u_bone[i] * vec4(a_position.xyz, 1.0)).xyz;\n"); + if (hasNormal) + WRITE(p, " worldnormal += w[i] * (u_bone[i] * vec4(a_normal, 0.0)).xyz;\n"); + WRITE(p, " }\n"); + +#else for (int i = 0; i < numWeights; i++) { const char *weightAttr = boneWeightAttr[i]; // workaround for "cant do .x of scalar" issue - if (numWeights == 1 && i == 0) weightAttr = "a_weight0123"; - if (numWeights == 5 && i == 4) weightAttr = "a_weight4567"; - WRITE(p, " worldpos += %s * (u_bone%i * vec4(a_position.xyz, 1.0)).xyz;\n", weightAttr, i); + if (numWeights == 1 && i == 0) weightAttr = "a_w1"; + if (numWeights == 5 && i == 4) weightAttr = "a_w2"; + WRITE(p, " worldpos += %s * (u_bone[%i] * vec4(a_position.xyz, 1.0)).xyz;\n", weightAttr, i); if (hasNormal) - WRITE(p, " worldnormal += %s * (u_bone%i * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i); + WRITE(p, " worldnormal += %s * (u_bone[%i] * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i); } +#endif - // Finally, multiply by world matrix (yes, we have to). + static const float rescale[4] = {0, 2*127.5f/128.f, 2*32767.5f/32768.f, 2.0f}; + float factor = rescale[(vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT]; + + // Finally, multiply by world matrix and compensate for quantization at the same time. WRITE(p, " worldpos = (u_world * vec4(worldpos * %f, 1.0)).xyz;\n", factor); if (hasNormal) WRITE(p, " worldnormal = (u_world * vec4(worldnormal, 0.0)).xyz;\n");