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