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