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