wined3d: Correctly display fog for right-handed projection matrix (try 4)

Joachim Priesner joachim.priesner at web.de
Thu Oct 2 14:45:26 CDT 2014


When using a right-handed projection matrix, z coordinates of
transformed vertices may be negative. This is not considered
in the code generating the GLSL fog shader for fixed-function fog.
The patch fixes that and adds a test.

Tested on openSUSE 13.1 and Windows 8.1.

Try 4 with tests including vertex shaders to make sure that the bug is
indeed in Wine's FFP implementation. Thanks Matteo Bruni for the very
helpful suggestions on how to implement this.
---
 dlls/d3d8/tests/visual.c   | 266 +++++++++++++++++++++++++++++++++++++
 dlls/d3d9/tests/visual.c   | 324 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/glsl_shader.c |   2 +-
 3 files changed, 591 insertions(+), 1 deletion(-)

diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c
index ba73bb6..3afa145 100644
--- a/dlls/d3d8/tests/visual.c
+++ b/dlls/d3d8/tests/visual.c
@@ -23,6 +23,12 @@
 #include <d3d8.h>
 #include "wine/test.h"
 
+/* Some color constants to make tests easier to read. */
+#define COLOR_FOG       0xff00ff00
+#define COLOR_FOGGED    0x0000ff00
+#define COLOR_UNFOGGED  0x00ff0000
+#define COLOR_CLEAR     0xffff00ff
+
 struct vec2
 {
     float x, y;
@@ -696,6 +702,265 @@ done:
     DestroyWindow(window);
 }
 
