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