joy.cpl: Remove uneeded FIXME message.
[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             hr = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
2335             break;
2336
2337         default:
2338             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2339                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2340             {
2341                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2342                 hr = E_NOTIMPL;
2343                 break;
2344             }
2345             hr = wined3d_device_get_render_state(device->wined3d_device, state, value);
2346     }
2347     wined3d_mutex_unlock();
2348
2349     return hr;
2350 }
2351
2352 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2353         D3DRENDERSTATETYPE state, DWORD *value)
2354 {
2355     return d3d_device7_GetRenderState(iface, state, value);
2356 }
2357
2358 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2359         D3DRENDERSTATETYPE state, DWORD *value)
2360 {
2361     HRESULT hr;
2362     WORD old_fpucw;
2363
2364     old_fpucw = d3d_fpu_setup();
2365     hr = d3d_device7_GetRenderState(iface, state, value);
2366     set_fpu_control_word(old_fpucw);
2367
2368     return hr;
2369 }
2370
2371 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2372         D3DRENDERSTATETYPE state, DWORD *value)
2373 {
2374     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2375     HRESULT hr;
2376
2377     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2378
2379     switch (state)
2380     {
2381         case D3DRENDERSTATE_TEXTUREHANDLE:
2382         {
2383             /* This state is wrapped to SetTexture in SetRenderState, so
2384              * it has to be wrapped to GetTexture here. */
2385             struct wined3d_texture *tex = NULL;
2386             *value = 0;
2387
2388             wined3d_mutex_lock();
2389             hr = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
2390             if (SUCCEEDED(hr) && tex)
2391             {
2392                 /* The parent of the texture is the IDirectDrawSurface7
2393                  * interface of the ddraw surface. */
2394                 struct ddraw_surface *parent = wined3d_texture_get_parent(tex);
2395                 if (parent)
2396                     *value = parent->Handle;
2397                 wined3d_texture_decref(tex);
2398             }
2399             wined3d_mutex_unlock();
2400
2401             return hr;
2402         }
2403
2404         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2405         {
2406             /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse
2407                the mapping to get the value. */
2408             DWORD colorop, colorarg1, colorarg2;
2409             DWORD alphaop, alphaarg1, alphaarg2;
2410
2411             wined3d_mutex_lock();
2412
2413             device->legacyTextureBlending = TRUE;
2414
2415             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_OP, &colorop);
2416             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG1, &colorarg1);
2417             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG2, &colorarg2);
2418             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_OP, &alphaop);
2419             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG1, &alphaarg1);
2420             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG2, &alphaarg2);
2421
2422             if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2423                     && alphaop == WINED3D_TOP_SELECT_ARG1 && alphaarg1 == WINED3DTA_TEXTURE)
2424                 *value = D3DTBLEND_DECAL;
2425             else if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2426                     && alphaop == WINED3D_TOP_MODULATE
2427                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2428                 *value = D3DTBLEND_DECALALPHA;
2429             else if (colorop == WINED3D_TOP_MODULATE
2430                     && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2431                     && alphaop == WINED3D_TOP_MODULATE
2432                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2433                 *value = D3DTBLEND_MODULATEALPHA;
2434             else
2435             {
2436                 struct wined3d_texture *tex = NULL;
2437                 HRESULT hr;
2438                 BOOL tex_alpha = FALSE;
2439                 DDPIXELFORMAT ddfmt;
2440
2441                 hr = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
2442
2443                 if(hr == WINED3D_OK && tex)
2444                 {
2445                     struct wined3d_resource *sub_resource;
2446
2447                     if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2448                     {
2449                         struct wined3d_resource_desc desc;
2450
2451                         wined3d_resource_get_desc(sub_resource, &desc);
2452                         ddfmt.dwSize = sizeof(ddfmt);
2453                         PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2454                         if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2455                     }
2456
2457                     wined3d_texture_decref(tex);
2458                 }
2459
2460                 if (!(colorop == WINED3D_TOP_MODULATE
2461                         && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2462                         && alphaop == (tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2)
2463                         && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT))
2464                     ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous.\n");
2465
2466                 *value = D3DTBLEND_MODULATE;
2467             }
2468
2469             wined3d_mutex_unlock();
2470
2471             return D3D_OK;
2472         }
2473
2474         default:
2475             return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2476     }
2477 }
2478
2479 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2480         D3DRENDERSTATETYPE state, DWORD *value)
2481 {
2482     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2483
2484     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2485
2486     return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2487 }
2488
2489 /*****************************************************************************
2490  * IDirect3DDevice7::SetRenderState
2491  *
2492  * Sets a render state. The possible render states are defined in
2493  * include/d3dtypes.h
2494  *
2495  * Version 2, 3 and 7
2496  *
2497  * Params:
2498  *  RenderStateType: State to set
2499  *  Value: Value to assign to that state
2500  *
2501  * Returns:
2502  *  D3D_OK on success,
2503  *  for details see IWineD3DDevice::SetRenderState
2504  *
2505  *****************************************************************************/
2506 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2507         D3DRENDERSTATETYPE state, DWORD value)
2508 {
2509     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2510     HRESULT hr;
2511
2512     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2513
2514     wined3d_mutex_lock();
2515     /* Some render states need special care */
2516     switch (state)
2517     {
2518         /*
2519          * The ddraw texture filter mapping works like this:
2520          *     D3DFILTER_NEAREST            Point min/mag, no mip
2521          *     D3DFILTER_MIPNEAREST         Point min/mag, point mip
2522          *     D3DFILTER_LINEARMIPNEAREST:  Point min/mag, linear mip
2523          *
2524          *     D3DFILTER_LINEAR             Linear min/mag, no mip
2525          *     D3DFILTER_MIPLINEAR          Linear min/mag, point mip
2526          *     D3DFILTER_LINEARMIPLINEAR    Linear min/mag, linear mip
2527          *
2528          * This is the opposite of the GL naming convention,
2529          * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2530          */
2531         case D3DRENDERSTATE_TEXTUREMAG:
2532         {
2533             enum wined3d_texture_filter_type tex_mag;
2534
2535             switch (value)
2536             {
2537                 case D3DFILTER_NEAREST:
2538                 case D3DFILTER_MIPNEAREST:
2539                 case D3DFILTER_LINEARMIPNEAREST:
2540                     tex_mag = WINED3D_TEXF_POINT;
2541                     break;
2542                 case D3DFILTER_LINEAR:
2543                 case D3DFILTER_MIPLINEAR:
2544                 case D3DFILTER_LINEARMIPLINEAR:
2545                     tex_mag = WINED3D_TEXF_LINEAR;
2546                     break;
2547                 default:
2548                     tex_mag = WINED3D_TEXF_POINT;
2549                     FIXME("Unhandled texture mag %#x.\n", value);
2550                     break;
2551             }
2552
2553             hr = wined3d_device_set_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2554             break;
2555         }
2556
2557         case D3DRENDERSTATE_TEXTUREMIN:
2558         {
2559             enum wined3d_texture_filter_type tex_min;
2560             enum wined3d_texture_filter_type tex_mip;
2561
2562             switch (value)
2563             {
2564                 case D3DFILTER_NEAREST:
2565                     tex_min = WINED3D_TEXF_POINT;
2566                     tex_mip = WINED3D_TEXF_NONE;
2567                     break;
2568                 case D3DFILTER_LINEAR:
2569                     tex_min = WINED3D_TEXF_LINEAR;
2570                     tex_mip = WINED3D_TEXF_NONE;
2571                     break;
2572                 case D3DFILTER_MIPNEAREST:
2573                     tex_min = WINED3D_TEXF_POINT;
2574                     tex_mip = WINED3D_TEXF_POINT;
2575                     break;
2576                 case D3DFILTER_MIPLINEAR:
2577                     tex_min = WINED3D_TEXF_LINEAR;
2578                     tex_mip = WINED3D_TEXF_POINT;
2579                     break;
2580                 case D3DFILTER_LINEARMIPNEAREST:
2581                     tex_min = WINED3D_TEXF_POINT;
2582                     tex_mip = WINED3D_TEXF_LINEAR;
2583                     break;
2584                 case D3DFILTER_LINEARMIPLINEAR:
2585                     tex_min = WINED3D_TEXF_LINEAR;
2586                     tex_mip = WINED3D_TEXF_LINEAR;
2587                     break;
2588
2589                 default:
2590                     FIXME("Unhandled texture min %#x.\n",value);
2591                     tex_min = WINED3D_TEXF_POINT;
2592                     tex_mip = WINED3D_TEXF_NONE;
2593                     break;
2594             }
2595
2596             wined3d_device_set_sampler_state(device->wined3d_device,
2597                     0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2598             hr = wined3d_device_set_sampler_state(device->wined3d_device,
2599                     0, WINED3D_SAMP_MIN_FILTER, tex_min);
2600             break;
2601         }
2602
2603         case D3DRENDERSTATE_TEXTUREADDRESS:
2604             wined3d_device_set_sampler_state(device->wined3d_device,
2605                     0, WINED3D_SAMP_ADDRESS_V, value);
2606             /* Drop through */
2607         case D3DRENDERSTATE_TEXTUREADDRESSU:
2608             hr = wined3d_device_set_sampler_state(device->wined3d_device,
2609                     0, WINED3D_SAMP_ADDRESS_U, value);
2610             break;
2611         case D3DRENDERSTATE_TEXTUREADDRESSV:
2612             hr = wined3d_device_set_sampler_state(device->wined3d_device,
2613                     0, WINED3D_SAMP_ADDRESS_V, value);
2614             break;
2615
2616         case D3DRENDERSTATE_BORDERCOLOR:
2617             /* This should probably just forward to the corresponding sampler
2618              * state. Needs tests. */
2619             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2620             hr = E_NOTIMPL;
2621             break;
2622
2623         case D3DRENDERSTATE_TEXTUREHANDLE:
2624         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2625             WARN("Render state %#x is invalid in d3d7.\n", state);
2626             hr = DDERR_INVALIDPARAMS;
2627             break;
2628
2629         case D3DRENDERSTATE_ZBIAS:
2630             hr = wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
2631             break;
2632
2633         default:
2634             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2635                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2636             {
2637                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2638                 hr = E_NOTIMPL;
2639                 break;
2640             }
2641
2642             hr = wined3d_device_set_render_state(device->wined3d_device, state, value);
2643             break;
2644     }
2645     wined3d_mutex_unlock();
2646
2647     return hr;
2648 }
2649
2650 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2651         D3DRENDERSTATETYPE state, DWORD value)
2652 {
2653     return d3d_device7_SetRenderState(iface, state, value);
2654 }
2655
2656 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2657         D3DRENDERSTATETYPE state, DWORD value)
2658 {
2659     HRESULT hr;
2660     WORD old_fpucw;
2661
2662     old_fpucw = d3d_fpu_setup();
2663     hr = d3d_device7_SetRenderState(iface, state, value);
2664     set_fpu_control_word(old_fpucw);
2665
2666     return hr;
2667 }
2668
2669 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2670         D3DRENDERSTATETYPE state, DWORD value)
2671 {
2672     /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2673     for this state can be directly mapped to texture stage colorop and alphaop, but
2674     D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2675     from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2676     alphaarg when needed.
2677
2678     Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2679
2680     Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2681     TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2682     are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2683     requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2684     with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2685     in device - TRUE if the app is using TEXTUREMAPBLEND.
2686
2687     Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2688     GetTextureStageState and vice versa. Not so on Wine, but it is 'undefined' anyway so, probably, ok,
2689     unless some broken game will be found that cares. */
2690
2691     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2692     HRESULT hr;
2693
2694     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2695
2696     wined3d_mutex_lock();
2697
2698     switch (state)
2699     {
2700         case D3DRENDERSTATE_TEXTUREHANDLE:
2701         {
2702             struct ddraw_surface *surf;
2703
2704             if (value == 0)
2705             {
2706                 hr = wined3d_device_set_texture(device->wined3d_device, 0, NULL);
2707                 break;
2708             }
2709
2710             surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2711             if (!surf)
2712             {
2713                 WARN("Invalid texture handle.\n");
2714                 hr = DDERR_INVALIDPARAMS;
2715                 break;
2716             }
2717
2718             hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2719             break;
2720         }
2721
2722         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2723         {
2724             device->legacyTextureBlending = TRUE;
2725
2726             switch (value)
2727             {
2728                 case D3DTBLEND_MODULATE:
2729                 {
2730                     struct wined3d_texture *tex = NULL;
2731                     BOOL tex_alpha = FALSE;
2732                     DDPIXELFORMAT ddfmt;
2733
2734                     hr = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
2735
2736                     if(hr == WINED3D_OK && tex)
2737                     {
2738                         struct wined3d_resource *sub_resource;
2739
2740                         if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2741                         {
2742                             struct wined3d_resource_desc desc;
2743
2744                             wined3d_resource_get_desc(sub_resource, &desc);
2745                             ddfmt.dwSize = sizeof(ddfmt);
2746                             PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2747                             if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2748                         }
2749
2750                         wined3d_texture_decref(tex);
2751                     }
2752
2753                     if (tex_alpha)
2754                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2755                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2756                     else
2757                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2758                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2759                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2760                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2761                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2762                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2763                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2764                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2765                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2766                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2767                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2768                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2769                     break;
2770                 }
2771
2772                 case D3DTBLEND_ADD:
2773                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2774                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2775                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2776                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2777                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2778                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2779                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2780                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2781                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2782                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2783                     break;
2784
2785                 case D3DTBLEND_MODULATEALPHA:
2786                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2787                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2788                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2789                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2790                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2791                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2792                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2793                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2794                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2795                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2796                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2797                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2798                     break;
2799
2800                 case D3DTBLEND_COPY:
2801                 case D3DTBLEND_DECAL:
2802                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2803                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2804                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2805                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2806                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2807                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2808                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2809                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2810                     break;
2811
2812                 case D3DTBLEND_DECALALPHA:
2813                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2814                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2815                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2816                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2817                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2818                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2819                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2820                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2821                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2822                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2823                     break;
2824
2825                 default:
2826                     FIXME("Unhandled texture environment %#x.\n", value);
2827             }
2828
2829             hr = D3D_OK;
2830             break;
2831         }
2832
2833         default:
2834             hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2835             break;
2836     }
2837     wined3d_mutex_unlock();
2838
2839     return hr;
2840 }
2841
2842 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2843         D3DRENDERSTATETYPE state, DWORD value)
2844 {
2845     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2846
2847     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2848
2849     return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2850 }
2851
2852 /*****************************************************************************
2853  * Direct3DDevice3::SetLightState
2854  *
2855  * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2856  * light states are forwarded to Direct3DDevice7 render states
2857  *
2858  * Version 2 and 3
2859  *
2860  * Params:
2861  *  LightStateType: The light state to change
2862  *  Value: The value to assign to that light state
2863  *
2864  * Returns:
2865  *  D3D_OK on success
2866  *  DDERR_INVALIDPARAMS if the parameters were incorrect
2867  *  Also check IDirect3DDevice7::SetRenderState
2868  *
2869  *****************************************************************************/
2870 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2871         D3DLIGHTSTATETYPE state, DWORD value)
2872 {
2873     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2874     HRESULT hr;
2875
2876     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2877
2878     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2879     {
2880         TRACE("Unexpected Light State Type\n");
2881         return DDERR_INVALIDPARAMS;
2882     }
2883
2884     wined3d_mutex_lock();
2885     if (state == D3DLIGHTSTATE_MATERIAL)
2886     {
2887         struct d3d_material *m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL);
2888         if (!m)
2889         {
2890             WARN("Invalid material handle.\n");
2891             wined3d_mutex_unlock();
2892             return DDERR_INVALIDPARAMS;
2893         }
2894
2895         TRACE(" activating material %p.\n", m);
2896         material_activate(m);
2897
2898         device->material = value;
2899     }
2900     else if (state == D3DLIGHTSTATE_COLORMODEL)
2901     {
2902         switch (value)
2903         {
2904             case D3DCOLOR_MONO:
2905                 ERR("DDCOLOR_MONO should not happen!\n");
2906                 break;
2907             case D3DCOLOR_RGB:
2908                 /* We are already in this mode */
2909                 TRACE("Setting color model to RGB (no-op).\n");
2910                 break;
2911             default:
2912                 ERR("Unknown color model!\n");
2913                 wined3d_mutex_unlock();
2914                 return DDERR_INVALIDPARAMS;
2915         }
2916     }
2917     else
2918     {
2919         D3DRENDERSTATETYPE rs;
2920         switch (state)
2921         {
2922             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
2923                 rs = D3DRENDERSTATE_AMBIENT;
2924                 break;
2925             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
2926                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2927                 break;
2928             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
2929                 rs = D3DRENDERSTATE_FOGSTART;
2930                 break;
2931             case D3DLIGHTSTATE_FOGEND:        /* 6 */
2932                 rs = D3DRENDERSTATE_FOGEND;
2933                 break;
2934             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
2935                 rs = D3DRENDERSTATE_FOGDENSITY;
2936                 break;
2937             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
2938                 rs = D3DRENDERSTATE_COLORVERTEX;
2939                 break;
2940             default:
2941                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2942                 wined3d_mutex_unlock();
2943                 return DDERR_INVALIDPARAMS;
2944         }
2945
2946         hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2947         wined3d_mutex_unlock();
2948         return hr;
2949     }
2950     wined3d_mutex_unlock();
2951
2952     return D3D_OK;
2953 }
2954
2955 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
2956         D3DLIGHTSTATETYPE state, DWORD value)
2957 {
2958     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2959
2960     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2961
2962     return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2963 }
2964
2965 /*****************************************************************************
2966  * IDirect3DDevice3::GetLightState
2967  *
2968  * Returns the current setting of a light state. The state is read from
2969  * the Direct3DDevice7 render state.
2970  *
2971  * Version 2 and 3
2972  *
2973  * Params:
2974  *  LightStateType: The light state to return
2975  *  Value: The address to store the light state setting at
2976  *
2977  * Returns:
2978  *  D3D_OK on success
2979  *  DDDERR_INVALIDPARAMS if the parameters were incorrect
2980  *  Also see IDirect3DDevice7::GetRenderState
2981  *
2982  *****************************************************************************/
2983 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
2984         D3DLIGHTSTATETYPE state, DWORD *value)
2985 {
2986     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2987     HRESULT hr;
2988
2989     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2990
2991     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2992     {
2993         TRACE("Unexpected Light State Type\n");
2994         return DDERR_INVALIDPARAMS;
2995     }
2996
2997     if (!value)
2998         return DDERR_INVALIDPARAMS;
2999
3000     wined3d_mutex_lock();
3001     if (state == D3DLIGHTSTATE_MATERIAL)
3002     {
3003         *value = device->material;
3004     }
3005     else if (state == D3DLIGHTSTATE_COLORMODEL)
3006     {
3007         *value = D3DCOLOR_RGB;
3008     }
3009     else
3010     {
3011         D3DRENDERSTATETYPE rs;
3012         switch (state)
3013         {
3014             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
3015                 rs = D3DRENDERSTATE_AMBIENT;
3016                 break;
3017             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
3018                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3019                 break;
3020             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
3021                 rs = D3DRENDERSTATE_FOGSTART;
3022                 break;
3023             case D3DLIGHTSTATE_FOGEND:        /* 6 */
3024                 rs = D3DRENDERSTATE_FOGEND;
3025                 break;
3026             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
3027                 rs = D3DRENDERSTATE_FOGDENSITY;
3028                 break;
3029             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
3030                 rs = D3DRENDERSTATE_COLORVERTEX;
3031                 break;
3032             default:
3033                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3034                 wined3d_mutex_unlock();
3035                 return DDERR_INVALIDPARAMS;
3036         }
3037
3038         hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3039         wined3d_mutex_unlock();
3040         return hr;
3041     }
3042     wined3d_mutex_unlock();
3043
3044     return D3D_OK;
3045 }
3046
3047 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3048         D3DLIGHTSTATETYPE state, DWORD *value)
3049 {
3050     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3051
3052     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3053
3054     return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3055 }
3056
3057 /*****************************************************************************
3058  * IDirect3DDevice7::SetTransform
3059  *
3060  * Assigns a D3DMATRIX to a transform type. The transform types are defined
3061  * in include/d3dtypes.h.
3062  * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3063  * (=255) for wined3d, because the 1 transform state was removed in d3d8
3064  * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3065  *
3066  * Version 2, 3 and 7
3067  *
3068  * Params:
3069  *  TransformStateType: transform state to set
3070  *  Matrix: Matrix to assign to the state
3071  *
3072  * Returns:
3073  *  D3D_OK on success
3074  *  DDERR_INVALIDPARAMS if Matrix == NULL
3075  *  For details see IWineD3DDevice::SetTransform
3076  *
3077  *****************************************************************************/
3078 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3079         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3080 {
3081     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3082     enum wined3d_transform_state wined3d_state;
3083     HRESULT hr;
3084
3085     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3086
3087     switch (state)
3088     {
3089         case D3DTRANSFORMSTATE_WORLD:
3090             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3091             break;
3092         case D3DTRANSFORMSTATE_WORLD1:
3093             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3094             break;
3095         case D3DTRANSFORMSTATE_WORLD2:
3096             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3097             break;
3098         case D3DTRANSFORMSTATE_WORLD3:
3099             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3100             break;
3101         default:
3102             wined3d_state = state;
3103     }
3104
3105     if (!matrix)
3106         return DDERR_INVALIDPARAMS;
3107
3108     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3109     wined3d_mutex_lock();
3110     hr = wined3d_device_set_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3111     wined3d_mutex_unlock();
3112
3113     return hr;
3114 }
3115
3116 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3117         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3118 {
3119     return d3d_device7_SetTransform(iface, state, matrix);
3120 }
3121
3122 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3123         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3124 {
3125     HRESULT hr;
3126     WORD old_fpucw;
3127
3128     old_fpucw = d3d_fpu_setup();
3129     hr = d3d_device7_SetTransform(iface, state, matrix);
3130     set_fpu_control_word(old_fpucw);
3131
3132     return hr;
3133 }
3134
3135 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3136         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3137 {
3138     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3139
3140     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3141
3142     if (!matrix)
3143         return DDERR_INVALIDPARAMS;
3144
3145     if (state == D3DTRANSFORMSTATE_PROJECTION)
3146     {
3147         D3DMATRIX projection;
3148         HRESULT hr;
3149
3150         wined3d_mutex_lock();
3151         multiply_matrix(&projection, &device->legacy_clipspace, matrix);
3152         hr = wined3d_device_set_transform(device->wined3d_device,
3153                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3154         if (SUCCEEDED(hr))
3155             device->legacy_projection = *matrix;
3156         wined3d_mutex_unlock();
3157
3158         return hr;
3159     }
3160
3161     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3162 }
3163
3164 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3165         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3166 {
3167     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3168
3169     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3170
3171     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3172 }
3173
3174 /*****************************************************************************
3175  * IDirect3DDevice7::GetTransform
3176  *
3177  * Returns the matrix assigned to a transform state
3178  * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3179  * SetTransform
3180  *
3181  * Params:
3182  *  TransformStateType: State to read the matrix from
3183  *  Matrix: Address to store the matrix at
3184  *
3185  * Returns:
3186  *  D3D_OK on success
3187  *  DDERR_INVALIDPARAMS if Matrix == NULL
3188  *  For details, see IWineD3DDevice::GetTransform
3189  *
3190  *****************************************************************************/
3191 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3192         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3193 {
3194     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3195     enum wined3d_transform_state wined3d_state;
3196     HRESULT hr;
3197
3198     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3199
3200     switch (state)
3201     {
3202         case D3DTRANSFORMSTATE_WORLD:
3203             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3204             break;
3205         case D3DTRANSFORMSTATE_WORLD1:
3206             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3207             break;
3208         case D3DTRANSFORMSTATE_WORLD2:
3209             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3210             break;
3211         case D3DTRANSFORMSTATE_WORLD3:
3212             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3213             break;
3214         default:
3215             wined3d_state = state;
3216     }
3217
3218     if (!matrix)
3219         return DDERR_INVALIDPARAMS;
3220
3221     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3222     wined3d_mutex_lock();
3223     hr = wined3d_device_get_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3224     wined3d_mutex_unlock();
3225
3226     return hr;
3227 }
3228
3229 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3230         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3231 {
3232     return d3d_device7_GetTransform(iface, state, matrix);
3233 }
3234
3235 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3236         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3237 {
3238     HRESULT hr;
3239     WORD old_fpucw;
3240
3241     old_fpucw = d3d_fpu_setup();
3242     hr = d3d_device7_GetTransform(iface, state, matrix);
3243     set_fpu_control_word(old_fpucw);
3244
3245     return hr;
3246 }
3247
3248 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3249         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3250 {
3251     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3252
3253     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3254
3255     if (!matrix)
3256         return DDERR_INVALIDPARAMS;
3257
3258     if (state == D3DTRANSFORMSTATE_PROJECTION)
3259     {
3260         wined3d_mutex_lock();
3261         *matrix = device->legacy_projection;
3262         wined3d_mutex_unlock();
3263         return DD_OK;
3264     }
3265
3266     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3267 }
3268
3269 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3270         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3271 {
3272     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3273
3274     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3275
3276     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3277 }
3278
3279 /*****************************************************************************
3280  * IDirect3DDevice7::MultiplyTransform
3281  *
3282  * Multiplies the already-set transform matrix of a transform state
3283  * with another matrix. For the world matrix, see SetTransform
3284  *
3285  * Version 2, 3 and 7
3286  *
3287  * Params:
3288  *  TransformStateType: Transform state to multiply
3289  *  D3DMatrix Matrix to multiply with.
3290  *
3291  * Returns
3292  *  D3D_OK on success
3293  *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
3294  *  For details, see IWineD3DDevice::MultiplyTransform
3295  *
3296  *****************************************************************************/
3297 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3298         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3299 {
3300     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3301     enum wined3d_transform_state wined3d_state;
3302     HRESULT hr;
3303
3304     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3305
3306     switch (state)
3307     {
3308         case D3DTRANSFORMSTATE_WORLD:
3309             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3310             break;
3311         case D3DTRANSFORMSTATE_WORLD1:
3312             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3313             break;
3314         case D3DTRANSFORMSTATE_WORLD2:
3315             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3316             break;
3317         case D3DTRANSFORMSTATE_WORLD3:
3318             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3319             break;
3320         default:
3321             wined3d_state = state;
3322     }
3323
3324     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3325     wined3d_mutex_lock();
3326     hr = wined3d_device_multiply_transform(device->wined3d_device,
3327             wined3d_state, (struct wined3d_matrix *)matrix);
3328     wined3d_mutex_unlock();
3329
3330     return hr;
3331 }
3332
3333 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3334         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3335 {
3336     return d3d_device7_MultiplyTransform(iface, state, matrix);
3337 }
3338
3339 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3340         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3341 {
3342     HRESULT hr;
3343     WORD old_fpucw;
3344
3345     old_fpucw = d3d_fpu_setup();
3346     hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3347     set_fpu_control_word(old_fpucw);
3348
3349     return hr;
3350 }
3351
3352 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3353         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3354 {
3355     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3356
3357     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3358
3359     if (state == D3DTRANSFORMSTATE_PROJECTION)
3360     {
3361         D3DMATRIX projection, tmp;
3362         HRESULT hr;
3363
3364         wined3d_mutex_lock();
3365         multiply_matrix(&tmp, &device->legacy_projection, matrix);
3366         multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3367         hr = wined3d_device_set_transform(device->wined3d_device,
3368                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3369         if (SUCCEEDED(hr))
3370             device->legacy_projection = tmp;
3371         wined3d_mutex_unlock();
3372
3373         return hr;
3374     }
3375
3376     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3377 }
3378
3379 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3380         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3381 {
3382     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3383
3384     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3385
3386     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3387 }
3388
3389 /*****************************************************************************
3390  * IDirect3DDevice7::DrawPrimitive
3391  *
3392  * Draws primitives based on vertices in an application-provided pointer
3393  *
3394  * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3395  * an FVF format for D3D7
3396  *
3397  * Params:
3398  *  PrimitiveType: The type of the primitives to draw
3399  *  Vertex type: Flexible vertex format vertex description
3400  *  Vertices: Pointer to the vertex array
3401  *  VertexCount: The number of vertices to draw
3402  *  Flags: As usual a few flags
3403  *
3404  * Returns:
3405  *  D3D_OK on success
3406  *  DDERR_INVALIDPARAMS if Vertices is NULL
3407  *  For details, see IWineD3DDevice::DrawPrimitiveUP
3408  *
3409  *****************************************************************************/
3410 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3411         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3412         DWORD vertex_count, DWORD flags)
3413 {
3414     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3415     UINT stride;
3416     HRESULT hr;
3417
3418     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3419             iface, primitive_type, fvf, vertices, vertex_count, flags);
3420
3421     if (!vertices)
3422         return DDERR_INVALIDPARAMS;
3423
3424     /* Get the stride */
3425     stride = get_flexible_vertex_size(fvf);
3426
3427     /* Set the FVF */
3428     wined3d_mutex_lock();
3429     hr = wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3430     if (hr != D3D_OK)
3431     {
3432         wined3d_mutex_unlock();
3433         return hr;
3434     }
3435
3436     /* This method translates to the user pointer draw of WineD3D */
3437     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3438     hr = wined3d_device_draw_primitive_up(device->wined3d_device, vertex_count, vertices, stride);
3439     wined3d_mutex_unlock();
3440
3441     return hr;
3442 }
3443
3444 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3445         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3446         DWORD vertex_count, DWORD flags)
3447 {
3448     return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3449 }
3450
3451 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3452         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3453         DWORD vertex_count, DWORD flags)
3454 {
3455     HRESULT hr;
3456     WORD old_fpucw;
3457
3458     old_fpucw = d3d_fpu_setup();
3459     hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3460     set_fpu_control_word(old_fpucw);
3461
3462     return hr;
3463 }
3464
3465 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3466         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3467         DWORD flags)
3468 {
3469     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3470
3471     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3472             iface, primitive_type, fvf, vertices, vertex_count, flags);
3473
3474     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3475             primitive_type, fvf, vertices, vertex_count, flags);
3476 }
3477
3478 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3479         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3480         DWORD vertex_count, DWORD flags)
3481 {
3482     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3483     DWORD fvf;
3484
3485     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3486             iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3487
3488     switch (vertex_type)
3489     {
3490         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3491         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3492         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3493         default:
3494             FIXME("Unhandled vertex type %#x.\n", vertex_type);
3495             return DDERR_INVALIDPARAMS;  /* Should never happen */
3496     }
3497
3498     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3499             primitive_type, fvf, vertices, vertex_count, flags);
3500 }
3501
3502 /*****************************************************************************
3503  * IDirect3DDevice7::DrawIndexedPrimitive
3504  *
3505  * Draws vertices from an application-provided pointer, based on the index
3506  * numbers in a WORD array.
3507  *
3508  * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3509  * an FVF format for D3D7
3510  *
3511  * Params:
3512  *  PrimitiveType: The primitive type to draw
3513  *  VertexType: The FVF vertex description
3514  *  Vertices: Pointer to the vertex array
3515  *  VertexCount: ?
3516  *  Indices: Pointer to the index array
3517  *  IndexCount: Number of indices = Number of vertices to draw
3518  *  Flags: As usual, some flags
3519  *
3520  * Returns:
3521  *  D3D_OK on success
3522  *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3523  *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
3524  *
3525  *****************************************************************************/
3526 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3527         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3528         WORD *indices, DWORD index_count, DWORD flags)
3529 {
3530     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3531     HRESULT hr;
3532
3533     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3534             "indices %p, index_count %u, flags %#x.\n",
3535             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3536
3537     /* Set the D3DDevice's FVF */
3538     wined3d_mutex_lock();
3539     hr = wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3540     if (FAILED(hr))
3541     {
3542         WARN("Failed to set vertex declaration, hr %#x.\n", hr);
3543         wined3d_mutex_unlock();
3544         return hr;
3545     }
3546
3547     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3548     hr = wined3d_device_draw_indexed_primitive_up(device->wined3d_device, index_count, indices,
3549             WINED3DFMT_R16_UINT, vertices, get_flexible_vertex_size(fvf));
3550     wined3d_mutex_unlock();
3551
3552     return hr;
3553 }
3554
3555 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3556         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3557         WORD *indices, DWORD index_count, DWORD flags)
3558 {
3559     return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3560             vertices, vertex_count, indices, index_count, flags);
3561 }
3562
3563 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3564         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3565         WORD *indices, DWORD index_count, DWORD flags)
3566 {
3567     HRESULT hr;
3568     WORD old_fpucw;
3569
3570     old_fpucw = d3d_fpu_setup();
3571     hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3572             vertices, vertex_count, indices, index_count, flags);
3573     set_fpu_control_word(old_fpucw);
3574
3575     return hr;
3576 }
3577
3578 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3579         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3580         WORD *indices, DWORD index_count, DWORD flags)
3581 {
3582     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3583
3584     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3585             "indices %p, index_count %u, flags %#x.\n",
3586             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3587
3588     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3589             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3590 }
3591
3592 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3593         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3594         DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3595 {
3596     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3597     DWORD fvf;
3598
3599     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3600             "indices %p, index_count %u, flags %#x.\n",
3601             iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3602
3603     switch (vertex_type)
3604     {
3605         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3606         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3607         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3608         default:
3609             ERR("Unhandled vertex type %#x.\n", vertex_type);
3610             return DDERR_INVALIDPARAMS;  /* Should never happen */
3611     }
3612
3613     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3614             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3615 }
3616
3617 /*****************************************************************************
3618  * IDirect3DDevice7::SetClipStatus
3619  *
3620  * Sets the clip status. This defines things as clipping conditions and
3621  * the extents of the clipping region.
3622  *
3623  * Version 2, 3 and 7
3624  *
3625  * Params:
3626  *  ClipStatus:
3627  *
3628  * Returns:
3629  *  D3D_OK because it's a stub
3630  *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3631  *
3632  *****************************************************************************/
3633 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3634 {
3635     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3636
3637     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
3638      * Perhaps this needs a new data type and an additional IWineD3DDevice method
3639      */
3640     /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
3641     return D3D_OK;
3642 }
3643
3644 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3645 {
3646     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3647
3648     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3649
3650     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3651 }
3652
3653 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3654 {
3655     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3656
3657     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3658
3659     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3660 }
3661
3662 /*****************************************************************************
3663  * IDirect3DDevice7::GetClipStatus
3664  *
3665  * Returns the clip status
3666  *
3667  * Params:
3668  *  ClipStatus: Address to write the clip status to
3669  *
3670  * Returns:
3671  *  D3D_OK because it's a stub
3672  *
3673  *****************************************************************************/
3674 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3675 {
3676     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3677
3678     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
3679     /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
3680     return D3D_OK;
3681 }
3682
3683 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3684 {
3685     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3686
3687     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3688
3689     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3690 }
3691
3692 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3693 {
3694     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3695
3696     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3697
3698     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3699 }
3700
3701 /*****************************************************************************
3702  * IDirect3DDevice::DrawPrimitiveStrided
3703  *
3704  * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3705  *
3706  * Version 3 and 7
3707  *
3708  * Params:
3709  *  PrimitiveType: The primitive type to draw
3710  *  VertexType: The FVF description of the vertices to draw (for the stride??)
3711  *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3712  *                         the vertex data locations
3713  *  VertexCount: The number of vertices to draw
3714  *  Flags: Some flags
3715  *
3716  * Returns:
3717  *  D3D_OK, because it's a stub
3718  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3719  *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
3720  *
3721  *****************************************************************************/
3722 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3723         DWORD VertexType, D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3724 {
3725     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3726     struct wined3d_strided_data wined3d_strided;
3727     DWORD i;
3728     HRESULT hr;
3729
3730     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3731             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3732
3733     memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3734     /* Get the strided data right. the wined3d structure is a bit bigger
3735      * Watch out: The contents of the strided data are determined by the fvf,
3736      * not by the members set in D3DDrawPrimStrideData. So it's valid
3737      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3738      * not set in the fvf.
3739      */
3740     if(VertexType & D3DFVF_POSITION_MASK)
3741     {
3742         wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
3743         wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
3744         wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3745         if (VertexType & D3DFVF_XYZRHW)
3746         {
3747             wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
3748             wined3d_strided.position_transformed = TRUE;
3749         }
3750         else
3751         {
3752             wined3d_strided.position_transformed = FALSE;
3753         }
3754     }
3755
3756     if (VertexType & D3DFVF_NORMAL)
3757     {
3758         wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
3759         wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
3760         wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
3761     }
3762
3763     if (VertexType & D3DFVF_DIFFUSE)
3764     {
3765         wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
3766         wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
3767         wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
3768     }
3769
3770     if (VertexType & D3DFVF_SPECULAR)
3771     {
3772         wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
3773         wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
3774         wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
3775     }
3776
3777     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
3778     {
3779         switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3780         {
3781             case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
3782             case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
3783             case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
3784             case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3785             default: ERR("Unexpected texture coordinate size %d\n",
3786                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
3787         }
3788         wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
3789         wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3790     }
3791
3792     /* WineD3D doesn't need the FVF here */
3793     wined3d_mutex_lock();
3794     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3795     hr = wined3d_device_draw_primitive_strided(device->wined3d_device, VertexCount, &wined3d_strided);
3796     wined3d_mutex_unlock();
3797
3798     return hr;
3799 }
3800
3801 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3802         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3803         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3804 {
3805     return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3806             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3807 }
3808
3809 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3810         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3811         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3812 {
3813     HRESULT hr;
3814     WORD old_fpucw;
3815
3816     old_fpucw = d3d_fpu_setup();
3817     hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3818             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3819     set_fpu_control_word(old_fpucw);
3820
3821     return hr;
3822 }
3823
3824 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3825         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3826         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3827 {
3828     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3829
3830     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3831             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3832
3833     return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
3834             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3835 }
3836
3837 /*****************************************************************************
3838  * IDirect3DDevice7::DrawIndexedPrimitiveStrided
3839  *
3840  * Draws primitives specified by strided data locations based on indices
3841  *
3842  * Version 3 and 7
3843  *
3844  * Params:
3845  *  PrimitiveType:
3846  *
3847  * Returns:
3848  *  D3D_OK, because it's a stub
3849  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3850  *  (DDERR_INVALIDPARAMS if Indices is NULL)
3851  *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
3852  *
3853  *****************************************************************************/
3854 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
3855         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3856         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3857         WORD *Indices, DWORD IndexCount, DWORD Flags)
3858 {
3859     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3860     struct wined3d_strided_data wined3d_strided;
3861     DWORD i;
3862     HRESULT hr;
3863
3864     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3865             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3866
3867     memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3868     /* Get the strided data right. the wined3d structure is a bit bigger
3869      * Watch out: The contents of the strided data are determined by the fvf,
3870      * not by the members set in D3DDrawPrimStrideData. So it's valid
3871      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3872      * not set in the fvf. */
3873     if (VertexType & D3DFVF_POSITION_MASK)
3874     {
3875         wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
3876         wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
3877         wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3878         if (VertexType & D3DFVF_XYZRHW)
3879         {
3880             wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
3881             wined3d_strided.position_transformed = TRUE;
3882         }
3883         else
3884         {
3885             wined3d_strided.position_transformed = FALSE;
3886         }
3887     }
3888
3889     if (VertexType & D3DFVF_NORMAL)
3890     {
3891         wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
3892         wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
3893         wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
3894     }
3895
3896     if (VertexType & D3DFVF_DIFFUSE)
3897     {
3898         wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
3899         wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
3900         wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
3901     }
3902
3903     if (VertexType & D3DFVF_SPECULAR)
3904     {
3905         wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
3906         wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
3907         wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
3908     }
3909
3910     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
3911     {
3912         switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3913         {
3914             case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
3915             case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
3916             case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
3917             case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3918             default: ERR("Unexpected texture coordinate size %d\n",
3919                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
3920         }
3921         wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
3922         wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3923     }
3924
3925     /* WineD3D doesn't need the FVF here */
3926     wined3d_mutex_lock();
3927     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3928     hr = wined3d_device_draw_indexed_primitive_strided(device->wined3d_device,
3929             IndexCount, &wined3d_strided, VertexCount, Indices, WINED3DFMT_R16_UINT);
3930     wined3d_mutex_unlock();
3931
3932     return hr;
3933 }
3934
3935 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3936         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3937         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3938         WORD *Indices, DWORD IndexCount, DWORD Flags)
3939 {
3940     return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
3941             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3942 }
3943
3944 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3945         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3946         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3947         WORD *Indices, DWORD IndexCount, DWORD Flags)
3948 {
3949     HRESULT hr;
3950     WORD old_fpucw;
3951
3952     old_fpucw = d3d_fpu_setup();
3953     hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
3954             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3955     set_fpu_control_word(old_fpucw);
3956
3957     return hr;
3958 }
3959
3960 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
3961         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3962         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
3963         DWORD IndexCount, DWORD Flags)
3964 {
3965     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3966
3967     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3968             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3969
3970     return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
3971             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3972 }
3973
3974 /*****************************************************************************
3975  * IDirect3DDevice7::DrawPrimitiveVB
3976  *
3977  * Draws primitives from a vertex buffer to the screen.
3978  *
3979  * Version 3 and 7
3980  *
3981  * Params:
3982  *  PrimitiveType: Type of primitive to be rendered.
3983  *  D3DVertexBuf: Source Vertex Buffer
3984  *  StartVertex: Index of the first vertex from the buffer to be rendered
3985  *  NumVertices: Number of vertices to be rendered
3986  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
3987  *
3988  * Return values
3989  *  D3D_OK on success
3990  *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
3991  *
3992  *****************************************************************************/
3993 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3994         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
3995 {
3996     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3997     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
3998     HRESULT hr;
3999     DWORD stride;
4000
4001     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4002             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4003
4004     /* Sanity checks */
4005     if (!vb)
4006     {
4007         WARN("No Vertex buffer specified.\n");
4008         return DDERR_INVALIDPARAMS;
4009     }
4010     stride = get_flexible_vertex_size(vb->fvf);
4011
4012     wined3d_mutex_lock();
4013     hr = wined3d_device_set_vertex_declaration(device->wined3d_device, vb->wineD3DVertexDeclaration);
4014     if (FAILED(hr))
4015     {
4016         WARN("Failed to set vertex declaration, hr %#x.\n", hr);
4017         wined3d_mutex_unlock();
4018         return hr;
4019     }
4020
4021     /* Set the vertex stream source */
4022     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4023     if (FAILED(hr))
4024     {
4025         WARN("Failed to set stream source, hr %#x.\n", hr);
4026         wined3d_mutex_unlock();
4027         return hr;
4028     }
4029
4030     /* Now draw the primitives */
4031     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
4032     hr = wined3d_device_draw_primitive(device->wined3d_device, StartVertex, NumVertices);
4033     wined3d_mutex_unlock();
4034
4035     return hr;
4036 }
4037
4038 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4039         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4040 {
4041     return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4042 }
4043
4044 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4045         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4046 {
4047     HRESULT hr;
4048     WORD old_fpucw;
4049
4050     old_fpucw = d3d_fpu_setup();
4051     hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4052     set_fpu_control_word(old_fpucw);
4053
4054     return hr;
4055 }
4056
4057 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4058         IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4059 {
4060     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4061     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4062
4063     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4064             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4065
4066     return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4067             PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4068 }
4069
4070
4071 /*****************************************************************************
4072  * IDirect3DDevice7::DrawIndexedPrimitiveVB
4073  *
4074  * Draws primitives from a vertex buffer to the screen
4075  *
4076  * Params:
4077  *  PrimitiveType: Type of primitive to be rendered.
4078  *  D3DVertexBuf: Source Vertex Buffer
4079  *  StartVertex: Index of the first vertex from the buffer to be rendered
4080  *  NumVertices: Number of vertices to be rendered
4081  *  Indices: Array of DWORDs used to index into the Vertices
4082  *  IndexCount: Number of indices in Indices
4083  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4084  *
4085  * Return values
4086  *
4087  *****************************************************************************/
4088 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4089         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4090         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4091 {
4092     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4093     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4094     DWORD stride = get_flexible_vertex_size(vb->fvf);
4095     struct wined3d_resource *wined3d_resource;
4096     struct wined3d_resource_desc desc;
4097     WORD *LockedIndices;
4098     HRESULT hr;
4099
4100     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4101             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4102
4103     /* Steps:
4104      * 1) Upload the Indices to the index buffer
4105      * 2) Set the index source
4106      * 3) Set the Vertex Buffer as the Stream source
4107      * 4) Call IWineD3DDevice::DrawIndexedPrimitive
4108      */
4109
4110     wined3d_mutex_lock();
4111
4112     hr = wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4113     if (FAILED(hr))
4114     {
4115         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
4116         wined3d_mutex_unlock();
4117         return hr;
4118     }
4119
4120     /* check that the buffer is large enough to hold the indices,
4121      * reallocate if necessary. */
4122     wined3d_resource = wined3d_buffer_get_resource(This->indexbuffer);
4123     wined3d_resource_get_desc(wined3d_resource, &desc);
4124     if (desc.size < IndexCount * sizeof(WORD))
4125     {
4126         UINT size = max(desc.size * 2, IndexCount * sizeof(WORD));
4127         struct wined3d_buffer *buffer;
4128
4129         TRACE("Growing index buffer to %u bytes\n", size);
4130
4131         hr = wined3d_buffer_create_ib(This->wined3d_device, size, WINED3DUSAGE_DYNAMIC /* Usage */,
4132                 WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
4133         if (FAILED(hr))
4134         {
4135             ERR("(%p) IWineD3DDevice::CreateIndexBuffer failed with hr = %08x\n", This, hr);
4136             wined3d_mutex_unlock();
4137             return hr;
4138         }
4139
4140         wined3d_buffer_decref(This->indexbuffer);
4141         This->indexbuffer = buffer;
4142     }
4143
4144     /* Copy the index stream into the index buffer. A new IWineD3DDevice
4145      * method could be created which takes an user pointer containing the
4146      * indices or a SetData-Method for the index buffer, which overrides the
4147      * index buffer data with our pointer. */
4148     hr = wined3d_buffer_map(This->indexbuffer, 0, IndexCount * sizeof(WORD),
4149             (BYTE **)&LockedIndices, 0);
4150     if (FAILED(hr))
4151     {
4152         ERR("Failed to map buffer, hr %#x.\n", hr);
4153         wined3d_mutex_unlock();
4154         return hr;
4155     }
4156     memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4157     wined3d_buffer_unmap(This->indexbuffer);
4158
4159     /* Set the index stream */
4160     wined3d_device_set_base_vertex_index(This->wined3d_device, StartVertex);
4161     hr = wined3d_device_set_index_buffer(This->wined3d_device, This->indexbuffer, WINED3DFMT_R16_UINT);
4162
4163     /* Set the vertex stream source */
4164     hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4165     if (FAILED(hr))
4166     {
4167         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4168         wined3d_mutex_unlock();
4169         return hr;
4170     }
4171
4172
4173     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4174     hr = wined3d_device_draw_indexed_primitive(This->wined3d_device, 0, IndexCount);
4175
4176     wined3d_mutex_unlock();
4177
4178     return hr;
4179 }
4180
4181 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4182         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4183         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4184 {
4185     return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4186             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4187 }
4188
4189 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4190         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4191         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4192 {
4193     HRESULT hr;
4194     WORD old_fpucw;
4195
4196     old_fpucw = d3d_fpu_setup();
4197     hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4198             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4199     set_fpu_control_word(old_fpucw);
4200
4201     return hr;
4202 }
4203
4204 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4205         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, WORD *Indices,
4206         DWORD IndexCount, DWORD Flags)
4207 {
4208     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4209     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4210
4211     TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4212             iface, PrimitiveType, D3DVertexBuf, Indices, IndexCount, Flags);
4213
4214     return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, PrimitiveType,
4215             &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount, Flags);
4216 }
4217
4218 /*****************************************************************************
4219  * IDirect3DDevice7::ComputeSphereVisibility
4220  *
4221  * Calculates the visibility of spheres in the current viewport. The spheres
4222  * are passed in the Centers and Radii arrays, the results are passed back
4223  * in the ReturnValues array. Return values are either completely visible,
4224  * partially visible or completely invisible.
4225  * The return value consist of a combination of D3DCLIP_* flags, or it's
4226  * 0 if the sphere is completely visible(according to the SDK, not checked)
4227  *
4228  * Version 3 and 7
4229  *
4230  * Params:
4231  *  Centers: Array containing the sphere centers
4232  *  Radii: Array containing the sphere radii
4233  *  NumSpheres: The number of centers and radii in the arrays
4234  *  Flags: Some flags
4235  *  ReturnValues: Array to write the results to
4236  *
4237  * Returns:
4238  *  D3D_OK
4239  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4240  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4241  *  is singular)
4242  *
4243  *****************************************************************************/
4244
4245 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4246 {
4247     float distance, norm;
4248
4249     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4250     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4251
4252     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4253     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4254     return 0;
4255 }
4256
4257 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4258         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4259 {
4260     D3DMATRIX m, temp;
4261     D3DVALUE origin_plane[6];
4262     D3DVECTOR vec[6];
4263     HRESULT hr;
4264     UINT i, j;
4265
4266     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4267             iface, centers, radii, sphere_count, flags, return_values);
4268
4269     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4270     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4271     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4272     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4273     multiply_matrix(&m, &temp, &m);
4274
4275     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4276     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4277     multiply_matrix(&m, &temp, &m);
4278
4279 /* Left plane */
4280     vec[0].u1.x = m._14 + m._11;
4281     vec[0].u2.y = m._24 + m._21;
4282     vec[0].u3.z = m._34 + m._31;
4283     origin_plane[0] = m._44 + m._41;
4284
4285 /* Right plane */
4286     vec[1].u1.x = m._14 - m._11;
4287     vec[1].u2.y = m._24 - m._21;
4288     vec[1].u3.z = m._34 - m._31;
4289     origin_plane[1] = m._44 - m._41;
4290
4291 /* Top plane */
4292     vec[2].u1.x = m._14 - m._12;
4293     vec[2].u2.y = m._24 - m._22;
4294     vec[2].u3.z = m._34 - m._32;
4295     origin_plane[2] = m._44 - m._42;
4296
4297 /* Bottom plane */
4298     vec[3].u1.x = m._14 + m._12;
4299     vec[3].u2.y = m._24 + m._22;
4300     vec[3].u3.z = m._34 + m._32;
4301     origin_plane[3] = m._44 + m._42;
4302
4303 /* Front plane */
4304     vec[4].u1.x = m._13;
4305     vec[4].u2.y = m._23;
4306     vec[4].u3.z = m._33;
4307     origin_plane[4] = m._43;
4308
4309 /* Back plane*/
4310     vec[5].u1.x = m._14 - m._13;
4311     vec[5].u2.y = m._24 - m._23;
4312     vec[5].u3.z = m._34 - m._33;
4313     origin_plane[5] = m._44 - m._43;
4314
4315     for (i = 0; i < sphere_count; ++i)
4316     {
4317         return_values[i] = 0;
4318         for (j = 0; j < 6; ++j)
4319             return_values[i] |= in_plane(j, vec[j], origin_plane[j], centers[i], radii[i]);
4320     }
4321
4322     return D3D_OK;
4323 }
4324
4325 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4326         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4327 {
4328     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4329
4330     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4331             iface, centers, radii, sphere_count, flags, return_values);
4332
4333     return IDirect3DDevice7_ComputeSphereVisibility(&device->IDirect3DDevice7_iface,
4334             centers, radii, sphere_count, flags, return_values);
4335 }
4336
4337 /*****************************************************************************
4338  * IDirect3DDevice7::GetTexture
4339  *
4340  * Returns the texture interface handle assigned to a texture stage.
4341  * The returned texture is AddRefed. This is taken from old ddraw,
4342  * not checked in Windows.
4343  *
4344  * Version 3 and 7
4345  *
4346  * Params:
4347  *  Stage: Texture stage to read the texture from
4348  *  Texture: Address to store the interface pointer at
4349  *
4350  * Returns:
4351  *  D3D_OK on success
4352  *  DDERR_INVALIDPARAMS if Texture is NULL
4353  *  For details, see IWineD3DDevice::GetTexture
4354  *
4355  *****************************************************************************/
4356 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4357         DWORD stage, IDirectDrawSurface7 **texture)
4358 {
4359     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4360     struct wined3d_texture *wined3d_texture;
4361     struct ddraw_surface *surface;
4362     HRESULT hr;
4363
4364     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4365
4366     if (!texture)
4367         return DDERR_INVALIDPARAMS;
4368
4369     wined3d_mutex_lock();
4370     hr = wined3d_device_get_texture(device->wined3d_device, stage, &wined3d_texture);
4371     if (FAILED(hr) || !wined3d_texture)
4372     {
4373         *texture = NULL;
4374         wined3d_mutex_unlock();
4375         return hr;
4376     }
4377
4378     surface = wined3d_texture_get_parent(wined3d_texture);
4379     *texture = &surface->IDirectDrawSurface7_iface;
4380     IDirectDrawSurface7_AddRef(*texture);
4381     wined3d_texture_decref(wined3d_texture);
4382     wined3d_mutex_unlock();
4383
4384     return hr;
4385 }
4386
4387 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4388         DWORD stage, IDirectDrawSurface7 **Texture)
4389 {
4390     return d3d_device7_GetTexture(iface, stage, Texture);
4391 }
4392
4393 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4394         DWORD stage, IDirectDrawSurface7 **Texture)
4395 {
4396     HRESULT hr;
4397     WORD old_fpucw;
4398
4399     old_fpucw = d3d_fpu_setup();
4400     hr = d3d_device7_GetTexture(iface, stage, Texture);
4401     set_fpu_control_word(old_fpucw);
4402
4403     return hr;
4404 }
4405
4406 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4407 {
4408     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4409     struct ddraw_surface *ret_val_impl;
4410     HRESULT ret;
4411     IDirectDrawSurface7 *ret_val;
4412
4413     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4414
4415     ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4416
4417     ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4418     *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4419
4420     TRACE("Returning texture %p.\n", *Texture2);
4421
4422     return ret;
4423 }
4424
4425 /*****************************************************************************
4426  * IDirect3DDevice7::SetTexture
4427  *
4428  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4429  *
4430  * Version 3 and 7
4431  *
4432  * Params:
4433  *  Stage: The stage to assign the texture to
4434  *  Texture: Interface pointer to the texture surface
4435  *
4436  * Returns
4437  * D3D_OK on success
4438  * For details, see IWineD3DDevice::SetTexture
4439  *
4440  *****************************************************************************/
4441 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4442         DWORD stage, IDirectDrawSurface7 *texture)
4443 {
4444     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4445     struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4446     HRESULT hr;
4447
4448     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4449
4450     /* Texture may be NULL here */
4451     wined3d_mutex_lock();
4452     hr = wined3d_device_set_texture(device->wined3d_device,
4453             stage, surf ? surf->wined3d_texture : NULL);
4454     wined3d_mutex_unlock();
4455
4456     return hr;
4457 }
4458
4459 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4460         DWORD stage, IDirectDrawSurface7 *texture)
4461 {
4462     return d3d_device7_SetTexture(iface, stage, texture);
4463 }
4464
4465 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4466         DWORD stage, IDirectDrawSurface7 *texture)
4467 {
4468     HRESULT hr;
4469     WORD old_fpucw;
4470
4471     old_fpucw = d3d_fpu_setup();
4472     hr = d3d_device7_SetTexture(iface, stage, texture);
4473     set_fpu_control_word(old_fpucw);
4474
4475     return hr;
4476 }
4477
4478 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4479         DWORD stage, IDirect3DTexture2 *texture)
4480 {
4481     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4482     struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4483     DWORD texmapblend;
4484     HRESULT hr;
4485
4486     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4487
4488     wined3d_mutex_lock();
4489
4490     if (device->legacyTextureBlending)
4491         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4492
4493     hr = IDirect3DDevice7_SetTexture(&device->IDirect3DDevice7_iface, stage, &tex->IDirectDrawSurface7_iface);
4494
4495     if (device->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4496     {
4497         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4498            See d3d_device3_SetRenderState() for details. */
4499         struct wined3d_texture *tex = NULL;
4500         BOOL tex_alpha = FALSE;
4501         DDPIXELFORMAT ddfmt;
4502         HRESULT result;
4503
4504         result = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
4505         if (result == WINED3D_OK && tex)
4506         {
4507             struct wined3d_resource *sub_resource;
4508
4509             if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4510             {
4511                 struct wined3d_resource_desc desc;
4512
4513                 wined3d_resource_get_desc(sub_resource, &desc);
4514                 ddfmt.dwSize = sizeof(ddfmt);
4515                 PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4516                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4517             }
4518
4519             wined3d_texture_decref(tex);
4520         }
4521
4522         /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4523         if (tex_alpha)
4524             wined3d_device_set_texture_stage_state(device->wined3d_device,
4525                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
4526         else
4527             wined3d_device_set_texture_stage_state(device->wined3d_device,
4528                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
4529     }
4530
4531     wined3d_mutex_unlock();
4532
4533     return hr;
4534 }
4535
4536 static const struct tss_lookup
4537 {
4538     BOOL sampler_state;
4539     enum wined3d_texture_stage_state state;
4540 }
4541 tss_lookup[] =
4542 {
4543     {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
4544     {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
4545     {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
4546     {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
4547     {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
4548     {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
4549     {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
4550     {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
4551     {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
4552     {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
4553     {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
4554     {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
4555     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 12, D3DTSS_ADDRESS */
4556     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
4557     {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
4558     {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
4559     {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
4560     {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
4561     {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
4562     {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
4563     {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
4564     {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
4565     {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
4566     {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
4567     {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4568 };
4569
4570 /*****************************************************************************
4571  * IDirect3DDevice7::GetTextureStageState
4572  *
4573  * Retrieves a state from a texture stage.
4574  *
4575  * Version 3 and 7
4576  *
4577  * Params:
4578  *  Stage: The stage to retrieve the state from
4579  *  TexStageStateType: The state type to retrieve
4580  *  State: Address to store the state's value at
4581  *
4582  * Returns:
4583  *  D3D_OK on success
4584  *  DDERR_INVALIDPARAMS if State is NULL
4585  *  For details, see IWineD3DDevice::GetTextureStageState
4586  *
4587  *****************************************************************************/
4588 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4589         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4590 {
4591     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4592     HRESULT hr;
4593     const struct tss_lookup *l;
4594
4595     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4596             iface, stage, state, value);
4597
4598     if (!value)
4599         return DDERR_INVALIDPARAMS;
4600
4601     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4602     {
4603         WARN("Invalid state %#x passed.\n", state);
4604         return DD_OK;
4605     }
4606
4607     l = &tss_lookup[state];
4608
4609     wined3d_mutex_lock();
4610
4611     if (l->sampler_state)
4612     {
4613         hr = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state, value);
4614
4615         switch (state)
4616         {
4617             /* Mipfilter is a sampler state with different values */
4618             case D3DTSS_MIPFILTER:
4619             {
4620                 switch (*value)
4621                 {
4622                     case WINED3D_TEXF_NONE:
4623                         *value = D3DTFP_NONE;
4624                         break;
4625                     case WINED3D_TEXF_POINT:
4626                         *value = D3DTFP_POINT;
4627                         break;
4628                     case WINED3D_TEXF_LINEAR:
4629                         *value = D3DTFP_LINEAR;
4630                         break;
4631                     default:
4632                         ERR("Unexpected mipfilter value %#x.\n", *value);
4633                         *value = D3DTFP_NONE;
4634                         break;
4635                 }
4636                 break;
4637             }
4638
4639             /* Magfilter has slightly different values */
4640             case D3DTSS_MAGFILTER:
4641             {
4642                 switch (*value)
4643                 {
4644                     case WINED3D_TEXF_POINT:
4645                             *value = D3DTFG_POINT;
4646                             break;
4647                     case WINED3D_TEXF_LINEAR:
4648                             *value = D3DTFG_LINEAR;
4649                             break;
4650                     case WINED3D_TEXF_ANISOTROPIC:
4651                             *value = D3DTFG_ANISOTROPIC;
4652                             break;
4653                     case WINED3D_TEXF_FLAT_CUBIC:
4654                             *value = D3DTFG_FLATCUBIC;
4655                             break;
4656                     case WINED3D_TEXF_GAUSSIAN_CUBIC:
4657                             *value = D3DTFG_GAUSSIANCUBIC;
4658                             break;
4659                     default:
4660                         ERR("Unexpected wined3d mag filter value %#x.\n", *value);
4661                         *value = D3DTFG_POINT;
4662                         break;
4663                 }
4664                 break;
4665             }
4666
4667             default:
4668                 break;
4669         }
4670     }
4671     else
4672     {
4673         hr = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state, value);
4674     }
4675
4676     wined3d_mutex_unlock();
4677
4678     return hr;
4679 }
4680
4681 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4682         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4683 {
4684     return d3d_device7_GetTextureStageState(iface, stage, state, value);
4685 }
4686
4687 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4688         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4689 {
4690     HRESULT hr;
4691     WORD old_fpucw;
4692
4693     old_fpucw = d3d_fpu_setup();
4694     hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
4695     set_fpu_control_word(old_fpucw);
4696
4697     return hr;
4698 }
4699
4700 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
4701         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4702 {
4703     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4704
4705     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4706             iface, stage, state, value);
4707
4708     return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4709 }
4710
4711 /*****************************************************************************
4712  * IDirect3DDevice7::SetTextureStageState
4713  *
4714  * Sets a texture stage state. Some stage types need to be handled specially,
4715  * because they do not exist in WineD3D and were moved to another place
4716  *
4717  * Version 3 and 7
4718  *
4719  * Params:
4720  *  Stage: The stage to modify
4721  *  TexStageStateType: The state to change
4722  *  State: The new value for the state
4723  *
4724  * Returns:
4725  *  D3D_OK on success
4726  *  For details, see IWineD3DDevice::SetTextureStageState
4727  *
4728  *****************************************************************************/
4729 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
4730         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4731 {
4732     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4733     const struct tss_lookup *l;
4734     HRESULT hr;
4735
4736     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4737             iface, stage, state, value);
4738
4739     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4740     {
4741         WARN("Invalid state %#x passed.\n", state);
4742         return DD_OK;
4743     }
4744
4745     l = &tss_lookup[state];
4746
4747     wined3d_mutex_lock();
4748
4749     if (l->sampler_state)
4750     {
4751         switch (state)
4752         {
4753             /* Mipfilter is a sampler state with different values */
4754             case D3DTSS_MIPFILTER:
4755             {
4756                 switch (value)
4757                 {
4758                     case D3DTFP_NONE:
4759                         value = WINED3D_TEXF_NONE;
4760                         break;
4761                     case D3DTFP_POINT:
4762                         value = WINED3D_TEXF_POINT;
4763                         break;
4764                     case 0: /* Unchecked */
4765                     case D3DTFP_LINEAR:
4766                         value = WINED3D_TEXF_LINEAR;
4767                         break;
4768                     default:
4769                         ERR("Unexpected mipfilter value %#x.\n", value);
4770                         value = WINED3D_TEXF_NONE;
4771                         break;
4772                 }
4773                 break;
4774             }
4775
4776             /* Magfilter has slightly different values */
4777             case D3DTSS_MAGFILTER:
4778             {
4779                 switch (value)
4780                 {
4781                     case D3DTFG_POINT:
4782                         value = WINED3D_TEXF_POINT;
4783                         break;
4784                     case D3DTFG_LINEAR:
4785                         value = WINED3D_TEXF_LINEAR;
4786                         break;
4787                     case D3DTFG_FLATCUBIC:
4788                         value = WINED3D_TEXF_FLAT_CUBIC;
4789                         break;
4790                     case D3DTFG_GAUSSIANCUBIC:
4791                         value = WINED3D_TEXF_GAUSSIAN_CUBIC;
4792                         break;
4793                     case D3DTFG_ANISOTROPIC:
4794                         value = WINED3D_TEXF_ANISOTROPIC;
4795                         break;
4796                     default:
4797                         ERR("Unexpected d3d7 mag filter value %#x.\n", value);
4798                         value = WINED3D_TEXF_POINT;
4799                         break;
4800                 }
4801                 break;
4802             }
4803
4804             case D3DTSS_ADDRESS:
4805                 wined3d_device_set_sampler_state(device->wined3d_device, stage, WINED3D_SAMP_ADDRESS_V, value);
4806                 break;
4807
4808             default:
4809                 break;
4810         }
4811
4812         hr = wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
4813     }
4814     else
4815     {
4816         hr = wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
4817     }
4818
4819     wined3d_mutex_unlock();
4820
4821     return hr;
4822 }
4823
4824 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4825         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4826 {
4827     return d3d_device7_SetTextureStageState(iface, stage, state, value);
4828 }
4829
4830 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4831         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4832 {
4833     HRESULT hr;
4834     WORD old_fpucw;
4835
4836     old_fpucw = d3d_fpu_setup();
4837     hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
4838     set_fpu_control_word(old_fpucw);
4839
4840     return hr;
4841 }
4842
4843 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
4844         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4845 {
4846     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4847
4848     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4849             iface, stage, state, value);
4850
4851     return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4852 }
4853
4854 /*****************************************************************************
4855  * IDirect3DDevice7::ValidateDevice
4856  *
4857  * SDK: "Reports the device's ability to render the currently set
4858  * texture-blending operations in a single pass". Whatever that means
4859  * exactly...
4860  *
4861  * Version 3 and 7
4862  *
4863  * Params:
4864  *  NumPasses: Address to write the number of necessary passes for the
4865  *             desired effect to.
4866  *
4867  * Returns:
4868  *  D3D_OK on success
4869  *  See IWineD3DDevice::ValidateDevice for more details
4870  *
4871  *****************************************************************************/
4872 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
4873 {
4874     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4875     HRESULT hr;
4876
4877     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4878
4879     wined3d_mutex_lock();
4880     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
4881     wined3d_mutex_unlock();
4882
4883     return hr;
4884 }
4885
4886 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
4887 {
4888     return d3d_device7_ValidateDevice(iface, pass_count);
4889 }
4890
4891 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
4892 {
4893     HRESULT hr;
4894     WORD old_fpucw;
4895
4896     old_fpucw = d3d_fpu_setup();
4897     hr = d3d_device7_ValidateDevice(iface, pass_count);
4898     set_fpu_control_word(old_fpucw);
4899
4900     return hr;
4901 }
4902
4903 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
4904 {
4905     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4906
4907     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4908
4909     return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
4910 }
4911
4912 /*****************************************************************************
4913  * IDirect3DDevice7::Clear
4914  *
4915  * Fills the render target, the z buffer and the stencil buffer with a
4916  * clear color / value
4917  *
4918  * Version 7 only
4919  *
4920  * Params:
4921  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
4922  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
4923  *  Flags: Some flags, as usual
4924  *  Color: Clear color for the render target
4925  *  Z: Clear value for the Z buffer
4926  *  Stencil: Clear value to store in each stencil buffer entry
4927  *
4928  * Returns:
4929  *  D3D_OK on success
4930  *  For details, see IWineD3DDevice::Clear
4931  *
4932  *****************************************************************************/
4933 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
4934         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4935 {
4936     const struct wined3d_color c =
4937     {
4938         ((color >> 16) & 0xff) / 255.0f,
4939         ((color >>  8) & 0xff) / 255.0f,
4940         (color & 0xff) / 255.0f,
4941         ((color >> 24) & 0xff) / 255.0f,
4942     };
4943     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4944     HRESULT hr;
4945
4946     TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
4947             iface, count, rects, flags, color, z, stencil);
4948
4949     wined3d_mutex_lock();
4950     hr = wined3d_device_clear(This->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
4951     wined3d_mutex_unlock();
4952
4953     return hr;
4954 }
4955
4956 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
4957         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4958 {
4959     return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
4960 }
4961
4962 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
4963         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4964 {
4965     HRESULT hr;
4966     WORD old_fpucw;
4967
4968     old_fpucw = d3d_fpu_setup();
4969     hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
4970     set_fpu_control_word(old_fpucw);
4971
4972     return hr;
4973 }
4974
4975 /*****************************************************************************
4976  * IDirect3DDevice7::SetViewport
4977  *
4978  * Sets the current viewport.
4979  *
4980  * Version 7 only, but IDirect3DViewport uses this call for older
4981  * versions
4982  *
4983  * Params:
4984  *  Data: The new viewport to set
4985  *
4986  * Returns:
4987  *  D3D_OK on success
4988  *  DDERR_INVALIDPARAMS if Data is NULL
4989  *  For more details, see IWineDDDevice::SetViewport
4990  *
4991  *****************************************************************************/
4992 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4993 {
4994     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4995     HRESULT hr;
4996
4997     TRACE("iface %p, viewport %p.\n", iface, viewport);
4998
4999     if (!viewport)
5000         return DDERR_INVALIDPARAMS;
5001
5002     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5003     wined3d_mutex_lock();
5004     hr = wined3d_device_set_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5005     wined3d_mutex_unlock();
5006
5007     return hr;
5008 }
5009
5010 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5011 {
5012     return d3d_device7_SetViewport(iface, viewport);
5013 }
5014
5015 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5016 {
5017     HRESULT hr;
5018     WORD old_fpucw;
5019
5020     old_fpucw = d3d_fpu_setup();
5021     hr = d3d_device7_SetViewport(iface, viewport);
5022     set_fpu_control_word(old_fpucw);
5023
5024     return hr;
5025 }
5026
5027 /*****************************************************************************
5028  * IDirect3DDevice::GetViewport
5029  *
5030  * Returns the current viewport
5031  *
5032  * Version 7
5033  *
5034  * Params:
5035  *  Data: D3D7Viewport structure to write the viewport information to
5036  *
5037  * Returns:
5038  *  D3D_OK on success
5039  *  DDERR_INVALIDPARAMS if Data is NULL
5040  *  For more details, see IWineD3DDevice::GetViewport
5041  *
5042  *****************************************************************************/
5043 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5044 {
5045     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5046     HRESULT hr;
5047
5048     TRACE("iface %p, viewport %p.\n", iface, viewport);
5049
5050     if (!viewport)
5051         return DDERR_INVALIDPARAMS;
5052
5053     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5054     wined3d_mutex_lock();
5055     hr = wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5056     wined3d_mutex_unlock();
5057
5058     return hr_ddraw_from_wined3d(hr);
5059 }
5060
5061 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5062 {
5063     return d3d_device7_GetViewport(iface, viewport);
5064 }
5065
5066 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5067 {
5068     HRESULT hr;
5069     WORD old_fpucw;
5070
5071     old_fpucw = d3d_fpu_setup();
5072     hr = d3d_device7_GetViewport(iface, viewport);
5073     set_fpu_control_word(old_fpucw);
5074
5075     return hr;
5076 }
5077
5078 /*****************************************************************************
5079  * IDirect3DDevice7::SetMaterial
5080  *
5081  * Sets the Material
5082  *
5083  * Version 7
5084  *
5085  * Params:
5086  *  Mat: The material to set
5087  *
5088  * Returns:
5089  *  D3D_OK on success
5090  *  DDERR_INVALIDPARAMS if Mat is NULL.
5091  *  For more details, see IWineD3DDevice::SetMaterial
5092  *
5093  *****************************************************************************/
5094 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5095 {
5096     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5097     HRESULT hr;
5098
5099     TRACE("iface %p, material %p.\n", iface, material);
5100
5101     if (!material)
5102         return DDERR_INVALIDPARAMS;
5103
5104     wined3d_mutex_lock();
5105     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5106     hr = wined3d_device_set_material(device->wined3d_device, (struct wined3d_material *)material);
5107     wined3d_mutex_unlock();
5108
5109     return hr_ddraw_from_wined3d(hr);
5110 }
5111
5112 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5113 {
5114     return d3d_device7_SetMaterial(iface, material);
5115 }
5116
5117 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5118 {
5119     HRESULT hr;
5120     WORD old_fpucw;
5121
5122     old_fpucw = d3d_fpu_setup();
5123     hr = d3d_device7_SetMaterial(iface, material);
5124     set_fpu_control_word(old_fpucw);
5125
5126     return hr;
5127 }
5128
5129 /*****************************************************************************
5130  * IDirect3DDevice7::GetMaterial
5131  *
5132  * Returns the current material
5133  *
5134  * Version 7
5135  *
5136  * Params:
5137  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5138  *
5139  * Returns:
5140  *  D3D_OK on success
5141  *  DDERR_INVALIDPARAMS if Mat is NULL
5142  *  For more details, see IWineD3DDevice::GetMaterial
5143  *
5144  *****************************************************************************/
5145 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5146 {
5147     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5148     HRESULT hr;
5149
5150     TRACE("iface %p, material %p.\n", iface, material);
5151
5152     wined3d_mutex_lock();
5153     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5154     hr = wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
5155     wined3d_mutex_unlock();
5156
5157     return hr_ddraw_from_wined3d(hr);
5158 }
5159
5160 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5161 {
5162     return d3d_device7_GetMaterial(iface, material);
5163 }
5164
5165 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5166 {
5167     HRESULT hr;
5168     WORD old_fpucw;
5169
5170     old_fpucw = d3d_fpu_setup();
5171     hr = d3d_device7_GetMaterial(iface, material);
5172     set_fpu_control_word(old_fpucw);
5173
5174     return hr;
5175 }
5176
5177 /*****************************************************************************
5178  * IDirect3DDevice7::SetLight
5179  *
5180  * Assigns a light to a light index, but doesn't activate it yet.
5181  *
5182  * Version 7, IDirect3DLight uses this method for older versions
5183  *
5184  * Params:
5185  *  LightIndex: The index of the new light
5186  *  Light: A D3DLIGHT7 structure describing the light
5187  *
5188  * Returns:
5189  *  D3D_OK on success
5190  *  For more details, see IWineD3DDevice::SetLight
5191  *
5192  *****************************************************************************/
5193 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5194 {
5195     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5196     HRESULT hr;
5197
5198     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5199
5200     wined3d_mutex_lock();
5201     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5202     hr = wined3d_device_set_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5203     wined3d_mutex_unlock();
5204
5205     return hr_ddraw_from_wined3d(hr);
5206 }
5207
5208 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5209 {
5210     return d3d_device7_SetLight(iface, light_idx, light);
5211 }
5212
5213 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5214 {
5215     HRESULT hr;
5216     WORD old_fpucw;
5217
5218     old_fpucw = d3d_fpu_setup();
5219     hr = d3d_device7_SetLight(iface, light_idx, light);
5220     set_fpu_control_word(old_fpucw);
5221
5222     return hr;
5223 }
5224
5225 /*****************************************************************************
5226  * IDirect3DDevice7::GetLight
5227  *
5228  * Returns the light assigned to a light index
5229  *
5230  * Params:
5231  *  Light: Structure to write the light information to
5232  *
5233  * Returns:
5234  *  D3D_OK on success
5235  *  DDERR_INVALIDPARAMS if Light is NULL
5236  *  For details, see IWineD3DDevice::GetLight
5237  *
5238  *****************************************************************************/
5239 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5240 {
5241     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5242     HRESULT rc;
5243
5244     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5245
5246     wined3d_mutex_lock();
5247     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5248     rc =  wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5249     wined3d_mutex_unlock();
5250
5251     /* Translate the result. WineD3D returns other values than D3D7 */
5252     return hr_ddraw_from_wined3d(rc);
5253 }
5254
5255 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5256 {
5257     return d3d_device7_GetLight(iface, light_idx, light);
5258 }
5259
5260 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5261 {
5262     HRESULT hr;
5263     WORD old_fpucw;
5264
5265     old_fpucw = d3d_fpu_setup();
5266     hr = d3d_device7_GetLight(iface, light_idx, light);
5267     set_fpu_control_word(old_fpucw);
5268
5269     return hr;
5270 }
5271
5272 /*****************************************************************************
5273  * IDirect3DDevice7::BeginStateBlock
5274  *
5275  * Begins recording to a stateblock
5276  *
5277  * Version 7
5278  *
5279  * Returns:
5280  *  D3D_OK on success
5281  *  For details see IWineD3DDevice::BeginStateBlock
5282  *
5283  *****************************************************************************/
5284 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5285 {
5286     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5287     HRESULT hr;
5288
5289     TRACE("iface %p.\n", iface);
5290
5291     wined3d_mutex_lock();
5292     hr = wined3d_device_begin_stateblock(device->wined3d_device);
5293     wined3d_mutex_unlock();
5294
5295     return hr_ddraw_from_wined3d(hr);
5296 }
5297
5298 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5299 {
5300     return d3d_device7_BeginStateBlock(iface);
5301 }
5302
5303 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5304 {
5305     HRESULT hr;
5306     WORD old_fpucw;
5307
5308     old_fpucw = d3d_fpu_setup();
5309     hr = d3d_device7_BeginStateBlock(iface);
5310     set_fpu_control_word(old_fpucw);
5311
5312     return hr;
5313 }
5314
5315 /*****************************************************************************
5316  * IDirect3DDevice7::EndStateBlock
5317  *
5318  * Stops recording to a state block and returns the created stateblock
5319  * handle.
5320  *
5321  * Version 7
5322  *
5323  * Params:
5324  *  BlockHandle: Address to store the stateblock's handle to
5325  *
5326  * Returns:
5327  *  D3D_OK on success
5328  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5329  *  See IWineD3DDevice::EndStateBlock for more details
5330  *
5331  *****************************************************************************/
5332 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5333 {
5334     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5335     struct wined3d_stateblock *wined3d_sb;
5336     HRESULT hr;
5337     DWORD h;
5338
5339     TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5340
5341     if (!stateblock)
5342         return DDERR_INVALIDPARAMS;
5343
5344     wined3d_mutex_lock();
5345
5346     hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_sb);
5347     if (FAILED(hr))
5348     {
5349         WARN("Failed to end stateblock, hr %#x.\n", hr);
5350         wined3d_mutex_unlock();
5351         *stateblock = 0;
5352         return hr_ddraw_from_wined3d(hr);
5353     }
5354
5355     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5356     if (h == DDRAW_INVALID_HANDLE)
5357     {
5358         ERR("Failed to allocate a stateblock handle.\n");
5359         wined3d_stateblock_decref(wined3d_sb);
5360         wined3d_mutex_unlock();
5361         *stateblock = 0;
5362         return DDERR_OUTOFMEMORY;
5363     }
5364
5365     wined3d_mutex_unlock();
5366     *stateblock = h + 1;
5367
5368     return hr_ddraw_from_wined3d(hr);
5369 }
5370
5371 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5372 {
5373     return d3d_device7_EndStateBlock(iface, stateblock);
5374 }
5375
5376 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5377 {
5378     HRESULT hr;
5379     WORD old_fpucw;
5380
5381     old_fpucw = d3d_fpu_setup();
5382     hr = d3d_device7_EndStateBlock(iface, stateblock);
5383     set_fpu_control_word(old_fpucw);
5384
5385     return hr;
5386 }
5387
5388 /*****************************************************************************
5389  * IDirect3DDevice7::PreLoad
5390  *
5391  * Allows the app to signal that a texture will be used soon, to allow
5392  * the Direct3DDevice to load it to the video card in the meantime.
5393  *
5394  * Version 7
5395  *
5396  * Params:
5397  *  Texture: The texture to preload
5398  *
5399  * Returns:
5400  *  D3D_OK on success
5401  *  DDERR_INVALIDPARAMS if Texture is NULL
5402  *  See IWineD3DSurface::PreLoad for details
5403  *
5404  *****************************************************************************/
5405 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5406 {
5407     struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5408
5409     TRACE("iface %p, texture %p.\n", iface, texture);
5410
5411     if (!texture)
5412         return DDERR_INVALIDPARAMS;
5413
5414     wined3d_mutex_lock();
5415     wined3d_surface_preload(surface->wined3d_surface);
5416     wined3d_mutex_unlock();
5417
5418     return D3D_OK;
5419 }
5420
5421 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5422 {
5423     return d3d_device7_PreLoad(iface, texture);
5424 }
5425
5426 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5427 {
5428     HRESULT hr;
5429     WORD old_fpucw;
5430
5431     old_fpucw = d3d_fpu_setup();
5432     hr = d3d_device7_PreLoad(iface, texture);
5433     set_fpu_control_word(old_fpucw);
5434
5435     return hr;
5436 }
5437
5438 /*****************************************************************************
5439  * IDirect3DDevice7::ApplyStateBlock
5440  *
5441  * Activates the state stored in a state block handle.
5442  *
5443  * Params:
5444  *  BlockHandle: The stateblock handle to activate
5445  *
5446  * Returns:
5447  *  D3D_OK on success
5448  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5449  *
5450  *****************************************************************************/
5451 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5452 {
5453     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5454     struct wined3d_stateblock *wined3d_sb;
5455     HRESULT hr;
5456
5457     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5458
5459     wined3d_mutex_lock();
5460     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5461     if (!wined3d_sb)
5462     {
5463         WARN("Invalid stateblock handle.\n");
5464         wined3d_mutex_unlock();
5465         return D3DERR_INVALIDSTATEBLOCK;
5466     }
5467
5468     hr = wined3d_stateblock_apply(wined3d_sb);
5469     wined3d_mutex_unlock();
5470
5471     return hr_ddraw_from_wined3d(hr);
5472 }
5473
5474 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5475 {
5476     return d3d_device7_ApplyStateBlock(iface, stateblock);
5477 }
5478
5479 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5480 {
5481     HRESULT hr;
5482     WORD old_fpucw;
5483
5484     old_fpucw = d3d_fpu_setup();
5485     hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5486     set_fpu_control_word(old_fpucw);
5487
5488     return hr;
5489 }
5490
5491 /*****************************************************************************
5492  * IDirect3DDevice7::CaptureStateBlock
5493  *
5494  * Updates a stateblock's values to the values currently set for the device
5495  *
5496  * Version 7
5497  *
5498  * Params:
5499  *  BlockHandle: Stateblock to update
5500  *
5501  * Returns:
5502  *  D3D_OK on success
5503  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5504  *  See IWineD3DDevice::CaptureStateBlock for more details
5505  *
5506  *****************************************************************************/
5507 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5508 {
5509     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5510     struct wined3d_stateblock *wined3d_sb;
5511     HRESULT hr;
5512
5513     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5514
5515     wined3d_mutex_lock();
5516     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5517     if (!wined3d_sb)
5518     {
5519         WARN("Invalid stateblock handle.\n");
5520         wined3d_mutex_unlock();
5521         return D3DERR_INVALIDSTATEBLOCK;
5522     }
5523
5524     hr = wined3d_stateblock_capture(wined3d_sb);
5525     wined3d_mutex_unlock();
5526
5527     return hr_ddraw_from_wined3d(hr);
5528 }
5529
5530 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5531 {
5532     return d3d_device7_CaptureStateBlock(iface, stateblock);
5533 }
5534
5535 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5536 {
5537     HRESULT hr;
5538     WORD old_fpucw;
5539
5540     old_fpucw = d3d_fpu_setup();
5541     hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5542     set_fpu_control_word(old_fpucw);
5543
5544     return hr;
5545 }
5546
5547 /*****************************************************************************
5548  * IDirect3DDevice7::DeleteStateBlock
5549  *
5550  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5551  *
5552  * Version 7
5553  *
5554  * Params:
5555  *  BlockHandle: Stateblock handle to delete
5556  *
5557  * Returns:
5558  *  D3D_OK on success
5559  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5560  *
5561  *****************************************************************************/
5562 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5563 {
5564     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5565     struct wined3d_stateblock *wined3d_sb;
5566     ULONG ref;
5567
5568     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5569
5570     wined3d_mutex_lock();
5571
5572     wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5573     if (!wined3d_sb)
5574     {
5575         WARN("Invalid stateblock handle.\n");
5576         wined3d_mutex_unlock();
5577         return D3DERR_INVALIDSTATEBLOCK;
5578     }
5579
5580     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5581     {
5582         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5583     }
5584
5585     wined3d_mutex_unlock();
5586
5587     return D3D_OK;
5588 }
5589
5590 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5591 {
5592     return d3d_device7_DeleteStateBlock(iface, stateblock);
5593 }
5594
5595 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5596 {
5597     HRESULT hr;
5598     WORD old_fpucw;
5599
5600     old_fpucw = d3d_fpu_setup();
5601     hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5602     set_fpu_control_word(old_fpucw);
5603
5604     return hr;
5605 }
5606
5607 /*****************************************************************************
5608  * IDirect3DDevice7::CreateStateBlock
5609  *
5610  * Creates a new state block handle.
5611  *
5612  * Version 7
5613  *
5614  * Params:
5615  *  Type: The state block type
5616  *  BlockHandle: Address to write the created handle to
5617  *
5618  * Returns:
5619  *   D3D_OK on success
5620  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5621  *
5622  *****************************************************************************/
5623 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5624         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5625 {
5626     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5627     struct wined3d_stateblock *wined3d_sb;
5628     HRESULT hr;
5629     DWORD h;
5630
5631     TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5632
5633     if (!stateblock)
5634         return DDERR_INVALIDPARAMS;
5635
5636     if (type != D3DSBT_ALL
5637             && type != D3DSBT_PIXELSTATE
5638             && type != D3DSBT_VERTEXSTATE)
5639     {
5640         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5641         return DDERR_INVALIDPARAMS;
5642     }
5643
5644     wined3d_mutex_lock();
5645
5646     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5647     hr = wined3d_stateblock_create(device->wined3d_device, type, &wined3d_sb);
5648     if (FAILED(hr))
5649     {
5650         WARN("Failed to create stateblock, hr %#x.\n", hr);
5651         wined3d_mutex_unlock();
5652         return hr_ddraw_from_wined3d(hr);
5653     }
5654
5655     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5656     if (h == DDRAW_INVALID_HANDLE)
5657     {
5658         ERR("Failed to allocate stateblock handle.\n");
5659         wined3d_stateblock_decref(wined3d_sb);
5660         wined3d_mutex_unlock();
5661         return DDERR_OUTOFMEMORY;
5662     }
5663
5664     *stateblock = h + 1;
5665     wined3d_mutex_unlock();
5666
5667     return hr_ddraw_from_wined3d(hr);
5668 }
5669
5670 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5671         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5672 {
5673     return d3d_device7_CreateStateBlock(iface, type, stateblock);
5674 }
5675
5676 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5677         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5678 {
5679     HRESULT hr;
5680     WORD old_fpucw;
5681
5682     old_fpucw = d3d_fpu_setup();
5683     hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5684     set_fpu_control_word(old_fpucw);
5685
5686     return hr;
5687 }
5688
5689 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
5690 {
5691     struct ddraw_surface *src_level, *dest_level;
5692     IDirectDrawSurface7 *temp;
5693     DDSURFACEDESC2 ddsd;
5694     BOOL levelFound; /* at least one suitable sublevel in dest found */
5695
5696     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5697      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5698      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5699      */
5700     levelFound = FALSE;
5701
5702     src_level = src;
5703     dest_level = dest;
5704
5705     for (;src_level && dest_level;)
5706     {
5707         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5708             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5709         {
5710             levelFound = TRUE;
5711
5712             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5713             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5714             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5715
5716             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5717
5718             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5719         }
5720
5721         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5722         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5723         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5724
5725         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5726
5727         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5728     }
5729
5730     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5731     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5732
5733     return !dest_level && levelFound;
5734 }
5735
5736 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dest,
5737         struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
5738 {
5739     struct ddraw_surface *src_level, *dest_level;
5740     IDirectDrawSurface7 *temp;
5741     DDSURFACEDESC2 ddsd;
5742     POINT point;
5743     RECT src_rect;
5744     HRESULT hr;
5745     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
5746     DWORD ckeyflag;
5747     DDCOLORKEY ddckey;
5748
5749     /* Copy palette, if possible. */
5750     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
5751     IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
5752
5753     if (pal_src != NULL && pal != NULL)
5754     {
5755         PALETTEENTRY palent[256];
5756
5757         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
5758         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
5759     }
5760
5761     if (pal) IDirectDrawPalette_Release(pal);
5762     if (pal_src) IDirectDrawPalette_Release(pal_src);
5763
5764     /* Copy colorkeys, if present. */
5765     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
5766     {
5767         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5768
5769         if (SUCCEEDED(hr))
5770         {
5771             IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5772         }
5773     }
5774
5775     src_level = src;
5776     dest_level = dest;
5777
5778     point = *DestPoint;
5779     src_rect = *SrcRect;
5780
5781     for (;src_level && dest_level;)
5782     {
5783         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5784             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5785         {
5786             UINT src_w = src_rect.right - src_rect.left;
5787             UINT src_h = src_rect.bottom - src_rect.top;
5788             RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
5789
5790             if (FAILED(hr = wined3d_surface_blt(dest_level->wined3d_surface, &dst_rect,
5791                     src_level->wined3d_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
5792                 ERR("Blit failed, hr %#x.\n", hr);
5793
5794             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5795             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5796             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5797
5798             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5799
5800             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5801         }
5802
5803         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5804         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5805         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5806
5807         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5808
5809         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5810
5811         point.x /= 2;
5812         point.y /= 2;
5813
5814         src_rect.top /= 2;
5815         src_rect.left /= 2;
5816         src_rect.right = (src_rect.right + 1) / 2;
5817         src_rect.bottom = (src_rect.bottom + 1) / 2;
5818     }
5819
5820     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5821     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5822 }
5823
5824 /*****************************************************************************
5825  * IDirect3DDevice7::Load
5826  *
5827  * Loads a rectangular area from the source into the destination texture.
5828  * It can also copy the source to the faces of a cubic environment map
5829  *
5830  * Version 7
5831  *
5832  * Params:
5833  *  DestTex: Destination texture
5834  *  DestPoint: Point in the destination where the source image should be
5835  *             written to
5836  *  SrcTex: Source texture
5837  *  SrcRect: Source rectangle
5838  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
5839  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
5840  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
5841  *
5842  * Returns:
5843  *  D3D_OK on success
5844  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
5845  *
5846  *
5847  *****************************************************************************/
5848 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
5849         IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5850 {
5851     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5852     struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
5853     struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
5854     POINT destpoint;
5855     RECT srcrect;
5856
5857     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
5858             iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
5859
5860     if( (!src) || (!dest) )
5861         return DDERR_INVALIDPARAMS;
5862
5863     wined3d_mutex_lock();
5864
5865     if (!src_rect)
5866     {
5867         srcrect.left = srcrect.top = 0;
5868         srcrect.right = src->surface_desc.dwWidth;
5869         srcrect.bottom = src->surface_desc.dwHeight;
5870     }
5871     else
5872         srcrect = *src_rect;
5873
5874     if (!dst_pos)
5875         destpoint.x = destpoint.y = 0;
5876     else
5877         destpoint = *dst_pos;
5878
5879     /* Check bad dimensions. dst_pos is validated against src, not dest, because
5880      * destination can be a subset of mip levels, in which case actual coordinates used
5881      * for it may be divided. If any dimension of dest is larger than source, it can't be
5882      * mip level subset, so an error can be returned early.
5883      */
5884     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
5885         srcrect.right > src->surface_desc.dwWidth ||
5886         srcrect.bottom > src->surface_desc.dwHeight ||
5887         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
5888         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
5889         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
5890         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
5891     {
5892         wined3d_mutex_unlock();
5893         return DDERR_INVALIDPARAMS;
5894     }
5895
5896     /* Must be top level surfaces. */
5897     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
5898         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
5899     {
5900         wined3d_mutex_unlock();
5901         return DDERR_INVALIDPARAMS;
5902     }
5903
5904     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5905     {
5906         struct ddraw_surface *src_face, *dest_face;
5907         DWORD src_face_flag, dest_face_flag;
5908         IDirectDrawSurface7 *temp;
5909         DDSURFACEDESC2 ddsd;
5910         int i;
5911
5912         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
5913         {
5914             wined3d_mutex_unlock();
5915             return DDERR_INVALIDPARAMS;
5916         }
5917
5918         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
5919          * time it's actual surface loading. */
5920         for (i = 0; i < 2; i++)
5921         {
5922             dest_face = dest;
5923             src_face = src;
5924
5925             for (;dest_face && src_face;)
5926             {
5927                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
5928                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
5929
5930                 if (src_face_flag == dest_face_flag)
5931                 {
5932                     if (i == 0)
5933                     {
5934                         /* Destination mip levels must be subset of source mip levels. */
5935                         if (!is_mip_level_subset(dest_face, src_face))
5936                         {
5937                             wined3d_mutex_unlock();
5938                             return DDERR_INVALIDPARAMS;
5939                         }
5940                     }
5941                     else if (flags & dest_face_flag)
5942                     {
5943                         copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
5944                     }
5945
5946                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
5947                     {
5948                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5949                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
5950                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5951
5952                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
5953
5954                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
5955                     }
5956                     else
5957                     {
5958                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
5959
5960                         src_face = NULL;
5961                     }
5962                 }
5963
5964                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
5965                 {
5966                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5967                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
5968                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5969
5970                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
5971
5972                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
5973                 }
5974                 else
5975                 {
5976                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
5977
5978                     dest_face = NULL;
5979                 }
5980             }
5981
5982             if (i == 0)
5983             {
5984                 /* Native returns error if src faces are not subset of dest faces. */
5985                 if (src_face)
5986                 {
5987                     wined3d_mutex_unlock();
5988                     return DDERR_INVALIDPARAMS;
5989                 }
5990             }
5991         }
5992
5993         wined3d_mutex_unlock();
5994         return D3D_OK;
5995     }
5996     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5997     {
5998         wined3d_mutex_unlock();
5999         return DDERR_INVALIDPARAMS;
6000     }
6001
6002     /* Handle non cube map textures. */
6003
6004     /* Destination mip levels must be subset of source mip levels. */
6005     if (!is_mip_level_subset(dest, src))
6006     {
6007         wined3d_mutex_unlock();
6008         return DDERR_INVALIDPARAMS;
6009     }
6010
6011     copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6012
6013     wined3d_mutex_unlock();
6014
6015     return D3D_OK;
6016 }
6017
6018 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6019         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6020 {
6021     return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6022 }
6023
6024 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6025         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6026 {
6027     HRESULT hr;
6028     WORD old_fpucw;
6029
6030     old_fpucw = d3d_fpu_setup();
6031     hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6032     set_fpu_control_word(old_fpucw);
6033
6034     return hr;
6035 }
6036
6037 /*****************************************************************************
6038  * IDirect3DDevice7::LightEnable
6039  *
6040  * Enables or disables a light
6041  *
6042  * Version 7, IDirect3DLight uses this method too.
6043  *
6044  * Params:
6045  *  LightIndex: The index of the light to enable / disable
6046  *  Enable: Enable or disable the light
6047  *
6048  * Returns:
6049  *  D3D_OK on success
6050  *  For more details, see IWineD3DDevice::SetLightEnable
6051  *
6052  *****************************************************************************/
6053 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6054 {
6055     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6056     HRESULT hr;
6057
6058     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6059
6060     wined3d_mutex_lock();
6061     hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
6062     wined3d_mutex_unlock();
6063
6064     return hr_ddraw_from_wined3d(hr);
6065 }
6066
6067 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6068 {
6069     return d3d_device7_LightEnable(iface, light_idx, enabled);
6070 }
6071
6072 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6073 {
6074     HRESULT hr;
6075     WORD old_fpucw;
6076
6077     old_fpucw = d3d_fpu_setup();
6078     hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6079     set_fpu_control_word(old_fpucw);
6080
6081     return hr;
6082 }
6083
6084 /*****************************************************************************
6085  * IDirect3DDevice7::GetLightEnable
6086  *
6087  * Retrieves if the light with the given index is enabled or not
6088  *
6089  * Version 7
6090  *
6091  * Params:
6092  *  LightIndex: Index of desired light
6093  *  Enable: Pointer to a BOOL which contains the result
6094  *
6095  * Returns:
6096  *  D3D_OK on success
6097  *  DDERR_INVALIDPARAMS if Enable is NULL
6098  *  See IWineD3DDevice::GetLightEnable for more details
6099  *
6100  *****************************************************************************/
6101 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6102 {
6103     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6104     HRESULT hr;
6105
6106     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6107
6108     if (!enabled)
6109         return DDERR_INVALIDPARAMS;
6110
6111     wined3d_mutex_lock();
6112     hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6113     wined3d_mutex_unlock();
6114
6115     return hr_ddraw_from_wined3d(hr);
6116 }
6117
6118 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6119 {
6120     return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6121 }
6122
6123 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6124 {
6125     HRESULT hr;
6126     WORD old_fpucw;
6127
6128     old_fpucw = d3d_fpu_setup();
6129     hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6130     set_fpu_control_word(old_fpucw);
6131
6132     return hr;
6133 }
6134
6135 /*****************************************************************************
6136  * IDirect3DDevice7::SetClipPlane
6137  *
6138  * Sets custom clipping plane
6139  *
6140  * Version 7
6141  *
6142  * Params:
6143  *  Index: The index of the clipping plane
6144  *  PlaneEquation: An equation defining the clipping plane
6145  *
6146  * Returns:
6147  *  D3D_OK on success
6148  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6149  *  See IWineD3DDevice::SetClipPlane for more details
6150  *
6151  *****************************************************************************/
6152 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6153 {
6154     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6155     HRESULT hr;
6156
6157     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6158
6159     if (!plane)
6160         return DDERR_INVALIDPARAMS;
6161
6162     wined3d_mutex_lock();
6163     hr = wined3d_device_set_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6164     wined3d_mutex_unlock();
6165
6166     return hr;
6167 }
6168
6169 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6170 {
6171     return d3d_device7_SetClipPlane(iface, idx, plane);
6172 }
6173
6174 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6175 {
6176     HRESULT hr;
6177     WORD old_fpucw;
6178
6179     old_fpucw = d3d_fpu_setup();
6180     hr = d3d_device7_SetClipPlane(iface, idx, plane);
6181     set_fpu_control_word(old_fpucw);
6182
6183     return hr;
6184 }
6185
6186 /*****************************************************************************
6187  * IDirect3DDevice7::GetClipPlane
6188  *
6189  * Returns the clipping plane with a specific index
6190  *
6191  * Params:
6192  *  Index: The index of the desired plane
6193  *  PlaneEquation: Address to store the plane equation to
6194  *
6195  * Returns:
6196  *  D3D_OK on success
6197  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6198  *  See IWineD3DDevice::GetClipPlane for more details
6199  *
6200  *****************************************************************************/
6201 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6202 {
6203     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6204     HRESULT hr;
6205
6206     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6207
6208     if (!plane)
6209         return DDERR_INVALIDPARAMS;
6210
6211     wined3d_mutex_lock();
6212     hr = wined3d_device_get_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6213     wined3d_mutex_unlock();
6214
6215     return hr;
6216 }
6217
6218 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6219 {
6220     return d3d_device7_GetClipPlane(iface, idx, plane);
6221 }
6222
6223 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6224 {
6225     HRESULT hr;
6226     WORD old_fpucw;
6227
6228     old_fpucw = d3d_fpu_setup();
6229     hr = d3d_device7_GetClipPlane(iface, idx, plane);
6230     set_fpu_control_word(old_fpucw);
6231
6232     return hr;
6233 }
6234
6235 /*****************************************************************************
6236  * IDirect3DDevice7::GetInfo
6237  *
6238  * Retrieves some information about the device. The DirectX sdk says that
6239  * this version returns S_FALSE for all retail builds of DirectX, that's what
6240  * this implementation does.
6241  *
6242  * Params:
6243  *  DevInfoID: Information type requested
6244  *  DevInfoStruct: Pointer to a structure to store the info to
6245  *  Size: Size of the structure
6246  *
6247  * Returns:
6248  *  S_FALSE, because it's a non-debug driver
6249  *
6250  *****************************************************************************/
6251 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6252 {
6253     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6254             iface, info_id, info, info_size);
6255
6256     if (TRACE_ON(ddraw))
6257     {
6258         TRACE(" info requested : ");
6259         switch (info_id)
6260         {
6261             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6262             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6263             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6264             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6265         }
6266     }
6267
6268     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6269 }
6270
6271 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6272  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6273  * are not duplicated.
6274
6275  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6276  * has already been setup for optimal d3d operation.
6277
6278  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6279  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6280  * by Sacrifice (game). */
6281 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6282 {
6283     /*** IUnknown Methods ***/
6284     d3d_device7_QueryInterface,
6285     d3d_device7_AddRef,
6286     d3d_device7_Release,
6287     /*** IDirect3DDevice7 ***/
6288     d3d_device7_GetCaps_FPUSetup,
6289     d3d_device7_EnumTextureFormats_FPUSetup,
6290     d3d_device7_BeginScene_FPUSetup,
6291     d3d_device7_EndScene_FPUSetup,
6292     d3d_device7_GetDirect3D,
6293     d3d_device7_SetRenderTarget_FPUSetup,
6294     d3d_device7_GetRenderTarget,
6295     d3d_device7_Clear_FPUSetup,
6296     d3d_device7_SetTransform_FPUSetup,
6297     d3d_device7_GetTransform_FPUSetup,
6298     d3d_device7_SetViewport_FPUSetup,
6299     d3d_device7_MultiplyTransform_FPUSetup,
6300     d3d_device7_GetViewport_FPUSetup,
6301     d3d_device7_SetMaterial_FPUSetup,
6302     d3d_device7_GetMaterial_FPUSetup,
6303     d3d_device7_SetLight_FPUSetup,
6304     d3d_device7_GetLight_FPUSetup,
6305     d3d_device7_SetRenderState_FPUSetup,
6306     d3d_device7_GetRenderState_FPUSetup,
6307     d3d_device7_BeginStateBlock_FPUSetup,
6308     d3d_device7_EndStateBlock_FPUSetup,
6309     d3d_device7_PreLoad_FPUSetup,
6310     d3d_device7_DrawPrimitive_FPUSetup,
6311     d3d_device7_DrawIndexedPrimitive_FPUSetup,
6312     d3d_device7_SetClipStatus,
6313     d3d_device7_GetClipStatus,
6314     d3d_device7_DrawPrimitiveStrided_FPUSetup,
6315     d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6316     d3d_device7_DrawPrimitiveVB_FPUSetup,
6317     d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6318     d3d_device7_ComputeSphereVisibility,
6319     d3d_device7_GetTexture_FPUSetup,
6320     d3d_device7_SetTexture_FPUSetup,
6321     d3d_device7_GetTextureStageState_FPUSetup,
6322     d3d_device7_SetTextureStageState_FPUSetup,
6323     d3d_device7_ValidateDevice_FPUSetup,
6324     d3d_device7_ApplyStateBlock_FPUSetup,
6325     d3d_device7_CaptureStateBlock_FPUSetup,
6326     d3d_device7_DeleteStateBlock_FPUSetup,
6327     d3d_device7_CreateStateBlock_FPUSetup,
6328     d3d_device7_Load_FPUSetup,
6329     d3d_device7_LightEnable_FPUSetup,
6330     d3d_device7_GetLightEnable_FPUSetup,
6331     d3d_device7_SetClipPlane_FPUSetup,
6332     d3d_device7_GetClipPlane_FPUSetup,
6333     d3d_device7_GetInfo
6334 };
6335
6336 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6337 {
6338     /*** IUnknown Methods ***/
6339     d3d_device7_QueryInterface,
6340     d3d_device7_AddRef,
6341     d3d_device7_Release,
6342     /*** IDirect3DDevice7 ***/
6343     d3d_device7_GetCaps_FPUPreserve,
6344     d3d_device7_EnumTextureFormats_FPUPreserve,
6345     d3d_device7_BeginScene_FPUPreserve,
6346     d3d_device7_EndScene_FPUPreserve,
6347     d3d_device7_GetDirect3D,
6348     d3d_device7_SetRenderTarget_FPUPreserve,
6349     d3d_device7_GetRenderTarget,
6350     d3d_device7_Clear_FPUPreserve,
6351     d3d_device7_SetTransform_FPUPreserve,
6352     d3d_device7_GetTransform_FPUPreserve,
6353     d3d_device7_SetViewport_FPUPreserve,
6354     d3d_device7_MultiplyTransform_FPUPreserve,
6355     d3d_device7_GetViewport_FPUPreserve,
6356     d3d_device7_SetMaterial_FPUPreserve,
6357     d3d_device7_GetMaterial_FPUPreserve,
6358     d3d_device7_SetLight_FPUPreserve,
6359     d3d_device7_GetLight_FPUPreserve,
6360     d3d_device7_SetRenderState_FPUPreserve,
6361     d3d_device7_GetRenderState_FPUPreserve,
6362     d3d_device7_BeginStateBlock_FPUPreserve,
6363     d3d_device7_EndStateBlock_FPUPreserve,
6364     d3d_device7_PreLoad_FPUPreserve,
6365     d3d_device7_DrawPrimitive_FPUPreserve,
6366     d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6367     d3d_device7_SetClipStatus,
6368     d3d_device7_GetClipStatus,
6369     d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6370     d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6371     d3d_device7_DrawPrimitiveVB_FPUPreserve,
6372     d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6373     d3d_device7_ComputeSphereVisibility,
6374     d3d_device7_GetTexture_FPUPreserve,
6375     d3d_device7_SetTexture_FPUPreserve,
6376     d3d_device7_GetTextureStageState_FPUPreserve,
6377     d3d_device7_SetTextureStageState_FPUPreserve,
6378     d3d_device7_ValidateDevice_FPUPreserve,
6379     d3d_device7_ApplyStateBlock_FPUPreserve,
6380     d3d_device7_CaptureStateBlock_FPUPreserve,
6381     d3d_device7_DeleteStateBlock_FPUPreserve,
6382     d3d_device7_CreateStateBlock_FPUPreserve,
6383     d3d_device7_Load_FPUPreserve,
6384     d3d_device7_LightEnable_FPUPreserve,
6385     d3d_device7_GetLightEnable_FPUPreserve,
6386     d3d_device7_SetClipPlane_FPUPreserve,
6387     d3d_device7_GetClipPlane_FPUPreserve,
6388     d3d_device7_GetInfo
6389 };
6390
6391 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6392 {
6393     /*** IUnknown Methods ***/
6394     d3d_device3_QueryInterface,
6395     d3d_device3_AddRef,
6396     d3d_device3_Release,
6397     /*** IDirect3DDevice3 ***/
6398     d3d_device3_GetCaps,
6399     d3d_device3_GetStats,
6400     d3d_device3_AddViewport,
6401     d3d_device3_DeleteViewport,
6402     d3d_device3_NextViewport,
6403     d3d_device3_EnumTextureFormats,
6404     d3d_device3_BeginScene,
6405     d3d_device3_EndScene,
6406     d3d_device3_GetDirect3D,
6407     d3d_device3_SetCurrentViewport,
6408     d3d_device3_GetCurrentViewport,
6409     d3d_device3_SetRenderTarget,
6410     d3d_device3_GetRenderTarget,
6411     d3d_device3_Begin,
6412     d3d_device3_BeginIndexed,
6413     d3d_device3_Vertex,
6414     d3d_device3_Index,
6415     d3d_device3_End,
6416     d3d_device3_GetRenderState,
6417     d3d_device3_SetRenderState,
6418     d3d_device3_GetLightState,
6419     d3d_device3_SetLightState,
6420     d3d_device3_SetTransform,
6421     d3d_device3_GetTransform,
6422     d3d_device3_MultiplyTransform,
6423     d3d_device3_DrawPrimitive,
6424     d3d_device3_DrawIndexedPrimitive,
6425     d3d_device3_SetClipStatus,
6426     d3d_device3_GetClipStatus,
6427     d3d_device3_DrawPrimitiveStrided,
6428     d3d_device3_DrawIndexedPrimitiveStrided,
6429     d3d_device3_DrawPrimitiveVB,
6430     d3d_device3_DrawIndexedPrimitiveVB,
6431     d3d_device3_ComputeSphereVisibility,
6432     d3d_device3_GetTexture,
6433     d3d_device3_SetTexture,
6434     d3d_device3_GetTextureStageState,
6435     d3d_device3_SetTextureStageState,
6436     d3d_device3_ValidateDevice
6437 };
6438
6439 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6440 {
6441     /*** IUnknown Methods ***/
6442     d3d_device2_QueryInterface,
6443     d3d_device2_AddRef,
6444     d3d_device2_Release,
6445     /*** IDirect3DDevice2 ***/
6446     d3d_device2_GetCaps,
6447     d3d_device2_SwapTextureHandles,
6448     d3d_device2_GetStats,
6449     d3d_device2_AddViewport,
6450     d3d_device2_DeleteViewport,
6451     d3d_device2_NextViewport,
6452     d3d_device2_EnumTextureFormats,
6453     d3d_device2_BeginScene,
6454     d3d_device2_EndScene,
6455     d3d_device2_GetDirect3D,
6456     d3d_device2_SetCurrentViewport,
6457     d3d_device2_GetCurrentViewport,
6458     d3d_device2_SetRenderTarget,
6459     d3d_device2_GetRenderTarget,
6460     d3d_device2_Begin,
6461     d3d_device2_BeginIndexed,
6462     d3d_device2_Vertex,
6463     d3d_device2_Index,
6464     d3d_device2_End,
6465     d3d_device2_GetRenderState,
6466     d3d_device2_SetRenderState,
6467     d3d_device2_GetLightState,
6468     d3d_device2_SetLightState,
6469     d3d_device2_SetTransform,
6470     d3d_device2_GetTransform,
6471     d3d_device2_MultiplyTransform,
6472     d3d_device2_DrawPrimitive,
6473     d3d_device2_DrawIndexedPrimitive,
6474     d3d_device2_SetClipStatus,
6475     d3d_device2_GetClipStatus
6476 };
6477
6478 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6479 {
6480     /*** IUnknown Methods ***/
6481     d3d_device1_QueryInterface,
6482     d3d_device1_AddRef,
6483     d3d_device1_Release,
6484     /*** IDirect3DDevice1 ***/
6485     d3d_device1_Initialize,
6486     d3d_device1_GetCaps,
6487     d3d_device1_SwapTextureHandles,
6488     d3d_device1_CreateExecuteBuffer,
6489     d3d_device1_GetStats,
6490     d3d_device1_Execute,
6491     d3d_device1_AddViewport,
6492     d3d_device1_DeleteViewport,
6493     d3d_device1_NextViewport,
6494     d3d_device1_Pick,
6495     d3d_device1_GetPickRecords,
6496     d3d_device1_EnumTextureFormats,
6497     d3d_device1_CreateMatrix,
6498     d3d_device1_SetMatrix,
6499     d3d_device1_GetMatrix,
6500     d3d_device1_DeleteMatrix,
6501     d3d_device1_BeginScene,
6502     d3d_device1_EndScene,
6503     d3d_device1_GetDirect3D
6504 };
6505
6506 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6507 {
6508     d3d_device_inner_QueryInterface,
6509     d3d_device_inner_AddRef,
6510     d3d_device_inner_Release,
6511 };
6512
6513 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6514 {
6515     if (!iface) return NULL;
6516     assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6517     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6518 }
6519
6520 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6521 {
6522     if (!iface) return NULL;
6523     assert(iface->lpVtbl == &d3d_device3_vtbl);
6524     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6525 }
6526
6527 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6528 {
6529     if (!iface) return NULL;
6530     assert(iface->lpVtbl == &d3d_device2_vtbl);
6531     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6532 }
6533
6534 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6535 {
6536     if (!iface) return NULL;
6537     assert(iface->lpVtbl == &d3d_device1_vtbl);
6538     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6539 }
6540
6541 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6542 {
6543     IDirectDrawSurface7 *depthStencil = NULL;
6544     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6545     struct ddraw_surface *dsi;
6546
6547     IDirectDrawSurface7_GetAttachedSurface(&device->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
6548     if (!depthStencil)
6549     {
6550         TRACE("Setting wined3d depth stencil to NULL\n");
6551         wined3d_device_set_depth_stencil(device->wined3d_device, NULL);
6552         return WINED3D_ZB_FALSE;
6553     }
6554
6555     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6556     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6557     wined3d_device_set_depth_stencil(device->wined3d_device, dsi->wined3d_surface);
6558
6559     IDirectDrawSurface7_Release(depthStencil);
6560     return WINED3D_ZB_TRUE;
6561 }
6562
6563 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
6564         struct ddraw_surface *target, UINT version, IUnknown *outer_unknown)
6565 {
6566     static const D3DMATRIX ident =
6567     {
6568         1.0f, 0.0f, 0.0f, 0.0f,
6569         0.0f, 1.0f, 0.0f, 0.0f,
6570         0.0f, 0.0f, 1.0f, 0.0f,
6571         0.0f, 0.0f, 0.0f, 1.0f,
6572     };
6573     HRESULT hr;
6574
6575     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6576         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6577     else
6578         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6579
6580     device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6581     device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6582     device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6583     device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6584     device->ref = 1;
6585     device->version = version;
6586
6587     if (outer_unknown)
6588         device->outer_unknown = outer_unknown;
6589     else
6590         device->outer_unknown = &device->IUnknown_inner;
6591
6592     device->ddraw = ddraw;
6593     device->target = target;
6594     list_init(&device->viewport_list);
6595
6596     if (!ddraw_handle_table_init(&device->handle_table, 64))
6597     {
6598         ERR("Failed to initialize handle table.\n");
6599         return DDERR_OUTOFMEMORY;
6600     }
6601
6602     device->legacyTextureBlending = FALSE;
6603     device->legacy_projection = ident;
6604     device->legacy_clipspace = ident;
6605
6606     /* Create an index buffer, it's needed for indexed drawing */
6607     hr = wined3d_buffer_create_ib(ddraw->wined3d_device, 0x40000 /* Length. Don't know how long it should be */,
6608             WINED3DUSAGE_DYNAMIC /* Usage */, WINED3D_POOL_DEFAULT, NULL,
6609             &ddraw_null_wined3d_parent_ops, &device->indexbuffer);
6610     if (FAILED(hr))
6611     {
6612         ERR("Failed to create an index buffer, hr %#x.\n", hr);
6613         ddraw_handle_table_destroy(&device->handle_table);
6614         return hr;
6615     }
6616
6617     /* This is for convenience. */
6618     device->wined3d_device = ddraw->wined3d_device;
6619     wined3d_device_incref(ddraw->wined3d_device);
6620
6621     /* Render to the back buffer */
6622     hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6623     if (FAILED(hr))
6624     {
6625         ERR("Failed to set render target, hr %#x.\n", hr);
6626         wined3d_buffer_decref(device->indexbuffer);
6627         ddraw_handle_table_destroy(&device->handle_table);
6628         return hr;
6629     }
6630
6631     /* FIXME: This is broken. The target AddRef() makes some sense, because
6632      * we store a pointer during initialization, but then that's also where
6633      * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
6634     /* AddRef the render target. Also AddRef the render target from ddraw,
6635      * because if it is released before the app releases the D3D device, the
6636      * D3D capabilities of wined3d will be uninitialized, which has bad effects.
6637      *
6638      * In most cases, those surfaces are the same anyway, but this will simply
6639      * add another ref which is released when the device is destroyed. */
6640     if (version != 1)
6641         IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6642
6643     ddraw->d3ddevice = device;
6644
6645     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_ZENABLE,
6646             d3d_device_update_depth_stencil(device));
6647     if (version == 1) /* Color keying is initially enabled for version 1 devices. */
6648         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_COLORKEYENABLE, TRUE);
6649
6650     return D3D_OK;
6651 }
6652
6653 HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
6654         UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6655 {
6656     struct d3d_device *object;
6657     HRESULT hr;
6658
6659     TRACE("ddraw %p, target %p, version %u, device %p, outer_unknown %p.\n",
6660             ddraw, target, version, device, outer_unknown);
6661
6662     if (DefaultSurfaceType != WINED3D_SURFACE_TYPE_OPENGL)
6663     {
6664         ERR_(winediag)("The application wants to create a Direct3D device, "
6665                 "but the current DirectDrawRenderer does not support this.\n");
6666
6667         return DDERR_NO3D;
6668     }
6669
6670     if (ddraw->d3ddevice)
6671     {
6672         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
6673         return DDERR_INVALIDPARAMS;
6674     }
6675
6676     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
6677     if (!object)
6678     {
6679         ERR("Failed to allocate device memory.\n");
6680         return DDERR_OUTOFMEMORY;
6681     }
6682
6683     hr = d3d_device_init(object, ddraw, target, version, outer_unknown);
6684     if (FAILED(hr))
6685     {
6686         WARN("Failed to initialize device, hr %#x.\n", hr);
6687         HeapFree(GetProcessHeap(), 0, object);
6688         return hr;
6689     }
6690
6691     TRACE("Created device %p.\n", object);
6692     *device = object;
6693
6694     return D3D_OK;
6695 }