[PATCH 1/4] wined3d: Handle fog_start == fog_end with table fog

Stefan Dösinger stefan at codeweavers.com
Fri Jun 14 15:34:20 CDT 2013


Wizard101 triggers this when running on a GPU that does not support
shader model 3.
---
 dlls/wined3d/arb_program_shader.c |  4 +++-
 dlls/wined3d/glsl_shader.c        |  4 +++-
 dlls/wined3d/state.c              | 42 ++++++++++++++++++++++++++++++++++-----
 3 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index fd2df68..3082ba4 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -6513,6 +6513,8 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi
 static void state_arbfp_fog(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
     enum fogsource new_source;
+    DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART];
+    DWORD fogend = state->render_states[WINED3D_RS_FOGEND];
 
     TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id);
 
@@ -6541,7 +6543,7 @@ static void state_arbfp_fog(struct wined3d_context *context, const struct wined3
         new_source = FOGSOURCE_FFP;
     }
 
-    if (new_source != context->fog_source)
+    if (new_source != context->fog_source || fogstart == fogend)
     {
         context->fog_source = new_source;
         state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART));
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index e14d7ab..ad9be6a 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -7086,6 +7086,8 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context,
 {
     BOOL use_vshader = use_vs(state);
     enum fogsource new_source;
+    DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART];
+    DWORD fogend = state->render_states[WINED3D_RS_FOGEND];
 
     context->select_shader = 1;
     context->load_constants = 1;
@@ -7107,7 +7109,7 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context,
         new_source = FOGSOURCE_FFP;
     }
 
-    if (new_source != context->fog_source)
+    if (new_source != context->fog_source || fogstart == fogend)
     {
         context->fog_source = new_source;
         state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART));
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index ffce803..40136be 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -1043,10 +1043,40 @@ void state_fogstartend(struct wined3d_context *context, const struct wined3d_sta
             fogstart = tmpvalue.f;
             tmpvalue.d = state->render_states[WINED3D_RS_FOGEND];
             fogend = tmpvalue.f;
-            /* In GL, fogstart == fogend disables fog, in D3D everything's fogged.*/
-            if(fogstart == fogend) {
-                fogstart = -INFINITY;
-                fogend = 0.0f;
+            /* In GL, fogstart == fogend disables fog. In d3d with vertex
+             * fog, everything is fogged. With table fog, everything with
+             * fog_coord < fog_start is unfogged, and fog_coord > fog_start
+             * is fogged. Windows drivers disagree when fog_coord == fog_start */
+            if (fogstart == fogend)
+            {
+                if (state->render_states[WINED3D_RS_FOGTABLEMODE])
+                {
+                    /* Float has 32 bit precision, while FPU registers
+                     * have much more(80 bit and more). Thus make sure
+                     * that the stored float fogend is > fogstart, not
+                     * the fpu register, hence the volatile. */
+                    if (isnan(fogstart) || isinf(fogstart) || isinf(-fogstart))
+                    {
+                        FIXME("Both fogstart and fogend are NaN, INF or -INF\n");
+                    }
+                    else
+                    {
+                        float increase = eps;
+                        volatile float fogend2 = fogend;
+                        do
+                        {
+                            fogend2 += increase;
+                            increase *= 2.0f;
+                        }
+                        while (fogstart == fogend2);
+                        fogend = fogend2;
+                    }
+                }
+                else
+                {
+                    fogstart = -INFINITY;
+                    fogend = 0.0f;
+                }
             }
             break;
 
@@ -1072,6 +1102,8 @@ void state_fog_fragpart(struct wined3d_context *context, const struct wined3d_st
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
     enum fogsource new_source;
+    DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART];
+    DWORD fogend = state->render_states[WINED3D_RS_FOGEND];
 
     TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id);
 
@@ -1217,7 +1249,7 @@ void state_fog_fragpart(struct wined3d_context *context, const struct wined3d_st
 
     glEnableWINE(GL_FOG);
     checkGLcall("glEnable GL_FOG");
-    if (new_source != context->fog_source)
+    if (new_source != context->fog_source || fogstart == fogend)
     {
         context->fog_source = new_source;
         state_fogstartend(context, state, STATE_RENDER(WINED3D_RS_FOGSTART));
-- 
1.8.1.5




More information about the wine-patches mailing list