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