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