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