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