ddraw: Implement DrawPrimitiveStrided with regular draws.
[wine] / dlls / ddraw / device.c
1 /*
2  * Copyright (c) 1998-2004 Lionel Ulmer
3  * Copyright (c) 2002-2005 Christian Costa
4  * Copyright (c) 2006-2009, 2011-2012 Stefan Dösinger
5  * Copyright (c) 2008 Alexander Dorofeyev
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  * IDirect3DDevice implementation, version 1, 2, 3 and 7. Rendering is relayed
22  * to WineD3D, some minimal DirectDraw specific management is handled here.
23  * The Direct3DDevice is NOT the parent of the WineD3DDevice, because d3d
24  * is initialized when DirectDraw creates the primary surface.
25  * Some type management is necessary, because some D3D types changed between
26  * D3D7 and D3D9.
27  *
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32
33 #include "ddraw_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
36 WINE_DECLARE_DEBUG_CHANNEL(winediag);
37
38 /* The device ID */
39 const GUID IID_D3DDEVICE_WineD3D = {
40   0xaef72d43,
41   0xb09a,
42   0x4b7b,
43   { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
44 };
45
46 static inline void set_fpu_control_word(WORD fpucw)
47 {
48 #if defined(__i386__) && defined(__GNUC__)
49     __asm__ volatile ("fldcw %0" : : "m" (fpucw));
50 #elif defined(__i386__) && defined(_MSC_VER)
51     __asm fldcw fpucw;
52 #endif
53 }
54
55 static inline WORD d3d_fpu_setup(void)
56 {
57     WORD oldcw;
58
59 #if defined(__i386__) && defined(__GNUC__)
60     __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
61 #elif defined(__i386__) && defined(_MSC_VER)
62     __asm fnstcw oldcw;
63 #else
64     static BOOL warned = FALSE;
65     if(!warned)
66     {
67         FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
68         warned = TRUE;
69     }
70     return 0;
71 #endif
72
73     set_fpu_control_word(0x37f);
74
75     return oldcw;
76 }
77
78 static inline struct d3d_device *impl_from_IUnknown(IUnknown *iface)
79 {
80     return CONTAINING_RECORD(iface, struct d3d_device, IUnknown_inner);
81 }
82
83 static HRESULT WINAPI d3d_device_inner_QueryInterface(IUnknown *iface, REFIID riid, void **out)
84 {
85     struct d3d_device *device = impl_from_IUnknown(iface);
86
87     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
88
89     if (!riid)
90     {
91         *out = NULL;
92         return DDERR_INVALIDPARAMS;
93     }
94
95     if (IsEqualGUID(&IID_IUnknown, riid))
96     {
97         IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
98         *out = &device->IDirect3DDevice7_iface;
99         return S_OK;
100     }
101
102     if (device->version == 7)
103     {
104         if (IsEqualGUID(&IID_IDirect3DDevice7, riid))
105         {
106             IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
107             *out = &device->IDirect3DDevice7_iface;
108             return S_OK;
109         }
110     }
111     else
112     {
113         if (IsEqualGUID(&IID_IDirect3DDevice3, riid) && device->version == 3)
114         {
115             IDirect3DDevice3_AddRef(&device->IDirect3DDevice3_iface);
116             *out = &device->IDirect3DDevice3_iface;
117             return S_OK;
118         }
119
120         if (IsEqualGUID(&IID_IDirect3DDevice2, riid) && device->version >= 2)
121         {
122             IDirect3DDevice2_AddRef(&device->IDirect3DDevice2_iface);
123             *out = &device->IDirect3DDevice2_iface;
124             return S_OK;
125         }
126
127         if (IsEqualGUID(&IID_IDirect3DDevice, riid))
128         {
129             IDirect3DDevice_AddRef(&device->IDirect3DDevice_iface);
130             *out = &device->IDirect3DDevice_iface;
131             return S_OK;
132         }
133     }
134
135     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
136
137     *out = NULL;
138     return E_NOINTERFACE;
139 }
140
141 static HRESULT WINAPI d3d_device7_QueryInterface(IDirect3DDevice7 *iface, REFIID riid, void **out)
142 {
143     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
144
145     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
146
147     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
148 }
149
150 static HRESULT WINAPI d3d_device3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid, void **out)
151 {
152     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
153
154     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
155
156     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
157 }
158
159 static HRESULT WINAPI d3d_device2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid, void **out)
160 {
161     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
162
163     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
164
165     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
166 }
167
168 static HRESULT WINAPI d3d_device1_QueryInterface(IDirect3DDevice *iface, REFIID riid, void **out)
169 {
170     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
171
172     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
173
174     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
175 }
176
177 static ULONG WINAPI d3d_device_inner_AddRef(IUnknown *iface)
178 {
179     struct d3d_device *device = impl_from_IUnknown(iface);
180     ULONG ref = InterlockedIncrement(&device->ref);
181
182     TRACE("%p increasing refcount to %u.\n", device, ref);
183
184     return ref;
185 }
186
187 static ULONG WINAPI d3d_device7_AddRef(IDirect3DDevice7 *iface)
188 {
189     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
190
191     TRACE("iface %p.\n", iface);
192
193     return IUnknown_AddRef(device->outer_unknown);
194 }
195
196 static ULONG WINAPI d3d_device3_AddRef(IDirect3DDevice3 *iface)
197 {
198     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
199
200     TRACE("iface %p.\n", iface);
201
202     return IUnknown_AddRef(device->outer_unknown);
203 }
204
205 static ULONG WINAPI d3d_device2_AddRef(IDirect3DDevice2 *iface)
206 {
207     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
208
209     TRACE("iface %p.\n", iface);
210
211     return IUnknown_AddRef(device->outer_unknown);
212 }
213
214 static ULONG WINAPI d3d_device1_AddRef(IDirect3DDevice *iface)
215 {
216     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
217
218     TRACE("iface %p.\n", iface);
219
220     return IUnknown_AddRef(device->outer_unknown);
221 }
222
223 static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
224 {
225     struct d3d_device *This = impl_from_IUnknown(iface);
226     ULONG ref = InterlockedDecrement(&This->ref);
227
228     TRACE("%p decreasing refcount to %u.\n", This, ref);
229
230     /* This method doesn't destroy the wined3d device, because it's still in
231      * use for 2D rendering. IDirectDrawSurface7::Release will destroy the
232      * wined3d device when the render target is released. */
233     if (!ref)
234     {
235         DWORD i;
236
237         wined3d_mutex_lock();
238
239         /* There is no need to unset any resources here, wined3d will take
240          * care of that on uninit_3d(). */
241
242         if (This->index_buffer)
243             wined3d_buffer_decref(This->index_buffer);
244         if (This->vertex_buffer)
245             wined3d_buffer_decref(This->vertex_buffer);
246
247         /* Set the device up to render to the front buffer since the back
248          * buffer will vanish soon. */
249         wined3d_device_set_render_target(This->wined3d_device, 0,
250                 This->ddraw->wined3d_frontbuffer, TRUE);
251
252         /* Release the wined3d device. This won't destroy it. */
253         if (!wined3d_device_decref(This->wined3d_device))
254             ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
255
256         /* The texture handles should be unset by now, but there might be some bits
257          * missing in our reference counting(needs test). Do a sanity check. */
258         for (i = 0; i < This->handle_table.entry_count; ++i)
259         {
260             struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
261
262             switch (entry->type)
263             {
264                 case DDRAW_HANDLE_FREE:
265                     break;
266
267                 case DDRAW_HANDLE_MATERIAL:
268                 {
269                     struct d3d_material *m = entry->object;
270                     FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
271                     m->Handle = 0;
272                     break;
273                 }
274
275                 case DDRAW_HANDLE_MATRIX:
276                 {
277                     /* No FIXME here because this might happen because of sloppy applications. */
278                     WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
279                     IDirect3DDevice_DeleteMatrix(&This->IDirect3DDevice_iface, i + 1);
280                     break;
281                 }
282
283                 case DDRAW_HANDLE_STATEBLOCK:
284                 {
285                     /* No FIXME here because this might happen because of sloppy applications. */
286                     WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
287                     IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
288                     break;
289                 }
290
291                 case DDRAW_HANDLE_SURFACE:
292                 {
293                     struct ddraw_surface *surf = entry->object;
294                     FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
295                     surf->Handle = 0;
296                     break;
297                 }
298
299                 default:
300                     FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
301                     break;
302             }
303         }
304
305         ddraw_handle_table_destroy(&This->handle_table);
306
307         TRACE("Releasing target %p.\n", This->target);
308         /* Release the render target. */
309         if (This->version != 1)
310             IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
311         TRACE("Target release done\n");
312
313         This->ddraw->d3ddevice = NULL;
314
315         /* Now free the structure */
316         HeapFree(GetProcessHeap(), 0, This);
317         wined3d_mutex_unlock();
318     }
319
320     TRACE("Done\n");
321     return ref;
322 }
323
324 static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
325 {
326     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
327
328     TRACE("iface %p.\n", iface);
329
330     return IUnknown_Release(device->outer_unknown);
331 }
332
333 static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
334 {
335     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
336
337     TRACE("iface %p.\n", iface);
338
339     return IUnknown_Release(device->outer_unknown);
340 }
341
342 static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
343 {
344     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
345
346     TRACE("iface %p.\n", iface);
347
348     return IUnknown_Release(device->outer_unknown);
349 }
350
351 static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
352 {
353     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
354
355     TRACE("iface %p.\n", iface);
356
357     return IUnknown_Release(device->outer_unknown);
358 }
359
360 /*****************************************************************************
361  * IDirect3DDevice Methods
362  *****************************************************************************/
363
364 /*****************************************************************************
365  * IDirect3DDevice::Initialize
366  *
367  * Initializes a Direct3DDevice. This implementation is a no-op, as all
368  * initialization is done at create time.
369  *
370  * Exists in Version 1
371  *
372  * Parameters:
373  *  No idea what they mean, as the MSDN page is gone
374  *
375  * Returns: DD_OK
376  *
377  *****************************************************************************/
378 static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
379         IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
380 {
381     /* It shouldn't be crucial, but print a FIXME, I'm interested if
382      * any game calls it and when. */
383     FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
384             iface, d3d, debugstr_guid(guid), device_desc);
385
386     return D3D_OK;
387 }
388
389 /*****************************************************************************
390  * IDirect3DDevice7::GetCaps
391  *
392  * Retrieves the device's capabilities
393  *
394  * This implementation is used for Version 7 only, the older versions have
395  * their own implementation.
396  *
397  * Parameters:
398  *  Desc: Pointer to a D3DDEVICEDESC7 structure to fill
399  *
400  * Returns:
401  *  D3D_OK on success
402  *  D3DERR_* if a problem occurs. See WineD3D
403  *
404  *****************************************************************************/
405 static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *Desc)
406 {
407     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
408     D3DDEVICEDESC OldDesc;
409
410     TRACE("iface %p, device_desc %p.\n", iface, Desc);
411
412     if (!Desc)
413     {
414         WARN("Desc is NULL, returning DDERR_INVALIDPARAMS.\n");
415         return DDERR_INVALIDPARAMS;
416     }
417
418     /* Call the same function used by IDirect3D, this saves code */
419     return IDirect3DImpl_GetCaps(device->ddraw->wined3d, &OldDesc, Desc);
420 }
421
422 static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
423 {
424     return d3d_device7_GetCaps(iface, desc);
425 }
426
427 static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
428 {
429     HRESULT hr;
430     WORD old_fpucw;
431
432     old_fpucw = d3d_fpu_setup();
433     hr = d3d_device7_GetCaps(iface, desc);
434     set_fpu_control_word(old_fpucw);
435
436     return hr;
437 }
438 /*****************************************************************************
439  * IDirect3DDevice3::GetCaps
440  *
441  * Retrieves the capabilities of the hardware device and the emulation
442  * device. For Wine, hardware and emulation are the same (it's all HW).
443  *
444  * This implementation is used for Version 1, 2, and 3. Version 7 has its own
445  *
446  * Parameters:
447  *  HWDesc: Structure to fill with the HW caps
448  *  HelDesc: Structure to fill with the hardware emulation caps
449  *
450  * Returns:
451  *  D3D_OK on success
452  *  D3DERR_* if a problem occurs. See WineD3D
453  *
454  *****************************************************************************/
455
456 /* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
457  * Microsoft just expanded the existing structure without naming them
458  * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
459  * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
460  * one with 252 bytes.
461  *
462  * All 3 versions are allowed as parameters and only the specified amount of
463  * bytes is written.
464  *
465  * Note that Direct3D7 and earlier are not available in native Win64
466  * ddraw.dll builds, so possible size differences between 32 bit and
467  * 64 bit are a non-issue.
468  */
469 static inline BOOL check_d3ddevicedesc_size(DWORD size)
470 {
471     if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
472             || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
473             || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
474     return FALSE;
475 }
476
477 static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
478         D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
479 {
480     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
481     D3DDEVICEDESC oldDesc;
482     D3DDEVICEDESC7 newDesc;
483     HRESULT hr;
484
485     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
486
487     if (!HWDesc)
488     {
489         WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
490         return DDERR_INVALIDPARAMS;
491     }
492     if (!check_d3ddevicedesc_size(HWDesc->dwSize))
493     {
494         WARN("HWDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
495         return DDERR_INVALIDPARAMS;
496     }
497     if (!HelDesc)
498     {
499         WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
500         return DDERR_INVALIDPARAMS;
501     }
502     if (!check_d3ddevicedesc_size(HelDesc->dwSize))
503     {
504         WARN("HelDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
505         return DDERR_INVALIDPARAMS;
506     }
507
508     hr = IDirect3DImpl_GetCaps(device->ddraw->wined3d, &oldDesc, &newDesc);
509     if (hr != D3D_OK)
510         return hr;
511
512     DD_STRUCT_COPY_BYSIZE(HWDesc, &oldDesc);
513     DD_STRUCT_COPY_BYSIZE(HelDesc, &oldDesc);
514     return D3D_OK;
515 }
516
517 static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
518         D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
519 {
520     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
521
522     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
523
524     return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
525 }
526
527 static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
528         D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
529 {
530     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
531
532     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
533
534     return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
535 }
536
537 /*****************************************************************************
538  * IDirect3DDevice2::SwapTextureHandles
539  *
540  * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
541  *
542  * Parameters:
543  *  Tex1, Tex2: The 2 Textures to swap
544  *
545  * Returns:
546  *  D3D_OK
547  *
548  *****************************************************************************/
549 static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
550         IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
551 {
552     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
553     struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
554     struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
555     DWORD h1, h2;
556
557     TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
558
559     wined3d_mutex_lock();
560
561     h1 = surf1->Handle - 1;
562     h2 = surf2->Handle - 1;
563     device->handle_table.entries[h1].object = surf2;
564     device->handle_table.entries[h2].object = surf1;
565     surf2->Handle = h1 + 1;
566     surf1->Handle = h2 + 1;
567
568     wined3d_mutex_unlock();
569
570     return D3D_OK;
571 }
572
573 static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
574         IDirect3DTexture *tex1, IDirect3DTexture *tex2)
575 {
576     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
577     struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
578     struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
579     IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
580     IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
581
582     TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
583
584     return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
585 }
586
587 /*****************************************************************************
588  * IDirect3DDevice3::GetStats
589  *
590  * This method seems to retrieve some stats from the device.
591  * The MSDN documentation doesn't exist any more, but the D3DSTATS
592  * structure suggests that the amount of drawn primitives and processed
593  * vertices is returned.
594  *
595  * Exists in Version 1, 2 and 3
596  *
597  * Parameters:
598  *  Stats: Pointer to a D3DSTATS structure to be filled
599  *
600  * Returns:
601  *  D3D_OK on success
602  *  DDERR_INVALIDPARAMS if Stats == NULL
603  *
604  *****************************************************************************/
605 static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
606 {
607     FIXME("iface %p, stats %p stub!\n", iface, Stats);
608
609     if(!Stats)
610         return DDERR_INVALIDPARAMS;
611
612     /* Fill the Stats with 0 */
613     Stats->dwTrianglesDrawn = 0;
614     Stats->dwLinesDrawn = 0;
615     Stats->dwPointsDrawn = 0;
616     Stats->dwSpansDrawn = 0;
617     Stats->dwVerticesProcessed = 0;
618
619     return D3D_OK;
620 }
621
622 static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
623 {
624     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
625
626     TRACE("iface %p, stats %p.\n", iface, stats);
627
628     return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
629 }
630
631 static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
632 {
633     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
634
635     TRACE("iface %p, stats %p.\n", iface, stats);
636
637     return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
638 }
639
640 /*****************************************************************************
641  * IDirect3DDevice::CreateExecuteBuffer
642  *
643  * Creates an IDirect3DExecuteBuffer, used for rendering with a
644  * Direct3DDevice.
645  *
646  * Version 1 only.
647  *
648  * Params:
649  *  Desc: Buffer description
650  *  ExecuteBuffer: Address to return the Interface pointer at
651  *  UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
652  *            support
653  *
654  * Returns:
655  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
656  *  DDERR_OUTOFMEMORY if we ran out of memory
657  *  D3D_OK on success
658  *
659  *****************************************************************************/
660 static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
661         D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
662 {
663     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
664     struct d3d_execute_buffer *object;
665     HRESULT hr;
666
667     TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
668             iface, buffer_desc, ExecuteBuffer, outer_unknown);
669
670     if (outer_unknown)
671         return CLASS_E_NOAGGREGATION;
672
673     /* Allocate the new Execute Buffer */
674     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
675     if(!object)
676     {
677         ERR("Failed to allocate execute buffer memory.\n");
678         return DDERR_OUTOFMEMORY;
679     }
680
681     hr = d3d_execute_buffer_init(object, device, buffer_desc);
682     if (FAILED(hr))
683     {
684         WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
685         HeapFree(GetProcessHeap(), 0, object);
686         return hr;
687     }
688
689     *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
690
691     TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
692
693     return D3D_OK;
694 }
695
696 /*****************************************************************************
697  * IDirect3DDevice::Execute
698  *
699  * Executes all the stuff in an execute buffer.
700  *
701  * Params:
702  *  ExecuteBuffer: The buffer to execute
703  *  Viewport: The viewport used for rendering
704  *  Flags: Some flags
705  *
706  * Returns:
707  *  DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
708  *  D3D_OK on success
709  *
710  *****************************************************************************/
711 static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
712         IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
713 {
714     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
715     struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
716     struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
717     HRESULT hr;
718
719     TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, viewport, flags);
720
721     if(!buffer)
722         return DDERR_INVALIDPARAMS;
723
724     /* Execute... */
725     wined3d_mutex_lock();
726     hr = d3d_execute_buffer_execute(buffer, device, viewport_impl);
727     wined3d_mutex_unlock();
728
729     return hr;
730 }
731
732 /*****************************************************************************
733  * IDirect3DDevice3::AddViewport
734  *
735  * Add a Direct3DViewport to the device's viewport list. These viewports
736  * are wrapped to IDirect3DDevice7 viewports in viewport.c
737  *
738  * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
739  * are the same interfaces.
740  *
741  * Params:
742  *  Viewport: The viewport to add
743  *
744  * Returns:
745  *  DDERR_INVALIDPARAMS if Viewport == NULL
746  *  D3D_OK on success
747  *
748  *****************************************************************************/
749 static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
750 {
751     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
752     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
753
754     TRACE("iface %p, viewport %p.\n", iface, viewport);
755
756     /* Sanity check */
757     if(!vp)
758         return DDERR_INVALIDPARAMS;
759
760     wined3d_mutex_lock();
761     list_add_head(&device->viewport_list, &vp->entry);
762     /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
763     vp->active_device = device;
764     wined3d_mutex_unlock();
765
766     return D3D_OK;
767 }
768
769 static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
770         IDirect3DViewport2 *viewport)
771 {
772     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
773     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
774
775     TRACE("iface %p, viewport %p.\n", iface, viewport);
776
777     return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
778 }
779
780 static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
781 {
782     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
783     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
784
785     TRACE("iface %p, viewport %p.\n", iface, viewport);
786
787     return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
788 }
789
790 /*****************************************************************************
791  * IDirect3DDevice3::DeleteViewport
792  *
793  * Deletes a Direct3DViewport from the device's viewport list.
794  *
795  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
796  * are equal.
797  *
798  * Params:
799  *  Viewport: The viewport to delete
800  *
801  * Returns:
802  *  D3D_OK on success
803  *  DDERR_INVALIDPARAMS if the viewport wasn't found in the list
804  *
805  *****************************************************************************/
806 static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
807 {
808     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
809     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
810
811     TRACE("iface %p, viewport %p.\n", iface, viewport);
812
813     wined3d_mutex_lock();
814
815     if (vp->active_device != device)
816     {
817         WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
818         wined3d_mutex_unlock();
819         return DDERR_INVALIDPARAMS;
820     }
821
822     vp->active_device = NULL;
823     list_remove(&vp->entry);
824
825     wined3d_mutex_unlock();
826
827     return D3D_OK;
828 }
829
830 static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
831 {
832     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
833     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
834
835     TRACE("iface %p, viewport %p.\n", iface, viewport);
836
837     return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
838 }
839
840 static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
841 {
842     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
843     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
844
845     TRACE("iface %p, viewport %p.\n", iface, viewport);
846
847     return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
848 }
849
850 /*****************************************************************************
851  * IDirect3DDevice3::NextViewport
852  *
853  * Returns a viewport from the viewport list, depending on the
854  * passed viewport and the flags.
855  *
856  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
857  * are equal.
858  *
859  * Params:
860  *  Viewport: Viewport to use for beginning the search
861  *  Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
862  *
863  * Returns:
864  *  D3D_OK on success
865  *  DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
866  *
867  *****************************************************************************/
868 static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
869         IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
870 {
871     struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
872     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
873     struct d3d_viewport *next;
874     struct list *entry;
875
876     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
877             iface, Viewport3, lplpDirect3DViewport3, flags);
878
879     if(!vp)
880     {
881         *lplpDirect3DViewport3 = NULL;
882         return DDERR_INVALIDPARAMS;
883     }
884
885
886     wined3d_mutex_lock();
887     switch (flags)
888     {
889         case D3DNEXT_NEXT:
890             entry = list_next(&This->viewport_list, &vp->entry);
891             break;
892
893         case D3DNEXT_HEAD:
894             entry = list_head(&This->viewport_list);
895             break;
896
897         case D3DNEXT_TAIL:
898             entry = list_tail(&This->viewport_list);
899             break;
900
901         default:
902             WARN("Invalid flags %#x.\n", flags);
903             *lplpDirect3DViewport3 = NULL;
904             wined3d_mutex_unlock();
905             return DDERR_INVALIDPARAMS;
906     }
907
908     if (entry)
909     {
910         next = LIST_ENTRY(entry, struct d3d_viewport, entry);
911         *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
912     }
913     else
914         *lplpDirect3DViewport3 = NULL;
915
916     wined3d_mutex_unlock();
917
918     return D3D_OK;
919 }
920
921 static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
922         IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
923 {
924     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
925     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
926     IDirect3DViewport3 *res;
927     HRESULT hr;
928
929     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
930             iface, viewport, next, flags);
931
932     hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
933             &vp->IDirect3DViewport3_iface, &res, flags);
934     *next = (IDirect3DViewport2 *)res;
935     return hr;
936 }
937
938 static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
939         IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
940 {
941     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
942     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
943     IDirect3DViewport3 *res;
944     HRESULT hr;
945
946     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
947             iface, viewport, next, flags);
948
949     hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
950             &vp->IDirect3DViewport3_iface, &res, flags);
951     *next = (IDirect3DViewport *)res;
952     return hr;
953 }
954
955 /*****************************************************************************
956  * IDirect3DDevice::Pick
957  *
958  * Executes an execute buffer without performing rendering. Instead, a
959  * list of primitives that intersect with (x1,y1) of the passed rectangle
960  * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
961  * this list.
962  *
963  * Version 1 only
964  *
965  * Params:
966  *  ExecuteBuffer: Buffer to execute
967  *  Viewport: Viewport to use for execution
968  *  Flags: None are defined, according to the SDK
969  *  Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
970  *        x2 and y2 are ignored.
971  *
972  * Returns:
973  *  D3D_OK because it's a stub
974  *
975  *****************************************************************************/
976 static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
977         IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
978 {
979     FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
980             iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
981
982     return D3D_OK;
983 }
984
985 /*****************************************************************************
986  * IDirect3DDevice::GetPickRecords
987  *
988  * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
989  *
990  * Version 1 only
991  *
992  * Params:
993  *  Count: Pointer to a DWORD containing the numbers of pick records to
994  *         retrieve
995  *  D3DPickRec: Address to store the resulting D3DPICKRECORD array.
996  *
997  * Returns:
998  *  D3D_OK, because it's a stub
999  *
1000  *****************************************************************************/
1001 static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
1002         DWORD *count, D3DPICKRECORD *records)
1003 {
1004     FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1005
1006     return D3D_OK;
1007 }
1008
1009 /*****************************************************************************
1010  * IDirect3DDevice7::EnumTextureformats
1011  *
1012  * Enumerates the supported texture formats. It has a list of all possible
1013  * formats and calls IWineD3D::CheckDeviceFormat for each format to see if
1014  * WineD3D supports it. If so, then it is passed to the app.
1015  *
1016  * This is for Version 7 and 3, older versions have a different
1017  * callback function and their own implementation
1018  *
1019  * Params:
1020  *  Callback: Callback to call for each enumerated format
1021  *  Arg: Argument to pass to the callback
1022  *
1023  * Returns:
1024  *  D3D_OK on success
1025  *  DDERR_INVALIDPARAMS if Callback == NULL
1026  *
1027  *****************************************************************************/
1028 static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
1029         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1030 {
1031     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1032     struct wined3d_display_mode mode;
1033     HRESULT hr;
1034     unsigned int i;
1035
1036     static const enum wined3d_format_id FormatList[] =
1037     {
1038         /* 16 bit */
1039         WINED3DFMT_B5G5R5X1_UNORM,
1040         WINED3DFMT_B5G5R5A1_UNORM,
1041         WINED3DFMT_B4G4R4A4_UNORM,
1042         WINED3DFMT_B5G6R5_UNORM,
1043         /* 32 bit */
1044         WINED3DFMT_B8G8R8X8_UNORM,
1045         WINED3DFMT_B8G8R8A8_UNORM,
1046         /* 8 bit */
1047         WINED3DFMT_B2G3R3_UNORM,
1048         WINED3DFMT_P8_UINT,
1049         /* FOURCC codes */
1050         WINED3DFMT_DXT1,
1051         WINED3DFMT_DXT3,
1052         WINED3DFMT_DXT5,
1053     };
1054
1055     static const enum wined3d_format_id BumpFormatList[] =
1056     {
1057         WINED3DFMT_R8G8_SNORM,
1058         WINED3DFMT_R5G5_SNORM_L6_UNORM,
1059         WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1060         WINED3DFMT_R16G16_SNORM,
1061         WINED3DFMT_R10G11B11_SNORM,
1062         WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1063     };
1064
1065     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1066
1067     if (!callback)
1068         return DDERR_INVALIDPARAMS;
1069
1070     wined3d_mutex_lock();
1071
1072     memset(&mode, 0, sizeof(mode));
1073     if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1074     {
1075         wined3d_mutex_unlock();
1076         WARN("Cannot get the current adapter format\n");
1077         return hr;
1078     }
1079
1080     for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1081     {
1082         if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, WINED3D_DEVICE_TYPE_HAL,
1083                 mode.format_id, 0, WINED3D_RTYPE_TEXTURE, FormatList[i]) == D3D_OK)
1084         {
1085             DDPIXELFORMAT pformat;
1086
1087             memset(&pformat, 0, sizeof(pformat));
1088             pformat.dwSize = sizeof(pformat);
1089             PixelFormat_WineD3DtoDD(&pformat, FormatList[i]);
1090
1091             TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1092             hr = callback(&pformat, context);
1093             if(hr != DDENUMRET_OK)
1094             {
1095                 TRACE("Format enumeration cancelled by application\n");
1096                 wined3d_mutex_unlock();
1097                 return D3D_OK;
1098             }
1099         }
1100     }
1101
1102     for (i = 0; i < sizeof(BumpFormatList) / sizeof(*BumpFormatList); ++i)
1103     {
1104         if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT,
1105                 WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1106                 WINED3D_RTYPE_TEXTURE, BumpFormatList[i]) == D3D_OK)
1107         {
1108             DDPIXELFORMAT pformat;
1109
1110             memset(&pformat, 0, sizeof(pformat));
1111             pformat.dwSize = sizeof(pformat);
1112             PixelFormat_WineD3DtoDD(&pformat, BumpFormatList[i]);
1113
1114             TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1115             hr = callback(&pformat, context);
1116             if(hr != DDENUMRET_OK)
1117             {
1118                 TRACE("Format enumeration cancelled by application\n");
1119                 wined3d_mutex_unlock();
1120                 return D3D_OK;
1121             }
1122         }
1123     }
1124     TRACE("End of enumeration\n");
1125     wined3d_mutex_unlock();
1126
1127     return D3D_OK;
1128 }
1129
1130 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1131         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1132 {
1133     return d3d_device7_EnumTextureFormats(iface, callback, context);
1134 }
1135
1136 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1137         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1138 {
1139     HRESULT hr;
1140     WORD old_fpucw;
1141
1142     old_fpucw = d3d_fpu_setup();
1143     hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1144     set_fpu_control_word(old_fpucw);
1145
1146     return hr;
1147 }
1148
1149 static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
1150         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1151 {
1152     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1153
1154     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1155
1156     return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1157 }
1158
1159 /*****************************************************************************
1160  * IDirect3DDevice2::EnumTextureformats
1161  *
1162  * EnumTextureFormats for Version 1 and 2, see
1163  * IDirect3DDevice7::EnumTexureFormats for a more detailed description.
1164  *
1165  * This version has a different callback and does not enumerate FourCC
1166  * formats
1167  *
1168  *****************************************************************************/
1169 static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
1170         LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1171 {
1172     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1173     struct wined3d_display_mode mode;
1174     HRESULT hr;
1175     unsigned int i;
1176
1177     static const enum wined3d_format_id FormatList[] =
1178     {
1179         /* 16 bit */
1180         WINED3DFMT_B5G5R5X1_UNORM,
1181         WINED3DFMT_B5G5R5A1_UNORM,
1182         WINED3DFMT_B4G4R4A4_UNORM,
1183         WINED3DFMT_B5G6R5_UNORM,
1184         /* 32 bit */
1185         WINED3DFMT_B8G8R8X8_UNORM,
1186         WINED3DFMT_B8G8R8A8_UNORM,
1187         /* 8 bit */
1188         WINED3DFMT_B2G3R3_UNORM,
1189         WINED3DFMT_P8_UINT,
1190         /* FOURCC codes - Not in this version*/
1191     };
1192
1193     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1194
1195     if (!callback)
1196         return DDERR_INVALIDPARAMS;
1197
1198     wined3d_mutex_lock();
1199
1200     memset(&mode, 0, sizeof(mode));
1201     if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1202     {
1203         wined3d_mutex_unlock();
1204         WARN("Cannot get the current adapter format\n");
1205         return hr;
1206     }
1207
1208     for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1209     {
1210         if (wined3d_check_device_format(device->ddraw->wined3d, 0, WINED3D_DEVICE_TYPE_HAL,
1211                 mode.format_id, 0, WINED3D_RTYPE_TEXTURE, FormatList[i]) == D3D_OK)
1212         {
1213             DDSURFACEDESC sdesc;
1214
1215             memset(&sdesc, 0, sizeof(sdesc));
1216             sdesc.dwSize = sizeof(sdesc);
1217             sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1218             sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1219             sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1220             PixelFormat_WineD3DtoDD(&sdesc.ddpfPixelFormat, FormatList[i]);
1221
1222             TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1223             hr = callback(&sdesc, context);
1224             if(hr != DDENUMRET_OK)
1225             {
1226                 TRACE("Format enumeration cancelled by application\n");
1227                 wined3d_mutex_unlock();
1228                 return D3D_OK;
1229             }
1230         }
1231     }
1232     TRACE("End of enumeration\n");
1233     wined3d_mutex_unlock();
1234
1235     return D3D_OK;
1236 }
1237
1238 static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
1239         LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1240 {
1241     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1242
1243     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1244
1245     return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1246 }
1247
1248 /*****************************************************************************
1249  * IDirect3DDevice::CreateMatrix
1250  *
1251  * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1252  * allocated for the handle.
1253  *
1254  * Version 1 only
1255  *
1256  * Params
1257  *  D3DMatHandle: Address to return the handle at
1258  *
1259  * Returns:
1260  *  D3D_OK on success
1261  *  DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1262  *
1263  *****************************************************************************/
1264 static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1265 {
1266     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1267     D3DMATRIX *Matrix;
1268     DWORD h;
1269
1270     TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1271
1272     if(!D3DMatHandle)
1273         return DDERR_INVALIDPARAMS;
1274
1275     Matrix = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DMATRIX));
1276     if(!Matrix)
1277     {
1278         ERR("Out of memory when allocating a D3DMATRIX\n");
1279         return DDERR_OUTOFMEMORY;
1280     }
1281
1282     wined3d_mutex_lock();
1283
1284     h = ddraw_allocate_handle(&device->handle_table, Matrix, DDRAW_HANDLE_MATRIX);
1285     if (h == DDRAW_INVALID_HANDLE)
1286     {
1287         ERR("Failed to allocate a matrix handle.\n");
1288         HeapFree(GetProcessHeap(), 0, Matrix);
1289         wined3d_mutex_unlock();
1290         return DDERR_OUTOFMEMORY;
1291     }
1292
1293     *D3DMatHandle = h + 1;
1294
1295     TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1296
1297     wined3d_mutex_unlock();
1298
1299     return D3D_OK;
1300 }
1301
1302 /*****************************************************************************
1303  * IDirect3DDevice::SetMatrix
1304  *
1305  * Sets a matrix for a matrix handle. The matrix is copied into the memory
1306  * allocated for the handle
1307  *
1308  * Version 1 only
1309  *
1310  * Params:
1311  *  D3DMatHandle: Handle to set the matrix to
1312  *  D3DMatrix: Matrix to set
1313  *
1314  * Returns:
1315  *  D3D_OK on success
1316  *  DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1317  *   to set is NULL
1318  *
1319  *****************************************************************************/
1320 static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
1321         D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1322 {
1323     struct d3d_device *This = impl_from_IDirect3DDevice(iface);
1324     D3DMATRIX *m;
1325
1326     TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1327
1328     if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1329
1330     wined3d_mutex_lock();
1331
1332     m = ddraw_get_object(&This->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1333     if (!m)
1334     {
1335         WARN("Invalid matrix handle.\n");
1336         wined3d_mutex_unlock();
1337         return DDERR_INVALIDPARAMS;
1338     }
1339
1340     if (TRACE_ON(ddraw))
1341         dump_D3DMATRIX(D3DMatrix);
1342
1343     *m = *D3DMatrix;
1344
1345     if (D3DMatHandle == This->world)
1346         wined3d_device_set_transform(This->wined3d_device,
1347                 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)D3DMatrix);
1348
1349     if (D3DMatHandle == This->view)
1350         wined3d_device_set_transform(This->wined3d_device,
1351                 WINED3D_TS_VIEW, (struct wined3d_matrix *)D3DMatrix);
1352
1353     if (D3DMatHandle == This->proj)
1354         wined3d_device_set_transform(This->wined3d_device,
1355                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)D3DMatrix);
1356
1357     wined3d_mutex_unlock();
1358
1359     return D3D_OK;
1360 }
1361
1362 /*****************************************************************************
1363  * IDirect3DDevice::GetMatrix
1364  *
1365  * Returns the content of a D3DMATRIX handle
1366  *
1367  * Version 1 only
1368  *
1369  * Params:
1370  *  D3DMatHandle: Matrix handle to read the content from
1371  *  D3DMatrix: Address to store the content at
1372  *
1373  * Returns:
1374  *  D3D_OK on success
1375  *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1376  *
1377  *****************************************************************************/
1378 static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
1379         D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1380 {
1381     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1382     D3DMATRIX *m;
1383
1384     TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1385
1386     if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1387
1388     wined3d_mutex_lock();
1389
1390     m = ddraw_get_object(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1391     if (!m)
1392     {
1393         WARN("Invalid matrix handle.\n");
1394         wined3d_mutex_unlock();
1395         return DDERR_INVALIDPARAMS;
1396     }
1397
1398     *D3DMatrix = *m;
1399
1400     wined3d_mutex_unlock();
1401
1402     return D3D_OK;
1403 }
1404
1405 /*****************************************************************************
1406  * IDirect3DDevice::DeleteMatrix
1407  *
1408  * Destroys a Matrix handle. Frees the memory and unsets the handle data
1409  *
1410  * Version 1 only
1411  *
1412  * Params:
1413  *  D3DMatHandle: Handle to destroy
1414  *
1415  * Returns:
1416  *  D3D_OK on success
1417  *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1418  *
1419  *****************************************************************************/
1420 static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1421 {
1422     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1423     D3DMATRIX *m;
1424
1425     TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1426
1427     wined3d_mutex_lock();
1428
1429     m = ddraw_free_handle(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1430     if (!m)
1431     {
1432         WARN("Invalid matrix handle.\n");
1433         wined3d_mutex_unlock();
1434         return DDERR_INVALIDPARAMS;
1435     }
1436
1437     wined3d_mutex_unlock();
1438
1439     HeapFree(GetProcessHeap(), 0, m);
1440
1441     return D3D_OK;
1442 }
1443
1444 /*****************************************************************************
1445  * IDirect3DDevice7::BeginScene
1446  *
1447  * This method must be called before any rendering is performed.
1448  * IDirect3DDevice::EndScene has to be called after the scene is complete
1449  *
1450  * Version 1, 2, 3 and 7
1451  *
1452  * Returns:
1453  *  D3D_OK on success, for details see IWineD3DDevice::BeginScene
1454  *  D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1455  *  started scene).
1456  *
1457  *****************************************************************************/
1458 static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1459 {
1460     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1461     HRESULT hr;
1462
1463     TRACE("iface %p.\n", iface);
1464
1465     wined3d_mutex_lock();
1466     hr = wined3d_device_begin_scene(device->wined3d_device);
1467     wined3d_mutex_unlock();
1468
1469     if(hr == WINED3D_OK) return D3D_OK;
1470     else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1471 }
1472
1473 static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1474 {
1475     return d3d_device7_BeginScene(iface);
1476 }
1477
1478 static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1479 {
1480     HRESULT hr;
1481     WORD old_fpucw;
1482
1483     old_fpucw = d3d_fpu_setup();
1484     hr = d3d_device7_BeginScene(iface);
1485     set_fpu_control_word(old_fpucw);
1486
1487     return hr;
1488 }
1489
1490 static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1491 {
1492     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1493
1494     TRACE("iface %p.\n", iface);
1495
1496     return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1497 }
1498
1499 static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1500 {
1501     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1502
1503     TRACE("iface %p.\n", iface);
1504
1505     return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1506 }
1507
1508 static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1509 {
1510     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1511
1512     TRACE("iface %p.\n", iface);
1513
1514     return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1515 }
1516
1517 /*****************************************************************************
1518  * IDirect3DDevice7::EndScene
1519  *
1520  * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1521  * This method must be called after rendering is finished.
1522  *
1523  * Version 1, 2, 3 and 7
1524  *
1525  * Returns:
1526  *  D3D_OK on success, for details see IWineD3DDevice::EndScene
1527  *  D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1528  *  that only if the scene was already ended.
1529  *
1530  *****************************************************************************/
1531 static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1532 {
1533     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1534     HRESULT hr;
1535
1536     TRACE("iface %p.\n", iface);
1537
1538     wined3d_mutex_lock();
1539     hr = wined3d_device_end_scene(device->wined3d_device);
1540     wined3d_mutex_unlock();
1541
1542     if(hr == WINED3D_OK) return D3D_OK;
1543     else return D3DERR_SCENE_NOT_IN_SCENE;
1544 }
1545
1546 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1547 {
1548     return d3d_device7_EndScene(iface);
1549 }
1550
1551 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1552 {
1553     HRESULT hr;
1554     WORD old_fpucw;
1555
1556     old_fpucw = d3d_fpu_setup();
1557     hr = d3d_device7_EndScene(iface);
1558     set_fpu_control_word(old_fpucw);
1559
1560     return hr;
1561 }
1562
1563 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1564 {
1565     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1566
1567     TRACE("iface %p.\n", iface);
1568
1569     return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1570 }
1571
1572 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1573 {
1574     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1575
1576     TRACE("iface %p.\n", iface);
1577
1578     return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1579 }
1580
1581 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1582 {
1583     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1584
1585     TRACE("iface %p.\n", iface);
1586
1587     return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1588 }
1589
1590 /*****************************************************************************
1591  * IDirect3DDevice7::GetDirect3D
1592  *
1593  * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1594  * this device.
1595  *
1596  * Params:
1597  *  Direct3D7: Address to store the interface pointer at
1598  *
1599  * Returns:
1600  *  D3D_OK on success
1601  *  DDERR_INVALIDPARAMS if Direct3D7 == NULL
1602  *
1603  *****************************************************************************/
1604 static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1605 {
1606     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1607
1608     TRACE("iface %p, d3d %p.\n", iface, d3d);
1609
1610     if (!d3d)
1611         return DDERR_INVALIDPARAMS;
1612
1613     *d3d = &device->ddraw->IDirect3D7_iface;
1614     IDirect3D7_AddRef(*d3d);
1615
1616     TRACE("Returning interface %p.\n", *d3d);
1617     return D3D_OK;
1618 }
1619
1620 static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1621 {
1622     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1623
1624     TRACE("iface %p, d3d %p.\n", iface, d3d);
1625
1626     if (!d3d)
1627         return DDERR_INVALIDPARAMS;
1628
1629     *d3d = &device->ddraw->IDirect3D3_iface;
1630     IDirect3D3_AddRef(*d3d);
1631
1632     TRACE("Returning interface %p.\n", *d3d);
1633     return D3D_OK;
1634 }
1635
1636 static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1637 {
1638     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1639
1640     TRACE("iface %p, d3d %p.\n", iface, d3d);
1641
1642     if (!d3d)
1643         return DDERR_INVALIDPARAMS;
1644
1645     *d3d = &device->ddraw->IDirect3D2_iface;
1646     IDirect3D2_AddRef(*d3d);
1647
1648     TRACE("Returning interface %p.\n", *d3d);
1649     return D3D_OK;
1650 }
1651
1652 static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1653 {
1654     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1655
1656     TRACE("iface %p, d3d %p.\n", iface, d3d);
1657
1658     if (!d3d)
1659         return DDERR_INVALIDPARAMS;
1660
1661     *d3d = &device->ddraw->IDirect3D_iface;
1662     IDirect3D_AddRef(*d3d);
1663
1664     TRACE("Returning interface %p.\n", *d3d);
1665     return D3D_OK;
1666 }
1667
1668 /*****************************************************************************
1669  * IDirect3DDevice3::SetCurrentViewport
1670  *
1671  * Sets a Direct3DViewport as the current viewport.
1672  * For the thunks note that all viewport interface versions are equal
1673  *
1674  * Params:
1675  *  Direct3DViewport3: The viewport to set
1676  *
1677  * Version 2 and 3
1678  *
1679  * Returns:
1680  *  D3D_OK on success
1681  *  (Is a NULL viewport valid?)
1682  *
1683  *****************************************************************************/
1684 static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *Direct3DViewport3)
1685 {
1686     struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
1687     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Direct3DViewport3);
1688
1689     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport3);
1690
1691     wined3d_mutex_lock();
1692     /* Do nothing if the specified viewport is the same as the current one */
1693     if (This->current_viewport == vp )
1694     {
1695         wined3d_mutex_unlock();
1696         return D3D_OK;
1697     }
1698
1699     if (vp->active_device != This)
1700     {
1701         WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
1702         wined3d_mutex_unlock();
1703         return DDERR_INVALIDPARAMS;
1704     }
1705
1706     /* Release previous viewport and AddRef the new one */
1707     if (This->current_viewport)
1708     {
1709         TRACE("ViewportImpl is at %p, interface is at %p\n", This->current_viewport,
1710                 &This->current_viewport->IDirect3DViewport3_iface);
1711         IDirect3DViewport3_Release(&This->current_viewport->IDirect3DViewport3_iface);
1712     }
1713     IDirect3DViewport3_AddRef(Direct3DViewport3);
1714
1715     /* Set this viewport as the current viewport */
1716     This->current_viewport = vp;
1717
1718     /* Activate this viewport */
1719     viewport_activate(This->current_viewport, FALSE);
1720
1721     wined3d_mutex_unlock();
1722
1723     return D3D_OK;
1724 }
1725
1726 static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1727 {
1728     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1729     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1730
1731     TRACE("iface %p, viewport %p.\n", iface, viewport);
1732
1733     return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
1734 }
1735
1736 /*****************************************************************************
1737  * IDirect3DDevice3::GetCurrentViewport
1738  *
1739  * Returns the currently active viewport.
1740  *
1741  * Version 2 and 3
1742  *
1743  * Params:
1744  *  Direct3DViewport3: Address to return the interface pointer at
1745  *
1746  * Returns:
1747  *  D3D_OK on success
1748  *  DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1749  *
1750  *****************************************************************************/
1751 static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1752 {
1753     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1754
1755     TRACE("iface %p, viewport %p.\n", iface, viewport);
1756
1757     if (!viewport)
1758         return DDERR_INVALIDPARAMS;
1759
1760     wined3d_mutex_lock();
1761     *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1762
1763     /* AddRef the returned viewport */
1764     if (*viewport)
1765         IDirect3DViewport3_AddRef(*viewport);
1766
1767     TRACE("Returning interface %p.\n", *viewport);
1768
1769     wined3d_mutex_unlock();
1770
1771     return D3D_OK;
1772 }
1773
1774 static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1775 {
1776     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1777
1778     TRACE("iface %p, viewport %p.\n", iface, viewport);
1779
1780     return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
1781             (IDirect3DViewport3 **)viewport);
1782 }
1783
1784 /*****************************************************************************
1785  * IDirect3DDevice7::SetRenderTarget
1786  *
1787  * Sets the render target for the Direct3DDevice.
1788  * For the thunks note that IDirectDrawSurface7 == IDirectDrawSurface4 and
1789  * IDirectDrawSurface3 == IDirectDrawSurface
1790  *
1791  * Version 2, 3 and 7
1792  *
1793  * Params:
1794  *  NewTarget: Pointer to an IDirectDrawSurface7 interface to set as the new
1795  *             render target
1796  *  Flags: Some flags
1797  *
1798  * Returns:
1799  *  D3D_OK on success, for details see IWineD3DDevice::SetRenderTarget
1800  *
1801  *****************************************************************************/
1802 static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct ddraw_surface *target)
1803 {
1804     HRESULT hr;
1805
1806     wined3d_mutex_lock();
1807
1808     if (device->target == target)
1809     {
1810         TRACE("No-op SetRenderTarget operation, not doing anything\n");
1811         wined3d_mutex_unlock();
1812         return D3D_OK;
1813     }
1814     device->target = target;
1815     hr = wined3d_device_set_render_target(device->wined3d_device, 0,
1816             target ? target->wined3d_surface : NULL, FALSE);
1817     if(hr != D3D_OK)
1818     {
1819         wined3d_mutex_unlock();
1820         return hr;
1821     }
1822     d3d_device_update_depth_stencil(device);
1823
1824     wined3d_mutex_unlock();
1825
1826     return D3D_OK;
1827 }
1828
1829 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
1830         IDirectDrawSurface7 *NewTarget, DWORD flags)
1831 {
1832     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1833     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface7(NewTarget);
1834
1835     TRACE("iface %p, target %p, flags %#x.\n", iface, NewTarget, flags);
1836
1837     IDirectDrawSurface7_AddRef(NewTarget);
1838     IDirectDrawSurface7_Release(&device->target->IDirectDrawSurface7_iface);
1839     return d3d_device_set_render_target(device, target);
1840 }
1841
1842 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1843         IDirectDrawSurface7 *NewTarget, DWORD flags)
1844 {
1845     return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1846 }
1847
1848 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1849         IDirectDrawSurface7 *NewTarget, DWORD flags)
1850 {
1851     HRESULT hr;
1852     WORD old_fpucw;
1853
1854     old_fpucw = d3d_fpu_setup();
1855     hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1856     set_fpu_control_word(old_fpucw);
1857
1858     return hr;
1859 }
1860
1861 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
1862         IDirectDrawSurface4 *NewRenderTarget, DWORD flags)
1863 {
1864     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1865     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface4(NewRenderTarget);
1866
1867     TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
1868
1869     IDirectDrawSurface4_AddRef(NewRenderTarget);
1870     IDirectDrawSurface4_Release(&device->target->IDirectDrawSurface4_iface);
1871     return d3d_device_set_render_target(device, target);
1872 }
1873
1874 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
1875         IDirectDrawSurface *NewRenderTarget, DWORD flags)
1876 {
1877     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1878     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface(NewRenderTarget);
1879
1880     TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
1881
1882     IDirectDrawSurface_AddRef(NewRenderTarget);
1883     IDirectDrawSurface_Release(&device->target->IDirectDrawSurface_iface);
1884     return d3d_device_set_render_target(device, target);
1885 }
1886
1887 /*****************************************************************************
1888  * IDirect3DDevice7::GetRenderTarget
1889  *
1890  * Returns the current render target.
1891  * This is handled locally, because the WineD3D render target's parent
1892  * is an IParent
1893  *
1894  * Version 2, 3 and 7
1895  *
1896  * Params:
1897  *  RenderTarget: Address to store the surface interface pointer
1898  *
1899  * Returns:
1900  *  D3D_OK on success
1901  *  DDERR_INVALIDPARAMS if RenderTarget == NULL
1902  *
1903  *****************************************************************************/
1904 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
1905 {
1906     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1907
1908     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1909
1910     if(!RenderTarget)
1911         return DDERR_INVALIDPARAMS;
1912
1913     wined3d_mutex_lock();
1914     *RenderTarget = &device->target->IDirectDrawSurface7_iface;
1915     IDirectDrawSurface7_AddRef(*RenderTarget);
1916     wined3d_mutex_unlock();
1917
1918     return D3D_OK;
1919 }
1920
1921 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
1922 {
1923     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1924     IDirectDrawSurface7 *RenderTarget7;
1925     struct ddraw_surface *RenderTargetImpl;
1926     HRESULT hr;
1927
1928     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1929
1930     if(!RenderTarget)
1931         return DDERR_INVALIDPARAMS;
1932
1933     hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
1934     if(hr != D3D_OK) return hr;
1935     RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1936     *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
1937     IDirectDrawSurface4_AddRef(*RenderTarget);
1938     IDirectDrawSurface7_Release(RenderTarget7);
1939     return D3D_OK;
1940 }
1941
1942 static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
1943 {
1944     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1945     IDirectDrawSurface7 *RenderTarget7;
1946     struct ddraw_surface *RenderTargetImpl;
1947     HRESULT hr;
1948
1949     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1950
1951     if(!RenderTarget)
1952         return DDERR_INVALIDPARAMS;
1953
1954     hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
1955     if(hr != D3D_OK) return hr;
1956     RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1957     *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
1958     IDirectDrawSurface_AddRef(*RenderTarget);
1959     IDirectDrawSurface7_Release(RenderTarget7);
1960     return D3D_OK;
1961 }
1962
1963 /*****************************************************************************
1964  * IDirect3DDevice3::Begin
1965  *
1966  * Begins a description block of vertices. This is similar to glBegin()
1967  * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
1968  * described with IDirect3DDevice::Vertex are drawn.
1969  *
1970  * Version 2 and 3
1971  *
1972  * Params:
1973  *  PrimitiveType: The type of primitives to draw
1974  *  VertexTypeDesc: A flexible vertex format description of the vertices
1975  *  Flags: Some flags..
1976  *
1977  * Returns:
1978  *  D3D_OK on success
1979  *
1980  *****************************************************************************/
1981 static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
1982         D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
1983 {
1984     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1985
1986     TRACE("iface %p, primitive_type %#x, fvf %#x, flags %#x.\n",
1987             iface, primitive_type, fvf, flags);
1988
1989     wined3d_mutex_lock();
1990     device->primitive_type = primitive_type;
1991     device->vertex_type = fvf;
1992     device->render_flags = flags;
1993     device->vertex_size = get_flexible_vertex_size(device->vertex_type);
1994     device->nb_vertices = 0;
1995     wined3d_mutex_unlock();
1996
1997     return D3D_OK;
1998 }
1999
2000 static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
2001         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2002 {
2003     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2004     DWORD fvf;
2005
2006     TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2007             iface, primitive_type, vertex_type, flags);
2008
2009     switch (vertex_type)
2010     {
2011         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2012         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2013         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2014         default:
2015             ERR("Unexpected vertex type %#x.\n", vertex_type);
2016             return DDERR_INVALIDPARAMS;  /* Should never happen */
2017     };
2018
2019     return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2020 }
2021
2022 /*****************************************************************************
2023  * IDirect3DDevice3::BeginIndexed
2024  *
2025  * Draws primitives based on vertices in a vertex array which are specified
2026  * by indices.
2027  *
2028  * Version 2 and 3
2029  *
2030  * Params:
2031  *  PrimitiveType: Primitive type to draw
2032  *  VertexType: A FVF description of the vertex format
2033  *  Vertices: pointer to an array containing the vertices
2034  *  NumVertices: The number of vertices in the vertex array
2035  *  Flags: Some flags ...
2036  *
2037  * Returns:
2038  *  D3D_OK, because it's a stub
2039  *
2040  *****************************************************************************/
2041 static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
2042         D3DPRIMITIVETYPE primitive_type, DWORD fvf,
2043         void *vertices, DWORD vertex_count, DWORD flags)
2044 {
2045     FIXME("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2046             iface, primitive_type, fvf, vertices, vertex_count, flags);
2047
2048     return D3D_OK;
2049 }
2050
2051
2052 static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
2053         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
2054         void *vertices, DWORD vertex_count, DWORD flags)
2055 {
2056     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2057     DWORD fvf;
2058
2059     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2060             iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2061
2062     switch (vertex_type)
2063     {
2064         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2065         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2066         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2067         default:
2068             ERR("Unexpected vertex type %#x.\n", vertex_type);
2069             return DDERR_INVALIDPARAMS;  /* Should never happen */
2070     };
2071
2072     return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
2073             primitive_type, fvf, vertices, vertex_count, flags);
2074 }
2075
2076 /*****************************************************************************
2077  * IDirect3DDevice3::Vertex
2078  *
2079  * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2080  * drawn vertices in a vertex buffer. If the buffer is too small, its
2081  * size is increased.
2082  *
2083  * Version 2 and 3
2084  *
2085  * Params:
2086  *  Vertex: Pointer to the vertex
2087  *
2088  * Returns:
2089  *  D3D_OK, on success
2090  *  DDERR_INVALIDPARAMS if Vertex is NULL
2091  *
2092  *****************************************************************************/
2093 static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2094 {
2095     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2096
2097     TRACE("iface %p, vertex %p.\n", iface, vertex);
2098
2099     if (!vertex)
2100         return DDERR_INVALIDPARAMS;
2101
2102     wined3d_mutex_lock();
2103     if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2104     {
2105         BYTE *old_buffer;
2106
2107         device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
2108         old_buffer = device->sysmem_vertex_buffer;
2109         device->sysmem_vertex_buffer = HeapAlloc(GetProcessHeap(), 0, device->buffer_size);
2110         if (old_buffer)
2111         {
2112             memcpy(device->sysmem_vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2113             HeapFree(GetProcessHeap(), 0, old_buffer);
2114         }
2115     }
2116
2117     memcpy(device->sysmem_vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2118     wined3d_mutex_unlock();
2119
2120     return D3D_OK;
2121 }
2122
2123 static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2124 {
2125     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2126
2127     TRACE("iface %p, vertex %p.\n", iface, vertex);
2128
2129     return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2130 }
2131
2132 /*****************************************************************************
2133  * IDirect3DDevice3::Index
2134  *
2135  * Specifies an index to a vertex to be drawn. The vertex array has to
2136  * be specified with BeginIndexed first.
2137  *
2138  * Parameters:
2139  *  VertexIndex: The index of the vertex to draw
2140  *
2141  * Returns:
2142  *  D3D_OK because it's a stub
2143  *
2144  *****************************************************************************/
2145 static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2146 {
2147     FIXME("iface %p, index %#x stub!\n", iface, index);
2148
2149     return D3D_OK;
2150 }
2151
2152 static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2153 {
2154     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2155
2156     TRACE("iface %p, index %#x.\n", iface, index);
2157
2158     return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2159 }
2160
2161 /*****************************************************************************
2162  * IDirect3DDevice3::End
2163  *
2164  * Ends a draw begun with IDirect3DDevice3::Begin or
2165  * IDirect3DDevice::BeginIndexed. The vertices specified with
2166  * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
2167  * the IDirect3DDevice7::DrawPrimitive method. So far only
2168  * non-indexed mode is supported
2169  *
2170  * Version 2 and 3
2171  *
2172  * Params:
2173  *  Flags: Some flags, as usual. Don't know which are defined
2174  *
2175  * Returns:
2176  *  The return value of IDirect3DDevice7::DrawPrimitive
2177  *
2178  *****************************************************************************/
2179 static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
2180 {
2181     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2182
2183     TRACE("iface %p, flags %#x.\n", iface, flags);
2184
2185     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface, device->primitive_type,
2186             device->vertex_type, device->sysmem_vertex_buffer, device->nb_vertices, device->render_flags);
2187 }
2188
2189 static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
2190 {
2191     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2192
2193     TRACE("iface %p, flags %#x.\n", iface, flags);
2194
2195     return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
2196 }
2197
2198 /*****************************************************************************
2199  * IDirect3DDevice7::GetRenderState
2200  *
2201  * Returns the value of a render state. The possible render states are
2202  * defined in include/d3dtypes.h
2203  *
2204  * Version 2, 3 and 7
2205  *
2206  * Params:
2207  *  RenderStateType: Render state to return the current setting of
2208  *  Value: Address to store the value at
2209  *
2210  * Returns:
2211  *  D3D_OK on success, for details see IWineD3DDevice::GetRenderState
2212  *  DDERR_INVALIDPARAMS if Value == NULL
2213  *
2214  *****************************************************************************/
2215 static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
2216         D3DRENDERSTATETYPE state, DWORD *value)
2217 {
2218     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2219     HRESULT hr = D3D_OK;
2220
2221     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2222
2223     if (!value)
2224         return DDERR_INVALIDPARAMS;
2225
2226     wined3d_mutex_lock();
2227     switch (state)
2228     {
2229         case D3DRENDERSTATE_TEXTUREMAG:
2230         {
2231             enum wined3d_texture_filter_type tex_mag;
2232
2233             tex_mag = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER);
2234             switch (tex_mag)
2235             {
2236                 case WINED3D_TEXF_POINT:
2237                     *value = D3DFILTER_NEAREST;
2238                     break;
2239                 case WINED3D_TEXF_LINEAR:
2240                     *value = D3DFILTER_LINEAR;
2241                     break;
2242                 default:
2243                     ERR("Unhandled texture mag %d !\n",tex_mag);
2244                     *value = 0;
2245             }
2246             break;
2247         }
2248
2249         case D3DRENDERSTATE_TEXTUREMIN:
2250         {
2251             enum wined3d_texture_filter_type tex_min;
2252             enum wined3d_texture_filter_type tex_mip;
2253
2254             tex_min = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MIN_FILTER);
2255             tex_mip = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MIP_FILTER);
2256             switch (tex_min)
2257             {
2258                 case WINED3D_TEXF_POINT:
2259                     switch (tex_mip)
2260                     {
2261                         case WINED3D_TEXF_NONE:
2262                             *value = D3DFILTER_NEAREST;
2263                             break;
2264                         case WINED3D_TEXF_POINT:
2265                             *value = D3DFILTER_MIPNEAREST;
2266                             break;
2267                         case WINED3D_TEXF_LINEAR:
2268                             *value = D3DFILTER_LINEARMIPNEAREST;
2269                             break;
2270                         default:
2271                             ERR("Unhandled mip filter %#x.\n", tex_mip);
2272                             *value = D3DFILTER_NEAREST;
2273                             break;
2274                     }
2275                     break;
2276                 case WINED3D_TEXF_LINEAR:
2277                     switch (tex_mip)
2278                     {
2279                         case WINED3D_TEXF_NONE:
2280                             *value = D3DFILTER_LINEAR;
2281                             break;
2282                         case WINED3D_TEXF_POINT:
2283                             *value = D3DFILTER_MIPLINEAR;
2284                             break;
2285                         case WINED3D_TEXF_LINEAR:
2286                             *value = D3DFILTER_LINEARMIPLINEAR;
2287                             break;
2288                         default:
2289                             ERR("Unhandled mip filter %#x.\n", tex_mip);
2290                             *value = D3DFILTER_LINEAR;
2291                             break;
2292                     }
2293                     break;
2294                 default:
2295                     ERR("Unhandled texture min filter %#x.\n",tex_min);
2296                     *value = D3DFILTER_NEAREST;
2297                     break;
2298             }
2299             break;
2300         }
2301
2302         case D3DRENDERSTATE_TEXTUREADDRESS:
2303         case D3DRENDERSTATE_TEXTUREADDRESSU:
2304             *value = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_ADDRESS_U);
2305             break;
2306         case D3DRENDERSTATE_TEXTUREADDRESSV:
2307             *value = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_ADDRESS_V);
2308             break;
2309
2310         case D3DRENDERSTATE_BORDERCOLOR:
2311             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2312             hr = E_NOTIMPL;
2313             break;
2314
2315         case D3DRENDERSTATE_TEXTUREHANDLE:
2316         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2317             WARN("Render state %#x is invalid in d3d7.\n", state);
2318             hr = DDERR_INVALIDPARAMS;
2319             break;
2320
2321         case D3DRENDERSTATE_ZBIAS:
2322             *value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
2323             break;
2324
2325         default:
2326             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2327                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2328             {
2329                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2330                 hr = E_NOTIMPL;
2331                 break;
2332             }
2333             *value = wined3d_device_get_render_state(device->wined3d_device, state);
2334     }
2335     wined3d_mutex_unlock();
2336
2337     return hr;
2338 }
2339
2340 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2341         D3DRENDERSTATETYPE state, DWORD *value)
2342 {
2343     return d3d_device7_GetRenderState(iface, state, value);
2344 }
2345
2346 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2347         D3DRENDERSTATETYPE state, DWORD *value)
2348 {
2349     HRESULT hr;
2350     WORD old_fpucw;
2351
2352     old_fpucw = d3d_fpu_setup();
2353     hr = d3d_device7_GetRenderState(iface, state, value);
2354     set_fpu_control_word(old_fpucw);
2355
2356     return hr;
2357 }
2358
2359 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2360         D3DRENDERSTATETYPE state, DWORD *value)
2361 {
2362     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2363
2364     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2365
2366     switch (state)
2367     {
2368         case D3DRENDERSTATE_TEXTUREHANDLE:
2369         {
2370             /* This state is wrapped to SetTexture in SetRenderState, so
2371              * it has to be wrapped to GetTexture here. */
2372             struct wined3d_texture *tex = NULL;
2373             *value = 0;
2374
2375             wined3d_mutex_lock();
2376             if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2377             {
2378                 /* The parent of the texture is the IDirectDrawSurface7
2379                  * interface of the ddraw surface. */
2380                 struct ddraw_surface *parent = wined3d_texture_get_parent(tex);
2381                 if (parent)
2382                     *value = parent->Handle;
2383             }
2384             wined3d_mutex_unlock();
2385
2386             return D3D_OK;
2387         }
2388
2389         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2390         {
2391             /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse
2392                the mapping to get the value. */
2393             DWORD colorop, colorarg1, colorarg2;
2394             DWORD alphaop, alphaarg1, alphaarg2;
2395
2396             wined3d_mutex_lock();
2397
2398             device->legacyTextureBlending = TRUE;
2399
2400             colorop = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_OP);
2401             colorarg1 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG1);
2402             colorarg2 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG2);
2403             alphaop = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_OP);
2404             alphaarg1 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG1);
2405             alphaarg2 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG2);
2406
2407             if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2408                     && alphaop == WINED3D_TOP_SELECT_ARG1 && alphaarg1 == WINED3DTA_TEXTURE)
2409                 *value = D3DTBLEND_DECAL;
2410             else if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2411                     && alphaop == WINED3D_TOP_MODULATE
2412                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2413                 *value = D3DTBLEND_DECALALPHA;
2414             else if (colorop == WINED3D_TOP_MODULATE
2415                     && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2416                     && alphaop == WINED3D_TOP_MODULATE
2417                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2418                 *value = D3DTBLEND_MODULATEALPHA;
2419             else
2420             {
2421                 struct wined3d_texture *tex = NULL;
2422                 BOOL tex_alpha = FALSE;
2423                 DDPIXELFORMAT ddfmt;
2424
2425                 if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2426                 {
2427                     struct wined3d_resource *sub_resource;
2428
2429                     if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2430                     {
2431                         struct wined3d_resource_desc desc;
2432
2433                         wined3d_resource_get_desc(sub_resource, &desc);
2434                         ddfmt.dwSize = sizeof(ddfmt);
2435                         PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2436                         if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2437                     }
2438                 }
2439
2440                 if (!(colorop == WINED3D_TOP_MODULATE
2441                         && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2442                         && alphaop == (tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2)
2443                         && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT))
2444                     ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous.\n");
2445
2446                 *value = D3DTBLEND_MODULATE;
2447             }
2448
2449             wined3d_mutex_unlock();
2450
2451             return D3D_OK;
2452         }
2453
2454         default:
2455             return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2456     }
2457 }
2458
2459 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2460         D3DRENDERSTATETYPE state, DWORD *value)
2461 {
2462     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2463
2464     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2465
2466     return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2467 }
2468
2469 /*****************************************************************************
2470  * IDirect3DDevice7::SetRenderState
2471  *
2472  * Sets a render state. The possible render states are defined in
2473  * include/d3dtypes.h
2474  *
2475  * Version 2, 3 and 7
2476  *
2477  * Params:
2478  *  RenderStateType: State to set
2479  *  Value: Value to assign to that state
2480  *
2481  * Returns:
2482  *  D3D_OK on success,
2483  *  for details see IWineD3DDevice::SetRenderState
2484  *
2485  *****************************************************************************/
2486 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2487         D3DRENDERSTATETYPE state, DWORD value)
2488 {
2489     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2490     HRESULT hr = D3D_OK;
2491
2492     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2493
2494     wined3d_mutex_lock();
2495     /* Some render states need special care */
2496     switch (state)
2497     {
2498         /*
2499          * The ddraw texture filter mapping works like this:
2500          *     D3DFILTER_NEAREST            Point min/mag, no mip
2501          *     D3DFILTER_MIPNEAREST         Point min/mag, point mip
2502          *     D3DFILTER_LINEARMIPNEAREST:  Point min/mag, linear mip
2503          *
2504          *     D3DFILTER_LINEAR             Linear min/mag, no mip
2505          *     D3DFILTER_MIPLINEAR          Linear min/mag, point mip
2506          *     D3DFILTER_LINEARMIPLINEAR    Linear min/mag, linear mip
2507          *
2508          * This is the opposite of the GL naming convention,
2509          * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2510          */
2511         case D3DRENDERSTATE_TEXTUREMAG:
2512         {
2513             enum wined3d_texture_filter_type tex_mag;
2514
2515             switch (value)
2516             {
2517                 case D3DFILTER_NEAREST:
2518                 case D3DFILTER_MIPNEAREST:
2519                 case D3DFILTER_LINEARMIPNEAREST:
2520                     tex_mag = WINED3D_TEXF_POINT;
2521                     break;
2522                 case D3DFILTER_LINEAR:
2523                 case D3DFILTER_MIPLINEAR:
2524                 case D3DFILTER_LINEARMIPLINEAR:
2525                     tex_mag = WINED3D_TEXF_LINEAR;
2526                     break;
2527                 default:
2528                     tex_mag = WINED3D_TEXF_POINT;
2529                     FIXME("Unhandled texture mag %#x.\n", value);
2530                     break;
2531             }
2532
2533             wined3d_device_set_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2534             break;
2535         }
2536
2537         case D3DRENDERSTATE_TEXTUREMIN:
2538         {
2539             enum wined3d_texture_filter_type tex_min;
2540             enum wined3d_texture_filter_type tex_mip;
2541
2542             switch (value)
2543             {
2544                 case D3DFILTER_NEAREST:
2545                     tex_min = WINED3D_TEXF_POINT;
2546                     tex_mip = WINED3D_TEXF_NONE;
2547                     break;
2548                 case D3DFILTER_LINEAR:
2549                     tex_min = WINED3D_TEXF_LINEAR;
2550                     tex_mip = WINED3D_TEXF_NONE;
2551                     break;
2552                 case D3DFILTER_MIPNEAREST:
2553                     tex_min = WINED3D_TEXF_POINT;
2554                     tex_mip = WINED3D_TEXF_POINT;
2555                     break;
2556                 case D3DFILTER_MIPLINEAR:
2557                     tex_min = WINED3D_TEXF_LINEAR;
2558                     tex_mip = WINED3D_TEXF_POINT;
2559                     break;
2560                 case D3DFILTER_LINEARMIPNEAREST:
2561                     tex_min = WINED3D_TEXF_POINT;
2562                     tex_mip = WINED3D_TEXF_LINEAR;
2563                     break;
2564                 case D3DFILTER_LINEARMIPLINEAR:
2565                     tex_min = WINED3D_TEXF_LINEAR;
2566                     tex_mip = WINED3D_TEXF_LINEAR;
2567                     break;
2568
2569                 default:
2570                     FIXME("Unhandled texture min %#x.\n",value);
2571                     tex_min = WINED3D_TEXF_POINT;
2572                     tex_mip = WINED3D_TEXF_NONE;
2573                     break;
2574             }
2575
2576             wined3d_device_set_sampler_state(device->wined3d_device,
2577                     0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2578             wined3d_device_set_sampler_state(device->wined3d_device,
2579                     0, WINED3D_SAMP_MIN_FILTER, tex_min);
2580             break;
2581         }
2582
2583         case D3DRENDERSTATE_TEXTUREADDRESS:
2584             wined3d_device_set_sampler_state(device->wined3d_device,
2585                     0, WINED3D_SAMP_ADDRESS_V, value);
2586             /* Drop through */
2587         case D3DRENDERSTATE_TEXTUREADDRESSU:
2588             wined3d_device_set_sampler_state(device->wined3d_device,
2589                     0, WINED3D_SAMP_ADDRESS_U, value);
2590             break;
2591         case D3DRENDERSTATE_TEXTUREADDRESSV:
2592             wined3d_device_set_sampler_state(device->wined3d_device,
2593                     0, WINED3D_SAMP_ADDRESS_V, value);
2594             break;
2595
2596         case D3DRENDERSTATE_BORDERCOLOR:
2597             /* This should probably just forward to the corresponding sampler
2598              * state. Needs tests. */
2599             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2600             hr = E_NOTIMPL;
2601             break;
2602
2603         case D3DRENDERSTATE_TEXTUREHANDLE:
2604         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2605             WARN("Render state %#x is invalid in d3d7.\n", state);
2606             hr = DDERR_INVALIDPARAMS;
2607             break;
2608
2609         case D3DRENDERSTATE_ZBIAS:
2610             wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
2611             break;
2612
2613         default:
2614             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2615                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2616             {
2617                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2618                 hr = E_NOTIMPL;
2619                 break;
2620             }
2621
2622             wined3d_device_set_render_state(device->wined3d_device, state, value);
2623             break;
2624     }
2625     wined3d_mutex_unlock();
2626
2627     return hr;
2628 }
2629
2630 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2631         D3DRENDERSTATETYPE state, DWORD value)
2632 {
2633     return d3d_device7_SetRenderState(iface, state, value);
2634 }
2635
2636 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2637         D3DRENDERSTATETYPE state, DWORD value)
2638 {
2639     HRESULT hr;
2640     WORD old_fpucw;
2641
2642     old_fpucw = d3d_fpu_setup();
2643     hr = d3d_device7_SetRenderState(iface, state, value);
2644     set_fpu_control_word(old_fpucw);
2645
2646     return hr;
2647 }
2648
2649 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2650         D3DRENDERSTATETYPE state, DWORD value)
2651 {
2652     /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2653     for this state can be directly mapped to texture stage colorop and alphaop, but
2654     D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2655     from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2656     alphaarg when needed.
2657
2658     Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2659
2660     Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2661     TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2662     are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2663     requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2664     with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2665     in device - TRUE if the app is using TEXTUREMAPBLEND.
2666
2667     Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2668     GetTextureStageState and vice versa. Not so on Wine, but it is 'undefined' anyway so, probably, ok,
2669     unless some broken game will be found that cares. */
2670
2671     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2672     HRESULT hr;
2673
2674     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2675
2676     wined3d_mutex_lock();
2677
2678     switch (state)
2679     {
2680         case D3DRENDERSTATE_TEXTUREHANDLE:
2681         {
2682             struct ddraw_surface *surf;
2683
2684             if (value == 0)
2685             {
2686                 hr = wined3d_device_set_texture(device->wined3d_device, 0, NULL);
2687                 break;
2688             }
2689
2690             surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2691             if (!surf)
2692             {
2693                 WARN("Invalid texture handle.\n");
2694                 hr = DDERR_INVALIDPARAMS;
2695                 break;
2696             }
2697
2698             hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2699             break;
2700         }
2701
2702         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2703         {
2704             device->legacyTextureBlending = TRUE;
2705
2706             switch (value)
2707             {
2708                 case D3DTBLEND_MODULATE:
2709                 {
2710                     struct wined3d_texture *tex = NULL;
2711                     BOOL tex_alpha = FALSE;
2712                     DDPIXELFORMAT ddfmt;
2713
2714                     if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2715                     {
2716                         struct wined3d_resource *sub_resource;
2717
2718                         if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2719                         {
2720                             struct wined3d_resource_desc desc;
2721
2722                             wined3d_resource_get_desc(sub_resource, &desc);
2723                             ddfmt.dwSize = sizeof(ddfmt);
2724                             PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2725                             if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2726                         }
2727                     }
2728
2729                     if (tex_alpha)
2730                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2731                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2732                     else
2733                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2734                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2735                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2736                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2737                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2738                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2739                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2740                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2741                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2742                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2743                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2744                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2745                     break;
2746                 }
2747
2748                 case D3DTBLEND_ADD:
2749                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2750                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2751                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2752                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2753                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2754                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2755                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2756                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2757                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2758                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2759                     break;
2760
2761                 case D3DTBLEND_MODULATEALPHA:
2762                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2763                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2764                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2765                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2766                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2767                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2768                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2769                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2770                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2771                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2772                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2773                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2774                     break;
2775
2776                 case D3DTBLEND_COPY:
2777                 case D3DTBLEND_DECAL:
2778                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2779                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2780                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2781                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2782                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2783                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2784                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2785                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2786                     break;
2787
2788                 case D3DTBLEND_DECALALPHA:
2789                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2790                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2791                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2792                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2793                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2794                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2795                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2796                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2797                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2798                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2799                     break;
2800
2801                 default:
2802                     FIXME("Unhandled texture environment %#x.\n", value);
2803             }
2804
2805             hr = D3D_OK;
2806             break;
2807         }
2808
2809         default:
2810             hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2811             break;
2812     }
2813     wined3d_mutex_unlock();
2814
2815     return hr;
2816 }
2817
2818 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2819         D3DRENDERSTATETYPE state, DWORD value)
2820 {
2821     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2822
2823     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2824
2825     return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2826 }
2827
2828 /*****************************************************************************
2829  * Direct3DDevice3::SetLightState
2830  *
2831  * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2832  * light states are forwarded to Direct3DDevice7 render states
2833  *
2834  * Version 2 and 3
2835  *
2836  * Params:
2837  *  LightStateType: The light state to change
2838  *  Value: The value to assign to that light state
2839  *
2840  * Returns:
2841  *  D3D_OK on success
2842  *  DDERR_INVALIDPARAMS if the parameters were incorrect
2843  *  Also check IDirect3DDevice7::SetRenderState
2844  *
2845  *****************************************************************************/
2846 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2847         D3DLIGHTSTATETYPE state, DWORD value)
2848 {
2849     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2850     HRESULT hr;
2851
2852     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2853
2854     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2855     {
2856         TRACE("Unexpected Light State Type\n");
2857         return DDERR_INVALIDPARAMS;
2858     }
2859
2860     wined3d_mutex_lock();
2861     if (state == D3DLIGHTSTATE_MATERIAL)
2862     {
2863         struct d3d_material *m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL);
2864         if (!m)
2865         {
2866             WARN("Invalid material handle.\n");
2867             wined3d_mutex_unlock();
2868             return DDERR_INVALIDPARAMS;
2869         }
2870
2871         TRACE(" activating material %p.\n", m);
2872         material_activate(m);
2873
2874         device->material = value;
2875     }
2876     else if (state == D3DLIGHTSTATE_COLORMODEL)
2877     {
2878         switch (value)
2879         {
2880             case D3DCOLOR_MONO:
2881                 ERR("DDCOLOR_MONO should not happen!\n");
2882                 break;
2883             case D3DCOLOR_RGB:
2884                 /* We are already in this mode */
2885                 TRACE("Setting color model to RGB (no-op).\n");
2886                 break;
2887             default:
2888                 ERR("Unknown color model!\n");
2889                 wined3d_mutex_unlock();
2890                 return DDERR_INVALIDPARAMS;
2891         }
2892     }
2893     else
2894     {
2895         D3DRENDERSTATETYPE rs;
2896         switch (state)
2897         {
2898             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
2899                 rs = D3DRENDERSTATE_AMBIENT;
2900                 break;
2901             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
2902                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2903                 break;
2904             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
2905                 rs = D3DRENDERSTATE_FOGSTART;
2906                 break;
2907             case D3DLIGHTSTATE_FOGEND:        /* 6 */
2908                 rs = D3DRENDERSTATE_FOGEND;
2909                 break;
2910             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
2911                 rs = D3DRENDERSTATE_FOGDENSITY;
2912                 break;
2913             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
2914                 rs = D3DRENDERSTATE_COLORVERTEX;
2915                 break;
2916             default:
2917                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2918                 wined3d_mutex_unlock();
2919                 return DDERR_INVALIDPARAMS;
2920         }
2921
2922         hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2923         wined3d_mutex_unlock();
2924         return hr;
2925     }
2926     wined3d_mutex_unlock();
2927
2928     return D3D_OK;
2929 }
2930
2931 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
2932         D3DLIGHTSTATETYPE state, DWORD value)
2933 {
2934     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2935
2936     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2937
2938     return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2939 }
2940
2941 /*****************************************************************************
2942  * IDirect3DDevice3::GetLightState
2943  *
2944  * Returns the current setting of a light state. The state is read from
2945  * the Direct3DDevice7 render state.
2946  *
2947  * Version 2 and 3
2948  *
2949  * Params:
2950  *  LightStateType: The light state to return
2951  *  Value: The address to store the light state setting at
2952  *
2953  * Returns:
2954  *  D3D_OK on success
2955  *  DDDERR_INVALIDPARAMS if the parameters were incorrect
2956  *  Also see IDirect3DDevice7::GetRenderState
2957  *
2958  *****************************************************************************/
2959 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
2960         D3DLIGHTSTATETYPE state, DWORD *value)
2961 {
2962     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2963     HRESULT hr;
2964
2965     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2966
2967     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2968     {
2969         TRACE("Unexpected Light State Type\n");
2970         return DDERR_INVALIDPARAMS;
2971     }
2972
2973     if (!value)
2974         return DDERR_INVALIDPARAMS;
2975
2976     wined3d_mutex_lock();
2977     if (state == D3DLIGHTSTATE_MATERIAL)
2978     {
2979         *value = device->material;
2980     }
2981     else if (state == D3DLIGHTSTATE_COLORMODEL)
2982     {
2983         *value = D3DCOLOR_RGB;
2984     }
2985     else
2986     {
2987         D3DRENDERSTATETYPE rs;
2988         switch (state)
2989         {
2990             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
2991                 rs = D3DRENDERSTATE_AMBIENT;
2992                 break;
2993             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
2994                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2995                 break;
2996             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
2997                 rs = D3DRENDERSTATE_FOGSTART;
2998                 break;
2999             case D3DLIGHTSTATE_FOGEND:        /* 6 */
3000                 rs = D3DRENDERSTATE_FOGEND;
3001                 break;
3002             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
3003                 rs = D3DRENDERSTATE_FOGDENSITY;
3004                 break;
3005             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
3006                 rs = D3DRENDERSTATE_COLORVERTEX;
3007                 break;
3008             default:
3009                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3010                 wined3d_mutex_unlock();
3011                 return DDERR_INVALIDPARAMS;
3012         }
3013
3014         hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3015         wined3d_mutex_unlock();
3016         return hr;
3017     }
3018     wined3d_mutex_unlock();
3019
3020     return D3D_OK;
3021 }
3022
3023 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3024         D3DLIGHTSTATETYPE state, DWORD *value)
3025 {
3026     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3027
3028     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3029
3030     return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3031 }
3032
3033 /*****************************************************************************
3034  * IDirect3DDevice7::SetTransform
3035  *
3036  * Assigns a D3DMATRIX to a transform type. The transform types are defined
3037  * in include/d3dtypes.h.
3038  * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3039  * (=255) for wined3d, because the 1 transform state was removed in d3d8
3040  * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3041  *
3042  * Version 2, 3 and 7
3043  *
3044  * Params:
3045  *  TransformStateType: transform state to set
3046  *  Matrix: Matrix to assign to the state
3047  *
3048  * Returns:
3049  *  D3D_OK on success
3050  *  DDERR_INVALIDPARAMS if Matrix == NULL
3051  *  For details see IWineD3DDevice::SetTransform
3052  *
3053  *****************************************************************************/
3054 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3055         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3056 {
3057     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3058     enum wined3d_transform_state wined3d_state;
3059
3060     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3061
3062     switch (state)
3063     {
3064         case D3DTRANSFORMSTATE_WORLD:
3065             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3066             break;
3067         case D3DTRANSFORMSTATE_WORLD1:
3068             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3069             break;
3070         case D3DTRANSFORMSTATE_WORLD2:
3071             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3072             break;
3073         case D3DTRANSFORMSTATE_WORLD3:
3074             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3075             break;
3076         default:
3077             wined3d_state = state;
3078     }
3079
3080     if (!matrix)
3081         return DDERR_INVALIDPARAMS;
3082
3083     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3084     wined3d_mutex_lock();
3085     wined3d_device_set_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3086     wined3d_mutex_unlock();
3087
3088     return D3D_OK;
3089 }
3090
3091 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3092         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3093 {
3094     return d3d_device7_SetTransform(iface, state, matrix);
3095 }
3096
3097 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3098         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3099 {
3100     HRESULT hr;
3101     WORD old_fpucw;
3102
3103     old_fpucw = d3d_fpu_setup();
3104     hr = d3d_device7_SetTransform(iface, state, matrix);
3105     set_fpu_control_word(old_fpucw);
3106
3107     return hr;
3108 }
3109
3110 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3111         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3112 {
3113     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3114
3115     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3116
3117     if (!matrix)
3118         return DDERR_INVALIDPARAMS;
3119
3120     if (state == D3DTRANSFORMSTATE_PROJECTION)
3121     {
3122         D3DMATRIX projection;
3123
3124         wined3d_mutex_lock();
3125         multiply_matrix(&projection, &device->legacy_clipspace, matrix);
3126         wined3d_device_set_transform(device->wined3d_device,
3127                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3128         device->legacy_projection = *matrix;
3129         wined3d_mutex_unlock();
3130
3131         return D3D_OK;
3132     }
3133
3134     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3135 }
3136
3137 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3138         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3139 {
3140     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3141
3142     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3143
3144     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3145 }
3146
3147 /*****************************************************************************
3148  * IDirect3DDevice7::GetTransform
3149  *
3150  * Returns the matrix assigned to a transform state
3151  * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3152  * SetTransform
3153  *
3154  * Params:
3155  *  TransformStateType: State to read the matrix from
3156  *  Matrix: Address to store the matrix at
3157  *
3158  * Returns:
3159  *  D3D_OK on success
3160  *  DDERR_INVALIDPARAMS if Matrix == NULL
3161  *  For details, see IWineD3DDevice::GetTransform
3162  *
3163  *****************************************************************************/
3164 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3165         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3166 {
3167     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3168     enum wined3d_transform_state wined3d_state;
3169
3170     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3171
3172     switch (state)
3173     {
3174         case D3DTRANSFORMSTATE_WORLD:
3175             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3176             break;
3177         case D3DTRANSFORMSTATE_WORLD1:
3178             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3179             break;
3180         case D3DTRANSFORMSTATE_WORLD2:
3181             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3182             break;
3183         case D3DTRANSFORMSTATE_WORLD3:
3184             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3185             break;
3186         default:
3187             wined3d_state = state;
3188     }
3189
3190     if (!matrix)
3191         return DDERR_INVALIDPARAMS;
3192
3193     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3194     wined3d_mutex_lock();
3195     wined3d_device_get_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3196     wined3d_mutex_unlock();
3197
3198     return D3D_OK;
3199 }
3200
3201 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3202         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3203 {
3204     return d3d_device7_GetTransform(iface, state, matrix);
3205 }
3206
3207 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3208         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3209 {
3210     HRESULT hr;
3211     WORD old_fpucw;
3212
3213     old_fpucw = d3d_fpu_setup();
3214     hr = d3d_device7_GetTransform(iface, state, matrix);
3215     set_fpu_control_word(old_fpucw);
3216
3217     return hr;
3218 }
3219
3220 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3221         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3222 {
3223     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3224
3225     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3226
3227     if (!matrix)
3228         return DDERR_INVALIDPARAMS;
3229
3230     if (state == D3DTRANSFORMSTATE_PROJECTION)
3231     {
3232         wined3d_mutex_lock();
3233         *matrix = device->legacy_projection;
3234         wined3d_mutex_unlock();
3235         return DD_OK;
3236     }
3237
3238     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3239 }
3240
3241 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3242         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3243 {
3244     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3245
3246     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3247
3248     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3249 }
3250
3251 /*****************************************************************************
3252  * IDirect3DDevice7::MultiplyTransform
3253  *
3254  * Multiplies the already-set transform matrix of a transform state
3255  * with another matrix. For the world matrix, see SetTransform
3256  *
3257  * Version 2, 3 and 7
3258  *
3259  * Params:
3260  *  TransformStateType: Transform state to multiply
3261  *  D3DMatrix Matrix to multiply with.
3262  *
3263  * Returns
3264  *  D3D_OK on success
3265  *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
3266  *  For details, see IWineD3DDevice::MultiplyTransform
3267  *
3268  *****************************************************************************/
3269 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3270         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3271 {
3272     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3273     enum wined3d_transform_state wined3d_state;
3274
3275     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3276
3277     switch (state)
3278     {
3279         case D3DTRANSFORMSTATE_WORLD:
3280             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3281             break;
3282         case D3DTRANSFORMSTATE_WORLD1:
3283             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3284             break;
3285         case D3DTRANSFORMSTATE_WORLD2:
3286             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3287             break;
3288         case D3DTRANSFORMSTATE_WORLD3:
3289             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3290             break;
3291         default:
3292             wined3d_state = state;
3293     }
3294
3295     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3296     wined3d_mutex_lock();
3297     wined3d_device_multiply_transform(device->wined3d_device,
3298             wined3d_state, (struct wined3d_matrix *)matrix);
3299     wined3d_mutex_unlock();
3300
3301     return D3D_OK;
3302 }
3303
3304 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3305         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3306 {
3307     return d3d_device7_MultiplyTransform(iface, state, matrix);
3308 }
3309
3310 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3311         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3312 {
3313     HRESULT hr;
3314     WORD old_fpucw;
3315
3316     old_fpucw = d3d_fpu_setup();
3317     hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3318     set_fpu_control_word(old_fpucw);
3319
3320     return hr;
3321 }
3322
3323 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3324         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3325 {
3326     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3327
3328     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3329
3330     if (state == D3DTRANSFORMSTATE_PROJECTION)
3331     {
3332         D3DMATRIX projection, tmp;
3333
3334         wined3d_mutex_lock();
3335         multiply_matrix(&tmp, &device->legacy_projection, matrix);
3336         multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3337         wined3d_device_set_transform(device->wined3d_device,
3338                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3339         device->legacy_projection = tmp;
3340         wined3d_mutex_unlock();
3341
3342         return D3D_OK;
3343     }
3344
3345     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3346 }
3347
3348 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3349         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3350 {
3351     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3352
3353     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3354
3355     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3356 }
3357
3358 /*****************************************************************************
3359  * IDirect3DDevice7::DrawPrimitive
3360  *
3361  * Draws primitives based on vertices in an application-provided pointer
3362  *
3363  * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3364  * an FVF format for D3D7
3365  *
3366  * Params:
3367  *  PrimitiveType: The type of the primitives to draw
3368  *  Vertex type: Flexible vertex format vertex description
3369  *  Vertices: Pointer to the vertex array
3370  *  VertexCount: The number of vertices to draw
3371  *  Flags: As usual a few flags
3372  *
3373  * Returns:
3374  *  D3D_OK on success
3375  *  DDERR_INVALIDPARAMS if Vertices is NULL
3376  *  For details, see IWineD3DDevice::DrawPrimitiveUP
3377  *
3378  *****************************************************************************/
3379
3380 /* The caller is responsible for wined3d locking */
3381 static HRESULT d3d_device_prepare_vertex_buffer(struct d3d_device *device, UINT min_size)
3382 {
3383     HRESULT hr;
3384
3385     if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
3386     {
3387         UINT size = max(device->vertex_buffer_size * 2, min_size);
3388         struct wined3d_buffer *buffer;
3389
3390         TRACE("Growing vertex buffer to %u bytes\n", size);
3391
3392         hr = wined3d_buffer_create_vb(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
3393                 WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
3394         if (FAILED(hr))
3395         {
3396             ERR("(%p) wined3d_buffer_create_vb failed with hr = %08x\n", device, hr);
3397             return hr;
3398         }
3399
3400         if (device->vertex_buffer)
3401             wined3d_buffer_decref(device->vertex_buffer);
3402
3403         device->vertex_buffer = buffer;
3404         device->vertex_buffer_size = size;
3405         device->vertex_buffer_pos = 0;
3406     }
3407     return D3D_OK;
3408 }
3409
3410 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3411         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3412         DWORD vertex_count, DWORD flags)
3413 {
3414     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3415     UINT stride, vb_pos, size, align;
3416     HRESULT hr;
3417     BYTE *data;
3418
3419     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3420             iface, primitive_type, fvf, vertices, vertex_count, flags);
3421
3422     if (!vertices)
3423         return DDERR_INVALIDPARAMS;
3424
3425     /* Get the stride */
3426     stride = get_flexible_vertex_size(fvf);
3427     size = vertex_count * stride;
3428
3429     wined3d_mutex_lock();
3430     hr = d3d_device_prepare_vertex_buffer(device, size);
3431     if (FAILED(hr))
3432         goto done;
3433
3434     vb_pos = device->vertex_buffer_pos;
3435     align = vb_pos % stride;
3436     if (align) align = stride - align;
3437     if (vb_pos + size + align > device->vertex_buffer_size)
3438         vb_pos = 0;
3439     else
3440         vb_pos += align;
3441
3442     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, size, &data,
3443             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3444     if (FAILED(hr))
3445         goto done;
3446     memcpy(data, vertices, size);
3447     wined3d_buffer_unmap(device->vertex_buffer);
3448     device->vertex_buffer_pos = vb_pos + size;
3449
3450     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
3451     if (FAILED(hr))
3452         goto done;
3453
3454     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3455     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3456     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vertex_count);
3457
3458 done:
3459     wined3d_mutex_unlock();
3460     return hr;
3461 }
3462
3463 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3464         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3465         DWORD vertex_count, DWORD flags)
3466 {
3467     return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3468 }
3469
3470 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3471         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3472         DWORD vertex_count, DWORD flags)
3473 {
3474     HRESULT hr;
3475     WORD old_fpucw;
3476
3477     old_fpucw = d3d_fpu_setup();
3478     hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3479     set_fpu_control_word(old_fpucw);
3480
3481     return hr;
3482 }
3483
3484 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3485         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3486         DWORD flags)
3487 {
3488     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3489
3490     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3491             iface, primitive_type, fvf, vertices, vertex_count, flags);
3492
3493     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3494             primitive_type, fvf, vertices, vertex_count, flags);
3495 }
3496
3497 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3498         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3499         DWORD vertex_count, DWORD flags)
3500 {
3501     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3502     DWORD fvf;
3503
3504     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3505             iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3506
3507     switch (vertex_type)
3508     {
3509         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3510         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3511         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3512         default:
3513             FIXME("Unhandled vertex type %#x.\n", vertex_type);
3514             return DDERR_INVALIDPARAMS;  /* Should never happen */
3515     }
3516
3517     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3518             primitive_type, fvf, vertices, vertex_count, flags);
3519 }
3520
3521 /*****************************************************************************
3522  * IDirect3DDevice7::DrawIndexedPrimitive
3523  *
3524  * Draws vertices from an application-provided pointer, based on the index
3525  * numbers in a WORD array.
3526  *
3527  * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3528  * an FVF format for D3D7
3529  *
3530  * Params:
3531  *  PrimitiveType: The primitive type to draw
3532  *  VertexType: The FVF vertex description
3533  *  Vertices: Pointer to the vertex array
3534  *  VertexCount: ?
3535  *  Indices: Pointer to the index array
3536  *  IndexCount: Number of indices = Number of vertices to draw
3537  *  Flags: As usual, some flags
3538  *
3539  * Returns:
3540  *  D3D_OK on success
3541  *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3542  *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
3543  *
3544  *****************************************************************************/
3545 /* The caller is responsible for wined3d locking */
3546 static HRESULT d3d_device_prepare_index_buffer(struct d3d_device *device, UINT min_size)
3547 {
3548     HRESULT hr;
3549
3550     if (device->index_buffer_size < min_size || !device->index_buffer)
3551     {
3552         UINT size = max(device->index_buffer_size * 2, min_size);
3553         struct wined3d_buffer *buffer;
3554
3555         TRACE("Growing index buffer to %u bytes\n", size);
3556
3557         hr = wined3d_buffer_create_ib(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
3558                 WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
3559         if (FAILED(hr))
3560         {
3561             ERR("(%p) wined3d_buffer_create_ib failed with hr = %08x\n", device, hr);
3562             return hr;
3563         }
3564
3565         if (device->index_buffer)
3566             wined3d_buffer_decref(device->index_buffer);
3567         device->index_buffer = buffer;
3568         device->index_buffer_size = size;
3569         device->index_buffer_pos = 0;
3570     }
3571     return D3D_OK;
3572 }
3573
3574 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3575         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3576         WORD *indices, DWORD index_count, DWORD flags)
3577 {
3578     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3579     HRESULT hr;
3580     UINT stride = get_flexible_vertex_size(fvf);
3581     UINT vtx_size = stride * vertex_count, idx_size = index_count * sizeof(*indices);
3582     UINT vb_pos, ib_pos, align;
3583     BYTE *data;
3584
3585     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3586             "indices %p, index_count %u, flags %#x.\n",
3587             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3588
3589     /* Set the D3DDevice's FVF */
3590     wined3d_mutex_lock();
3591
3592     hr = d3d_device_prepare_vertex_buffer(device, vtx_size);
3593     if (FAILED(hr))
3594         goto done;
3595
3596     vb_pos = device->vertex_buffer_pos;
3597     align = vb_pos % stride;
3598     if (align) align = stride - align;
3599     if (vb_pos + vtx_size + align > device->vertex_buffer_size)
3600         vb_pos = 0;
3601     else
3602         vb_pos += align;
3603
3604     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, vtx_size, &data,
3605             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3606     if (FAILED(hr))
3607         goto done;
3608     memcpy(data, vertices, vtx_size);
3609     wined3d_buffer_unmap(device->vertex_buffer);
3610     device->vertex_buffer_pos = vb_pos + vtx_size;
3611
3612     hr = d3d_device_prepare_index_buffer(device, idx_size);
3613     if (FAILED(hr))
3614         goto done;
3615     ib_pos = device->index_buffer_pos;
3616     if (device->index_buffer_size - idx_size < ib_pos)
3617         ib_pos = 0;
3618
3619     hr = wined3d_buffer_map(device->index_buffer, ib_pos, idx_size, &data,
3620             ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3621     if (FAILED(hr))
3622         goto done;
3623     memcpy(data, indices, idx_size);
3624     wined3d_buffer_unmap(device->index_buffer);
3625     device->index_buffer_pos = ib_pos + idx_size;
3626
3627     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
3628     if (FAILED(hr))
3629         goto done;
3630     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer, WINED3DFMT_R16_UINT);
3631
3632     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3633     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3634     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / stride);
3635     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / sizeof(*indices), index_count);
3636
3637 done:
3638     wined3d_mutex_unlock();
3639     return hr;
3640 }
3641
3642 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3643         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3644         WORD *indices, DWORD index_count, DWORD flags)
3645 {
3646     return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3647             vertices, vertex_count, indices, index_count, flags);
3648 }
3649
3650 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3651         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3652         WORD *indices, DWORD index_count, DWORD flags)
3653 {
3654     HRESULT hr;
3655     WORD old_fpucw;
3656
3657     old_fpucw = d3d_fpu_setup();
3658     hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3659             vertices, vertex_count, indices, index_count, flags);
3660     set_fpu_control_word(old_fpucw);
3661
3662     return hr;
3663 }
3664
3665 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3666         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3667         WORD *indices, DWORD index_count, DWORD flags)
3668 {
3669     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3670
3671     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3672             "indices %p, index_count %u, flags %#x.\n",
3673             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3674
3675     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3676             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3677 }
3678
3679 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3680         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3681         DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3682 {
3683     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3684     DWORD fvf;
3685
3686     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3687             "indices %p, index_count %u, flags %#x.\n",
3688             iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3689
3690     switch (vertex_type)
3691     {
3692         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3693         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3694         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3695         default:
3696             ERR("Unhandled vertex type %#x.\n", vertex_type);
3697             return DDERR_INVALIDPARAMS;  /* Should never happen */
3698     }
3699
3700     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3701             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3702 }
3703
3704 /*****************************************************************************
3705  * IDirect3DDevice7::SetClipStatus
3706  *
3707  * Sets the clip status. This defines things as clipping conditions and
3708  * the extents of the clipping region.
3709  *
3710  * Version 2, 3 and 7
3711  *
3712  * Params:
3713  *  ClipStatus:
3714  *
3715  * Returns:
3716  *  D3D_OK because it's a stub
3717  *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3718  *
3719  *****************************************************************************/
3720 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3721 {
3722     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3723
3724     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
3725      * Perhaps this needs a new data type and an additional IWineD3DDevice method
3726      */
3727     /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
3728     return D3D_OK;
3729 }
3730
3731 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3732 {
3733     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3734
3735     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3736
3737     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3738 }
3739
3740 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3741 {
3742     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3743
3744     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3745
3746     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3747 }
3748
3749 /*****************************************************************************
3750  * IDirect3DDevice7::GetClipStatus
3751  *
3752  * Returns the clip status
3753  *
3754  * Params:
3755  *  ClipStatus: Address to write the clip status to
3756  *
3757  * Returns:
3758  *  D3D_OK because it's a stub
3759  *
3760  *****************************************************************************/
3761 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3762 {
3763     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3764
3765     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
3766     /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
3767     return D3D_OK;
3768 }
3769
3770 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3771 {
3772     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3773
3774     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3775
3776     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3777 }
3778
3779 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3780 {
3781     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3782
3783     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3784
3785     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3786 }
3787
3788 /*****************************************************************************
3789  * IDirect3DDevice::DrawPrimitiveStrided
3790  *
3791  * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3792  *
3793  * Version 3 and 7
3794  *
3795  * Params:
3796  *  PrimitiveType: The primitive type to draw
3797  *  VertexType: The FVF description of the vertices to draw (for the stride??)
3798  *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3799  *                         the vertex data locations
3800  *  VertexCount: The number of vertices to draw
3801  *  Flags: Some flags
3802  *
3803  * Returns:
3804  *  D3D_OK, because it's a stub
3805  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3806  *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
3807  *
3808  *****************************************************************************/
3809 static void pack_strided_data(BYTE *dst, DWORD count, const D3DDRAWPRIMITIVESTRIDEDDATA *src, DWORD fvf)
3810 {
3811     DWORD i, tex, offset;
3812
3813     for (i = 0; i < count; i++)
3814     {
3815         /* The contents of the strided data are determined by the fvf,
3816          * not by the members set in src. So it's valid
3817          * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3818          * not set in the fvf. */
3819         if (fvf & D3DFVF_POSITION_MASK)
3820         {
3821             offset = i * src->position.dwStride;
3822             if (fvf & D3DFVF_XYZRHW)
3823             {
3824                 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 4 * sizeof(float));
3825                 dst += 4 * sizeof(float);
3826             }
3827             else
3828             {
3829                 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 3 * sizeof(float));
3830                 dst += 3 * sizeof(float);
3831             }
3832         }
3833
3834         if (fvf & D3DFVF_NORMAL)
3835         {
3836             offset = i * src->normal.dwStride;
3837             memcpy(dst, ((BYTE *)src->normal.lpvData) + offset, 3 * sizeof(float));
3838             dst += 3 * sizeof(float);
3839         }
3840
3841         if (fvf & D3DFVF_DIFFUSE)
3842         {
3843             offset = i * src->diffuse.dwStride;
3844             memcpy(dst, ((BYTE *)src->diffuse.lpvData) + offset, sizeof(DWORD));
3845             dst += sizeof(DWORD);
3846         }
3847
3848         if (fvf & D3DFVF_SPECULAR)
3849         {
3850             offset = i * src->specular.dwStride;
3851             memcpy(dst, ((BYTE *)src->specular.lpvData) + offset, sizeof(DWORD));
3852             dst += sizeof(DWORD);
3853         }
3854
3855         for (tex = 0; tex < GET_TEXCOUNT_FROM_FVF(fvf); ++tex)
3856         {
3857             DWORD attrib_count = GET_TEXCOORD_SIZE_FROM_FVF(fvf, tex);
3858             offset = i * src->textureCoords[tex].dwStride;
3859             memcpy(dst, ((BYTE *)src->textureCoords[tex].lpvData) + offset, attrib_count * sizeof(float));
3860             dst += attrib_count * sizeof(float);
3861         }
3862     }
3863 }
3864
3865 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3866         DWORD VertexType, D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3867 {
3868     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3869     HRESULT hr;
3870     UINT dst_stride = get_flexible_vertex_size(VertexType);
3871     UINT dst_size = dst_stride * VertexCount;
3872     UINT vb_pos, align;
3873     BYTE *dst_data;
3874
3875     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3876             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3877
3878     wined3d_mutex_lock();
3879     hr = d3d_device_prepare_vertex_buffer(device, dst_size);
3880     if (FAILED(hr))
3881         goto done;
3882
3883     vb_pos = device->vertex_buffer_pos;
3884     align = vb_pos % dst_stride;
3885     if (align) align = dst_stride - align;
3886     if (vb_pos + dst_size + align > device->vertex_buffer_size)
3887         vb_pos = 0;
3888     else
3889         vb_pos += align;
3890
3891     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, dst_size, &dst_data,
3892             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3893     if (FAILED(hr))
3894         goto done;
3895     pack_strided_data(dst_data, VertexCount, D3DDrawPrimStrideData, VertexType);
3896     wined3d_buffer_unmap(device->vertex_buffer);
3897     device->vertex_buffer_pos = vb_pos + dst_size;
3898
3899     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, dst_stride);
3900     if (FAILED(hr))
3901         goto done;
3902     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, VertexType));
3903
3904     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3905     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / dst_stride, VertexCount);
3906
3907 done:
3908     wined3d_mutex_unlock();
3909     return hr;
3910 }
3911
3912 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3913         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3914         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3915 {
3916     return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3917             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3918 }
3919
3920 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3921         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3922         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3923 {
3924     HRESULT hr;
3925     WORD old_fpucw;
3926
3927     old_fpucw = d3d_fpu_setup();
3928     hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3929             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3930     set_fpu_control_word(old_fpucw);
3931
3932     return hr;
3933 }
3934
3935 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3936         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3937         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3938 {
3939     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3940
3941     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3942             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3943
3944     return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
3945             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3946 }
3947
3948 /*****************************************************************************
3949  * IDirect3DDevice7::DrawIndexedPrimitiveStrided
3950  *
3951  * Draws primitives specified by strided data locations based on indices
3952  *
3953  * Version 3 and 7
3954  *
3955  * Params:
3956  *  PrimitiveType:
3957  *
3958  * Returns:
3959  *  D3D_OK, because it's a stub
3960  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3961  *  (DDERR_INVALIDPARAMS if Indices is NULL)
3962  *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
3963  *
3964  *****************************************************************************/
3965 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
3966         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3967         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3968         WORD *Indices, DWORD IndexCount, DWORD Flags)
3969 {
3970     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3971     struct wined3d_strided_data wined3d_strided;
3972     DWORD i;
3973     HRESULT hr;
3974
3975     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3976             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3977
3978     memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3979     /* Get the strided data right. the wined3d structure is a bit bigger
3980      * Watch out: The contents of the strided data are determined by the fvf,
3981      * not by the members set in D3DDrawPrimStrideData. So it's valid
3982      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3983      * not set in the fvf. */
3984     if (VertexType & D3DFVF_POSITION_MASK)
3985     {
3986         wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
3987         wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
3988         wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3989         if (VertexType & D3DFVF_XYZRHW)
3990         {
3991             wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
3992             wined3d_strided.position_transformed = TRUE;
3993         }
3994         else
3995         {
3996             wined3d_strided.position_transformed = FALSE;
3997         }
3998     }
3999
4000     if (VertexType & D3DFVF_NORMAL)
4001     {
4002         wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
4003         wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
4004         wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
4005     }
4006
4007     if (VertexType & D3DFVF_DIFFUSE)
4008     {
4009         wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
4010         wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
4011         wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
4012     }
4013
4014     if (VertexType & D3DFVF_SPECULAR)
4015     {
4016         wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
4017         wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
4018         wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
4019     }
4020
4021     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
4022     {
4023         switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
4024         {
4025             case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
4026             case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
4027             case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
4028             case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
4029             default: ERR("Unexpected texture coordinate size %d\n",
4030                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
4031         }
4032         wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
4033         wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
4034     }
4035
4036     /* WineD3D doesn't need the FVF here */
4037     wined3d_mutex_lock();
4038     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
4039     wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
4040     hr = wined3d_device_draw_indexed_primitive_strided(device->wined3d_device,
4041             IndexCount, &wined3d_strided, VertexCount, Indices, WINED3DFMT_R16_UINT);
4042     wined3d_mutex_unlock();
4043
4044     return hr;
4045 }
4046
4047 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4048         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4049         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4050         WORD *Indices, DWORD IndexCount, DWORD Flags)
4051 {
4052     return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4053             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4054 }
4055
4056 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4057         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4058         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4059         WORD *Indices, DWORD IndexCount, DWORD Flags)
4060 {
4061     HRESULT hr;
4062     WORD old_fpucw;
4063
4064     old_fpucw = d3d_fpu_setup();
4065     hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4066             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4067     set_fpu_control_word(old_fpucw);
4068
4069     return hr;
4070 }
4071
4072 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4073         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4074         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4075         DWORD IndexCount, DWORD Flags)
4076 {
4077     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4078
4079     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4080             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4081
4082     return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
4083             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4084 }
4085
4086 /*****************************************************************************
4087  * IDirect3DDevice7::DrawPrimitiveVB
4088  *
4089  * Draws primitives from a vertex buffer to the screen.
4090  *
4091  * Version 3 and 7
4092  *
4093  * Params:
4094  *  PrimitiveType: Type of primitive to be rendered.
4095  *  D3DVertexBuf: Source Vertex Buffer
4096  *  StartVertex: Index of the first vertex from the buffer to be rendered
4097  *  NumVertices: Number of vertices to be rendered
4098  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4099  *
4100  * Return values
4101  *  D3D_OK on success
4102  *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4103  *
4104  *****************************************************************************/
4105 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4106         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4107 {
4108     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4109     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4110     HRESULT hr;
4111     DWORD stride;
4112
4113     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4114             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4115
4116     /* Sanity checks */
4117     if (!vb)
4118     {
4119         WARN("No Vertex buffer specified.\n");
4120         return DDERR_INVALIDPARAMS;
4121     }
4122     stride = get_flexible_vertex_size(vb->fvf);
4123
4124     wined3d_mutex_lock();
4125     wined3d_device_set_vertex_declaration(device->wined3d_device, vb->wineD3DVertexDeclaration);
4126     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4127     if (FAILED(hr))
4128     {
4129         WARN("Failed to set stream source, hr %#x.\n", hr);
4130         wined3d_mutex_unlock();
4131         return hr;
4132     }
4133
4134     /* Now draw the primitives */
4135     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
4136     hr = wined3d_device_draw_primitive(device->wined3d_device, StartVertex, NumVertices);
4137
4138     if (SUCCEEDED(hr))
4139         vb->read_since_last_map = TRUE;
4140
4141     wined3d_mutex_unlock();
4142
4143     return hr;
4144 }
4145
4146 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4147         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4148 {
4149     return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4150 }
4151
4152 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4153         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4154 {
4155     HRESULT hr;
4156     WORD old_fpucw;
4157
4158     old_fpucw = d3d_fpu_setup();
4159     hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4160     set_fpu_control_word(old_fpucw);
4161
4162     return hr;
4163 }
4164
4165 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4166         IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4167 {
4168     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4169     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4170
4171     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4172             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4173
4174     return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4175             PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4176 }
4177
4178 /*****************************************************************************
4179  * IDirect3DDevice7::DrawIndexedPrimitiveVB
4180  *
4181  * Draws primitives from a vertex buffer to the screen
4182  *
4183  * Params:
4184  *  PrimitiveType: Type of primitive to be rendered.
4185  *  D3DVertexBuf: Source Vertex Buffer
4186  *  StartVertex: Index of the first vertex from the buffer to be rendered
4187  *  NumVertices: Number of vertices to be rendered
4188  *  Indices: Array of DWORDs used to index into the Vertices
4189  *  IndexCount: Number of indices in Indices
4190  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4191  *
4192  * Return values
4193  *
4194  *****************************************************************************/
4195 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4196         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4197         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4198 {
4199     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4200     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4201     DWORD stride = get_flexible_vertex_size(vb->fvf);
4202     WORD *LockedIndices;
4203     HRESULT hr;
4204     UINT ib_pos;
4205
4206     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4207             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4208
4209     /* Steps:
4210      * 1) Upload the Indices to the index buffer
4211      * 2) Set the index source
4212      * 3) Set the Vertex Buffer as the Stream source
4213      * 4) Call IWineD3DDevice::DrawIndexedPrimitive
4214      */
4215
4216     wined3d_mutex_lock();
4217
4218     wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4219
4220     hr = d3d_device_prepare_index_buffer(This, IndexCount * sizeof(WORD));
4221     if (FAILED(hr))
4222     {
4223         wined3d_mutex_unlock();
4224         return hr;
4225     }
4226     ib_pos = This->index_buffer_pos;
4227
4228     if (This->index_buffer_size - IndexCount * sizeof(WORD) < ib_pos)
4229         ib_pos = 0;
4230
4231     /* Copy the index stream into the index buffer. A new IWineD3DDevice
4232      * method could be created which takes an user pointer containing the
4233      * indices or a SetData-Method for the index buffer, which overrides the
4234      * index buffer data with our pointer. */
4235     hr = wined3d_buffer_map(This->index_buffer, ib_pos, IndexCount * sizeof(WORD),
4236             (BYTE **)&LockedIndices, ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
4237     if (FAILED(hr))
4238     {
4239         ERR("Failed to map buffer, hr %#x.\n", hr);
4240         wined3d_mutex_unlock();
4241         return hr;
4242     }
4243     memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4244     wined3d_buffer_unmap(This->index_buffer);
4245     This->index_buffer_pos = ib_pos + IndexCount * sizeof(WORD);
4246
4247     /* Set the index stream */
4248     wined3d_device_set_base_vertex_index(This->wined3d_device, StartVertex);
4249     wined3d_device_set_index_buffer(This->wined3d_device, This->index_buffer, WINED3DFMT_R16_UINT);
4250
4251     /* Set the vertex stream source */
4252     hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4253     if (FAILED(hr))
4254     {
4255         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4256         wined3d_mutex_unlock();
4257         return hr;
4258     }
4259
4260
4261     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4262     hr = wined3d_device_draw_indexed_primitive(This->wined3d_device, ib_pos / sizeof(WORD), IndexCount);
4263
4264     if (SUCCEEDED(hr))
4265         vb->read_since_last_map = TRUE;
4266
4267     wined3d_mutex_unlock();
4268
4269     return hr;
4270 }
4271
4272 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4273         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4274         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4275 {
4276     return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4277             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4278 }
4279
4280 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4281         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4282         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4283 {
4284     HRESULT hr;
4285     WORD old_fpucw;
4286
4287     old_fpucw = d3d_fpu_setup();
4288     hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4289             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4290     set_fpu_control_word(old_fpucw);
4291
4292     return hr;
4293 }
4294
4295 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4296         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, WORD *Indices,
4297         DWORD IndexCount, DWORD Flags)
4298 {
4299     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4300     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4301
4302     TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4303             iface, PrimitiveType, D3DVertexBuf, Indices, IndexCount, Flags);
4304
4305     return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, PrimitiveType,
4306             &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount, Flags);
4307 }
4308
4309 /*****************************************************************************
4310  * IDirect3DDevice7::ComputeSphereVisibility
4311  *
4312  * Calculates the visibility of spheres in the current viewport. The spheres
4313  * are passed in the Centers and Radii arrays, the results are passed back
4314  * in the ReturnValues array. Return values are either completely visible,
4315  * partially visible or completely invisible.
4316  * The return value consist of a combination of D3DCLIP_* flags, or it's
4317  * 0 if the sphere is completely visible(according to the SDK, not checked)
4318  *
4319  * Version 3 and 7
4320  *
4321  * Params:
4322  *  Centers: Array containing the sphere centers
4323  *  Radii: Array containing the sphere radii
4324  *  NumSpheres: The number of centers and radii in the arrays
4325  *  Flags: Some flags
4326  *  ReturnValues: Array to write the results to
4327  *
4328  * Returns:
4329  *  D3D_OK
4330  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4331  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4332  *  is singular)
4333  *
4334  *****************************************************************************/
4335
4336 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4337 {
4338     float distance, norm;
4339
4340     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4341     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4342
4343     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4344     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4345     return 0;
4346 }
4347
4348 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4349         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4350 {
4351     D3DMATRIX m, temp;
4352     D3DVALUE origin_plane[6];
4353     D3DVECTOR vec[6];
4354     HRESULT hr;
4355     UINT i, j;
4356
4357     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4358             iface, centers, radii, sphere_count, flags, return_values);
4359
4360     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4361     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4362     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4363     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4364     multiply_matrix(&m, &temp, &m);
4365
4366     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4367     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4368     multiply_matrix(&m, &temp, &m);
4369
4370 /* Left plane */
4371     vec[0].u1.x = m._14 + m._11;
4372     vec[0].u2.y = m._24 + m._21;
4373     vec[0].u3.z = m._34 + m._31;
4374     origin_plane[0] = m._44 + m._41;
4375
4376 /* Right plane */
4377     vec[1].u1.x = m._14 - m._11;
4378     vec[1].u2.y = m._24 - m._21;
4379     vec[1].u3.z = m._34 - m._31;
4380     origin_plane[1] = m._44 - m._41;
4381
4382 /* Top plane */
4383     vec[2].u1.x = m._14 - m._12;
4384     vec[2].u2.y = m._24 - m._22;
4385     vec[2].u3.z = m._34 - m._32;
4386     origin_plane[2] = m._44 - m._42;
4387
4388 /* Bottom plane */
4389     vec[3].u1.x = m._14 + m._12;
4390     vec[3].u2.y = m._24 + m._22;
4391     vec[3].u3.z = m._34 + m._32;
4392     origin_plane[3] = m._44 + m._42;
4393
4394 /* Front plane */
4395     vec[4].u1.x = m._13;
4396     vec[4].u2.y = m._23;
4397     vec[4].u3.z = m._33;
4398     origin_plane[4] = m._43;
4399
4400 /* Back plane*/
4401     vec[5].u1.x = m._14 - m._13;
4402     vec[5].u2.y = m._24 - m._23;
4403     vec[5].u3.z = m._34 - m._33;
4404     origin_plane[5] = m._44 - m._43;
4405
4406     for (i = 0; i < sphere_count; ++i)
4407     {
4408         return_values[i] = 0;
4409         for (j = 0; j < 6; ++j)
4410             return_values[i] |= in_plane(j, vec[j], origin_plane[j], centers[i], radii[i]);
4411     }
4412
4413     return D3D_OK;
4414 }
4415
4416 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4417         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4418 {
4419     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4420
4421     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4422             iface, centers, radii, sphere_count, flags, return_values);
4423
4424     return IDirect3DDevice7_ComputeSphereVisibility(&device->IDirect3DDevice7_iface,
4425             centers, radii, sphere_count, flags, return_values);
4426 }
4427
4428 /*****************************************************************************
4429  * IDirect3DDevice7::GetTexture
4430  *
4431  * Returns the texture interface handle assigned to a texture stage.
4432  * The returned texture is AddRefed. This is taken from old ddraw,
4433  * not checked in Windows.
4434  *
4435  * Version 3 and 7
4436  *
4437  * Params:
4438  *  Stage: Texture stage to read the texture from
4439  *  Texture: Address to store the interface pointer at
4440  *
4441  * Returns:
4442  *  D3D_OK on success
4443  *  DDERR_INVALIDPARAMS if Texture is NULL
4444  *  For details, see IWineD3DDevice::GetTexture
4445  *
4446  *****************************************************************************/
4447 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4448         DWORD stage, IDirectDrawSurface7 **texture)
4449 {
4450     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4451     struct wined3d_texture *wined3d_texture;
4452     struct ddraw_surface *surface;
4453
4454     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4455
4456     if (!texture)
4457         return DDERR_INVALIDPARAMS;
4458
4459     wined3d_mutex_lock();
4460     if (!(wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
4461     {
4462         *texture = NULL;
4463         wined3d_mutex_unlock();
4464         return D3D_OK;
4465     }
4466
4467     surface = wined3d_texture_get_parent(wined3d_texture);
4468     *texture = &surface->IDirectDrawSurface7_iface;
4469     IDirectDrawSurface7_AddRef(*texture);
4470     wined3d_mutex_unlock();
4471
4472     return D3D_OK;
4473 }
4474
4475 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4476         DWORD stage, IDirectDrawSurface7 **Texture)
4477 {
4478     return d3d_device7_GetTexture(iface, stage, Texture);
4479 }
4480
4481 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4482         DWORD stage, IDirectDrawSurface7 **Texture)
4483 {
4484     HRESULT hr;
4485     WORD old_fpucw;
4486
4487     old_fpucw = d3d_fpu_setup();
4488     hr = d3d_device7_GetTexture(iface, stage, Texture);
4489     set_fpu_control_word(old_fpucw);
4490
4491     return hr;
4492 }
4493
4494 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4495 {
4496     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4497     struct ddraw_surface *ret_val_impl;
4498     HRESULT ret;
4499     IDirectDrawSurface7 *ret_val;
4500
4501     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4502
4503     ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4504
4505     ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4506     *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4507
4508     TRACE("Returning texture %p.\n", *Texture2);
4509
4510     return ret;
4511 }
4512
4513 /*****************************************************************************
4514  * IDirect3DDevice7::SetTexture
4515  *
4516  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4517  *
4518  * Version 3 and 7
4519  *
4520  * Params:
4521  *  Stage: The stage to assign the texture to
4522  *  Texture: Interface pointer to the texture surface
4523  *
4524  * Returns
4525  * D3D_OK on success
4526  * For details, see IWineD3DDevice::SetTexture
4527  *
4528  *****************************************************************************/
4529 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4530         DWORD stage, IDirectDrawSurface7 *texture)
4531 {
4532     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4533     struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4534     HRESULT hr;
4535
4536     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4537
4538     /* Texture may be NULL here */
4539     wined3d_mutex_lock();
4540     hr = wined3d_device_set_texture(device->wined3d_device,
4541             stage, surf ? surf->wined3d_texture : NULL);
4542     wined3d_mutex_unlock();
4543
4544     return hr;
4545 }
4546
4547 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4548         DWORD stage, IDirectDrawSurface7 *texture)
4549 {
4550     return d3d_device7_SetTexture(iface, stage, texture);
4551 }
4552
4553 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4554         DWORD stage, IDirectDrawSurface7 *texture)
4555 {
4556     HRESULT hr;
4557     WORD old_fpucw;
4558
4559     old_fpucw = d3d_fpu_setup();
4560     hr = d3d_device7_SetTexture(iface, stage, texture);
4561     set_fpu_control_word(old_fpucw);
4562
4563     return hr;
4564 }
4565
4566 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4567         DWORD stage, IDirect3DTexture2 *texture)
4568 {
4569     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4570     struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4571     DWORD texmapblend;
4572     HRESULT hr;
4573
4574     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4575
4576     wined3d_mutex_lock();
4577
4578     if (device->legacyTextureBlending)
4579         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4580
4581     hr = IDirect3DDevice7_SetTexture(&device->IDirect3DDevice7_iface, stage, &tex->IDirectDrawSurface7_iface);
4582
4583     if (device->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4584     {
4585         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4586            See d3d_device3_SetRenderState() for details. */
4587         struct wined3d_texture *tex = NULL;
4588         BOOL tex_alpha = FALSE;
4589         DDPIXELFORMAT ddfmt;
4590
4591         if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
4592         {
4593             struct wined3d_resource *sub_resource;
4594
4595             if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4596             {
4597                 struct wined3d_resource_desc desc;
4598
4599                 wined3d_resource_get_desc(sub_resource, &desc);
4600                 ddfmt.dwSize = sizeof(ddfmt);
4601                 PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4602                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4603             }
4604         }
4605
4606         /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4607         if (tex_alpha)
4608             wined3d_device_set_texture_stage_state(device->wined3d_device,
4609                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
4610         else
4611             wined3d_device_set_texture_stage_state(device->wined3d_device,
4612                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
4613     }
4614
4615     wined3d_mutex_unlock();
4616
4617     return hr;
4618 }
4619
4620 static const struct tss_lookup
4621 {
4622     BOOL sampler_state;
4623     enum wined3d_texture_stage_state state;
4624 }
4625 tss_lookup[] =
4626 {
4627     {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
4628     {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
4629     {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
4630     {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
4631     {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
4632     {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
4633     {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
4634     {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
4635     {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
4636     {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
4637     {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
4638     {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
4639     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 12, D3DTSS_ADDRESS */
4640     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
4641     {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
4642     {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
4643     {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
4644     {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
4645     {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
4646     {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
4647     {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
4648     {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
4649     {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
4650     {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
4651     {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4652 };
4653
4654 /*****************************************************************************
4655  * IDirect3DDevice7::GetTextureStageState
4656  *
4657  * Retrieves a state from a texture stage.
4658  *
4659  * Version 3 and 7
4660  *
4661  * Params:
4662  *  Stage: The stage to retrieve the state from
4663  *  TexStageStateType: The state type to retrieve
4664  *  State: Address to store the state's value at
4665  *
4666  * Returns:
4667  *  D3D_OK on success
4668  *  DDERR_INVALIDPARAMS if State is NULL
4669  *  For details, see IWineD3DDevice::GetTextureStageState
4670  *
4671  *****************************************************************************/
4672 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4673         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4674 {
4675     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4676     const struct tss_lookup *l;
4677
4678     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4679             iface, stage, state, value);
4680
4681     if (!value)
4682         return DDERR_INVALIDPARAMS;
4683
4684     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4685     {
4686         WARN("Invalid state %#x passed.\n", state);
4687         return DD_OK;
4688     }
4689
4690     l = &tss_lookup[state];
4691
4692     wined3d_mutex_lock();
4693
4694     if (l->sampler_state)
4695     {
4696         *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state);
4697
4698         switch (state)
4699         {
4700             /* Mipfilter is a sampler state with different values */
4701             case D3DTSS_MIPFILTER:
4702             {
4703                 switch (*value)
4704                 {
4705                     case WINED3D_TEXF_NONE:
4706                         *value = D3DTFP_NONE;
4707                         break;
4708                     case WINED3D_TEXF_POINT:
4709                         *value = D3DTFP_POINT;
4710                         break;
4711                     case WINED3D_TEXF_LINEAR:
4712                         *value = D3DTFP_LINEAR;
4713                         break;
4714                     default:
4715                         ERR("Unexpected mipfilter value %#x.\n", *value);
4716                         *value = D3DTFP_NONE;
4717                         break;
4718                 }
4719                 break;
4720             }
4721
4722             /* Magfilter has slightly different values */
4723             case D3DTSS_MAGFILTER:
4724             {
4725                 switch (*value)
4726                 {
4727                     case WINED3D_TEXF_POINT:
4728                             *value = D3DTFG_POINT;
4729                             break;
4730                     case WINED3D_TEXF_LINEAR:
4731                             *value = D3DTFG_LINEAR;
4732                             break;
4733                     case WINED3D_TEXF_ANISOTROPIC:
4734                             *value = D3DTFG_ANISOTROPIC;
4735                             break;
4736                     case WINED3D_TEXF_FLAT_CUBIC:
4737                             *value = D3DTFG_FLATCUBIC;
4738                             break;
4739                     case WINED3D_TEXF_GAUSSIAN_CUBIC:
4740                             *value = D3DTFG_GAUSSIANCUBIC;
4741                             break;
4742                     default:
4743                         ERR("Unexpected wined3d mag filter value %#x.\n", *value);
4744                         *value = D3DTFG_POINT;
4745                         break;
4746                 }
4747                 break;
4748             }
4749
4750             default:
4751                 break;
4752         }
4753     }
4754     else
4755     {
4756         *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state);
4757     }
4758
4759     wined3d_mutex_unlock();
4760
4761     return D3D_OK;
4762 }
4763
4764 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4765         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4766 {
4767     return d3d_device7_GetTextureStageState(iface, stage, state, value);
4768 }
4769
4770 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4771         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4772 {
4773     HRESULT hr;
4774     WORD old_fpucw;
4775
4776     old_fpucw = d3d_fpu_setup();
4777     hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
4778     set_fpu_control_word(old_fpucw);
4779
4780     return hr;
4781 }
4782
4783 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
4784         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4785 {
4786     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4787
4788     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4789             iface, stage, state, value);
4790
4791     return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4792 }
4793
4794 /*****************************************************************************
4795  * IDirect3DDevice7::SetTextureStageState
4796  *
4797  * Sets a texture stage state. Some stage types need to be handled specially,
4798  * because they do not exist in WineD3D and were moved to another place
4799  *
4800  * Version 3 and 7
4801  *
4802  * Params:
4803  *  Stage: The stage to modify
4804  *  TexStageStateType: The state to change
4805  *  State: The new value for the state
4806  *
4807  * Returns:
4808  *  D3D_OK on success
4809  *  For details, see IWineD3DDevice::SetTextureStageState
4810  *
4811  *****************************************************************************/
4812 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
4813         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4814 {
4815     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4816     const struct tss_lookup *l;
4817
4818     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4819             iface, stage, state, value);
4820
4821     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4822     {
4823         WARN("Invalid state %#x passed.\n", state);
4824         return DD_OK;
4825     }
4826
4827     l = &tss_lookup[state];
4828
4829     wined3d_mutex_lock();
4830
4831     if (l->sampler_state)
4832     {
4833         switch (state)
4834         {
4835             /* Mipfilter is a sampler state with different values */
4836             case D3DTSS_MIPFILTER:
4837             {
4838                 switch (value)
4839                 {
4840                     case D3DTFP_NONE:
4841                         value = WINED3D_TEXF_NONE;
4842                         break;
4843                     case D3DTFP_POINT:
4844                         value = WINED3D_TEXF_POINT;
4845                         break;
4846                     case 0: /* Unchecked */
4847                     case D3DTFP_LINEAR:
4848                         value = WINED3D_TEXF_LINEAR;
4849                         break;
4850                     default:
4851                         ERR("Unexpected mipfilter value %#x.\n", value);
4852                         value = WINED3D_TEXF_NONE;
4853                         break;
4854                 }
4855                 break;
4856             }
4857
4858             /* Magfilter has slightly different values */
4859             case D3DTSS_MAGFILTER:
4860             {
4861                 switch (value)
4862                 {
4863                     case D3DTFG_POINT:
4864                         value = WINED3D_TEXF_POINT;
4865                         break;
4866                     case D3DTFG_LINEAR:
4867                         value = WINED3D_TEXF_LINEAR;
4868                         break;
4869                     case D3DTFG_FLATCUBIC:
4870                         value = WINED3D_TEXF_FLAT_CUBIC;
4871                         break;
4872                     case D3DTFG_GAUSSIANCUBIC:
4873                         value = WINED3D_TEXF_GAUSSIAN_CUBIC;
4874                         break;
4875                     case D3DTFG_ANISOTROPIC:
4876                         value = WINED3D_TEXF_ANISOTROPIC;
4877                         break;
4878                     default:
4879                         ERR("Unexpected d3d7 mag filter value %#x.\n", value);
4880                         value = WINED3D_TEXF_POINT;
4881                         break;
4882                 }
4883                 break;
4884             }
4885
4886             case D3DTSS_ADDRESS:
4887                 wined3d_device_set_sampler_state(device->wined3d_device, stage, WINED3D_SAMP_ADDRESS_V, value);
4888                 break;
4889
4890             default:
4891                 break;
4892         }
4893
4894         wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
4895     }
4896     else
4897     {
4898         wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
4899     }
4900
4901     wined3d_mutex_unlock();
4902
4903     return D3D_OK;
4904 }
4905
4906 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4907         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4908 {
4909     return d3d_device7_SetTextureStageState(iface, stage, state, value);
4910 }
4911
4912 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4913         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4914 {
4915     HRESULT hr;
4916     WORD old_fpucw;
4917
4918     old_fpucw = d3d_fpu_setup();
4919     hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
4920     set_fpu_control_word(old_fpucw);
4921
4922     return hr;
4923 }
4924
4925 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
4926         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4927 {
4928     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4929
4930     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4931             iface, stage, state, value);
4932
4933     return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4934 }
4935
4936 /*****************************************************************************
4937  * IDirect3DDevice7::ValidateDevice
4938  *
4939  * SDK: "Reports the device's ability to render the currently set
4940  * texture-blending operations in a single pass". Whatever that means
4941  * exactly...
4942  *
4943  * Version 3 and 7
4944  *
4945  * Params:
4946  *  NumPasses: Address to write the number of necessary passes for the
4947  *             desired effect to.
4948  *
4949  * Returns:
4950  *  D3D_OK on success
4951  *  See IWineD3DDevice::ValidateDevice for more details
4952  *
4953  *****************************************************************************/
4954 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
4955 {
4956     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4957     HRESULT hr;
4958
4959     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4960
4961     wined3d_mutex_lock();
4962     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
4963     wined3d_mutex_unlock();
4964
4965     return hr;
4966 }
4967
4968 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
4969 {
4970     return d3d_device7_ValidateDevice(iface, pass_count);
4971 }
4972
4973 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
4974 {
4975     HRESULT hr;
4976     WORD old_fpucw;
4977
4978     old_fpucw = d3d_fpu_setup();
4979     hr = d3d_device7_ValidateDevice(iface, pass_count);
4980     set_fpu_control_word(old_fpucw);
4981
4982     return hr;
4983 }
4984
4985 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
4986 {
4987     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4988
4989     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4990
4991     return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
4992 }
4993
4994 /*****************************************************************************
4995  * IDirect3DDevice7::Clear
4996  *
4997  * Fills the render target, the z buffer and the stencil buffer with a
4998  * clear color / value
4999  *
5000  * Version 7 only
5001  *
5002  * Params:
5003  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
5004  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
5005  *  Flags: Some flags, as usual
5006  *  Color: Clear color for the render target
5007  *  Z: Clear value for the Z buffer
5008  *  Stencil: Clear value to store in each stencil buffer entry
5009  *
5010  * Returns:
5011  *  D3D_OK on success
5012  *  For details, see IWineD3DDevice::Clear
5013  *
5014  *****************************************************************************/
5015 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
5016         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5017 {
5018     const struct wined3d_color c =
5019     {
5020         ((color >> 16) & 0xff) / 255.0f,
5021         ((color >>  8) & 0xff) / 255.0f,
5022         (color & 0xff) / 255.0f,
5023         ((color >> 24) & 0xff) / 255.0f,
5024     };
5025     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
5026     HRESULT hr;
5027
5028     TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5029             iface, count, rects, flags, color, z, stencil);
5030
5031     wined3d_mutex_lock();
5032     hr = wined3d_device_clear(This->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5033     wined3d_mutex_unlock();
5034
5035     return hr;
5036 }
5037
5038 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
5039         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5040 {
5041     return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5042 }
5043
5044 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
5045         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5046 {
5047     HRESULT hr;
5048     WORD old_fpucw;
5049
5050     old_fpucw = d3d_fpu_setup();
5051     hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5052     set_fpu_control_word(old_fpucw);
5053
5054     return hr;
5055 }
5056
5057 /*****************************************************************************
5058  * IDirect3DDevice7::SetViewport
5059  *
5060  * Sets the current viewport.
5061  *
5062  * Version 7 only, but IDirect3DViewport uses this call for older
5063  * versions
5064  *
5065  * Params:
5066  *  Data: The new viewport to set
5067  *
5068  * Returns:
5069  *  D3D_OK on success
5070  *  DDERR_INVALIDPARAMS if Data is NULL
5071  *  For more details, see IWineDDDevice::SetViewport
5072  *
5073  *****************************************************************************/
5074 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5075 {
5076     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5077
5078     TRACE("iface %p, viewport %p.\n", iface, viewport);
5079
5080     if (!viewport)
5081         return DDERR_INVALIDPARAMS;
5082
5083     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5084     wined3d_mutex_lock();
5085     wined3d_device_set_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5086     wined3d_mutex_unlock();
5087
5088     return D3D_OK;
5089 }
5090
5091 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5092 {
5093     return d3d_device7_SetViewport(iface, viewport);
5094 }
5095
5096 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5097 {
5098     HRESULT hr;
5099     WORD old_fpucw;
5100
5101     old_fpucw = d3d_fpu_setup();
5102     hr = d3d_device7_SetViewport(iface, viewport);
5103     set_fpu_control_word(old_fpucw);
5104
5105     return hr;
5106 }
5107
5108 /*****************************************************************************
5109  * IDirect3DDevice::GetViewport
5110  *
5111  * Returns the current viewport
5112  *
5113  * Version 7
5114  *
5115  * Params:
5116  *  Data: D3D7Viewport structure to write the viewport information to
5117  *
5118  * Returns:
5119  *  D3D_OK on success
5120  *  DDERR_INVALIDPARAMS if Data is NULL
5121  *  For more details, see IWineD3DDevice::GetViewport
5122  *
5123  *****************************************************************************/
5124 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5125 {
5126     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5127
5128     TRACE("iface %p, viewport %p.\n", iface, viewport);
5129
5130     if (!viewport)
5131         return DDERR_INVALIDPARAMS;
5132
5133     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5134     wined3d_mutex_lock();
5135     wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5136     wined3d_mutex_unlock();
5137
5138     return D3D_OK;
5139 }
5140
5141 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5142 {
5143     return d3d_device7_GetViewport(iface, viewport);
5144 }
5145
5146 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5147 {
5148     HRESULT hr;
5149     WORD old_fpucw;
5150
5151     old_fpucw = d3d_fpu_setup();
5152     hr = d3d_device7_GetViewport(iface, viewport);
5153     set_fpu_control_word(old_fpucw);
5154
5155     return hr;
5156 }
5157
5158 /*****************************************************************************
5159  * IDirect3DDevice7::SetMaterial
5160  *
5161  * Sets the Material
5162  *
5163  * Version 7
5164  *
5165  * Params:
5166  *  Mat: The material to set
5167  *
5168  * Returns:
5169  *  D3D_OK on success
5170  *  DDERR_INVALIDPARAMS if Mat is NULL.
5171  *  For more details, see IWineD3DDevice::SetMaterial
5172  *
5173  *****************************************************************************/
5174 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5175 {
5176     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5177
5178     TRACE("iface %p, material %p.\n", iface, material);
5179
5180     if (!material)
5181         return DDERR_INVALIDPARAMS;
5182
5183     wined3d_mutex_lock();
5184     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5185     wined3d_device_set_material(device->wined3d_device, (struct wined3d_material *)material);
5186     wined3d_mutex_unlock();
5187
5188     return D3D_OK;
5189 }
5190
5191 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5192 {
5193     return d3d_device7_SetMaterial(iface, material);
5194 }
5195
5196 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5197 {
5198     HRESULT hr;
5199     WORD old_fpucw;
5200
5201     old_fpucw = d3d_fpu_setup();
5202     hr = d3d_device7_SetMaterial(iface, material);
5203     set_fpu_control_word(old_fpucw);
5204
5205     return hr;
5206 }
5207
5208 /*****************************************************************************
5209  * IDirect3DDevice7::GetMaterial
5210  *
5211  * Returns the current material
5212  *
5213  * Version 7
5214  *
5215  * Params:
5216  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5217  *
5218  * Returns:
5219  *  D3D_OK on success
5220  *  DDERR_INVALIDPARAMS if Mat is NULL
5221  *  For more details, see IWineD3DDevice::GetMaterial
5222  *
5223  *****************************************************************************/
5224 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5225 {
5226     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5227
5228     TRACE("iface %p, material %p.\n", iface, material);
5229
5230     wined3d_mutex_lock();
5231     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5232     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
5233     wined3d_mutex_unlock();
5234
5235     return D3D_OK;
5236 }
5237
5238 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5239 {
5240     return d3d_device7_GetMaterial(iface, material);
5241 }
5242
5243 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5244 {
5245     HRESULT hr;
5246     WORD old_fpucw;
5247
5248     old_fpucw = d3d_fpu_setup();
5249     hr = d3d_device7_GetMaterial(iface, material);
5250     set_fpu_control_word(old_fpucw);
5251
5252     return hr;
5253 }
5254
5255 /*****************************************************************************
5256  * IDirect3DDevice7::SetLight
5257  *
5258  * Assigns a light to a light index, but doesn't activate it yet.
5259  *
5260  * Version 7, IDirect3DLight uses this method for older versions
5261  *
5262  * Params:
5263  *  LightIndex: The index of the new light
5264  *  Light: A D3DLIGHT7 structure describing the light
5265  *
5266  * Returns:
5267  *  D3D_OK on success
5268  *  For more details, see IWineD3DDevice::SetLight
5269  *
5270  *****************************************************************************/
5271 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5272 {
5273     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5274     HRESULT hr;
5275
5276     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5277
5278     wined3d_mutex_lock();
5279     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5280     hr = wined3d_device_set_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5281     wined3d_mutex_unlock();
5282
5283     return hr_ddraw_from_wined3d(hr);
5284 }
5285
5286 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5287 {
5288     return d3d_device7_SetLight(iface, light_idx, light);
5289 }
5290
5291 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5292 {
5293     HRESULT hr;
5294     WORD old_fpucw;
5295
5296     old_fpucw = d3d_fpu_setup();
5297     hr = d3d_device7_SetLight(iface, light_idx, light);
5298     set_fpu_control_word(old_fpucw);
5299
5300     return hr;
5301 }
5302
5303 /*****************************************************************************
5304  * IDirect3DDevice7::GetLight
5305  *
5306  * Returns the light assigned to a light index
5307  *
5308  * Params:
5309  *  Light: Structure to write the light information to
5310  *
5311  * Returns:
5312  *  D3D_OK on success
5313  *  DDERR_INVALIDPARAMS if Light is NULL
5314  *  For details, see IWineD3DDevice::GetLight
5315  *
5316  *****************************************************************************/
5317 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5318 {
5319     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5320     HRESULT rc;
5321
5322     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5323
5324     wined3d_mutex_lock();
5325     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5326     rc =  wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5327     wined3d_mutex_unlock();
5328
5329     /* Translate the result. WineD3D returns other values than D3D7 */
5330     return hr_ddraw_from_wined3d(rc);
5331 }
5332
5333 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5334 {
5335     return d3d_device7_GetLight(iface, light_idx, light);
5336 }
5337
5338 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5339 {
5340     HRESULT hr;
5341     WORD old_fpucw;
5342
5343     old_fpucw = d3d_fpu_setup();
5344     hr = d3d_device7_GetLight(iface, light_idx, light);
5345     set_fpu_control_word(old_fpucw);
5346
5347     return hr;
5348 }
5349
5350 /*****************************************************************************
5351  * IDirect3DDevice7::BeginStateBlock
5352  *
5353  * Begins recording to a stateblock
5354  *
5355  * Version 7
5356  *
5357  * Returns:
5358  *  D3D_OK on success
5359  *  For details see IWineD3DDevice::BeginStateBlock
5360  *
5361  *****************************************************************************/
5362 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5363 {
5364     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5365     HRESULT hr;
5366
5367     TRACE("iface %p.\n", iface);
5368
5369     wined3d_mutex_lock();
5370     hr = wined3d_device_begin_stateblock(device->wined3d_device);
5371     wined3d_mutex_unlock();
5372
5373     return hr_ddraw_from_wined3d(hr);
5374 }
5375
5376 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5377 {
5378     return d3d_device7_BeginStateBlock(iface);
5379 }
5380
5381 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5382 {
5383     HRESULT hr;
5384     WORD old_fpucw;
5385
5386     old_fpucw = d3d_fpu_setup();
5387     hr = d3d_device7_BeginStateBlock(iface);
5388     set_fpu_control_word(old_fpucw);
5389
5390     return hr;
5391 }
5392
5393 /*****************************************************************************
5394  * IDirect3DDevice7::EndStateBlock
5395  *
5396  * Stops recording to a state block and returns the created stateblock
5397  * handle.
5398  *
5399  * Version 7
5400  *
5401  * Params:
5402  *  BlockHandle: Address to store the stateblock's handle to
5403  *
5404  * Returns:
5405  *  D3D_OK on success
5406  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5407  *  See IWineD3DDevice::EndStateBlock for more details
5408  *
5409  *****************************************************************************/
5410 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5411 {
5412     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5413     struct wined3d_stateblock *wined3d_sb;
5414     HRESULT hr;
5415     DWORD h;
5416
5417     TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5418
5419     if (!stateblock)
5420         return DDERR_INVALIDPARAMS;
5421
5422     wined3d_mutex_lock();
5423
5424     hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_sb);
5425     if (FAILED(hr))
5426     {
5427         WARN("Failed to end stateblock, hr %#x.\n", hr);
5428         wined3d_mutex_unlock();
5429         *stateblock = 0;
5430         return hr_ddraw_from_wined3d(hr);
5431     }
5432
5433     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5434     if (h == DDRAW_INVALID_HANDLE)
5435     {
5436         ERR("Failed to allocate a stateblock handle.\n");
5437         wined3d_stateblock_decref(wined3d_sb);
5438         wined3d_mutex_unlock();
5439         *stateblock = 0;
5440         return DDERR_OUTOFMEMORY;
5441     }
5442
5443     wined3d_mutex_unlock();
5444     *stateblock = h + 1;
5445
5446     return hr_ddraw_from_wined3d(hr);
5447 }
5448
5449 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5450 {
5451     return d3d_device7_EndStateBlock(iface, stateblock);
5452 }
5453
5454 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5455 {
5456     HRESULT hr;
5457     WORD old_fpucw;
5458
5459     old_fpucw = d3d_fpu_setup();
5460     hr = d3d_device7_EndStateBlock(iface, stateblock);
5461     set_fpu_control_word(old_fpucw);
5462
5463     return hr;
5464 }
5465
5466 /*****************************************************************************
5467  * IDirect3DDevice7::PreLoad
5468  *
5469  * Allows the app to signal that a texture will be used soon, to allow
5470  * the Direct3DDevice to load it to the video card in the meantime.
5471  *
5472  * Version 7
5473  *
5474  * Params:
5475  *  Texture: The texture to preload
5476  *
5477  * Returns:
5478  *  D3D_OK on success
5479  *  DDERR_INVALIDPARAMS if Texture is NULL
5480  *  See IWineD3DSurface::PreLoad for details
5481  *
5482  *****************************************************************************/
5483 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5484 {
5485     struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5486
5487     TRACE("iface %p, texture %p.\n", iface, texture);
5488
5489     if (!texture)
5490         return DDERR_INVALIDPARAMS;
5491
5492     wined3d_mutex_lock();
5493     wined3d_surface_preload(surface->wined3d_surface);
5494     wined3d_mutex_unlock();
5495
5496     return D3D_OK;
5497 }
5498
5499 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5500 {
5501     return d3d_device7_PreLoad(iface, texture);
5502 }
5503
5504 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5505 {
5506     HRESULT hr;
5507     WORD old_fpucw;
5508
5509     old_fpucw = d3d_fpu_setup();
5510     hr = d3d_device7_PreLoad(iface, texture);
5511     set_fpu_control_word(old_fpucw);
5512
5513     return hr;
5514 }
5515
5516 /*****************************************************************************
5517  * IDirect3DDevice7::ApplyStateBlock
5518  *
5519  * Activates the state stored in a state block handle.
5520  *
5521  * Params:
5522  *  BlockHandle: The stateblock handle to activate
5523  *
5524  * Returns:
5525  *  D3D_OK on success
5526  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5527  *
5528  *****************************************************************************/
5529 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5530 {
5531     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5532     struct wined3d_stateblock *wined3d_sb;
5533
5534     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5535
5536     wined3d_mutex_lock();
5537     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5538     if (!wined3d_sb)
5539     {
5540         WARN("Invalid stateblock handle.\n");
5541         wined3d_mutex_unlock();
5542         return D3DERR_INVALIDSTATEBLOCK;
5543     }
5544
5545     wined3d_stateblock_apply(wined3d_sb);
5546     wined3d_mutex_unlock();
5547
5548     return D3D_OK;
5549 }
5550
5551 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5552 {
5553     return d3d_device7_ApplyStateBlock(iface, stateblock);
5554 }
5555
5556 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5557 {
5558     HRESULT hr;
5559     WORD old_fpucw;
5560
5561     old_fpucw = d3d_fpu_setup();
5562     hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5563     set_fpu_control_word(old_fpucw);
5564
5565     return hr;
5566 }
5567
5568 /*****************************************************************************
5569  * IDirect3DDevice7::CaptureStateBlock
5570  *
5571  * Updates a stateblock's values to the values currently set for the device
5572  *
5573  * Version 7
5574  *
5575  * Params:
5576  *  BlockHandle: Stateblock to update
5577  *
5578  * Returns:
5579  *  D3D_OK on success
5580  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5581  *  See IWineD3DDevice::CaptureStateBlock for more details
5582  *
5583  *****************************************************************************/
5584 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5585 {
5586     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5587     struct wined3d_stateblock *wined3d_sb;
5588
5589     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5590
5591     wined3d_mutex_lock();
5592     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5593     if (!wined3d_sb)
5594     {
5595         WARN("Invalid stateblock handle.\n");
5596         wined3d_mutex_unlock();
5597         return D3DERR_INVALIDSTATEBLOCK;
5598     }
5599
5600     wined3d_stateblock_capture(wined3d_sb);
5601     wined3d_mutex_unlock();
5602
5603     return D3D_OK;
5604 }
5605
5606 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5607 {
5608     return d3d_device7_CaptureStateBlock(iface, stateblock);
5609 }
5610
5611 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5612 {
5613     HRESULT hr;
5614     WORD old_fpucw;
5615
5616     old_fpucw = d3d_fpu_setup();
5617     hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5618     set_fpu_control_word(old_fpucw);
5619
5620     return hr;
5621 }
5622
5623 /*****************************************************************************
5624  * IDirect3DDevice7::DeleteStateBlock
5625  *
5626  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5627  *
5628  * Version 7
5629  *
5630  * Params:
5631  *  BlockHandle: Stateblock handle to delete
5632  *
5633  * Returns:
5634  *  D3D_OK on success
5635  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5636  *
5637  *****************************************************************************/
5638 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5639 {
5640     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5641     struct wined3d_stateblock *wined3d_sb;
5642     ULONG ref;
5643
5644     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5645
5646     wined3d_mutex_lock();
5647
5648     wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5649     if (!wined3d_sb)
5650     {
5651         WARN("Invalid stateblock handle.\n");
5652         wined3d_mutex_unlock();
5653         return D3DERR_INVALIDSTATEBLOCK;
5654     }
5655
5656     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5657     {
5658         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5659     }
5660
5661     wined3d_mutex_unlock();
5662
5663     return D3D_OK;
5664 }
5665
5666 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5667 {
5668     return d3d_device7_DeleteStateBlock(iface, stateblock);
5669 }
5670
5671 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5672 {
5673     HRESULT hr;
5674     WORD old_fpucw;
5675
5676     old_fpucw = d3d_fpu_setup();
5677     hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5678     set_fpu_control_word(old_fpucw);
5679
5680     return hr;
5681 }
5682
5683 /*****************************************************************************
5684  * IDirect3DDevice7::CreateStateBlock
5685  *
5686  * Creates a new state block handle.
5687  *
5688  * Version 7
5689  *
5690  * Params:
5691  *  Type: The state block type
5692  *  BlockHandle: Address to write the created handle to
5693  *
5694  * Returns:
5695  *   D3D_OK on success
5696  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5697  *
5698  *****************************************************************************/
5699 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5700         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5701 {
5702     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5703     struct wined3d_stateblock *wined3d_sb;
5704     HRESULT hr;
5705     DWORD h;
5706
5707     TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5708
5709     if (!stateblock)
5710         return DDERR_INVALIDPARAMS;
5711
5712     if (type != D3DSBT_ALL
5713             && type != D3DSBT_PIXELSTATE
5714             && type != D3DSBT_VERTEXSTATE)
5715     {
5716         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5717         return DDERR_INVALIDPARAMS;
5718     }
5719
5720     wined3d_mutex_lock();
5721
5722     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5723     hr = wined3d_stateblock_create(device->wined3d_device, type, &wined3d_sb);
5724     if (FAILED(hr))
5725     {
5726         WARN("Failed to create stateblock, hr %#x.\n", hr);
5727         wined3d_mutex_unlock();
5728         return hr_ddraw_from_wined3d(hr);
5729     }
5730
5731     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5732     if (h == DDRAW_INVALID_HANDLE)
5733     {
5734         ERR("Failed to allocate stateblock handle.\n");
5735         wined3d_stateblock_decref(wined3d_sb);
5736         wined3d_mutex_unlock();
5737         return DDERR_OUTOFMEMORY;
5738     }
5739
5740     *stateblock = h + 1;
5741     wined3d_mutex_unlock();
5742
5743     return hr_ddraw_from_wined3d(hr);
5744 }
5745
5746 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5747         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5748 {
5749     return d3d_device7_CreateStateBlock(iface, type, stateblock);
5750 }
5751
5752 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5753         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5754 {
5755     HRESULT hr;
5756     WORD old_fpucw;
5757
5758     old_fpucw = d3d_fpu_setup();
5759     hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5760     set_fpu_control_word(old_fpucw);
5761
5762     return hr;
5763 }
5764
5765 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
5766 {
5767     struct ddraw_surface *src_level, *dest_level;
5768     IDirectDrawSurface7 *temp;
5769     DDSURFACEDESC2 ddsd;
5770     BOOL levelFound; /* at least one suitable sublevel in dest found */
5771
5772     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5773      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5774      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5775      */
5776     levelFound = FALSE;
5777
5778     src_level = src;
5779     dest_level = dest;
5780
5781     for (;src_level && dest_level;)
5782     {
5783         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5784             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5785         {
5786             levelFound = TRUE;
5787
5788             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5789             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5790             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5791
5792             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5793
5794             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5795         }
5796
5797         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5798         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5799         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5800
5801         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5802
5803         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5804     }
5805
5806     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5807     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5808
5809     return !dest_level && levelFound;
5810 }
5811
5812 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dest,
5813         struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
5814 {
5815     struct ddraw_surface *src_level, *dest_level;
5816     IDirectDrawSurface7 *temp;
5817     DDSURFACEDESC2 ddsd;
5818     POINT point;
5819     RECT src_rect;
5820     HRESULT hr;
5821     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
5822     DWORD ckeyflag;
5823     DDCOLORKEY ddckey;
5824
5825     /* Copy palette, if possible. */
5826     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
5827     IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
5828
5829     if (pal_src != NULL && pal != NULL)
5830     {
5831         PALETTEENTRY palent[256];
5832
5833         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
5834         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
5835     }
5836
5837     if (pal) IDirectDrawPalette_Release(pal);
5838     if (pal_src) IDirectDrawPalette_Release(pal_src);
5839
5840     /* Copy colorkeys, if present. */
5841     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
5842     {
5843         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5844
5845         if (SUCCEEDED(hr))
5846         {
5847             IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5848         }
5849     }
5850
5851     src_level = src;
5852     dest_level = dest;
5853
5854     point = *DestPoint;
5855     src_rect = *SrcRect;
5856
5857     for (;src_level && dest_level;)
5858     {
5859         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5860             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5861         {
5862             UINT src_w = src_rect.right - src_rect.left;
5863             UINT src_h = src_rect.bottom - src_rect.top;
5864             RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
5865
5866             if (FAILED(hr = wined3d_surface_blt(dest_level->wined3d_surface, &dst_rect,
5867                     src_level->wined3d_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
5868                 ERR("Blit failed, hr %#x.\n", hr);
5869
5870             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5871             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5872             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5873
5874             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5875
5876             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5877         }
5878
5879         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5880         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5881         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5882
5883         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5884
5885         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5886
5887         point.x /= 2;
5888         point.y /= 2;
5889
5890         src_rect.top /= 2;
5891         src_rect.left /= 2;
5892         src_rect.right = (src_rect.right + 1) / 2;
5893         src_rect.bottom = (src_rect.bottom + 1) / 2;
5894     }
5895
5896     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5897     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5898 }
5899
5900 /*****************************************************************************
5901  * IDirect3DDevice7::Load
5902  *
5903  * Loads a rectangular area from the source into the destination texture.
5904  * It can also copy the source to the faces of a cubic environment map
5905  *
5906  * Version 7
5907  *
5908  * Params:
5909  *  DestTex: Destination texture
5910  *  DestPoint: Point in the destination where the source image should be
5911  *             written to
5912  *  SrcTex: Source texture
5913  *  SrcRect: Source rectangle
5914  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
5915  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
5916  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
5917  *
5918  * Returns:
5919  *  D3D_OK on success
5920  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
5921  *
5922  *
5923  *****************************************************************************/
5924 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
5925         IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5926 {
5927     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5928     struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
5929     struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
5930     POINT destpoint;
5931     RECT srcrect;
5932
5933     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
5934             iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
5935
5936     if( (!src) || (!dest) )
5937         return DDERR_INVALIDPARAMS;
5938
5939     wined3d_mutex_lock();
5940
5941     if (!src_rect)
5942     {
5943         srcrect.left = srcrect.top = 0;
5944         srcrect.right = src->surface_desc.dwWidth;
5945         srcrect.bottom = src->surface_desc.dwHeight;
5946     }
5947     else
5948         srcrect = *src_rect;
5949
5950     if (!dst_pos)
5951         destpoint.x = destpoint.y = 0;
5952     else
5953         destpoint = *dst_pos;
5954
5955     /* Check bad dimensions. dst_pos is validated against src, not dest, because
5956      * destination can be a subset of mip levels, in which case actual coordinates used
5957      * for it may be divided. If any dimension of dest is larger than source, it can't be
5958      * mip level subset, so an error can be returned early.
5959      */
5960     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
5961         srcrect.right > src->surface_desc.dwWidth ||
5962         srcrect.bottom > src->surface_desc.dwHeight ||
5963         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
5964         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
5965         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
5966         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
5967     {
5968         wined3d_mutex_unlock();
5969         return DDERR_INVALIDPARAMS;
5970     }
5971
5972     /* Must be top level surfaces. */
5973     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
5974         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
5975     {
5976         wined3d_mutex_unlock();
5977         return DDERR_INVALIDPARAMS;
5978     }
5979
5980     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5981     {
5982         struct ddraw_surface *src_face, *dest_face;
5983         DWORD src_face_flag, dest_face_flag;
5984         IDirectDrawSurface7 *temp;
5985         DDSURFACEDESC2 ddsd;
5986         int i;
5987
5988         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
5989         {
5990             wined3d_mutex_unlock();
5991             return DDERR_INVALIDPARAMS;
5992         }
5993
5994         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
5995          * time it's actual surface loading. */
5996         for (i = 0; i < 2; i++)
5997         {
5998             dest_face = dest;
5999             src_face = src;
6000
6001             for (;dest_face && src_face;)
6002             {
6003                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6004                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6005
6006                 if (src_face_flag == dest_face_flag)
6007                 {
6008                     if (i == 0)
6009                     {
6010                         /* Destination mip levels must be subset of source mip levels. */
6011                         if (!is_mip_level_subset(dest_face, src_face))
6012                         {
6013                             wined3d_mutex_unlock();
6014                             return DDERR_INVALIDPARAMS;
6015                         }
6016                     }
6017                     else if (flags & dest_face_flag)
6018                     {
6019                         copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6020                     }
6021
6022                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6023                     {
6024                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6025                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6026                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6027
6028                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6029
6030                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6031                     }
6032                     else
6033                     {
6034                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6035
6036                         src_face = NULL;
6037                     }
6038                 }
6039
6040                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6041                 {
6042                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6043                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6044                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6045
6046                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6047
6048                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6049                 }
6050                 else
6051                 {
6052                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6053
6054                     dest_face = NULL;
6055                 }
6056             }
6057
6058             if (i == 0)
6059             {
6060                 /* Native returns error if src faces are not subset of dest faces. */
6061                 if (src_face)
6062                 {
6063                     wined3d_mutex_unlock();
6064                     return DDERR_INVALIDPARAMS;
6065                 }
6066             }
6067         }
6068
6069         wined3d_mutex_unlock();
6070         return D3D_OK;
6071     }
6072     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6073     {
6074         wined3d_mutex_unlock();
6075         return DDERR_INVALIDPARAMS;
6076     }
6077
6078     /* Handle non cube map textures. */
6079
6080     /* Destination mip levels must be subset of source mip levels. */
6081     if (!is_mip_level_subset(dest, src))
6082     {
6083         wined3d_mutex_unlock();
6084         return DDERR_INVALIDPARAMS;
6085     }
6086
6087     copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6088
6089     wined3d_mutex_unlock();
6090
6091     return D3D_OK;
6092 }
6093
6094 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6095         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6096 {
6097     return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6098 }
6099
6100 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6101         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6102 {
6103     HRESULT hr;
6104     WORD old_fpucw;
6105
6106     old_fpucw = d3d_fpu_setup();
6107     hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6108     set_fpu_control_word(old_fpucw);
6109
6110     return hr;
6111 }
6112
6113 /*****************************************************************************
6114  * IDirect3DDevice7::LightEnable
6115  *
6116  * Enables or disables a light
6117  *
6118  * Version 7, IDirect3DLight uses this method too.
6119  *
6120  * Params:
6121  *  LightIndex: The index of the light to enable / disable
6122  *  Enable: Enable or disable the light
6123  *
6124  * Returns:
6125  *  D3D_OK on success
6126  *  For more details, see IWineD3DDevice::SetLightEnable
6127  *
6128  *****************************************************************************/
6129 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6130 {
6131     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6132     HRESULT hr;
6133
6134     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6135
6136     wined3d_mutex_lock();
6137     hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
6138     wined3d_mutex_unlock();
6139
6140     return hr_ddraw_from_wined3d(hr);
6141 }
6142
6143 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6144 {
6145     return d3d_device7_LightEnable(iface, light_idx, enabled);
6146 }
6147
6148 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6149 {
6150     HRESULT hr;
6151     WORD old_fpucw;
6152
6153     old_fpucw = d3d_fpu_setup();
6154     hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6155     set_fpu_control_word(old_fpucw);
6156
6157     return hr;
6158 }
6159
6160 /*****************************************************************************
6161  * IDirect3DDevice7::GetLightEnable
6162  *
6163  * Retrieves if the light with the given index is enabled or not
6164  *
6165  * Version 7
6166  *
6167  * Params:
6168  *  LightIndex: Index of desired light
6169  *  Enable: Pointer to a BOOL which contains the result
6170  *
6171  * Returns:
6172  *  D3D_OK on success
6173  *  DDERR_INVALIDPARAMS if Enable is NULL
6174  *  See IWineD3DDevice::GetLightEnable for more details
6175  *
6176  *****************************************************************************/
6177 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6178 {
6179     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6180     HRESULT hr;
6181
6182     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6183
6184     if (!enabled)
6185         return DDERR_INVALIDPARAMS;
6186
6187     wined3d_mutex_lock();
6188     hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6189     wined3d_mutex_unlock();
6190
6191     return hr_ddraw_from_wined3d(hr);
6192 }
6193
6194 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6195 {
6196     return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6197 }
6198
6199 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6200 {
6201     HRESULT hr;
6202     WORD old_fpucw;
6203
6204     old_fpucw = d3d_fpu_setup();
6205     hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6206     set_fpu_control_word(old_fpucw);
6207
6208     return hr;
6209 }
6210
6211 /*****************************************************************************
6212  * IDirect3DDevice7::SetClipPlane
6213  *
6214  * Sets custom clipping plane
6215  *
6216  * Version 7
6217  *
6218  * Params:
6219  *  Index: The index of the clipping plane
6220  *  PlaneEquation: An equation defining the clipping plane
6221  *
6222  * Returns:
6223  *  D3D_OK on success
6224  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6225  *  See IWineD3DDevice::SetClipPlane for more details
6226  *
6227  *****************************************************************************/
6228 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6229 {
6230     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6231     HRESULT hr;
6232
6233     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6234
6235     if (!plane)
6236         return DDERR_INVALIDPARAMS;
6237
6238     wined3d_mutex_lock();
6239     hr = wined3d_device_set_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6240     wined3d_mutex_unlock();
6241
6242     return hr;
6243 }
6244
6245 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6246 {
6247     return d3d_device7_SetClipPlane(iface, idx, plane);
6248 }
6249
6250 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6251 {
6252     HRESULT hr;
6253     WORD old_fpucw;
6254
6255     old_fpucw = d3d_fpu_setup();
6256     hr = d3d_device7_SetClipPlane(iface, idx, plane);
6257     set_fpu_control_word(old_fpucw);
6258
6259     return hr;
6260 }
6261
6262 /*****************************************************************************
6263  * IDirect3DDevice7::GetClipPlane
6264  *
6265  * Returns the clipping plane with a specific index
6266  *
6267  * Params:
6268  *  Index: The index of the desired plane
6269  *  PlaneEquation: Address to store the plane equation to
6270  *
6271  * Returns:
6272  *  D3D_OK on success
6273  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6274  *  See IWineD3DDevice::GetClipPlane for more details
6275  *
6276  *****************************************************************************/
6277 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6278 {
6279     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6280     HRESULT hr;
6281
6282     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6283
6284     if (!plane)
6285         return DDERR_INVALIDPARAMS;
6286
6287     wined3d_mutex_lock();
6288     hr = wined3d_device_get_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6289     wined3d_mutex_unlock();
6290
6291     return hr;
6292 }
6293
6294 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6295 {
6296     return d3d_device7_GetClipPlane(iface, idx, plane);
6297 }
6298
6299 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6300 {
6301     HRESULT hr;
6302     WORD old_fpucw;
6303
6304     old_fpucw = d3d_fpu_setup();
6305     hr = d3d_device7_GetClipPlane(iface, idx, plane);
6306     set_fpu_control_word(old_fpucw);
6307
6308     return hr;
6309 }
6310
6311 /*****************************************************************************
6312  * IDirect3DDevice7::GetInfo
6313  *
6314  * Retrieves some information about the device. The DirectX sdk says that
6315  * this version returns S_FALSE for all retail builds of DirectX, that's what
6316  * this implementation does.
6317  *
6318  * Params:
6319  *  DevInfoID: Information type requested
6320  *  DevInfoStruct: Pointer to a structure to store the info to
6321  *  Size: Size of the structure
6322  *
6323  * Returns:
6324  *  S_FALSE, because it's a non-debug driver
6325  *
6326  *****************************************************************************/
6327 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6328 {
6329     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6330             iface, info_id, info, info_size);
6331
6332     if (TRACE_ON(ddraw))
6333     {
6334         TRACE(" info requested : ");
6335         switch (info_id)
6336         {
6337             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6338             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6339             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6340             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6341         }
6342     }
6343
6344     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6345 }
6346
6347 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6348  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6349  * are not duplicated.
6350
6351  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6352  * has already been setup for optimal d3d operation.
6353
6354  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6355  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6356  * by Sacrifice (game). */
6357 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6358 {
6359     /*** IUnknown Methods ***/
6360     d3d_device7_QueryInterface,
6361     d3d_device7_AddRef,
6362     d3d_device7_Release,
6363     /*** IDirect3DDevice7 ***/
6364     d3d_device7_GetCaps_FPUSetup,
6365     d3d_device7_EnumTextureFormats_FPUSetup,
6366     d3d_device7_BeginScene_FPUSetup,
6367     d3d_device7_EndScene_FPUSetup,
6368     d3d_device7_GetDirect3D,
6369     d3d_device7_SetRenderTarget_FPUSetup,
6370     d3d_device7_GetRenderTarget,
6371     d3d_device7_Clear_FPUSetup,
6372     d3d_device7_SetTransform_FPUSetup,
6373     d3d_device7_GetTransform_FPUSetup,
6374     d3d_device7_SetViewport_FPUSetup,
6375     d3d_device7_MultiplyTransform_FPUSetup,
6376     d3d_device7_GetViewport_FPUSetup,
6377     d3d_device7_SetMaterial_FPUSetup,
6378     d3d_device7_GetMaterial_FPUSetup,
6379     d3d_device7_SetLight_FPUSetup,
6380     d3d_device7_GetLight_FPUSetup,
6381     d3d_device7_SetRenderState_FPUSetup,
6382     d3d_device7_GetRenderState_FPUSetup,
6383     d3d_device7_BeginStateBlock_FPUSetup,
6384     d3d_device7_EndStateBlock_FPUSetup,
6385     d3d_device7_PreLoad_FPUSetup,
6386     d3d_device7_DrawPrimitive_FPUSetup,
6387     d3d_device7_DrawIndexedPrimitive_FPUSetup,
6388     d3d_device7_SetClipStatus,
6389     d3d_device7_GetClipStatus,
6390     d3d_device7_DrawPrimitiveStrided_FPUSetup,
6391     d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6392     d3d_device7_DrawPrimitiveVB_FPUSetup,
6393     d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6394     d3d_device7_ComputeSphereVisibility,
6395     d3d_device7_GetTexture_FPUSetup,
6396     d3d_device7_SetTexture_FPUSetup,
6397     d3d_device7_GetTextureStageState_FPUSetup,
6398     d3d_device7_SetTextureStageState_FPUSetup,
6399     d3d_device7_ValidateDevice_FPUSetup,
6400     d3d_device7_ApplyStateBlock_FPUSetup,
6401     d3d_device7_CaptureStateBlock_FPUSetup,
6402     d3d_device7_DeleteStateBlock_FPUSetup,
6403     d3d_device7_CreateStateBlock_FPUSetup,
6404     d3d_device7_Load_FPUSetup,
6405     d3d_device7_LightEnable_FPUSetup,
6406     d3d_device7_GetLightEnable_FPUSetup,
6407     d3d_device7_SetClipPlane_FPUSetup,
6408     d3d_device7_GetClipPlane_FPUSetup,
6409     d3d_device7_GetInfo
6410 };
6411
6412 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6413 {
6414     /*** IUnknown Methods ***/
6415     d3d_device7_QueryInterface,
6416     d3d_device7_AddRef,
6417     d3d_device7_Release,
6418     /*** IDirect3DDevice7 ***/
6419     d3d_device7_GetCaps_FPUPreserve,
6420     d3d_device7_EnumTextureFormats_FPUPreserve,
6421     d3d_device7_BeginScene_FPUPreserve,
6422     d3d_device7_EndScene_FPUPreserve,
6423     d3d_device7_GetDirect3D,
6424     d3d_device7_SetRenderTarget_FPUPreserve,
6425     d3d_device7_GetRenderTarget,
6426     d3d_device7_Clear_FPUPreserve,
6427     d3d_device7_SetTransform_FPUPreserve,
6428     d3d_device7_GetTransform_FPUPreserve,
6429     d3d_device7_SetViewport_FPUPreserve,
6430     d3d_device7_MultiplyTransform_FPUPreserve,
6431     d3d_device7_GetViewport_FPUPreserve,
6432     d3d_device7_SetMaterial_FPUPreserve,
6433     d3d_device7_GetMaterial_FPUPreserve,
6434     d3d_device7_SetLight_FPUPreserve,
6435     d3d_device7_GetLight_FPUPreserve,
6436     d3d_device7_SetRenderState_FPUPreserve,
6437     d3d_device7_GetRenderState_FPUPreserve,
6438     d3d_device7_BeginStateBlock_FPUPreserve,
6439     d3d_device7_EndStateBlock_FPUPreserve,
6440     d3d_device7_PreLoad_FPUPreserve,
6441     d3d_device7_DrawPrimitive_FPUPreserve,
6442     d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6443     d3d_device7_SetClipStatus,
6444     d3d_device7_GetClipStatus,
6445     d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6446     d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6447     d3d_device7_DrawPrimitiveVB_FPUPreserve,
6448     d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6449     d3d_device7_ComputeSphereVisibility,
6450     d3d_device7_GetTexture_FPUPreserve,
6451     d3d_device7_SetTexture_FPUPreserve,
6452     d3d_device7_GetTextureStageState_FPUPreserve,
6453     d3d_device7_SetTextureStageState_FPUPreserve,
6454     d3d_device7_ValidateDevice_FPUPreserve,
6455     d3d_device7_ApplyStateBlock_FPUPreserve,
6456     d3d_device7_CaptureStateBlock_FPUPreserve,
6457     d3d_device7_DeleteStateBlock_FPUPreserve,
6458     d3d_device7_CreateStateBlock_FPUPreserve,
6459     d3d_device7_Load_FPUPreserve,
6460     d3d_device7_LightEnable_FPUPreserve,
6461     d3d_device7_GetLightEnable_FPUPreserve,
6462     d3d_device7_SetClipPlane_FPUPreserve,
6463     d3d_device7_GetClipPlane_FPUPreserve,
6464     d3d_device7_GetInfo
6465 };
6466
6467 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6468 {
6469     /*** IUnknown Methods ***/
6470     d3d_device3_QueryInterface,
6471     d3d_device3_AddRef,
6472     d3d_device3_Release,
6473     /*** IDirect3DDevice3 ***/
6474     d3d_device3_GetCaps,
6475     d3d_device3_GetStats,
6476     d3d_device3_AddViewport,
6477     d3d_device3_DeleteViewport,
6478     d3d_device3_NextViewport,
6479     d3d_device3_EnumTextureFormats,
6480     d3d_device3_BeginScene,
6481     d3d_device3_EndScene,
6482     d3d_device3_GetDirect3D,
6483     d3d_device3_SetCurrentViewport,
6484     d3d_device3_GetCurrentViewport,
6485     d3d_device3_SetRenderTarget,
6486     d3d_device3_GetRenderTarget,
6487     d3d_device3_Begin,
6488     d3d_device3_BeginIndexed,
6489     d3d_device3_Vertex,
6490     d3d_device3_Index,
6491     d3d_device3_End,
6492     d3d_device3_GetRenderState,
6493     d3d_device3_SetRenderState,
6494     d3d_device3_GetLightState,
6495     d3d_device3_SetLightState,
6496     d3d_device3_SetTransform,
6497     d3d_device3_GetTransform,
6498     d3d_device3_MultiplyTransform,
6499     d3d_device3_DrawPrimitive,
6500     d3d_device3_DrawIndexedPrimitive,
6501     d3d_device3_SetClipStatus,
6502     d3d_device3_GetClipStatus,
6503     d3d_device3_DrawPrimitiveStrided,
6504     d3d_device3_DrawIndexedPrimitiveStrided,
6505     d3d_device3_DrawPrimitiveVB,
6506     d3d_device3_DrawIndexedPrimitiveVB,
6507     d3d_device3_ComputeSphereVisibility,
6508     d3d_device3_GetTexture,
6509     d3d_device3_SetTexture,
6510     d3d_device3_GetTextureStageState,
6511     d3d_device3_SetTextureStageState,
6512     d3d_device3_ValidateDevice
6513 };
6514
6515 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6516 {
6517     /*** IUnknown Methods ***/
6518     d3d_device2_QueryInterface,
6519     d3d_device2_AddRef,
6520     d3d_device2_Release,
6521     /*** IDirect3DDevice2 ***/
6522     d3d_device2_GetCaps,
6523     d3d_device2_SwapTextureHandles,
6524     d3d_device2_GetStats,
6525     d3d_device2_AddViewport,
6526     d3d_device2_DeleteViewport,
6527     d3d_device2_NextViewport,
6528     d3d_device2_EnumTextureFormats,
6529     d3d_device2_BeginScene,
6530     d3d_device2_EndScene,
6531     d3d_device2_GetDirect3D,
6532     d3d_device2_SetCurrentViewport,
6533     d3d_device2_GetCurrentViewport,
6534     d3d_device2_SetRenderTarget,
6535     d3d_device2_GetRenderTarget,
6536     d3d_device2_Begin,
6537     d3d_device2_BeginIndexed,
6538     d3d_device2_Vertex,
6539     d3d_device2_Index,
6540     d3d_device2_End,
6541     d3d_device2_GetRenderState,
6542     d3d_device2_SetRenderState,
6543     d3d_device2_GetLightState,
6544     d3d_device2_SetLightState,
6545     d3d_device2_SetTransform,
6546     d3d_device2_GetTransform,
6547     d3d_device2_MultiplyTransform,
6548     d3d_device2_DrawPrimitive,
6549     d3d_device2_DrawIndexedPrimitive,
6550     d3d_device2_SetClipStatus,
6551     d3d_device2_GetClipStatus
6552 };
6553
6554 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6555 {
6556     /*** IUnknown Methods ***/
6557     d3d_device1_QueryInterface,
6558     d3d_device1_AddRef,
6559     d3d_device1_Release,
6560     /*** IDirect3DDevice1 ***/
6561     d3d_device1_Initialize,
6562     d3d_device1_GetCaps,
6563     d3d_device1_SwapTextureHandles,
6564     d3d_device1_CreateExecuteBuffer,
6565     d3d_device1_GetStats,
6566     d3d_device1_Execute,
6567     d3d_device1_AddViewport,
6568     d3d_device1_DeleteViewport,
6569     d3d_device1_NextViewport,
6570     d3d_device1_Pick,
6571     d3d_device1_GetPickRecords,
6572     d3d_device1_EnumTextureFormats,
6573     d3d_device1_CreateMatrix,
6574     d3d_device1_SetMatrix,
6575     d3d_device1_GetMatrix,
6576     d3d_device1_DeleteMatrix,
6577     d3d_device1_BeginScene,
6578     d3d_device1_EndScene,
6579     d3d_device1_GetDirect3D
6580 };
6581
6582 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6583 {
6584     d3d_device_inner_QueryInterface,
6585     d3d_device_inner_AddRef,
6586     d3d_device_inner_Release,
6587 };
6588
6589 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6590 {
6591     if (!iface) return NULL;
6592     assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6593     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6594 }
6595
6596 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6597 {
6598     if (!iface) return NULL;
6599     assert(iface->lpVtbl == &d3d_device3_vtbl);
6600     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6601 }
6602
6603 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6604 {
6605     if (!iface) return NULL;
6606     assert(iface->lpVtbl == &d3d_device2_vtbl);
6607     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6608 }
6609
6610 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6611 {
6612     if (!iface) return NULL;
6613     assert(iface->lpVtbl == &d3d_device1_vtbl);
6614     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6615 }
6616
6617 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6618 {
6619     IDirectDrawSurface7 *depthStencil = NULL;
6620     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6621     struct ddraw_surface *dsi;
6622
6623     IDirectDrawSurface7_GetAttachedSurface(&device->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
6624     if (!depthStencil)
6625     {
6626         TRACE("Setting wined3d depth stencil to NULL\n");
6627         wined3d_device_set_depth_stencil(device->wined3d_device, NULL);
6628         return WINED3D_ZB_FALSE;
6629     }
6630
6631     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6632     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6633     wined3d_device_set_depth_stencil(device->wined3d_device, dsi->wined3d_surface);
6634
6635     IDirectDrawSurface7_Release(depthStencil);
6636     return WINED3D_ZB_TRUE;
6637 }
6638
6639 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
6640         struct ddraw_surface *target, UINT version, IUnknown *outer_unknown)
6641 {
6642     static const D3DMATRIX ident =
6643     {
6644         1.0f, 0.0f, 0.0f, 0.0f,
6645         0.0f, 1.0f, 0.0f, 0.0f,
6646         0.0f, 0.0f, 1.0f, 0.0f,
6647         0.0f, 0.0f, 0.0f, 1.0f,
6648     };
6649     HRESULT hr;
6650
6651     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6652         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6653     else
6654         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6655
6656     device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6657     device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6658     device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6659     device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6660     device->ref = 1;
6661     device->version = version;
6662
6663     if (outer_unknown)
6664         device->outer_unknown = outer_unknown;
6665     else
6666         device->outer_unknown = &device->IUnknown_inner;
6667
6668     device->ddraw = ddraw;
6669     device->target = target;
6670     list_init(&device->viewport_list);
6671
6672     if (!ddraw_handle_table_init(&device->handle_table, 64))
6673     {
6674         ERR("Failed to initialize handle table.\n");
6675         return DDERR_OUTOFMEMORY;
6676     }
6677
6678     device->legacyTextureBlending = FALSE;
6679     device->legacy_projection = ident;
6680     device->legacy_clipspace = ident;
6681
6682     /* This is for convenience. */
6683     device->wined3d_device = ddraw->wined3d_device;
6684     wined3d_device_incref(ddraw->wined3d_device);
6685
6686     /* Render to the back buffer */
6687     hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6688     if (FAILED(hr))
6689     {
6690         ERR("Failed to set render target, hr %#x.\n", hr);
6691         ddraw_handle_table_destroy(&device->handle_table);
6692         return hr;
6693     }
6694
6695     /* FIXME: This is broken. The target AddRef() makes some sense, because
6696      * we store a pointer during initialization, but then that's also where
6697      * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
6698     /* AddRef the render target. Also AddRef the render target from ddraw,
6699      * because if it is released before the app releases the D3D device, the
6700      * D3D capabilities of wined3d will be uninitialized, which has bad effects.
6701      *
6702      * In most cases, those surfaces are the same anyway, but this will simply
6703      * add another ref which is released when the device is destroyed. */
6704     if (version != 1)
6705         IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6706
6707     ddraw->d3ddevice = device;
6708
6709     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_ZENABLE,
6710             d3d_device_update_depth_stencil(device));
6711     if (version == 1) /* Color keying is initially enabled for version 1 devices. */
6712         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_COLORKEYENABLE, TRUE);
6713
6714     return D3D_OK;
6715 }
6716
6717 HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
6718         UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6719 {
6720     struct d3d_device *object;
6721     HRESULT hr;
6722
6723     TRACE("ddraw %p, target %p, version %u, device %p, outer_unknown %p.\n",
6724             ddraw, target, version, device, outer_unknown);
6725
6726     if (DefaultSurfaceType != DDRAW_SURFACE_TYPE_OPENGL)
6727     {
6728         ERR_(winediag)("The application wants to create a Direct3D device, "
6729                 "but the current DirectDrawRenderer does not support this.\n");
6730
6731         return DDERR_NO3D;
6732     }
6733
6734     if (ddraw->d3ddevice)
6735     {
6736         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
6737         return DDERR_INVALIDPARAMS;
6738     }
6739
6740     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
6741     if (!object)
6742     {
6743         ERR("Failed to allocate device memory.\n");
6744         return DDERR_OUTOFMEMORY;
6745     }
6746
6747     hr = d3d_device_init(object, ddraw, target, version, outer_unknown);
6748     if (FAILED(hr))
6749     {
6750         WARN("Failed to initialize device, hr %#x.\n", hr);
6751         HeapFree(GetProcessHeap(), 0, object);
6752         return hr;
6753     }
6754
6755     TRACE("Created device %p.\n", object);
6756     *device = object;
6757
6758     return D3D_OK;
6759 }