ddraw: Handle the Direct3D clipspace transformation.

Direct3D3 and earlier have an extra transformation to scale clipspace. It's
controlled by the extra viewport parameters in those versions.
This commit is contained in:
Henri Verbeet 2011-12-21 21:34:56 +01:00 committed by Alexandre Julliard
parent 27e3e1a89b
commit 4a30db74b1
4 changed files with 122 additions and 31 deletions

View File

@ -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;

View File

@ -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 */,

View File

@ -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);

View File

@ -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;
@ -398,12 +433,10 @@ IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
wined3d_mutex_lock();
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;