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