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