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