[PATCH 1/5] ddraw: Handle the Direct3D clipspace transformation.

Henri Verbeet hverbeet at codeweavers.com
Wed Dec 21 14:34:56 CST 2011


Direct3D3 and earlier have an extra transformation to scale clipspace. It's
controlled by the extra viewport parameters in those versions.
---
 dlls/ddraw/ddraw_private.h |    2 +
 dlls/ddraw/device.c        |   74 ++++++++++++++++++++++++++++++++++++++-----
 dlls/ddraw/tests/ddraw4.c  |   24 +++++++-------
 dlls/ddraw/viewport.c      |   53 +++++++++++++++++++++++++------
 4 files changed, 122 insertions(+), 31 deletions(-)

diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index 41bb4fd..d848c82 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -300,6 +300,8 @@ struct IDirect3DDeviceImpl
 
     /* Required to keep track which of two available texture blending modes in d3ddevice3 is used */
     BOOL legacyTextureBlending;
+    D3DMATRIX legacy_projection;
+    D3DMATRIX legacy_clipspace;
 
     /* Light state */
     DWORD material;
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index ed0d567..d90bf82 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -3279,13 +3279,32 @@ IDirect3DDeviceImpl_7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
 }
 
 static HRESULT WINAPI IDirect3DDeviceImpl_3_SetTransform(IDirect3DDevice3 *iface,
-        D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
+        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
 {
     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
 
-    TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
+    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
 
-    return IDirect3DDevice7_SetTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
+    if (!matrix)
+        return DDERR_INVALIDPARAMS;
+
+    if (state == D3DTRANSFORMSTATE_PROJECTION)
+    {
+        D3DMATRIX projection;
+        HRESULT hr;
+
+        wined3d_mutex_lock();
+        multiply_matrix(&projection, &This->legacy_clipspace, matrix);
+        hr = wined3d_device_set_transform(This->wined3d_device,
+                WINED3DTS_PROJECTION, (struct wined3d_matrix *)&projection);
+        if (SUCCEEDED(hr))
+            This->legacy_projection = *matrix;
+        wined3d_mutex_unlock();
+
+        return hr;
+    }
+
+    return IDirect3DDevice7_SetTransform(&This->IDirect3DDevice7_iface, state, matrix);
 }
 
 static HRESULT WINAPI IDirect3DDeviceImpl_2_SetTransform(IDirect3DDevice2 *iface,
@@ -3370,13 +3389,24 @@ IDirect3DDeviceImpl_7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
 }
 
 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetTransform(IDirect3DDevice3 *iface,
-        D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
+        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
 {
     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
 
-    TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
+    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
 
-    return IDirect3DDevice7_GetTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
+    if (!matrix)
+        return DDERR_INVALIDPARAMS;
+
+    if (state == D3DTRANSFORMSTATE_PROJECTION)
+    {
+        wined3d_mutex_lock();
+        *matrix = This->legacy_projection;
+        wined3d_mutex_unlock();
+        return DD_OK;
+    }
+
+    return IDirect3DDevice7_GetTransform(&This->IDirect3DDevice7_iface, state, matrix);
 }
 
 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetTransform(IDirect3DDevice2 *iface,
@@ -3460,13 +3490,30 @@ IDirect3DDeviceImpl_7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
 }
 
 static HRESULT WINAPI IDirect3DDeviceImpl_3_MultiplyTransform(IDirect3DDevice3 *iface,
-        D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
+        D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
 {
     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
 
-    TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
+    TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
 
-    return IDirect3DDevice7_MultiplyTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
+    if (state == D3DTRANSFORMSTATE_PROJECTION)
+    {
+        D3DMATRIX projection, tmp;
+        HRESULT hr;
+
+        wined3d_mutex_lock();
+        multiply_matrix(&tmp, &This->legacy_projection, matrix);
+        multiply_matrix(&projection, &This->legacy_clipspace, &tmp);
+        hr = wined3d_device_set_transform(This->wined3d_device,
+                WINED3DTS_PROJECTION, (struct wined3d_matrix *)&projection);
+        if (SUCCEEDED(hr))
+            This->legacy_projection = tmp;
+        wined3d_mutex_unlock();
+
+        return hr;
+    }
+
+    return IDirect3DDevice7_MultiplyTransform(&This->IDirect3DDevice7_iface, state, matrix);
 }
 
 static HRESULT WINAPI IDirect3DDeviceImpl_2_MultiplyTransform(IDirect3DDevice2 *iface,
@@ -6911,6 +6958,13 @@ IDirect3DDeviceImpl_UpdateDepthStencil(IDirect3DDeviceImpl *This)
 
 HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *target)
 {
+    static const D3DMATRIX ident =
+    {
+        1.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 1.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 1.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 1.0f,
+    };
     HRESULT hr;
 
     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
@@ -6933,6 +6987,8 @@ HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDi
     }
 
     device->legacyTextureBlending = FALSE;
+    device->legacy_projection = ident;
+    device->legacy_clipspace = ident;
 
     /* Create an index buffer, it's needed for indexed drawing */
     hr = wined3d_buffer_create_ib(ddraw->wined3d_device, 0x40000 /* Length. Don't know how long it should be */,
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 9a34a1a..033a82d 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -216,13 +216,13 @@ static void test_process_vertices(void)
 
     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
-    todo_wine ok(compare_vec4(&dst_data[0], -6.500e+1f, +1.800e+2f, +2.000e-1f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[0], -6.500e+1f, +1.800e+2f, +2.000e-1f, +1.000e+0f, 4096),
             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
-    todo_wine ok(compare_vec4(&dst_data[1], -4.000e+1f, +1.400e+2f, +4.000e-1f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[1], -4.000e+1f, +1.400e+2f, +4.000e-1f, +1.000e+0f, 4096),
             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
-    todo_wine ok(compare_vec4(&dst_data[2], -1.500e+1f, +1.000e+2f, +6.000e-1f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[2], -1.500e+1f, +1.000e+2f, +6.000e-1f, +1.000e+0f, 4096),
             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
@@ -236,13 +236,13 @@ static void test_process_vertices(void)
 
     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
-    todo_wine ok(compare_vec4(&dst_data[0], +8.500e+1f, -1.000e+2f, +1.800e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[0], +8.500e+1f, -1.000e+2f, +1.800e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
-    todo_wine ok(compare_vec4(&dst_data[1], +1.100e+2f, -1.400e+2f, +2.000e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[1], +1.100e+2f, -1.400e+2f, +2.000e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
-    todo_wine ok(compare_vec4(&dst_data[2], +1.350e+2f, -1.800e+2f, +2.200e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[2], +1.350e+2f, -1.800e+2f, +2.200e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
@@ -267,13 +267,13 @@ static void test_process_vertices(void)
 
     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
-    todo_wine ok(compare_vec4(&dst_data[0], +7.500e+1f, +4.000e+1f, -8.000e-1f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[0], +7.500e+1f, +4.000e+1f, -8.000e-1f, +1.000e+0f, 4096),
             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
-    todo_wine ok(compare_vec4(&dst_data[1], +1.200e+2f, +2.000e+1f, -1.000e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[1], +1.200e+2f, +2.000e+1f, -1.000e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
-    todo_wine ok(compare_vec4(&dst_data[2], +1.650e+2f, +0.000e+0f, -1.200e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[2], +1.650e+2f, +0.000e+0f, -1.200e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
@@ -298,13 +298,13 @@ static void test_process_vertices(void)
 
     hr = IDirect3DVertexBuffer_Lock(dst_vb, DDLOCK_READONLY, (void **)&dst_data, NULL);
     ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr);
-    todo_wine ok(compare_vec4(&dst_data[0], +1.100e+2f, +6.800e+1f, +7.000e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[0], +1.100e+2f, +6.800e+1f, +7.000e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 0 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[0].x, dst_data[0].y, dst_data[0].z, dst_data[0].w);
-    todo_wine ok(compare_vec4(&dst_data[1], +1.170e+2f, +6.600e+1f, +8.000e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[1], +1.170e+2f, +6.600e+1f, +8.000e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 1 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[1].x, dst_data[1].y, dst_data[1].z, dst_data[1].w);
-    todo_wine ok(compare_vec4(&dst_data[2], +1.240e+2f, +6.400e+1f, +9.000e+0f, +1.000e+0f, 4096),
+    ok(compare_vec4(&dst_data[2], +1.240e+2f, +6.400e+1f, +9.000e+0f, +1.000e+0f, 4096),
             "Got unexpected vertex 2 {%.8e, %.8e, %.8e, %.8e}.\n",
             dst_data[2].x, dst_data[2].y, dst_data[2].z, dst_data[2].w);
     hr = IDirect3DVertexBuffer_Unlock(dst_vb);
diff --git a/dlls/ddraw/viewport.c b/dlls/ddraw/viewport.c
index b5d2a0c..d82f1de 100644
--- a/dlls/ddraw/viewport.c
+++ b/dlls/ddraw/viewport.c
@@ -30,6 +30,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
  * Helper functions
  *****************************************************************************/
 
+static void update_clip_space(IDirect3DDeviceImpl *device,
+        struct wined3d_vec3 *scale, struct wined3d_vec3 *offset)
+{
+    D3DMATRIX clip_space =
+    {
+        scale->x,  0.0f,      0.0f,      0.0f,
+        0.0f,      scale->y,  0.0f,      0.0f,
+        0.0f,      0.0f,      scale->z,  0.0f,
+        offset->x, offset->y, offset->z, 1.0f,
+    };
+    D3DMATRIX projection;
+    HRESULT hr;
+
+    multiply_matrix(&projection, &clip_space, &device->legacy_projection);
+    hr = wined3d_device_set_transform(device->wined3d_device,
+            WINED3DTS_PROJECTION, (struct wined3d_matrix *)&projection);
+    if (SUCCEEDED(hr))
+        device->legacy_clipspace = clip_space;
+}
+
 /*****************************************************************************
  * viewport_activate
  *
@@ -38,6 +58,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
  *****************************************************************************/
 void viewport_activate(IDirect3DViewportImpl *This, BOOL ignore_lights)
 {
+    struct wined3d_vec3 scale, offset;
     D3DVIEWPORT7 vp;
 
     if (!ignore_lights)
@@ -58,8 +79,15 @@ void viewport_activate(IDirect3DViewportImpl *This, BOOL ignore_lights)
         vp.dwY = This->viewports.vp2.dwY;
         vp.dwHeight = This->viewports.vp2.dwHeight;
         vp.dwWidth = This->viewports.vp2.dwWidth;
-        vp.dvMinZ = This->viewports.vp2.dvMinZ;
-        vp.dvMaxZ = This->viewports.vp2.dvMaxZ;
+        vp.dvMinZ = 0.0f;
+        vp.dvMaxZ = 1.0f;
+
+        scale.x = 2.0f / This->viewports.vp2.dvClipWidth;
+        scale.y = 2.0f / This->viewports.vp2.dvClipHeight;
+        scale.z = 1.0f / (This->viewports.vp2.dvMaxZ - This->viewports.vp2.dvMinZ);
+        offset.x = -2.0f * This->viewports.vp2.dvClipX / This->viewports.vp2.dvClipWidth - 1.0f;
+        offset.y = -2.0f * This->viewports.vp2.dvClipY / This->viewports.vp2.dvClipHeight + 1.0f;
+        offset.z = -This->viewports.vp2.dvMinZ / (This->viewports.vp2.dvMaxZ - This->viewports.vp2.dvMinZ);
     }
     else
     {
@@ -67,11 +95,18 @@ void viewport_activate(IDirect3DViewportImpl *This, BOOL ignore_lights)
         vp.dwY = This->viewports.vp1.dwY;
         vp.dwHeight = This->viewports.vp1.dwHeight;
         vp.dwWidth = This->viewports.vp1.dwWidth;
-        vp.dvMinZ = This->viewports.vp1.dvMinZ;
-        vp.dvMaxZ = This->viewports.vp1.dvMaxZ;
+        vp.dvMinZ = 0.0f;
+        vp.dvMaxZ = 1.0f;
+
+        scale.x = 2.0f * This->viewports.vp1.dvScaleX / This->viewports.vp1.dwWidth;
+        scale.y = 2.0f * This->viewports.vp1.dvScaleY / This->viewports.vp1.dwHeight;
+        scale.z = 1.0f;
+        offset.x = 0.0f;
+        offset.y = 0.0f;
+        offset.z = 0.0f;
     }
 
-    /* And also set the viewport */
+    update_clip_space(This->active_device, &scale, &offset);
     IDirect3DDevice7_SetViewport(&This->active_device->IDirect3DDevice7_iface, &vp);
 }
 
@@ -368,7 +403,7 @@ IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
                                         DWORD *lpOffScreen)
 {
     IDirect3DViewportImpl *This = impl_from_IDirect3DViewport3(iface);
-    D3DMATRIX view_mat, world_mat, proj_mat, mat;
+    D3DMATRIX view_mat, world_mat, mat;
     float *in;
     float *out;
     float x, y, z, w;
@@ -399,11 +434,9 @@ IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
     wined3d_device_get_transform(This->active_device->wined3d_device,
             D3DTRANSFORMSTATE_VIEW, (struct wined3d_matrix *)&view_mat);
     wined3d_device_get_transform(This->active_device->wined3d_device,
-            D3DTRANSFORMSTATE_PROJECTION, (struct wined3d_matrix *)&proj_mat);
-    wined3d_device_get_transform(This->active_device->wined3d_device,
             WINED3DTS_WORLDMATRIX(0), (struct wined3d_matrix *)&world_mat);
-    multiply_matrix(&mat,&view_mat,&world_mat);
-    multiply_matrix(&mat,&proj_mat,&mat);
+    multiply_matrix(&mat, &view_mat, &world_mat);
+    multiply_matrix(&mat, &This->active_device->legacy_projection, &mat);
 
     in = lpData->lpIn;
     out = lpData->lpOut;
-- 
1.7.3.4




More information about the wine-patches mailing list