[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