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