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