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