+/* This tests fog in combination with a right-handed projection matrix. */
+static void fog_righthanded_test(void)
+{
+    /* Fill the null-shader entry with the FVF (SetVertexShader is "overloaded" on d3d8) */
+    DWORD vertex_shader[3] = {D3DFVF_XYZ | D3DFVF_DIFFUSE, 0, 0};
+    DWORD pixel_shader[2] = {0, 0};
+    IDirect3DDevice8 *device;
+    unsigned int i;
+    IDirect3D8 *d3d;
+    D3DCOLOR color;
+    ULONG refcount;
+    D3DCAPS8 caps;
+    HWND window;
+    HRESULT hr;
+    union
+    {
+        float f;
+        DWORD i;
+    } start, end;
+
+    /* For all vertex shaders the view matrix goes in registers c0...c3,
+     * the projection matrix goes in registers c4...c7. */
+
+    /* basic vertex shader without fog computation ("non foggy") */
+    static const DWORD vertex_shader_code1[] =
+    {
+        0xfffe0100,                                                             /* vs_1_0             */
+        /* output.Pos = mul(input.Pos, View) */
+        0x00000009, 0x80010000, 0x90e40000, 0xa0e40000,                         /* dp4 r0.x, v0, c0   */
+        0x00000009, 0x80020000, 0x90e40000, 0xa0e40001,                         /* dp4 r0.y, v0, c1   */
+        0x00000009, 0x80040000, 0x90e40000, 0xa0e40002,                         /* dp4 r0.z, v0, c2   */
+        0x00000009, 0x80080000, 0x90e40000, 0xa0e40003,                         /* dp4 r0.w, v0, c3   */
+        /* output.Pos = mul(output.Pos, Projection) */
+        0x00000009, 0xc0010000, 0x80e40000, 0xa0e40004,                         /* dp4 oPos.x, r0, c4 */
+        0x00000009, 0xc0020000, 0x80e40000, 0xa0e40005,                         /* dp4 oPos.y, r0, c5 */
+        0x00000009, 0xc0040000, 0x80e40000, 0xa0e40006,                         /* dp4 oPos.z, r0, c6 */
+        0x00000009, 0xc0080000, 0x80e40000, 0xa0e40007,                         /* dp4 oPos.w, r0, c7 */
+        /* output.Color = input.Color */
+        0x00000001, 0xd00f0000, 0x90e40001,                                     /* mov oD0, v1        */
+        0x0000ffff,                                                             /* END                */
+    };
+
+   /* Basic vertex shader with fog computation ("foggy").
+    * Using the vertex' x coordinate as fog coordinate so that all test cases that use vertex fog
+    * will have a gradient from fully fogged (green, left) to unfogged (red, right). */
+    static const DWORD vertex_shader_code2[] =
+    {
+        0xfffe0100,                                                             /* vs_1_0             */
+        /* output.Pos = mul(input.Pos, View) */
+        0x00000009, 0x80010000, 0x90e40000, 0xa0e40000,                         /* dp4 r0.x, v0, c0   */
+        0x00000009, 0x80020000, 0x90e40000, 0xa0e40001,                         /* dp4 r0.y, v0, c1   */
+        0x00000009, 0x80040000, 0x90e40000, 0xa0e40002,                         /* dp4 r0.z, v0, c2   */
+        0x00000009, 0x80080000, 0x90e40000, 0xa0e40003,                         /* dp4 r0.w, v0, c3   */
+        /* output.Pos = mul(output.Pos, Projection) */
+        0x00000009, 0xc0010000, 0x80e40000, 0xa0e40004,                         /* dp4 oPos.x, r0, c4 */
+        0x00000009, 0xc0020000, 0x80e40000, 0xa0e40005,                         /* dp4 oPos.y, r0, c5 */
+        0x00000009, 0xc0040000, 0x80e40000, 0xa0e40006,                         /* dp4 oPos.z, r0, c6 */
+        0x00000009, 0xc0080000, 0x80e40000, 0xa0e40007,                         /* dp4 oPos.w, r0, c7 */
+        /* output.Color = input.Color */
+        0x00000001, 0xd00f0000, 0x90e40001,                                     /* mov oD0, v1        */
+        /* output.Fog = input.Pos.x */
+        0x00000001, 0xc00f0001, 0x90000000,                                     /* mov oFog, v0.x     */
+        0x0000ffff,                                                             /* END                */
+     };
+
+    /* Basic pixel shader */
+    static const DWORD pixel_shader_code[] =
+    {
+        0xffff0101,                                                             /* ps_1_1     */
+        0x00000001, 0x800f0000, 0x90e40000,                                     /* mov r0, v0 */
+        0x0000ffff
+    };
+
+    static struct
+    {
+        struct vec3 position;
+        DWORD diffuse;
+    }
+    quad[] =
+    {
+        {{-1.0f, -1.0f, 10.0f}, COLOR_UNFOGGED},
+        {{-1.0f,  1.0f, 10.0f}, COLOR_UNFOGGED},
+        {{ 1.0f, -1.0f, 10.0f}, COLOR_UNFOGGED},
+        {{ 1.0f,  1.0f, 10.0f}, COLOR_UNFOGGED},
+    };
+    static const DWORD vertex_decl[] =
+    {
+        D3DVSD_STREAM(0),
+        D3DVSD_REG(0, D3DVSDT_FLOAT3),  /* position, v0 */
+        D3DVSD_REG(1, D3DVSDT_D3DCOLOR),  /* diffuse color, v1 */
+        D3DVSD_END()
+    };
+    static const struct test_data_t
+    {
+        int vshader;
+        int pshader;
+        D3DFOGMODE vfog;
+        D3DFOGMODE tfog;
+        DWORD color_left;
+        DWORD color_right;
+    }
+    test_data[] =
+    {
+        /* No vertex shader */
+        {0, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+
+        /* Vertex shader without vertex fog computation. */
+        {1, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+
+        /* Vertex shader with vertex fog computation */
+        {2, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {2, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {2, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+        {2, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+    };
+    /* A right-handed perspective projection matrix designed so that vertices
+     * (x in [-1..1], y in [-1..1], z = 0.1) will be mapped to the view plane.
+     * Obtained from D3DXMatrixPerspectiveFovRH with the parameters
+     * fov=84.29deg, aspect=640/480 near=0.01, far=100 */
+    static const D3DMATRIX proj_mat_rh =
+    {{{
+        0.828732f, 0.0f,       0.0f,       0.0f,
+        0.0f,      1.104976f,  0.0f,       0.0f,
+        0.0f,      0.0f,      -1.0001f,   -1.0f,
+        0.0f,      0.0f,      -0.010001f,  0.0f
+    }}};
+    /* Need a transposed version of the projection matrix to pass to the vertex shader
+     * (because shaders internally use column-major order of matrices).
+     * The view matrix is already symmetrical, so no need to transpose it. */
+    static const D3DMATRIX proj_mat_rh_transposed =
+    {{{
+        0.828732f, 0.0f,       0.0f,     0.0f,
+        0.0f,      1.104976f,  0.0f,     0.0f,
+        0.0f,      0.0f,      -1.0001f, -0.010001f,
+        0.0f,      0.0f,      -1.0f,     0.0f
+    }}};
+    static const D3DMATRIX view_mat_rh =
+    {{{
+        1.0f, 0.0f,  0.0f, 0.0f,
+        0.0f, 1.0f,  0.0f, 0.0f,
+        0.0f, 0.0f, -0.1f, 0.0f,
+        0.0f, 0.0f,  0.0f, 1.0f
+    }}};
+
+    window = CreateWindowA("static", "d3d8_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            0, 0, 640, 480, NULL, NULL, NULL, NULL);
+    d3d = Direct3DCreate8(D3D_SDK_VERSION);
+    ok(!!d3d, "Failed to create a D3D object.\n");
+    if (!(device = create_device(d3d, window, window, TRUE)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        goto done;
+    }
+
+    hr = IDirect3DDevice8_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+
+    if (caps.PixelShaderVersion >= D3DPS_VERSION(1, 1))
+    {
+        hr = IDirect3DDevice8_CreatePixelShader(device, pixel_shader_code, &pixel_shader[1]);
+        ok(SUCCEEDED(hr), "CreatePixelShader failed (%08x)\n", hr);
+    } else {
+        skip("No ps_1_1 support, skipping some fog tests.\n");
+    }
+
+    if (caps.VertexShaderVersion >= D3DVS_VERSION(1, 0))
+    {
+        hr = IDirect3DDevice8_CreateVertexShader(device, vertex_decl, vertex_shader_code1, &vertex_shader[1], 0);
+        ok(SUCCEEDED(hr), "CreateVertexShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice8_CreateVertexShader(device, vertex_decl, vertex_shader_code2, &vertex_shader[2], 0);
+        ok(SUCCEEDED(hr), "CreateVertexShader failed (%08x)\n", hr);
+    } else {
+        skip("No vs_1_0 support, skipping some fog tests.\n");
+    }
+
+    start.f = 0.1f;
+    end.f = 0.9f;
+
+    /* Setup initial states: No lighting, fog on, fog color */
+    hr = IDirect3DDevice8_SetRenderState(device, D3DRS_LIGHTING, FALSE);
+    ok(SUCCEEDED(hr), "Turning off lighting failed (%08x)\n", hr);
+    hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGENABLE, TRUE);
+    ok(SUCCEEDED(hr), "Turning on fog calculations failed (%08x)\n", hr);
+    hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGCOLOR, COLOR_FOG);
+    ok(SUCCEEDED(hr), "Setting fog color failed (%08x)\n", hr);
+
+    hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGSTART, start.i);
+    ok(SUCCEEDED(hr), "Setting fog start failed (%08x)\n", hr);
+    hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGEND, end.i);
+    ok(SUCCEEDED(hr), "Setting fog end failed (%08x)\n", hr);
+
+    hr = IDirect3DDevice8_SetTransform(device, D3DTS_PROJECTION, &proj_mat_rh);
+    ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
+    hr = IDirect3DDevice8_SetTransform(device, D3DTS_VIEW, &view_mat_rh);
+    ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice8_SetVertexShaderConstant(device, 0, &view_mat_rh, 4);
+    ok(SUCCEEDED(hr), "SetVertexShaderConstant (view matrix) failed (%08x)\n", hr);
+    hr = IDirect3DDevice8_SetVertexShaderConstant(device, 4, &proj_mat_rh_transposed, 4);
+    ok(SUCCEEDED(hr), "SetVertexShaderConstant (projection matrix) failed (%08x)\n", hr);
+
+    for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); ++i)
+    {
+        if ((test_data[i].pshader != 0 && pixel_shader[test_data[i].pshader] == 0)
+                || (test_data[i].vshader != 0 && vertex_shader[test_data[i].vshader] == 0))
+            continue;
+
+        hr = IDirect3DDevice8_SetVertexShader(device, vertex_shader[test_data[i].vshader]);
+        ok(SUCCEEDED(hr), "SetVertexShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice8_SetPixelShader(device, pixel_shader[test_data[i].pshader]);
+        ok(SUCCEEDED(hr), "SetPixelShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGVERTEXMODE, test_data[i].vfog);
+        ok(SUCCEEDED(hr), "Setting fog vertex mode to %d failed (%08x)\n", test_data[i].vfog, hr);
+        hr = IDirect3DDevice8_SetRenderState(device, D3DRS_FOGTABLEMODE, test_data[i].tfog);
+        ok(SUCCEEDED(hr), "Setting fog table mode to %d failed (%08x)\n", test_data[i].tfog, hr);
+
+        hr = IDirect3DDevice8_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, COLOR_CLEAR, 1.0f, 0);
+        ok(SUCCEEDED(hr), "IDirect3DDevice9_Clear failed (%08x)\n", hr);
+        hr = IDirect3DDevice8_BeginScene(device);
+        ok(SUCCEEDED(hr), "BeginScene returned failed (%08x)\n", hr);
+        hr = IDirect3DDevice8_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, &quad[0], sizeof(quad[0]));
+        ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%08x)\n", hr);
+        hr = IDirect3DDevice8_EndScene(device);
+        ok(SUCCEEDED(hr), "EndScene failed (%08x)\n", hr);
+
+        /* Use 5% tolerance on the colors since there may be a gradient
+         * between left and right vertices. */
+        color = getPixelColor(device, 60, 240);
+        ok(color_match(color, test_data[i].color_left, 13),
+                "fog vs%i ps%i fvm%i ftm%i: got left color %08x, expected %08x+-5%%\n",
+                test_data[i].vshader, test_data[i].pshader, test_data[i].vfog,
+                test_data[i].tfog, color, test_data[i].color_left);
+        color = getPixelColor(device, 580, 240);
+        ok(color_match(color, test_data[i].color_right, 13),
+                "fog vs%i ps%i fvm%i ftm%i: got right color %08x, expected %08x+-5%%\n",
+                test_data[i].vshader, test_data[i].pshader, test_data[i].vfog,
+                test_data[i].tfog, color, test_data[i].color_right);
+
+        IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
+    }
+    for (i = 0; i < sizeof(vertex_shader)/sizeof(vertex_shader[0]); i++)
+        if (vertex_shader[i])
+            IDirect3DDevice8_DeleteVertexShader(device, vertex_shader[i]);
+    for (i = 0; i < sizeof(pixel_shader)/sizeof(pixel_shader[0]); i++)
+        if (pixel_shader[i])
+            IDirect3DDevice8_DeletePixelShader(device, pixel_shader[i]);
+    refcount = IDirect3DDevice8_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+done:
+    IDirect3D8_Release(d3d);
+    DestroyWindow(window);
+}
+
 /* This tests fog in combination with shaders.
  * What's tested: linear fog (vertex and table) with pixel shader
  *                linear table fog with non foggy vertex shader
@@ -5092,6 +5357,7 @@ START_TEST(visual)
     offscreen_test();
     alpha_test();
     test_scalar_instructions();
+    fog_righthanded_test();
     fog_with_shader_test();
     cnd_test();
     p8_texture_test();
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 117c8eb..4784f9f 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -32,6 +32,12 @@
 #include <d3d9.h>
 #include "wine/test.h"
 
+/* Some color constants to make tests more easier to read. */
+#define COLOR_FOG       0xff00ff00
+#define COLOR_FOGGED    0x0000ff00
+#define COLOR_UNFOGGED  0x00ff0000
+#define COLOR_CLEAR     0xffff00ff
+
 struct vec2
 {
     float x, y;
@@ -1825,6 +1831,323 @@ done:
     DestroyWindow(window);
 }
 
+/* This test tests fog in combination with a right-handed projection matrix. */
+static void fog_righthanded_test(void)
+{
+    IDirect3DVertexShader9 *vertex_shader[4] = {NULL, NULL, NULL, NULL};
+    IDirect3DPixelShader9 *pixel_shader[3] = {NULL, NULL, NULL};
+    IDirect3DVertexDeclaration9 *vertex_declaration = NULL;
+    IDirect3DDevice9 *device;
+    unsigned int i;
+    IDirect3D9 *d3d;
+    ULONG refcount;
+    D3DCAPS9 caps;
+    DWORD color;
+    HWND window;
+    HRESULT hr;
+    union
+    {
+        float f;
+        DWORD i;
+    } start, end;
+
+    /* For all vertex shaders the view matrix goes in registers c0...c3,
+     * the projection matrix goes in registers c4...c7. */
+
+    /* basic vertex shader without fog computation ("non foggy") */
+    static const DWORD vertex_shader_code1[] =
+    {
+        0xfffe0101,                                                             /* vs_1_1             */
+        0x0000001f, 0x80000000, 0x900f0000,                                     /* dcl_position0 v0   */
+        0x0000001f, 0x8000000a, 0x900f0001,                                     /* dcl_color0 v1      */
+        /* output.Pos = mul(input.Pos, View) */
+        0x00000009, 0x80010000, 0x90e40000, 0xa0e40000,                         /* dp4 r0.x, v0, c0   */
+        0x00000009, 0x80020000, 0x90e40000, 0xa0e40001,                         /* dp4 r0.y, v0, c1   */
+        0x00000009, 0x80040000, 0x90e40000, 0xa0e40002,                         /* dp4 r0.z, v0, c2   */
+        0x00000009, 0x80080000, 0x90e40000, 0xa0e40003,                         /* dp4 r0.w, v0, c3   */
+        /* output.Pos = mul(output.Pos, Projection) */
+        0x00000009, 0xc0010000, 0x80e40000, 0xa0e40004,                         /* dp4 oPos.x, r0, c4 */
+        0x00000009, 0xc0020000, 0x80e40000, 0xa0e40005,                         /* dp4 oPos.y, r0, c5 */
+        0x00000009, 0xc0040000, 0x80e40000, 0xa0e40006,                         /* dp4 oPos.z, r0, c6 */
+        0x00000009, 0xc0080000, 0x80e40000, 0xa0e40007,                         /* dp4 oPos.w, r0, c7 */
+        /* output.Color = input.Color */
+        0x00000001, 0xd00f0000, 0x90e40001,                                     /* mov oD0, v1        */
+        0x0000ffff,                                                             /* END                */
+    };
+
+    /* Basic vertex shader with fog computation ("foggy").
+     * Using the vertex' x coordinate as fog coordinate so that all test cases that use vertex fog
+     * will have a gradient from fully fogged (green, left) to unfogged (red, right). */
+    static const DWORD vertex_shader_code2[] =
+    {
+        0xfffe0101,                                                             /* vs_1_1             */
+        0x0000001f, 0x80000000, 0x900f0000,                                     /* dcl_position0 v0   */
+        0x0000001f, 0x8000000a, 0x900f0001,                                     /* dcl_color0 v1      */
+        /* output.Pos = mul(input.Pos, View) */
+        0x00000009, 0x80010000, 0x90e40000, 0xa0e40000,                         /* dp4 r0.x, v0, c0   */
+        0x00000009, 0x80020000, 0x90e40000, 0xa0e40001,                         /* dp4 r0.y, v0, c1   */
+        0x00000009, 0x80040000, 0x90e40000, 0xa0e40002,                         /* dp4 r0.z, v0, c2   */
+        0x00000009, 0x80080000, 0x90e40000, 0xa0e40003,                         /* dp4 r0.w, v0, c3   */
+        /* output.Pos = mul(output.Pos, Projection) */
+        0x00000009, 0xc0010000, 0x80e40000, 0xa0e40004,                         /* dp4 oPos.x, r0, c4 */
+        0x00000009, 0xc0020000, 0x80e40000, 0xa0e40005,                         /* dp4 oPos.y, r0, c5 */
+        0x00000009, 0xc0040000, 0x80e40000, 0xa0e40006,                         /* dp4 oPos.z, r0, c6 */
+        0x00000009, 0xc0080000, 0x80e40000, 0xa0e40007,                         /* dp4 oPos.w, r0, c7 */
+        /* output.Color = input.Color */
+        0x00000001, 0xd00f0000, 0x90e40001,                                     /* mov oD0, v1        */
+        /* output.Fog = input.Pos.x */
+        0x00000001, 0xc00f0001, 0x90000000,                                     /* mov oFog, v0.x     */
+        0x0000ffff,                                                             /* END                */
+    };
+
+    /* basic vertex shader with fog computation ("foggy"), vs_2_0 */
+    static const DWORD vertex_shader_code3[] =
+    {
+        0xfffe0200,                                                             /* vs_2_0             */
+        0x0200001f, 0x80000000, 0x900f0000,                                     /* dcl_position0 v0   */
+        0x0200001f, 0x8000000a, 0x900f0001,                                     /* dcl_color0 v1      */
+        /* output.Pos = mul(input.Pos, View) */
+        0x03000009, 0x80010000, 0x90e40000, 0xa0e40000,                         /* dp4 r0.x, v0, c0   */
+        0x03000009, 0x80020000, 0x90e40000, 0xa0e40001,                         /* dp4 r0.y, v0, c1   */
+        0x03000009, 0x80040000, 0x90e40000, 0xa0e40002,                         /* dp4 r0.z, v0, c2   */
+        0x03000009, 0x80080000, 0x90e40000, 0xa0e40003,                         /* dp4 r0.w, v0, c3   */
+        /* output.Pos = mul(output.Pos, Projection) */
+        0x03000009, 0xc0010000, 0x80e40000, 0xa0e40004,                         /* dp4 oPos.x, r0, c4 */
+        0x03000009, 0xc0020000, 0x80e40000, 0xa0e40005,                         /* dp4 oPos.y, r0, c5 */
+        0x03000009, 0xc0040000, 0x80e40000, 0xa0e40006,                         /* dp4 oPos.z, r0, c6 */
+        0x03000009, 0xc0080000, 0x80e40000, 0xa0e40007,                         /* dp4 oPos.w, r0, c7 */
+        /* output.Color = input.Color */
+        0x02000001, 0xd00f0000, 0x90e40001,                                     /* mov oD0, v1        */
+        /* output.Fog = input.Pos.x */
+        0x02000001, 0xc00f0001, 0x90000000,                                     /* mov oFog, v0.x     */
+        0x0000ffff,                                                             /* END                */
+    };
+
+    /* basic pixel shader */
+    static const DWORD pixel_shader_code[] =
+    {
+        0xffff0101,                                                             /* ps_1_1     */
+        0x00000001, 0x800f0000, 0x90e40000,                                     /* mov r0, v0 */
+        0x0000ffff
+    };
+    static const DWORD pixel_shader_code2[] =
+    {
+        0xffff0200,                                                             /* ps_2_0      */
+        0x0200001f, 0x80000000, 0x900f0000,                                     /* dcl v0      */
+        0x02000001, 0x800f0800, 0x90e40000,                                     /* mov oC0, v0 */
+        0x0000ffff
+    };
+    struct
+    {
+        struct vec3 position;
+        DWORD diffuse;
+    }
+    quad[] =
+    {
+        {{-1.0f, -1.0f, 10.0f}, COLOR_UNFOGGED},
+        {{-1.0f,  1.0f, 10.0f}, COLOR_UNFOGGED},
+        {{ 1.0f, -1.0f, 10.0f}, COLOR_UNFOGGED},
+        {{ 1.0f,  1.0f, 10.0f}, COLOR_UNFOGGED},
+    };
+    static const D3DVERTEXELEMENT9 decl_elements[] =
+    {
+        {0,  0, D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
+        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT,    D3DDECLUSAGE_COLOR, 0},
+        D3DDECL_END()
+    };
+    static const struct test_data_t
+    {
+        int vshader;
+        int pshader;
+        D3DFOGMODE vfog;
+        D3DFOGMODE tfog;
+        DWORD color_left;
+        DWORD color_right;
+    }
+    test_data[] =
+    {
+        /* No vertex shader */
+        {0, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 2, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+        {0, 2, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+
+        /* Vertex shader without vertex fog computation. */
+        {1, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 2, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+        {1, 2, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_FOGGED},
+
+        /* Vertex shader vs_1_1 with vertex fog computation */
+        {2, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {2, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {2, 2, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {2, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+        {2, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+        {2, 2, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+
+        /* Vertex shader vs_2_0 with vertex fog computation */
+        {3, 0, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {3, 1, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {3, 2, D3DFOG_NONE, D3DFOG_LINEAR, COLOR_FOGGED, COLOR_FOGGED},
+        {3, 0, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+        {3, 1, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+        {3, 2, D3DFOG_LINEAR, D3DFOG_NONE, COLOR_FOGGED, COLOR_UNFOGGED},
+    };
+    /* A right-handed perspective projection matrix designed so that vertices
+     * (x in [-1..1], y in [-1..1], z = 0.1) will be mapped to the view plane.
+     * Obtained from D3DXMatrixPerspectiveFovRH with the parameters
+     * fov=84.29deg, aspect=640/480 near=0.01, far=100 */
+    static const D3DMATRIX proj_mat_rh =
+    {{{
+        0.828732f, 0.0f,       0.0f,       0.0f,
+        0.0f,      1.104976f,  0.0f,       0.0f,
+        0.0f,      0.0f,      -1.0001f,   -1.0f,
+        0.0f,      0.0f,      -0.010001f,  0.0f
+    }}};
+    /* Need a transposed version of the projection matrix to pass to the vertex shader
+     * (because shaders internally use column-major order of matrices).
+     * The view matrix is already symmetrical, so no need to transpose it. */
+    static const D3DMATRIX proj_mat_rh_transposed =
+    {{{
+        0.828732f, 0.0f,       0.0f,     0.0f,
+        0.0f,      1.104976f,  0.0f,     0.0f,
+        0.0f,      0.0f,      -1.0001f, -0.010001f,
+        0.0f,      0.0f,      -1.0f,     0.0f
+    }}};
+    static const D3DMATRIX view_mat_rh =
+    {{{
+        1.0f, 0.0f,  0.0f, 0.0f,
+        0.0f, 1.0f,  0.0f, 0.0f,
+        0.0f, 0.0f, -0.1f, 0.0f,
+        0.0f, 0.0f,  0.0f, 1.0f
+    }}};
+
+    window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            0, 0, 640, 480, NULL, NULL, NULL, NULL);
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    ok(!!d3d, "Failed to create a D3D object.\n");
+    if (!(device = create_device(d3d, window, window, TRUE)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        goto done;
+    }
+
+    hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get device caps, hr %#x.\n", hr);
+    if (caps.PixelShaderVersion >= D3DPS_VERSION(1, 1))
+    {
+        hr = IDirect3DDevice9_CreateVertexShader(device, vertex_shader_code1, &vertex_shader[1]);
+        ok(SUCCEEDED(hr), "CreateVertexShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_CreateVertexShader(device, vertex_shader_code2, &vertex_shader[2]);
+        ok(SUCCEEDED(hr), "CreateVertexShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_CreatePixelShader(device, pixel_shader_code, &pixel_shader[1]);
+        ok(SUCCEEDED(hr), "CreatePixelShader failed (%08x)\n", hr);
+
+        if (caps.PixelShaderVersion >= D3DPS_VERSION(2, 0))
+        {
+            hr = IDirect3DDevice9_CreateVertexShader(device, vertex_shader_code3, &vertex_shader[3]);
+            ok(SUCCEEDED(hr), "CreateVertexShader failed (%08x)\n", hr);
+            hr = IDirect3DDevice9_CreatePixelShader(device, pixel_shader_code2, &pixel_shader[2]);
+            ok(SUCCEEDED(hr), "CreatePixelShader failed (%08x)\n", hr);
+        } else {
+            skip("No shader model 2 support, skipping some fog tests.\n");
+        }
+    }
+    else
+    {
+        skip("No shader model 1.1 support, skipping some fog tests.\n");
+    }
+
+    start.f = 0.1f;
+    end.f = 0.9f;
+
+    hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements, &vertex_declaration);
+    ok(SUCCEEDED(hr), "CreateVertexDeclaration failed (%08x)\n", hr);
+
+    /* Setup initial states: No lighting, fog on, fog color */
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
+    ok(SUCCEEDED(hr), "Turning off lighting failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGENABLE, TRUE);
+    ok(SUCCEEDED(hr), "Turning on fog calculations failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGCOLOR, COLOR_FOG);
+    ok(SUCCEEDED(hr), "Setting fog color failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_SetVertexDeclaration(device, vertex_declaration);
+    ok(SUCCEEDED(hr), "SetVertexDeclaration failed (%08x)\n", hr);
+
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGSTART, start.i);
+    ok(SUCCEEDED(hr), "Setting fog start failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGEND, end.i);
+    ok(SUCCEEDED(hr), "Setting fog end failed (%08x)\n", hr);
+
+    hr = IDirect3DDevice9_SetTransform(device, D3DTS_PROJECTION, &proj_mat_rh);
+    ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr);
+    hr = IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &view_mat_rh);
+    ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_SetVertexShaderConstantF(device, 0, (const float*)&view_mat_rh, 4);
+    ok(SUCCEEDED(hr), "SetVertexShaderConstantF (view matrix) failed (%08x)\n", hr);
+    hr = IDirect3DDevice9_SetVertexShaderConstantF(device, 4, (const float*)&proj_mat_rh_transposed, 4);
+    ok(SUCCEEDED(hr), "SetVertexShaderConstantF (projection matrix) failed (%08x)\n", hr);
+
+    for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); i++)
+    {
+        if ((test_data[i].pshader != 0 && pixel_shader[test_data[i].pshader] == NULL)
+                || (test_data[i].vshader != 0 && vertex_shader[test_data[i].vshader] == NULL))
+            continue;
+
+        hr = IDirect3DDevice9_SetVertexShader(device, vertex_shader[test_data[i].vshader]);
+        ok(SUCCEEDED(hr), "SetVertexShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_SetPixelShader(device, pixel_shader[test_data[i].pshader]);
+        ok(SUCCEEDED(hr), "SetPixelShader failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGVERTEXMODE, test_data[i].vfog);
+        ok( SUCCEEDED(hr), "Setting fog vertex mode to %d failed (%08x)\n", test_data[i].vfog, hr);
+        hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGTABLEMODE, test_data[i].tfog);
+        ok( SUCCEEDED(hr), "Setting fog table mode to %d failed (%08x)\n", test_data[i].tfog, hr);
+
+        hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, COLOR_CLEAR, 1.0f, 0);
+        ok(SUCCEEDED(hr), "IDirect3DDevice9_Clear failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_BeginScene(device);
+        ok(SUCCEEDED(hr), "BeginScene failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLESTRIP, 2, &quad[0], sizeof(quad[0]));
+        ok(SUCCEEDED(hr), "DrawPrimitiveUP failed (%08x)\n", hr);
+        hr = IDirect3DDevice9_EndScene(device);
+        ok(SUCCEEDED(hr), "EndScene failed (%08x)\n", hr);
+
+        /* Use 5% tolerance on the colors since there may be a gradient
+         * between left and right vertices. */
+        color = getPixelColor(device, 60, 240);
+        ok(color_match(color, test_data[i].color_left, 13),
+                "fog vs%i ps%i fvm%i ftm%i: got left color %08x, expected %08x+-5%%\n",
+                test_data[i].vshader, test_data[i].pshader, test_data[i].vfog,
+                test_data[i].tfog, color, test_data[i].color_left);
+        color = getPixelColor(device, 580, 240);
+        ok(color_match(color, test_data[i].color_right, 13),
+                "fog vs%i ps%i fvm%i ftm%i: got right color %08x, expected %08x+-5%%\n",
+                test_data[i].vshader, test_data[i].pshader, test_data[i].vfog,
+                test_data[i].tfog, color, test_data[i].color_right);
+
+        IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+    }
+
+    for (i = 0; i < sizeof(vertex_shader)/sizeof(vertex_shader[0]); i++)
+        if (vertex_shader[i])
+            IDirect3DVertexShader9_Release(vertex_shader[i]);
+    for (i = 0; i < sizeof(pixel_shader)/sizeof(pixel_shader[0]); i++)
+        if (pixel_shader[i])
+            IDirect3DPixelShader9_Release(pixel_shader[i]);
+    IDirect3DVertexDeclaration9_Release(vertex_declaration);
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+done:
+    IDirect3D9_Release(d3d);
+    DestroyWindow(window);
+}
+
 /* This test tests fog in combination with shaders.
  * What's tested: linear fog (vertex and table) with pixel shader
  *                linear table fog with non foggy vertex shader
@@ -16729,6 +17052,7 @@ START_TEST(visual)
     test_vshader_input();
     test_vshader_float16();
     stream_test();
+    fog_righthanded_test();
     fog_with_shader_test();
     texbem_test();
     texdepth_test();
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 34cc567..f158ee2 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -5005,7 +5005,7 @@ static GLhandleARB shader_glsl_generate_ffp_vertex_shader(struct wined3d_shader_
                 /* Need to undo the [0.0 - 1.0] -> [-1.0 - 1.0] transformation from D3D to GL coordinates. */
                 shader_addline(buffer, "gl_FogFragCoord = gl_Position.z * 0.5 + 0.5;\n");
             else
-                shader_addline(buffer, "gl_FogFragCoord = ec_pos.z;\n");
+                shader_addline(buffer, "gl_FogFragCoord = abs(ec_pos.z);\n");
             break;
 
         default:
-- 
1.8.4.5




More information about the wine-patches mailing list