ddraw: Fix and test case for situation where DDSD_MIPMAPCOUNT is set and dwMipMapCoun...
[wine] / dlls / ddraw / tests / d3d.c
1 /*
2  * Some unit tests for d3d functions
3  *
4  * Copyright (C) 2005 Antoine Chavasse
5  * Copyright (C) 2006 Stefan Dösinger for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <assert.h>
23 #include "wine/test.h"
24 #include "ddraw.h"
25 #include "d3d.h"
26
27 static LPDIRECTDRAW7           lpDD = NULL;
28 static LPDIRECT3D7             lpD3D = NULL;
29 static LPDIRECTDRAWSURFACE7    lpDDS = NULL;
30 static LPDIRECTDRAWSURFACE7    lpDDSdepth = NULL;
31 static LPDIRECT3DDEVICE7       lpD3DDevice = NULL;
32 static LPDIRECT3DVERTEXBUFFER7 lpVBufSrc = NULL;
33 static LPDIRECT3DVERTEXBUFFER7 lpVBufDest1 = NULL;
34 static LPDIRECT3DVERTEXBUFFER7 lpVBufDest2 = NULL;
35
36 /* To compare bad floating point numbers. Not the ideal way to do it,
37  * but it should be enough for here */
38 #define comparefloat(a, b) ( (((a) - (b)) < 0.0001) && (((a) - (b)) > -0.0001) )
39
40 static HRESULT (WINAPI *pDirectDrawCreateEx)(LPGUID,LPVOID*,REFIID,LPUNKNOWN);
41
42 typedef struct _VERTEX
43 {
44     float x, y, z;  /* position */
45 } VERTEX, *LPVERTEX;
46
47 typedef struct _TVERTEX
48 {
49     float x, y, z;  /* position */
50     float rhw;
51 } TVERTEX, *LPTVERTEX;
52
53
54 static void init_function_pointers(void)
55 {
56     HMODULE hmod = GetModuleHandleA("ddraw.dll");
57     pDirectDrawCreateEx = (void*)GetProcAddress(hmod, "DirectDrawCreateEx");
58 }
59
60
61 static BOOL CreateDirect3D(void)
62 {
63     HRESULT rc;
64     DDSURFACEDESC2 ddsd;
65
66     rc = pDirectDrawCreateEx(NULL, (void**)&lpDD,
67         &IID_IDirectDraw7, NULL);
68     ok(rc==DD_OK || rc==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", rc);
69     if (!lpDD) {
70         trace("DirectDrawCreateEx() failed with an error %x\n", rc);
71         return FALSE;
72     }
73
74     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL);
75     ok(rc==DD_OK, "SetCooperativeLevel returned: %x\n", rc);
76
77     rc = IDirectDraw7_QueryInterface(lpDD, &IID_IDirect3D7, (void**) &lpD3D);
78     if (rc == E_NOINTERFACE) return FALSE;
79     ok(rc==DD_OK, "QueryInterface returned: %x\n", rc);
80
81     memset(&ddsd, 0, sizeof(ddsd));
82     ddsd.dwSize = sizeof(ddsd);
83     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
84     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
85     ddsd.dwWidth = 256;
86     ddsd.dwHeight = 256;
87     rc = IDirectDraw7_CreateSurface(lpDD, &ddsd, &lpDDS, NULL);
88     ok(rc==DD_OK, "CreateSurface returned: %x\n", rc);
89     if (!SUCCEEDED(rc))
90         return FALSE;
91
92     memset(&ddsd, 0, sizeof(ddsd));
93     ddsd.dwSize = sizeof(ddsd);
94     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
95     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
96     U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
97     U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
98     U1(U4(ddsd).ddpfPixelFormat).dwZBufferBitDepth = 16;
99     U3(U4(ddsd).ddpfPixelFormat).dwZBitMask = 0x0000FFFF;
100     ddsd.dwWidth = 256;
101     ddsd.dwHeight = 256;
102     rc = IDirectDraw7_CreateSurface(lpDD, &ddsd, &lpDDSdepth, NULL);
103     ok(rc==DD_OK, "CreateSurface returned: %x\n", rc);
104     if (!SUCCEEDED(rc)) {
105         lpDDSdepth = NULL;
106     } else {
107         rc = IDirectDrawSurface_AddAttachedSurface(lpDDS, lpDDSdepth);
108         ok(rc == DD_OK, "IDirectDrawSurface_AddAttachedSurface returned %x\n", rc);
109         if (!SUCCEEDED(rc))
110             return FALSE;
111     }
112
113     rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DTnLHalDevice, lpDDS,
114         &lpD3DDevice);
115     ok(rc==D3D_OK || rc==DDERR_NOPALETTEATTACHED || rc==E_OUTOFMEMORY, "CreateDevice returned: %x\n", rc);
116     if (!lpD3DDevice) {
117         trace("IDirect3D7::CreateDevice() for a TnL Hal device failed with an error %x, trying HAL\n", rc);
118         rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DHALDevice, lpDDS,
119             &lpD3DDevice);
120         if (!lpD3DDevice) {
121             trace("IDirect3D7::CreateDevice() for a HAL device failed with an error %x, trying RGB\n", rc);
122             rc = IDirect3D7_CreateDevice(lpD3D, &IID_IDirect3DRGBDevice, lpDDS,
123                 &lpD3DDevice);
124             if (!lpD3DDevice) {
125                 trace("IDirect3D7::CreateDevice() for a RGB device failed with an error %x, giving up\n", rc);
126                 return FALSE;
127             }
128         }
129     }
130
131     return TRUE;
132 }
133
134 static void ReleaseDirect3D(void)
135 {
136     if (lpD3DDevice != NULL)
137     {
138         IDirect3DDevice7_Release(lpD3DDevice);
139         lpD3DDevice = NULL;
140     }
141
142     if (lpDDSdepth != NULL)
143     {
144         IDirectDrawSurface_Release(lpDDSdepth);
145         lpDDSdepth = NULL;
146     }
147
148     if (lpDDS != NULL)
149     {
150         IDirectDrawSurface_Release(lpDDS);
151         lpDDS = NULL;
152     }
153
154     if (lpD3D != NULL)
155     {
156         IDirect3D7_Release(lpD3D);
157         lpD3D = NULL;
158     }
159
160     if (lpDD != NULL)
161     {
162         IDirectDraw_Release(lpDD);
163         lpDD = NULL;
164     }
165 }
166
167 static void LightTest(void)
168 {
169     HRESULT rc;
170     D3DLIGHT7 light;
171     D3DLIGHT7 defaultlight;
172     BOOL bEnabled = FALSE;
173     float one = 1.0f;
174     float zero= 0.0f;
175     D3DMATERIAL7 mat;
176
177     /* Set a few lights with funky indices. */
178     memset(&light, 0, sizeof(light));
179     light.dltType = D3DLIGHT_DIRECTIONAL;
180     U1(light.dcvDiffuse).r = 0.5f;
181     U2(light.dcvDiffuse).g = 0.6f;
182     U3(light.dcvDiffuse).b = 0.7f;
183     U2(light.dvDirection).y = 1.f;
184
185     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 5, &light);
186     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
187     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 10, &light);
188     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
189     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 45, &light);
190     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
191
192
193     /* Try to retrieve a light beyond the indices of the lights that have
194        been set. */
195     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 50, &light);
196     ok(rc==DDERR_INVALIDPARAMS, "GetLight returned: %x\n", rc);
197     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 2, &light);
198     ok(rc==DDERR_INVALIDPARAMS, "GetLight returned: %x\n", rc);
199
200
201     /* Try to retrieve one of the lights that have been set */
202     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 10, &light);
203     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
204
205
206     /* Enable a light that have been previously set. */
207     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 10, TRUE);
208     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
209
210
211     /* Enable some lights that have not been previously set, and verify that
212        they have been initialized with proper default values. */
213     memset(&defaultlight, 0, sizeof(D3DLIGHT7));
214     defaultlight.dltType = D3DLIGHT_DIRECTIONAL;
215     U1(defaultlight.dcvDiffuse).r = 1.f;
216     U2(defaultlight.dcvDiffuse).g = 1.f;
217     U3(defaultlight.dcvDiffuse).b = 1.f;
218     U3(defaultlight.dvDirection).z = 1.f;
219
220     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 20, TRUE);
221     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
222     memset(&light, 0, sizeof(D3DLIGHT7));
223     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 20, &light);
224     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
225     ok(!memcmp(&light, &defaultlight, sizeof(D3DLIGHT7)),
226         "light data doesn't match expected default values\n" );
227
228     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 50, TRUE);
229     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
230     memset(&light, 0, sizeof(D3DLIGHT7));
231     rc = IDirect3DDevice7_GetLight(lpD3DDevice, 50, &light);
232     ok(rc==D3D_OK, "GetLight returned: %x\n", rc);
233     ok(!memcmp(&light, &defaultlight, sizeof(D3DLIGHT7)),
234         "light data doesn't match expected default values\n" );
235
236
237     /* Disable one of the light that have been previously enabled. */
238     rc = IDirect3DDevice7_LightEnable(lpD3DDevice, 20, FALSE);
239     ok(rc==D3D_OK, "LightEnable returned: %x\n", rc);
240
241     /* Try to retrieve the enable status of some lights */
242     /* Light 20 is supposed to be disabled */
243     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 20, &bEnabled );
244     ok(rc==D3D_OK, "GetLightEnable returned: %x\n", rc);
245     ok(!bEnabled, "GetLightEnable says the light is enabled\n");
246
247     /* Light 10 is supposed to be enabled */
248     bEnabled = FALSE;
249     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 10, &bEnabled );
250     ok(rc==D3D_OK, "GetLightEnable returned: %x\n", rc);
251     ok(bEnabled, "GetLightEnable says the light is disabled\n");
252
253     /* Light 80 has not been set */
254     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 80, &bEnabled );
255     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
256
257     /* Light 23 has not been set */
258     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 23, &bEnabled );
259     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
260
261     /* Set some lights with invalid parameters */
262     memset(&light, 0, sizeof(D3DLIGHT7));
263     light.dltType = 0;
264     U1(light.dcvDiffuse).r = 1.f;
265     U2(light.dcvDiffuse).g = 1.f;
266     U3(light.dcvDiffuse).b = 1.f;
267     U3(light.dvDirection).z = 1.f;
268     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 100, &light);
269     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
270
271     memset(&light, 0, sizeof(D3DLIGHT7));
272     light.dltType = 12345;
273     U1(light.dcvDiffuse).r = 1.f;
274     U2(light.dcvDiffuse).g = 1.f;
275     U3(light.dcvDiffuse).b = 1.f;
276     U3(light.dvDirection).z = 1.f;
277     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 101, &light);
278     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
279
280     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 102, NULL);
281     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
282
283     memset(&light, 0, sizeof(D3DLIGHT7));
284     light.dltType = D3DLIGHT_SPOT;
285     U1(light.dcvDiffuse).r = 1.f;
286     U2(light.dcvDiffuse).g = 1.f;
287     U3(light.dcvDiffuse).b = 1.f;
288     U3(light.dvDirection).z = 1.f;
289
290     light.dvAttenuation0 = -one / zero; /* -INFINITY */
291     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
292     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
293
294     light.dvAttenuation0 = -1.0;
295     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
296     ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
297
298     light.dvAttenuation0 = 0.0;
299     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
300     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
301
302     light.dvAttenuation0 = 1.0;
303     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
304     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
305
306     light.dvAttenuation0 = one / zero; /* +INFINITY */
307     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
308     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
309
310     light.dvAttenuation0 = zero / zero; /* NaN */
311     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
312     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
313
314     /* Directional light ignores attenuation */
315     light.dltType = D3DLIGHT_DIRECTIONAL;
316     light.dvAttenuation0 = -1.0;
317     rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
318     ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
319
320     memset(&mat, 0, sizeof(mat));
321     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
322     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial returned: %x\n", rc);
323
324     U4(mat).power = 129.0;
325     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
326     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial(power = 129.0) returned: %x\n", rc);
327     memset(&mat, 0, sizeof(mat));
328     rc = IDirect3DDevice7_GetMaterial(lpD3DDevice, &mat);
329     ok(rc == D3D_OK, "IDirect3DDevice7_GetMaterial returned: %x\n", rc);
330     ok(U4(mat).power == 129, "Returned power is %f\n", U4(mat).power);
331
332     U4(mat).power = -1.0;
333     rc = IDirect3DDevice7_SetMaterial(lpD3DDevice, &mat);
334     ok(rc == D3D_OK, "IDirect3DDevice7_SetMaterial(power = -1.0) returned: %x\n", rc);
335     memset(&mat, 0, sizeof(mat));
336     rc = IDirect3DDevice7_GetMaterial(lpD3DDevice, &mat);
337     ok(rc == D3D_OK, "IDirect3DDevice7_GetMaterial returned: %x\n", rc);
338     ok(U4(mat).power == -1, "Returned power is %f\n", U4(mat).power);
339 }
340
341 static void ProcessVerticesTest(void)
342 {
343     D3DVERTEXBUFFERDESC desc;
344     HRESULT rc;
345     VERTEX *in;
346     TVERTEX *out;
347     VERTEX *out2;
348     D3DVIEWPORT7 vp;
349     D3DMATRIX view = {  2.0, 0.0, 0.0, 0.0,
350                         0.0, -1.0, 0.0, 0.0,
351                         0.0, 0.0, 1.0, 0.0,
352                         0.0, 0.0, 0.0, 3.0 };
353
354     D3DMATRIX world = { 0.0, 1.0, 0.0, 0.0,
355                         1.0, 0.0, 0.0, 0.0,
356                         0.0, 0.0, 0.0, 1.0,
357                         0.0, 1.0, 1.0, 1.0 };
358
359     D3DMATRIX proj = {  1.0, 0.0, 0.0, 1.0,
360                         0.0, 1.0, 1.0, 0.0,
361                         0.0, 1.0, 1.0, 0.0,
362                         1.0, 0.0, 0.0, 1.0 };
363     /* Create some vertex buffers */
364
365     memset(&desc, 0, sizeof(desc));
366     desc.dwSize = sizeof(desc);
367     desc.dwCaps = 0;
368     desc.dwFVF = D3DFVF_XYZ;
369     desc.dwNumVertices = 16;
370     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufSrc, 0);
371     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
372     if (!lpVBufSrc)
373     {
374         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
375         goto out;
376     }
377
378     memset(&desc, 0, sizeof(desc));
379     desc.dwSize = sizeof(desc);
380     desc.dwCaps = 0;
381     desc.dwFVF = D3DFVF_XYZRHW;
382     desc.dwNumVertices = 16;
383     /* Msdn says that the last parameter must be 0 - check that */
384     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufDest1, 4);
385     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
386     if (!lpVBufDest1)
387     {
388         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
389         goto out;
390     }
391
392     memset(&desc, 0, sizeof(desc));
393     desc.dwSize = sizeof(desc);
394     desc.dwCaps = 0;
395     desc.dwFVF = D3DFVF_XYZ;
396     desc.dwNumVertices = 16;
397     /* Msdn says that the last parameter must be 0 - check that */
398     rc = IDirect3D7_CreateVertexBuffer(lpD3D, &desc, &lpVBufDest2, 12345678);
399     ok(rc==D3D_OK || rc==E_OUTOFMEMORY, "CreateVertexBuffer returned: %x\n", rc);
400     if (!lpVBufDest2)
401     {
402         trace("IDirect3D7::CreateVertexBuffer() failed with an error %x\n", rc);
403         goto out;
404     }
405
406     rc = IDirect3DVertexBuffer7_Lock(lpVBufSrc, 0, (void **) &in, NULL);
407     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
408     if(!in) goto out;
409
410     /* Check basic transformation */
411
412     in[0].x = 0.0;
413     in[0].y = 0.0;
414     in[0].z = 0.0;
415
416     in[1].x = 1.0;
417     in[1].y = 1.0;
418     in[1].z = 1.0;
419
420     in[2].x = -1.0;
421     in[2].y = -1.0;
422     in[2].z = 0.5;
423
424     in[3].x = 0.5;
425     in[3].y = -0.5;
426     in[3].z = 0.25;
427     rc = IDirect3DVertexBuffer7_Unlock(lpVBufSrc);
428     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
429
430     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
431     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
432
433     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest2, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
434     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
435
436     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
437     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
438     if(!out) goto out;
439
440     /* Check the results */
441     ok( comparefloat(out[0].x, 128.0 ) &&
442         comparefloat(out[0].y, 128.0 ) &&
443         comparefloat(out[0].z, 0.0 ) &&
444         comparefloat(out[0].rhw, 1.0 ),
445         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
446
447     ok( comparefloat(out[1].x, 256.0 ) &&
448         comparefloat(out[1].y, 0.0 ) &&
449         comparefloat(out[1].z, 1.0 ) &&
450         comparefloat(out[1].rhw, 1.0 ),
451         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
452
453     ok( comparefloat(out[2].x, 0.0 ) &&
454         comparefloat(out[2].y, 256.0 ) &&
455         comparefloat(out[2].z, 0.5 ) &&
456         comparefloat(out[2].rhw, 1.0 ),
457         "Output 2 vertex is (%f , %f , %f , %f)\n", out[2].x, out[2].y, out[2].z, out[2].rhw);
458
459     ok( comparefloat(out[3].x, 192.0 ) &&
460         comparefloat(out[3].y, 192.0 ) &&
461         comparefloat(out[3].z, 0.25 ) &&
462         comparefloat(out[3].rhw, 1.0 ),
463         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
464
465     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
466     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
467     out = NULL;
468
469     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest2, 0, (void **) &out2, NULL);
470     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
471     if(!out2) goto out;
472     /* Small thing without much practial meaning, but I stumbled upon it,
473      * so let's check for it: If the output vertex buffer has to RHW value,
474      * The RHW value of the last vertex is written into the next vertex
475      */
476     ok( comparefloat(out2[4].x, 1.0 ) &&
477         comparefloat(out2[4].y, 0.0 ) &&
478         comparefloat(out2[4].z, 0.0 ),
479         "Output 4 vertex is (%f , %f , %f)\n", out2[4].x, out2[4].y, out2[4].z);
480
481     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest2);
482     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
483     out = NULL;
484
485     /* Try a more complicated viewport, same vertices */
486     memset(&vp, 0, sizeof(vp));
487     vp.dwX = 10;
488     vp.dwY = 5;
489     vp.dwWidth = 246;
490     vp.dwHeight = 130;
491     vp.dvMinZ = -2.0;
492     vp.dvMaxZ = 4.0;
493     rc = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
494     ok(rc==D3D_OK, "IDirect3DDevice7_SetViewport failed with rc=%x\n", rc);
495
496     /* Process again */
497     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
498     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
499
500     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
501     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
502     if(!out) goto out;
503
504     /* Check the results */
505     ok( comparefloat(out[0].x, 133.0 ) &&
506         comparefloat(out[0].y, 70.0 ) &&
507         comparefloat(out[0].z, -2.0 ) &&
508         comparefloat(out[0].rhw, 1.0 ),
509         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
510
511     ok( comparefloat(out[1].x, 256.0 ) &&
512         comparefloat(out[1].y, 5.0 ) &&
513         comparefloat(out[1].z, 4.0 ) &&
514         comparefloat(out[1].rhw, 1.0 ),
515         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
516
517     ok( comparefloat(out[2].x, 10.0 ) &&
518         comparefloat(out[2].y, 135.0 ) &&
519         comparefloat(out[2].z, 1.0 ) &&
520         comparefloat(out[2].rhw, 1.0 ),
521         "Output 2 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
522
523     ok( comparefloat(out[3].x, 194.5 ) &&
524         comparefloat(out[3].y, 102.5 ) &&
525         comparefloat(out[3].z, -0.5 ) &&
526         comparefloat(out[3].rhw, 1.0 ),
527         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
528
529     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
530     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
531     out = NULL;
532
533     /* Play with some matrices. */
534
535     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_VIEW, &view);
536     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
537
538     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_PROJECTION, &proj);
539     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
540
541     rc = IDirect3DDevice7_SetTransform(lpD3DDevice, D3DTRANSFORMSTATE_WORLD, &world);
542     ok(rc==D3D_OK, "IDirect3DDevice7_SetTransform failed\n");
543
544     rc = IDirect3DVertexBuffer7_ProcessVertices(lpVBufDest1, D3DVOP_TRANSFORM, 0, 4, lpVBufSrc, 0, lpD3DDevice, 0);
545     ok(rc==D3D_OK , "IDirect3DVertexBuffer::ProcessVertices returned: %x\n", rc);
546
547     rc = IDirect3DVertexBuffer7_Lock(lpVBufDest1, 0, (void **) &out, NULL);
548     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Lock returned: %x\n", rc);
549     if(!out) goto out;
550
551     /* Keep the viewport simpler, otherwise we get bad numbers to compare */
552     vp.dwX = 0;
553     vp.dwY = 0;
554     vp.dwWidth = 100;
555     vp.dwHeight = 100;
556     vp.dvMinZ = 1.0;
557     vp.dvMaxZ = 0.0;
558     rc = IDirect3DDevice7_SetViewport(lpD3DDevice, &vp);
559     ok(rc==D3D_OK, "IDirect3DDevice7_SetViewport failed\n");
560
561     /* Check the results */
562     ok( comparefloat(out[0].x, 256.0 ) &&    /* X coordinate is cut at the surface edges */
563         comparefloat(out[0].y, 70.0 ) &&
564         comparefloat(out[0].z, -2.0 ) &&
565         comparefloat(out[0].rhw, (1.0 / 3.0)),
566         "Output 0 vertex is (%f , %f , %f , %f)\n", out[0].x, out[0].y, out[0].z, out[0].rhw);
567
568     ok( comparefloat(out[1].x, 256.0 ) &&
569         comparefloat(out[1].y, 78.125000 ) &&
570         comparefloat(out[1].z, -2.750000 ) &&
571         comparefloat(out[1].rhw, 0.125000 ),
572         "Output 1 vertex is (%f , %f , %f , %f)\n", out[1].x, out[1].y, out[1].z, out[1].rhw);
573
574     ok( comparefloat(out[2].x, 256.0 ) &&
575         comparefloat(out[2].y, 44.000000 ) &&
576         comparefloat(out[2].z, 0.400000 ) &&
577         comparefloat(out[2].rhw, 0.400000 ),
578         "Output 2 vertex is (%f , %f , %f , %f)\n", out[2].x, out[2].y, out[2].z, out[2].rhw);
579
580     ok( comparefloat(out[3].x, 256.0 ) &&
581         comparefloat(out[3].y, 81.818184 ) &&
582         comparefloat(out[3].z, -3.090909 ) &&
583         comparefloat(out[3].rhw, 0.363636 ),
584         "Output 3 vertex is (%f , %f , %f , %f)\n", out[3].x, out[3].y, out[3].z, out[3].rhw);
585
586     rc = IDirect3DVertexBuffer7_Unlock(lpVBufDest1);
587     ok(rc==D3D_OK , "IDirect3DVertexBuffer::Unlock returned: %x\n", rc);
588     out = NULL;
589
590 out:
591     IDirect3DVertexBuffer7_Release(lpVBufSrc);
592     IDirect3DVertexBuffer7_Release(lpVBufDest1);
593     IDirect3DVertexBuffer7_Release(lpVBufDest2);
594 }
595
596 static void StateTest( void )
597 {
598     HRESULT rc;
599
600     /* The msdn says its undocumented, does it return an error too? */
601     rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_ZVISIBLE, TRUE);
602     ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, TRUE) returned %08x\n", rc);
603     rc = IDirect3DDevice7_SetRenderState(lpD3DDevice, D3DRENDERSTATE_ZVISIBLE, FALSE);
604     ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, FALSE) returned %08x\n", rc);
605 }
606
607
608 static void SceneTest(void)
609 {
610     HRESULT                      hr;
611
612     /* Test an EndScene without beginscene. Should return an error */
613     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
614     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
615
616     /* Test a normal BeginScene / EndScene pair, this should work */
617     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
618     ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr);
619     if(SUCCEEDED(hr))
620     {
621         DDBLTFX fx;
622         memset(&fx, 0, sizeof(fx));
623         fx.dwSize = sizeof(fx);
624
625         if(lpDDSdepth) {
626             hr = IDirectDrawSurface7_Blt(lpDDSdepth, NULL, NULL, NULL, DDBLT_DEPTHFILL, &fx);
627             ok(hr == D3D_OK, "Depthfill failed in a BeginScene / EndScene pair\n");
628         } else {
629             skip("Depth stencil creation failed at startup, skipping\n");
630         }
631         hr = IDirect3DDevice7_EndScene(lpD3DDevice);
632         ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr);
633     }
634
635     /* Test another EndScene without having begun a new scene. Should return an error */
636     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
637     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
638
639     /* Two nested BeginScene and EndScene calls */
640     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
641     ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr);
642     hr = IDirect3DDevice7_BeginScene(lpD3DDevice);
643     ok(hr == D3DERR_SCENE_IN_SCENE, "IDirect3DDevice7_BeginScene returned %08x\n", hr);
644     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
645     ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr);
646     hr = IDirect3DDevice7_EndScene(lpD3DDevice);
647     ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr);
648
649     /* TODO: Verify that blitting works in the same way as in d3d9 */
650 }
651
652 static void LimitTest(void)
653 {
654     IDirectDrawSurface7 *pTexture = NULL;
655     HRESULT hr;
656     int i;
657     DDSURFACEDESC2 ddsd;
658
659     memset(&ddsd, 0, sizeof(ddsd));
660     ddsd.dwSize = sizeof(ddsd);
661     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
662     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
663     ddsd.dwWidth = 16;
664     ddsd.dwHeight = 16;
665     hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &pTexture, NULL);
666     ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
667     if(!pTexture) return;
668
669     for(i = 0; i < 8; i++) {
670         hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, pTexture);
671         ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
672         hr = IDirect3DDevice7_SetTexture(lpD3DDevice, i, NULL);
673         ok(hr == D3D_OK, "IDirect3DDevice8_SetTexture for sampler %d failed with %08x\n", i, hr);
674         hr = IDirect3DDevice7_SetTextureStageState(lpD3DDevice, i, D3DTSS_COLOROP, D3DTOP_ADD);
675         ok(hr == D3D_OK, "IDirect3DDevice8_SetTextureStageState for texture %d failed with %08x\n", i, hr);
676     }
677
678     IDirectDrawSurface7_Release(pTexture);
679 }
680
681 static HRESULT WINAPI enumDevicesCallback(GUID *Guid,LPSTR DeviceDescription,LPSTR DeviceName, D3DDEVICEDESC *hal, D3DDEVICEDESC *hel, VOID *ctx)
682 {
683     UINT ver = *((UINT *) ctx);
684     if(IsEqualGUID(&IID_IDirect3DRGBDevice, Guid))
685     {
686         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
687            "RGB Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
688         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
689            "RGB Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
690         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
691            "RGB Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
692         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
693            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
694
695         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
696            "RGB Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
697         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
698            "RGB Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
699         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
700            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
701         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
702            "RGB Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
703     }
704     else if(IsEqualGUID(&IID_IDirect3DHALDevice, Guid))
705     {
706         /* pow2 is hardware dependent */
707
708         ok(hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
709            "HAL Device %d hal line caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
710         ok(hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
711            "HAL Device %d hal tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
712         ok((hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
713            "HAL Device %d hel line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
714         ok((hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
715            "HAL Device %d hel tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
716     }
717     else if(IsEqualGUID(&IID_IDirect3DRefDevice, Guid))
718     {
719         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
720            "REF Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
721         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
722            "REF Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
723         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
724            "REF Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
725         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
726            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
727
728         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
729            "REF Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
730         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
731            "REF Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
732         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
733            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
734         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
735            "REF Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
736     }
737     else if(IsEqualGUID(&IID_IDirect3DRampDevice, Guid))
738     {
739         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
740            "Ramp Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
741         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
742            "Ramp Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
743         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
744            "Ramp Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
745         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
746            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
747
748         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
749            "Ramp Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
750         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
751            "Ramp Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
752         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
753            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
754         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
755            "Ramp Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
756     }
757     else if(IsEqualGUID(&IID_IDirect3DMMXDevice, Guid))
758     {
759         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
760            "MMX Device %d hal line caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
761         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) == 0,
762            "MMX Device %d hal tri caps has D3DPTEXTURECAPS_POW2 flag set\n", ver);
763         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
764            "MMX Device %d hel line caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
765         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2,
766            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_POW2 flag set\n", ver);
767
768         ok((hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
769            "MMX Device %d hal line caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
770         ok((hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) == 0,
771            "MMX Device %d hal tri caps has D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
772         ok(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
773            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
774         ok(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE,
775            "MMX Device %d hel tri caps does not have D3DPTEXTURECAPS_PERSPECTIVE set\n", ver);
776     }
777     else
778     {
779         ok(FALSE, "Unexpected device enumerated: \"%s\" \"%s\"\n", DeviceDescription, DeviceName);
780         if(hal->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hal line has pow2 set\n");
781         else trace("hal line does NOT have pow2 set\n");
782         if(hal->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hal tri has pow2 set\n");
783         else trace("hal tri does NOT have pow2 set\n");
784         if(hel->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hel line has pow2 set\n");
785         else trace("hel line does NOT have pow2 set\n");
786         if(hel->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) trace("hel tri has pow2 set\n");
787         else trace("hel tri does NOT have pow2 set\n");
788     }
789     return DDENUMRET_OK;
790 }
791
792 static void CapsTest(void)
793 {
794     IDirect3D3 *d3d3;
795     IDirect3D3 *d3d2;
796     IDirectDraw *dd1;
797     HRESULT hr;
798     UINT ver;
799
800     hr = DirectDrawCreate(NULL, &dd1, NULL);
801     ok(hr == DD_OK, "Cannot create a DirectDraw 1 interface, hr = %08x\n", hr);
802     hr = IDirectDraw_QueryInterface(dd1, &IID_IDirect3D3, (void **) &d3d3);
803     ok(hr == D3D_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
804     ver = 3;
805     IDirect3D3_EnumDevices(d3d3, enumDevicesCallback, &ver);
806
807     IDirect3D3_Release(d3d3);
808     IDirectDraw_Release(dd1);
809
810     hr = DirectDrawCreate(NULL, &dd1, NULL);
811     ok(hr == DD_OK, "Cannot create a DirectDraw 1 interface, hr = %08x\n", hr);
812     hr = IDirectDraw_QueryInterface(dd1, &IID_IDirect3D2, (void **) &d3d2);
813     ok(hr == D3D_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
814     ver = 2;
815     IDirect3D2_EnumDevices(d3d2, enumDevicesCallback, &ver);
816
817     IDirect3D2_Release(d3d2);
818     IDirectDraw_Release(dd1);
819 }
820
821 struct v_in {
822     float x, y, z;
823 };
824 struct v_out {
825     float x, y, z, rhw;
826 };
827
828 static void Direct3D1Test(void)
829 {
830     IDirect3DDevice *dev1 = NULL;
831     IDirectDraw *dd;
832     IDirect3D *d3d;
833     IDirectDrawSurface *dds;
834     IDirect3DExecuteBuffer *exebuf;
835     IDirect3DViewport *vp;
836     HRESULT hr;
837     DDSURFACEDESC ddsd;
838     D3DEXECUTEBUFFERDESC desc;
839     D3DVIEWPORT vp_data;
840     D3DINSTRUCTION *instr;
841     D3DBRANCH *branch;
842     unsigned int idx = 0;
843     static struct v_in testverts[] = {
844         {0.0, 0.0, 0.0},  { 1.0,  1.0,  1.0}, {-1.0, -1.0, -1.0},
845         {0.5, 0.5, 0.5},  {-0.5, -0.5, -0.5}, {-0.5, -0.5, 0.0},
846     };
847     static struct v_in cliptest[] = {
848         {25.59, 25.59, 1.0},  {-25.59, -25.59,  0.0},
849         {25.61, 25.61, 1.01}, {-25.60, -25.60, -0.01},
850     };
851     static struct v_in offscreentest[] = {
852         {128.1, 0.0, 0.0},
853     };
854     struct v_out out[sizeof(testverts) / sizeof(testverts[0])];
855     D3DHVERTEX outH[sizeof(testverts) / sizeof(testverts[0])];
856     D3DTRANSFORMDATA transformdata;
857     DWORD i = FALSE;
858
859     /* An IDirect3DDevice cannot be queryInterfaced from an IDirect3DDevice7 on windows */
860     hr = DirectDrawCreate(NULL, &dd, NULL);
861     ok(hr==DD_OK || hr==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreate returned: %x\n", hr);
862     if (!dd) {
863         trace("DirectDrawCreate() failed with an error %x\n", hr);
864         return;
865     }
866
867     hr = IDirectDraw_SetCooperativeLevel(dd, NULL, DDSCL_NORMAL);
868     ok(hr==DD_OK, "SetCooperativeLevel returned: %x\n", hr);
869
870     hr = IDirectDraw_QueryInterface(dd, &IID_IDirect3D, (void**) &d3d);
871     ok(hr==DD_OK, "QueryInterface returned: %x\n", hr);
872
873     memset(&ddsd, 0, sizeof(ddsd));
874     ddsd.dwSize = sizeof(ddsd);
875     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
876     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
877     ddsd.dwWidth = 256;
878     ddsd.dwHeight = 256;
879     hr = IDirectDraw_CreateSurface(dd, &ddsd, &dds, NULL);
880     ok(hr==DD_OK, "CreateSurface returned: %x\n", hr);
881
882     dev1 = NULL;
883     hr = IDirectDrawSurface_QueryInterface(dds, &IID_IDirect3DRGBDevice, (void **) &dev1);
884     ok(hr==D3D_OK || hr==DDERR_NOPALETTEATTACHED || hr==E_OUTOFMEMORY, "CreateDevice returned: %x\n", hr);
885     if(!dev1) return;
886
887     memset(&desc, 0, sizeof(desc));
888     desc.dwSize = sizeof(desc);
889     desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
890     desc.dwCaps = D3DDEBCAPS_VIDEOMEMORY;
891     desc.dwBufferSize = 128;
892     desc.lpData = NULL;
893     hr = IDirect3DDevice_CreateExecuteBuffer(dev1, &desc, &exebuf, NULL);
894     ok(hr == D3D_OK, "IDirect3DDevice_CreateExecuteBuffer failed: %08x\n", hr);
895
896     memset(&desc, 0, sizeof(desc));
897     desc.dwSize = sizeof(desc);
898
899     hr = IDirect3DExecuteBuffer_Lock(exebuf, &desc);
900     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Lock failed: %08x\n", hr);
901     instr = desc.lpData;
902     instr[idx].bOpcode = D3DOP_BRANCHFORWARD;
903     instr[idx].bSize = sizeof(*branch);
904     instr[idx].wCount = 1;
905     idx++;
906     branch = (D3DBRANCH *) &instr[idx];
907     branch->dwMask = 0x0;
908     branch->dwValue = 1;
909     branch->bNegate = TRUE;
910     branch->dwOffset = 0;
911     idx += (sizeof(*branch) / sizeof(*instr));
912     instr[idx].bOpcode = D3DOP_EXIT;
913     instr[idx].bSize = 0;
914     instr[idx].bSize = 0;
915     hr = IDirect3DExecuteBuffer_Unlock(exebuf);
916     ok(hr == D3D_OK, "IDirect3DExecuteBuffer_Unlock failed: %08x\n", hr);
917
918     hr = IDirect3D_CreateViewport(d3d, &vp, NULL);
919     ok(hr == D3D_OK, "IDirect3D_CreateViewport failed: %08x\n", hr);
920     hr = IDirect3DViewport_Initialize(vp, d3d);
921     ok(hr == DDERR_ALREADYINITIALIZED, "IDirect3DViewport_Initialize returned %08x\n", hr);
922
923     hr = IDirect3DDevice_AddViewport(dev1, vp);
924     ok(hr == D3D_OK, "IDirect3DDevice_AddViewport returned %08x\n", hr);
925     vp_data.dwSize = sizeof(vp_data);
926     vp_data.dwX = 0;
927     vp_data.dwY = 0;
928     vp_data.dwWidth = 256;
929     vp_data.dwHeight = 256;
930     vp_data.dvScaleX = 1;
931     vp_data.dvScaleY = 1;
932     vp_data.dvMaxX = 256;
933     vp_data.dvMaxY = 256;
934     vp_data.dvMinZ = 0;
935     vp_data.dvMaxZ = 1;
936     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
937     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
938
939     hr = IDirect3DDevice_Execute(dev1, exebuf, vp, D3DEXECUTE_CLIPPED);
940     ok(hr == D3D_OK, "IDirect3DDevice_Execute returned %08x\n", hr);
941
942     memset(&transformdata, 0, sizeof(transformdata));
943     transformdata.dwSize = sizeof(transformdata);
944     transformdata.lpIn = (void *) testverts;
945     transformdata.dwInSize = sizeof(testverts[0]);
946     transformdata.lpOut = out;
947     transformdata.dwOutSize = sizeof(out[0]);
948
949     transformdata.lpHOut = NULL;
950     hr = IDirect3DViewport_TransformVertices(vp, sizeof(testverts) / sizeof(testverts[0]),
951                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
952                                              &i);
953     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
954
955     transformdata.lpHOut = outH;
956     memset(outH, 0xaa, sizeof(outH));
957     hr = IDirect3DViewport_TransformVertices(vp, sizeof(testverts) / sizeof(testverts[0]),
958                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
959                                              &i);
960     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
961     ok(i == 0, "Offscreen is %d\n", i);
962
963     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
964         static const struct v_out cmp[] = {
965             {128.0, 128.0, 0.0, 1}, {129.0, 127.0,  1.0, 1}, {127.0, 129.0, -1, 1},
966             {128.5, 127.5, 0.5, 1}, {127.5, 128.5, -0.5, 1}, {127.5, 128.5,  0, 1}
967         };
968
969         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
970            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
971            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
972            out[i].x, out[i].y, out[i].z, out[i].rhw,
973            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
974     }
975     for(i = 0; i < sizeof(outH); i++) {
976         if(((unsigned char *) outH)[i] != 0xaa) {
977             ok(FALSE, "Homogenous output was generated despite UNCLIPPED flag\n");
978             break;
979         }
980     }
981
982     vp_data.dvScaleX = 5;
983     vp_data.dvScaleY = 5;
984     vp_data.dvMinZ = -25;
985     vp_data.dvMaxZ = 60;
986     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
987     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
988     hr = IDirect3DViewport_TransformVertices(vp, sizeof(testverts) / sizeof(testverts[0]),
989                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
990                                              &i);
991     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
992     ok(i == 0, "Offscreen is %d\n", i);
993     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
994         static const struct v_out cmp[] = {
995             {128.0, 128.0, 0.0, 1}, {133.0, 123.0,  1.0, 1}, {123.0, 133.0, -1, 1},
996             {130.5, 125.5, 0.5, 1}, {125.5, 130.5, -0.5, 1}, {125.5, 130.5,  0, 1}
997         };
998         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
999            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1000            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1001            out[i].x, out[i].y, out[i].z, out[i].rhw,
1002            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1003     }
1004
1005     vp_data.dwX = 10;
1006     vp_data.dwY = 20;
1007     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
1008     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1009     hr = IDirect3DViewport_TransformVertices(vp, sizeof(testverts) / sizeof(testverts[0]),
1010                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1011                                              &i);
1012     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1013     ok(i == 0, "Offscreen is %d\n", i);
1014     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1015         static const struct v_out cmp[] = {
1016             {138.0, 148.0, 0.0, 1}, {143.0, 143.0,  1.0, 1}, {133.0, 153.0, -1, 1},
1017             {140.5, 145.5, 0.5, 1}, {135.5, 150.5, -0.5, 1}, {135.5, 150.5,  0, 1}
1018         };
1019         ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1020            cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1021            "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1022            out[i].x, out[i].y, out[i].z, out[i].rhw,
1023            cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1024     }
1025
1026     memset(out, 0xbb, sizeof(out));
1027     hr = IDirect3DViewport_TransformVertices(vp, sizeof(testverts) / sizeof(testverts[0]),
1028                                              &transformdata, D3DTRANSFORM_CLIPPED,
1029                                              &i);
1030     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1031     ok(i == 0, "Offscreen is %d\n", i);
1032     for(i = 0; i < sizeof(testverts) / sizeof(testverts[0]); i++) {
1033         static const D3DHVERTEX cmpH[] = {
1034             {0,             { 0.0}, { 0.0}, { 0.0}}, {0, { 1.0}, { 1.0}, {1.0}},
1035             {D3DCLIP_FRONT, {-1.0}, {-1.0}, {-1.0}}, {0, { 0.5}, { 0.5}, {0.5}},
1036             {D3DCLIP_FRONT, {-0.5}, {-0.5}, {-0.5}}, {0, {-0.5}, {-0.5}, {0.0}}
1037         };
1038         ok(U1(cmpH[i]).hx == U1(outH[i]).hx && U2(cmpH[i]).hy == U2(outH[i]).hy &&
1039            U3(cmpH[i]).hz == U3(outH[i]).hz && cmpH[i].dwFlags == outH[i].dwFlags,
1040            "HVertex %d differs. Got %08x %f %f %f, expexted %08x %f %f %f\n", i + 1,
1041            outH[i].dwFlags, U1(outH[i]).hx, U2(outH[i]).hy, U3(outH[i]).hz,
1042            cmpH[i].dwFlags, U1(cmpH[i]).hx, U2(cmpH[i]).hy, U3(cmpH[i]).hz);
1043
1044         /* No scheme has been found behind those return values. It seems to be
1045          * whatever data windows has when throwing the vertex away. Modify the
1046          * input test vertices to test this more. Depending on the input data
1047          * it can happen that the z coord gets written into y, or similar things
1048          */
1049         if(0)
1050         {
1051             static const struct v_out cmp[] = {
1052                 {138.0, 148.0, 0.0, 1}, {143.0, 143.0,  1.0, 1}, { -1.0,  -1.0, 0.5, 1},
1053                 {140.5, 145.5, 0.5, 1}, { -0.5,  -0.5, -0.5, 1}, {135.5, 150.5, 0.0, 1}
1054             };
1055             ok(cmp[i].x == out[i].x && cmp[i].y == out[i].y &&
1056                cmp[i].z == out[i].z && cmp[i].rhw == out[i].rhw,
1057                 "Vertex %d differs. Got %f %f %f %f, expexted %f %f %f %f\n", i + 1,
1058                out[i].x, out[i].y, out[i].z, out[i].rhw,
1059                cmp[i].x, cmp[i].y, cmp[i].z, cmp[i].rhw);
1060         }
1061     }
1062     for(i = 0; i < sizeof(out) / sizeof(DWORD); i++) {
1063         ok(((DWORD *) out)[i] != 0xbbbbbbbb,
1064                 "Regular output DWORD %d remained untouched\n", i);
1065     }
1066
1067     transformdata.lpIn = (void *) cliptest;
1068     transformdata.dwInSize = sizeof(cliptest[0]);
1069     hr = IDirect3DViewport_TransformVertices(vp, sizeof(cliptest) / sizeof(cliptest[0]),
1070                                              &transformdata, D3DTRANSFORM_CLIPPED,
1071                                              &i);
1072     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1073     ok(i == 0, "Offscreen is %d\n", i);
1074     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1075         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1076         {
1077             0,
1078             0,
1079             D3DCLIP_RIGHT | D3DCLIP_BACK   | D3DCLIP_TOP,
1080             D3DCLIP_LEFT  | D3DCLIP_BOTTOM | D3DCLIP_FRONT,
1081         };
1082         ok(Flags[i] == outH[i].dwFlags,
1083            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1084            outH[i].dwFlags, Flags[i]);
1085     }
1086
1087     vp_data.dwWidth = 10;
1088     vp_data.dwHeight = 1000;
1089     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
1090     i = 10;
1091     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1092     hr = IDirect3DViewport_TransformVertices(vp, sizeof(cliptest) / sizeof(cliptest[0]),
1093                                              &transformdata, D3DTRANSFORM_CLIPPED,
1094                                              &i);
1095     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1096     ok(i == 0, "Offscreen is %d\n", i);
1097     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1098         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1099         {
1100             D3DCLIP_RIGHT,
1101             D3DCLIP_LEFT,
1102             D3DCLIP_RIGHT | D3DCLIP_BACK,
1103             D3DCLIP_LEFT  | D3DCLIP_FRONT,
1104         };
1105         ok(Flags[i] == outH[i].dwFlags,
1106            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1107            outH[i].dwFlags, Flags[i]);
1108     }
1109     vp_data.dwWidth = 256;
1110     vp_data.dwHeight = 256;
1111     vp_data.dvScaleX = 1;
1112     vp_data.dvScaleY = 1;
1113     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
1114     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1115     hr = IDirect3DViewport_TransformVertices(vp, sizeof(cliptest) / sizeof(cliptest[0]),
1116                                              &transformdata, D3DTRANSFORM_CLIPPED,
1117                                              &i);
1118     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1119     ok(i == 0, "Offscreen is %s\n", i ? "TRUE" : "FALSE");
1120     for(i = 0; i < sizeof(cliptest) / sizeof(cliptest[0]); i++) {
1121         DWORD Flags[sizeof(cliptest) / sizeof(cliptest[0])] =
1122         {
1123             0,
1124             0,
1125             D3DCLIP_BACK,
1126             D3DCLIP_FRONT,
1127         };
1128         ok(Flags[i] == outH[i].dwFlags,
1129            "Cliptest %d differs. Got %08x expexted %08x\n", i + 1,
1130            outH[i].dwFlags, Flags[i]);
1131     }
1132
1133     /* Finally try to figure out how the DWORD dwOffscreen works.
1134      * Apparently no vertex is offscreen with clipping off,
1135      * and with clipping on the offscreen flag is set if only one vertex
1136      * is transformed, and this vertex is offscreen.
1137      */
1138     vp_data.dwWidth = 5;
1139     vp_data.dwHeight = 5;
1140     vp_data.dvScaleX = 10000;
1141     vp_data.dvScaleY = 10000;
1142     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
1143     ok(hr == D3D_OK, "IDirect3DViewport_SetViewport returned %08x\n", hr);
1144     transformdata.lpIn = cliptest;
1145     hr = IDirect3DViewport_TransformVertices(vp, 1,
1146                                              &transformdata, D3DTRANSFORM_UNCLIPPED,
1147                                              &i);
1148     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1149     ok(i == 0, "Offscreen is %d\n", i);
1150     hr = IDirect3DViewport_TransformVertices(vp, 1,
1151                                              &transformdata, D3DTRANSFORM_CLIPPED,
1152                                              &i);
1153     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1154     ok(i == (D3DCLIP_RIGHT | D3DCLIP_TOP), "Offscreen is %d\n", i);
1155     hr = IDirect3DViewport_TransformVertices(vp, 2,
1156                                              &transformdata, D3DTRANSFORM_CLIPPED,
1157                                              &i);
1158     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1159     ok(i == 0, "Offscreen is %d\n", i);
1160     transformdata.lpIn = cliptest + 1;
1161     hr = IDirect3DViewport_TransformVertices(vp, 1,
1162                                              &transformdata, D3DTRANSFORM_CLIPPED,
1163                                              &i);
1164     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1165     ok(i == (D3DCLIP_BOTTOM | D3DCLIP_LEFT), "Offscreen is %d\n", i);
1166
1167     transformdata.lpIn = (void *) offscreentest;
1168     transformdata.dwInSize = sizeof(offscreentest[0]);
1169     vp_data.dwWidth = 257;
1170     vp_data.dwHeight = 257;
1171     vp_data.dvScaleX = 1;
1172     vp_data.dvScaleY = 1;
1173     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
1174     i = 12345;
1175     hr = IDirect3DViewport_TransformVertices(vp, sizeof(offscreentest) / sizeof(offscreentest[0]),
1176                                              &transformdata, D3DTRANSFORM_CLIPPED,
1177                                              &i);
1178     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1179     ok(i == 0, "Offscreen is %d\n", i);
1180     vp_data.dwWidth = 256;
1181     vp_data.dwHeight = 256;
1182     hr = IDirect3DViewport_SetViewport(vp, &vp_data);
1183     i = 12345;
1184     hr = IDirect3DViewport_TransformVertices(vp, sizeof(offscreentest) / sizeof(offscreentest[0]),
1185                                              &transformdata, D3DTRANSFORM_CLIPPED,
1186                                              &i);
1187     ok(hr == D3D_OK, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1188     ok(i == D3DCLIP_RIGHT, "Offscreen is %d\n", i);
1189
1190     hr = IDirect3DViewport_TransformVertices(vp, sizeof(testverts) / sizeof(testverts[0]),
1191                                              &transformdata, 0,
1192                                              &i);
1193     ok(hr == DDERR_INVALIDPARAMS, "IDirect3DViewport_TransformVertices returned %08x\n", hr);
1194
1195     hr = IDirect3DDevice_DeleteViewport(dev1, vp);
1196     ok(hr == D3D_OK, "IDirect3DDevice_DeleteViewport returned %08x\n", hr);
1197
1198     IDirect3DViewport_Release(vp);
1199     IDirect3DExecuteBuffer_Release(exebuf);
1200     IDirect3DDevice_Release(dev1);
1201     IDirectDrawSurface_Release(dds);
1202     IDirect3D_Release(d3d);
1203     IDirectDraw_Release(dd);
1204     return;
1205 }
1206
1207 START_TEST(d3d)
1208 {
1209     init_function_pointers();
1210     if(!pDirectDrawCreateEx) {
1211         skip("function DirectDrawCreateEx not available\n");
1212         return;
1213     }
1214
1215     if(!CreateDirect3D()) {
1216         trace("Skipping tests\n");
1217         return;
1218     }
1219     LightTest();
1220     ProcessVerticesTest();
1221     StateTest();
1222     SceneTest();
1223     LimitTest();
1224     CapsTest();
1225     ReleaseDirect3D();
1226     Direct3D1Test();
1227 }