mscms: Handle errors from lcms more gracefully.
[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);
320         IWineD3DIndexBuffer_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                 WINED3DFORMAT fmt;
2562                 DDPIXELFORMAT ddfmt;
2563
2564                 hr = IWineD3DDevice_GetTexture(This->wineD3DDevice,
2565                                             0,
2566                                             &tex);
2567
2568                 if(hr == WINED3D_OK && tex)
2569                 {
2570                     memset(&desc, 0, sizeof(desc));
2571                     desc.Format = &fmt;
2572                     hr = IWineD3DTexture_GetLevelDesc((IWineD3DTexture*) tex, 0, &desc);
2573                     if (SUCCEEDED(hr))
2574                     {
2575                         ddfmt.dwSize = sizeof(ddfmt);
2576                         PixelFormat_WineD3DtoDD(&ddfmt, fmt);
2577                         if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2578                     }
2579
2580                     IWineD3DBaseTexture_Release(tex);
2581                 }
2582
2583                 if (!(colorop == WINED3DTOP_MODULATE && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT &&
2584                       alphaop == WINED3DTOP_SELECTARG1 && alphaarg1 == (tex_alpha ? WINED3DTA_TEXTURE : WINED3DTA_CURRENT)))
2585                 {
2586                     ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous\n");
2587                 }
2588
2589                 *lpdwRenderState = D3DTBLEND_MODULATE;
2590             }
2591
2592             LeaveCriticalSection(&ddraw_cs);
2593
2594             return D3D_OK;
2595         }
2596
2597         default:
2598             return IDirect3DDevice7_GetRenderState((IDirect3DDevice7 *)This, dwRenderStateType, lpdwRenderState);
2599     }
2600 }
2601
2602 static HRESULT WINAPI
2603 Thunk_IDirect3DDeviceImpl_2_GetRenderState(IDirect3DDevice2 *iface,
2604                                            D3DRENDERSTATETYPE dwRenderStateType,
2605                                            DWORD *lpdwRenderState)
2606 {
2607     IDirect3DDeviceImpl *This = device_from_device2(iface);
2608     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice3 interface.\n", This, dwRenderStateType, lpdwRenderState);
2609     return IDirect3DDevice3_GetRenderState((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
2610             dwRenderStateType, lpdwRenderState);
2611 }
2612
2613 /*****************************************************************************
2614  * IDirect3DDevice7::SetRenderState
2615  *
2616  * Sets a render state. The possible render states are defined in
2617  * include/d3dtypes.h
2618  *
2619  * Version 2, 3 and 7
2620  *
2621  * Params:
2622  *  RenderStateType: State to set
2623  *  Value: Value to assign to that state
2624  *
2625  * Returns:
2626  *  D3D_OK on success,
2627  *  for details see IWineD3DDevice::SetRenderState
2628  *
2629  *****************************************************************************/
2630 static HRESULT
2631 IDirect3DDeviceImpl_7_SetRenderState(IDirect3DDevice7 *iface,
2632                                      D3DRENDERSTATETYPE RenderStateType,
2633                                      DWORD Value)
2634 {
2635     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2636     HRESULT hr;
2637     TRACE("(%p)->(%08x,%d): Relay\n", This, RenderStateType, Value);
2638
2639     EnterCriticalSection(&ddraw_cs);
2640     /* Some render states need special care */
2641     switch(RenderStateType)
2642     {
2643         case D3DRENDERSTATE_TEXTUREMAG:
2644         {
2645             WINED3DTEXTUREFILTERTYPE tex_mag = WINED3DTEXF_NONE;
2646
2647             switch ((D3DTEXTUREFILTER) Value)
2648             {
2649                 case D3DFILTER_NEAREST:
2650                 case D3DFILTER_LINEARMIPNEAREST:
2651                     tex_mag = WINED3DTEXF_POINT;
2652                     break;
2653                 case D3DFILTER_LINEAR:
2654                 case D3DFILTER_LINEARMIPLINEAR:
2655                     tex_mag = WINED3DTEXF_LINEAR;
2656                     break;
2657                 default:
2658                     ERR("Unhandled texture mag %d !\n",Value);
2659             }
2660
2661             hr = IWineD3DDevice_SetSamplerState(This->wineD3DDevice,
2662                                                 0, WINED3DSAMP_MAGFILTER,
2663                                                 tex_mag);
2664             break;
2665         }
2666
2667         case D3DRENDERSTATE_TEXTUREMIN:
2668         {
2669             WINED3DTEXTUREFILTERTYPE tex_min = WINED3DTEXF_NONE;
2670             WINED3DTEXTUREFILTERTYPE tex_mip = WINED3DTEXF_NONE;
2671
2672             switch ((D3DTEXTUREFILTER) Value)
2673             {
2674                 case D3DFILTER_NEAREST:
2675                     tex_min = WINED3DTEXF_POINT;
2676                     break;
2677                 case D3DFILTER_LINEAR:
2678                     tex_min = WINED3DTEXF_LINEAR;
2679                     break;
2680                 case D3DFILTER_MIPNEAREST:
2681                     tex_min = WINED3DTEXF_NONE;
2682                     tex_mip = WINED3DTEXF_POINT;
2683                     break;
2684                 case D3DFILTER_MIPLINEAR:
2685                     tex_min = WINED3DTEXF_NONE;
2686                     tex_mip = WINED3DTEXF_LINEAR;
2687                     break;
2688                 case D3DFILTER_LINEARMIPNEAREST:
2689                     tex_min = WINED3DTEXF_POINT;
2690                     tex_mip = WINED3DTEXF_LINEAR;
2691                     break;
2692                 case D3DFILTER_LINEARMIPLINEAR:
2693                     tex_min = WINED3DTEXF_LINEAR;
2694                     tex_mip = WINED3DTEXF_LINEAR;
2695                     break;
2696
2697                 default:
2698                     ERR("Unhandled texture min %d !\n",Value);
2699             }
2700
2701                    IWineD3DDevice_SetSamplerState(This->wineD3DDevice,
2702                                                   0, WINED3DSAMP_MIPFILTER,
2703                                                   tex_mip);
2704             hr = IWineD3DDevice_SetSamplerState(This->wineD3DDevice,
2705                                                 0, WINED3DSAMP_MINFILTER,
2706                                                 tex_min);
2707             break;
2708         }
2709
2710         case D3DRENDERSTATE_TEXTUREADDRESS:
2711                    IWineD3DDevice_SetSamplerState(This->wineD3DDevice,
2712                                                   0, WINED3DSAMP_ADDRESSV,
2713                                                   Value);
2714             /* Drop through */
2715         case D3DRENDERSTATE_TEXTUREADDRESSU:
2716             hr = IWineD3DDevice_SetSamplerState(This->wineD3DDevice,
2717                                                 0, WINED3DSAMP_ADDRESSU,
2718                                                 Value);
2719             break;
2720         case D3DRENDERSTATE_TEXTUREADDRESSV:
2721             hr = IWineD3DDevice_SetSamplerState(This->wineD3DDevice,
2722                                                 0, WINED3DSAMP_ADDRESSV,
2723                                                 Value);
2724             break;
2725
2726         default:
2727
2728             /* FIXME: Unhandled: D3DRENDERSTATE_STIPPLEPATTERN00 - 31 */
2729
2730             hr = IWineD3DDevice_SetRenderState(This->wineD3DDevice,
2731                                                RenderStateType,
2732                                                Value);
2733             break;
2734     }
2735     LeaveCriticalSection(&ddraw_cs);
2736     return hr;
2737 }
2738
2739 static HRESULT WINAPI
2740 IDirect3DDeviceImpl_7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2741                                      D3DRENDERSTATETYPE RenderStateType,
2742                                      DWORD Value)
2743 {
2744     return IDirect3DDeviceImpl_7_SetRenderState(iface, RenderStateType, Value);
2745 }
2746
2747 static HRESULT WINAPI
2748 IDirect3DDeviceImpl_7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2749                                      D3DRENDERSTATETYPE RenderStateType,
2750                                      DWORD Value)
2751 {
2752     HRESULT hr;
2753     WORD old_fpucw;
2754
2755     old_fpucw = d3d_fpu_setup();
2756     hr = IDirect3DDeviceImpl_7_SetRenderState(iface, RenderStateType, Value);
2757     set_fpu_control_word(old_fpucw);
2758
2759     return hr;
2760 }
2761
2762 static HRESULT WINAPI
2763 IDirect3DDeviceImpl_3_SetRenderState(IDirect3DDevice3 *iface,
2764                                      D3DRENDERSTATETYPE RenderStateType,
2765                                      DWORD Value)
2766 {
2767     /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2768     for this state can be directly mapped to texture stage colorop and alphaop, but
2769     D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2770     from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2771     alphaarg when needed.
2772
2773     Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2774
2775     Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2776     TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2777     are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2778     requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2779     with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2780     in device - TRUE if the app is using TEXTUREMAPBLEND.
2781
2782     Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2783     GetTextureStageState and vice versa. Not so on Wine, but it is 'undefined' anyway so, probably, ok,
2784     unless some broken game will be found that cares. */
2785
2786     HRESULT hr;
2787     IDirect3DDeviceImpl *This = device_from_device3(iface);
2788     TRACE("(%p)->(%08x,%d)\n", This, RenderStateType, Value);
2789
2790     EnterCriticalSection(&ddraw_cs);
2791
2792     switch(RenderStateType)
2793     {
2794         case D3DRENDERSTATE_TEXTUREHANDLE:
2795         {
2796             if(Value == 0)
2797             {
2798                 hr = IWineD3DDevice_SetTexture(This->wineD3DDevice,
2799                                                0,
2800                                                NULL);
2801                 break;
2802             }
2803
2804             if(Value > This->numHandles)
2805             {
2806                 FIXME("Specified handle %d out of range\n", Value);
2807                 hr = DDERR_INVALIDPARAMS;
2808                 break;
2809             }
2810             if(This->Handles[Value - 1].type != DDrawHandle_Texture)
2811             {
2812                 FIXME("Handle %d isn't a texture handle\n", Value);
2813                 hr = DDERR_INVALIDPARAMS;
2814                 break;
2815             }
2816             else
2817             {
2818                 IDirectDrawSurfaceImpl *surf = This->Handles[Value - 1].ptr;
2819                 IDirect3DTexture2 *tex = surf ? (IDirect3DTexture2 *)&surf->IDirect3DTexture2_vtbl : NULL;
2820                 hr = IDirect3DDevice3_SetTexture(iface, 0, tex);
2821                 break;
2822             }
2823         }
2824
2825         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2826         {
2827             This->legacyTextureBlending = TRUE;
2828
2829             switch ( (D3DTEXTUREBLEND) Value)
2830             {
2831                 case D3DTBLEND_MODULATE:
2832                 {
2833                     BOOL tex_alpha = FALSE;
2834                     IWineD3DBaseTexture *tex = NULL;
2835                     WINED3DSURFACE_DESC desc;
2836                     WINED3DFORMAT fmt;
2837                     DDPIXELFORMAT ddfmt;
2838
2839                     hr = IWineD3DDevice_GetTexture(This->wineD3DDevice,
2840                                                 0,
2841                                                 &tex);
2842
2843                     if(hr == WINED3D_OK && tex)
2844                     {
2845                         memset(&desc, 0, sizeof(desc));
2846                         desc.Format = &fmt;
2847                         hr = IWineD3DTexture_GetLevelDesc((IWineD3DTexture*) tex, 0, &desc);
2848                         if (SUCCEEDED(hr))
2849                         {
2850                             ddfmt.dwSize = sizeof(ddfmt);
2851                             PixelFormat_WineD3DtoDD(&ddfmt, fmt);
2852                             if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2853                         }
2854
2855                         IWineD3DBaseTexture_Release(tex);
2856                     }
2857
2858                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1);
2859                     if (tex_alpha)
2860                     {
2861                         IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
2862                     }
2863                     else
2864                     {
2865                         IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_CURRENT);
2866                     }
2867
2868                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2869                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2870                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, WINED3DTOP_MODULATE);
2871
2872                     break;
2873                 }
2874
2875                 case D3DTBLEND_ADD:
2876                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, WINED3DTOP_ADD);
2877                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2878                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2879                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
2880                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG2, WINED3DTA_CURRENT);
2881                     break;
2882
2883                 case D3DTBLEND_MODULATEALPHA:
2884                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2885                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
2886                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2887                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG2, WINED3DTA_CURRENT);
2888                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, WINED3DTOP_MODULATE);
2889                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_MODULATE);
2890                     break;
2891
2892                 case D3DTBLEND_COPY:
2893                 case D3DTBLEND_DECAL:
2894                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2895                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
2896                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, WINED3DTOP_SELECTARG1);
2897                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1);
2898                     break;
2899
2900                 case D3DTBLEND_DECALALPHA:
2901                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, WINED3DTOP_BLENDTEXTUREALPHA);
2902                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2903                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2904                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
2905                     IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG2, WINED3DTA_CURRENT);
2906                     break;
2907
2908                 default:
2909                     ERR("Unhandled texture environment %d !\n",Value);
2910             }
2911
2912             hr = D3D_OK;
2913             break;
2914         }
2915
2916         default:
2917             hr = IDirect3DDevice7_SetRenderState((IDirect3DDevice7 *)This, RenderStateType, Value);
2918             break;
2919     }
2920
2921     LeaveCriticalSection(&ddraw_cs);
2922
2923     return hr;
2924 }
2925
2926 static HRESULT WINAPI
2927 Thunk_IDirect3DDeviceImpl_2_SetRenderState(IDirect3DDevice2 *iface,
2928                                            D3DRENDERSTATETYPE RenderStateType,
2929                                            DWORD Value)
2930 {
2931     IDirect3DDeviceImpl *This = device_from_device2(iface);
2932     TRACE_(ddraw_thunk)("(%p)->(%08x,%d) thunking to IDirect3DDevice3 interface.\n", This, RenderStateType, Value);
2933     return IDirect3DDevice3_SetRenderState((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, RenderStateType, Value);
2934 }
2935
2936 /*****************************************************************************
2937  * Direct3DDevice3::SetLightState
2938  *
2939  * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2940  * light states are forwarded to Direct3DDevice7 render states
2941  *
2942  * Version 2 and 3
2943  *
2944  * Params:
2945  *  LightStateType: The light state to change
2946  *  Value: The value to assign to that light state
2947  *
2948  * Returns:
2949  *  D3D_OK on success
2950  *  DDERR_INVALIDPARAMS if the parameters were incorrect
2951  *  Also check IDirect3DDevice7::SetRenderState
2952  *
2953  *****************************************************************************/
2954 static HRESULT WINAPI
2955 IDirect3DDeviceImpl_3_SetLightState(IDirect3DDevice3 *iface,
2956                                     D3DLIGHTSTATETYPE LightStateType,
2957                                     DWORD Value)
2958 {
2959     IDirect3DDeviceImpl *This = device_from_device3(iface);
2960     HRESULT hr;
2961
2962     TRACE("(%p)->(%08x,%08x)\n", This, LightStateType, Value);
2963
2964     if (!LightStateType && (LightStateType > D3DLIGHTSTATE_COLORVERTEX))
2965     {
2966         TRACE("Unexpected Light State Type\n");
2967         return DDERR_INVALIDPARAMS;
2968     }
2969
2970     EnterCriticalSection(&ddraw_cs);
2971     if (LightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */)
2972     {
2973         IDirect3DMaterialImpl *mat;
2974
2975         if(Value == 0) mat = NULL;
2976         else if(Value > This->numHandles)
2977         {
2978             ERR("Material handle out of range(%d)\n", Value);
2979             LeaveCriticalSection(&ddraw_cs);
2980             return DDERR_INVALIDPARAMS;
2981         }
2982         else if(This->Handles[Value - 1].type != DDrawHandle_Material)
2983         {
2984             ERR("Invalid handle %d\n", Value);
2985             LeaveCriticalSection(&ddraw_cs);
2986             return DDERR_INVALIDPARAMS;
2987         }
2988         else
2989         {
2990             mat = This->Handles[Value - 1].ptr;
2991         }
2992
2993         if (mat != NULL)
2994         {
2995             TRACE(" activating material %p.\n", mat);
2996             mat->activate(mat);
2997         }
2998         else
2999         {
3000             FIXME(" D3DLIGHTSTATE_MATERIAL called with NULL material !!!\n");
3001         }
3002         This->material = Value;
3003     }
3004     else if (LightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */)
3005     {
3006         switch (Value)
3007         {
3008             case D3DCOLOR_MONO:
3009                 ERR("DDCOLOR_MONO should not happen!\n");
3010                 break;
3011             case D3DCOLOR_RGB:
3012                 /* We are already in this mode */
3013                 TRACE("Setting color model to RGB (no-op).\n");
3014                 break;
3015             default:
3016                 ERR("Unknown color model!\n");
3017                 LeaveCriticalSection(&ddraw_cs);
3018                 return DDERR_INVALIDPARAMS;
3019         }
3020     }
3021     else
3022     {
3023         D3DRENDERSTATETYPE rs;
3024         switch (LightStateType)
3025         {
3026             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
3027                 rs = D3DRENDERSTATE_AMBIENT;
3028                 break;          
3029             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
3030                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3031                 break;
3032             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
3033                 rs = D3DRENDERSTATE_FOGSTART;
3034                 break;
3035             case D3DLIGHTSTATE_FOGEND:        /* 6 */
3036                 rs = D3DRENDERSTATE_FOGEND;
3037                 break;
3038             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
3039                 rs = D3DRENDERSTATE_FOGDENSITY;
3040                 break;
3041             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
3042                 rs = D3DRENDERSTATE_COLORVERTEX;
3043                 break;
3044             default:
3045                 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", LightStateType);
3046                 LeaveCriticalSection(&ddraw_cs);
3047                 return DDERR_INVALIDPARAMS;
3048         }
3049
3050         hr = IDirect3DDevice7_SetRenderState((IDirect3DDevice7 *)This, rs, Value);
3051         LeaveCriticalSection(&ddraw_cs);
3052         return hr;
3053     }
3054
3055     LeaveCriticalSection(&ddraw_cs);
3056     return D3D_OK;
3057 }
3058
3059 static HRESULT WINAPI
3060 Thunk_IDirect3DDeviceImpl_2_SetLightState(IDirect3DDevice2 *iface,
3061                                           D3DLIGHTSTATETYPE LightStateType,
3062                                           DWORD Value)
3063 {
3064     IDirect3DDeviceImpl *This = device_from_device2(iface);
3065     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x) thunking to IDirect3DDevice3 interface.\n", This, LightStateType, Value);
3066     return IDirect3DDevice3_SetLightState((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, LightStateType, Value);
3067 }
3068
3069 /*****************************************************************************
3070  * IDirect3DDevice3::GetLightState
3071  *
3072  * Returns the current setting of a light state. The state is read from
3073  * the Direct3DDevice7 render state.
3074  *
3075  * Version 2 and 3
3076  *
3077  * Params:
3078  *  LightStateType: The light state to return
3079  *  Value: The address to store the light state setting at
3080  *
3081  * Returns:
3082  *  D3D_OK on success
3083  *  DDDERR_INVALIDPARAMS if the parameters were incorrect
3084  *  Also see IDirect3DDevice7::GetRenderState
3085  *
3086  *****************************************************************************/
3087 static HRESULT WINAPI
3088 IDirect3DDeviceImpl_3_GetLightState(IDirect3DDevice3 *iface,
3089                                     D3DLIGHTSTATETYPE LightStateType,
3090                                     DWORD *Value)
3091 {
3092     IDirect3DDeviceImpl *This = device_from_device3(iface);
3093     HRESULT hr;
3094
3095     TRACE("(%p)->(%08x,%p)\n", This, LightStateType, Value);
3096
3097     if (!LightStateType && (LightStateType > D3DLIGHTSTATE_COLORVERTEX))
3098     {
3099         TRACE("Unexpected Light State Type\n");
3100         return DDERR_INVALIDPARAMS;
3101     }
3102
3103     if(!Value)
3104         return DDERR_INVALIDPARAMS;
3105
3106     EnterCriticalSection(&ddraw_cs);
3107     if (LightStateType == D3DLIGHTSTATE_MATERIAL /* 1 */)
3108     {
3109         *Value = This->material;
3110     }
3111     else if (LightStateType == D3DLIGHTSTATE_COLORMODEL /* 3 */)
3112     {
3113         *Value = D3DCOLOR_RGB;
3114     }
3115     else
3116     {
3117         D3DRENDERSTATETYPE rs;
3118         switch (LightStateType)
3119         {
3120             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
3121                 rs = D3DRENDERSTATE_AMBIENT;
3122                 break;          
3123             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
3124                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3125                 break;
3126             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
3127                 rs = D3DRENDERSTATE_FOGSTART;
3128                 break;
3129             case D3DLIGHTSTATE_FOGEND:        /* 6 */
3130                 rs = D3DRENDERSTATE_FOGEND;
3131                 break;
3132             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
3133                 rs = D3DRENDERSTATE_FOGDENSITY;
3134                 break;
3135             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
3136                 rs = D3DRENDERSTATE_COLORVERTEX;
3137                 break;
3138             default:
3139                 ERR("Unknown D3DLIGHTSTATETYPE %d.\n", LightStateType);
3140                 LeaveCriticalSection(&ddraw_cs);
3141                 return DDERR_INVALIDPARAMS;
3142         }
3143
3144         hr = IDirect3DDevice7_GetRenderState((IDirect3DDevice7 *)This, rs, Value);
3145         LeaveCriticalSection(&ddraw_cs);
3146         return hr;
3147     }
3148
3149     LeaveCriticalSection(&ddraw_cs);
3150     return D3D_OK;
3151 }
3152
3153 static HRESULT WINAPI
3154 Thunk_IDirect3DDeviceImpl_2_GetLightState(IDirect3DDevice2 *iface,
3155                                           D3DLIGHTSTATETYPE LightStateType,
3156                                           DWORD *Value)
3157 {
3158     IDirect3DDeviceImpl *This = device_from_device2(iface);
3159     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice3 interface.\n", This, LightStateType, Value);
3160     return IDirect3DDevice3_GetLightState((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, LightStateType, Value);
3161 }
3162
3163 /*****************************************************************************
3164  * IDirect3DDevice7::SetTransform
3165  *
3166  * Assigns a D3DMATRIX to a transform type. The transform types are defined
3167  * in include/d3dtypes.h.
3168  * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3169  * (=255) for wined3d, because the 1 transform state was removed in d3d8
3170  * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3171  *
3172  * Version 2, 3 and 7
3173  *
3174  * Params:
3175  *  TransformStateType: transform state to set
3176  *  Matrix: Matrix to assign to the state
3177  *
3178  * Returns:
3179  *  D3D_OK on success
3180  *  DDERR_INVALIDPARAMS if Matrix == NULL
3181  *  For details see IWineD3DDevice::SetTransform
3182  *
3183  *****************************************************************************/
3184 static HRESULT
3185 IDirect3DDeviceImpl_7_SetTransform(IDirect3DDevice7 *iface,
3186                                    D3DTRANSFORMSTATETYPE TransformStateType,
3187                                    D3DMATRIX *Matrix)
3188 {
3189     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3190     D3DTRANSFORMSTATETYPE type;
3191     HRESULT hr;
3192     TRACE("(%p)->(%08x,%p): Relay\n", This, TransformStateType, Matrix);
3193
3194     switch(TransformStateType)
3195     {
3196         case D3DTRANSFORMSTATE_WORLD :  type = WINED3DTS_WORLDMATRIX(0); break;
3197         case D3DTRANSFORMSTATE_WORLD1:  type = WINED3DTS_WORLDMATRIX(1); break;
3198         case D3DTRANSFORMSTATE_WORLD2:  type = WINED3DTS_WORLDMATRIX(2); break;
3199         case D3DTRANSFORMSTATE_WORLD3:  type = WINED3DTS_WORLDMATRIX(3); break;
3200         default:                        type = TransformStateType;
3201     }
3202
3203     if(!Matrix)
3204        return DDERR_INVALIDPARAMS;
3205
3206     /* Note: D3DMATRIX is compatible with WINED3DMATRIX */
3207     EnterCriticalSection(&ddraw_cs);
3208     hr = IWineD3DDevice_SetTransform(This->wineD3DDevice,
3209                                      type,
3210                                      (WINED3DMATRIX*) Matrix);
3211     LeaveCriticalSection(&ddraw_cs);
3212     return hr;
3213 }
3214
3215 static HRESULT WINAPI
3216 IDirect3DDeviceImpl_7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3217                                    D3DTRANSFORMSTATETYPE TransformStateType,
3218                                    D3DMATRIX *Matrix)
3219 {
3220     return IDirect3DDeviceImpl_7_SetTransform(iface, TransformStateType, Matrix);
3221 }
3222
3223 static HRESULT WINAPI
3224 IDirect3DDeviceImpl_7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3225                                    D3DTRANSFORMSTATETYPE TransformStateType,
3226                                    D3DMATRIX *Matrix)
3227 {
3228     HRESULT hr;
3229     WORD old_fpucw;
3230
3231     old_fpucw = d3d_fpu_setup();
3232     hr = IDirect3DDeviceImpl_7_SetTransform(iface, TransformStateType, Matrix);
3233     set_fpu_control_word(old_fpucw);
3234
3235     return hr;
3236 }
3237
3238 static HRESULT WINAPI
3239 Thunk_IDirect3DDeviceImpl_3_SetTransform(IDirect3DDevice3 *iface,
3240                                          D3DTRANSFORMSTATETYPE TransformStateType,
3241                                          D3DMATRIX *D3DMatrix)
3242 {
3243     IDirect3DDeviceImpl *This = device_from_device3(iface);
3244     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, TransformStateType, D3DMatrix);
3245     return IDirect3DDevice7_SetTransform((IDirect3DDevice7 *)This, TransformStateType, D3DMatrix);
3246 }
3247
3248 static HRESULT WINAPI
3249 Thunk_IDirect3DDeviceImpl_2_SetTransform(IDirect3DDevice2 *iface,
3250                                          D3DTRANSFORMSTATETYPE TransformStateType,
3251                                          D3DMATRIX *D3DMatrix)
3252 {
3253     IDirect3DDeviceImpl *This = device_from_device2(iface);
3254     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, TransformStateType, D3DMatrix);
3255     return IDirect3DDevice7_SetTransform((IDirect3DDevice7 *)This, TransformStateType, D3DMatrix);
3256 }
3257
3258 /*****************************************************************************
3259  * IDirect3DDevice7::GetTransform
3260  *
3261  * Returns the matrix assigned to a transform state
3262  * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3263  * SetTransform
3264  *
3265  * Params:
3266  *  TransformStateType: State to read the matrix from
3267  *  Matrix: Address to store the matrix at
3268  *
3269  * Returns:
3270  *  D3D_OK on success
3271  *  DDERR_INVALIDPARAMS if Matrix == NULL
3272  *  For details, see IWineD3DDevice::GetTransform
3273  *
3274  *****************************************************************************/
3275 static HRESULT
3276 IDirect3DDeviceImpl_7_GetTransform(IDirect3DDevice7 *iface,
3277                                    D3DTRANSFORMSTATETYPE TransformStateType,
3278                                    D3DMATRIX *Matrix)
3279 {
3280     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3281     D3DTRANSFORMSTATETYPE type;
3282     HRESULT hr;
3283     TRACE("(%p)->(%08x,%p): Relay\n", This, TransformStateType, Matrix);
3284
3285     switch(TransformStateType)
3286     {
3287         case D3DTRANSFORMSTATE_WORLD :  type = WINED3DTS_WORLDMATRIX(0); break;
3288         case D3DTRANSFORMSTATE_WORLD1:  type = WINED3DTS_WORLDMATRIX(1); break;
3289         case D3DTRANSFORMSTATE_WORLD2:  type = WINED3DTS_WORLDMATRIX(2); break;
3290         case D3DTRANSFORMSTATE_WORLD3:  type = WINED3DTS_WORLDMATRIX(3); break;
3291         default:                        type = TransformStateType;
3292     }
3293
3294     if(!Matrix)
3295         return DDERR_INVALIDPARAMS;
3296
3297     /* Note: D3DMATRIX is compatible with WINED3DMATRIX */
3298     EnterCriticalSection(&ddraw_cs);
3299     hr = IWineD3DDevice_GetTransform(This->wineD3DDevice, type, (WINED3DMATRIX*) Matrix);
3300     LeaveCriticalSection(&ddraw_cs);
3301     return hr;
3302 }
3303
3304 static HRESULT WINAPI
3305 IDirect3DDeviceImpl_7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3306                                    D3DTRANSFORMSTATETYPE TransformStateType,
3307                                    D3DMATRIX *Matrix)
3308 {
3309     return IDirect3DDeviceImpl_7_GetTransform(iface, TransformStateType, Matrix);
3310 }
3311
3312 static HRESULT WINAPI
3313 IDirect3DDeviceImpl_7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3314                                    D3DTRANSFORMSTATETYPE TransformStateType,
3315                                    D3DMATRIX *Matrix)
3316 {
3317     HRESULT hr;
3318     WORD old_fpucw;
3319
3320     old_fpucw = d3d_fpu_setup();
3321     hr = IDirect3DDeviceImpl_7_GetTransform(iface, TransformStateType, Matrix);
3322     set_fpu_control_word(old_fpucw);
3323
3324     return hr;
3325 }
3326
3327 static HRESULT WINAPI
3328 Thunk_IDirect3DDeviceImpl_3_GetTransform(IDirect3DDevice3 *iface,
3329                                          D3DTRANSFORMSTATETYPE TransformStateType,
3330                                          D3DMATRIX *D3DMatrix)
3331 {
3332     IDirect3DDeviceImpl *This = device_from_device3(iface);
3333     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, TransformStateType, D3DMatrix);
3334     return IDirect3DDevice7_GetTransform((IDirect3DDevice7 *)This, TransformStateType, D3DMatrix);
3335 }
3336
3337 static HRESULT WINAPI
3338 Thunk_IDirect3DDeviceImpl_2_GetTransform(IDirect3DDevice2 *iface,
3339                                          D3DTRANSFORMSTATETYPE TransformStateType,
3340                                          D3DMATRIX *D3DMatrix)
3341 {
3342     IDirect3DDeviceImpl *This = device_from_device2(iface);
3343     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, TransformStateType, D3DMatrix);
3344     return IDirect3DDevice7_GetTransform((IDirect3DDevice7 *)This, TransformStateType, D3DMatrix);
3345 }
3346
3347 /*****************************************************************************
3348  * IDirect3DDevice7::MultiplyTransform
3349  *
3350  * Multiplies the already-set transform matrix of a transform state
3351  * with another matrix. For the world matrix, see SetTransform
3352  *
3353  * Version 2, 3 and 7
3354  *
3355  * Params:
3356  *  TransformStateType: Transform state to multiply
3357  *  D3DMatrix Matrix to multiply with.
3358  *
3359  * Returns
3360  *  D3D_OK on success
3361  *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
3362  *  For details, see IWineD3DDevice::MultiplyTransform
3363  *
3364  *****************************************************************************/
3365 static HRESULT
3366 IDirect3DDeviceImpl_7_MultiplyTransform(IDirect3DDevice7 *iface,
3367                                         D3DTRANSFORMSTATETYPE TransformStateType,
3368                                         D3DMATRIX *D3DMatrix)
3369 {
3370     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3371     HRESULT hr;
3372     D3DTRANSFORMSTATETYPE type;
3373     TRACE("(%p)->(%08x,%p): Relay\n", This, TransformStateType, D3DMatrix);
3374
3375     switch(TransformStateType)
3376     {
3377         case D3DTRANSFORMSTATE_WORLD :  type = WINED3DTS_WORLDMATRIX(0); break;
3378         case D3DTRANSFORMSTATE_WORLD1:  type = WINED3DTS_WORLDMATRIX(1); break;
3379         case D3DTRANSFORMSTATE_WORLD2:  type = WINED3DTS_WORLDMATRIX(2); break;
3380         case D3DTRANSFORMSTATE_WORLD3:  type = WINED3DTS_WORLDMATRIX(3); break;
3381         default:                        type = TransformStateType;
3382     }
3383
3384     /* Note: D3DMATRIX is compatible with WINED3DMATRIX */
3385     EnterCriticalSection(&ddraw_cs);
3386     hr = IWineD3DDevice_MultiplyTransform(This->wineD3DDevice,
3387                                           type,
3388                                           (WINED3DMATRIX*) D3DMatrix);
3389     LeaveCriticalSection(&ddraw_cs);
3390     return hr;
3391 }
3392
3393 static HRESULT WINAPI
3394 IDirect3DDeviceImpl_7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3395                                         D3DTRANSFORMSTATETYPE TransformStateType,
3396                                         D3DMATRIX *D3DMatrix)
3397 {
3398     return IDirect3DDeviceImpl_7_MultiplyTransform(iface, TransformStateType, D3DMatrix);
3399 }
3400
3401 static HRESULT WINAPI
3402 IDirect3DDeviceImpl_7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3403                                         D3DTRANSFORMSTATETYPE TransformStateType,
3404                                         D3DMATRIX *D3DMatrix)
3405 {
3406     HRESULT hr;
3407     WORD old_fpucw;
3408
3409     old_fpucw = d3d_fpu_setup();
3410     hr = IDirect3DDeviceImpl_7_MultiplyTransform(iface, TransformStateType, D3DMatrix);
3411     set_fpu_control_word(old_fpucw);
3412
3413     return hr;
3414 }
3415
3416 static HRESULT WINAPI
3417 Thunk_IDirect3DDeviceImpl_3_MultiplyTransform(IDirect3DDevice3 *iface,
3418                                               D3DTRANSFORMSTATETYPE TransformStateType,
3419                                               D3DMATRIX *D3DMatrix)
3420 {
3421     IDirect3DDeviceImpl *This = device_from_device3(iface);
3422     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, TransformStateType, D3DMatrix);
3423     return IDirect3DDevice7_MultiplyTransform((IDirect3DDevice7 *)This, TransformStateType, D3DMatrix);
3424 }
3425
3426 static HRESULT WINAPI
3427 Thunk_IDirect3DDeviceImpl_2_MultiplyTransform(IDirect3DDevice2 *iface,
3428                                               D3DTRANSFORMSTATETYPE TransformStateType,
3429                                               D3DMATRIX *D3DMatrix)
3430 {
3431     IDirect3DDeviceImpl *This = device_from_device2(iface);
3432     TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, TransformStateType, D3DMatrix);
3433     return IDirect3DDevice7_MultiplyTransform((IDirect3DDevice7 *)This, TransformStateType, D3DMatrix);
3434 }
3435
3436 /*****************************************************************************
3437  * IDirect3DDevice7::DrawPrimitive
3438  *
3439  * Draws primitives based on vertices in an application-provided pointer
3440  *
3441  * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3442  * an FVF format for D3D7
3443  *
3444  * Params:
3445  *  PrimitiveType: The type of the primitives to draw
3446  *  Vertex type: Flexible vertex format vertex description
3447  *  Vertices: Pointer to the vertex array
3448  *  VertexCount: The number of vertices to draw
3449  *  Flags: As usual a few flags
3450  *
3451  * Returns:
3452  *  D3D_OK on success
3453  *  DDERR_INVALIDPARAMS if Vertices is NULL
3454  *  For details, see IWineD3DDevice::DrawPrimitiveUP
3455  *
3456  *****************************************************************************/
3457 static HRESULT
3458 IDirect3DDeviceImpl_7_DrawPrimitive(IDirect3DDevice7 *iface,
3459                                     D3DPRIMITIVETYPE PrimitiveType,
3460                                     DWORD VertexType,
3461                                     void *Vertices,
3462                                     DWORD VertexCount,
3463                                     DWORD Flags)
3464 {
3465     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3466     UINT PrimitiveCount, stride;
3467     HRESULT hr;
3468     TRACE("(%p)->(%08x,%08x,%p,%08x,%08x): Relay!\n", This, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3469
3470     if(!Vertices)
3471         return DDERR_INVALIDPARAMS;
3472
3473     /* Get the vertex count */
3474     switch(PrimitiveType)
3475     {
3476       case D3DPT_POINTLIST: 
3477         PrimitiveCount = VertexCount;
3478         break;
3479
3480       case D3DPT_LINELIST: 
3481         PrimitiveCount = VertexCount / 2;
3482         break;
3483
3484       case D3DPT_LINESTRIP:
3485         PrimitiveCount = VertexCount - 1;
3486         break;
3487
3488       case D3DPT_TRIANGLELIST:
3489         PrimitiveCount = VertexCount / 3;
3490         break;
3491
3492       case D3DPT_TRIANGLESTRIP:
3493         PrimitiveCount = VertexCount - 2;
3494         break;
3495
3496       case D3DPT_TRIANGLEFAN:
3497         PrimitiveCount = VertexCount - 2;
3498         break;
3499
3500       default:
3501         return DDERR_INVALIDPARAMS;
3502     }
3503
3504     /* Get the stride */
3505     stride = get_flexible_vertex_size(VertexType);
3506
3507     /* Set the FVF */
3508     EnterCriticalSection(&ddraw_cs);
3509     hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice,
3510                                              IDirectDrawImpl_FindDecl(This->ddraw, VertexType));
3511     if(hr != D3D_OK)
3512     {
3513         LeaveCriticalSection(&ddraw_cs);
3514         return hr;
3515     }
3516
3517     /* This method translates to the user pointer draw of WineD3D */
3518     hr = IWineD3DDevice_DrawPrimitiveUP(This->wineD3DDevice,
3519                                         PrimitiveType,
3520                                         PrimitiveCount,
3521                                         Vertices,
3522                                         stride);
3523     LeaveCriticalSection(&ddraw_cs);
3524     return hr;
3525 }
3526
3527 static HRESULT WINAPI
3528 IDirect3DDeviceImpl_7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3529                                     D3DPRIMITIVETYPE PrimitiveType,
3530                                     DWORD VertexType,
3531                                     void *Vertices,
3532                                     DWORD VertexCount,
3533                                     DWORD Flags)
3534 {
3535     return IDirect3DDeviceImpl_7_DrawPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3536 }
3537
3538 static HRESULT WINAPI
3539 IDirect3DDeviceImpl_7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3540                                     D3DPRIMITIVETYPE PrimitiveType,
3541                                     DWORD VertexType,
3542                                     void *Vertices,
3543                                     DWORD VertexCount,
3544                                     DWORD Flags)
3545 {
3546     HRESULT hr;
3547     WORD old_fpucw;
3548
3549     old_fpucw = d3d_fpu_setup();
3550     hr = IDirect3DDeviceImpl_7_DrawPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3551     set_fpu_control_word(old_fpucw);
3552
3553     return hr;
3554 }
3555
3556 static HRESULT WINAPI
3557 Thunk_IDirect3DDeviceImpl_3_DrawPrimitive(IDirect3DDevice3 *iface,
3558                                           D3DPRIMITIVETYPE PrimitiveType,
3559                                           DWORD VertexType,
3560                                           void *Vertices,
3561                                           DWORD VertexCount,
3562                                           DWORD Flags)
3563 {
3564     IDirect3DDeviceImpl *This = device_from_device3(iface);
3565     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3566     return IDirect3DDevice7_DrawPrimitive((IDirect3DDevice7 *)This,
3567             PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3568 }
3569
3570 static HRESULT WINAPI
3571 Thunk_IDirect3DDeviceImpl_2_DrawPrimitive(IDirect3DDevice2 *iface,
3572                                           D3DPRIMITIVETYPE PrimitiveType,
3573                                           D3DVERTEXTYPE VertexType,
3574                                           void *Vertices,
3575                                           DWORD VertexCount,
3576                                           DWORD Flags)
3577 {
3578     IDirect3DDeviceImpl *This = device_from_device2(iface);
3579     DWORD FVF;
3580     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3581
3582     switch(VertexType)
3583     {
3584         case D3DVT_VERTEX: FVF = D3DFVF_VERTEX; break;
3585         case D3DVT_LVERTEX: FVF = D3DFVF_LVERTEX; break;
3586         case D3DVT_TLVERTEX: FVF = D3DFVF_TLVERTEX; break;
3587         default:
3588             ERR("Unexpected vertex type %d\n", VertexType);
3589             return DDERR_INVALIDPARAMS;  /* Should never happen */
3590     }
3591
3592     return IDirect3DDevice7_DrawPrimitive((IDirect3DDevice7 *)This, PrimitiveType, FVF, Vertices, VertexCount, Flags);
3593 }
3594
3595 /*****************************************************************************
3596  * IDirect3DDevice7::DrawIndexedPrimitive
3597  *
3598  * Draws vertices from an application-provided pointer, based on the index
3599  * numbers in a WORD array.
3600  *
3601  * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3602  * an FVF format for D3D7
3603  *
3604  * Params:
3605  *  PrimitiveType: The primitive type to draw
3606  *  VertexType: The FVF vertex description
3607  *  Vertices: Pointer to the vertex array
3608  *  VertexCount: ?
3609  *  Indices: Pointer to the index array
3610  *  IndexCount: Number of indices = Number of vertices to draw
3611  *  Flags: As usual, some flags
3612  *
3613  * Returns:
3614  *  D3D_OK on success
3615  *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3616  *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
3617  *
3618  *****************************************************************************/
3619 static HRESULT
3620 IDirect3DDeviceImpl_7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3621                                            D3DPRIMITIVETYPE PrimitiveType,
3622                                            DWORD VertexType,
3623                                            void *Vertices,
3624                                            DWORD VertexCount,
3625                                            WORD *Indices,
3626                                            DWORD IndexCount,
3627                                            DWORD Flags)
3628 {
3629     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3630     UINT PrimitiveCount = 0;
3631     HRESULT hr;
3632     TRACE("(%p)->(%08x,%08x,%p,%08x,%p,%08x,%08x): Relay!\n", This, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3633
3634     /* Get the primitive number */
3635     switch(PrimitiveType)
3636     {
3637       case D3DPT_POINTLIST: 
3638         PrimitiveCount = IndexCount;
3639         break;
3640
3641       case D3DPT_LINELIST: 
3642         PrimitiveCount = IndexCount / 2;
3643         break;
3644
3645       case D3DPT_LINESTRIP:
3646         PrimitiveCount = IndexCount - 1;
3647         break;
3648
3649       case D3DPT_TRIANGLELIST:
3650         PrimitiveCount = IndexCount / 3;
3651         break;
3652
3653       case D3DPT_TRIANGLESTRIP:
3654         PrimitiveCount = IndexCount - 2;
3655         break;
3656
3657       case D3DPT_TRIANGLEFAN:
3658         PrimitiveCount = IndexCount - 2;
3659         break;
3660
3661       default:
3662         return DDERR_INVALIDPARAMS;
3663     }
3664
3665     /* Set the D3DDevice's FVF */
3666     EnterCriticalSection(&ddraw_cs);
3667     hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice,
3668                                              IDirectDrawImpl_FindDecl(This->ddraw, VertexType));
3669     if(FAILED(hr))
3670     {
3671         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
3672         LeaveCriticalSection(&ddraw_cs);
3673         return hr;
3674     }
3675
3676     hr = IWineD3DDevice_DrawIndexedPrimitiveUP(This->wineD3DDevice, PrimitiveType, 0 /* MinVertexIndex */,
3677             VertexCount /* UINT NumVertexIndex */, PrimitiveCount, Indices, WINED3DFMT_R16_UINT, Vertices,
3678             get_flexible_vertex_size(VertexType));
3679     LeaveCriticalSection(&ddraw_cs);
3680     return hr;
3681 }
3682
3683 static HRESULT WINAPI
3684 IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3685                                            D3DPRIMITIVETYPE PrimitiveType,
3686                                            DWORD VertexType,
3687                                            void *Vertices,
3688                                            DWORD VertexCount,
3689                                            WORD *Indices,
3690                                            DWORD IndexCount,
3691                                            DWORD Flags)
3692 {
3693     return IDirect3DDeviceImpl_7_DrawIndexedPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3694 }
3695
3696 static HRESULT WINAPI
3697 IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3698                                            D3DPRIMITIVETYPE PrimitiveType,
3699                                            DWORD VertexType,
3700                                            void *Vertices,
3701                                            DWORD VertexCount,
3702                                            WORD *Indices,
3703                                            DWORD IndexCount,
3704                                            DWORD Flags)
3705 {
3706     HRESULT hr;
3707     WORD old_fpucw;
3708
3709     old_fpucw = d3d_fpu_setup();
3710     hr = IDirect3DDeviceImpl_7_DrawIndexedPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3711     set_fpu_control_word(old_fpucw);
3712
3713     return hr;
3714 }
3715
3716 static HRESULT WINAPI
3717 Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3718                                                  D3DPRIMITIVETYPE PrimitiveType,
3719                                                  DWORD VertexType,
3720                                                  void *Vertices,
3721                                                  DWORD VertexCount,
3722                                                  WORD *Indices,
3723                                                  DWORD IndexCount,
3724                                                  DWORD Flags)
3725 {
3726     IDirect3DDeviceImpl *This = device_from_device3(iface);
3727     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p,%08x,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3728     return IDirect3DDevice7_DrawIndexedPrimitive((IDirect3DDevice7 *)This,
3729             PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3730 }
3731
3732 static HRESULT WINAPI
3733 Thunk_IDirect3DDeviceImpl_2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3734                                                  D3DPRIMITIVETYPE PrimitiveType,
3735                                                  D3DVERTEXTYPE VertexType,
3736                                                  void *Vertices,
3737                                                  DWORD VertexCount,
3738                                                  WORD *Indices,
3739                                                  DWORD IndexCount,
3740                                                  DWORD Flags)
3741 {
3742     DWORD FVF;
3743     IDirect3DDeviceImpl *This = device_from_device2(iface);
3744     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p,%08x,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3745
3746     switch(VertexType)
3747     {
3748         case D3DVT_VERTEX: FVF = D3DFVF_VERTEX; break;
3749         case D3DVT_LVERTEX: FVF = D3DFVF_LVERTEX; break;
3750         case D3DVT_TLVERTEX: FVF = D3DFVF_TLVERTEX; break;
3751         default:
3752             ERR("Unexpected vertex type %d\n", VertexType);
3753             return DDERR_INVALIDPARAMS;  /* Should never happen */
3754     }
3755
3756     return IDirect3DDevice7_DrawIndexedPrimitive((IDirect3DDevice7 *)This,
3757             PrimitiveType, FVF, Vertices, VertexCount, Indices, IndexCount, Flags);
3758 }
3759
3760 /*****************************************************************************
3761  * IDirect3DDevice7::SetClipStatus
3762  *
3763  * Sets the clip status. This defines things as clipping conditions and
3764  * the extents of the clipping region.
3765  *
3766  * Version 2, 3 and 7
3767  *
3768  * Params:
3769  *  ClipStatus:
3770  *
3771  * Returns:
3772  *  D3D_OK because it's a stub
3773  *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3774  *
3775  *****************************************************************************/
3776 static HRESULT WINAPI
3777 IDirect3DDeviceImpl_7_SetClipStatus(IDirect3DDevice7 *iface,
3778                                     D3DCLIPSTATUS *ClipStatus)
3779 {
3780     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3781     FIXME("(%p)->(%p): Stub!\n", This, ClipStatus);
3782
3783     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
3784      * Perhaps this needs a new data type and an additional IWineD3DDevice method
3785      */
3786     /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
3787     return D3D_OK;
3788 }
3789
3790 static HRESULT WINAPI
3791 Thunk_IDirect3DDeviceImpl_3_SetClipStatus(IDirect3DDevice3 *iface,
3792                                           D3DCLIPSTATUS *ClipStatus)
3793 {
3794     IDirect3DDeviceImpl *This = device_from_device3(iface);
3795     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice7 interface.\n", This, ClipStatus);
3796     return IDirect3DDevice7_SetClipStatus((IDirect3DDevice7 *)This, ClipStatus);
3797 }
3798
3799 static HRESULT WINAPI
3800 Thunk_IDirect3DDeviceImpl_2_SetClipStatus(IDirect3DDevice2 *iface,
3801                                           D3DCLIPSTATUS *ClipStatus)
3802 {
3803     IDirect3DDeviceImpl *This = device_from_device2(iface);
3804     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice7 interface.\n", This, ClipStatus);
3805     return IDirect3DDevice7_SetClipStatus((IDirect3DDevice7 *)This, ClipStatus);
3806 }
3807
3808 /*****************************************************************************
3809  * IDirect3DDevice7::GetClipStatus
3810  *
3811  * Returns the clip status
3812  *
3813  * Params:
3814  *  ClipStatus: Address to write the clip status to
3815  *
3816  * Returns:
3817  *  D3D_OK because it's a stub
3818  *
3819  *****************************************************************************/
3820 static HRESULT WINAPI
3821 IDirect3DDeviceImpl_7_GetClipStatus(IDirect3DDevice7 *iface,
3822                                     D3DCLIPSTATUS *ClipStatus)
3823 {
3824     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3825     FIXME("(%p)->(%p): Stub!\n", This, ClipStatus);
3826
3827     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
3828     /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
3829     return D3D_OK;
3830 }
3831
3832 static HRESULT WINAPI
3833 Thunk_IDirect3DDeviceImpl_3_GetClipStatus(IDirect3DDevice3 *iface,
3834                                           D3DCLIPSTATUS *ClipStatus)
3835 {
3836     IDirect3DDeviceImpl *This = device_from_device3(iface);
3837     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice7 interface.\n", This, ClipStatus);
3838     return IDirect3DDevice7_GetClipStatus((IDirect3DDevice7 *)This, ClipStatus);
3839 }
3840
3841 static HRESULT WINAPI
3842 Thunk_IDirect3DDeviceImpl_2_GetClipStatus(IDirect3DDevice2 *iface,
3843                                           D3DCLIPSTATUS *ClipStatus)
3844 {
3845     IDirect3DDeviceImpl *This = device_from_device2(iface);
3846     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice7 interface.\n", This, ClipStatus);
3847     return IDirect3DDevice7_GetClipStatus((IDirect3DDevice7 *)This, ClipStatus);
3848 }
3849
3850 /*****************************************************************************
3851  * IDirect3DDevice::DrawPrimitiveStrided
3852  *
3853  * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3854  *
3855  * Version 3 and 7
3856  *
3857  * Params:
3858  *  PrimitiveType: The primitive type to draw
3859  *  VertexType: The FVF description of the vertices to draw (for the stride??)
3860  *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3861  *                         the vertex data locations
3862  *  VertexCount: The number of vertices to draw
3863  *  Flags: Some flags
3864  *
3865  * Returns:
3866  *  D3D_OK, because it's a stub
3867  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3868  *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
3869  *
3870  *****************************************************************************/
3871 static HRESULT
3872 IDirect3DDeviceImpl_7_DrawPrimitiveStrided(IDirect3DDevice7 *iface,
3873                                            D3DPRIMITIVETYPE PrimitiveType,
3874                                            DWORD VertexType,
3875                                            D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3876                                            DWORD VertexCount,
3877                                            DWORD Flags)
3878 {
3879     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
3880     WineDirect3DVertexStridedData WineD3DStrided;
3881     DWORD i;
3882     UINT PrimitiveCount;
3883     HRESULT hr;
3884
3885     TRACE("(%p)->(%08x,%08x,%p,%08x,%08x): stub!\n", This, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3886
3887     memset(&WineD3DStrided, 0, sizeof(WineD3DStrided));
3888     /* Get the strided data right. the wined3d structure is a bit bigger
3889      * Watch out: The contents of the strided data are determined by the fvf,
3890      * not by the members set in D3DDrawPrimStrideData. So it's valid
3891      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3892      * not set in the fvf.
3893      */
3894     if(VertexType & D3DFVF_POSITION_MASK)
3895     {
3896         WineD3DStrided.u.s.position.lpData = D3DDrawPrimStrideData->position.lpvData;
3897         WineD3DStrided.u.s.position.dwStride = D3DDrawPrimStrideData->position.dwStride;
3898         WineD3DStrided.u.s.position.dwType = WINED3DDECLTYPE_FLOAT3;
3899         if (VertexType & D3DFVF_XYZRHW)
3900         {
3901             WineD3DStrided.u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
3902             WineD3DStrided.position_transformed = TRUE;
3903         } else
3904             WineD3DStrided.position_transformed = FALSE;
3905     }
3906
3907     if(VertexType & D3DFVF_NORMAL)
3908     {
3909         WineD3DStrided.u.s.normal.lpData = D3DDrawPrimStrideData->normal.lpvData;
3910         WineD3DStrided.u.s.normal.dwStride = D3DDrawPrimStrideData->normal.dwStride;
3911         WineD3DStrided.u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3;
3912     }
3913
3914     if(VertexType & D3DFVF_DIFFUSE)
3915     {
3916         WineD3DStrided.u.s.diffuse.lpData = D3DDrawPrimStrideData->diffuse.lpvData;
3917         WineD3DStrided.u.s.diffuse.dwStride = D3DDrawPrimStrideData->diffuse.dwStride;
3918         WineD3DStrided.u.s.diffuse.dwType = WINED3DDECLTYPE_D3DCOLOR;
3919     }
3920
3921     if(VertexType & D3DFVF_SPECULAR)
3922     {
3923         WineD3DStrided.u.s.specular.lpData = D3DDrawPrimStrideData->specular.lpvData;
3924         WineD3DStrided.u.s.specular.dwStride = D3DDrawPrimStrideData->specular.dwStride;
3925         WineD3DStrided.u.s.specular.dwType = WINED3DDECLTYPE_D3DCOLOR;
3926     }
3927
3928     for( i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); i++)
3929     {
3930         WineD3DStrided.u.s.texCoords[i].lpData = D3DDrawPrimStrideData->textureCoords[i].lpvData;
3931         WineD3DStrided.u.s.texCoords[i].dwStride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3932         switch(GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3933         {
3934             case 1: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT1; break;
3935             case 2: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT2; break;
3936             case 3: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT3; break;
3937             case 4: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT4; break;
3938             default: ERR("Unexpected texture coordinate size %d\n",
3939                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
3940         }
3941     }
3942
3943     /* Get the primitive count */
3944     switch(PrimitiveType)
3945     {
3946         case D3DPT_POINTLIST: 
3947           PrimitiveCount = VertexCount;
3948           break;
3949
3950         case D3DPT_LINELIST: 
3951           PrimitiveCount = VertexCount / 2;
3952           break;
3953
3954         case D3DPT_LINESTRIP:
3955           PrimitiveCount = VertexCount - 1;
3956           break;
3957
3958         case D3DPT_TRIANGLELIST:
3959           PrimitiveCount = VertexCount / 3;
3960           break;
3961
3962         case D3DPT_TRIANGLESTRIP:
3963           PrimitiveCount = VertexCount - 2;
3964           break;
3965
3966         case D3DPT_TRIANGLEFAN:
3967           PrimitiveCount = VertexCount - 2;
3968           break;
3969
3970         default: return DDERR_INVALIDPARAMS;
3971     }
3972
3973     /* WineD3D doesn't need the FVF here */
3974     EnterCriticalSection(&ddraw_cs);
3975     hr = IWineD3DDevice_DrawPrimitiveStrided(This->wineD3DDevice,
3976                                              PrimitiveType,
3977                                              PrimitiveCount,
3978                                              &WineD3DStrided);
3979     LeaveCriticalSection(&ddraw_cs);
3980     return hr;
3981 }
3982
3983 static HRESULT WINAPI
3984 IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3985                                            D3DPRIMITIVETYPE PrimitiveType,
3986                                            DWORD VertexType,
3987                                            D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3988                                            DWORD VertexCount,
3989                                            DWORD Flags)
3990 {
3991     return IDirect3DDeviceImpl_7_DrawPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3992 }
3993
3994 static HRESULT WINAPI
3995 IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3996                                            D3DPRIMITIVETYPE PrimitiveType,
3997                                            DWORD VertexType,
3998                                            D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3999                                            DWORD VertexCount,
4000                                            DWORD Flags)
4001 {
4002     HRESULT hr;
4003     WORD old_fpucw;
4004
4005     old_fpucw = d3d_fpu_setup();
4006     hr = IDirect3DDeviceImpl_7_DrawPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4007     set_fpu_control_word(old_fpucw);
4008
4009     return hr;
4010 }
4011
4012 static HRESULT WINAPI
4013 Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
4014                                                  D3DPRIMITIVETYPE PrimitiveType,
4015                                                  DWORD VertexType,
4016                                                  D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4017                                                  DWORD VertexCount,
4018                                                  DWORD Flags)
4019 {
4020     IDirect3DDeviceImpl *This = device_from_device3(iface);
4021     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4022     return IDirect3DDevice7_DrawPrimitiveStrided((IDirect3DDevice7 *)This,
4023             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4024 }
4025
4026 /*****************************************************************************
4027  * IDirect3DDevice7::DrawIndexedPrimitiveStrided
4028  *
4029  * Draws primitives specified by strided data locations based on indices
4030  *
4031  * Version 3 and 7
4032  *
4033  * Params:
4034  *  PrimitiveType:
4035  *
4036  * Returns:
4037  *  D3D_OK, because it's a stub
4038  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
4039  *  (DDERR_INVALIDPARAMS if Indices is NULL)
4040  *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
4041  *
4042  *****************************************************************************/
4043 static HRESULT
4044 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
4045                                                   D3DPRIMITIVETYPE PrimitiveType,
4046                                                   DWORD VertexType,
4047                                                   D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4048                                                   DWORD VertexCount,
4049                                                   WORD *Indices,
4050                                                   DWORD IndexCount,
4051                                                   DWORD Flags)
4052 {
4053     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4054     WineDirect3DVertexStridedData WineD3DStrided;
4055     DWORD i;
4056     UINT PrimitiveCount;
4057     HRESULT hr;
4058
4059     TRACE("(%p)->(%08x,%08x,%p,%08x,%p,%08x,%08x)\n", This, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4060
4061     memset(&WineD3DStrided, 0, sizeof(WineD3DStrided));
4062     /* Get the strided data right. the wined3d structure is a bit bigger
4063      * Watch out: The contents of the strided data are determined by the fvf,
4064      * not by the members set in D3DDrawPrimStrideData. So it's valid
4065      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
4066      * not set in the fvf.
4067      */
4068     if(VertexType & D3DFVF_POSITION_MASK)
4069     {
4070         WineD3DStrided.u.s.position.lpData = D3DDrawPrimStrideData->position.lpvData;
4071         WineD3DStrided.u.s.position.dwStride = D3DDrawPrimStrideData->position.dwStride;
4072         WineD3DStrided.u.s.position.dwType = WINED3DDECLTYPE_FLOAT3;
4073         if (VertexType & D3DFVF_XYZRHW)
4074         {
4075             WineD3DStrided.u.s.position.dwType = WINED3DDECLTYPE_FLOAT4;
4076             WineD3DStrided.position_transformed = TRUE;
4077         } else
4078             WineD3DStrided.position_transformed = FALSE;
4079     }
4080
4081     if(VertexType & D3DFVF_NORMAL)
4082     {
4083         WineD3DStrided.u.s.normal.lpData = D3DDrawPrimStrideData->normal.lpvData;
4084         WineD3DStrided.u.s.normal.dwStride = D3DDrawPrimStrideData->normal.dwStride;
4085         WineD3DStrided.u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3;
4086     }
4087
4088     if(VertexType & D3DFVF_DIFFUSE)
4089     {
4090         WineD3DStrided.u.s.diffuse.lpData = D3DDrawPrimStrideData->diffuse.lpvData;
4091         WineD3DStrided.u.s.diffuse.dwStride = D3DDrawPrimStrideData->diffuse.dwStride;
4092         WineD3DStrided.u.s.diffuse.dwType = WINED3DDECLTYPE_D3DCOLOR;
4093     }
4094
4095     if(VertexType & D3DFVF_SPECULAR)
4096     {
4097         WineD3DStrided.u.s.specular.lpData = D3DDrawPrimStrideData->specular.lpvData;
4098         WineD3DStrided.u.s.specular.dwStride = D3DDrawPrimStrideData->specular.dwStride;
4099         WineD3DStrided.u.s.specular.dwType = WINED3DDECLTYPE_D3DCOLOR;
4100     }
4101
4102     for( i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); i++)
4103     {
4104         WineD3DStrided.u.s.texCoords[i].lpData = D3DDrawPrimStrideData->textureCoords[i].lpvData;
4105         WineD3DStrided.u.s.texCoords[i].dwStride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
4106         switch(GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
4107         {
4108             case 1: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT1; break;
4109             case 2: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT2; break;
4110             case 3: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT3; break;
4111             case 4: WineD3DStrided.u.s.texCoords[i].dwType = WINED3DDECLTYPE_FLOAT4; break;
4112             default: ERR("Unexpected texture coordinate size %d\n",
4113                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
4114         }
4115     }
4116
4117     /* Get the primitive count */
4118     switch(PrimitiveType)
4119     {
4120         case D3DPT_POINTLIST:
4121             PrimitiveCount = IndexCount;
4122             break;
4123
4124         case D3DPT_LINELIST:
4125             PrimitiveCount = IndexCount / 2;
4126             break;
4127
4128         case D3DPT_LINESTRIP:
4129             PrimitiveCount = IndexCount - 1;
4130             break;
4131
4132         case D3DPT_TRIANGLELIST:
4133             PrimitiveCount = IndexCount / 3;
4134             break;
4135
4136         case D3DPT_TRIANGLESTRIP:
4137             PrimitiveCount = IndexCount - 2;
4138             break;
4139
4140         case D3DPT_TRIANGLEFAN:
4141             PrimitiveCount = IndexCount - 2;
4142             break;
4143
4144             default: return DDERR_INVALIDPARAMS;
4145     }
4146
4147     /* WineD3D doesn't need the FVF here */
4148     EnterCriticalSection(&ddraw_cs);
4149     hr = IWineD3DDevice_DrawIndexedPrimitiveStrided(This->wineD3DDevice, PrimitiveType,
4150             PrimitiveCount, &WineD3DStrided, VertexCount, Indices, WINED3DFMT_R16_UINT);
4151     LeaveCriticalSection(&ddraw_cs);
4152     return hr;
4153 }
4154
4155 static HRESULT WINAPI
4156 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4157                                                   D3DPRIMITIVETYPE PrimitiveType,
4158                                                   DWORD VertexType,
4159                                                   D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4160                                                   DWORD VertexCount,
4161                                                   WORD *Indices,
4162                                                   DWORD IndexCount,
4163                                                   DWORD Flags)
4164 {
4165     return IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4166 }
4167
4168 static HRESULT WINAPI
4169 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4170                                                   D3DPRIMITIVETYPE PrimitiveType,
4171                                                   DWORD VertexType,
4172                                                   D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4173                                                   DWORD VertexCount,
4174                                                   WORD *Indices,
4175                                                   DWORD IndexCount,
4176                                                   DWORD Flags)
4177 {
4178     HRESULT hr;
4179     WORD old_fpucw;
4180
4181     old_fpucw = d3d_fpu_setup();
4182     hr = IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4183     set_fpu_control_word(old_fpucw);
4184
4185     return hr;
4186 }
4187
4188 static HRESULT WINAPI
4189 Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4190                                                         D3DPRIMITIVETYPE PrimitiveType,
4191                                                         DWORD VertexType,
4192                                                         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4193                                                         DWORD VertexCount,
4194                                                         WORD *Indices,
4195                                                         DWORD IndexCount,
4196                                                         DWORD Flags)
4197 {
4198     IDirect3DDeviceImpl *This = device_from_device3(iface);
4199     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p,%08x,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4200     return IDirect3DDevice7_DrawIndexedPrimitiveStrided((IDirect3DDevice7 *)This, PrimitiveType,
4201             VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4202 }
4203
4204 /*****************************************************************************
4205  * IDirect3DDevice7::DrawPrimitiveVB
4206  *
4207  * Draws primitives from a vertex buffer to the screen.
4208  *
4209  * Version 3 and 7
4210  *
4211  * Params:
4212  *  PrimitiveType: Type of primitive to be rendered.
4213  *  D3DVertexBuf: Source Vertex Buffer
4214  *  StartVertex: Index of the first vertex from the buffer to be rendered
4215  *  NumVertices: Number of vertices to be rendered
4216  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4217  *
4218  * Return values
4219  *  D3D_OK on success
4220  *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4221  *
4222  *****************************************************************************/
4223 static HRESULT
4224 IDirect3DDeviceImpl_7_DrawPrimitiveVB(IDirect3DDevice7 *iface,
4225                                       D3DPRIMITIVETYPE PrimitiveType,
4226                                       IDirect3DVertexBuffer7 *D3DVertexBuf,
4227                                       DWORD StartVertex,
4228                                       DWORD NumVertices,
4229                                       DWORD Flags)
4230 {
4231     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4232     IDirect3DVertexBufferImpl *vb = (IDirect3DVertexBufferImpl *)D3DVertexBuf;
4233     UINT PrimitiveCount;
4234     HRESULT hr;
4235     DWORD stride;
4236     WINED3DVERTEXBUFFER_DESC Desc;
4237
4238     TRACE("(%p)->(%08x,%p,%08x,%08x,%08x)\n", This, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4239
4240     /* Sanity checks */
4241     if(!vb)
4242     {
4243         ERR("(%p) No Vertex buffer specified\n", This);
4244         return DDERR_INVALIDPARAMS;
4245     }
4246
4247     /* Get the primitive count */
4248     switch(PrimitiveType)
4249     {
4250         case D3DPT_POINTLIST: 
4251           PrimitiveCount = NumVertices;
4252           break;
4253
4254         case D3DPT_LINELIST: 
4255           PrimitiveCount = NumVertices / 2;
4256           break;
4257
4258         case D3DPT_LINESTRIP:
4259           PrimitiveCount = NumVertices - 1;
4260           break;
4261
4262         case D3DPT_TRIANGLELIST:
4263           PrimitiveCount = NumVertices / 3;
4264           break;
4265
4266         case D3DPT_TRIANGLESTRIP:
4267           PrimitiveCount = NumVertices - 2;
4268           break;
4269
4270         case D3DPT_TRIANGLEFAN:
4271           PrimitiveCount = NumVertices - 2;
4272           break;
4273
4274         default:
4275           return DDERR_INVALIDPARAMS;
4276     }
4277
4278     /* Get the FVF of the vertex buffer, and its stride */
4279     EnterCriticalSection(&ddraw_cs);
4280     hr = IWineD3DVertexBuffer_GetDesc(vb->wineD3DVertexBuffer,
4281                                       &Desc);
4282     if(hr != D3D_OK)
4283     {
4284         ERR("(%p) IWineD3DVertexBuffer::GetDesc failed with hr = %08x\n", This, hr);
4285         LeaveCriticalSection(&ddraw_cs);
4286         return hr;
4287     }
4288     stride = get_flexible_vertex_size(Desc.FVF);
4289
4290     hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice,
4291                                              vb->wineD3DVertexDeclaration);
4292     if(FAILED(hr))
4293     {
4294         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
4295         LeaveCriticalSection(&ddraw_cs);
4296         return hr;
4297     }
4298
4299     /* Set the vertex stream source */
4300     hr = IWineD3DDevice_SetStreamSource(This->wineD3DDevice,
4301                                         0 /* StreamNumber */,
4302                                         vb->wineD3DVertexBuffer,
4303                                         0 /* StartVertex - we pass this to DrawPrimitive */,
4304                                         stride);
4305     if(hr != D3D_OK)
4306     {
4307         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4308         LeaveCriticalSection(&ddraw_cs);
4309         return hr;
4310     }
4311
4312     /* Now draw the primitives */
4313     hr = IWineD3DDevice_DrawPrimitive(This->wineD3DDevice,
4314                                       PrimitiveType,
4315                                       StartVertex,
4316                                       PrimitiveCount);
4317     LeaveCriticalSection(&ddraw_cs);
4318     return hr;
4319 }
4320
4321 static HRESULT WINAPI
4322 IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4323                                       D3DPRIMITIVETYPE PrimitiveType,
4324                                       IDirect3DVertexBuffer7 *D3DVertexBuf,
4325                                       DWORD StartVertex,
4326                                       DWORD NumVertices,
4327                                       DWORD Flags)
4328 {
4329     return IDirect3DDeviceImpl_7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4330 }
4331
4332 static HRESULT WINAPI
4333 IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4334                                       D3DPRIMITIVETYPE PrimitiveType,
4335                                       IDirect3DVertexBuffer7 *D3DVertexBuf,
4336                                       DWORD StartVertex,
4337                                       DWORD NumVertices,
4338                                       DWORD Flags)
4339 {
4340     HRESULT hr;
4341     WORD old_fpucw;
4342
4343     old_fpucw = d3d_fpu_setup();
4344     hr = IDirect3DDeviceImpl_7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4345     set_fpu_control_word(old_fpucw);
4346
4347     return hr;
4348 }
4349
4350 static HRESULT WINAPI
4351 Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB(IDirect3DDevice3 *iface,
4352                                             D3DPRIMITIVETYPE PrimitiveType,
4353                                             IDirect3DVertexBuffer *D3DVertexBuf,
4354                                             DWORD StartVertex,
4355                                             DWORD NumVertices,
4356                                             DWORD Flags)
4357 {
4358     IDirect3DDeviceImpl *This = device_from_device3(iface);
4359     IDirect3DVertexBufferImpl *vb = D3DVertexBuf ? vb_from_vb1(D3DVertexBuf) : NULL;
4360     TRACE_(ddraw_thunk)("(%p)->(%08x,%p,%08x,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This,  PrimitiveType, vb, StartVertex, NumVertices, Flags);
4361     return IDirect3DDevice7_DrawPrimitiveVB((IDirect3DDevice7 *)This, PrimitiveType,
4362             (IDirect3DVertexBuffer7 *)vb, StartVertex, NumVertices, Flags);
4363 }
4364
4365
4366 /*****************************************************************************
4367  * IDirect3DDevice7::DrawIndexedPrimitiveVB
4368  *
4369  * Draws primitives from a vertex buffer to the screen
4370  *
4371  * Params:
4372  *  PrimitiveType: Type of primitive to be rendered.
4373  *  D3DVertexBuf: Source Vertex Buffer
4374  *  StartVertex: Index of the first vertex from the buffer to be rendered
4375  *  NumVertices: Number of vertices to be rendered
4376  *  Indices: Array of DWORDs used to index into the Vertices
4377  *  IndexCount: Number of indices in Indices
4378  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4379  *
4380  * Return values
4381  *
4382  *****************************************************************************/
4383 static HRESULT
4384 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4385                                              D3DPRIMITIVETYPE PrimitiveType,
4386                                              IDirect3DVertexBuffer7 *D3DVertexBuf,
4387                                              DWORD StartVertex,
4388                                              DWORD NumVertices,
4389                                              WORD *Indices,
4390                                              DWORD IndexCount,
4391                                              DWORD Flags)
4392 {
4393     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4394     IDirect3DVertexBufferImpl *vb = (IDirect3DVertexBufferImpl *)D3DVertexBuf;
4395     DWORD stride;
4396     UINT PrimitiveCount;
4397     WORD *LockedIndices;
4398     HRESULT hr;
4399     WINED3DVERTEXBUFFER_DESC Desc;
4400
4401     TRACE("(%p)->(%08x,%p,%d,%d,%p,%d,%08x)\n", This, PrimitiveType, vb, StartVertex, NumVertices, Indices, IndexCount, Flags);
4402
4403     /* Steps:
4404      * 1) Calculate some things: Vertex count -> Primitive count, stride, ...
4405      * 2) Upload the Indices to the index buffer
4406      * 3) Set the index source
4407      * 4) Set the Vertex Buffer as the Stream source
4408      * 5) Call IWineD3DDevice::DrawIndexedPrimitive
4409      */
4410
4411     /* Get the primitive count */
4412     switch(PrimitiveType)
4413     {
4414         case D3DPT_POINTLIST: 
4415           PrimitiveCount = IndexCount;
4416           break;
4417
4418         case D3DPT_LINELIST: 
4419           PrimitiveCount = IndexCount / 2;
4420           break;
4421
4422         case D3DPT_LINESTRIP:
4423           PrimitiveCount = IndexCount - 1;
4424           break;
4425
4426         case D3DPT_TRIANGLELIST:
4427           PrimitiveCount = IndexCount / 3;
4428           break;
4429
4430         case D3DPT_TRIANGLESTRIP:
4431           PrimitiveCount = IndexCount - 2;
4432           break;
4433
4434         case D3DPT_TRIANGLEFAN:
4435           PrimitiveCount = IndexCount - 2;
4436           break;
4437
4438         default: return DDERR_INVALIDPARAMS;
4439     }
4440
4441     EnterCriticalSection(&ddraw_cs);
4442     /* Get the FVF of the vertex buffer, and its stride */
4443     hr = IWineD3DVertexBuffer_GetDesc(vb->wineD3DVertexBuffer,
4444                                       &Desc);
4445     if(hr != D3D_OK)
4446     {
4447         ERR("(%p) IWineD3DVertexBuffer::GetDesc failed with hr = %08x\n", This, hr);
4448         LeaveCriticalSection(&ddraw_cs);
4449         return hr;
4450     }
4451     stride = get_flexible_vertex_size(Desc.FVF);
4452     TRACE("Vertex buffer FVF = %08x, stride=%d\n", Desc.FVF, stride);
4453
4454     hr = IWineD3DDevice_SetVertexDeclaration(This->wineD3DDevice,
4455                                              vb->wineD3DVertexDeclaration);
4456     if(FAILED(hr))
4457     {
4458         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
4459         LeaveCriticalSection(&ddraw_cs);
4460         return hr;
4461     }
4462
4463     /* copy the index stream into the index buffer.
4464      * A new IWineD3DDevice method could be created
4465      * which takes an user pointer containing the indices
4466      * or a SetData-Method for the index buffer, which
4467      * overrides the index buffer data with our pointer.
4468      */
4469     hr = IWineD3DIndexBuffer_Lock(This->indexbuffer,
4470                                   0 /* OffSetToLock */,
4471                                   IndexCount * sizeof(WORD),
4472                                   (BYTE **) &LockedIndices,
4473                                   0 /* Flags */);
4474     assert(IndexCount < 0x100000);
4475     if(hr != D3D_OK)
4476     {
4477         ERR("(%p) IWineD3DIndexBuffer::Lock failed with hr = %08x\n", This, hr);
4478         LeaveCriticalSection(&ddraw_cs);
4479         return hr;
4480     }
4481     memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4482     hr = IWineD3DIndexBuffer_Unlock(This->indexbuffer);
4483     if(hr != D3D_OK)
4484     {
4485         ERR("(%p) IWineD3DIndexBuffer::Unlock failed with hr = %08x\n", This, hr);
4486         LeaveCriticalSection(&ddraw_cs);
4487         return hr;
4488     }
4489
4490     /* Set the index stream */
4491     IWineD3DDevice_SetBaseVertexIndex(This->wineD3DDevice, StartVertex);
4492     hr = IWineD3DDevice_SetIndices(This->wineD3DDevice, This->indexbuffer);
4493
4494     /* Set the vertex stream source */
4495     hr = IWineD3DDevice_SetStreamSource(This->wineD3DDevice,
4496                                         0 /* StreamNumber */,
4497                                         vb->wineD3DVertexBuffer,
4498                                         0 /* offset, we pass this to DrawIndexedPrimitive */,
4499                                         stride);
4500     if(hr != D3D_OK)
4501     {
4502         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4503         LeaveCriticalSection(&ddraw_cs);
4504         return hr;
4505     }
4506
4507
4508     hr = IWineD3DDevice_DrawIndexedPrimitive(This->wineD3DDevice,
4509                                              PrimitiveType,
4510                                              0 /* minIndex */,
4511                                              NumVertices,
4512                                              0 /* StartIndex */,
4513                                              PrimitiveCount);
4514
4515     LeaveCriticalSection(&ddraw_cs);
4516     return hr;
4517 }
4518
4519 static HRESULT WINAPI
4520 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4521                                              D3DPRIMITIVETYPE PrimitiveType,
4522                                              IDirect3DVertexBuffer7 *D3DVertexBuf,
4523                                              DWORD StartVertex,
4524                                              DWORD NumVertices,
4525                                              WORD *Indices,
4526                                              DWORD IndexCount,
4527                                              DWORD Flags)
4528 {
4529     return IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4530 }
4531
4532 static HRESULT WINAPI
4533 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4534                                              D3DPRIMITIVETYPE PrimitiveType,
4535                                              IDirect3DVertexBuffer7 *D3DVertexBuf,
4536                                              DWORD StartVertex,
4537                                              DWORD NumVertices,
4538                                              WORD *Indices,
4539                                              DWORD IndexCount,
4540                                              DWORD Flags)
4541 {
4542     HRESULT hr;
4543     WORD old_fpucw;
4544
4545     old_fpucw = d3d_fpu_setup();
4546     hr = IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4547     set_fpu_control_word(old_fpucw);
4548
4549     return hr;
4550 }
4551
4552 static HRESULT WINAPI
4553 Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4554                                                    D3DPRIMITIVETYPE PrimitiveType,
4555                                                    IDirect3DVertexBuffer *D3DVertexBuf,
4556                                                    WORD *Indices,
4557                                                    DWORD IndexCount,
4558                                                    DWORD Flags)
4559 {
4560     IDirect3DDeviceImpl *This = device_from_device3(iface);
4561     IDirect3DVertexBufferImpl *VB = vb_from_vb1(D3DVertexBuf);
4562     TRACE_(ddraw_thunk)("(%p)->(%08x,%p,%p,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, PrimitiveType, VB, Indices, IndexCount, Flags);
4563
4564     return IDirect3DDevice7_DrawIndexedPrimitiveVB((IDirect3DDevice7 *)This, PrimitiveType,
4565             (IDirect3DVertexBuffer7 *)VB, 0, IndexCount, Indices, IndexCount, Flags);
4566 }
4567
4568 /*****************************************************************************
4569  * IDirect3DDevice7::ComputeSphereVisibility
4570  *
4571  * Calculates the visibility of spheres in the current viewport. The spheres
4572  * are passed in the Centers and Radii arrays, the results are passed back
4573  * in the ReturnValues array. Return values are either completely visible,
4574  * partially visible or completely invisible.
4575  * The return value consist of a combination of D3DCLIP_* flags, or it's
4576  * 0 if the sphere is completely visible(according to the SDK, not checked)
4577  *
4578  * Sounds like an overdose of math ;)
4579  *
4580  * Version 3 and 7
4581  *
4582  * Params:
4583  *  Centers: Array containing the sphere centers
4584  *  Radii: Array containing the sphere radii
4585  *  NumSpheres: The number of centers and radii in the arrays
4586  *  Flags: Some flags
4587  *  ReturnValues: Array to write the results to
4588  *
4589  * Returns:
4590  *  D3D_OK because it's a stub
4591  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4592  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4593  *  is singular)
4594  *
4595  *****************************************************************************/
4596
4597 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4598 {
4599     float distance, norm;
4600
4601     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4602     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4603
4604     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4605     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4606     return 0;
4607 }
4608
4609 static HRESULT WINAPI
4610 IDirect3DDeviceImpl_7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4611                                               D3DVECTOR *Centers,
4612                                               D3DVALUE *Radii,
4613                                               DWORD NumSpheres,
4614                                               DWORD Flags,
4615                                               DWORD *ReturnValues)
4616 {
4617     D3DMATRIX m, temp;
4618     D3DVALUE origin_plane[6];
4619     D3DVECTOR vec[6];
4620     HRESULT hr;
4621     UINT i, j;
4622
4623     TRACE("(%p)->(%p,%p,%08x,%08x,%p)\n", iface, Centers, Radii, NumSpheres, Flags, ReturnValues);
4624
4625     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4626     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4627     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4628     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4629     multiply_matrix_D3D_way(&m, &m, &temp);
4630
4631     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4632     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4633     multiply_matrix_D3D_way(&m, &m, &temp);
4634
4635 /* Left plane */
4636     vec[0].u1.x = m._14 + m._11;
4637     vec[0].u2.y = m._24 + m._21;
4638     vec[0].u3.z = m._34 + m._31;
4639     origin_plane[0] = m._44 + m._41;
4640
4641 /* Right plane */
4642     vec[1].u1.x = m._14 - m._11;
4643     vec[1].u2.y = m._24 - m._21;
4644     vec[1].u3.z = m._34 - m._31;
4645     origin_plane[1] = m._44 - m._41;
4646
4647 /* Top plane */
4648     vec[2].u1.x = m._14 - m._12;
4649     vec[2].u2.y = m._24 - m._22;
4650     vec[2].u3.z = m._34 - m._32;
4651     origin_plane[2] = m._44 - m._42;
4652
4653 /* Bottom plane */
4654     vec[3].u1.x = m._14 + m._12;
4655     vec[3].u2.y = m._24 + m._22;
4656     vec[3].u3.z = m._34 + m._32;
4657     origin_plane[3] = m._44 + m._42;
4658
4659 /* Front plane */
4660     vec[4].u1.x = m._13;
4661     vec[4].u2.y = m._23;
4662     vec[4].u3.z = m._33;
4663     origin_plane[4] = m._43;
4664
4665 /* Back plane*/
4666     vec[5].u1.x = m._14 - m._13;
4667     vec[5].u2.y = m._24 - m._23;
4668     vec[5].u3.z = m._34 - m._33;
4669     origin_plane[5] = m._44 - m._43;
4670
4671     for(i=0; i<NumSpheres; i++)
4672     {
4673         ReturnValues[i] = 0;
4674         for(j=0; j<6; j++) ReturnValues[i] |= in_plane(j, vec[j], origin_plane[j], Centers[i], Radii[i]);
4675     }
4676
4677     return D3D_OK;
4678 }
4679
4680 static HRESULT WINAPI
4681 Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4682                                                     D3DVECTOR *Centers,
4683                                                     D3DVALUE *Radii,
4684                                                     DWORD NumSpheres,
4685                                                     DWORD Flags,
4686                                                     DWORD *ReturnValues)
4687 {
4688     IDirect3DDeviceImpl *This = device_from_device3(iface);
4689     TRACE_(ddraw_thunk)("(%p)->(%p,%p,%08x,%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, Centers, Radii, NumSpheres, Flags, ReturnValues);
4690     return IDirect3DDevice7_ComputeSphereVisibility((IDirect3DDevice7 *)This,
4691             Centers, Radii, NumSpheres, Flags, ReturnValues);
4692 }
4693
4694 /*****************************************************************************
4695  * IDirect3DDevice7::GetTexture
4696  *
4697  * Returns the texture interface handle assigned to a texture stage.
4698  * The returned texture is AddRefed. This is taken from old ddraw,
4699  * not checked in Windows.
4700  *
4701  * Version 3 and 7
4702  *
4703  * Params:
4704  *  Stage: Texture stage to read the texture from
4705  *  Texture: Address to store the interface pointer at
4706  *
4707  * Returns:
4708  *  D3D_OK on success
4709  *  DDERR_INVALIDPARAMS if Texture is NULL
4710  *  For details, see IWineD3DDevice::GetTexture
4711  *
4712  *****************************************************************************/
4713 static HRESULT
4714 IDirect3DDeviceImpl_7_GetTexture(IDirect3DDevice7 *iface,
4715                                  DWORD Stage,
4716                                  IDirectDrawSurface7 **Texture)
4717 {
4718     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4719     IWineD3DBaseTexture *Surf;
4720     HRESULT hr;
4721     TRACE("(%p)->(%d,%p): Relay\n", This, Stage, Texture);
4722
4723     if(!Texture)
4724     {
4725         TRACE("Texture == NULL, failing with DDERR_INVALIDPARAMS\n");
4726         return DDERR_INVALIDPARAMS;
4727     }
4728
4729     EnterCriticalSection(&ddraw_cs);
4730     hr = IWineD3DDevice_GetTexture(This->wineD3DDevice, Stage, &Surf);
4731     if( (hr != D3D_OK) || (!Surf) ) 
4732     {
4733         *Texture = NULL;
4734         LeaveCriticalSection(&ddraw_cs);
4735         return hr;
4736     }
4737
4738     /* GetParent AddRef()s, which is perfectly OK.
4739      * We have passed the IDirectDrawSurface7 interface to WineD3D, so that's OK too.
4740      */
4741     hr = IWineD3DBaseTexture_GetParent(Surf,
4742                                        (IUnknown **) Texture);
4743     LeaveCriticalSection(&ddraw_cs);
4744     return hr;
4745 }
4746
4747 static HRESULT WINAPI
4748 IDirect3DDeviceImpl_7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4749                                  DWORD Stage,
4750                                  IDirectDrawSurface7 **Texture)
4751 {
4752     return IDirect3DDeviceImpl_7_GetTexture(iface, Stage, Texture);
4753 }
4754
4755 static HRESULT WINAPI
4756 IDirect3DDeviceImpl_7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4757                                  DWORD Stage,
4758                                  IDirectDrawSurface7 **Texture)
4759 {
4760     HRESULT hr;
4761     WORD old_fpucw;
4762
4763     old_fpucw = d3d_fpu_setup();
4764     hr = IDirect3DDeviceImpl_7_GetTexture(iface, Stage, Texture);
4765     set_fpu_control_word(old_fpucw);
4766
4767     return hr;
4768 }
4769
4770 static HRESULT WINAPI
4771 Thunk_IDirect3DDeviceImpl_3_GetTexture(IDirect3DDevice3 *iface,
4772                                        DWORD Stage,
4773                                        IDirect3DTexture2 **Texture2)
4774 {
4775     IDirect3DDeviceImpl *This = device_from_device3(iface);
4776     HRESULT ret;
4777     IDirectDrawSurface7 *ret_val;
4778
4779     TRACE_(ddraw_thunk)("(%p)->(%d,%p) thunking to IDirect3DDevice7 interface.\n", This, Stage, Texture2);
4780     ret = IDirect3DDevice7_GetTexture((IDirect3DDevice7 *)This, Stage, &ret_val);
4781
4782     *Texture2 = ret_val ? (IDirect3DTexture2 *)&((IDirectDrawSurfaceImpl *)ret_val)->IDirect3DTexture2_vtbl : NULL;
4783
4784     TRACE_(ddraw_thunk)(" returning interface %p.\n", *Texture2);
4785
4786     return ret;
4787 }
4788
4789 /*****************************************************************************
4790  * IDirect3DDevice7::SetTexture
4791  *
4792  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4793  *
4794  * Version 3 and 7
4795  *
4796  * Params:
4797  *  Stage: The stage to assign the texture to
4798  *  Texture: Interface pointer to the texture surface
4799  *
4800  * Returns
4801  * D3D_OK on success
4802  * For details, see IWineD3DDevice::SetTexture
4803  *
4804  *****************************************************************************/
4805 static HRESULT
4806 IDirect3DDeviceImpl_7_SetTexture(IDirect3DDevice7 *iface,
4807                                  DWORD Stage,
4808                                  IDirectDrawSurface7 *Texture)
4809 {
4810     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4811     IDirectDrawSurfaceImpl *surf = (IDirectDrawSurfaceImpl *)Texture;
4812     HRESULT hr;
4813     TRACE("(%p)->(%08x,%p): Relay!\n", This, Stage, surf);
4814
4815     /* Texture may be NULL here */
4816     EnterCriticalSection(&ddraw_cs);
4817     hr = IWineD3DDevice_SetTexture(This->wineD3DDevice,
4818                                    Stage,
4819                                    surf ? surf->wineD3DTexture : NULL);
4820     LeaveCriticalSection(&ddraw_cs);
4821     return hr;
4822 }
4823
4824 static HRESULT WINAPI
4825 IDirect3DDeviceImpl_7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4826                                  DWORD Stage,
4827                                  IDirectDrawSurface7 *Texture)
4828 {
4829     return IDirect3DDeviceImpl_7_SetTexture(iface, Stage, Texture);
4830 }
4831
4832 static HRESULT WINAPI
4833 IDirect3DDeviceImpl_7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4834                                  DWORD Stage,
4835                                  IDirectDrawSurface7 *Texture)
4836 {
4837     HRESULT hr;
4838     WORD old_fpucw;
4839
4840     old_fpucw = d3d_fpu_setup();
4841     hr = IDirect3DDeviceImpl_7_SetTexture(iface, Stage, Texture);
4842     set_fpu_control_word(old_fpucw);
4843
4844     return hr;
4845 }
4846
4847 static HRESULT WINAPI
4848 IDirect3DDeviceImpl_3_SetTexture(IDirect3DDevice3 *iface,
4849                                  DWORD Stage,
4850                                  IDirect3DTexture2 *Texture2)
4851 {
4852     IDirect3DDeviceImpl *This = device_from_device3(iface);
4853     IDirectDrawSurfaceImpl *tex = Texture2 ? surface_from_texture2(Texture2) : NULL;
4854     DWORD texmapblend;
4855     HRESULT hr;
4856     TRACE("(%p)->(%d,%p)\n", This, Stage, tex);
4857
4858     EnterCriticalSection(&ddraw_cs);
4859
4860     if (This->legacyTextureBlending)
4861         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4862
4863     hr = IDirect3DDevice7_SetTexture((IDirect3DDevice7 *)This, Stage, (IDirectDrawSurface7 *)tex);
4864
4865     if (This->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4866     {
4867         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4868            See IDirect3DDeviceImpl_3_SetRenderState for details. */
4869         BOOL tex_alpha = FALSE;
4870         IWineD3DBaseTexture *tex = NULL;
4871         WINED3DSURFACE_DESC desc;
4872         WINED3DFORMAT fmt;
4873         DDPIXELFORMAT ddfmt;
4874         HRESULT result;
4875
4876         result = IWineD3DDevice_GetTexture(This->wineD3DDevice,
4877                                     0,
4878                                     &tex);
4879
4880         if(result == WINED3D_OK && tex)
4881         {
4882             memset(&desc, 0, sizeof(desc));
4883             desc.Format = &fmt;
4884             result = IWineD3DTexture_GetLevelDesc((IWineD3DTexture*) tex, 0, &desc);
4885             if (SUCCEEDED(result))
4886             {
4887                 ddfmt.dwSize = sizeof(ddfmt);
4888                 PixelFormat_WineD3DtoDD(&ddfmt, fmt);
4889                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4890             }
4891
4892             IWineD3DBaseTexture_Release(tex);
4893         }
4894
4895         /* alphaop is WINED3DTOP_SELECTARG1 if it's D3DTBLEND_MODULATE, so only modify alphaarg1 */
4896         if (tex_alpha)
4897         {
4898             IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
4899         }
4900         else
4901         {
4902             IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_CURRENT);
4903         }
4904     }
4905
4906     LeaveCriticalSection(&ddraw_cs);
4907
4908     return hr;
4909 }
4910
4911 static const struct tss_lookup
4912 {
4913     BOOL sampler_state;
4914     DWORD state;
4915 }
4916 tss_lookup[] =
4917 {
4918     {FALSE, WINED3DTSS_FORCE_DWORD},            /*  0, unused */
4919     {FALSE, WINED3DTSS_COLOROP},                /*  1, D3DTSS_COLOROP */
4920     {FALSE, WINED3DTSS_COLORARG1},              /*  2, D3DTSS_COLORARG1 */
4921     {FALSE, WINED3DTSS_COLORARG2},              /*  3, D3DTSS_COLORARG2 */
4922     {FALSE, WINED3DTSS_ALPHAOP},                /*  4, D3DTSS_ALPHAOP */
4923     {FALSE, WINED3DTSS_ALPHAARG1},              /*  5, D3DTSS_ALPHAARG1 */
4924     {FALSE, WINED3DTSS_ALPHAARG2},              /*  6, D3DTSS_ALPHAARG2 */
4925     {FALSE, WINED3DTSS_BUMPENVMAT00},           /*  7, D3DTSS_BUMPENVMAT00 */
4926     {FALSE, WINED3DTSS_BUMPENVMAT01},           /*  8, D3DTSS_BUMPENVMAT01 */
4927     {FALSE, WINED3DTSS_BUMPENVMAT10},           /*  9, D3DTSS_BUMPENVMAT10 */
4928     {FALSE, WINED3DTSS_BUMPENVMAT11},           /* 10, D3DTSS_BUMPENVMAT11 */
4929     {FALSE, WINED3DTSS_TEXCOORDINDEX},          /* 11, D3DTSS_TEXCOORDINDEX */
4930     {TRUE,  WINED3DSAMP_ADDRESSU},              /* 12, D3DTSS_ADDRESS */
4931     {TRUE,  WINED3DSAMP_ADDRESSU},              /* 13, D3DTSS_ADDRESSU */
4932     {TRUE,  WINED3DSAMP_ADDRESSV},              /* 14, D3DTSS_ADDRESSV */
4933     {TRUE,  WINED3DSAMP_BORDERCOLOR},           /* 15, D3DTSS_BORDERCOLOR */
4934     {TRUE,  WINED3DSAMP_MAGFILTER},             /* 16, D3DTSS_MAGFILTER */
4935     {TRUE,  WINED3DSAMP_MINFILTER},             /* 17, D3DTSS_MINFILTER */
4936     {TRUE,  WINED3DSAMP_MIPFILTER},             /* 18, D3DTSS_MIPFILTER */
4937     {TRUE,  WINED3DSAMP_MIPMAPLODBIAS},         /* 19, D3DTSS_MIPMAPLODBIAS */
4938     {TRUE,  WINED3DSAMP_MAXMIPLEVEL},           /* 20, D3DTSS_MAXMIPLEVEL */
4939     {TRUE,  WINED3DSAMP_MAXANISOTROPY},         /* 21, D3DTSS_MAXANISOTROPY */
4940     {FALSE, WINED3DTSS_BUMPENVLSCALE},          /* 22, D3DTSS_BUMPENVLSCALE */
4941     {FALSE, WINED3DTSS_BUMPENVLOFFSET},         /* 23, D3DTSS_BUMPENVLOFFSET */
4942     {FALSE, WINED3DTSS_TEXTURETRANSFORMFLAGS},  /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4943 };
4944
4945 /*****************************************************************************
4946  * IDirect3DDevice7::GetTextureStageState
4947  *
4948  * Retrieves a state from a texture stage.
4949  *
4950  * Version 3 and 7
4951  *
4952  * Params:
4953  *  Stage: The stage to retrieve the state from
4954  *  TexStageStateType: The state type to retrieve
4955  *  State: Address to store the state's value at
4956  *
4957  * Returns:
4958  *  D3D_OK on success
4959  *  DDERR_INVALIDPARAMS if State is NULL
4960  *  For details, see IWineD3DDevice::GetTextureStageState
4961  *
4962  *****************************************************************************/
4963 static HRESULT
4964 IDirect3DDeviceImpl_7_GetTextureStageState(IDirect3DDevice7 *iface,
4965                                            DWORD Stage,
4966                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4967                                            DWORD *State)
4968 {
4969     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4970     HRESULT hr;
4971     const struct tss_lookup *l = &tss_lookup[TexStageStateType];
4972     TRACE("(%p)->(%08x,%08x,%p): Relay!\n", This, Stage, TexStageStateType, State);
4973
4974     if(!State)
4975         return DDERR_INVALIDPARAMS;
4976
4977     EnterCriticalSection(&ddraw_cs);
4978
4979     if (l->sampler_state)
4980     {
4981         hr = IWineD3DDevice_GetSamplerState(This->wineD3DDevice, Stage, l->state, State);
4982
4983         switch(TexStageStateType)
4984         {
4985             /* Mipfilter is a sampler state with different values */
4986             case D3DTSS_MIPFILTER:
4987             {
4988                 switch(*State)
4989                 {
4990                     case WINED3DTEXF_NONE: *State = D3DTFP_NONE; break;
4991                     case WINED3DTEXF_POINT: *State = D3DTFP_POINT; break;
4992                     case WINED3DTEXF_LINEAR: *State = D3DTFP_LINEAR; break;
4993                     default:
4994                         ERR("Unexpected mipfilter value %#x\n", *State);
4995                         *State = D3DTFP_NONE;
4996                         break;
4997                 }
4998                 break;
4999             }
5000
5001             /* Magfilter has slightly different values */
5002             case D3DTSS_MAGFILTER:
5003             {
5004                 switch(*State)
5005                 {
5006                     case WINED3DTEXF_POINT: *State = D3DTFG_POINT; break;
5007                     case WINED3DTEXF_LINEAR: *State = D3DTFG_LINEAR; break;
5008                     case WINED3DTEXF_ANISOTROPIC: *State = D3DTFG_ANISOTROPIC; break;
5009                     case WINED3DTEXF_FLATCUBIC: *State = D3DTFG_FLATCUBIC; break;
5010                     case WINED3DTEXF_GAUSSIANCUBIC: *State = D3DTFG_GAUSSIANCUBIC; break;
5011                     default:
5012                         ERR("Unexpected wined3d mag filter value %#x\n", *State);
5013                         *State = D3DTFG_POINT;
5014                         break;
5015                 }
5016                 break;
5017             }
5018
5019             default:
5020                 break;
5021         }
5022     }
5023     else
5024     {
5025         hr = IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, Stage, l->state, State);
5026     }
5027
5028     LeaveCriticalSection(&ddraw_cs);
5029     return hr;
5030 }
5031
5032 static HRESULT WINAPI
5033 IDirect3DDeviceImpl_7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5034                                            DWORD Stage,
5035                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
5036                                            DWORD *State)
5037 {
5038     return IDirect3DDeviceImpl_7_GetTextureStageState(iface, Stage, TexStageStateType, State);
5039 }
5040
5041 static HRESULT WINAPI
5042 IDirect3DDeviceImpl_7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5043                                            DWORD Stage,
5044                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
5045                                            DWORD *State)
5046 {
5047     HRESULT hr;
5048     WORD old_fpucw;
5049
5050     old_fpucw = d3d_fpu_setup();
5051     hr = IDirect3DDeviceImpl_7_GetTextureStageState(iface, Stage, TexStageStateType, State);
5052     set_fpu_control_word(old_fpucw);
5053
5054     return hr;
5055 }
5056
5057 static HRESULT WINAPI
5058 Thunk_IDirect3DDeviceImpl_3_GetTextureStageState(IDirect3DDevice3 *iface,
5059                                                  DWORD Stage,
5060                                                  D3DTEXTURESTAGESTATETYPE TexStageStateType,
5061                                                  DWORD *State)
5062 {
5063     IDirect3DDeviceImpl *This = device_from_device3(iface);
5064     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, Stage, TexStageStateType, State);
5065     return IDirect3DDevice7_GetTextureStageState((IDirect3DDevice7 *)This, Stage, TexStageStateType, State);
5066 }
5067
5068 /*****************************************************************************
5069  * IDirect3DDevice7::SetTextureStageState
5070  *
5071  * Sets a texture stage state. Some stage types need to be handled specially,
5072  * because they do not exist in WineD3D and were moved to another place
5073  *
5074  * Version 3 and 7
5075  *
5076  * Params:
5077  *  Stage: The stage to modify
5078  *  TexStageStateType: The state to change
5079  *  State: The new value for the state
5080  *
5081  * Returns:
5082  *  D3D_OK on success
5083  *  For details, see IWineD3DDevice::SetTextureStageState
5084  *
5085  *****************************************************************************/
5086 static HRESULT
5087 IDirect3DDeviceImpl_7_SetTextureStageState(IDirect3DDevice7 *iface,
5088                                            DWORD Stage,
5089                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
5090                                            DWORD State)
5091 {
5092     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5093     const struct tss_lookup *l = &tss_lookup[TexStageStateType];
5094     HRESULT hr;
5095     TRACE("(%p)->(%08x,%08x,%08x): Relay!\n", This, Stage, TexStageStateType, State);
5096
5097     EnterCriticalSection(&ddraw_cs);
5098
5099     if (l->sampler_state)
5100     {
5101         switch(TexStageStateType)
5102         {
5103             /* Mipfilter is a sampler state with different values */
5104             case D3DTSS_MIPFILTER:
5105             {
5106                 switch(State)
5107                 {
5108                     case D3DTFP_NONE: State = WINED3DTEXF_NONE; break;
5109                     case D3DTFP_POINT: State = WINED3DTEXF_POINT; break;
5110                     case 0: /* Unchecked */
5111                     case D3DTFP_LINEAR: State = WINED3DTEXF_LINEAR; break;
5112                     default:
5113                         ERR("Unexpected mipfilter value %d\n", State);
5114                         State = WINED3DTEXF_NONE;
5115                         break;
5116                 }
5117                 break;
5118             }
5119
5120             /* Magfilter has slightly different values */
5121             case D3DTSS_MAGFILTER:
5122             {
5123                 switch(State)
5124                 {
5125                     case D3DTFG_POINT: State = WINED3DTEXF_POINT; break;
5126                     case D3DTFG_LINEAR: State = WINED3DTEXF_LINEAR; break;
5127                     case D3DTFG_FLATCUBIC: State = WINED3DTEXF_FLATCUBIC; break;
5128                     case D3DTFG_GAUSSIANCUBIC: State = WINED3DTEXF_GAUSSIANCUBIC; break;
5129                     case D3DTFG_ANISOTROPIC: State = WINED3DTEXF_ANISOTROPIC; break;
5130                     default:
5131                         ERR("Unexpected d3d7 mag filter type %d\n", State);
5132                         State = WINED3DTEXF_POINT;
5133                         break;
5134                 }
5135                 break;
5136             }
5137
5138             case D3DTSS_ADDRESS:
5139                 IWineD3DDevice_SetSamplerState(This->wineD3DDevice, Stage, WINED3DSAMP_ADDRESSV, State);
5140                 break;
5141
5142             default:
5143                 break;
5144         }
5145
5146         hr = IWineD3DDevice_SetSamplerState(This->wineD3DDevice, Stage, l->state, State);
5147     }
5148     else
5149     {
5150         hr = IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, Stage, l->state, State);
5151     }
5152
5153     LeaveCriticalSection(&ddraw_cs);
5154     return hr;
5155 }
5156
5157 static HRESULT WINAPI
5158 IDirect3DDeviceImpl_7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5159                                            DWORD Stage,
5160                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
5161                                            DWORD State)
5162 {
5163     return IDirect3DDeviceImpl_7_SetTextureStageState(iface, Stage, TexStageStateType, State);
5164 }
5165
5166 static HRESULT WINAPI
5167 IDirect3DDeviceImpl_7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5168                                            DWORD Stage,
5169                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
5170                                            DWORD State)
5171 {
5172     HRESULT hr;
5173     WORD old_fpucw;
5174
5175     old_fpucw = d3d_fpu_setup();
5176     hr = IDirect3DDeviceImpl_7_SetTextureStageState(iface, Stage, TexStageStateType, State);
5177     set_fpu_control_word(old_fpucw);
5178
5179     return hr;
5180 }
5181
5182 static HRESULT WINAPI
5183 Thunk_IDirect3DDeviceImpl_3_SetTextureStageState(IDirect3DDevice3 *iface,
5184                                                  DWORD Stage,
5185                                                  D3DTEXTURESTAGESTATETYPE TexStageStateType,
5186                                                  DWORD State)
5187 {
5188     IDirect3DDeviceImpl *This = device_from_device3(iface);
5189     TRACE_(ddraw_thunk)("(%p)->(%08x,%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, Stage, TexStageStateType, State);
5190     return IDirect3DDevice7_SetTextureStageState((IDirect3DDevice7 *)This, Stage, TexStageStateType, State);
5191 }
5192
5193 /*****************************************************************************
5194  * IDirect3DDevice7::ValidateDevice
5195  *
5196  * SDK: "Reports the device's ability to render the currently set
5197  * texture-blending operations in a single pass". Whatever that means
5198  * exactly...
5199  *
5200  * Version 3 and 7
5201  *
5202  * Params:
5203  *  NumPasses: Address to write the number of necessary passes for the
5204  *             desired effect to.
5205  *
5206  * Returns:
5207  *  D3D_OK on success
5208  *  See IWineD3DDevice::ValidateDevice for more details
5209  *
5210  *****************************************************************************/
5211 static HRESULT
5212 IDirect3DDeviceImpl_7_ValidateDevice(IDirect3DDevice7 *iface,
5213                                      DWORD *NumPasses)
5214 {
5215     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5216     HRESULT hr;
5217     TRACE("(%p)->(%p): Relay\n", This, NumPasses);
5218
5219     EnterCriticalSection(&ddraw_cs);
5220     hr = IWineD3DDevice_ValidateDevice(This->wineD3DDevice, NumPasses);
5221     LeaveCriticalSection(&ddraw_cs);
5222     return hr;
5223 }
5224
5225 static HRESULT WINAPI
5226 IDirect3DDeviceImpl_7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface,
5227                                      DWORD *NumPasses)
5228 {
5229     return IDirect3DDeviceImpl_7_ValidateDevice(iface, NumPasses);
5230 }
5231
5232 static HRESULT WINAPI
5233 IDirect3DDeviceImpl_7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface,
5234                                      DWORD *NumPasses)
5235 {
5236     HRESULT hr;
5237     WORD old_fpucw;
5238
5239     old_fpucw = d3d_fpu_setup();
5240     hr = IDirect3DDeviceImpl_7_ValidateDevice(iface, NumPasses);
5241     set_fpu_control_word(old_fpucw);
5242
5243     return hr;
5244 }
5245
5246 static HRESULT WINAPI
5247 Thunk_IDirect3DDeviceImpl_3_ValidateDevice(IDirect3DDevice3 *iface,
5248                                            DWORD *Passes)
5249 {
5250     IDirect3DDeviceImpl *This = device_from_device3(iface);
5251     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice7 interface.\n", This, Passes);
5252     return IDirect3DDevice7_ValidateDevice((IDirect3DDevice7 *)This, Passes);
5253 }
5254
5255 /*****************************************************************************
5256  * IDirect3DDevice7::Clear
5257  *
5258  * Fills the render target, the z buffer and the stencil buffer with a
5259  * clear color / value
5260  *
5261  * Version 7 only
5262  *
5263  * Params:
5264  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
5265  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
5266  *  Flags: Some flags, as usual
5267  *  Color: Clear color for the render target
5268  *  Z: Clear value for the Z buffer
5269  *  Stencil: Clear value to store in each stencil buffer entry
5270  *
5271  * Returns:
5272  *  D3D_OK on success
5273  *  For details, see IWineD3DDevice::Clear
5274  *
5275  *****************************************************************************/
5276 static HRESULT
5277 IDirect3DDeviceImpl_7_Clear(IDirect3DDevice7 *iface,
5278                             DWORD Count,
5279                             D3DRECT *Rects,
5280                             DWORD Flags,
5281                             D3DCOLOR Color,
5282                             D3DVALUE Z,
5283                             DWORD Stencil)
5284 {
5285     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5286     HRESULT hr;
5287     TRACE("(%p)->(%08x,%p,%08x,%08x,%f,%08x): Relay\n", This, Count, Rects, Flags, Color, Z, Stencil);
5288
5289     /* Note; D3DRECT is compatible with WINED3DRECT */
5290     EnterCriticalSection(&ddraw_cs);
5291     hr = IWineD3DDevice_Clear(This->wineD3DDevice, Count, (WINED3DRECT*) Rects, Flags, Color, Z, Stencil);
5292     LeaveCriticalSection(&ddraw_cs);
5293     return hr;
5294 }
5295
5296 static HRESULT WINAPI
5297 IDirect3DDeviceImpl_7_Clear_FPUSetup(IDirect3DDevice7 *iface,
5298                             DWORD Count,
5299                             D3DRECT *Rects,
5300                             DWORD Flags,
5301                             D3DCOLOR Color,
5302                             D3DVALUE Z,
5303                             DWORD Stencil)
5304 {
5305     return IDirect3DDeviceImpl_7_Clear(iface, Count, Rects, Flags, Color, Z, Stencil);
5306 }
5307
5308 static HRESULT WINAPI
5309 IDirect3DDeviceImpl_7_Clear_FPUPreserve(IDirect3DDevice7 *iface,
5310                             DWORD Count,
5311                             D3DRECT *Rects,
5312                             DWORD Flags,
5313                             D3DCOLOR Color,
5314                             D3DVALUE Z,
5315                             DWORD Stencil)
5316 {
5317     HRESULT hr;
5318     WORD old_fpucw;
5319
5320     old_fpucw = d3d_fpu_setup();
5321     hr = IDirect3DDeviceImpl_7_Clear(iface, Count, Rects, Flags, Color, Z, Stencil);
5322     set_fpu_control_word(old_fpucw);
5323
5324     return hr;
5325 }
5326
5327 /*****************************************************************************
5328  * IDirect3DDevice7::SetViewport
5329  *
5330  * Sets the current viewport.
5331  *
5332  * Version 7 only, but IDirect3DViewport uses this call for older
5333  * versions
5334  *
5335  * Params:
5336  *  Data: The new viewport to set
5337  *
5338  * Returns:
5339  *  D3D_OK on success
5340  *  DDERR_INVALIDPARAMS if Data is NULL
5341  *  For more details, see IWineDDDevice::SetViewport
5342  *
5343  *****************************************************************************/
5344 static HRESULT
5345 IDirect3DDeviceImpl_7_SetViewport(IDirect3DDevice7 *iface,
5346                                   D3DVIEWPORT7 *Data)
5347 {
5348     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5349     HRESULT hr;
5350     TRACE("(%p)->(%p) Relay!\n", This, Data);
5351
5352     if(!Data)
5353         return DDERR_INVALIDPARAMS;
5354
5355     /* Note: D3DVIEWPORT7 is compatible with WINED3DVIEWPORT */
5356     EnterCriticalSection(&ddraw_cs);
5357     hr = IWineD3DDevice_SetViewport(This->wineD3DDevice,
5358                                     (WINED3DVIEWPORT*) Data);
5359     LeaveCriticalSection(&ddraw_cs);
5360     return hr;
5361 }
5362
5363 static HRESULT WINAPI
5364 IDirect3DDeviceImpl_7_SetViewport_FPUSetup(IDirect3DDevice7 *iface,
5365                                   D3DVIEWPORT7 *Data)
5366 {
5367     return IDirect3DDeviceImpl_7_SetViewport(iface, Data);
5368 }
5369
5370 static HRESULT WINAPI
5371 IDirect3DDeviceImpl_7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface,
5372                                   D3DVIEWPORT7 *Data)
5373 {
5374     HRESULT hr;
5375     WORD old_fpucw;
5376
5377     old_fpucw = d3d_fpu_setup();
5378     hr = IDirect3DDeviceImpl_7_SetViewport(iface, Data);
5379     set_fpu_control_word(old_fpucw);
5380
5381     return hr;
5382 }
5383
5384 /*****************************************************************************
5385  * IDirect3DDevice::GetViewport
5386  *
5387  * Returns the current viewport
5388  *
5389  * Version 7
5390  *
5391  * Params:
5392  *  Data: D3D7Viewport structure to write the viewport information to
5393  *
5394  * Returns:
5395  *  D3D_OK on success
5396  *  DDERR_INVALIDPARAMS if Data is NULL
5397  *  For more details, see IWineD3DDevice::GetViewport
5398  *
5399  *****************************************************************************/
5400 static HRESULT
5401 IDirect3DDeviceImpl_7_GetViewport(IDirect3DDevice7 *iface,
5402                                   D3DVIEWPORT7 *Data)
5403 {
5404     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5405     HRESULT hr;
5406     TRACE("(%p)->(%p) Relay!\n", This, Data);
5407
5408     if(!Data)
5409         return DDERR_INVALIDPARAMS;
5410
5411     /* Note: D3DVIEWPORT7 is compatible with WINED3DVIEWPORT */
5412     EnterCriticalSection(&ddraw_cs);
5413     hr = IWineD3DDevice_GetViewport(This->wineD3DDevice,
5414                                     (WINED3DVIEWPORT*) Data);
5415
5416     LeaveCriticalSection(&ddraw_cs);
5417     return hr_ddraw_from_wined3d(hr);
5418 }
5419
5420 static HRESULT WINAPI
5421 IDirect3DDeviceImpl_7_GetViewport_FPUSetup(IDirect3DDevice7 *iface,
5422                                   D3DVIEWPORT7 *Data)
5423 {
5424     return IDirect3DDeviceImpl_7_GetViewport(iface, Data);
5425 }
5426
5427 static HRESULT WINAPI
5428 IDirect3DDeviceImpl_7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface,
5429                                   D3DVIEWPORT7 *Data)
5430 {
5431     HRESULT hr;
5432     WORD old_fpucw;
5433
5434     old_fpucw = d3d_fpu_setup();
5435     hr = IDirect3DDeviceImpl_7_GetViewport(iface, Data);
5436     set_fpu_control_word(old_fpucw);
5437
5438     return hr;
5439 }
5440
5441 /*****************************************************************************
5442  * IDirect3DDevice7::SetMaterial
5443  *
5444  * Sets the Material
5445  *
5446  * Version 7
5447  *
5448  * Params:
5449  *  Mat: The material to set
5450  *
5451  * Returns:
5452  *  D3D_OK on success
5453  *  DDERR_INVALIDPARAMS if Mat is NULL.
5454  *  For more details, see IWineD3DDevice::SetMaterial
5455  *
5456  *****************************************************************************/
5457 static HRESULT
5458 IDirect3DDeviceImpl_7_SetMaterial(IDirect3DDevice7 *iface,
5459                                   D3DMATERIAL7 *Mat)
5460 {
5461     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5462     HRESULT hr;
5463     TRACE("(%p)->(%p): Relay!\n", This, Mat);
5464
5465     if (!Mat) return DDERR_INVALIDPARAMS;
5466     /* Note: D3DMATERIAL7 is compatible with WINED3DMATERIAL */
5467     EnterCriticalSection(&ddraw_cs);
5468     hr = IWineD3DDevice_SetMaterial(This->wineD3DDevice,
5469                                     (WINED3DMATERIAL*) Mat);
5470     LeaveCriticalSection(&ddraw_cs);
5471     return hr_ddraw_from_wined3d(hr);
5472 }
5473
5474 static HRESULT WINAPI
5475 IDirect3DDeviceImpl_7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface,
5476                                   D3DMATERIAL7 *Mat)
5477 {
5478     return IDirect3DDeviceImpl_7_SetMaterial(iface, Mat);
5479 }
5480
5481 static HRESULT WINAPI
5482 IDirect3DDeviceImpl_7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface,
5483                                   D3DMATERIAL7 *Mat)
5484 {
5485     HRESULT hr;
5486     WORD old_fpucw;
5487
5488     old_fpucw = d3d_fpu_setup();
5489     hr = IDirect3DDeviceImpl_7_SetMaterial(iface, Mat);
5490     set_fpu_control_word(old_fpucw);
5491
5492     return hr;
5493 }
5494
5495 /*****************************************************************************
5496  * IDirect3DDevice7::GetMaterial
5497  *
5498  * Returns the current material
5499  *
5500  * Version 7
5501  *
5502  * Params:
5503  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5504  *
5505  * Returns:
5506  *  D3D_OK on success
5507  *  DDERR_INVALIDPARAMS if Mat is NULL
5508  *  For more details, see IWineD3DDevice::GetMaterial
5509  *
5510  *****************************************************************************/
5511 static HRESULT
5512 IDirect3DDeviceImpl_7_GetMaterial(IDirect3DDevice7 *iface,
5513                                   D3DMATERIAL7 *Mat)
5514 {
5515     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5516     HRESULT hr;
5517     TRACE("(%p)->(%p): Relay!\n", This, Mat);
5518
5519     EnterCriticalSection(&ddraw_cs);
5520     /* Note: D3DMATERIAL7 is compatible with WINED3DMATERIAL */ 
5521     hr = IWineD3DDevice_GetMaterial(This->wineD3DDevice,
5522                                     (WINED3DMATERIAL*) Mat);
5523     LeaveCriticalSection(&ddraw_cs);
5524     return hr_ddraw_from_wined3d(hr);
5525 }
5526
5527 static HRESULT WINAPI
5528 IDirect3DDeviceImpl_7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface,
5529                                   D3DMATERIAL7 *Mat)
5530 {
5531     return IDirect3DDeviceImpl_7_GetMaterial(iface, Mat);
5532 }
5533
5534 static HRESULT WINAPI
5535 IDirect3DDeviceImpl_7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface,
5536                                   D3DMATERIAL7 *Mat)
5537 {
5538     HRESULT hr;
5539     WORD old_fpucw;
5540
5541     old_fpucw = d3d_fpu_setup();
5542     hr = IDirect3DDeviceImpl_7_GetMaterial(iface, Mat);
5543     set_fpu_control_word(old_fpucw);
5544
5545     return hr;
5546 }
5547
5548 /*****************************************************************************
5549  * IDirect3DDevice7::SetLight
5550  *
5551  * Assigns a light to a light index, but doesn't activate it yet.
5552  *
5553  * Version 7, IDirect3DLight uses this method for older versions
5554  *
5555  * Params:
5556  *  LightIndex: The index of the new light
5557  *  Light: A D3DLIGHT7 structure describing the light
5558  *
5559  * Returns:
5560  *  D3D_OK on success
5561  *  For more details, see IWineD3DDevice::SetLight
5562  *
5563  *****************************************************************************/
5564 static HRESULT
5565 IDirect3DDeviceImpl_7_SetLight(IDirect3DDevice7 *iface,
5566                                DWORD LightIndex,
5567                                D3DLIGHT7 *Light)
5568 {
5569     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5570     HRESULT hr;
5571     TRACE("(%p)->(%08x,%p): Relay!\n", This, LightIndex, Light);
5572
5573     EnterCriticalSection(&ddraw_cs);
5574     /* Note: D3DLIGHT7 is compatible with WINED3DLIGHT */
5575     hr = IWineD3DDevice_SetLight(This->wineD3DDevice,
5576                                  LightIndex,
5577                                  (WINED3DLIGHT*) Light);
5578     LeaveCriticalSection(&ddraw_cs);
5579     return hr_ddraw_from_wined3d(hr);
5580 }
5581
5582 static HRESULT WINAPI
5583 IDirect3DDeviceImpl_7_SetLight_FPUSetup(IDirect3DDevice7 *iface,
5584                                DWORD LightIndex,
5585                                D3DLIGHT7 *Light)
5586 {
5587     return IDirect3DDeviceImpl_7_SetLight(iface, LightIndex, Light);
5588 }
5589
5590 static HRESULT WINAPI
5591 IDirect3DDeviceImpl_7_SetLight_FPUPreserve(IDirect3DDevice7 *iface,
5592                                DWORD LightIndex,
5593                                D3DLIGHT7 *Light)
5594 {
5595     HRESULT hr;
5596     WORD old_fpucw;
5597
5598     old_fpucw = d3d_fpu_setup();
5599     hr = IDirect3DDeviceImpl_7_SetLight(iface, LightIndex, Light);
5600     set_fpu_control_word(old_fpucw);
5601
5602     return hr;
5603 }
5604
5605 /*****************************************************************************
5606  * IDirect3DDevice7::GetLight
5607  *
5608  * Returns the light assigned to a light index
5609  *
5610  * Params:
5611  *  Light: Structure to write the light information to
5612  *
5613  * Returns:
5614  *  D3D_OK on success
5615  *  DDERR_INVALIDPARAMS if Light is NULL
5616  *  For details, see IWineD3DDevice::GetLight
5617  *
5618  *****************************************************************************/
5619 static HRESULT
5620 IDirect3DDeviceImpl_7_GetLight(IDirect3DDevice7 *iface,
5621                                DWORD LightIndex,
5622                                D3DLIGHT7 *Light)
5623 {
5624     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5625     HRESULT rc;
5626     TRACE("(%p)->(%08x,%p): Relay!\n", This, LightIndex, Light);
5627
5628     EnterCriticalSection(&ddraw_cs);
5629     /* Note: D3DLIGHT7 is compatible with WINED3DLIGHT */
5630     rc =  IWineD3DDevice_GetLight(This->wineD3DDevice,
5631                                   LightIndex,
5632                                   (WINED3DLIGHT*) Light);
5633
5634     /* Translate the result. WineD3D returns other values than D3D7 */
5635     LeaveCriticalSection(&ddraw_cs);
5636     return hr_ddraw_from_wined3d(rc);
5637 }
5638
5639 static HRESULT WINAPI
5640 IDirect3DDeviceImpl_7_GetLight_FPUSetup(IDirect3DDevice7 *iface,
5641                                DWORD LightIndex,
5642                                D3DLIGHT7 *Light)
5643 {
5644     return IDirect3DDeviceImpl_7_GetLight(iface, LightIndex, Light);
5645 }
5646
5647 static HRESULT WINAPI
5648 IDirect3DDeviceImpl_7_GetLight_FPUPreserve(IDirect3DDevice7 *iface,
5649                                DWORD LightIndex,
5650                                D3DLIGHT7 *Light)
5651 {
5652     HRESULT hr;
5653     WORD old_fpucw;
5654
5655     old_fpucw = d3d_fpu_setup();
5656     hr = IDirect3DDeviceImpl_7_GetLight(iface, LightIndex, Light);
5657     set_fpu_control_word(old_fpucw);
5658
5659     return hr;
5660 }
5661
5662 /*****************************************************************************
5663  * IDirect3DDevice7::BeginStateBlock
5664  *
5665  * Begins recording to a stateblock
5666  *
5667  * Version 7
5668  *
5669  * Returns:
5670  *  D3D_OK on success
5671  *  For details see IWineD3DDevice::BeginStateBlock
5672  *
5673  *****************************************************************************/
5674 static HRESULT
5675 IDirect3DDeviceImpl_7_BeginStateBlock(IDirect3DDevice7 *iface)
5676 {
5677     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5678     HRESULT hr;
5679     TRACE("(%p)->(): Relay!\n", This);
5680
5681     EnterCriticalSection(&ddraw_cs);
5682     hr = IWineD3DDevice_BeginStateBlock(This->wineD3DDevice);
5683     LeaveCriticalSection(&ddraw_cs);
5684     return hr_ddraw_from_wined3d(hr);
5685 }
5686
5687 static HRESULT WINAPI
5688 IDirect3DDeviceImpl_7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5689 {
5690     return IDirect3DDeviceImpl_7_BeginStateBlock(iface);
5691 }
5692
5693 static HRESULT WINAPI
5694 IDirect3DDeviceImpl_7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5695 {
5696     HRESULT hr;
5697     WORD old_fpucw;
5698
5699     old_fpucw = d3d_fpu_setup();
5700     hr = IDirect3DDeviceImpl_7_BeginStateBlock(iface);
5701     set_fpu_control_word(old_fpucw);
5702
5703     return hr;
5704 }
5705
5706 /*****************************************************************************
5707  * IDirect3DDevice7::EndStateBlock
5708  *
5709  * Stops recording to a state block and returns the created stateblock
5710  * handle.
5711  *
5712  * Version 7
5713  *
5714  * Params:
5715  *  BlockHandle: Address to store the stateblock's handle to
5716  *
5717  * Returns:
5718  *  D3D_OK on success
5719  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5720  *  See IWineD3DDevice::EndStateBlock for more details
5721  *
5722  *****************************************************************************/
5723 static HRESULT
5724 IDirect3DDeviceImpl_7_EndStateBlock(IDirect3DDevice7 *iface,
5725                                     DWORD *BlockHandle)
5726 {
5727     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5728     HRESULT hr;
5729     TRACE("(%p)->(%p): Relay!\n", This, BlockHandle);
5730
5731     if(!BlockHandle)
5732     {
5733         WARN("BlockHandle == NULL, returning DDERR_INVALIDPARAMS\n");
5734         return DDERR_INVALIDPARAMS;
5735     }
5736
5737     EnterCriticalSection(&ddraw_cs);
5738     *BlockHandle = IDirect3DDeviceImpl_CreateHandle(This);
5739     if(!*BlockHandle)
5740     {
5741         ERR("Cannot get a handle number for the stateblock\n");
5742         LeaveCriticalSection(&ddraw_cs);
5743         return DDERR_OUTOFMEMORY;
5744     }
5745     This->Handles[*BlockHandle - 1].type = DDrawHandle_StateBlock;
5746     hr = IWineD3DDevice_EndStateBlock(This->wineD3DDevice,
5747                                       (IWineD3DStateBlock **) &This->Handles[*BlockHandle - 1].ptr);
5748     LeaveCriticalSection(&ddraw_cs);
5749     return hr_ddraw_from_wined3d(hr);
5750 }
5751
5752 static HRESULT WINAPI
5753 IDirect3DDeviceImpl_7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5754                                     DWORD *BlockHandle)
5755 {
5756     return IDirect3DDeviceImpl_7_EndStateBlock(iface, BlockHandle);
5757 }
5758
5759 static HRESULT WINAPI
5760 IDirect3DDeviceImpl_7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5761                                     DWORD *BlockHandle)
5762 {
5763     HRESULT hr;
5764     WORD old_fpucw;
5765
5766     old_fpucw = d3d_fpu_setup();
5767     hr = IDirect3DDeviceImpl_7_EndStateBlock(iface, BlockHandle);
5768     set_fpu_control_word(old_fpucw);
5769
5770     return hr;
5771 }
5772
5773 /*****************************************************************************
5774  * IDirect3DDevice7::PreLoad
5775  *
5776  * Allows the app to signal that a texture will be used soon, to allow
5777  * the Direct3DDevice to load it to the video card in the meantime.
5778  *
5779  * Version 7
5780  *
5781  * Params:
5782  *  Texture: The texture to preload
5783  *
5784  * Returns:
5785  *  D3D_OK on success
5786  *  DDERR_INVALIDPARAMS if Texture is NULL
5787  *  See IWineD3DSurface::PreLoad for details
5788  *
5789  *****************************************************************************/
5790 static HRESULT
5791 IDirect3DDeviceImpl_7_PreLoad(IDirect3DDevice7 *iface,
5792                               IDirectDrawSurface7 *Texture)
5793 {
5794     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5795     IDirectDrawSurfaceImpl *surf = (IDirectDrawSurfaceImpl *)Texture;
5796
5797     TRACE("(%p)->(%p): Relay!\n", This, surf);
5798
5799     if(!Texture)
5800         return DDERR_INVALIDPARAMS;
5801
5802     EnterCriticalSection(&ddraw_cs);
5803     IWineD3DSurface_PreLoad(surf->WineD3DSurface);
5804     LeaveCriticalSection(&ddraw_cs);
5805     return D3D_OK;
5806 }
5807
5808 static HRESULT WINAPI
5809 IDirect3DDeviceImpl_7_PreLoad_FPUSetup(IDirect3DDevice7 *iface,
5810                               IDirectDrawSurface7 *Texture)
5811 {
5812     return IDirect3DDeviceImpl_7_PreLoad(iface, Texture);
5813 }
5814
5815 static HRESULT WINAPI
5816 IDirect3DDeviceImpl_7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface,
5817                               IDirectDrawSurface7 *Texture)
5818 {
5819     HRESULT hr;
5820     WORD old_fpucw;
5821
5822     old_fpucw = d3d_fpu_setup();
5823     hr = IDirect3DDeviceImpl_7_PreLoad(iface, Texture);
5824     set_fpu_control_word(old_fpucw);
5825
5826     return hr;
5827 }
5828
5829 /*****************************************************************************
5830  * IDirect3DDevice7::ApplyStateBlock
5831  *
5832  * Activates the state stored in a state block handle.
5833  *
5834  * Params:
5835  *  BlockHandle: The stateblock handle to activate
5836  *
5837  * Returns:
5838  *  D3D_OK on success
5839  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5840  *
5841  *****************************************************************************/
5842 static HRESULT
5843 IDirect3DDeviceImpl_7_ApplyStateBlock(IDirect3DDevice7 *iface,
5844                                       DWORD BlockHandle)
5845 {
5846     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5847     HRESULT hr;
5848     TRACE("(%p)->(%08x): Relay!\n", This, BlockHandle);
5849
5850     EnterCriticalSection(&ddraw_cs);
5851     if(!BlockHandle || BlockHandle > This->numHandles)
5852     {
5853         WARN("Out of range handle %d, returning D3DERR_INVALIDSTATEBLOCK\n", BlockHandle);
5854         LeaveCriticalSection(&ddraw_cs);
5855         return D3DERR_INVALIDSTATEBLOCK;
5856     }
5857     if(This->Handles[BlockHandle - 1].type != DDrawHandle_StateBlock)
5858     {
5859         WARN("Handle %d is not a stateblock, returning D3DERR_INVALIDSTATEBLOCK\n", BlockHandle);
5860         LeaveCriticalSection(&ddraw_cs);
5861         return D3DERR_INVALIDSTATEBLOCK;
5862     }
5863
5864     hr = IWineD3DStateBlock_Apply((IWineD3DStateBlock *) This->Handles[BlockHandle - 1].ptr);
5865     LeaveCriticalSection(&ddraw_cs);
5866     return hr_ddraw_from_wined3d(hr);
5867 }
5868
5869 static HRESULT WINAPI
5870 IDirect3DDeviceImpl_7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5871                                       DWORD BlockHandle)
5872 {
5873     return IDirect3DDeviceImpl_7_ApplyStateBlock(iface, BlockHandle);
5874 }
5875
5876 static HRESULT WINAPI
5877 IDirect3DDeviceImpl_7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5878                                       DWORD BlockHandle)
5879 {
5880     HRESULT hr;
5881     WORD old_fpucw;
5882
5883     old_fpucw = d3d_fpu_setup();
5884     hr = IDirect3DDeviceImpl_7_ApplyStateBlock(iface, BlockHandle);
5885     set_fpu_control_word(old_fpucw);
5886
5887     return hr;
5888 }
5889
5890 /*****************************************************************************
5891  * IDirect3DDevice7::CaptureStateBlock
5892  *
5893  * Updates a stateblock's values to the values currently set for the device
5894  *
5895  * Version 7
5896  *
5897  * Params:
5898  *  BlockHandle: Stateblock to update
5899  *
5900  * Returns:
5901  *  D3D_OK on success
5902  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5903  *  See IWineD3DDevice::CaptureStateBlock for more details
5904  *
5905  *****************************************************************************/
5906 static HRESULT
5907 IDirect3DDeviceImpl_7_CaptureStateBlock(IDirect3DDevice7 *iface,
5908                                         DWORD BlockHandle)
5909 {
5910     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5911     HRESULT hr;
5912     TRACE("(%p)->(%08x): Relay!\n", This, BlockHandle);
5913
5914     EnterCriticalSection(&ddraw_cs);
5915     if(BlockHandle == 0 || BlockHandle > This->numHandles)
5916     {
5917         WARN("Out of range handle %d, returning D3DERR_INVALIDSTATEBLOCK\n", BlockHandle);
5918         LeaveCriticalSection(&ddraw_cs);
5919         return D3DERR_INVALIDSTATEBLOCK;
5920     }
5921     if(This->Handles[BlockHandle - 1].type != DDrawHandle_StateBlock)
5922     {
5923         WARN("Handle %d is not a stateblock, returning D3DERR_INVALIDSTATEBLOCK\n", BlockHandle);
5924         LeaveCriticalSection(&ddraw_cs);
5925         return D3DERR_INVALIDSTATEBLOCK;
5926     }
5927
5928     hr = IWineD3DStateBlock_Capture((IWineD3DStateBlock *) This->Handles[BlockHandle - 1].ptr);
5929     LeaveCriticalSection(&ddraw_cs);
5930     return hr_ddraw_from_wined3d(hr);
5931 }
5932
5933 static HRESULT WINAPI
5934 IDirect3DDeviceImpl_7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5935                                         DWORD BlockHandle)
5936 {
5937     return IDirect3DDeviceImpl_7_CaptureStateBlock(iface, BlockHandle);
5938 }
5939
5940 static HRESULT WINAPI
5941 IDirect3DDeviceImpl_7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5942                                         DWORD BlockHandle)
5943 {
5944     HRESULT hr;
5945     WORD old_fpucw;
5946
5947     old_fpucw = d3d_fpu_setup();
5948     hr = IDirect3DDeviceImpl_7_CaptureStateBlock(iface, BlockHandle);
5949     set_fpu_control_word(old_fpucw);
5950
5951     return hr;
5952 }
5953
5954 /*****************************************************************************
5955  * IDirect3DDevice7::DeleteStateBlock
5956  *
5957  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5958  *
5959  * Version 7
5960  *
5961  * Params:
5962  *  BlockHandle: Stateblock handle to delete
5963  *
5964  * Returns:
5965  *  D3D_OK on success
5966  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5967  *
5968  *****************************************************************************/
5969 static HRESULT
5970 IDirect3DDeviceImpl_7_DeleteStateBlock(IDirect3DDevice7 *iface,
5971                                        DWORD BlockHandle)
5972 {
5973     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5974     ULONG ref;
5975     TRACE("(%p)->(%08x): Relay!\n", This, BlockHandle);
5976
5977     EnterCriticalSection(&ddraw_cs);
5978     if(BlockHandle == 0 || BlockHandle > This->numHandles)
5979     {
5980         WARN("Out of range handle %d, returning D3DERR_INVALIDSTATEBLOCK\n", BlockHandle);
5981         LeaveCriticalSection(&ddraw_cs);
5982         return D3DERR_INVALIDSTATEBLOCK;
5983     }
5984     if(This->Handles[BlockHandle - 1].type != DDrawHandle_StateBlock)
5985     {
5986         WARN("Handle %d is not a stateblock, returning D3DERR_INVALIDSTATEBLOCK\n", BlockHandle);
5987         LeaveCriticalSection(&ddraw_cs);
5988         return D3DERR_INVALIDSTATEBLOCK;
5989     }
5990
5991     ref = IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->Handles[BlockHandle - 1].ptr);
5992     if(ref)
5993     {
5994         ERR("Something is still holding the stateblock %p(Handle %d). Ref = %d\n", This->Handles[BlockHandle - 1].ptr, BlockHandle, ref);
5995     }
5996     This->Handles[BlockHandle - 1].ptr = NULL;
5997     This->Handles[BlockHandle - 1].type = DDrawHandle_Unknown;
5998
5999     LeaveCriticalSection(&ddraw_cs);
6000     return D3D_OK;
6001 }
6002
6003 static HRESULT WINAPI
6004 IDirect3DDeviceImpl_7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface,
6005                                        DWORD BlockHandle)
6006 {
6007     return IDirect3DDeviceImpl_7_DeleteStateBlock(iface, BlockHandle);
6008 }
6009
6010 static HRESULT WINAPI
6011 IDirect3DDeviceImpl_7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
6012                                        DWORD BlockHandle)
6013 {
6014     HRESULT hr;
6015     WORD old_fpucw;
6016
6017     old_fpucw = d3d_fpu_setup();
6018     hr = IDirect3DDeviceImpl_7_DeleteStateBlock(iface, BlockHandle);
6019     set_fpu_control_word(old_fpucw);
6020
6021     return hr;
6022 }
6023
6024 /*****************************************************************************
6025  * IDirect3DDevice7::CreateStateBlock
6026  *
6027  * Creates a new state block handle.
6028  *
6029  * Version 7
6030  *
6031  * Params:
6032  *  Type: The state block type
6033  *  BlockHandle: Address to write the created handle to
6034  *
6035  * Returns:
6036  *   D3D_OK on success
6037  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
6038  *
6039  *****************************************************************************/
6040 static HRESULT
6041 IDirect3DDeviceImpl_7_CreateStateBlock(IDirect3DDevice7 *iface,
6042                                        D3DSTATEBLOCKTYPE Type,
6043                                        DWORD *BlockHandle)
6044 {
6045     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6046     HRESULT hr;
6047     TRACE("(%p)->(%08x,%p)!\n", This, Type, BlockHandle);
6048
6049     if(!BlockHandle)
6050     {
6051         WARN("BlockHandle == NULL, returning DDERR_INVALIDPARAMS\n");
6052         return DDERR_INVALIDPARAMS;
6053     }
6054     if(Type != D3DSBT_ALL         && Type != D3DSBT_PIXELSTATE &&
6055        Type != D3DSBT_VERTEXSTATE                              ) {
6056         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
6057         return DDERR_INVALIDPARAMS;
6058     }
6059
6060     EnterCriticalSection(&ddraw_cs);
6061     *BlockHandle = IDirect3DDeviceImpl_CreateHandle(This);
6062     if(!*BlockHandle)
6063     {
6064         ERR("Cannot get a handle number for the stateblock\n");
6065         LeaveCriticalSection(&ddraw_cs);
6066         return DDERR_OUTOFMEMORY;
6067     }
6068     This->Handles[*BlockHandle - 1].type = DDrawHandle_StateBlock;
6069
6070     /* The D3DSTATEBLOCKTYPE enum is fine here */
6071     hr = IWineD3DDevice_CreateStateBlock(This->wineD3DDevice,
6072                                          Type,
6073                                          (IWineD3DStateBlock **) &This->Handles[*BlockHandle - 1].ptr,
6074                                          NULL /* Parent, hope that works */);
6075     LeaveCriticalSection(&ddraw_cs);
6076     return hr_ddraw_from_wined3d(hr);
6077 }
6078
6079 static HRESULT WINAPI
6080 IDirect3DDeviceImpl_7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
6081                                        D3DSTATEBLOCKTYPE Type,
6082                                        DWORD *BlockHandle)
6083 {
6084     return IDirect3DDeviceImpl_7_CreateStateBlock(iface, Type, BlockHandle);
6085 }
6086
6087 static HRESULT WINAPI
6088 IDirect3DDeviceImpl_7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
6089                                        D3DSTATEBLOCKTYPE Type,
6090                                        DWORD *BlockHandle)
6091 {
6092     HRESULT hr;
6093     WORD old_fpucw;
6094
6095     old_fpucw = d3d_fpu_setup();
6096     hr =IDirect3DDeviceImpl_7_CreateStateBlock(iface, Type, BlockHandle);
6097     set_fpu_control_word(old_fpucw);
6098
6099     return hr;
6100 }
6101
6102 /* Helper function for IDirect3DDeviceImpl_7_Load. */
6103 static BOOL is_mip_level_subset(IDirectDrawSurfaceImpl *dest,
6104                                 IDirectDrawSurfaceImpl *src)
6105 {
6106     IDirectDrawSurfaceImpl *src_level, *dest_level;
6107     IDirectDrawSurface7 *temp;
6108     DDSURFACEDESC2 ddsd;
6109     BOOL levelFound; /* at least one suitable sublevel in dest found */
6110
6111     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
6112      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
6113      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
6114      */
6115     levelFound = FALSE;
6116
6117     src_level = src;
6118     dest_level = dest;
6119
6120     for (;src_level && dest_level;)
6121     {
6122         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6123             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6124         {
6125             levelFound = TRUE;
6126
6127             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6128             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6129             IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)dest_level, &ddsd.ddsCaps, &temp);
6130
6131             if (dest_level != dest) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)dest_level);
6132
6133             dest_level = (IDirectDrawSurfaceImpl *)temp;
6134         }
6135
6136         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6137         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6138         IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)src_level, &ddsd.ddsCaps, &temp);
6139
6140         if (src_level != src) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)src_level);
6141
6142         src_level = (IDirectDrawSurfaceImpl *)temp;
6143     }
6144
6145     if (src_level && src_level != src) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)src_level);
6146     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)dest_level);
6147
6148     return !dest_level && levelFound;
6149 }
6150
6151 /* Helper function for IDirect3DDeviceImpl_7_Load. */
6152 static void copy_mipmap_chain(IDirect3DDeviceImpl *device,
6153                               IDirectDrawSurfaceImpl *dest,
6154                               IDirectDrawSurfaceImpl *src,
6155                               POINT *DestPoint,
6156                               RECT *SrcRect)
6157 {
6158     IDirectDrawSurfaceImpl *src_level, *dest_level;
6159     IDirectDrawSurface7 *temp;
6160     DDSURFACEDESC2 ddsd;
6161     POINT point;
6162     RECT rect;
6163     HRESULT hr;
6164     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
6165     DWORD ckeyflag;
6166     DDCOLORKEY ddckey;
6167     BOOL palette_missing = FALSE;
6168
6169     /* Copy palette, if possible. */
6170     IDirectDrawSurface7_GetPalette((IDirectDrawSurface7 *)src, &pal_src);
6171     IDirectDrawSurface7_GetPalette((IDirectDrawSurface7 *)dest, &pal);
6172
6173     if (pal_src != NULL && pal != NULL)
6174     {
6175         PALETTEENTRY palent[256];
6176
6177         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
6178         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
6179     }
6180
6181     if (dest->surface_desc.u4.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
6182             DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8) && !pal)
6183     {
6184         palette_missing = TRUE;
6185     }
6186
6187     if (pal) IDirectDrawPalette_Release(pal);
6188     if (pal_src) IDirectDrawPalette_Release(pal_src);
6189
6190     /* Copy colorkeys, if present. */
6191     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
6192     {
6193         hr = IDirectDrawSurface7_GetColorKey((IDirectDrawSurface7 *)src, ckeyflag, &ddckey);
6194
6195         if (SUCCEEDED(hr))
6196         {
6197             IDirectDrawSurface7_SetColorKey((IDirectDrawSurface7 *)dest, ckeyflag, &ddckey);
6198         }
6199     }
6200
6201     src_level = src;
6202     dest_level = dest;
6203
6204     point = *DestPoint;
6205     rect = *SrcRect;
6206
6207     for (;src_level && dest_level;)
6208     {
6209         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6210             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6211         {
6212             /* Try UpdateSurface that may perform a more direct opengl loading. But skip this if destination is paletted texture and has no palette.
6213              * Some games like Sacrifice set palette after Load, and it is a waste of effort to try to load texture without palette and generates
6214              * warnings in wined3d. */
6215             if (!palette_missing)
6216                 hr = IWineD3DDevice_UpdateSurface(device->wineD3DDevice, src_level->WineD3DSurface, &rect, dest_level->WineD3DSurface,
6217                                 &point);
6218
6219             if (palette_missing || FAILED(hr))
6220             {
6221                 /* UpdateSurface may fail e.g. if dest is in system memory. Fall back to BltFast that is less strict. */
6222                 IWineD3DSurface_BltFast(dest_level->WineD3DSurface,
6223                                         point.x, point.y,
6224                                         src_level->WineD3DSurface, &rect, 0);
6225             }
6226
6227             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6228             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6229             IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)dest_level, &ddsd.ddsCaps, &temp);
6230
6231             if (dest_level != dest) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)dest_level);
6232
6233             dest_level = (IDirectDrawSurfaceImpl *)temp;
6234         }
6235
6236         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6237         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6238         IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)src_level, &ddsd.ddsCaps, &temp);
6239
6240         if (src_level != src) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)src_level);
6241
6242         src_level = (IDirectDrawSurfaceImpl *)temp;
6243
6244         point.x /= 2;
6245         point.y /= 2;
6246
6247         rect.top /= 2;
6248         rect.left /= 2;
6249         rect.right = (rect.right + 1) / 2;
6250         rect.bottom = (rect.bottom + 1) / 2;
6251     }
6252
6253     if (src_level && src_level != src) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)src_level);
6254     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)dest_level);
6255 }
6256
6257 /*****************************************************************************
6258  * IDirect3DDevice7::Load
6259  *
6260  * Loads a rectangular area from the source into the destination texture.
6261  * It can also copy the source to the faces of a cubic environment map
6262  *
6263  * Version 7
6264  *
6265  * Params:
6266  *  DestTex: Destination texture
6267  *  DestPoint: Point in the destination where the source image should be
6268  *             written to
6269  *  SrcTex: Source texture
6270  *  SrcRect: Source rectangle
6271  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6272  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6273  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6274  *
6275  * Returns:
6276  *  D3D_OK on success
6277  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
6278  *
6279  *
6280  *****************************************************************************/
6281
6282 static HRESULT
6283 IDirect3DDeviceImpl_7_Load(IDirect3DDevice7 *iface,
6284                            IDirectDrawSurface7 *DestTex,
6285                            POINT *DestPoint,
6286                            IDirectDrawSurface7 *SrcTex,
6287                            RECT *SrcRect,
6288                            DWORD Flags)
6289 {
6290     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6291     IDirectDrawSurfaceImpl *dest = (IDirectDrawSurfaceImpl *)DestTex;
6292     IDirectDrawSurfaceImpl *src = (IDirectDrawSurfaceImpl *)SrcTex;
6293     POINT destpoint;
6294     RECT srcrect;
6295     TRACE("(%p)->(%p,%p,%p,%p,%08x)\n", This, dest, DestPoint, src, SrcRect, Flags);
6296
6297     if( (!src) || (!dest) )
6298         return DDERR_INVALIDPARAMS;
6299
6300     EnterCriticalSection(&ddraw_cs);
6301
6302     if (SrcRect) srcrect = *SrcRect;
6303     else
6304     {
6305         srcrect.left = srcrect.top = 0;
6306         srcrect.right = src->surface_desc.dwWidth;
6307         srcrect.bottom = src->surface_desc.dwHeight;
6308     }
6309
6310     if (DestPoint) destpoint = *DestPoint;
6311     else
6312     {
6313         destpoint.x = destpoint.y = 0;
6314     }
6315     /* Check bad dimensions. DestPoint is validated against src, not dest, because
6316      * destination can be a subset of mip levels, in which case actual coordinates used
6317      * for it may be divided. If any dimension of dest is larger than source, it can't be
6318      * mip level subset, so an error can be returned early.
6319      */
6320     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
6321         srcrect.right > src->surface_desc.dwWidth ||
6322         srcrect.bottom > src->surface_desc.dwHeight ||
6323         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6324         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6325         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6326         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6327     {
6328         LeaveCriticalSection(&ddraw_cs);
6329         return DDERR_INVALIDPARAMS;
6330     }
6331
6332     /* Must be top level surfaces. */
6333     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6334         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6335     {
6336         LeaveCriticalSection(&ddraw_cs);
6337         return DDERR_INVALIDPARAMS;
6338     }
6339
6340     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6341     {
6342         DWORD src_face_flag, dest_face_flag;
6343         IDirectDrawSurfaceImpl *src_face, *dest_face;
6344         IDirectDrawSurface7 *temp;
6345         DDSURFACEDESC2 ddsd;
6346         int i;
6347
6348         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6349         {
6350             LeaveCriticalSection(&ddraw_cs);
6351             return DDERR_INVALIDPARAMS;
6352         }
6353
6354         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6355          * time it's actual surface loading. */
6356         for (i = 0; i < 2; i++)
6357         {
6358             dest_face = dest;
6359             src_face = src;
6360
6361             for (;dest_face && src_face;)
6362             {
6363                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6364                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6365
6366                 if (src_face_flag == dest_face_flag)
6367                 {
6368                     if (i == 0)
6369                     {
6370                         /* Destination mip levels must be subset of source mip levels. */
6371                         if (!is_mip_level_subset(dest_face, src_face))
6372                         {
6373                             LeaveCriticalSection(&ddraw_cs);
6374                             return DDERR_INVALIDPARAMS;
6375                         }
6376                     }
6377                     else if (Flags & dest_face_flag)
6378                     {
6379                         copy_mipmap_chain(This, dest_face, src_face, &destpoint, &srcrect);
6380                     }
6381
6382                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6383                     {
6384                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6385                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6386                         IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)src, &ddsd.ddsCaps, &temp);
6387
6388                         if (src_face != src) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)src_face);
6389
6390                         src_face = (IDirectDrawSurfaceImpl *)temp;
6391                     }
6392                     else
6393                     {
6394                         if (src_face != src) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)src_face);
6395
6396                         src_face = NULL;
6397                     }
6398                 }
6399
6400                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6401                 {
6402                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6403                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6404                     IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)dest, &ddsd.ddsCaps, &temp);
6405
6406                     if (dest_face != dest) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)dest_face);
6407
6408                     dest_face = (IDirectDrawSurfaceImpl *)temp;
6409                 }
6410                 else
6411                 {
6412                     if (dest_face != dest) IDirectDrawSurface7_Release((IDirectDrawSurface7 *)dest_face);
6413
6414                     dest_face = NULL;
6415                 }
6416             }
6417
6418             if (i == 0)
6419             {
6420                 /* Native returns error if src faces are not subset of dest faces. */
6421                 if (src_face)
6422                 {
6423                     LeaveCriticalSection(&ddraw_cs);
6424                     return DDERR_INVALIDPARAMS;
6425                 }
6426             }
6427         }
6428
6429         LeaveCriticalSection(&ddraw_cs);
6430         return D3D_OK;
6431     }
6432     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6433     {
6434         LeaveCriticalSection(&ddraw_cs);
6435         return DDERR_INVALIDPARAMS;
6436     }
6437
6438     /* Handle non cube map textures. */
6439
6440     /* Destination mip levels must be subset of source mip levels. */
6441     if (!is_mip_level_subset(dest, src))
6442     {
6443         LeaveCriticalSection(&ddraw_cs);
6444         return DDERR_INVALIDPARAMS;
6445     }
6446
6447     copy_mipmap_chain(This, dest, src, &destpoint, &srcrect);
6448
6449     LeaveCriticalSection(&ddraw_cs);
6450     return D3D_OK;
6451 }
6452
6453 static HRESULT WINAPI
6454 IDirect3DDeviceImpl_7_Load_FPUSetup(IDirect3DDevice7 *iface,
6455                            IDirectDrawSurface7 *DestTex,
6456                            POINT *DestPoint,
6457                            IDirectDrawSurface7 *SrcTex,
6458                            RECT *SrcRect,
6459                            DWORD Flags)
6460 {
6461     return IDirect3DDeviceImpl_7_Load(iface, DestTex, DestPoint, SrcTex, SrcRect, Flags);
6462 }
6463
6464 static HRESULT WINAPI
6465 IDirect3DDeviceImpl_7_Load_FPUPreserve(IDirect3DDevice7 *iface,
6466                            IDirectDrawSurface7 *DestTex,
6467                            POINT *DestPoint,
6468                            IDirectDrawSurface7 *SrcTex,
6469                            RECT *SrcRect,
6470                            DWORD Flags)
6471 {
6472     HRESULT hr;
6473     WORD old_fpucw;
6474
6475     old_fpucw = d3d_fpu_setup();
6476     hr = IDirect3DDeviceImpl_7_Load(iface, DestTex, DestPoint, SrcTex, SrcRect, Flags);
6477     set_fpu_control_word(old_fpucw);
6478
6479     return hr;
6480 }
6481
6482 /*****************************************************************************
6483  * IDirect3DDevice7::LightEnable
6484  *
6485  * Enables or disables a light
6486  *
6487  * Version 7, IDirect3DLight uses this method too.
6488  *
6489  * Params:
6490  *  LightIndex: The index of the light to enable / disable
6491  *  Enable: Enable or disable the light
6492  *
6493  * Returns:
6494  *  D3D_OK on success
6495  *  For more details, see IWineD3DDevice::SetLightEnable
6496  *
6497  *****************************************************************************/
6498 static HRESULT
6499 IDirect3DDeviceImpl_7_LightEnable(IDirect3DDevice7 *iface,
6500                                   DWORD LightIndex,
6501                                   BOOL Enable)
6502 {
6503     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6504     HRESULT hr;
6505     TRACE("(%p)->(%08x,%d): Relay!\n", This, LightIndex, Enable);
6506
6507     EnterCriticalSection(&ddraw_cs);
6508     hr = IWineD3DDevice_SetLightEnable(This->wineD3DDevice, LightIndex, Enable);
6509     LeaveCriticalSection(&ddraw_cs);
6510     return hr_ddraw_from_wined3d(hr);
6511 }
6512
6513 static HRESULT WINAPI
6514 IDirect3DDeviceImpl_7_LightEnable_FPUSetup(IDirect3DDevice7 *iface,
6515                                   DWORD LightIndex,
6516                                   BOOL Enable)
6517 {
6518     return IDirect3DDeviceImpl_7_LightEnable(iface, LightIndex, Enable);
6519 }
6520
6521 static HRESULT WINAPI
6522 IDirect3DDeviceImpl_7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface,
6523                                   DWORD LightIndex,
6524                                   BOOL Enable)
6525 {
6526     HRESULT hr;
6527     WORD old_fpucw;
6528
6529     old_fpucw = d3d_fpu_setup();
6530     hr = IDirect3DDeviceImpl_7_LightEnable(iface, LightIndex, Enable);
6531     set_fpu_control_word(old_fpucw);
6532
6533     return hr;
6534 }
6535
6536 /*****************************************************************************
6537  * IDirect3DDevice7::GetLightEnable
6538  *
6539  * Retrieves if the light with the given index is enabled or not
6540  *
6541  * Version 7
6542  *
6543  * Params:
6544  *  LightIndex: Index of desired light
6545  *  Enable: Pointer to a BOOL which contains the result
6546  *
6547  * Returns:
6548  *  D3D_OK on success
6549  *  DDERR_INVALIDPARAMS if Enable is NULL
6550  *  See IWineD3DDevice::GetLightEnable for more details
6551  *
6552  *****************************************************************************/
6553 static HRESULT
6554 IDirect3DDeviceImpl_7_GetLightEnable(IDirect3DDevice7 *iface,
6555                                      DWORD LightIndex,
6556                                      BOOL* Enable)
6557 {
6558     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6559     HRESULT hr;
6560     TRACE("(%p)->(%08x,%p): Relay\n", This, LightIndex, Enable);
6561
6562     if(!Enable)
6563         return DDERR_INVALIDPARAMS;
6564
6565     EnterCriticalSection(&ddraw_cs);
6566     hr = IWineD3DDevice_GetLightEnable(This->wineD3DDevice, LightIndex, Enable);
6567     LeaveCriticalSection(&ddraw_cs);
6568     return hr_ddraw_from_wined3d(hr);
6569 }
6570
6571 static HRESULT WINAPI
6572 IDirect3DDeviceImpl_7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface,
6573                                      DWORD LightIndex,
6574                                      BOOL* Enable)
6575 {
6576     return IDirect3DDeviceImpl_7_GetLightEnable(iface, LightIndex, Enable);
6577 }
6578
6579 static HRESULT WINAPI
6580 IDirect3DDeviceImpl_7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface,
6581                                      DWORD LightIndex,
6582                                      BOOL* Enable)
6583 {
6584     HRESULT hr;
6585     WORD old_fpucw;
6586
6587     old_fpucw = d3d_fpu_setup();
6588     hr = IDirect3DDeviceImpl_7_GetLightEnable(iface, LightIndex, Enable);
6589     set_fpu_control_word(old_fpucw);
6590
6591     return hr;
6592 }
6593
6594 /*****************************************************************************
6595  * IDirect3DDevice7::SetClipPlane
6596  *
6597  * Sets custom clipping plane
6598  *
6599  * Version 7
6600  *
6601  * Params:
6602  *  Index: The index of the clipping plane
6603  *  PlaneEquation: An equation defining the clipping plane
6604  *
6605  * Returns:
6606  *  D3D_OK on success
6607  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6608  *  See IWineD3DDevice::SetClipPlane for more details
6609  *
6610  *****************************************************************************/
6611 static HRESULT
6612 IDirect3DDeviceImpl_7_SetClipPlane(IDirect3DDevice7 *iface,
6613                                    DWORD Index,
6614                                    D3DVALUE* PlaneEquation)
6615 {
6616     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6617     HRESULT hr;
6618     TRACE("(%p)->(%08x,%p): Relay!\n", This, Index, PlaneEquation);
6619
6620     if(!PlaneEquation)
6621         return DDERR_INVALIDPARAMS;
6622
6623     EnterCriticalSection(&ddraw_cs);
6624     hr = IWineD3DDevice_SetClipPlane(This->wineD3DDevice, Index, PlaneEquation);
6625     LeaveCriticalSection(&ddraw_cs);
6626     return hr;
6627 }
6628
6629 static HRESULT WINAPI
6630 IDirect3DDeviceImpl_7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface,
6631                                    DWORD Index,
6632                                    D3DVALUE* PlaneEquation)
6633 {
6634     return IDirect3DDeviceImpl_7_SetClipPlane(iface, Index, PlaneEquation);
6635 }
6636
6637 static HRESULT WINAPI
6638 IDirect3DDeviceImpl_7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface,
6639                                    DWORD Index,
6640                                    D3DVALUE* PlaneEquation)
6641 {
6642     HRESULT hr;
6643     WORD old_fpucw;
6644
6645     old_fpucw = d3d_fpu_setup();
6646     hr = IDirect3DDeviceImpl_7_SetClipPlane(iface, Index, PlaneEquation);
6647     set_fpu_control_word(old_fpucw);
6648
6649     return hr;
6650 }
6651
6652 /*****************************************************************************
6653  * IDirect3DDevice7::GetClipPlane
6654  *
6655  * Returns the clipping plane with a specific index
6656  *
6657  * Params:
6658  *  Index: The index of the desired plane
6659  *  PlaneEquation: Address to store the plane equation to
6660  *
6661  * Returns:
6662  *  D3D_OK on success
6663  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6664  *  See IWineD3DDevice::GetClipPlane for more details
6665  *
6666  *****************************************************************************/
6667 static HRESULT
6668 IDirect3DDeviceImpl_7_GetClipPlane(IDirect3DDevice7 *iface,
6669                                    DWORD Index,
6670                                    D3DVALUE* PlaneEquation)
6671 {
6672     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6673     HRESULT hr;
6674     TRACE("(%p)->(%d,%p): Relay!\n", This, Index, PlaneEquation);
6675
6676     if(!PlaneEquation)
6677         return DDERR_INVALIDPARAMS;
6678
6679     EnterCriticalSection(&ddraw_cs);
6680     hr = IWineD3DDevice_GetClipPlane(This->wineD3DDevice, Index, PlaneEquation);
6681     LeaveCriticalSection(&ddraw_cs);
6682     return hr;
6683 }
6684
6685 static HRESULT WINAPI
6686 IDirect3DDeviceImpl_7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface,
6687                                    DWORD Index,
6688                                    D3DVALUE* PlaneEquation)
6689 {
6690     return IDirect3DDeviceImpl_7_GetClipPlane(iface, Index, PlaneEquation);
6691 }
6692
6693 static HRESULT WINAPI
6694 IDirect3DDeviceImpl_7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface,
6695                                    DWORD Index,
6696                                    D3DVALUE* PlaneEquation)
6697 {
6698     HRESULT hr;
6699     WORD old_fpucw;
6700
6701     old_fpucw = d3d_fpu_setup();
6702     hr = IDirect3DDeviceImpl_7_GetClipPlane(iface, Index, PlaneEquation);
6703     set_fpu_control_word(old_fpucw);
6704
6705     return hr;
6706 }
6707
6708 /*****************************************************************************
6709  * IDirect3DDevice7::GetInfo
6710  *
6711  * Retrieves some information about the device. The DirectX sdk says that
6712  * this version returns S_FALSE for all retail builds of DirectX, that's what
6713  * this implementation does.
6714  *
6715  * Params:
6716  *  DevInfoID: Information type requested
6717  *  DevInfoStruct: Pointer to a structure to store the info to
6718  *  Size: Size of the structure
6719  *
6720  * Returns:
6721  *  S_FALSE, because it's a non-debug driver
6722  *
6723  *****************************************************************************/
6724 static HRESULT WINAPI
6725 IDirect3DDeviceImpl_7_GetInfo(IDirect3DDevice7 *iface,
6726                               DWORD DevInfoID,
6727                               void *DevInfoStruct,
6728                               DWORD Size)
6729 {
6730     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6731     TRACE("(%p)->(%08x,%p,%08x)\n", This, DevInfoID, DevInfoStruct, Size);
6732
6733     if (TRACE_ON(d3d7))
6734     {
6735         TRACE(" info requested : ");
6736         switch (DevInfoID)
6737         {
6738             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6739             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6740             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6741             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6742         }
6743     }
6744
6745     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6746 }
6747
6748 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6749  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6750  * are not duplicated.
6751
6752  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6753  * has already been setup for optimal d3d operation.
6754
6755  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6756  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6757  * by Sacrifice (game). */
6758 const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUSetup_Vtbl =
6759 {
6760     /*** IUnknown Methods ***/
6761     IDirect3DDeviceImpl_7_QueryInterface,
6762     IDirect3DDeviceImpl_7_AddRef,
6763     IDirect3DDeviceImpl_7_Release,
6764     /*** IDirect3DDevice7 ***/
6765     IDirect3DDeviceImpl_7_GetCaps_FPUSetup,
6766     IDirect3DDeviceImpl_7_EnumTextureFormats_FPUSetup,
6767     IDirect3DDeviceImpl_7_BeginScene_FPUSetup,
6768     IDirect3DDeviceImpl_7_EndScene_FPUSetup,
6769     IDirect3DDeviceImpl_7_GetDirect3D,
6770     IDirect3DDeviceImpl_7_SetRenderTarget_FPUSetup,
6771     IDirect3DDeviceImpl_7_GetRenderTarget,
6772     IDirect3DDeviceImpl_7_Clear_FPUSetup,
6773     IDirect3DDeviceImpl_7_SetTransform_FPUSetup,
6774     IDirect3DDeviceImpl_7_GetTransform_FPUSetup,
6775     IDirect3DDeviceImpl_7_SetViewport_FPUSetup,
6776     IDirect3DDeviceImpl_7_MultiplyTransform_FPUSetup,
6777     IDirect3DDeviceImpl_7_GetViewport_FPUSetup,
6778     IDirect3DDeviceImpl_7_SetMaterial_FPUSetup,
6779     IDirect3DDeviceImpl_7_GetMaterial_FPUSetup,
6780     IDirect3DDeviceImpl_7_SetLight_FPUSetup,
6781     IDirect3DDeviceImpl_7_GetLight_FPUSetup,
6782     IDirect3DDeviceImpl_7_SetRenderState_FPUSetup,
6783     IDirect3DDeviceImpl_7_GetRenderState_FPUSetup,
6784     IDirect3DDeviceImpl_7_BeginStateBlock_FPUSetup,
6785     IDirect3DDeviceImpl_7_EndStateBlock_FPUSetup,
6786     IDirect3DDeviceImpl_7_PreLoad_FPUSetup,
6787     IDirect3DDeviceImpl_7_DrawPrimitive_FPUSetup,
6788     IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUSetup,
6789     IDirect3DDeviceImpl_7_SetClipStatus,
6790     IDirect3DDeviceImpl_7_GetClipStatus,
6791     IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUSetup,
6792     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUSetup,
6793     IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUSetup,
6794     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUSetup,
6795     IDirect3DDeviceImpl_7_ComputeSphereVisibility,
6796     IDirect3DDeviceImpl_7_GetTexture_FPUSetup,
6797     IDirect3DDeviceImpl_7_SetTexture_FPUSetup,
6798     IDirect3DDeviceImpl_7_GetTextureStageState_FPUSetup,
6799     IDirect3DDeviceImpl_7_SetTextureStageState_FPUSetup,
6800     IDirect3DDeviceImpl_7_ValidateDevice_FPUSetup,
6801     IDirect3DDeviceImpl_7_ApplyStateBlock_FPUSetup,
6802     IDirect3DDeviceImpl_7_CaptureStateBlock_FPUSetup,
6803     IDirect3DDeviceImpl_7_DeleteStateBlock_FPUSetup,
6804     IDirect3DDeviceImpl_7_CreateStateBlock_FPUSetup,
6805     IDirect3DDeviceImpl_7_Load_FPUSetup,
6806     IDirect3DDeviceImpl_7_LightEnable_FPUSetup,
6807     IDirect3DDeviceImpl_7_GetLightEnable_FPUSetup,
6808     IDirect3DDeviceImpl_7_SetClipPlane_FPUSetup,
6809     IDirect3DDeviceImpl_7_GetClipPlane_FPUSetup,
6810     IDirect3DDeviceImpl_7_GetInfo
6811 };
6812
6813 const IDirect3DDevice7Vtbl IDirect3DDevice7_FPUPreserve_Vtbl =
6814 {
6815     /*** IUnknown Methods ***/
6816     IDirect3DDeviceImpl_7_QueryInterface,
6817     IDirect3DDeviceImpl_7_AddRef,
6818     IDirect3DDeviceImpl_7_Release,
6819     /*** IDirect3DDevice7 ***/
6820     IDirect3DDeviceImpl_7_GetCaps_FPUPreserve,
6821     IDirect3DDeviceImpl_7_EnumTextureFormats_FPUPreserve,
6822     IDirect3DDeviceImpl_7_BeginScene_FPUPreserve,
6823     IDirect3DDeviceImpl_7_EndScene_FPUPreserve,
6824     IDirect3DDeviceImpl_7_GetDirect3D,
6825     IDirect3DDeviceImpl_7_SetRenderTarget_FPUPreserve,
6826     IDirect3DDeviceImpl_7_GetRenderTarget,
6827     IDirect3DDeviceImpl_7_Clear_FPUPreserve,
6828     IDirect3DDeviceImpl_7_SetTransform_FPUPreserve,
6829     IDirect3DDeviceImpl_7_GetTransform_FPUPreserve,
6830     IDirect3DDeviceImpl_7_SetViewport_FPUPreserve,
6831     IDirect3DDeviceImpl_7_MultiplyTransform_FPUPreserve,
6832     IDirect3DDeviceImpl_7_GetViewport_FPUPreserve,
6833     IDirect3DDeviceImpl_7_SetMaterial_FPUPreserve,
6834     IDirect3DDeviceImpl_7_GetMaterial_FPUPreserve,
6835     IDirect3DDeviceImpl_7_SetLight_FPUPreserve,
6836     IDirect3DDeviceImpl_7_GetLight_FPUPreserve,
6837     IDirect3DDeviceImpl_7_SetRenderState_FPUPreserve,
6838     IDirect3DDeviceImpl_7_GetRenderState_FPUPreserve,
6839     IDirect3DDeviceImpl_7_BeginStateBlock_FPUPreserve,
6840     IDirect3DDeviceImpl_7_EndStateBlock_FPUPreserve,
6841     IDirect3DDeviceImpl_7_PreLoad_FPUPreserve,
6842     IDirect3DDeviceImpl_7_DrawPrimitive_FPUPreserve,
6843     IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUPreserve,
6844     IDirect3DDeviceImpl_7_SetClipStatus,
6845     IDirect3DDeviceImpl_7_GetClipStatus,
6846     IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUPreserve,
6847     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUPreserve,
6848     IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUPreserve,
6849     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUPreserve,
6850     IDirect3DDeviceImpl_7_ComputeSphereVisibility,
6851     IDirect3DDeviceImpl_7_GetTexture_FPUPreserve,
6852     IDirect3DDeviceImpl_7_SetTexture_FPUPreserve,
6853     IDirect3DDeviceImpl_7_GetTextureStageState_FPUPreserve,
6854     IDirect3DDeviceImpl_7_SetTextureStageState_FPUPreserve,
6855     IDirect3DDeviceImpl_7_ValidateDevice_FPUPreserve,
6856     IDirect3DDeviceImpl_7_ApplyStateBlock_FPUPreserve,
6857     IDirect3DDeviceImpl_7_CaptureStateBlock_FPUPreserve,
6858     IDirect3DDeviceImpl_7_DeleteStateBlock_FPUPreserve,
6859     IDirect3DDeviceImpl_7_CreateStateBlock_FPUPreserve,
6860     IDirect3DDeviceImpl_7_Load_FPUPreserve,
6861     IDirect3DDeviceImpl_7_LightEnable_FPUPreserve,
6862     IDirect3DDeviceImpl_7_GetLightEnable_FPUPreserve,
6863     IDirect3DDeviceImpl_7_SetClipPlane_FPUPreserve,
6864     IDirect3DDeviceImpl_7_GetClipPlane_FPUPreserve,
6865     IDirect3DDeviceImpl_7_GetInfo
6866 };
6867
6868 const IDirect3DDevice3Vtbl IDirect3DDevice3_Vtbl =
6869 {
6870     /*** IUnknown Methods ***/
6871     Thunk_IDirect3DDeviceImpl_3_QueryInterface,
6872     Thunk_IDirect3DDeviceImpl_3_AddRef,
6873     Thunk_IDirect3DDeviceImpl_3_Release,
6874     /*** IDirect3DDevice3 ***/
6875     IDirect3DDeviceImpl_3_GetCaps,
6876     IDirect3DDeviceImpl_3_GetStats,
6877     IDirect3DDeviceImpl_3_AddViewport,
6878     IDirect3DDeviceImpl_3_DeleteViewport,
6879     IDirect3DDeviceImpl_3_NextViewport,
6880     Thunk_IDirect3DDeviceImpl_3_EnumTextureFormats,
6881     Thunk_IDirect3DDeviceImpl_3_BeginScene,
6882     Thunk_IDirect3DDeviceImpl_3_EndScene,
6883     Thunk_IDirect3DDeviceImpl_3_GetDirect3D,
6884     IDirect3DDeviceImpl_3_SetCurrentViewport,
6885     IDirect3DDeviceImpl_3_GetCurrentViewport,
6886     Thunk_IDirect3DDeviceImpl_3_SetRenderTarget,
6887     Thunk_IDirect3DDeviceImpl_3_GetRenderTarget,
6888     IDirect3DDeviceImpl_3_Begin,
6889     IDirect3DDeviceImpl_3_BeginIndexed,
6890     IDirect3DDeviceImpl_3_Vertex,
6891     IDirect3DDeviceImpl_3_Index,
6892     IDirect3DDeviceImpl_3_End,
6893     IDirect3DDeviceImpl_3_GetRenderState,
6894     IDirect3DDeviceImpl_3_SetRenderState,
6895     IDirect3DDeviceImpl_3_GetLightState,
6896     IDirect3DDeviceImpl_3_SetLightState,
6897     Thunk_IDirect3DDeviceImpl_3_SetTransform,
6898     Thunk_IDirect3DDeviceImpl_3_GetTransform,
6899     Thunk_IDirect3DDeviceImpl_3_MultiplyTransform,
6900     Thunk_IDirect3DDeviceImpl_3_DrawPrimitive,
6901     Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
6902     Thunk_IDirect3DDeviceImpl_3_SetClipStatus,
6903     Thunk_IDirect3DDeviceImpl_3_GetClipStatus,
6904     Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
6905     Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
6906     Thunk_IDirect3DDeviceImpl_3_DrawPrimitiveVB,
6907     Thunk_IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
6908     Thunk_IDirect3DDeviceImpl_3_ComputeSphereVisibility,
6909     Thunk_IDirect3DDeviceImpl_3_GetTexture,
6910     IDirect3DDeviceImpl_3_SetTexture,
6911     Thunk_IDirect3DDeviceImpl_3_GetTextureStageState,
6912     Thunk_IDirect3DDeviceImpl_3_SetTextureStageState,
6913     Thunk_IDirect3DDeviceImpl_3_ValidateDevice
6914 };
6915
6916 const IDirect3DDevice2Vtbl IDirect3DDevice2_Vtbl =
6917 {
6918     /*** IUnknown Methods ***/
6919     Thunk_IDirect3DDeviceImpl_2_QueryInterface,
6920     Thunk_IDirect3DDeviceImpl_2_AddRef,
6921     Thunk_IDirect3DDeviceImpl_2_Release,
6922     /*** IDirect3DDevice2 ***/
6923     Thunk_IDirect3DDeviceImpl_2_GetCaps,
6924     IDirect3DDeviceImpl_2_SwapTextureHandles,
6925     Thunk_IDirect3DDeviceImpl_2_GetStats,
6926     Thunk_IDirect3DDeviceImpl_2_AddViewport,
6927     Thunk_IDirect3DDeviceImpl_2_DeleteViewport,
6928     Thunk_IDirect3DDeviceImpl_2_NextViewport,
6929     IDirect3DDeviceImpl_2_EnumTextureFormats,
6930     Thunk_IDirect3DDeviceImpl_2_BeginScene,
6931     Thunk_IDirect3DDeviceImpl_2_EndScene,
6932     Thunk_IDirect3DDeviceImpl_2_GetDirect3D,
6933     Thunk_IDirect3DDeviceImpl_2_SetCurrentViewport,
6934     Thunk_IDirect3DDeviceImpl_2_GetCurrentViewport,
6935     Thunk_IDirect3DDeviceImpl_2_SetRenderTarget,
6936     Thunk_IDirect3DDeviceImpl_2_GetRenderTarget,
6937     Thunk_IDirect3DDeviceImpl_2_Begin,
6938     Thunk_IDirect3DDeviceImpl_2_BeginIndexed,
6939     Thunk_IDirect3DDeviceImpl_2_Vertex,
6940     Thunk_IDirect3DDeviceImpl_2_Index,
6941     Thunk_IDirect3DDeviceImpl_2_End,
6942     Thunk_IDirect3DDeviceImpl_2_GetRenderState,
6943     Thunk_IDirect3DDeviceImpl_2_SetRenderState,
6944     Thunk_IDirect3DDeviceImpl_2_GetLightState,
6945     Thunk_IDirect3DDeviceImpl_2_SetLightState,
6946     Thunk_IDirect3DDeviceImpl_2_SetTransform,
6947     Thunk_IDirect3DDeviceImpl_2_GetTransform,
6948     Thunk_IDirect3DDeviceImpl_2_MultiplyTransform,
6949     Thunk_IDirect3DDeviceImpl_2_DrawPrimitive,
6950     Thunk_IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
6951     Thunk_IDirect3DDeviceImpl_2_SetClipStatus,
6952     Thunk_IDirect3DDeviceImpl_2_GetClipStatus
6953 };
6954
6955 const IDirect3DDeviceVtbl IDirect3DDevice1_Vtbl =
6956 {
6957     /*** IUnknown Methods ***/
6958     Thunk_IDirect3DDeviceImpl_1_QueryInterface,
6959     Thunk_IDirect3DDeviceImpl_1_AddRef,
6960     Thunk_IDirect3DDeviceImpl_1_Release,
6961     /*** IDirect3DDevice1 ***/
6962     IDirect3DDeviceImpl_1_Initialize,
6963     Thunk_IDirect3DDeviceImpl_1_GetCaps,
6964     Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles,
6965     IDirect3DDeviceImpl_1_CreateExecuteBuffer,
6966     Thunk_IDirect3DDeviceImpl_1_GetStats,
6967     IDirect3DDeviceImpl_1_Execute,
6968     Thunk_IDirect3DDeviceImpl_1_AddViewport,
6969     Thunk_IDirect3DDeviceImpl_1_DeleteViewport,
6970     Thunk_IDirect3DDeviceImpl_1_NextViewport,
6971     IDirect3DDeviceImpl_1_Pick,
6972     IDirect3DDeviceImpl_1_GetPickRecords,
6973     Thunk_IDirect3DDeviceImpl_1_EnumTextureFormats,
6974     IDirect3DDeviceImpl_1_CreateMatrix,
6975     IDirect3DDeviceImpl_1_SetMatrix,
6976     IDirect3DDeviceImpl_1_GetMatrix,
6977     IDirect3DDeviceImpl_1_DeleteMatrix,
6978     Thunk_IDirect3DDeviceImpl_1_BeginScene,
6979     Thunk_IDirect3DDeviceImpl_1_EndScene,
6980     Thunk_IDirect3DDeviceImpl_1_GetDirect3D
6981 };
6982
6983 /*****************************************************************************
6984  * IDirect3DDeviceImpl_CreateHandle
6985  *
6986  * Not called from the VTable
6987  *
6988  * Some older interface versions operate with handles, which are basically
6989  * DWORDs which identify an interface, for example
6990  * IDirect3DDevice::SetRenderState with DIRECT3DRENDERSTATE_TEXTUREHANDLE
6991  *
6992  * Those handle could be just casts to the interface pointers or vice versa,
6993  * but that is not 64 bit safe and would mean blindly derefering a DWORD
6994  * passed by the app. Instead there is a dynamic array in the device which
6995  * keeps a DWORD to pointer information and a type for the handle.
6996  *
6997  * Basically this array only grows, when a handle is freed its pointer is
6998  * just set to NULL. There will be much more reads from the array than
6999  * insertion operations, so a dynamic array is fine.
7000  *
7001  * Params:
7002  *  This: D3DDevice implementation for which this handle should be created
7003  *
7004  * Returns:
7005  *  A free handle on success
7006  *  0 on failure
7007  *
7008  *****************************************************************************/
7009 DWORD
7010 IDirect3DDeviceImpl_CreateHandle(IDirect3DDeviceImpl *This)
7011 {
7012     DWORD i;
7013     struct HandleEntry *oldHandles = This->Handles;
7014
7015     TRACE("(%p)\n", This);
7016
7017     for(i = 0; i < This->numHandles; i++)
7018     {
7019         if(This->Handles[i].ptr == NULL &&
7020            This->Handles[i].type == DDrawHandle_Unknown)
7021         {
7022             TRACE("Reusing freed handle %d\n", i + 1);
7023             return i + 1;
7024         }
7025     }
7026
7027     TRACE("Growing the handle array\n");
7028
7029     This->numHandles++;
7030     This->Handles = HeapAlloc(GetProcessHeap(), 0, sizeof(struct HandleEntry) * This->numHandles);
7031     if(!This->Handles)
7032     {
7033         ERR("Out of memory\n");
7034         This->Handles = oldHandles;
7035         This->numHandles--;
7036         return 0;
7037     }
7038     if(oldHandles)
7039     {
7040         memcpy(This->Handles, oldHandles, (This->numHandles - 1) * sizeof(struct HandleEntry));
7041         HeapFree(GetProcessHeap(), 0, oldHandles);
7042     }
7043
7044     TRACE("Returning %d\n", This->numHandles);
7045     return This->numHandles;
7046 }
7047
7048 /*****************************************************************************
7049  * IDirect3DDeviceImpl_UpdateDepthStencil
7050  *
7051  * Checks the current render target for attached depth stencils and sets the
7052  * WineD3D depth stencil accordingly.
7053  *
7054  * Returns:
7055  *  The depth stencil state to set if creating the device
7056  *
7057  *****************************************************************************/
7058 WINED3DZBUFFERTYPE
7059 IDirect3DDeviceImpl_UpdateDepthStencil(IDirect3DDeviceImpl *This)
7060 {
7061     IDirectDrawSurface7 *depthStencil = NULL;
7062     IDirectDrawSurfaceImpl *dsi;
7063     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
7064
7065     IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)This->target, &depthcaps, &depthStencil);
7066     if(!depthStencil)
7067     {
7068         TRACE("Setting wined3d depth stencil to NULL\n");
7069         IWineD3DDevice_SetDepthStencilSurface(This->wineD3DDevice,
7070                                               NULL);
7071         return WINED3DZB_FALSE;
7072     }
7073
7074     dsi = (IDirectDrawSurfaceImpl *)depthStencil;
7075     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->WineD3DSurface);
7076     IWineD3DDevice_SetDepthStencilSurface(This->wineD3DDevice,
7077                                           dsi->WineD3DSurface);
7078
7079     IDirectDrawSurface7_Release(depthStencil);
7080     return WINED3DZB_TRUE;
7081 }