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