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