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