| /* |
| * Copyright 2006 Stefan Dösinger for CodeWeavers |
| * Copyright 2011 Henri Verbeet for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "wine/test.h" |
| #include <limits.h> |
| #include "d3d.h" |
| |
| static HRESULT (WINAPI *pDirectDrawCreateEx)(GUID *guid, void **ddraw, REFIID iid, IUnknown *outer_unknown); |
| |
| struct vec3 |
| { |
| float x, y, z; |
| }; |
| |
| struct vec4 |
| { |
| float x, y, z, w; |
| }; |
| |
| static BOOL compare_float(float f, float g, unsigned int ulps) |
| { |
| int x = *(int *)&f; |
| int y = *(int *)&g; |
| |
| if (x < 0) |
| x = INT_MIN - x; |
| if (y < 0) |
| y = INT_MIN - y; |
| |
| if (abs(x - y) > ulps) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| static BOOL compare_vec3(struct vec3 *vec, float x, float y, float z, unsigned int ulps) |
| { |
| return compare_float(vec->x, x, ulps) |
| && compare_float(vec->y, y, ulps) |
| && compare_float(vec->z, z, ulps); |
| } |
| |
| static BOOL compare_vec4(struct vec4 *vec, float x, float y, float z, float w, unsigned int ulps) |
| { |
| return compare_float(vec->x, x, ulps) |
| && compare_float(vec->y, y, ulps) |
| && compare_float(vec->z, z, ulps) |
| && compare_float(vec->w, w, ulps); |
| } |
| |
| static IDirect3DDevice7 *create_device(HWND window, DWORD coop_level) |
| { |
| IDirect3DDevice7 *device = NULL; |
| IDirectDrawSurface7 *surface; |
| DDSURFACEDESC2 surface_desc; |
| IDirectDraw7 *ddraw; |
| IDirect3D7 *d3d7; |
| HRESULT hr; |
| |
| if (FAILED(pDirectDrawCreateEx(NULL, (void **)&ddraw, &IID_IDirectDraw7, NULL))) |
| return NULL; |
| |
| hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, coop_level); |
| ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr); |
| |
| memset(&surface_desc, 0, sizeof(surface_desc)); |
| surface_desc.dwSize = sizeof(surface_desc); |
| surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; |
| surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; |
| surface_desc.dwWidth = 640; |
| surface_desc.dwHeight = 480; |
| |
| hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL); |
| ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr); |
| |
| if (coop_level & DDSCL_NORMAL) |
| { |
| IDirectDrawClipper *clipper; |
| |
| hr = IDirectDraw7_CreateClipper(ddraw, 0, &clipper, NULL); |
| ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr); |
| hr = IDirectDrawClipper_SetHWnd(clipper, 0, window); |
| ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr); |
| hr = IDirectDrawSurface7_SetClipper(surface, clipper); |
| ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr); |
| IDirectDrawClipper_Release(clipper); |
| } |
| |
| hr = IDirectDraw7_QueryInterface(ddraw, &IID_IDirect3D7, (void **)&d3d7); |
| IDirectDraw7_Release(ddraw); |
| if (FAILED(hr)) |
| { |
| IDirectDrawSurface7_Release(surface); |
| return NULL; |
| } |
| |
| hr = IDirect3D7_CreateDevice(d3d7, &IID_IDirect3DTnLHalDevice, surface, &device); |
| IDirect3D7_Release(d3d7); |
| IDirectDrawSurface7_Release(surface); |
| if (FAILED(hr)) |
| return NULL; |
| |
| return device; |
| } |
| |
| static void test_process_vertices(void) |
| { |
| IDirect3DVertexBuffer7 *src_vb, *dst_vb1, *dst_vb2; |
| D3DVERTEXBUFFERDESC vb_desc; |
| IDirect3DDevice7 *device; |
| struct vec4 *dst_data; |
| struct vec3 *dst_data2; |
| struct vec3 *src_data; |
| IDirect3D7 *d3d7; |
| D3DVIEWPORT7 vp; |
| HWND window; |
| HRESULT hr; |
| |
| static D3DMATRIX world = |
| { |
| 0.0f, 1.0f, 0.0f, 0.0f, |
| 1.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 1.0f, |
| 0.0f, 1.0f, 1.0f, 1.0f, |
| }; |
| static D3DMATRIX view = |
| { |
| 2.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, 3.0f, |
| }; |
| static D3DMATRIX proj = |
| { |
| 1.0f, 0.0f, 0.0f, 1.0f, |
| 0.0f, 1.0f, 1.0f, 0.0f, |
| 0.0f, 1.0f, 1.0f, 0.0f, |
| 1.0f, 0.0f, 0.0f, 1.0f, |
| }; |
| |
| window = CreateWindowA("static", "d3d7_test", WS_OVERLAPPEDWINDOW, |
| 0, 0, 640, 480, 0, 0, 0, 0); |
| if (!(device = create_device(window, DDSCL_NORMAL))) |
| { |
| skip("Failed to create a 3D device, skipping test.\n"); |
| DestroyWindow(window); |
| return; |
| } |
| |
| hr = IDirect3DDevice7_GetDirect3D(device, &d3d7); |
| ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr); |
| |
| memset(&vb_desc, 0, sizeof(vb_desc)); |
| vb_desc.dwSize = sizeof(vb_desc); |
| vb_desc.dwFVF = D3DFVF_XYZ; |
| vb_desc.dwNumVertices = 4; |
| hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &src_vb, 0); |
| ok(SUCCEEDED(hr), "Failed to create source vertex buffer, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_Lock(src_vb, 0, (void **)&src_data, NULL); |
| ok(SUCCEEDED(hr), "Failed to lock source vertex buffer, hr %#x.\n", hr); |
| src_data[0].x = 0.0f; |
| src_data[0].y = 0.0f; |
| src_data[0].z = 0.0f; |
| src_data[1].x = 1.0f; |
| src_data[1].y = 1.0f; |
| src_data[1].z = 1.0f; |
| src_data[2].x = -1.0f; |
| src_data[2].y = -1.0f; |
| src_data[2].z = 0.5f; |
| src_data[3].x = 0.5f; |
| src_data[3].y = -0.5f; |
| src_data[3].z = 0.25f; |
| hr = IDirect3DVertexBuffer7_Unlock(src_vb); |
| ok(SUCCEEDED(hr), "Failed to unlock source vertex buffer, hr %#x.\n", hr); |
| |
| memset(&vb_desc, 0, sizeof(vb_desc)); |
| vb_desc.dwSize = sizeof(vb_desc); |
| vb_desc.dwFVF = D3DFVF_XYZRHW; |
| vb_desc.dwNumVertices = 4; |
| /* MSDN says that the last parameter must be 0 - check that. */ |
| hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &dst_vb1, 4); |
| ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr); |
| |
| memset(&vb_desc, 0, sizeof(vb_desc)); |
| vb_desc.dwSize = sizeof(vb_desc); |
| vb_desc.dwFVF = D3DFVF_XYZ; |
| vb_desc.dwNumVertices = 5; |
| /* MSDN says that the last parameter must be 0 - check that. */ |
| hr = IDirect3D7_CreateVertexBuffer(d3d7, &vb_desc, &dst_vb2, 12345678); |
| ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr); |
| |
| memset(&vp, 0, sizeof(vp)); |
| vp.dwX = 64; |
| vp.dwY = 64; |
| vp.dwWidth = 128; |
| vp.dwHeight = 128; |
| vp.dvMinZ = 0.0f; |
| vp.dvMaxZ = 1.0f; |
| hr = IDirect3DDevice7_SetViewport(device, &vp); |
| ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0); |
| ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr); |
| hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb2, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0); |
| ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL); |
| ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr); |
| ok(compare_vec4(&dst_data[0], +1.280e+2f, +1.280e+2f, +0.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); |
| ok(compare_vec4(&dst_data[1], +1.920e+2f, +6.400e+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); |
| ok(compare_vec4(&dst_data[2], +6.400e+1f, +1.920e+2f, +5.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); |
| ok(compare_vec4(&dst_data[3], +1.600e+2f, +1.600e+2f, +2.500e-1f, +1.000e+0f, 4096), |
| "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n", |
| dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w); |
| hr = IDirect3DVertexBuffer7_Unlock(dst_vb1); |
| ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_Lock(dst_vb2, 0, (void **)&dst_data2, NULL); |
| ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr); |
| /* Small thing without much practical meaning, but I stumbled upon it, |
| * so let's check for it: If the output vertex buffer has no RHW value, |
| * the RHW value of the last vertex is written into the next vertex. */ |
| ok(compare_vec3(&dst_data2[4], +1.000e+0f, +0.000e+0f, +0.000e+0f, 4096), |
| "Got unexpected vertex 4 {%.8e, %.8e, %.8e}.\n", |
| dst_data2[4].x, dst_data2[4].y, dst_data2[4].z); |
| hr = IDirect3DVertexBuffer7_Unlock(dst_vb2); |
| ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr); |
| |
| /* Try a more complicated viewport, same vertices. */ |
| memset(&vp, 0, sizeof(vp)); |
| vp.dwX = 10; |
| vp.dwY = 5; |
| vp.dwWidth = 246; |
| vp.dwHeight = 130; |
| vp.dvMinZ = -2.0f; |
| vp.dvMaxZ = 4.0f; |
| hr = IDirect3DDevice7_SetViewport(device, &vp); |
| ok(SUCCEEDED(hr), "Failed to set viewport, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0); |
| ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL); |
| ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr); |
| ok(compare_vec4(&dst_data[0], +1.330e+2f, +7.000e+1f, -2.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); |
| ok(compare_vec4(&dst_data[1], +2.560e+2f, +5.000e+0f, +4.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); |
| ok(compare_vec4(&dst_data[2], +1.000e+1f, +1.350e+2f, +1.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); |
| ok(compare_vec4(&dst_data[3], +1.945e+2f, +1.025e+2f, -5.000e-1f, +1.000e+0f, 4096), |
| "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n", |
| dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w); |
| hr = IDirect3DVertexBuffer7_Unlock(dst_vb1); |
| ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr); |
| |
| hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_WORLD, &world); |
| ok(SUCCEEDED(hr), "Failed to set world transform, hr %#x.\n", hr); |
| hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_VIEW, &view); |
| ok(SUCCEEDED(hr), "Failed to set view transform, hr %#x.\n", hr); |
| hr = IDirect3DDevice7_SetTransform(device, D3DTRANSFORMSTATE_PROJECTION, &proj); |
| ok(SUCCEEDED(hr), "Failed to set projection transform, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_ProcessVertices(dst_vb1, D3DVOP_TRANSFORM, 0, 4, src_vb, 0, device, 0); |
| ok(SUCCEEDED(hr), "Failed to process vertices, hr %#x.\n", hr); |
| |
| hr = IDirect3DVertexBuffer7_Lock(dst_vb1, 0, (void **)&dst_data, NULL); |
| ok(SUCCEEDED(hr), "Failed to lock destination vertex buffer, hr %#x.\n", hr); |
| ok(compare_vec4(&dst_data[0], +2.560e+2f, +7.000e+1f, -2.000e+0f, +3.333e-1f, 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); |
| ok(compare_vec4(&dst_data[1], +2.560e+2f, +7.813e+1f, -2.750e+0f, +1.250e-1f, 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); |
| ok(compare_vec4(&dst_data[2], +2.560e+2f, +4.400e+1f, +4.000e-1f, +4.000e-1f, 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); |
| ok(compare_vec4(&dst_data[3], +2.560e+2f, +8.182e+1f, -3.091e+0f, +3.636e-1f, 4096), |
| "Got unexpected vertex 3 {%.8e, %.8e, %.8e, %.8e}.\n", |
| dst_data[3].x, dst_data[3].y, dst_data[3].z, dst_data[3].w); |
| hr = IDirect3DVertexBuffer7_Unlock(dst_vb1); |
| ok(SUCCEEDED(hr), "Failed to unlock destination vertex buffer, hr %#x.\n", hr); |
| |
| IDirect3DVertexBuffer7_Release(dst_vb2); |
| IDirect3DVertexBuffer7_Release(dst_vb1); |
| IDirect3DVertexBuffer7_Release(src_vb); |
| IDirect3D7_Release(d3d7); |
| IDirect3DDevice7_Release(device); |
| DestroyWindow(window); |
| } |
| |
| START_TEST(ddraw7) |
| { |
| HMODULE module = GetModuleHandleA("ddraw.dll"); |
| |
| if (!(pDirectDrawCreateEx = (void *)GetProcAddress(module, "DirectDrawCreateEx"))) |
| { |
| win_skip("DirectDrawCreateEx not available, skipping tests.\n"); |
| return; |
| } |
| |
| test_process_vertices(); |
| } |