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