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