[PATCH] wined3d: Don't use the builtin FFP uniform for the normal matrix.

Matteo Bruni mbruni at codeweavers.com
Fri Mar 20 12:56:53 CDT 2015


---
 dlls/wined3d/glsl_shader.c | 95 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 2 deletions(-)

diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index c2f5de1..2698052 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -120,6 +120,7 @@ struct glsl_vs_program
     GLint modelview_matrix_location;
     GLint projection_matrix_location;
     GLint texture_matrix_location[MAX_TEXTURES];
+    GLint normal_matrix_location;
 };
 
 struct glsl_gs_program
@@ -753,6 +754,92 @@ static void shader_glsl_ffp_vertex_texmatrix_uniform(const struct wined3d_contex
     checkGLcall("glUniformMatrix4fv");
 }
 
+/* Taken and adapted from Mesa. */
+static BOOL invert_matrix_3d_general(struct wined3d_matrix *out, const struct wined3d_matrix *in)
+{
+   float pos, neg, t;
+   float det;
+   struct wined3d_matrix temp;
+
+   /* Calculate the determinant of upper left 3x3 submatrix and
+    * determine if the matrix is singular. */
+   pos = neg = 0.0f;
+   t =  in->_11 * in->_22 * in->_33;
+   if (t >= 0.0f)
+       pos += t;
+   else
+       neg += t;
+
+   t =  in->_21 * in->_32 * in->_13;
+   if (t >= 0.0f)
+       pos += t;
+   else
+       neg += t;
+   t =  in->_31 * in->_12 * in->_23;
+   if (t >= 0.0f)
+       pos += t;
+   else
+       neg += t;
+
+   t = -in->_31 * in->_22 * in->_13;
+   if (t >= 0.0f)
+       pos += t;
+   else
+       neg += t;
+   t = -in->_21 * in->_12 * in->_33;
+   if (t >= 0.0f)
+       pos += t;
+   else
+       neg += t;
+
+   t = -in->_11 * in->_32 * in->_23;
+   if (t >= 0.0f)
+       pos += t;
+   else
+       neg += t;
+
+   det = pos + neg;
+
+   if (fabsf(det) < 1e-25f)
+      return FALSE;
+
+   det = 1.0f / det;
+   temp._11 =  (in->_22 * in->_33 - in->_32 * in->_23) * det;
+   temp._12 = -(in->_12 * in->_33 - in->_32 * in->_13) * det;
+   temp._13 =  (in->_12 * in->_23 - in->_22 * in->_13) * det;
+   temp._21 = -(in->_21 * in->_33 - in->_31 * in->_23) * det;
+   temp._22 =  (in->_11 * in->_33 - in->_31 * in->_13) * det;
+   temp._23 = -(in->_11 * in->_23 - in->_21 * in->_13) * det;
+   temp._31 =  (in->_21 * in->_32 - in->_31 * in->_22) * det;
+   temp._32 = -(in->_11 * in->_32 - in->_31 * in->_12) * det;
+   temp._33 =  (in->_11 * in->_22 - in->_21 * in->_12) * det;
+
+   memcpy(out, &temp, sizeof(temp));
+   return TRUE;
+}
+
+static void shader_glsl_ffp_vertex_normalmatrix_uniform(const struct wined3d_context *context,
+        const struct wined3d_state *state, struct glsl_shader_prog_link *prog)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    float mat[3][3];
+    struct wined3d_matrix mv;
+    unsigned int i, j;
+
+    /* gl_NormalMatrix is defined in the spec as "transpose of the inverse of the
+     * upper leftmost 3x3 of gl_ModelViewMatrix". */
+    get_modelview_matrix(context, state, &mv);
+    /* TODO: Could check for and use optimized matrix inversion functions for
+     * special (common) cases, like Mesa does. */
+    invert_matrix_3d_general(&mv, &mv);
+    for (i = 0; i < 3; ++i)
+        for (j = 0; j < 3; ++j)
+            mat[i][j] = ((float *)&mv)[i * 4 + j];
+
+    GL_EXTCALL(glUniformMatrix3fv(prog->vs.normal_matrix_location, 1, FALSE, (GLfloat *)mat));
+    checkGLcall("glUniformMatrix3fv");
+}
+
 /* Context activation is done by the caller (state handler). */
 static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context *context,
         const struct wined3d_state *state)
@@ -802,6 +889,8 @@ static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context
         get_modelview_matrix(context, state, &mat);
         GL_EXTCALL(glUniformMatrix4fv(prog->vs.modelview_matrix_location, 1, FALSE, &mat._11));
         checkGLcall("glUniformMatrix4fv");
+
+        shader_glsl_ffp_vertex_normalmatrix_uniform(context, state, prog);
     }
 
     if (update_mask & WINED3D_SHADER_CONST_FFP_PROJ)
@@ -5024,6 +5113,7 @@ static GLuint shader_glsl_generate_ffp_vertex_shader(struct wined3d_shader_buffe
     shader_addline(buffer, "uniform mat4 ffp_modelview_matrix;\n");
     shader_addline(buffer, "uniform mat4 ffp_projection_matrix;\n");
     shader_addline(buffer, "uniform mat4 ffp_texture_matrix[%u];\n", MAX_TEXTURES);
+    shader_addline(buffer, "uniform mat3 ffp_normal_matrix;\n");
 
     shader_addline(buffer, "\nvoid main()\n{\n");
     shader_addline(buffer, "float m;\n");
@@ -5047,9 +5137,9 @@ static GLuint shader_glsl_generate_ffp_vertex_shader(struct wined3d_shader_buffe
     if (!settings->normal)
         shader_addline(buffer, "vec3 normal = vec3(0.0);\n");
     else if (settings->normalize)
-        shader_addline(buffer, "vec3 normal = normalize(gl_NormalMatrix * gl_Normal);\n");
+        shader_addline(buffer, "vec3 normal = normalize(ffp_normal_matrix * gl_Normal);\n");
     else
-        shader_addline(buffer, "vec3 normal = gl_NormalMatrix * gl_Normal;\n");
+        shader_addline(buffer, "vec3 normal = ffp_normal_matrix * gl_Normal;\n");
 
     shader_glsl_ffp_vertex_lighting(buffer, settings, gl_info);
 
@@ -5814,6 +5904,7 @@ static void shader_glsl_init_vs_uniform_locations(const struct wined3d_gl_info *
         sprintf(name, "ffp_texture_matrix[%u]", i);
         vs->texture_matrix_location[i] = GL_EXTCALL(glGetUniformLocation(program_id, name));
     }
+    vs->normal_matrix_location = GL_EXTCALL(glGetUniformLocation(program_id, "ffp_normal_matrix"));
 }
 
 static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info *gl_info,
-- 
2.0.5




More information about the wine-patches mailing list