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