crypt32: Add additional path for Solaris 11 Express.
[wine] / dlls / ddraw / device.c
1 /*
2  * Copyright (c) 1998-2004 Lionel Ulmer
3  * Copyright (c) 2002-2005 Christian Costa
4  * Copyright (c) 2006 Stefan Dösinger
5  * Copyright (c) 2008 Alexander Dorofeyev
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * IDirect3DDevice implementation, version 1, 2, 3 and 7. Rendering is relayed
22  * to WineD3D, some minimal DirectDraw specific management is handled here.
23  * The Direct3DDevice is NOT the parent of the WineD3DDevice, because d3d
24  * is initialized when DirectDraw creates the primary surface.
25  * Some type management is necessary, because some D3D types changed between
26  * D3D7 and D3D9.
27  *
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32
33 #include "ddraw_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
36
37 /* The device ID */
38 const GUID IID_D3DDEVICE_WineD3D = {
39   0xaef72d43,
40   0xb09a,
41   0x4b7b,
42   { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
43 };
44
45 static inline void set_fpu_control_word(WORD fpucw)
46 {
47 #if defined(__i386__) && defined(__GNUC__)
48     __asm__ volatile ("fldcw %0" : : "m" (fpucw));
49 #elif defined(__i386__) && defined(_MSC_VER)
50     __asm fldcw fpucw;
51 #endif
52 }
53
54 static inline WORD d3d_fpu_setup(void)
55 {
56     WORD oldcw;
57
58 #if defined(__i386__) && defined(__GNUC__)
59     __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
60 #elif defined(__i386__) && defined(_MSC_VER)
61     __asm fnstcw oldcw;
62 #else
63     static BOOL warned = FALSE;
64     if(!warned)
65     {
66         FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
67         warned = TRUE;
68     }
69     return 0;
70 #endif
71
72     set_fpu_control_word(0x37f);
73
74     return oldcw;
75 }
76
77 /*****************************************************************************
78  * IUnknown Methods. Common for Version 1, 2, 3 and 7
79  *****************************************************************************/
80
81 /*****************************************************************************
82  * IDirect3DDevice7::QueryInterface
83  *
84  * Used to query other interfaces from a Direct3DDevice interface.
85  * It can return interface pointers to all Direct3DDevice versions as well
86  * as IDirectDraw and IDirect3D. For a link to QueryInterface
87  * rules see ddraw.c, IDirectDraw7::QueryInterface
88  *
89  * Exists in Version 1, 2, 3 and 7
90  *
91  * Params:
92  *  refiid: Interface ID queried for
93  *  obj: Used to return the interface pointer
94  *
95  * Returns:
96  *  D3D_OK or E_NOINTERFACE
97  *
98  *****************************************************************************/
99 static HRESULT WINAPI
100 IDirect3DDeviceImpl_7_QueryInterface(IDirect3DDevice7 *iface,
101                                      REFIID refiid,
102                                      void **obj)
103 {
104     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
105
106     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(refiid), obj);
107
108     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
109     *obj = NULL;
110
111     if(!refiid)
112         return DDERR_INVALIDPARAMS;
113
114     if ( IsEqualGUID( &IID_IUnknown, refiid ) )
115     {
116         *obj = iface;
117     }
118
119     /* Check DirectDraw Interfaces. */
120     else if( IsEqualGUID( &IID_IDirectDraw7, refiid ) )
121     {
122         *obj = &This->ddraw->IDirectDraw7_iface;
123         TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
124     }
125     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
126     {
127         *obj = &This->ddraw->IDirectDraw4_iface;
128         TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
129     }
130     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
131     {
132         *obj = &This->ddraw->IDirectDraw2_iface;
133         TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
134     }
135     else if( IsEqualGUID( &IID_IDirectDraw, refiid ) )
136     {
137         *obj = &This->ddraw->IDirectDraw_iface;
138         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
139     }
140
141     /* Direct3D */
142     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) )
143     {
144         *obj = &This->ddraw->IDirect3D_iface;
145         TRACE("(%p) Returning IDirect3D interface at %p\n", This, *obj);
146     }
147     else if ( IsEqualGUID( &IID_IDirect3D2 , refiid ) )
148     {
149         *obj = &This->ddraw->IDirect3D2_iface;
150         TRACE("(%p) Returning IDirect3D2 interface at %p\n", This, *obj);
151     }
152     else if ( IsEqualGUID( &IID_IDirect3D3 , refiid ) )
153     {
154         *obj = &This->ddraw->IDirect3D3_iface;
155         TRACE("(%p) Returning IDirect3D3 interface at %p\n", This, *obj);
156     }
157     else if ( IsEqualGUID( &IID_IDirect3D7 , refiid ) )
158     {
159         *obj = &This->ddraw->IDirect3D7_iface;
160         TRACE("(%p) Returning IDirect3D7 interface at %p\n", This, *obj);
161     }
162
163     /* Direct3DDevice */
164     else if ( IsEqualGUID( &IID_IDirect3DDevice  , refiid ) )
165     {
166         *obj = &This->IDirect3DDevice_vtbl;
167         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
168     }
169     else if ( IsEqualGUID( &IID_IDirect3DDevice2  , refiid ) ) {
170         *obj = &This->IDirect3DDevice2_vtbl;
171         TRACE("(%p) Returning IDirect3DDevice2 interface at %p\n", This, *obj);
172     }
173     else if ( IsEqualGUID( &IID_IDirect3DDevice3  , refiid ) ) {
174         *obj = &This->IDirect3DDevice3_vtbl;
175         TRACE("(%p) Returning IDirect3DDevice3 interface at %p\n", This, *obj);
176     }
177     else if ( IsEqualGUID( &IID_IDirect3DDevice7  , refiid ) ) {
178         *obj = This;
179         TRACE("(%p) Returning IDirect3DDevice7 interface at %p\n", This, *obj);
180     }
181
182     /* Unknown interface */
183     else
184     {
185         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
186         return E_NOINTERFACE;
187     }
188
189     /* AddRef the returned interface */
190     IUnknown_AddRef( (IUnknown *) *obj);
191     return D3D_OK;
192 }
193
194 static HRESULT WINAPI IDirect3DDeviceImpl_3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid,
195         void **obj)
196 {
197     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
198
199     return IDirect3DDevice7_QueryInterface((IDirect3DDevice7 *)device_from_device3(iface), riid, obj);
200 }
201
202 static HRESULT WINAPI IDirect3DDeviceImpl_2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid,
203         void **obj)
204 {
205     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
206
207     return IDirect3DDevice7_QueryInterface((IDirect3DDevice7 *)device_from_device2(iface), riid, obj);
208 }
209
210 static HRESULT WINAPI IDirect3DDeviceImpl_1_QueryInterface(IDirect3DDevice *iface, REFIID riid,
211         void **obp)
212 {
213     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
214
215     return IDirect3DDevice7_QueryInterface((IDirect3DDevice7 *)device_from_device1(iface), riid, obp);
216 }
217
218 /*****************************************************************************
219  * IDirect3DDevice7::AddRef
220  *
221  * Increases the refcount....
222  * The most exciting Method, definitely
223  *
224  * Exists in Version 1, 2, 3 and 7
225  *
226  * Returns:
227  *  The new refcount
228  *
229  *****************************************************************************/
230 static ULONG WINAPI
231 IDirect3DDeviceImpl_7_AddRef(IDirect3DDevice7 *iface)
232 {
233     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
234     ULONG ref = InterlockedIncrement(&This->ref);
235
236     TRACE("%p increasing refcount to %u.\n", This, ref);
237
238     return ref;
239 }
240
241 static ULONG WINAPI IDirect3DDeviceImpl_3_AddRef(IDirect3DDevice3 *iface)
242 {
243     TRACE("iface %p.\n", iface);
244
245     return IDirect3DDevice7_AddRef((IDirect3DDevice7 *)device_from_device3(iface));
246 }
247
248 static ULONG WINAPI IDirect3DDeviceImpl_2_AddRef(IDirect3DDevice2 *iface)
249 {
250     TRACE("iface %p.\n", iface);
251
252     return IDirect3DDevice7_AddRef((IDirect3DDevice7 *)device_from_device2(iface));
253 }
254
255 static ULONG WINAPI IDirect3DDeviceImpl_1_AddRef(IDirect3DDevice *iface)
256 {
257     TRACE("iface %p.\n", iface);
258
259     return IDirect3DDevice7_AddRef((IDirect3DDevice7 *)device_from_device1(iface));
260 }
261
262 /*****************************************************************************
263  * IDirect3DDevice7::Release
264  *
265  * Decreases the refcount of the interface
266  * When the refcount is reduced to 0, the object is destroyed.
267  *
268  * Exists in Version 1, 2, 3 and 7
269  *
270  * Returns:d
271  *  The new refcount
272  *
273  *****************************************************************************/
274 static ULONG WINAPI
275 IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
276 {
277     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
278     ULONG ref = InterlockedDecrement(&This->ref);
279
280     TRACE("%p decreasing refcount to %u.\n", This, ref);
281
282     /* This method doesn't destroy the WineD3DDevice, because it's still in use for
283      * 2D rendering. IDirectDrawSurface7::Release will destroy the WineD3DDevice
284      * when the render target is released
285      */
286     if (ref == 0)
287     {
288         DWORD i;
289
290         EnterCriticalSection(&ddraw_cs);
291
292         /* There is no need to unset any resources here, wined3d will take
293          * care of that on Uninit3D(). */
294
295         /* Free the index buffer. */
296         wined3d_buffer_decref(This->indexbuffer);
297
298         /* Set the device up to render to the front buffer since the back
299          * buffer will vanish soon. */
300         wined3d_device_set_render_target(This->wined3d_device, 0,
301                 This->ddraw->d3d_target->wined3d_surface, TRUE);
302
303         /* Release the WineD3DDevice. This won't destroy it. */
304         if (!wined3d_device_decref(This->wined3d_device))
305             ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
306
307         /* The texture handles should be unset by now, but there might be some bits
308          * missing in our reference counting(needs test). Do a sanity check. */
309         for (i = 0; i < This->handle_table.entry_count; ++i)
310         {
311             struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
312
313             switch (entry->type)
314             {
315                 case DDRAW_HANDLE_FREE:
316                     break;
317
318                 case DDRAW_HANDLE_MATERIAL:
319                 {
320                     IDirect3DMaterialImpl *m = entry->object;
321                     FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
322                     m->Handle = 0;
323                     break;
324                 }
325
326                 case DDRAW_HANDLE_MATRIX:
327                 {
328                     /* No FIXME here because this might happen because of sloppy applications. */
329                     WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
330                     IDirect3DDevice_DeleteMatrix((IDirect3DDevice *)&This->IDirect3DDevice_vtbl, i + 1);
331                     break;
332                 }
333
334                 case DDRAW_HANDLE_STATEBLOCK:
335                 {
336                     /* No FIXME here because this might happen because of sloppy applications. */
337                     WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
338                     IDirect3DDevice7_DeleteStateBlock(iface, i + 1);
339                     break;
340                 }
341
342                 case DDRAW_HANDLE_SURFACE:
343                 {
344                     IDirectDrawSurfaceImpl *surf = entry->object;
345                     FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
346                     surf->Handle = 0;
347                     break;
348                 }
349
350                 default:
351                     FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
352                     break;
353             }
354         }
355
356         ddraw_handle_table_destroy(&This->handle_table);
357
358         TRACE("Releasing target %p %p\n", This->target, This->ddraw->d3d_target);
359         /* Release the render target and the WineD3D render target
360          * (See IDirect3D7::CreateDevice for more comments on this)
361          */
362         IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
363         IDirectDrawSurface7_Release(&This->ddraw->d3d_target->IDirectDrawSurface7_iface);
364         TRACE("Target release done\n");
365
366         This->ddraw->d3ddevice = NULL;
367
368         /* Now free the structure */
369         HeapFree(GetProcessHeap(), 0, This);
370         LeaveCriticalSection(&ddraw_cs);
371     }
372
373     TRACE("Done\n");
374     return ref;
375 }
376
377 static ULONG WINAPI IDirect3DDeviceImpl_3_Release(IDirect3DDevice3 *iface)
378 {
379     TRACE("iface %p.\n", iface);
380
381     return IDirect3DDevice7_Release((IDirect3DDevice7 *)device_from_device3(iface));
382 }
383
384 static ULONG WINAPI IDirect3DDeviceImpl_2_Release(IDirect3DDevice2 *iface)
385 {
386     TRACE("iface %p.\n", iface);
387
388     return IDirect3DDevice7_Release((IDirect3DDevice7 *)device_from_device2(iface));
389 }
390
391 static ULONG WINAPI IDirect3DDeviceImpl_1_Release(IDirect3DDevice *iface)
392 {
393     TRACE("iface %p.\n", iface);
394
395     return IDirect3DDevice7_Release((IDirect3DDevice7 *)device_from_device1(iface));
396 }
397
398 /*****************************************************************************
399  * IDirect3DDevice Methods
400  *****************************************************************************/
401
402 /*****************************************************************************
403  * IDirect3DDevice::Initialize
404  *
405  * Initializes a Direct3DDevice. This implementation is a no-op, as all
406  * initialization is done at create time.
407  *
408  * Exists in Version 1
409  *
410  * Parameters:
411  *  No idea what they mean, as the MSDN page is gone
412  *
413  * Returns: DD_OK
414  *
415  *****************************************************************************/
416 static HRESULT WINAPI
417 IDirect3DDeviceImpl_1_Initialize(IDirect3DDevice *iface,
418                                  IDirect3D *Direct3D, GUID *guid,
419                                  D3DDEVICEDESC *Desc)
420 {
421     /* It shouldn't be crucial, but print a FIXME, I'm interested if
422      * any game calls it and when. */
423     FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
424             iface, Direct3D, debugstr_guid(guid), Desc);
425
426     return D3D_OK;
427 }
428
429 /*****************************************************************************
430  * IDirect3DDevice7::GetCaps
431  *
432  * Retrieves the device's capabilities
433  *
434  * This implementation is used for Version 7 only, the older versions have
435  * their own implementation.
436  *
437  * Parameters:
438  *  Desc: Pointer to a D3DDEVICEDESC7 structure to fill
439  *
440  * Returns:
441  *  D3D_OK on success
442  *  D3DERR_* if a problem occurs. See WineD3D
443  *
444  *****************************************************************************/
445 static HRESULT
446 IDirect3DDeviceImpl_7_GetCaps(IDirect3DDevice7 *iface,
447                               D3DDEVICEDESC7 *Desc)
448 {
449     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
450     D3DDEVICEDESC OldDesc;
451
452     TRACE("iface %p, device_desc %p.\n", iface, Desc);
453
454     /* Call the same function used by IDirect3D, this saves code */
455     return IDirect3DImpl_GetCaps(This->ddraw->wineD3D, &OldDesc, Desc);
456 }
457
458 static HRESULT WINAPI
459 IDirect3DDeviceImpl_7_GetCaps_FPUSetup(IDirect3DDevice7 *iface,
460                               D3DDEVICEDESC7 *Desc)
461 {
462     return IDirect3DDeviceImpl_7_GetCaps(iface, Desc);
463 }
464
465 static HRESULT WINAPI
466 IDirect3DDeviceImpl_7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface,
467                               D3DDEVICEDESC7 *Desc)
468 {
469     HRESULT hr;
470     WORD old_fpucw;
471
472     old_fpucw = d3d_fpu_setup();
473     hr = IDirect3DDeviceImpl_7_GetCaps(iface, Desc);
474     set_fpu_control_word(old_fpucw);
475
476     return hr;
477 }
478 /*****************************************************************************
479  * IDirect3DDevice3::GetCaps
480  *
481  * Retrieves the capabilities of the hardware device and the emulation
482  * device. For Wine, hardware and emulation are the same (it's all HW).
483  *
484  * This implementation is used for Version 1, 2, and 3. Version 7 has its own
485  *
486  * Parameters:
487  *  HWDesc: Structure to fill with the HW caps
488  *  HelDesc: Structure to fill with the hardware emulation caps
489  *
490  * Returns:
491  *  D3D_OK on success
492  *  D3DERR_* if a problem occurs. See WineD3D
493  *
494  *****************************************************************************/
495 static HRESULT WINAPI
496 IDirect3DDeviceImpl_3_GetCaps(IDirect3DDevice3 *iface,
497                               D3DDEVICEDESC *HWDesc,
498                               D3DDEVICEDESC *HelDesc)
499 {
500     IDirect3DDeviceImpl *This = device_from_device3(iface);
501     D3DDEVICEDESC7 newDesc;
502     HRESULT hr;
503
504     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
505
506     hr = IDirect3DImpl_GetCaps(This->ddraw->wineD3D, HWDesc, &newDesc);
507     if(hr != D3D_OK) return hr;
508
509     *HelDesc = *HWDesc;
510     return D3D_OK;
511 }
512
513 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetCaps(IDirect3DDevice2 *iface,
514         D3DDEVICEDESC *D3DHWDevDesc, D3DDEVICEDESC *D3DHELDevDesc)
515 {
516     IDirect3DDeviceImpl *This = device_from_device2(iface);
517     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, D3DHWDevDesc, D3DHELDevDesc);
518     return IDirect3DDevice3_GetCaps((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, D3DHWDevDesc, D3DHELDevDesc);
519 }
520
521 static HRESULT WINAPI IDirect3DDeviceImpl_1_GetCaps(IDirect3DDevice *iface,
522         D3DDEVICEDESC *D3DHWDevDesc, D3DDEVICEDESC *D3DHELDevDesc)
523 {
524     IDirect3DDeviceImpl *This = device_from_device1(iface);
525     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, D3DHWDevDesc, D3DHELDevDesc);
526     return IDirect3DDevice3_GetCaps((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, D3DHWDevDesc, D3DHELDevDesc);
527 }
528
529 /*****************************************************************************
530  * IDirect3DDevice2::SwapTextureHandles
531  *
532  * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
533  *
534  * Parameters:
535  *  Tex1, Tex2: The 2 Textures to swap
536  *
537  * Returns:
538  *  D3D_OK
539  *
540  *****************************************************************************/
541 static HRESULT WINAPI
542 IDirect3DDeviceImpl_2_SwapTextureHandles(IDirect3DDevice2 *iface,
543                                          IDirect3DTexture2 *Tex1,
544                                          IDirect3DTexture2 *Tex2)
545 {
546     IDirect3DDeviceImpl *This = device_from_device2(iface);
547     IDirectDrawSurfaceImpl *surf1 = surface_from_texture2(Tex1);
548     IDirectDrawSurfaceImpl *surf2 = surface_from_texture2(Tex2);
549     DWORD h1, h2;
550
551     TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, Tex1, Tex2);
552
553     EnterCriticalSection(&ddraw_cs);
554
555     h1 = surf1->Handle - 1;
556     h2 = surf2->Handle - 1;
557     This->handle_table.entries[h1].object = surf2;
558     This->handle_table.entries[h2].object = surf1;
559     surf2->Handle = h1 + 1;
560     surf1->Handle = h2 + 1;
561
562     LeaveCriticalSection(&ddraw_cs);
563
564     return D3D_OK;
565 }
566
567 static HRESULT WINAPI IDirect3DDeviceImpl_1_SwapTextureHandles(IDirect3DDevice *iface,
568         IDirect3DTexture *D3DTex1, IDirect3DTexture *D3DTex2)
569 {
570     IDirect3DDeviceImpl *This = device_from_device1(iface);
571     IDirectDrawSurfaceImpl *surf1 = surface_from_texture1(D3DTex1);
572     IDirectDrawSurfaceImpl *surf2 = surface_from_texture1(D3DTex2);
573     IDirect3DTexture2 *t1 = surf1 ? (IDirect3DTexture2 *)&surf1->IDirect3DTexture2_vtbl : NULL;
574     IDirect3DTexture2 *t2 = surf2 ? (IDirect3DTexture2 *)&surf2->IDirect3DTexture2_vtbl : NULL;
575
576     TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, D3DTex1, D3DTex2);
577
578     return IDirect3DDevice2_SwapTextureHandles((IDirect3DDevice2 *)&This->IDirect3DDevice2_vtbl, t1, t2);
579 }
580
581 /*****************************************************************************
582  * IDirect3DDevice3::GetStats
583  *
584  * This method seems to retrieve some stats from the device.
585  * The MSDN documentation doesn't exist any more, but the D3DSTATS
586  * structure suggests that the amount of drawn primitives and processed
587  * vertices is returned.
588  *
589  * Exists in Version 1, 2 and 3
590  *
591  * Parameters:
592  *  Stats: Pointer to a D3DSTATS structure to be filled
593  *
594  * Returns:
595  *  D3D_OK on success
596  *  DDERR_INVALIDPARAMS if Stats == NULL
597  *
598  *****************************************************************************/
599 static HRESULT WINAPI
600 IDirect3DDeviceImpl_3_GetStats(IDirect3DDevice3 *iface,
601                                D3DSTATS *Stats)
602 {
603     FIXME("iface %p, stats %p stub!\n", iface, Stats);
604
605     if(!Stats)
606         return DDERR_INVALIDPARAMS;
607
608     /* Fill the Stats with 0 */
609     Stats->dwTrianglesDrawn = 0;
610     Stats->dwLinesDrawn = 0;
611     Stats->dwPointsDrawn = 0;
612     Stats->dwSpansDrawn = 0;
613     Stats->dwVerticesProcessed = 0;
614
615     return D3D_OK;
616 }
617
618 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *Stats)
619 {
620     IDirect3DDeviceImpl *This = device_from_device2(iface);
621
622     TRACE("iface %p, stats %p.\n", iface, Stats);
623
624     return IDirect3DDevice3_GetStats((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, Stats);
625 }
626
627 static HRESULT WINAPI IDirect3DDeviceImpl_1_GetStats(IDirect3DDevice *iface, D3DSTATS *Stats)
628 {
629     IDirect3DDeviceImpl *This = device_from_device1(iface);
630
631     TRACE("iface %p, stats %p.\n", iface, Stats);
632
633     return IDirect3DDevice3_GetStats((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, Stats);
634 }
635
636 /*****************************************************************************
637  * IDirect3DDevice::CreateExecuteBuffer
638  *
639  * Creates an IDirect3DExecuteBuffer, used for rendering with a
640  * Direct3DDevice.
641  *
642  * Version 1 only.
643  *
644  * Params:
645  *  Desc: Buffer description
646  *  ExecuteBuffer: Address to return the Interface pointer at
647  *  UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
648  *            support
649  *
650  * Returns:
651  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
652  *  DDERR_OUTOFMEMORY if we ran out of memory
653  *  D3D_OK on success
654  *
655  *****************************************************************************/
656 static HRESULT WINAPI
657 IDirect3DDeviceImpl_1_CreateExecuteBuffer(IDirect3DDevice *iface,
658                                           D3DEXECUTEBUFFERDESC *Desc,
659                                           IDirect3DExecuteBuffer **ExecuteBuffer,
660                                           IUnknown *UnkOuter)
661 {
662     IDirect3DDeviceImpl *This = device_from_device1(iface);
663     IDirect3DExecuteBufferImpl* object;
664     HRESULT hr;
665
666     TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
667             iface, Desc, ExecuteBuffer, UnkOuter);
668
669     if(UnkOuter)
670         return CLASS_E_NOAGGREGATION;
671
672     /* Allocate the new Execute Buffer */
673     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DExecuteBufferImpl));
674     if(!object)
675     {
676         ERR("Out of memory when allocating a IDirect3DExecuteBufferImpl structure\n");
677         return DDERR_OUTOFMEMORY;
678     }
679
680     hr = d3d_execute_buffer_init(object, This, Desc);
681     if (FAILED(hr))
682     {
683         WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
684         HeapFree(GetProcessHeap(), 0, object);
685         return hr;
686     }
687
688     *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
689
690     TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
691
692     return D3D_OK;
693 }
694
695 /*****************************************************************************
696  * IDirect3DDevice::Execute
697  *
698  * Executes all the stuff in an execute buffer.
699  *
700  * Params:
701  *  ExecuteBuffer: The buffer to execute
702  *  Viewport: The viewport used for rendering
703  *  Flags: Some flags
704  *
705  * Returns:
706  *  DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
707  *  D3D_OK on success
708  *
709  *****************************************************************************/
710 static HRESULT WINAPI IDirect3DDeviceImpl_1_Execute(IDirect3DDevice *iface,
711         IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *Viewport, DWORD Flags)
712 {
713     IDirect3DDeviceImpl *This = device_from_device1(iface);
714     IDirect3DExecuteBufferImpl *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
715     IDirect3DViewportImpl *Direct3DViewportImpl = (IDirect3DViewportImpl *)Viewport;
716     HRESULT hr;
717
718     TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, Viewport, Flags);
719
720     if(!buffer)
721         return DDERR_INVALIDPARAMS;
722
723     /* Execute... */
724     EnterCriticalSection(&ddraw_cs);
725     hr = d3d_execute_buffer_execute(buffer, This, Direct3DViewportImpl);
726     LeaveCriticalSection(&ddraw_cs);
727
728     return hr;
729 }
730
731 /*****************************************************************************
732  * IDirect3DDevice3::AddViewport
733  *
734  * Add a Direct3DViewport to the device's viewport list. These viewports
735  * are wrapped to IDirect3DDevice7 viewports in viewport.c
736  *
737  * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
738  * are the same interfaces.
739  *
740  * Params:
741  *  Viewport: The viewport to add
742  *
743  * Returns:
744  *  DDERR_INVALIDPARAMS if Viewport == NULL
745  *  D3D_OK on success
746  *
747  *****************************************************************************/
748 static HRESULT WINAPI
749 IDirect3DDeviceImpl_3_AddViewport(IDirect3DDevice3 *iface,
750                                   IDirect3DViewport3 *Viewport)
751 {
752     IDirect3DDeviceImpl *This = device_from_device3(iface);
753     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Viewport;
754
755     TRACE("iface %p, viewport %p.\n", iface, Viewport);
756
757     /* Sanity check */
758     if(!vp)
759         return DDERR_INVALIDPARAMS;
760
761     EnterCriticalSection(&ddraw_cs);
762     list_add_head(&This->viewport_list, &vp->entry);
763     vp->active_device = This; /* Viewport must be usable for Clear() after AddViewport,
764                                     so set active_device here. */
765     LeaveCriticalSection(&ddraw_cs);
766
767     return D3D_OK;
768 }
769
770 static HRESULT WINAPI IDirect3DDeviceImpl_2_AddViewport(IDirect3DDevice2 *iface,
771         IDirect3DViewport2 *Direct3DViewport2)
772 {
773     IDirect3DDeviceImpl *This = device_from_device2(iface);
774     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Direct3DViewport2;
775
776     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport2);
777
778     return IDirect3DDevice3_AddViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, (IDirect3DViewport3 *)vp);
779 }
780
781 static HRESULT WINAPI IDirect3DDeviceImpl_1_AddViewport(IDirect3DDevice *iface,
782         IDirect3DViewport *Direct3DViewport)
783 {
784     IDirect3DDeviceImpl *This = device_from_device1(iface);
785     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Direct3DViewport;
786
787     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport);
788
789     return IDirect3DDevice3_AddViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, (IDirect3DViewport3 *)vp);
790 }
791
792 /*****************************************************************************
793  * IDirect3DDevice3::DeleteViewport
794  *
795  * Deletes a Direct3DViewport from the device's viewport list.
796  *
797  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
798  * are equal.
799  *
800  * Params:
801  *  Viewport: The viewport to delete
802  *
803  * Returns:
804  *  D3D_OK on success
805  *  DDERR_INVALIDPARAMS if the viewport wasn't found in the list
806  *
807  *****************************************************************************/
808 static HRESULT WINAPI IDirect3DDeviceImpl_3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
809 {
810     IDirect3DDeviceImpl *device = device_from_device3(iface);
811     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)viewport;
812
813     TRACE("iface %p, viewport %p.\n", iface, viewport);
814
815     EnterCriticalSection(&ddraw_cs);
816
817     if (vp->active_device != device)
818     {
819         WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
820         LeaveCriticalSection(&ddraw_cs);
821         return DDERR_INVALIDPARAMS;
822     }
823
824     vp->active_device = NULL;
825     list_remove(&vp->entry);
826
827     LeaveCriticalSection(&ddraw_cs);
828     return D3D_OK;
829 }
830
831 static HRESULT WINAPI IDirect3DDeviceImpl_2_DeleteViewport(IDirect3DDevice2 *iface,
832         IDirect3DViewport2 *Direct3DViewport2)
833 {
834     IDirect3DDeviceImpl *This = device_from_device2(iface);
835     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Direct3DViewport2;
836
837     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport2);
838
839     return IDirect3DDevice3_DeleteViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, (IDirect3DViewport3 *)vp);
840 }
841
842 static HRESULT WINAPI IDirect3DDeviceImpl_1_DeleteViewport(IDirect3DDevice *iface,
843         IDirect3DViewport *Direct3DViewport)
844 {
845     IDirect3DDeviceImpl *This = device_from_device1(iface);
846     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Direct3DViewport;
847
848     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport);
849
850     return IDirect3DDevice3_DeleteViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, (IDirect3DViewport3 *)vp);
851 }
852
853 /*****************************************************************************
854  * IDirect3DDevice3::NextViewport
855  *
856  * Returns a viewport from the viewport list, depending on the
857  * passed viewport and the flags.
858  *
859  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
860  * are equal.
861  *
862  * Params:
863  *  Viewport: Viewport to use for beginning the search
864  *  Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
865  *
866  * Returns:
867  *  D3D_OK on success
868  *  DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
869  *
870  *****************************************************************************/
871 static HRESULT WINAPI
872 IDirect3DDeviceImpl_3_NextViewport(IDirect3DDevice3 *iface,
873                                    IDirect3DViewport3 *Viewport3,
874                                    IDirect3DViewport3 **lplpDirect3DViewport3,
875                                    DWORD Flags)
876 {
877     IDirect3DDeviceImpl *This = device_from_device3(iface);
878     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Viewport3;
879     struct list *entry;
880
881     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
882             iface, Viewport3, lplpDirect3DViewport3, Flags);
883
884     if(!vp)
885     {
886         *lplpDirect3DViewport3 = NULL;
887         return DDERR_INVALIDPARAMS;
888     }
889
890
891     EnterCriticalSection(&ddraw_cs);
892     switch (Flags)
893     {
894         case D3DNEXT_NEXT:
895             entry = list_next(&This->viewport_list, &vp->entry);
896             break;
897
898         case D3DNEXT_HEAD:
899             entry = list_head(&This->viewport_list);
900             break;
901
902         case D3DNEXT_TAIL:
903             entry = list_tail(&This->viewport_list);
904             break;
905
906         default:
907             WARN("Invalid flags %#x.\n", Flags);
908             *lplpDirect3DViewport3 = NULL;
909             LeaveCriticalSection(&ddraw_cs);
910             return DDERR_INVALIDPARAMS;
911     }
912
913     if (entry)
914         *lplpDirect3DViewport3 = (IDirect3DViewport3 *)LIST_ENTRY(entry, IDirect3DViewportImpl, entry);
915     else
916         *lplpDirect3DViewport3 = NULL;
917
918     LeaveCriticalSection(&ddraw_cs);
919     return D3D_OK;
920 }
921
922 static HRESULT WINAPI IDirect3DDeviceImpl_2_NextViewport(IDirect3DDevice2 *iface,
923         IDirect3DViewport2 *Viewport2, IDirect3DViewport2 **lplpDirect3DViewport2, DWORD Flags)
924 {
925     IDirect3DDeviceImpl *This = device_from_device2(iface);
926     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Viewport2;
927     IDirect3DViewport3 *res;
928     HRESULT hr;
929
930     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
931             iface, Viewport2, lplpDirect3DViewport2, Flags);
932
933     hr = IDirect3DDevice3_NextViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
934             (IDirect3DViewport3 *)vp, &res, Flags);
935     *lplpDirect3DViewport2 = (IDirect3DViewport2 *)res;
936     return hr;
937 }
938
939 static HRESULT WINAPI IDirect3DDeviceImpl_1_NextViewport(IDirect3DDevice *iface,
940         IDirect3DViewport *Viewport, IDirect3DViewport **lplpDirect3DViewport, DWORD Flags)
941 {
942     IDirect3DDeviceImpl *This = device_from_device1(iface);
943     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Viewport;
944     IDirect3DViewport3 *res;
945     HRESULT hr;
946
947     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
948             iface, Viewport, lplpDirect3DViewport, Flags);
949
950     hr = IDirect3DDevice3_NextViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
951             (IDirect3DViewport3 *)vp, &res, Flags);
952     *lplpDirect3DViewport = (IDirect3DViewport *)res;
953     return hr;
954 }
955
956 /*****************************************************************************
957  * IDirect3DDevice::Pick
958  *
959  * Executes an execute buffer without performing rendering. Instead, a
960  * list of primitives that intersect with (x1,y1) of the passed rectangle
961  * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
962  * this list.
963  *
964  * Version 1 only
965  *
966  * Params:
967  *  ExecuteBuffer: Buffer to execute
968  *  Viewport: Viewport to use for execution
969  *  Flags: None are defined, according to the SDK
970  *  Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
971  *        x2 and y2 are ignored.
972  *
973  * Returns:
974  *  D3D_OK because it's a stub
975  *
976  *****************************************************************************/
977 static HRESULT WINAPI
978 IDirect3DDeviceImpl_1_Pick(IDirect3DDevice *iface,
979                            IDirect3DExecuteBuffer *ExecuteBuffer,
980                            IDirect3DViewport *Viewport,
981                            DWORD Flags,
982                            D3DRECT *Rect)
983 {
984     FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
985             iface, ExecuteBuffer, Viewport, Flags, wine_dbgstr_rect((RECT *)Rect));
986
987     return D3D_OK;
988 }
989
990 /*****************************************************************************
991  * IDirect3DDevice::GetPickRecords
992  *
993  * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
994  *
995  * Version 1 only
996  *
997  * Params:
998  *  Count: Pointer to a DWORD containing the numbers of pick records to
999  *         retrieve
1000  *  D3DPickRec: Address to store the resulting D3DPICKRECORD array.
1001  *
1002  * Returns:
1003  *  D3D_OK, because it's a stub
1004  *
1005  *****************************************************************************/
1006 static HRESULT WINAPI
1007 IDirect3DDeviceImpl_1_GetPickRecords(IDirect3DDevice *iface,
1008                                      DWORD *Count,
1009                                      D3DPICKRECORD *D3DPickRec)
1010 {
1011     FIXME("iface %p, count %p, records %p stub!\n", iface, Count, D3DPickRec);
1012
1013     return D3D_OK;
1014 }
1015
1016 /*****************************************************************************
1017  * IDirect3DDevice7::EnumTextureformats
1018  *
1019  * Enumerates the supported texture formats. It has a list of all possible
1020  * formats and calls IWineD3D::CheckDeviceFormat for each format to see if
1021  * WineD3D supports it. If so, then it is passed to the app.
1022  *
1023  * This is for Version 7 and 3, older versions have a different
1024  * callback function and their own implementation
1025  *
1026  * Params:
1027  *  Callback: Callback to call for each enumerated format
1028  *  Arg: Argument to pass to the callback
1029  *
1030  * Returns:
1031  *  D3D_OK on success
1032  *  DDERR_INVALIDPARAMS if Callback == NULL
1033  *
1034  *****************************************************************************/
1035 static HRESULT
1036 IDirect3DDeviceImpl_7_EnumTextureFormats(IDirect3DDevice7 *iface,
1037                                          LPD3DENUMPIXELFORMATSCALLBACK Callback,
1038                                          void *Arg)
1039 {
1040     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
1041     HRESULT hr;
1042     WINED3DDISPLAYMODE mode;
1043     unsigned int i;
1044
1045     static const enum wined3d_format_id FormatList[] =
1046     {
1047         /* 32 bit */
1048         WINED3DFMT_B8G8R8A8_UNORM,
1049         WINED3DFMT_B8G8R8X8_UNORM,
1050         /* 24 bit */
1051         WINED3DFMT_B8G8R8_UNORM,
1052         /* 16 Bit */
1053         WINED3DFMT_B5G5R5A1_UNORM,
1054         WINED3DFMT_B4G4R4A4_UNORM,
1055         WINED3DFMT_B5G6R5_UNORM,
1056         WINED3DFMT_B5G5R5X1_UNORM,
1057         /* 8 Bit */
1058         WINED3DFMT_B2G3R3_UNORM,
1059         WINED3DFMT_P8_UINT,
1060         /* FOURCC codes */
1061         WINED3DFMT_DXT1,
1062         WINED3DFMT_DXT3,
1063         WINED3DFMT_DXT5,
1064     };
1065
1066     static const enum wined3d_format_id BumpFormatList[] =
1067     {
1068         WINED3DFMT_R8G8_SNORM,
1069         WINED3DFMT_R5G5_SNORM_L6_UNORM,
1070         WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1071         WINED3DFMT_R16G16_SNORM,
1072         WINED3DFMT_R10G11B11_SNORM,
1073         WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1074     };
1075
1076     TRACE("iface %p, callback %p, context %p.\n", iface, Callback, Arg);
1077
1078     if(!Callback)
1079         return DDERR_INVALIDPARAMS;
1080
1081     EnterCriticalSection(&ddraw_cs);
1082
1083     memset(&mode, 0, sizeof(mode));
1084     hr = wined3d_device_get_display_mode(This->ddraw->wined3d_device, 0, &mode);
1085     if (FAILED(hr))
1086     {
1087         LeaveCriticalSection(&ddraw_cs);
1088         WARN("Cannot get the current adapter format\n");
1089         return hr;
1090     }
1091
1092     for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1093     {
1094         hr = wined3d_check_device_format(This->ddraw->wineD3D, WINED3DADAPTER_DEFAULT, WINED3DDEVTYPE_HAL,
1095                 mode.Format, 0, WINED3DRTYPE_TEXTURE, FormatList[i], SURFACE_OPENGL);
1096         if (hr == D3D_OK)
1097         {
1098             DDPIXELFORMAT pformat;
1099
1100             memset(&pformat, 0, sizeof(pformat));
1101             pformat.dwSize = sizeof(pformat);
1102             PixelFormat_WineD3DtoDD(&pformat, FormatList[i]);
1103
1104             TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1105             hr = Callback(&pformat, Arg);
1106             if(hr != DDENUMRET_OK)
1107             {
1108                 TRACE("Format enumeration cancelled by application\n");
1109                 LeaveCriticalSection(&ddraw_cs);
1110                 return D3D_OK;
1111             }
1112         }
1113     }
1114
1115     for (i = 0; i < sizeof(BumpFormatList) / sizeof(*BumpFormatList); ++i)
1116     {
1117         hr = wined3d_check_device_format(This->ddraw->wineD3D, WINED3DADAPTER_DEFAULT,
1118                 WINED3DDEVTYPE_HAL, mode.Format, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1119                 WINED3DRTYPE_TEXTURE, BumpFormatList[i], SURFACE_OPENGL);
1120         if (hr == D3D_OK)
1121         {
1122             DDPIXELFORMAT pformat;
1123
1124             memset(&pformat, 0, sizeof(pformat));
1125             pformat.dwSize = sizeof(pformat);
1126             PixelFormat_WineD3DtoDD(&pformat, BumpFormatList[i]);
1127
1128             TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1129             hr = Callback(&pformat, Arg);
1130             if(hr != DDENUMRET_OK)
1131             {
1132                 TRACE("Format enumeration cancelled by application\n");
1133                 LeaveCriticalSection(&ddraw_cs);
1134                 return D3D_OK;
1135             }
1136         }
1137     }
1138     TRACE("End of enumeration\n");
1139     LeaveCriticalSection(&ddraw_cs);
1140     return D3D_OK;
1141 }
1142
1143 static HRESULT WINAPI
1144 IDirect3DDeviceImpl_7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1145                                          LPD3DENUMPIXELFORMATSCALLBACK Callback,
1146                                          void *Arg)
1147 {
1148     return IDirect3DDeviceImpl_7_EnumTextureFormats(iface, Callback, Arg);
1149 }
1150
1151 static HRESULT WINAPI
1152 IDirect3DDeviceImpl_7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1153                                          LPD3DENUMPIXELFORMATSCALLBACK Callback,
1154                                          void *Arg)
1155 {
1156     HRESULT hr;
1157     WORD old_fpucw;
1158
1159     old_fpucw = d3d_fpu_setup();
1160     hr = IDirect3DDeviceImpl_7_EnumTextureFormats(iface, Callback, Arg);
1161     set_fpu_control_word(old_fpucw);
1162
1163     return hr;
1164 }
1165
1166 static HRESULT WINAPI IDirect3DDeviceImpl_3_EnumTextureFormats(IDirect3DDevice3 *iface,
1167         LPD3DENUMPIXELFORMATSCALLBACK Callback, void *Arg)
1168 {
1169     IDirect3DDeviceImpl *This = device_from_device3(iface);
1170
1171     TRACE("iface %p, callback %p, context %p.\n", iface, Callback, Arg);
1172
1173     return IDirect3DDevice7_EnumTextureFormats((IDirect3DDevice7 *)This, Callback, Arg);
1174 }
1175
1176 /*****************************************************************************
1177  * IDirect3DDevice2::EnumTextureformats
1178  *
1179  * EnumTextureFormats for Version 1 and 2, see
1180  * IDirect3DDevice7::EnumTexureFormats for a more detailed description.
1181  *
1182  * This version has a different callback and does not enumerate FourCC
1183  * formats
1184  *
1185  *****************************************************************************/
1186 static HRESULT WINAPI
1187 IDirect3DDeviceImpl_2_EnumTextureFormats(IDirect3DDevice2 *iface,
1188                                          LPD3DENUMTEXTUREFORMATSCALLBACK Callback,
1189                                          void *Arg)
1190 {
1191     IDirect3DDeviceImpl *This = device_from_device2(iface);
1192     HRESULT hr;
1193     unsigned int i;
1194     WINED3DDISPLAYMODE mode;
1195
1196     static const enum wined3d_format_id FormatList[] =
1197     {
1198         /* 32 bit */
1199         WINED3DFMT_B8G8R8A8_UNORM,
1200         WINED3DFMT_B8G8R8X8_UNORM,
1201         /* 24 bit */
1202         WINED3DFMT_B8G8R8_UNORM,
1203         /* 16 Bit */
1204         WINED3DFMT_B5G5R5A1_UNORM,
1205         WINED3DFMT_B4G4R4A4_UNORM,
1206         WINED3DFMT_B5G6R5_UNORM,
1207         WINED3DFMT_B5G5R5X1_UNORM,
1208         /* 8 Bit */
1209         WINED3DFMT_B2G3R3_UNORM,
1210         WINED3DFMT_P8_UINT,
1211         /* FOURCC codes - Not in this version*/
1212     };
1213
1214     TRACE("iface %p, callback %p, context %p.\n", iface, Callback, Arg);
1215
1216     if(!Callback)
1217         return DDERR_INVALIDPARAMS;
1218
1219     EnterCriticalSection(&ddraw_cs);
1220
1221     memset(&mode, 0, sizeof(mode));
1222     hr = wined3d_device_get_display_mode(This->ddraw->wined3d_device, 0, &mode);
1223     if (FAILED(hr))
1224     {
1225         LeaveCriticalSection(&ddraw_cs);
1226         WARN("Cannot get the current adapter format\n");
1227         return hr;
1228     }
1229
1230     for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1231     {
1232         hr = wined3d_check_device_format(This->ddraw->wineD3D, 0, WINED3DDEVTYPE_HAL,
1233                 mode.Format, 0, WINED3DRTYPE_TEXTURE, FormatList[i], SURFACE_OPENGL);
1234         if (hr == D3D_OK)
1235         {
1236             DDSURFACEDESC sdesc;
1237
1238             memset(&sdesc, 0, sizeof(sdesc));
1239             sdesc.dwSize = sizeof(sdesc);
1240             sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1241             sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1242             sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1243             PixelFormat_WineD3DtoDD(&sdesc.ddpfPixelFormat, FormatList[i]);
1244
1245             TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1246             hr = Callback(&sdesc, Arg);
1247             if(hr != DDENUMRET_OK)
1248             {
1249                 TRACE("Format enumeration cancelled by application\n");
1250                 LeaveCriticalSection(&ddraw_cs);
1251                 return D3D_OK;
1252             }
1253         }
1254     }
1255     TRACE("End of enumeration\n");
1256     LeaveCriticalSection(&ddraw_cs);
1257     return D3D_OK;
1258 }
1259
1260 static HRESULT WINAPI IDirect3DDeviceImpl_1_EnumTextureFormats(IDirect3DDevice *iface,
1261         LPD3DENUMTEXTUREFORMATSCALLBACK Callback, void *Arg)
1262 {
1263     IDirect3DDeviceImpl *This = device_from_device1(iface);
1264
1265     TRACE("iface %p, callback %p, context %p.\n", iface, Callback, Arg);
1266
1267     return IDirect3DDevice2_EnumTextureFormats((IDirect3DDevice2 *)&This->IDirect3DDevice2_vtbl, Callback, Arg);
1268 }
1269
1270 /*****************************************************************************
1271  * IDirect3DDevice::CreateMatrix
1272  *
1273  * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1274  * allocated for the handle.
1275  *
1276  * Version 1 only
1277  *
1278  * Params
1279  *  D3DMatHandle: Address to return the handle at
1280  *
1281  * Returns:
1282  *  D3D_OK on success
1283  *  DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1284  *
1285  *****************************************************************************/
1286 static HRESULT WINAPI
1287 IDirect3DDeviceImpl_1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1288 {
1289     IDirect3DDeviceImpl *This = device_from_device1(iface);
1290     D3DMATRIX *Matrix;
1291     DWORD h;
1292
1293     TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1294
1295     if(!D3DMatHandle)
1296         return DDERR_INVALIDPARAMS;
1297
1298     Matrix = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DMATRIX));
1299     if(!Matrix)
1300     {
1301         ERR("Out of memory when allocating a D3DMATRIX\n");
1302         return DDERR_OUTOFMEMORY;
1303     }
1304
1305     EnterCriticalSection(&ddraw_cs);
1306
1307     h = ddraw_allocate_handle(&This->handle_table, Matrix, DDRAW_HANDLE_MATRIX);
1308     if (h == DDRAW_INVALID_HANDLE)
1309     {
1310         ERR("Failed to allocate a matrix handle.\n");
1311         HeapFree(GetProcessHeap(), 0, Matrix);
1312         LeaveCriticalSection(&ddraw_cs);
1313         return DDERR_OUTOFMEMORY;
1314     }
1315
1316     *D3DMatHandle = h + 1;
1317
1318     TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1319
1320     LeaveCriticalSection(&ddraw_cs);
1321     return D3D_OK;
1322 }
1323
1324 /*****************************************************************************
1325  * IDirect3DDevice::SetMatrix
1326  *
1327  * Sets a matrix for a matrix handle. The matrix is copied into the memory
1328  * allocated for the handle
1329  *
1330  * Version 1 only
1331  *
1332  * Params:
1333  *  D3DMatHandle: Handle to set the matrix to
1334  *  D3DMatrix: Matrix to set
1335  *
1336  * Returns:
1337  *  D3D_OK on success
1338  *  DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1339  *   to set is NULL
1340  *
1341  *****************************************************************************/
1342 static HRESULT WINAPI
1343 IDirect3DDeviceImpl_1_SetMatrix(IDirect3DDevice *iface,
1344                                 D3DMATRIXHANDLE D3DMatHandle,
1345                                 D3DMATRIX *D3DMatrix)
1346 {
1347     IDirect3DDeviceImpl *This = device_from_device1(iface);
1348     D3DMATRIX *m;
1349
1350     TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1351
1352     if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1353
1354     EnterCriticalSection(&ddraw_cs);
1355
1356     m = ddraw_get_object(&This->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1357     if (!m)
1358     {
1359         WARN("Invalid matrix handle.\n");
1360         LeaveCriticalSection(&ddraw_cs);
1361         return DDERR_INVALIDPARAMS;
1362     }
1363
1364     if (TRACE_ON(ddraw))
1365         dump_D3DMATRIX(D3DMatrix);
1366
1367     *m = *D3DMatrix;
1368
1369     if (D3DMatHandle == This->world)
1370         wined3d_device_set_transform(This->wined3d_device, WINED3DTS_WORLDMATRIX(0), (WINED3DMATRIX *)D3DMatrix);
1371
1372     if (D3DMatHandle == This->view)
1373         wined3d_device_set_transform(This->wined3d_device, WINED3DTS_VIEW, (WINED3DMATRIX *)D3DMatrix);
1374
1375     if (D3DMatHandle == This->proj)
1376         wined3d_device_set_transform(This->wined3d_device, WINED3DTS_PROJECTION, (WINED3DMATRIX *)D3DMatrix);
1377
1378     LeaveCriticalSection(&ddraw_cs);
1379     return D3D_OK;
1380 }
1381
1382 /*****************************************************************************
1383  * IDirect3DDevice::GetMatrix
1384  *
1385  * Returns the content of a D3DMATRIX handle
1386  *
1387  * Version 1 only
1388  *
1389  * Params:
1390  *  D3DMatHandle: Matrix handle to read the content from
1391  *  D3DMatrix: Address to store the content at
1392  *
1393  * Returns:
1394  *  D3D_OK on success
1395  *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1396  *
1397  *****************************************************************************/
1398 static HRESULT WINAPI
1399 IDirect3DDeviceImpl_1_GetMatrix(IDirect3DDevice *iface,
1400                                 D3DMATRIXHANDLE D3DMatHandle,
1401                                 D3DMATRIX *D3DMatrix)
1402 {
1403     IDirect3DDeviceImpl *This = device_from_device1(iface);
1404     D3DMATRIX *m;
1405
1406     TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1407
1408     if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1409
1410     EnterCriticalSection(&ddraw_cs);
1411
1412     m = ddraw_get_object(&This->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1413     if (!m)
1414     {
1415         WARN("Invalid matrix handle.\n");
1416         LeaveCriticalSection(&ddraw_cs);
1417         return DDERR_INVALIDPARAMS;
1418     }
1419
1420     *D3DMatrix = *m;
1421
1422     LeaveCriticalSection(&ddraw_cs);
1423     return D3D_OK;
1424 }
1425
1426 /*****************************************************************************
1427  * IDirect3DDevice::DeleteMatrix
1428  *
1429  * Destroys a Matrix handle. Frees the memory and unsets the handle data
1430  *
1431  * Version 1 only
1432  *
1433  * Params:
1434  *  D3DMatHandle: Handle to destroy
1435  *
1436  * Returns:
1437  *  D3D_OK on success
1438  *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1439  *
1440  *****************************************************************************/
1441 static HRESULT WINAPI
1442 IDirect3DDeviceImpl_1_DeleteMatrix(IDirect3DDevice *iface,
1443                                    D3DMATRIXHANDLE D3DMatHandle)
1444 {
1445     IDirect3DDeviceImpl *This = device_from_device1(iface);
1446     D3DMATRIX *m;
1447
1448     TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1449
1450     EnterCriticalSection(&ddraw_cs);
1451
1452     m = ddraw_free_handle(&This->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1453     if (!m)
1454     {
1455         WARN("Invalid matrix handle.\n");
1456         LeaveCriticalSection(&ddraw_cs);
1457         return DDERR_INVALIDPARAMS;
1458     }
1459
1460     LeaveCriticalSection(&ddraw_cs);
1461
1462     HeapFree(GetProcessHeap(), 0, m);
1463
1464     return D3D_OK;
1465 }
1466
1467 /*****************************************************************************
1468  * IDirect3DDevice7::BeginScene
1469  *
1470  * This method must be called before any rendering is performed.
1471  * IDirect3DDevice::EndScene has to be called after the scene is complete
1472  *
1473  * Version 1, 2, 3 and 7
1474  *
1475  * Returns:
1476  *  D3D_OK on success, for details see IWineD3DDevice::BeginScene
1477  *  D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1478  *  started scene).
1479  *
1480  *****************************************************************************/
1481 static HRESULT
1482 IDirect3DDeviceImpl_7_BeginScene(IDirect3DDevice7 *iface)
1483 {
1484     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
1485     HRESULT hr;
1486
1487     TRACE("iface %p.\n", iface);
1488
1489     EnterCriticalSection(&ddraw_cs);
1490     hr = wined3d_device_begin_scene(This->wined3d_device);
1491     LeaveCriticalSection(&ddraw_cs);
1492     if(hr == WINED3D_OK) return D3D_OK;
1493     else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1494 }
1495
1496 static HRESULT WINAPI
1497 IDirect3DDeviceImpl_7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1498 {
1499     return IDirect3DDeviceImpl_7_BeginScene(iface);
1500 }
1501
1502 static HRESULT WINAPI
1503 IDirect3DDeviceImpl_7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1504 {
1505     HRESULT hr;
1506     WORD old_fpucw;
1507
1508     old_fpucw = d3d_fpu_setup();
1509     hr = IDirect3DDeviceImpl_7_BeginScene(iface);
1510     set_fpu_control_word(old_fpucw);
1511
1512     return hr;
1513 }
1514
1515 static HRESULT WINAPI IDirect3DDeviceImpl_3_BeginScene(IDirect3DDevice3 *iface)
1516 {
1517     TRACE("iface %p.\n", iface);
1518
1519     return IDirect3DDevice7_BeginScene((IDirect3DDevice7 *)device_from_device3(iface));
1520 }
1521
1522 static HRESULT WINAPI IDirect3DDeviceImpl_2_BeginScene(IDirect3DDevice2 *iface)
1523 {
1524     TRACE("iface %p.\n", iface);
1525
1526     return IDirect3DDevice7_BeginScene((IDirect3DDevice7 *)device_from_device2(iface));
1527 }
1528
1529 static HRESULT WINAPI IDirect3DDeviceImpl_1_BeginScene(IDirect3DDevice *iface)
1530 {
1531     TRACE("iface %p.\n", iface);
1532
1533     return IDirect3DDevice7_BeginScene((IDirect3DDevice7 *)device_from_device1(iface));
1534 }
1535
1536 /*****************************************************************************
1537  * IDirect3DDevice7::EndScene
1538  *
1539  * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1540  * This method must be called after rendering is finished.
1541  *
1542  * Version 1, 2, 3 and 7
1543  *
1544  * Returns:
1545  *  D3D_OK on success, for details see IWineD3DDevice::EndScene
1546  *  D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1547  *  that only if the scene was already ended.
1548  *
1549  *****************************************************************************/
1550 static HRESULT
1551 IDirect3DDeviceImpl_7_EndScene(IDirect3DDevice7 *iface)
1552 {
1553     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
1554     HRESULT hr;
1555
1556     TRACE("iface %p.\n", iface);
1557
1558     EnterCriticalSection(&ddraw_cs);
1559     hr = wined3d_device_end_scene(This->wined3d_device);
1560     LeaveCriticalSection(&ddraw_cs);
1561     if(hr == WINED3D_OK) return D3D_OK;
1562     else return D3DERR_SCENE_NOT_IN_SCENE;
1563 }
1564
1565 static HRESULT WINAPI DECLSPEC_HOTPATCH
1566 IDirect3DDeviceImpl_7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1567 {
1568     return IDirect3DDeviceImpl_7_EndScene(iface);
1569 }
1570
1571 static HRESULT WINAPI DECLSPEC_HOTPATCH
1572 IDirect3DDeviceImpl_7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1573 {
1574     HRESULT hr;
1575     WORD old_fpucw;
1576
1577     old_fpucw = d3d_fpu_setup();
1578     hr = IDirect3DDeviceImpl_7_EndScene(iface);
1579     set_fpu_control_word(old_fpucw);
1580
1581     return hr;
1582 }
1583
1584 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3DDeviceImpl_3_EndScene(IDirect3DDevice3 *iface)
1585 {
1586     TRACE("iface %p.\n", iface);
1587
1588     return IDirect3DDevice7_EndScene((IDirect3DDevice7 *)device_from_device3(iface));
1589 }
1590
1591 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3DDeviceImpl_2_EndScene(IDirect3DDevice2 *iface)
1592 {
1593     TRACE("iface %p.\n", iface);
1594
1595     return IDirect3DDevice7_EndScene((IDirect3DDevice7 *)device_from_device2(iface));
1596 }
1597
1598 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3DDeviceImpl_1_EndScene(IDirect3DDevice *iface)
1599 {
1600     TRACE("iface %p.\n", iface);
1601
1602     return IDirect3DDevice7_EndScene((IDirect3DDevice7 *)device_from_device1(iface));
1603 }
1604
1605 /*****************************************************************************
1606  * IDirect3DDevice7::GetDirect3D
1607  *
1608  * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1609  * this device.
1610  *
1611  * Params:
1612  *  Direct3D7: Address to store the interface pointer at
1613  *
1614  * Returns:
1615  *  D3D_OK on success
1616  *  DDERR_INVALIDPARAMS if Direct3D7 == NULL
1617  *
1618  *****************************************************************************/
1619 static HRESULT WINAPI
1620 IDirect3DDeviceImpl_7_GetDirect3D(IDirect3DDevice7 *iface,
1621                                   IDirect3D7 **Direct3D7)
1622 {
1623     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
1624
1625     TRACE("iface %p, d3d %p.\n", iface, Direct3D7);
1626
1627     if(!Direct3D7)
1628         return DDERR_INVALIDPARAMS;
1629
1630     *Direct3D7 = &This->ddraw->IDirect3D7_iface;
1631     IDirect3D7_AddRef(*Direct3D7);
1632
1633     TRACE(" returning interface %p\n", *Direct3D7);
1634     return D3D_OK;
1635 }
1636
1637 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetDirect3D(IDirect3DDevice3 *iface,
1638         IDirect3D3 **Direct3D3)
1639 {
1640     IDirect3DDeviceImpl *This = device_from_device3(iface);
1641
1642     TRACE("iface %p, d3d %p.\n", iface, Direct3D3);
1643
1644     if(!Direct3D3)
1645         return DDERR_INVALIDPARAMS;
1646
1647     IDirect3D3_AddRef(&This->ddraw->IDirect3D3_iface);
1648     *Direct3D3 = &This->ddraw->IDirect3D3_iface;
1649     TRACE(" returning interface %p\n", *Direct3D3);
1650     return D3D_OK;
1651 }
1652
1653 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetDirect3D(IDirect3DDevice2 *iface,
1654         IDirect3D2 **Direct3D2)
1655 {
1656     IDirect3DDeviceImpl *This = device_from_device2(iface);
1657
1658     TRACE("iface %p, d3d %p.\n", iface, Direct3D2);
1659
1660     if(!Direct3D2)
1661         return DDERR_INVALIDPARAMS;
1662
1663     IDirect3D2_AddRef(&This->ddraw->IDirect3D2_iface);
1664     *Direct3D2 = &This->ddraw->IDirect3D2_iface;
1665     TRACE(" returning interface %p\n", *Direct3D2);
1666     return D3D_OK;
1667 }
1668
1669 static HRESULT WINAPI IDirect3DDeviceImpl_1_GetDirect3D(IDirect3DDevice *iface,
1670         IDirect3D **Direct3D)
1671 {
1672     IDirect3DDeviceImpl *This = device_from_device1(iface);
1673
1674     TRACE("iface %p, d3d %p.\n", iface, Direct3D);
1675
1676     if(!Direct3D)
1677         return DDERR_INVALIDPARAMS;
1678
1679     IDirect3D_AddRef(&This->ddraw->IDirect3D_iface);
1680     *Direct3D = &This->ddraw->IDirect3D_iface;
1681     TRACE(" returning interface %p\n", *Direct3D);
1682     return D3D_OK;
1683 }
1684
1685 /*****************************************************************************
1686  * IDirect3DDevice3::SetCurrentViewport
1687  *
1688  * Sets a Direct3DViewport as the current viewport.
1689  * For the thunks note that all viewport interface versions are equal
1690  *
1691  * Params:
1692  *  Direct3DViewport3: The viewport to set
1693  *
1694  * Version 2 and 3
1695  *
1696  * Returns:
1697  *  D3D_OK on success
1698  *  (Is a NULL viewport valid?)
1699  *
1700  *****************************************************************************/
1701 static HRESULT WINAPI
1702 IDirect3DDeviceImpl_3_SetCurrentViewport(IDirect3DDevice3 *iface,
1703                                          IDirect3DViewport3 *Direct3DViewport3)
1704 {
1705     IDirect3DDeviceImpl *This = device_from_device3(iface);
1706     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Direct3DViewport3;
1707
1708     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport3);
1709
1710     EnterCriticalSection(&ddraw_cs);
1711     /* Do nothing if the specified viewport is the same as the current one */
1712     if (This->current_viewport == vp )
1713     {
1714         LeaveCriticalSection(&ddraw_cs);
1715         return D3D_OK;
1716     }
1717
1718     if (vp->active_device != This)
1719     {
1720         WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
1721         LeaveCriticalSection(&ddraw_cs);
1722         return DDERR_INVALIDPARAMS;
1723     }
1724
1725     /* Release previous viewport and AddRef the new one */
1726     if (This->current_viewport)
1727     {
1728         TRACE("ViewportImpl is at %p, interface is at %p\n", This->current_viewport,
1729                 (IDirect3DViewport3 *)This->current_viewport);
1730         IDirect3DViewport3_Release((IDirect3DViewport3 *)This->current_viewport);
1731     }
1732     IDirect3DViewport3_AddRef(Direct3DViewport3);
1733
1734     /* Set this viewport as the current viewport */
1735     This->current_viewport = vp;
1736
1737     /* Activate this viewport */
1738     viewport_activate(This->current_viewport, FALSE);
1739
1740     LeaveCriticalSection(&ddraw_cs);
1741     return D3D_OK;
1742 }
1743
1744 static HRESULT WINAPI IDirect3DDeviceImpl_2_SetCurrentViewport(IDirect3DDevice2 *iface,
1745         IDirect3DViewport2 *Direct3DViewport2)
1746 {
1747     IDirect3DDeviceImpl *This = device_from_device2(iface);
1748     IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)Direct3DViewport2;
1749
1750     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport2);
1751
1752     return IDirect3DDevice3_SetCurrentViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
1753             (IDirect3DViewport3 *)vp);
1754 }
1755
1756 /*****************************************************************************
1757  * IDirect3DDevice3::GetCurrentViewport
1758  *
1759  * Returns the currently active viewport.
1760  *
1761  * Version 2 and 3
1762  *
1763  * Params:
1764  *  Direct3DViewport3: Address to return the interface pointer at
1765  *
1766  * Returns:
1767  *  D3D_OK on success
1768  *  DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1769  *
1770  *****************************************************************************/
1771 static HRESULT WINAPI
1772 IDirect3DDeviceImpl_3_GetCurrentViewport(IDirect3DDevice3 *iface,
1773                                          IDirect3DViewport3 **Direct3DViewport3)
1774 {
1775     IDirect3DDeviceImpl *This = device_from_device3(iface);
1776
1777     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport3);
1778
1779     if(!Direct3DViewport3)
1780         return DDERR_INVALIDPARAMS;
1781
1782     EnterCriticalSection(&ddraw_cs);
1783     *Direct3DViewport3 = (IDirect3DViewport3 *)This->current_viewport;
1784
1785     /* AddRef the returned viewport */
1786     if(*Direct3DViewport3) IDirect3DViewport3_AddRef(*Direct3DViewport3);
1787
1788     TRACE(" returning interface %p\n", *Direct3DViewport3);
1789
1790     LeaveCriticalSection(&ddraw_cs);
1791     return D3D_OK;
1792 }
1793
1794 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetCurrentViewport(IDirect3DDevice2 *iface,
1795         IDirect3DViewport2 **Direct3DViewport2)
1796 {
1797     IDirect3DDeviceImpl *This = device_from_device2(iface);
1798     HRESULT hr;
1799
1800     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport2);
1801
1802     hr = IDirect3DDevice3_GetCurrentViewport((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
1803             (IDirect3DViewport3 **)Direct3DViewport2);
1804     if(hr != D3D_OK) return hr;
1805     return D3D_OK;
1806 }
1807
1808 /*****************************************************************************
1809  * IDirect3DDevice7::SetRenderTarget
1810  *
1811  * Sets the render target for the Direct3DDevice.
1812  * For the thunks note that IDirectDrawSurface7 == IDirectDrawSurface4 and
1813  * IDirectDrawSurface3 == IDirectDrawSurface
1814  *
1815  * Version 2, 3 and 7
1816  *
1817  * Params:
1818  *  NewTarget: Pointer to an IDirectDrawSurface7 interface to set as the new
1819  *             render target
1820  *  Flags: Some flags
1821  *
1822  * Returns:
1823  *  D3D_OK on success, for details see IWineD3DDevice::SetRenderTarget
1824  *
1825  *****************************************************************************/
1826 static HRESULT d3d_device_set_render_target(IDirect3DDeviceImpl *This, IDirectDrawSurfaceImpl *Target)
1827 {
1828     HRESULT hr;
1829
1830     EnterCriticalSection(&ddraw_cs);
1831     /* Flags: Not used */
1832
1833     if(This->target == Target)
1834     {
1835         TRACE("No-op SetRenderTarget operation, not doing anything\n");
1836         LeaveCriticalSection(&ddraw_cs);
1837         return D3D_OK;
1838     }
1839     This->target = Target;
1840     hr = wined3d_device_set_render_target(This->wined3d_device, 0,
1841             Target ? Target->wined3d_surface : NULL, FALSE);
1842     if(hr != D3D_OK)
1843     {
1844         LeaveCriticalSection(&ddraw_cs);
1845         return hr;
1846     }
1847     IDirect3DDeviceImpl_UpdateDepthStencil(This);
1848     LeaveCriticalSection(&ddraw_cs);
1849     return D3D_OK;
1850 }
1851
1852 static HRESULT
1853 IDirect3DDeviceImpl_7_SetRenderTarget(IDirect3DDevice7 *iface,
1854                                       IDirectDrawSurface7 *NewTarget,
1855                                       DWORD Flags)
1856 {
1857     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
1858     IDirectDrawSurfaceImpl *Target = unsafe_impl_from_IDirectDrawSurface7(NewTarget);
1859
1860     TRACE("iface %p, target %p, flags %#x.\n", iface, NewTarget, Flags);
1861     /* Flags: Not used */
1862
1863     IDirectDrawSurface7_AddRef(NewTarget);
1864     IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
1865     return d3d_device_set_render_target(This, Target);
1866 }
1867
1868 static HRESULT WINAPI
1869 IDirect3DDeviceImpl_7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1870                                       IDirectDrawSurface7 *NewTarget,
1871                                       DWORD Flags)
1872 {
1873     return IDirect3DDeviceImpl_7_SetRenderTarget(iface, NewTarget, Flags);
1874 }
1875
1876 static HRESULT WINAPI
1877 IDirect3DDeviceImpl_7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1878                                       IDirectDrawSurface7 *NewTarget,
1879                                       DWORD Flags)
1880 {
1881     HRESULT hr;
1882     WORD old_fpucw;
1883
1884     old_fpucw = d3d_fpu_setup();
1885     hr = IDirect3DDeviceImpl_7_SetRenderTarget(iface, NewTarget, Flags);
1886     set_fpu_control_word(old_fpucw);
1887
1888     return hr;
1889 }
1890
1891 static HRESULT WINAPI IDirect3DDeviceImpl_3_SetRenderTarget(IDirect3DDevice3 *iface,
1892         IDirectDrawSurface4 *NewRenderTarget, DWORD Flags)
1893 {
1894     IDirect3DDeviceImpl *This = device_from_device3(iface);
1895     IDirectDrawSurfaceImpl *Target = unsafe_impl_from_IDirectDrawSurface4(NewRenderTarget);
1896
1897     TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, Flags);
1898
1899     IDirectDrawSurface4_AddRef(NewRenderTarget);
1900     IDirectDrawSurface4_Release(&This->target->IDirectDrawSurface4_iface);
1901     return d3d_device_set_render_target(This, Target);
1902 }
1903
1904 static HRESULT WINAPI IDirect3DDeviceImpl_2_SetRenderTarget(IDirect3DDevice2 *iface,
1905         IDirectDrawSurface *NewRenderTarget, DWORD Flags)
1906 {
1907     IDirect3DDeviceImpl *This = device_from_device2(iface);
1908     IDirectDrawSurfaceImpl *Target = unsafe_impl_from_IDirectDrawSurface(NewRenderTarget);
1909
1910     TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, Flags);
1911
1912     IDirectDrawSurface_AddRef(NewRenderTarget);
1913     IDirectDrawSurface_Release(&This->target->IDirectDrawSurface_iface);
1914     return d3d_device_set_render_target(This, Target);
1915 }
1916
1917 /*****************************************************************************
1918  * IDirect3DDevice7::GetRenderTarget
1919  *
1920  * Returns the current render target.
1921  * This is handled locally, because the WineD3D render target's parent
1922  * is an IParent
1923  *
1924  * Version 2, 3 and 7
1925  *
1926  * Params:
1927  *  RenderTarget: Address to store the surface interface pointer
1928  *
1929  * Returns:
1930  *  D3D_OK on success
1931  *  DDERR_INVALIDPARAMS if RenderTarget == NULL
1932  *
1933  *****************************************************************************/
1934 static HRESULT WINAPI
1935 IDirect3DDeviceImpl_7_GetRenderTarget(IDirect3DDevice7 *iface,
1936                                       IDirectDrawSurface7 **RenderTarget)
1937 {
1938     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
1939
1940     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1941
1942     if(!RenderTarget)
1943         return DDERR_INVALIDPARAMS;
1944
1945     EnterCriticalSection(&ddraw_cs);
1946     *RenderTarget = &This->target->IDirectDrawSurface7_iface;
1947     IDirectDrawSurface7_AddRef(*RenderTarget);
1948
1949     LeaveCriticalSection(&ddraw_cs);
1950     return D3D_OK;
1951 }
1952
1953 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetRenderTarget(IDirect3DDevice3 *iface,
1954         IDirectDrawSurface4 **RenderTarget)
1955 {
1956     IDirect3DDeviceImpl *This = device_from_device3(iface);
1957     IDirectDrawSurface7 *RenderTarget7;
1958     IDirectDrawSurfaceImpl *RenderTargetImpl;
1959     HRESULT hr;
1960
1961     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1962
1963     if(!RenderTarget)
1964         return DDERR_INVALIDPARAMS;
1965
1966     hr = IDirect3DDevice7_GetRenderTarget((IDirect3DDevice7 *)This, &RenderTarget7);
1967     if(hr != D3D_OK) return hr;
1968     RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1969     *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
1970     IDirectDrawSurface4_AddRef(*RenderTarget);
1971     IDirectDrawSurface7_Release(RenderTarget7);
1972     return D3D_OK;
1973 }
1974
1975 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetRenderTarget(IDirect3DDevice2 *iface,
1976         IDirectDrawSurface **RenderTarget)
1977 {
1978     IDirect3DDeviceImpl *This = device_from_device2(iface);
1979     IDirectDrawSurface7 *RenderTarget7;
1980     IDirectDrawSurfaceImpl *RenderTargetImpl;
1981     HRESULT hr;
1982
1983     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1984
1985     if(!RenderTarget)
1986         return DDERR_INVALIDPARAMS;
1987
1988     hr = IDirect3DDevice7_GetRenderTarget((IDirect3DDevice7 *)This, &RenderTarget7);
1989     if(hr != D3D_OK) return hr;
1990     RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1991     *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
1992     IDirectDrawSurface_AddRef(*RenderTarget);
1993     IDirectDrawSurface7_Release(RenderTarget7);
1994     return D3D_OK;
1995 }
1996
1997 /*****************************************************************************
1998  * IDirect3DDevice3::Begin
1999  *
2000  * Begins a description block of vertices. This is similar to glBegin()
2001  * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
2002  * described with IDirect3DDevice::Vertex are drawn.
2003  *
2004  * Version 2 and 3
2005  *
2006  * Params:
2007  *  PrimitiveType: The type of primitives to draw
2008  *  VertexTypeDesc: A flexible vertex format description of the vertices
2009  *  Flags: Some flags..
2010  *
2011  * Returns:
2012  *  D3D_OK on success
2013  *
2014  *****************************************************************************/
2015 static HRESULT WINAPI
2016 IDirect3DDeviceImpl_3_Begin(IDirect3DDevice3 *iface,
2017                             D3DPRIMITIVETYPE PrimitiveType,
2018                             DWORD VertexTypeDesc,
2019                             DWORD Flags)
2020 {
2021     IDirect3DDeviceImpl *This = device_from_device3(iface);
2022
2023     TRACE("iface %p, primitive_type %#x, FVF %#x, flags %#x.\n",
2024             iface, PrimitiveType, VertexTypeDesc, Flags);
2025
2026     EnterCriticalSection(&ddraw_cs);
2027     This->primitive_type = PrimitiveType;
2028     This->vertex_type = VertexTypeDesc;
2029     This->render_flags = Flags;
2030     This->vertex_size = get_flexible_vertex_size(This->vertex_type);
2031     This->nb_vertices = 0;
2032     LeaveCriticalSection(&ddraw_cs);
2033
2034     return D3D_OK;
2035 }
2036
2037 static HRESULT WINAPI IDirect3DDeviceImpl_2_Begin(IDirect3DDevice2 *iface, D3DPRIMITIVETYPE d3dpt,
2038         D3DVERTEXTYPE dwVertexTypeDesc, DWORD dwFlags)
2039 {
2040     DWORD FVF;
2041     IDirect3DDeviceImpl *This = device_from_device2(iface);
2042
2043     TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2044             iface, d3dpt, dwVertexTypeDesc, dwFlags);
2045
2046     switch(dwVertexTypeDesc)
2047     {
2048         case D3DVT_VERTEX: FVF = D3DFVF_VERTEX; break;
2049         case D3DVT_LVERTEX: FVF = D3DFVF_LVERTEX; break;
2050         case D3DVT_TLVERTEX: FVF = D3DFVF_TLVERTEX; break;
2051         default:
2052             ERR("Unexpected vertex type %d\n", dwVertexTypeDesc);
2053             return DDERR_INVALIDPARAMS;  /* Should never happen */
2054     };
2055
2056     return IDirect3DDevice3_Begin((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, d3dpt, FVF, dwFlags);
2057 }
2058
2059 /*****************************************************************************
2060  * IDirect3DDevice3::BeginIndexed
2061  *
2062  * Draws primitives based on vertices in a vertex array which are specified
2063  * by indices.
2064  *
2065  * Version 2 and 3
2066  *
2067  * Params:
2068  *  PrimitiveType: Primitive type to draw
2069  *  VertexType: A FVF description of the vertex format
2070  *  Vertices: pointer to an array containing the vertices
2071  *  NumVertices: The number of vertices in the vertex array
2072  *  Flags: Some flags ...
2073  *
2074  * Returns:
2075  *  D3D_OK, because it's a stub
2076  *
2077  *****************************************************************************/
2078 static HRESULT WINAPI
2079 IDirect3DDeviceImpl_3_BeginIndexed(IDirect3DDevice3 *iface,
2080                                    D3DPRIMITIVETYPE PrimitiveType,
2081                                    DWORD VertexType,
2082                                    void *Vertices,
2083                                    DWORD NumVertices,
2084                                    DWORD Flags)
2085 {
2086     FIXME("iface %p, primitive_type %#x, FVF %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2087             iface, PrimitiveType, VertexType, Vertices, NumVertices, Flags);
2088
2089     return D3D_OK;
2090 }
2091
2092
2093 static HRESULT WINAPI IDirect3DDeviceImpl_2_BeginIndexed(IDirect3DDevice2 *iface,
2094         D3DPRIMITIVETYPE d3dptPrimitiveType, D3DVERTEXTYPE d3dvtVertexType,
2095         void *lpvVertices, DWORD dwNumVertices, DWORD dwFlags)
2096 {
2097     DWORD FVF;
2098     IDirect3DDeviceImpl *This = device_from_device2(iface);
2099
2100     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2101             iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwNumVertices, dwFlags);
2102
2103     switch(d3dvtVertexType)
2104     {
2105         case D3DVT_VERTEX: FVF = D3DFVF_VERTEX; break;
2106         case D3DVT_LVERTEX: FVF = D3DFVF_LVERTEX; break;
2107         case D3DVT_TLVERTEX: FVF = D3DFVF_TLVERTEX; break;
2108         default:
2109             ERR("Unexpected vertex type %d\n", d3dvtVertexType);
2110             return DDERR_INVALIDPARAMS;  /* Should never happen */
2111     };
2112
2113     return IDirect3DDevice3_BeginIndexed((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
2114             d3dptPrimitiveType, FVF, lpvVertices, dwNumVertices, dwFlags);
2115 }
2116
2117 /*****************************************************************************
2118  * IDirect3DDevice3::Vertex
2119  *
2120  * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2121  * drawn vertices in a vertex buffer. If the buffer is too small, its
2122  * size is increased.
2123  *
2124  * Version 2 and 3
2125  *
2126  * Params:
2127  *  Vertex: Pointer to the vertex
2128  *
2129  * Returns:
2130  *  D3D_OK, on success
2131  *  DDERR_INVALIDPARAMS if Vertex is NULL
2132  *
2133  *****************************************************************************/
2134 static HRESULT WINAPI
2135 IDirect3DDeviceImpl_3_Vertex(IDirect3DDevice3 *iface,
2136                              void *Vertex)
2137 {
2138     IDirect3DDeviceImpl *This = device_from_device3(iface);
2139
2140     TRACE("iface %p, vertex %p.\n", iface, Vertex);
2141
2142     if(!Vertex)
2143         return DDERR_INVALIDPARAMS;
2144
2145     EnterCriticalSection(&ddraw_cs);
2146     if ((This->nb_vertices+1)*This->vertex_size > This->buffer_size)
2147     {
2148         BYTE *old_buffer;
2149         This->buffer_size = This->buffer_size ? This->buffer_size * 2 : This->vertex_size * 3;
2150         old_buffer = This->vertex_buffer;
2151         This->vertex_buffer = HeapAlloc(GetProcessHeap(), 0, This->buffer_size);
2152         if (old_buffer)
2153         {
2154             CopyMemory(This->vertex_buffer, old_buffer, This->nb_vertices * This->vertex_size);
2155             HeapFree(GetProcessHeap(), 0, old_buffer);
2156         }
2157     }
2158
2159     CopyMemory(This->vertex_buffer + This->nb_vertices++ * This->vertex_size, Vertex, This->vertex_size);
2160
2161     LeaveCriticalSection(&ddraw_cs);
2162     return D3D_OK;
2163 }
2164
2165 static HRESULT WINAPI IDirect3DDeviceImpl_2_Vertex(IDirect3DDevice2 *iface, void *lpVertexType)
2166 {
2167     IDirect3DDeviceImpl *This = device_from_device2(iface);
2168
2169     TRACE("iface %p, vertex %p.\n", iface, lpVertexType);
2170
2171     return IDirect3DDevice3_Vertex((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, lpVertexType);
2172 }
2173
2174 /*****************************************************************************
2175  * IDirect3DDevice3::Index
2176  *
2177  * Specifies an index to a vertex to be drawn. The vertex array has to
2178  * be specified with BeginIndexed first.
2179  *
2180  * Parameters:
2181  *  VertexIndex: The index of the vertex to draw
2182  *
2183  * Returns:
2184  *  D3D_OK because it's a stub
2185  *
2186  *****************************************************************************/
2187 static HRESULT WINAPI
2188 IDirect3DDeviceImpl_3_Index(IDirect3DDevice3 *iface,
2189                             WORD VertexIndex)
2190 {
2191     FIXME("iface %p, index %#x stub!\n", iface, VertexIndex);
2192
2193     return D3D_OK;
2194 }
2195
2196 static HRESULT WINAPI IDirect3DDeviceImpl_2_Index(IDirect3DDevice2 *iface, WORD wVertexIndex)
2197 {
2198     IDirect3DDeviceImpl *This = device_from_device2(iface);
2199
2200     TRACE("iface %p, index %#x.\n", iface, wVertexIndex);
2201
2202     return IDirect3DDevice3_Index((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, wVertexIndex);
2203 }
2204
2205 /*****************************************************************************
2206  * IDirect3DDevice3::End
2207  *
2208  * Ends a draw begun with IDirect3DDevice3::Begin or
2209  * IDirect3DDevice::BeginIndexed. The vertices specified with
2210  * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
2211  * the IDirect3DDevice7::DrawPrimitive method. So far only
2212  * non-indexed mode is supported
2213  *
2214  * Version 2 and 3
2215  *
2216  * Params:
2217  *  Flags: Some flags, as usual. Don't know which are defined
2218  *
2219  * Returns:
2220  *  The return value of IDirect3DDevice7::DrawPrimitive
2221  *
2222  *****************************************************************************/
2223 static HRESULT WINAPI
2224 IDirect3DDeviceImpl_3_End(IDirect3DDevice3 *iface,
2225                           DWORD Flags)
2226 {
2227     IDirect3DDeviceImpl *This = device_from_device3(iface);
2228
2229     TRACE("iface %p, flags %#x.\n", iface, Flags);
2230
2231     return IDirect3DDevice7_DrawPrimitive((IDirect3DDevice7 *)This, This->primitive_type,
2232             This->vertex_type, This->vertex_buffer, This->nb_vertices, This->render_flags);
2233 }
2234
2235 static HRESULT WINAPI IDirect3DDeviceImpl_2_End(IDirect3DDevice2 *iface, DWORD dwFlags)
2236 {
2237     IDirect3DDeviceImpl *This = device_from_device2(iface);
2238
2239     TRACE("iface %p, flags %#x.\n", iface, dwFlags);
2240
2241     return IDirect3DDevice3_End((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl, dwFlags);
2242 }
2243
2244 /*****************************************************************************
2245  * IDirect3DDevice7::GetRenderState
2246  *
2247  * Returns the value of a render state. The possible render states are
2248  * defined in include/d3dtypes.h
2249  *
2250  * Version 2, 3 and 7
2251  *
2252  * Params:
2253  *  RenderStateType: Render state to return the current setting of
2254  *  Value: Address to store the value at
2255  *
2256  * Returns:
2257  *  D3D_OK on success, for details see IWineD3DDevice::GetRenderState
2258  *  DDERR_INVALIDPARAMS if Value == NULL
2259  *
2260  *****************************************************************************/
2261 static HRESULT IDirect3DDeviceImpl_7_GetRenderState(IDirect3DDevice7 *iface,
2262         D3DRENDERSTATETYPE RenderStateType, DWORD *Value)
2263 {
2264     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2265     HRESULT hr;
2266
2267     TRACE("iface %p, state %#x, value %p.\n", iface, RenderStateType, Value);
2268
2269     if(!Value)
2270         return DDERR_INVALIDPARAMS;
2271
2272     EnterCriticalSection(&ddraw_cs);
2273     switch(RenderStateType)
2274     {
2275         case D3DRENDERSTATE_TEXTUREMAG:
2276         {
2277             WINED3DTEXTUREFILTERTYPE tex_mag;
2278
2279             hr = wined3d_device_get_sampler_state(This->wined3d_device, 0, WINED3DSAMP_MAGFILTER, &tex_mag);
2280
2281             switch (tex_mag)
2282             {
2283                 case WINED3DTEXF_POINT:
2284                     *Value = D3DFILTER_NEAREST;
2285                     break;
2286                 case WINED3DTEXF_LINEAR:
2287                     *Value = D3DFILTER_LINEAR;
2288                     break;
2289                 default:
2290                     ERR("Unhandled texture mag %d !\n",tex_mag);
2291                     *Value = 0;
2292             }
2293             break;
2294         }
2295
2296         case D3DRENDERSTATE_TEXTUREMIN:
2297         {
2298             WINED3DTEXTUREFILTERTYPE tex_min;
2299             WINED3DTEXTUREFILTERTYPE tex_mip;
2300
2301             hr = wined3d_device_get_sampler_state(This->wined3d_device,
2302                     0, WINED3DSAMP_MINFILTER, &tex_min);
2303             if (FAILED(hr))
2304             {
2305                 LeaveCriticalSection(&ddraw_cs);
2306                 return hr;
2307             }
2308             hr = wined3d_device_get_sampler_state(This->wined3d_device,
2309                     0, WINED3DSAMP_MIPFILTER, &tex_mip);
2310
2311             switch (tex_min)
2312             {
2313                 case WINED3DTEXF_POINT:
2314                     switch (tex_mip)
2315                     {
2316                         case WINED3DTEXF_NONE:
2317                             *Value = D3DFILTER_NEAREST;
2318                             break;
2319                         case WINED3DTEXF_POINT:
2320                             *Value = D3DFILTER_MIPNEAREST;
2321                             break;
2322                         case WINED3DTEXF_LINEAR:
2323                             *Value = D3DFILTER_LINEARMIPNEAREST;
2324                             break;
2325                         default:
2326                             ERR("Unhandled mip filter %#x.\n", tex_mip);
2327                             *Value = D3DFILTER_NEAREST;
2328                             break;
2329                     }
2330                     break;
2331                 case WINED3DTEXF_LINEAR:
2332                     switch (tex_mip)
2333                     {
2334                         case WINED3DTEXF_NONE:
2335                             *Value = D3DFILTER_LINEAR;
2336                             break;
2337                         case WINED3DTEXF_POINT:
2338                             *Value = D3DFILTER_MIPLINEAR;
2339                             break;
2340                         case WINED3DTEXF_LINEAR:
2341                             *Value = D3DFILTER_LINEARMIPLINEAR;
2342                             break;
2343                         default:
2344                             ERR("Unhandled mip filter %#x.\n", tex_mip);
2345                             *Value = D3DFILTER_LINEAR;
2346                             break;
2347                     }
2348                     break;
2349                 default:
2350                     ERR("Unhandled texture min filter %#x.\n",tex_min);
2351                     *Value = D3DFILTER_NEAREST;
2352                     break;
2353             }
2354             break;
2355         }
2356
2357         case D3DRENDERSTATE_TEXTUREADDRESS:
2358         case D3DRENDERSTATE_TEXTUREADDRESSU:
2359             hr = wined3d_device_get_sampler_state(This->wined3d_device,
2360                     0, WINED3DSAMP_ADDRESSU, Value);
2361             break;
2362         case D3DRENDERSTATE_TEXTUREADDRESSV:
2363             hr = wined3d_device_get_sampler_state(This->wined3d_device,
2364                     0, WINED3DSAMP_ADDRESSV, Value);
2365             break;
2366
2367         case D3DRENDERSTATE_BORDERCOLOR:
2368             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2369             hr = E_NOTIMPL;
2370             break;
2371
2372         case D3DRENDERSTATE_TEXTUREHANDLE:
2373         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2374             WARN("Render state %#x is invalid in d3d7.\n", RenderStateType);
2375             hr = DDERR_INVALIDPARAMS;
2376             break;
2377
2378         case D3DRENDERSTATE_ZBIAS:
2379             hr = wined3d_device_get_render_state(This->wined3d_device, WINED3DRS_DEPTHBIAS, Value);
2380             break;
2381
2382         default:
2383             if (RenderStateType >= D3DRENDERSTATE_STIPPLEPATTERN00
2384                     && RenderStateType <= D3DRENDERSTATE_STIPPLEPATTERN31)
2385             {
2386                 FIXME("Unhandled stipple pattern render state (%#x).\n",
2387                         RenderStateType);
2388                 hr = E_NOTIMPL;
2389                 break;
2390             }
2391             hr = wined3d_device_get_render_state(This->wined3d_device, RenderStateType, Value);
2392     }
2393     LeaveCriticalSection(&ddraw_cs);
2394     return hr;
2395 }
2396
2397 static HRESULT WINAPI
2398 IDirect3DDeviceImpl_7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2399                                      D3DRENDERSTATETYPE RenderStateType,
2400                                      DWORD *Value)
2401 {
2402     return IDirect3DDeviceImpl_7_GetRenderState(iface, RenderStateType, Value);
2403 }
2404
2405 static HRESULT WINAPI
2406 IDirect3DDeviceImpl_7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2407                                      D3DRENDERSTATETYPE RenderStateType,
2408                                      DWORD *Value)
2409 {
2410     HRESULT hr;
2411     WORD old_fpucw;
2412
2413     old_fpucw = d3d_fpu_setup();
2414     hr = IDirect3DDeviceImpl_7_GetRenderState(iface, RenderStateType, Value);
2415     set_fpu_control_word(old_fpucw);
2416
2417     return hr;
2418 }
2419
2420 static HRESULT WINAPI
2421 IDirect3DDeviceImpl_3_GetRenderState(IDirect3DDevice3 *iface,
2422                                      D3DRENDERSTATETYPE dwRenderStateType,
2423                                      DWORD *lpdwRenderState)
2424 {
2425     IDirect3DDeviceImpl *This = device_from_device3(iface);
2426     HRESULT hr;
2427
2428     TRACE("iface %p, state %#x, value %p.\n", iface, dwRenderStateType, lpdwRenderState);
2429
2430     switch(dwRenderStateType)
2431     {
2432         case D3DRENDERSTATE_TEXTUREHANDLE:
2433         {
2434             /* This state is wrapped to SetTexture in SetRenderState, so
2435              * it has to be wrapped to GetTexture here. */
2436             struct wined3d_texture *tex = NULL;
2437             *lpdwRenderState = 0;
2438
2439             EnterCriticalSection(&ddraw_cs);
2440
2441             hr = wined3d_device_get_texture(This->wined3d_device, 0, &tex);
2442             if (SUCCEEDED(hr) && tex)
2443             {
2444                 /* The parent of the texture is the IDirectDrawSurface7
2445                  * interface of the ddraw surface. */
2446                 IDirectDrawSurfaceImpl *parent = wined3d_texture_get_parent(tex);
2447                 if (parent) *lpdwRenderState = parent->Handle;
2448                 wined3d_texture_decref(tex);
2449             }
2450
2451             LeaveCriticalSection(&ddraw_cs);
2452
2453             return hr;
2454         }
2455
2456         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2457         {
2458             /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse
2459                the mapping to get the value. */
2460             DWORD colorop, colorarg1, colorarg2;
2461             DWORD alphaop, alphaarg1, alphaarg2;
2462
2463             EnterCriticalSection(&ddraw_cs);
2464
2465             This->legacyTextureBlending = TRUE;
2466
2467             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_COLOROP, &colorop);
2468             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_COLORARG1, &colorarg1);
2469             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_COLORARG2, &colorarg2);
2470             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAOP, &alphaop);
2471             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAARG1, &alphaarg1);
2472             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAARG2, &alphaarg2);
2473
2474             if (colorop == WINED3DTOP_SELECTARG1 && colorarg1 == WINED3DTA_TEXTURE &&
2475                 alphaop == WINED3DTOP_SELECTARG1 && alphaarg1 == WINED3DTA_TEXTURE)
2476             {
2477                 *lpdwRenderState = D3DTBLEND_DECAL;
2478             }
2479             else if (colorop == WINED3DTOP_SELECTARG1 && colorarg1 == WINED3DTA_TEXTURE &&
2480                 alphaop == WINED3DTOP_MODULATE && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2481             {
2482                 *lpdwRenderState = D3DTBLEND_DECALALPHA;
2483             }
2484             else if (colorop == WINED3DTOP_MODULATE && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT &&
2485                 alphaop == WINED3DTOP_MODULATE && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2486             {
2487                 *lpdwRenderState = D3DTBLEND_MODULATEALPHA;
2488             }
2489             else
2490             {
2491                 struct wined3d_texture *tex = NULL;
2492                 HRESULT hr;
2493                 BOOL tex_alpha = FALSE;
2494                 DDPIXELFORMAT ddfmt;
2495
2496                 hr = wined3d_device_get_texture(This->wined3d_device, 0, &tex);
2497
2498                 if(hr == WINED3D_OK && tex)
2499                 {
2500                     struct wined3d_resource *sub_resource;
2501
2502                     if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2503                     {
2504                         struct wined3d_resource_desc desc;
2505
2506                         wined3d_resource_get_desc(sub_resource, &desc);
2507                         ddfmt.dwSize = sizeof(ddfmt);
2508                         PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2509                         if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2510                     }
2511
2512                     wined3d_texture_decref(tex);
2513                 }
2514
2515                 if (!(colorop == WINED3DTOP_MODULATE && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT &&
2516                       alphaop == (tex_alpha ? WINED3DTOP_SELECTARG1 : WINED3DTOP_SELECTARG2) &&
2517                       alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT))
2518                 {
2519                     ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous\n");
2520                 }
2521
2522                 *lpdwRenderState = D3DTBLEND_MODULATE;
2523             }
2524
2525             LeaveCriticalSection(&ddraw_cs);
2526
2527             return D3D_OK;
2528         }
2529
2530         default:
2531             return IDirect3DDevice7_GetRenderState((IDirect3DDevice7 *)This, dwRenderStateType, lpdwRenderState);
2532     }
2533 }
2534
2535 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetRenderState(IDirect3DDevice2 *iface,
2536         D3DRENDERSTATETYPE dwRenderStateType, DWORD *lpdwRenderState)
2537 {
2538     IDirect3DDeviceImpl *This = device_from_device2(iface);
2539
2540     TRACE("iface %p, state %#x, value %p.\n", iface, dwRenderStateType, lpdwRenderState);
2541
2542     return IDirect3DDevice3_GetRenderState((IDirect3DDevice3 *)&This->IDirect3DDevice3_vtbl,
2543             dwRenderStateType, lpdwRenderState);
2544 }
2545
2546 /*****************************************************************************
2547  * IDirect3DDevice7::SetRenderState
2548  *
2549  * Sets a render state. The possible render states are defined in
2550  * include/d3dtypes.h
2551  *
2552  * Version 2, 3 and 7
2553  *
2554  * Params:
2555  *  RenderStateType: State to set
2556  *  Value: Value to assign to that state
2557  *
2558  * Returns:
2559  *  D3D_OK on success,
2560  *  for details see IWineD3DDevice::SetRenderState
2561  *
2562  *****************************************************************************/
2563 static HRESULT
2564 IDirect3DDeviceImpl_7_SetRenderState(IDirect3DDevice7 *iface,
2565                                      D3DRENDERSTATETYPE RenderStateType,
2566                                      DWORD Value)
2567 {
2568     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
2569     HRESULT hr;
2570
2571     TRACE("iface %p, state %#x, value %#x.\n", iface, RenderStateType, Value);
2572
2573     EnterCriticalSection(&ddraw_cs);
2574     /* Some render states need special care */
2575     switch(RenderStateType)
2576     {
2577         /*
2578          * The ddraw texture filter mapping works like this:
2579          *     D3DFILTER_NEAREST            Point min/mag, no mip
2580          *     D3DFILTER_MIPNEAREST         Point min/mag, point mip
2581          *     D3DFILTER_LINEARMIPNEAREST:  Point min/mag, linear mip
2582          *
2583          *     D3DFILTER_LINEAR             Linear min/mag, no mip
2584          *     D3DFILTER_MIPLINEAR          Linear min/mag, point mip
2585          *     D3DFILTER_LINEARMIPLINEAR    Linear min/mag, linear mip
2586          *
2587          * This is the opposite of the GL naming convention,
2588          * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2589          */
2590         case D3DRENDERSTATE_TEXTUREMAG:
2591         {
2592             WINED3DTEXTUREFILTERTYPE tex_mag;
2593
2594             switch (Value)
2595             {
2596                 case D3DFILTER_NEAREST:
2597                 case D3DFILTER_MIPNEAREST:
2598                 case D3DFILTER_LINEARMIPNEAREST:
2599                     tex_mag = WINED3DTEXF_POINT;
2600                     break;
2601                 case D3DFILTER_LINEAR:
2602                 case D3DFILTER_MIPLINEAR:
2603                 case D3DFILTER_LINEARMIPLINEAR:
2604                     tex_mag = WINED3DTEXF_LINEAR;
2605                     break;
2606                 default:
2607                     tex_mag = WINED3DTEXF_POINT;
2608                     ERR("Unhandled texture mag %d !\n",Value);
2609                     break;
2610             }
2611
2612             hr = wined3d_device_set_sampler_state(This->wined3d_device, 0, WINED3DSAMP_MAGFILTER, tex_mag);
2613             break;
2614         }
2615
2616         case D3DRENDERSTATE_TEXTUREMIN:
2617         {
2618             WINED3DTEXTUREFILTERTYPE tex_min;
2619             WINED3DTEXTUREFILTERTYPE tex_mip;
2620
2621             switch ((D3DTEXTUREFILTER) Value)
2622             {
2623                 case D3DFILTER_NEAREST:
2624                     tex_min = WINED3DTEXF_POINT;
2625                     tex_mip = WINED3DTEXF_NONE;
2626                     break;
2627                 case D3DFILTER_LINEAR:
2628                     tex_min = WINED3DTEXF_LINEAR;
2629                     tex_mip = WINED3DTEXF_NONE;
2630                     break;
2631                 case D3DFILTER_MIPNEAREST:
2632                     tex_min = WINED3DTEXF_POINT;
2633                     tex_mip = WINED3DTEXF_POINT;
2634                     break;
2635                 case D3DFILTER_MIPLINEAR:
2636                     tex_min = WINED3DTEXF_LINEAR;
2637                     tex_mip = WINED3DTEXF_POINT;
2638                     break;
2639                 case D3DFILTER_LINEARMIPNEAREST:
2640                     tex_min = WINED3DTEXF_POINT;
2641                     tex_mip = WINED3DTEXF_LINEAR;
2642                     break;
2643                 case D3DFILTER_LINEARMIPLINEAR:
2644                     tex_min = WINED3DTEXF_LINEAR;
2645                     tex_mip = WINED3DTEXF_LINEAR;
2646                     break;
2647
2648                 default:
2649                     ERR("Unhandled texture min %d !\n",Value);
2650                     tex_min = WINED3DTEXF_POINT;
2651                     tex_mip = WINED3DTEXF_NONE;
2652                     break;
2653             }
2654
2655             wined3d_device_set_sampler_state(This->wined3d_device,
2656                     0, WINED3DSAMP_MIPFILTER, tex_mip);
2657             hr = wined3d_device_set_sampler_state(This->wined3d_device,
2658                     0, WINED3DSAMP_MINFILTER, tex_min);
2659             break;
2660         }
2661
2662         case D3DRENDERSTATE_TEXTUREADDRESS:
2663             wined3d_device_set_sampler_state(This->wined3d_device,
2664                     0, WINED3DSAMP_ADDRESSV, Value);
2665             /* Drop through */
2666         case D3DRENDERSTATE_TEXTUREADDRESSU:
2667             hr = wined3d_device_set_sampler_state(This->wined3d_device,
2668                     0, WINED3DSAMP_ADDRESSU, Value);
2669             break;
2670         case D3DRENDERSTATE_TEXTUREADDRESSV:
2671             hr = wined3d_device_set_sampler_state(This->wined3d_device,
2672                     0, WINED3DSAMP_ADDRESSV, Value);
2673             break;
2674
2675         case D3DRENDERSTATE_BORDERCOLOR:
2676             /* This should probably just forward to the corresponding sampler
2677              * state. Needs tests. */
2678             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2679             hr = E_NOTIMPL;
2680             break;
2681
2682         case D3DRENDERSTATE_TEXTUREHANDLE:
2683         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2684             WARN("Render state %#x is invalid in d3d7.\n", RenderStateType);
2685             hr = DDERR_INVALIDPARAMS;
2686             break;
2687
2688         case D3DRENDERSTATE_ZBIAS:
2689             hr = wined3d_device_set_render_state(This->wined3d_device, WINED3DRS_DEPTHBIAS, Value);
2690             break;
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 = unsafe_impl_from_IDirect3DVertexBuffer7(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 = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
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, &vb->IDirect3DVertexBuffer7_iface, 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 = unsafe_impl_from_IDirect3DVertexBuffer7(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 = unsafe_impl_from_IDirect3DVertexBuffer(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, &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount,
4285             Flags);
4286 }
4287
4288 /*****************************************************************************
4289  * IDirect3DDevice7::ComputeSphereVisibility
4290  *
4291  * Calculates the visibility of spheres in the current viewport. The spheres
4292  * are passed in the Centers and Radii arrays, the results are passed back
4293  * in the ReturnValues array. Return values are either completely visible,
4294  * partially visible or completely invisible.
4295  * The return value consist of a combination of D3DCLIP_* flags, or it's
4296  * 0 if the sphere is completely visible(according to the SDK, not checked)
4297  *
4298  * Version 3 and 7
4299  *
4300  * Params:
4301  *  Centers: Array containing the sphere centers
4302  *  Radii: Array containing the sphere radii
4303  *  NumSpheres: The number of centers and radii in the arrays
4304  *  Flags: Some flags
4305  *  ReturnValues: Array to write the results to
4306  *
4307  * Returns:
4308  *  D3D_OK
4309  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4310  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4311  *  is singular)
4312  *
4313  *****************************************************************************/
4314
4315 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4316 {
4317     float distance, norm;
4318
4319     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4320     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4321
4322     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4323     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4324     return 0;
4325 }
4326
4327 static HRESULT WINAPI
4328 IDirect3DDeviceImpl_7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4329                                               D3DVECTOR *Centers,
4330                                               D3DVALUE *Radii,
4331                                               DWORD NumSpheres,
4332                                               DWORD Flags,
4333                                               DWORD *ReturnValues)
4334 {
4335     D3DMATRIX m, temp;
4336     D3DVALUE origin_plane[6];
4337     D3DVECTOR vec[6];
4338     HRESULT hr;
4339     UINT i, j;
4340
4341     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4342             iface, Centers, Radii, NumSpheres, Flags, ReturnValues);
4343
4344     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4345     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4346     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4347     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4348     multiply_matrix(&m, &temp, &m);
4349
4350     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4351     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4352     multiply_matrix(&m, &temp, &m);
4353
4354 /* Left plane */
4355     vec[0].u1.x = m._14 + m._11;
4356     vec[0].u2.y = m._24 + m._21;
4357     vec[0].u3.z = m._34 + m._31;
4358     origin_plane[0] = m._44 + m._41;
4359
4360 /* Right plane */
4361     vec[1].u1.x = m._14 - m._11;
4362     vec[1].u2.y = m._24 - m._21;
4363     vec[1].u3.z = m._34 - m._31;
4364     origin_plane[1] = m._44 - m._41;
4365
4366 /* Top plane */
4367     vec[2].u1.x = m._14 - m._12;
4368     vec[2].u2.y = m._24 - m._22;
4369     vec[2].u3.z = m._34 - m._32;
4370     origin_plane[2] = m._44 - m._42;
4371
4372 /* Bottom plane */
4373     vec[3].u1.x = m._14 + m._12;
4374     vec[3].u2.y = m._24 + m._22;
4375     vec[3].u3.z = m._34 + m._32;
4376     origin_plane[3] = m._44 + m._42;
4377
4378 /* Front plane */
4379     vec[4].u1.x = m._13;
4380     vec[4].u2.y = m._23;
4381     vec[4].u3.z = m._33;
4382     origin_plane[4] = m._43;
4383
4384 /* Back plane*/
4385     vec[5].u1.x = m._14 - m._13;
4386     vec[5].u2.y = m._24 - m._23;
4387     vec[5].u3.z = m._34 - m._33;
4388     origin_plane[5] = m._44 - m._43;
4389
4390     for(i=0; i<NumSpheres; i++)
4391     {
4392         ReturnValues[i] = 0;
4393         for(j=0; j<6; j++) ReturnValues[i] |= in_plane(j, vec[j], origin_plane[j], Centers[i], Radii[i]);
4394     }
4395
4396     return D3D_OK;
4397 }
4398
4399 static HRESULT WINAPI IDirect3DDeviceImpl_3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4400         D3DVECTOR *Centers, D3DVALUE *Radii, DWORD NumSpheres, DWORD Flags, DWORD *ReturnValues)
4401 {
4402     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4403             iface, Centers, Radii, NumSpheres, Flags, ReturnValues);
4404
4405     return IDirect3DDevice7_ComputeSphereVisibility((IDirect3DDevice7 *)device_from_device3(iface),
4406             Centers, Radii, NumSpheres, Flags, ReturnValues);
4407 }
4408
4409 /*****************************************************************************
4410  * IDirect3DDevice7::GetTexture
4411  *
4412  * Returns the texture interface handle assigned to a texture stage.
4413  * The returned texture is AddRefed. This is taken from old ddraw,
4414  * not checked in Windows.
4415  *
4416  * Version 3 and 7
4417  *
4418  * Params:
4419  *  Stage: Texture stage to read the texture from
4420  *  Texture: Address to store the interface pointer at
4421  *
4422  * Returns:
4423  *  D3D_OK on success
4424  *  DDERR_INVALIDPARAMS if Texture is NULL
4425  *  For details, see IWineD3DDevice::GetTexture
4426  *
4427  *****************************************************************************/
4428 static HRESULT
4429 IDirect3DDeviceImpl_7_GetTexture(IDirect3DDevice7 *iface,
4430                                  DWORD Stage,
4431                                  IDirectDrawSurface7 **Texture)
4432 {
4433     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4434     struct wined3d_texture *wined3d_texture;
4435     HRESULT hr;
4436
4437     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture);
4438
4439     if(!Texture)
4440     {
4441         TRACE("Texture == NULL, failing with DDERR_INVALIDPARAMS\n");
4442         return DDERR_INVALIDPARAMS;
4443     }
4444
4445     EnterCriticalSection(&ddraw_cs);
4446     hr = wined3d_device_get_texture(This->wined3d_device, Stage, &wined3d_texture);
4447     if (FAILED(hr) || !wined3d_texture)
4448     {
4449         *Texture = NULL;
4450         LeaveCriticalSection(&ddraw_cs);
4451         return hr;
4452     }
4453
4454     *Texture = wined3d_texture_get_parent(wined3d_texture);
4455     IDirectDrawSurface7_AddRef(*Texture);
4456     LeaveCriticalSection(&ddraw_cs);
4457     return hr;
4458 }
4459
4460 static HRESULT WINAPI
4461 IDirect3DDeviceImpl_7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4462                                  DWORD Stage,
4463                                  IDirectDrawSurface7 **Texture)
4464 {
4465     return IDirect3DDeviceImpl_7_GetTexture(iface, Stage, Texture);
4466 }
4467
4468 static HRESULT WINAPI
4469 IDirect3DDeviceImpl_7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4470                                  DWORD Stage,
4471                                  IDirectDrawSurface7 **Texture)
4472 {
4473     HRESULT hr;
4474     WORD old_fpucw;
4475
4476     old_fpucw = d3d_fpu_setup();
4477     hr = IDirect3DDeviceImpl_7_GetTexture(iface, Stage, Texture);
4478     set_fpu_control_word(old_fpucw);
4479
4480     return hr;
4481 }
4482
4483 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetTexture(IDirect3DDevice3 *iface, DWORD Stage,
4484         IDirect3DTexture2 **Texture2)
4485 {
4486     HRESULT ret;
4487     IDirectDrawSurface7 *ret_val;
4488     IDirectDrawSurfaceImpl *ret_val_impl;
4489
4490     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture2);
4491
4492     ret = IDirect3DDevice7_GetTexture((IDirect3DDevice7 *)device_from_device3(iface), Stage, &ret_val);
4493
4494     ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4495     *Texture2 = ret_val_impl ? (IDirect3DTexture2 *)&ret_val_impl->IDirect3DTexture2_vtbl : NULL;
4496
4497     TRACE("Returning texture %p.\n", *Texture2);
4498
4499     return ret;
4500 }
4501
4502 /*****************************************************************************
4503  * IDirect3DDevice7::SetTexture
4504  *
4505  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4506  *
4507  * Version 3 and 7
4508  *
4509  * Params:
4510  *  Stage: The stage to assign the texture to
4511  *  Texture: Interface pointer to the texture surface
4512  *
4513  * Returns
4514  * D3D_OK on success
4515  * For details, see IWineD3DDevice::SetTexture
4516  *
4517  *****************************************************************************/
4518 static HRESULT
4519 IDirect3DDeviceImpl_7_SetTexture(IDirect3DDevice7 *iface,
4520                                  DWORD Stage,
4521                                  IDirectDrawSurface7 *Texture)
4522 {
4523     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4524     IDirectDrawSurfaceImpl *surf = unsafe_impl_from_IDirectDrawSurface7(Texture);
4525     HRESULT hr;
4526
4527     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture);
4528
4529     /* Texture may be NULL here */
4530     EnterCriticalSection(&ddraw_cs);
4531     hr = wined3d_device_set_texture(This->wined3d_device,
4532             Stage, surf ? surf->wined3d_texture : NULL);
4533     LeaveCriticalSection(&ddraw_cs);
4534     return hr;
4535 }
4536
4537 static HRESULT WINAPI
4538 IDirect3DDeviceImpl_7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4539                                  DWORD Stage,
4540                                  IDirectDrawSurface7 *Texture)
4541 {
4542     return IDirect3DDeviceImpl_7_SetTexture(iface, Stage, Texture);
4543 }
4544
4545 static HRESULT WINAPI
4546 IDirect3DDeviceImpl_7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4547                                  DWORD Stage,
4548                                  IDirectDrawSurface7 *Texture)
4549 {
4550     HRESULT hr;
4551     WORD old_fpucw;
4552
4553     old_fpucw = d3d_fpu_setup();
4554     hr = IDirect3DDeviceImpl_7_SetTexture(iface, Stage, Texture);
4555     set_fpu_control_word(old_fpucw);
4556
4557     return hr;
4558 }
4559
4560 static HRESULT WINAPI
4561 IDirect3DDeviceImpl_3_SetTexture(IDirect3DDevice3 *iface,
4562                                  DWORD Stage,
4563                                  IDirect3DTexture2 *Texture2)
4564 {
4565     IDirect3DDeviceImpl *This = device_from_device3(iface);
4566     IDirectDrawSurfaceImpl *tex = Texture2 ? surface_from_texture2(Texture2) : NULL;
4567     DWORD texmapblend;
4568     HRESULT hr;
4569
4570     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture2);
4571
4572     EnterCriticalSection(&ddraw_cs);
4573
4574     if (This->legacyTextureBlending)
4575         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4576
4577     hr = IDirect3DDevice7_SetTexture((IDirect3DDevice7 *)This, Stage, &tex->IDirectDrawSurface7_iface);
4578
4579     if (This->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4580     {
4581         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4582            See IDirect3DDeviceImpl_3_SetRenderState for details. */
4583         struct wined3d_texture *tex = NULL;
4584         BOOL tex_alpha = FALSE;
4585         DDPIXELFORMAT ddfmt;
4586         HRESULT result;
4587
4588         result = wined3d_device_get_texture(This->wined3d_device, 0, &tex);
4589         if (result == WINED3D_OK && tex)
4590         {
4591             struct wined3d_resource *sub_resource;
4592
4593             if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4594             {
4595                 struct wined3d_resource_desc desc;
4596
4597                 wined3d_resource_get_desc(sub_resource, &desc);
4598                 ddfmt.dwSize = sizeof(ddfmt);
4599                 PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4600                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4601             }
4602
4603             wined3d_texture_decref(tex);
4604         }
4605
4606         /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4607         if (tex_alpha)
4608             wined3d_device_set_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1);
4609         else
4610             wined3d_device_set_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
4611     }
4612
4613     LeaveCriticalSection(&ddraw_cs);
4614
4615     return hr;
4616 }
4617
4618 static const struct tss_lookup
4619 {
4620     BOOL sampler_state;
4621     DWORD state;
4622 }
4623 tss_lookup[] =
4624 {
4625     {FALSE, WINED3DTSS_FORCE_DWORD},            /*  0, unused */
4626     {FALSE, WINED3DTSS_COLOROP},                /*  1, D3DTSS_COLOROP */
4627     {FALSE, WINED3DTSS_COLORARG1},              /*  2, D3DTSS_COLORARG1 */
4628     {FALSE, WINED3DTSS_COLORARG2},              /*  3, D3DTSS_COLORARG2 */
4629     {FALSE, WINED3DTSS_ALPHAOP},                /*  4, D3DTSS_ALPHAOP */
4630     {FALSE, WINED3DTSS_ALPHAARG1},              /*  5, D3DTSS_ALPHAARG1 */
4631     {FALSE, WINED3DTSS_ALPHAARG2},              /*  6, D3DTSS_ALPHAARG2 */
4632     {FALSE, WINED3DTSS_BUMPENVMAT00},           /*  7, D3DTSS_BUMPENVMAT00 */
4633     {FALSE, WINED3DTSS_BUMPENVMAT01},           /*  8, D3DTSS_BUMPENVMAT01 */
4634     {FALSE, WINED3DTSS_BUMPENVMAT10},           /*  9, D3DTSS_BUMPENVMAT10 */
4635     {FALSE, WINED3DTSS_BUMPENVMAT11},           /* 10, D3DTSS_BUMPENVMAT11 */
4636     {FALSE, WINED3DTSS_TEXCOORDINDEX},          /* 11, D3DTSS_TEXCOORDINDEX */
4637     {TRUE,  WINED3DSAMP_ADDRESSU},              /* 12, D3DTSS_ADDRESS */
4638     {TRUE,  WINED3DSAMP_ADDRESSU},              /* 13, D3DTSS_ADDRESSU */
4639     {TRUE,  WINED3DSAMP_ADDRESSV},              /* 14, D3DTSS_ADDRESSV */
4640     {TRUE,  WINED3DSAMP_BORDERCOLOR},           /* 15, D3DTSS_BORDERCOLOR */
4641     {TRUE,  WINED3DSAMP_MAGFILTER},             /* 16, D3DTSS_MAGFILTER */
4642     {TRUE,  WINED3DSAMP_MINFILTER},             /* 17, D3DTSS_MINFILTER */
4643     {TRUE,  WINED3DSAMP_MIPFILTER},             /* 18, D3DTSS_MIPFILTER */
4644     {TRUE,  WINED3DSAMP_MIPMAPLODBIAS},         /* 19, D3DTSS_MIPMAPLODBIAS */
4645     {TRUE,  WINED3DSAMP_MAXMIPLEVEL},           /* 20, D3DTSS_MAXMIPLEVEL */
4646     {TRUE,  WINED3DSAMP_MAXANISOTROPY},         /* 21, D3DTSS_MAXANISOTROPY */
4647     {FALSE, WINED3DTSS_BUMPENVLSCALE},          /* 22, D3DTSS_BUMPENVLSCALE */
4648     {FALSE, WINED3DTSS_BUMPENVLOFFSET},         /* 23, D3DTSS_BUMPENVLOFFSET */
4649     {FALSE, WINED3DTSS_TEXTURETRANSFORMFLAGS},  /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4650 };
4651
4652 /*****************************************************************************
4653  * IDirect3DDevice7::GetTextureStageState
4654  *
4655  * Retrieves a state from a texture stage.
4656  *
4657  * Version 3 and 7
4658  *
4659  * Params:
4660  *  Stage: The stage to retrieve the state from
4661  *  TexStageStateType: The state type to retrieve
4662  *  State: Address to store the state's value at
4663  *
4664  * Returns:
4665  *  D3D_OK on success
4666  *  DDERR_INVALIDPARAMS if State is NULL
4667  *  For details, see IWineD3DDevice::GetTextureStageState
4668  *
4669  *****************************************************************************/
4670 static HRESULT
4671 IDirect3DDeviceImpl_7_GetTextureStageState(IDirect3DDevice7 *iface,
4672                                            DWORD Stage,
4673                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4674                                            DWORD *State)
4675 {
4676     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4677     HRESULT hr;
4678     const struct tss_lookup *l;
4679
4680     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4681             iface, Stage, TexStageStateType, State);
4682
4683     if(!State)
4684         return DDERR_INVALIDPARAMS;
4685
4686     if (TexStageStateType > D3DTSS_TEXTURETRANSFORMFLAGS)
4687     {
4688         WARN("Invalid TexStageStateType %#x passed.\n", TexStageStateType);
4689         return DD_OK;
4690     }
4691
4692     l = &tss_lookup[TexStageStateType];
4693
4694     EnterCriticalSection(&ddraw_cs);
4695
4696     if (l->sampler_state)
4697     {
4698         hr = wined3d_device_get_sampler_state(This->wined3d_device, Stage, l->state, State);
4699
4700         switch(TexStageStateType)
4701         {
4702             /* Mipfilter is a sampler state with different values */
4703             case D3DTSS_MIPFILTER:
4704             {
4705                 switch(*State)
4706                 {
4707                     case WINED3DTEXF_NONE: *State = D3DTFP_NONE; break;
4708                     case WINED3DTEXF_POINT: *State = D3DTFP_POINT; break;
4709                     case WINED3DTEXF_LINEAR: *State = D3DTFP_LINEAR; break;
4710                     default:
4711                         ERR("Unexpected mipfilter value %#x\n", *State);
4712                         *State = D3DTFP_NONE;
4713                         break;
4714                 }
4715                 break;
4716             }
4717
4718             /* Magfilter has slightly different values */
4719             case D3DTSS_MAGFILTER:
4720             {
4721                 switch(*State)
4722                 {
4723                     case WINED3DTEXF_POINT: *State = D3DTFG_POINT; break;
4724                     case WINED3DTEXF_LINEAR: *State = D3DTFG_LINEAR; break;
4725                     case WINED3DTEXF_ANISOTROPIC: *State = D3DTFG_ANISOTROPIC; break;
4726                     case WINED3DTEXF_FLATCUBIC: *State = D3DTFG_FLATCUBIC; break;
4727                     case WINED3DTEXF_GAUSSIANCUBIC: *State = D3DTFG_GAUSSIANCUBIC; break;
4728                     default:
4729                         ERR("Unexpected wined3d mag filter value %#x\n", *State);
4730                         *State = D3DTFG_POINT;
4731                         break;
4732                 }
4733                 break;
4734             }
4735
4736             default:
4737                 break;
4738         }
4739     }
4740     else
4741     {
4742         hr = wined3d_device_get_texture_stage_state(This->wined3d_device, Stage, l->state, State);
4743     }
4744
4745     LeaveCriticalSection(&ddraw_cs);
4746     return hr;
4747 }
4748
4749 static HRESULT WINAPI
4750 IDirect3DDeviceImpl_7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4751                                            DWORD Stage,
4752                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4753                                            DWORD *State)
4754 {
4755     return IDirect3DDeviceImpl_7_GetTextureStageState(iface, Stage, TexStageStateType, State);
4756 }
4757
4758 static HRESULT WINAPI
4759 IDirect3DDeviceImpl_7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4760                                            DWORD Stage,
4761                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4762                                            DWORD *State)
4763 {
4764     HRESULT hr;
4765     WORD old_fpucw;
4766
4767     old_fpucw = d3d_fpu_setup();
4768     hr = IDirect3DDeviceImpl_7_GetTextureStageState(iface, Stage, TexStageStateType, State);
4769     set_fpu_control_word(old_fpucw);
4770
4771     return hr;
4772 }
4773
4774 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetTextureStageState(IDirect3DDevice3 *iface,
4775         DWORD Stage, D3DTEXTURESTAGESTATETYPE TexStageStateType, DWORD *State)
4776 {
4777     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4778             iface, Stage, TexStageStateType, State);
4779
4780     return IDirect3DDevice7_GetTextureStageState((IDirect3DDevice7 *)device_from_device3(iface),
4781             Stage, TexStageStateType, State);
4782 }
4783
4784 /*****************************************************************************
4785  * IDirect3DDevice7::SetTextureStageState
4786  *
4787  * Sets a texture stage state. Some stage types need to be handled specially,
4788  * because they do not exist in WineD3D and were moved to another place
4789  *
4790  * Version 3 and 7
4791  *
4792  * Params:
4793  *  Stage: The stage to modify
4794  *  TexStageStateType: The state to change
4795  *  State: The new value for the state
4796  *
4797  * Returns:
4798  *  D3D_OK on success
4799  *  For details, see IWineD3DDevice::SetTextureStageState
4800  *
4801  *****************************************************************************/
4802 static HRESULT
4803 IDirect3DDeviceImpl_7_SetTextureStageState(IDirect3DDevice7 *iface,
4804                                            DWORD Stage,
4805                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4806                                            DWORD State)
4807 {
4808     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4809     const struct tss_lookup *l;
4810     HRESULT hr;
4811
4812     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4813             iface, Stage, TexStageStateType, State);
4814
4815     if (TexStageStateType > D3DTSS_TEXTURETRANSFORMFLAGS)
4816     {
4817         WARN("Invalid TexStageStateType %#x passed.\n", TexStageStateType);
4818         return DD_OK;
4819     }
4820
4821     l = &tss_lookup[TexStageStateType];
4822
4823     EnterCriticalSection(&ddraw_cs);
4824
4825     if (l->sampler_state)
4826     {
4827         switch(TexStageStateType)
4828         {
4829             /* Mipfilter is a sampler state with different values */
4830             case D3DTSS_MIPFILTER:
4831             {
4832                 switch(State)
4833                 {
4834                     case D3DTFP_NONE: State = WINED3DTEXF_NONE; break;
4835                     case D3DTFP_POINT: State = WINED3DTEXF_POINT; break;
4836                     case 0: /* Unchecked */
4837                     case D3DTFP_LINEAR: State = WINED3DTEXF_LINEAR; break;
4838                     default:
4839                         ERR("Unexpected mipfilter value %d\n", State);
4840                         State = WINED3DTEXF_NONE;
4841                         break;
4842                 }
4843                 break;
4844             }
4845
4846             /* Magfilter has slightly different values */
4847             case D3DTSS_MAGFILTER:
4848             {
4849                 switch(State)
4850                 {
4851                     case D3DTFG_POINT: State = WINED3DTEXF_POINT; break;
4852                     case D3DTFG_LINEAR: State = WINED3DTEXF_LINEAR; break;
4853                     case D3DTFG_FLATCUBIC: State = WINED3DTEXF_FLATCUBIC; break;
4854                     case D3DTFG_GAUSSIANCUBIC: State = WINED3DTEXF_GAUSSIANCUBIC; break;
4855                     case D3DTFG_ANISOTROPIC: State = WINED3DTEXF_ANISOTROPIC; break;
4856                     default:
4857                         ERR("Unexpected d3d7 mag filter type %d\n", State);
4858                         State = WINED3DTEXF_POINT;
4859                         break;
4860                 }
4861                 break;
4862             }
4863
4864             case D3DTSS_ADDRESS:
4865                 wined3d_device_set_sampler_state(This->wined3d_device, Stage, WINED3DSAMP_ADDRESSV, State);
4866                 break;
4867
4868             default:
4869                 break;
4870         }
4871
4872         hr = wined3d_device_set_sampler_state(This->wined3d_device, Stage, l->state, State);
4873     }
4874     else
4875     {
4876         hr = wined3d_device_set_texture_stage_state(This->wined3d_device, Stage, l->state, State);
4877     }
4878
4879     LeaveCriticalSection(&ddraw_cs);
4880     return hr;
4881 }
4882
4883 static HRESULT WINAPI
4884 IDirect3DDeviceImpl_7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4885                                            DWORD Stage,
4886                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4887                                            DWORD State)
4888 {
4889     return IDirect3DDeviceImpl_7_SetTextureStageState(iface, Stage, TexStageStateType, State);
4890 }
4891
4892 static HRESULT WINAPI
4893 IDirect3DDeviceImpl_7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4894                                            DWORD Stage,
4895                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4896                                            DWORD State)
4897 {
4898     HRESULT hr;
4899     WORD old_fpucw;
4900
4901     old_fpucw = d3d_fpu_setup();
4902     hr = IDirect3DDeviceImpl_7_SetTextureStageState(iface, Stage, TexStageStateType, State);
4903     set_fpu_control_word(old_fpucw);
4904
4905     return hr;
4906 }
4907
4908 static HRESULT WINAPI IDirect3DDeviceImpl_3_SetTextureStageState(IDirect3DDevice3 *iface,
4909         DWORD Stage, D3DTEXTURESTAGESTATETYPE TexStageStateType, DWORD State)
4910 {
4911     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4912             iface, Stage, TexStageStateType, State);
4913
4914     return IDirect3DDevice7_SetTextureStageState((IDirect3DDevice7 *)device_from_device3(iface),
4915             Stage, TexStageStateType, State);
4916 }
4917
4918 /*****************************************************************************
4919  * IDirect3DDevice7::ValidateDevice
4920  *
4921  * SDK: "Reports the device's ability to render the currently set
4922  * texture-blending operations in a single pass". Whatever that means
4923  * exactly...
4924  *
4925  * Version 3 and 7
4926  *
4927  * Params:
4928  *  NumPasses: Address to write the number of necessary passes for the
4929  *             desired effect to.
4930  *
4931  * Returns:
4932  *  D3D_OK on success
4933  *  See IWineD3DDevice::ValidateDevice for more details
4934  *
4935  *****************************************************************************/
4936 static HRESULT
4937 IDirect3DDeviceImpl_7_ValidateDevice(IDirect3DDevice7 *iface,
4938                                      DWORD *NumPasses)
4939 {
4940     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
4941     HRESULT hr;
4942
4943     TRACE("iface %p, pass_count %p.\n", iface, NumPasses);
4944
4945     EnterCriticalSection(&ddraw_cs);
4946     hr = wined3d_device_validate_device(This->wined3d_device, NumPasses);
4947     LeaveCriticalSection(&ddraw_cs);
4948     return hr;
4949 }
4950
4951 static HRESULT WINAPI
4952 IDirect3DDeviceImpl_7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface,
4953                                      DWORD *NumPasses)
4954 {
4955     return IDirect3DDeviceImpl_7_ValidateDevice(iface, NumPasses);
4956 }
4957
4958 static HRESULT WINAPI
4959 IDirect3DDeviceImpl_7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface,
4960                                      DWORD *NumPasses)
4961 {
4962     HRESULT hr;
4963     WORD old_fpucw;
4964
4965     old_fpucw = d3d_fpu_setup();
4966     hr = IDirect3DDeviceImpl_7_ValidateDevice(iface, NumPasses);
4967     set_fpu_control_word(old_fpucw);
4968
4969     return hr;
4970 }
4971
4972 static HRESULT WINAPI IDirect3DDeviceImpl_3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *Passes)
4973 {
4974     TRACE("iface %p, pass_count %p.\n", iface, Passes);
4975
4976     return IDirect3DDevice7_ValidateDevice((IDirect3DDevice7 *)device_from_device3(iface), Passes);
4977 }
4978
4979 /*****************************************************************************
4980  * IDirect3DDevice7::Clear
4981  *
4982  * Fills the render target, the z buffer and the stencil buffer with a
4983  * clear color / value
4984  *
4985  * Version 7 only
4986  *
4987  * Params:
4988  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
4989  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
4990  *  Flags: Some flags, as usual
4991  *  Color: Clear color for the render target
4992  *  Z: Clear value for the Z buffer
4993  *  Stencil: Clear value to store in each stencil buffer entry
4994  *
4995  * Returns:
4996  *  D3D_OK on success
4997  *  For details, see IWineD3DDevice::Clear
4998  *
4999  *****************************************************************************/
5000 static HRESULT
5001 IDirect3DDeviceImpl_7_Clear(IDirect3DDevice7 *iface,
5002                             DWORD Count,
5003                             D3DRECT *Rects,
5004                             DWORD Flags,
5005                             D3DCOLOR Color,
5006                             D3DVALUE Z,
5007                             DWORD Stencil)
5008 {
5009     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5010     HRESULT hr;
5011
5012     TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5013             iface, Count, Rects, Flags, Color, Z, Stencil);
5014
5015     EnterCriticalSection(&ddraw_cs);
5016     hr = wined3d_device_clear(This->wined3d_device, Count, (RECT *)Rects, Flags, Color, Z, Stencil);
5017     LeaveCriticalSection(&ddraw_cs);
5018     return hr;
5019 }
5020
5021 static HRESULT WINAPI
5022 IDirect3DDeviceImpl_7_Clear_FPUSetup(IDirect3DDevice7 *iface,
5023                             DWORD Count,
5024                             D3DRECT *Rects,
5025                             DWORD Flags,
5026                             D3DCOLOR Color,
5027                             D3DVALUE Z,
5028                             DWORD Stencil)
5029 {
5030     return IDirect3DDeviceImpl_7_Clear(iface, Count, Rects, Flags, Color, Z, Stencil);
5031 }
5032
5033 static HRESULT WINAPI
5034 IDirect3DDeviceImpl_7_Clear_FPUPreserve(IDirect3DDevice7 *iface,
5035                             DWORD Count,
5036                             D3DRECT *Rects,
5037                             DWORD Flags,
5038                             D3DCOLOR Color,
5039                             D3DVALUE Z,
5040                             DWORD Stencil)
5041 {
5042     HRESULT hr;
5043     WORD old_fpucw;
5044
5045     old_fpucw = d3d_fpu_setup();
5046     hr = IDirect3DDeviceImpl_7_Clear(iface, Count, Rects, Flags, Color, Z, Stencil);
5047     set_fpu_control_word(old_fpucw);
5048
5049     return hr;
5050 }
5051
5052 /*****************************************************************************
5053  * IDirect3DDevice7::SetViewport
5054  *
5055  * Sets the current viewport.
5056  *
5057  * Version 7 only, but IDirect3DViewport uses this call for older
5058  * versions
5059  *
5060  * Params:
5061  *  Data: The new viewport to set
5062  *
5063  * Returns:
5064  *  D3D_OK on success
5065  *  DDERR_INVALIDPARAMS if Data is NULL
5066  *  For more details, see IWineDDDevice::SetViewport
5067  *
5068  *****************************************************************************/
5069 static HRESULT
5070 IDirect3DDeviceImpl_7_SetViewport(IDirect3DDevice7 *iface,
5071                                   D3DVIEWPORT7 *Data)
5072 {
5073     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5074     HRESULT hr;
5075
5076     TRACE("iface %p, viewport %p.\n", iface, Data);
5077
5078     if(!Data)
5079         return DDERR_INVALIDPARAMS;
5080
5081     /* Note: D3DVIEWPORT7 is compatible with WINED3DVIEWPORT */
5082     EnterCriticalSection(&ddraw_cs);
5083     hr = wined3d_device_set_viewport(This->wined3d_device, (WINED3DVIEWPORT *)Data);
5084     LeaveCriticalSection(&ddraw_cs);
5085     return hr;
5086 }
5087
5088 static HRESULT WINAPI
5089 IDirect3DDeviceImpl_7_SetViewport_FPUSetup(IDirect3DDevice7 *iface,
5090                                   D3DVIEWPORT7 *Data)
5091 {
5092     return IDirect3DDeviceImpl_7_SetViewport(iface, Data);
5093 }
5094
5095 static HRESULT WINAPI
5096 IDirect3DDeviceImpl_7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface,
5097                                   D3DVIEWPORT7 *Data)
5098 {
5099     HRESULT hr;
5100     WORD old_fpucw;
5101
5102     old_fpucw = d3d_fpu_setup();
5103     hr = IDirect3DDeviceImpl_7_SetViewport(iface, Data);
5104     set_fpu_control_word(old_fpucw);
5105
5106     return hr;
5107 }
5108
5109 /*****************************************************************************
5110  * IDirect3DDevice::GetViewport
5111  *
5112  * Returns the current viewport
5113  *
5114  * Version 7
5115  *
5116  * Params:
5117  *  Data: D3D7Viewport structure to write the viewport information to
5118  *
5119  * Returns:
5120  *  D3D_OK on success
5121  *  DDERR_INVALIDPARAMS if Data is NULL
5122  *  For more details, see IWineD3DDevice::GetViewport
5123  *
5124  *****************************************************************************/
5125 static HRESULT
5126 IDirect3DDeviceImpl_7_GetViewport(IDirect3DDevice7 *iface,
5127                                   D3DVIEWPORT7 *Data)
5128 {
5129     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5130     HRESULT hr;
5131
5132     TRACE("iface %p, viewport %p.\n", iface, Data);
5133
5134     if(!Data)
5135         return DDERR_INVALIDPARAMS;
5136
5137     /* Note: D3DVIEWPORT7 is compatible with WINED3DVIEWPORT */
5138     EnterCriticalSection(&ddraw_cs);
5139     hr = wined3d_device_get_viewport(This->wined3d_device, (WINED3DVIEWPORT *)Data);
5140
5141     LeaveCriticalSection(&ddraw_cs);
5142     return hr_ddraw_from_wined3d(hr);
5143 }
5144
5145 static HRESULT WINAPI
5146 IDirect3DDeviceImpl_7_GetViewport_FPUSetup(IDirect3DDevice7 *iface,
5147                                   D3DVIEWPORT7 *Data)
5148 {
5149     return IDirect3DDeviceImpl_7_GetViewport(iface, Data);
5150 }
5151
5152 static HRESULT WINAPI
5153 IDirect3DDeviceImpl_7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface,
5154                                   D3DVIEWPORT7 *Data)
5155 {
5156     HRESULT hr;
5157     WORD old_fpucw;
5158
5159     old_fpucw = d3d_fpu_setup();
5160     hr = IDirect3DDeviceImpl_7_GetViewport(iface, Data);
5161     set_fpu_control_word(old_fpucw);
5162
5163     return hr;
5164 }
5165
5166 /*****************************************************************************
5167  * IDirect3DDevice7::SetMaterial
5168  *
5169  * Sets the Material
5170  *
5171  * Version 7
5172  *
5173  * Params:
5174  *  Mat: The material to set
5175  *
5176  * Returns:
5177  *  D3D_OK on success
5178  *  DDERR_INVALIDPARAMS if Mat is NULL.
5179  *  For more details, see IWineD3DDevice::SetMaterial
5180  *
5181  *****************************************************************************/
5182 static HRESULT
5183 IDirect3DDeviceImpl_7_SetMaterial(IDirect3DDevice7 *iface,
5184                                   D3DMATERIAL7 *Mat)
5185 {
5186     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5187     HRESULT hr;
5188
5189     TRACE("iface %p, material %p.\n", iface, Mat);
5190
5191     if (!Mat) return DDERR_INVALIDPARAMS;
5192     /* Note: D3DMATERIAL7 is compatible with WINED3DMATERIAL */
5193     EnterCriticalSection(&ddraw_cs);
5194     hr = wined3d_device_set_material(This->wined3d_device, (WINED3DMATERIAL *)Mat);
5195     LeaveCriticalSection(&ddraw_cs);
5196     return hr_ddraw_from_wined3d(hr);
5197 }
5198
5199 static HRESULT WINAPI
5200 IDirect3DDeviceImpl_7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface,
5201                                   D3DMATERIAL7 *Mat)
5202 {
5203     return IDirect3DDeviceImpl_7_SetMaterial(iface, Mat);
5204 }
5205
5206 static HRESULT WINAPI
5207 IDirect3DDeviceImpl_7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface,
5208                                   D3DMATERIAL7 *Mat)
5209 {
5210     HRESULT hr;
5211     WORD old_fpucw;
5212
5213     old_fpucw = d3d_fpu_setup();
5214     hr = IDirect3DDeviceImpl_7_SetMaterial(iface, Mat);
5215     set_fpu_control_word(old_fpucw);
5216
5217     return hr;
5218 }
5219
5220 /*****************************************************************************
5221  * IDirect3DDevice7::GetMaterial
5222  *
5223  * Returns the current material
5224  *
5225  * Version 7
5226  *
5227  * Params:
5228  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5229  *
5230  * Returns:
5231  *  D3D_OK on success
5232  *  DDERR_INVALIDPARAMS if Mat is NULL
5233  *  For more details, see IWineD3DDevice::GetMaterial
5234  *
5235  *****************************************************************************/
5236 static HRESULT
5237 IDirect3DDeviceImpl_7_GetMaterial(IDirect3DDevice7 *iface,
5238                                   D3DMATERIAL7 *Mat)
5239 {
5240     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5241     HRESULT hr;
5242
5243     TRACE("iface %p, material %p.\n", iface, Mat);
5244
5245     EnterCriticalSection(&ddraw_cs);
5246     /* Note: D3DMATERIAL7 is compatible with WINED3DMATERIAL */
5247     hr = wined3d_device_get_material(This->wined3d_device, (WINED3DMATERIAL *)Mat);
5248     LeaveCriticalSection(&ddraw_cs);
5249     return hr_ddraw_from_wined3d(hr);
5250 }
5251
5252 static HRESULT WINAPI
5253 IDirect3DDeviceImpl_7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface,
5254                                   D3DMATERIAL7 *Mat)
5255 {
5256     return IDirect3DDeviceImpl_7_GetMaterial(iface, Mat);
5257 }
5258
5259 static HRESULT WINAPI
5260 IDirect3DDeviceImpl_7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface,
5261                                   D3DMATERIAL7 *Mat)
5262 {
5263     HRESULT hr;
5264     WORD old_fpucw;
5265
5266     old_fpucw = d3d_fpu_setup();
5267     hr = IDirect3DDeviceImpl_7_GetMaterial(iface, Mat);
5268     set_fpu_control_word(old_fpucw);
5269
5270     return hr;
5271 }
5272
5273 /*****************************************************************************
5274  * IDirect3DDevice7::SetLight
5275  *
5276  * Assigns a light to a light index, but doesn't activate it yet.
5277  *
5278  * Version 7, IDirect3DLight uses this method for older versions
5279  *
5280  * Params:
5281  *  LightIndex: The index of the new light
5282  *  Light: A D3DLIGHT7 structure describing the light
5283  *
5284  * Returns:
5285  *  D3D_OK on success
5286  *  For more details, see IWineD3DDevice::SetLight
5287  *
5288  *****************************************************************************/
5289 static HRESULT
5290 IDirect3DDeviceImpl_7_SetLight(IDirect3DDevice7 *iface,
5291                                DWORD LightIndex,
5292                                D3DLIGHT7 *Light)
5293 {
5294     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5295     HRESULT hr;
5296
5297     TRACE("iface %p, light_idx %u, light %p.\n", iface, LightIndex, Light);
5298
5299     EnterCriticalSection(&ddraw_cs);
5300     /* Note: D3DLIGHT7 is compatible with WINED3DLIGHT */
5301     hr = wined3d_device_set_light(This->wined3d_device, LightIndex, (WINED3DLIGHT *)Light);
5302     LeaveCriticalSection(&ddraw_cs);
5303     return hr_ddraw_from_wined3d(hr);
5304 }
5305
5306 static HRESULT WINAPI
5307 IDirect3DDeviceImpl_7_SetLight_FPUSetup(IDirect3DDevice7 *iface,
5308                                DWORD LightIndex,
5309                                D3DLIGHT7 *Light)
5310 {
5311     return IDirect3DDeviceImpl_7_SetLight(iface, LightIndex, Light);
5312 }
5313
5314 static HRESULT WINAPI
5315 IDirect3DDeviceImpl_7_SetLight_FPUPreserve(IDirect3DDevice7 *iface,
5316                                DWORD LightIndex,
5317                                D3DLIGHT7 *Light)
5318 {
5319     HRESULT hr;
5320     WORD old_fpucw;
5321
5322     old_fpucw = d3d_fpu_setup();
5323     hr = IDirect3DDeviceImpl_7_SetLight(iface, LightIndex, Light);
5324     set_fpu_control_word(old_fpucw);
5325
5326     return hr;
5327 }
5328
5329 /*****************************************************************************
5330  * IDirect3DDevice7::GetLight
5331  *
5332  * Returns the light assigned to a light index
5333  *
5334  * Params:
5335  *  Light: Structure to write the light information to
5336  *
5337  * Returns:
5338  *  D3D_OK on success
5339  *  DDERR_INVALIDPARAMS if Light is NULL
5340  *  For details, see IWineD3DDevice::GetLight
5341  *
5342  *****************************************************************************/
5343 static HRESULT
5344 IDirect3DDeviceImpl_7_GetLight(IDirect3DDevice7 *iface,
5345                                DWORD LightIndex,
5346                                D3DLIGHT7 *Light)
5347 {
5348     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5349     HRESULT rc;
5350
5351     TRACE("iface %p, light_idx %u, light %p.\n", iface, LightIndex, Light);
5352
5353     EnterCriticalSection(&ddraw_cs);
5354     /* Note: D3DLIGHT7 is compatible with WINED3DLIGHT */
5355     rc =  wined3d_device_get_light(This->wined3d_device, LightIndex, (WINED3DLIGHT *)Light);
5356
5357     /* Translate the result. WineD3D returns other values than D3D7 */
5358     LeaveCriticalSection(&ddraw_cs);
5359     return hr_ddraw_from_wined3d(rc);
5360 }
5361
5362 static HRESULT WINAPI
5363 IDirect3DDeviceImpl_7_GetLight_FPUSetup(IDirect3DDevice7 *iface,
5364                                DWORD LightIndex,
5365                                D3DLIGHT7 *Light)
5366 {
5367     return IDirect3DDeviceImpl_7_GetLight(iface, LightIndex, Light);
5368 }
5369
5370 static HRESULT WINAPI
5371 IDirect3DDeviceImpl_7_GetLight_FPUPreserve(IDirect3DDevice7 *iface,
5372                                DWORD LightIndex,
5373                                D3DLIGHT7 *Light)
5374 {
5375     HRESULT hr;
5376     WORD old_fpucw;
5377
5378     old_fpucw = d3d_fpu_setup();
5379     hr = IDirect3DDeviceImpl_7_GetLight(iface, LightIndex, Light);
5380     set_fpu_control_word(old_fpucw);
5381
5382     return hr;
5383 }
5384
5385 /*****************************************************************************
5386  * IDirect3DDevice7::BeginStateBlock
5387  *
5388  * Begins recording to a stateblock
5389  *
5390  * Version 7
5391  *
5392  * Returns:
5393  *  D3D_OK on success
5394  *  For details see IWineD3DDevice::BeginStateBlock
5395  *
5396  *****************************************************************************/
5397 static HRESULT
5398 IDirect3DDeviceImpl_7_BeginStateBlock(IDirect3DDevice7 *iface)
5399 {
5400     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5401     HRESULT hr;
5402
5403     TRACE("iface %p.\n", iface);
5404
5405     EnterCriticalSection(&ddraw_cs);
5406     hr = wined3d_device_begin_stateblock(This->wined3d_device);
5407     LeaveCriticalSection(&ddraw_cs);
5408     return hr_ddraw_from_wined3d(hr);
5409 }
5410
5411 static HRESULT WINAPI
5412 IDirect3DDeviceImpl_7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5413 {
5414     return IDirect3DDeviceImpl_7_BeginStateBlock(iface);
5415 }
5416
5417 static HRESULT WINAPI
5418 IDirect3DDeviceImpl_7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5419 {
5420     HRESULT hr;
5421     WORD old_fpucw;
5422
5423     old_fpucw = d3d_fpu_setup();
5424     hr = IDirect3DDeviceImpl_7_BeginStateBlock(iface);
5425     set_fpu_control_word(old_fpucw);
5426
5427     return hr;
5428 }
5429
5430 /*****************************************************************************
5431  * IDirect3DDevice7::EndStateBlock
5432  *
5433  * Stops recording to a state block and returns the created stateblock
5434  * handle.
5435  *
5436  * Version 7
5437  *
5438  * Params:
5439  *  BlockHandle: Address to store the stateblock's handle to
5440  *
5441  * Returns:
5442  *  D3D_OK on success
5443  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5444  *  See IWineD3DDevice::EndStateBlock for more details
5445  *
5446  *****************************************************************************/
5447 static HRESULT
5448 IDirect3DDeviceImpl_7_EndStateBlock(IDirect3DDevice7 *iface,
5449                                     DWORD *BlockHandle)
5450 {
5451     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5452     struct wined3d_stateblock *wined3d_sb;
5453     HRESULT hr;
5454     DWORD h;
5455
5456     TRACE("iface %p, stateblock %p.\n", iface, BlockHandle);
5457
5458     if(!BlockHandle)
5459     {
5460         WARN("BlockHandle == NULL, returning DDERR_INVALIDPARAMS\n");
5461         return DDERR_INVALIDPARAMS;
5462     }
5463
5464     EnterCriticalSection(&ddraw_cs);
5465
5466     hr = wined3d_device_end_stateblock(This->wined3d_device, &wined3d_sb);
5467     if (FAILED(hr))
5468     {
5469         WARN("Failed to end stateblock, hr %#x.\n", hr);
5470         LeaveCriticalSection(&ddraw_cs);
5471         *BlockHandle = 0;
5472         return hr_ddraw_from_wined3d(hr);
5473     }
5474
5475     h = ddraw_allocate_handle(&This->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5476     if (h == DDRAW_INVALID_HANDLE)
5477     {
5478         ERR("Failed to allocate a stateblock handle.\n");
5479         wined3d_stateblock_decref(wined3d_sb);
5480         LeaveCriticalSection(&ddraw_cs);
5481         *BlockHandle = 0;
5482         return DDERR_OUTOFMEMORY;
5483     }
5484
5485     LeaveCriticalSection(&ddraw_cs);
5486     *BlockHandle = h + 1;
5487
5488     return hr_ddraw_from_wined3d(hr);
5489 }
5490
5491 static HRESULT WINAPI
5492 IDirect3DDeviceImpl_7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5493                                     DWORD *BlockHandle)
5494 {
5495     return IDirect3DDeviceImpl_7_EndStateBlock(iface, BlockHandle);
5496 }
5497
5498 static HRESULT WINAPI
5499 IDirect3DDeviceImpl_7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5500                                     DWORD *BlockHandle)
5501 {
5502     HRESULT hr;
5503     WORD old_fpucw;
5504
5505     old_fpucw = d3d_fpu_setup();
5506     hr = IDirect3DDeviceImpl_7_EndStateBlock(iface, BlockHandle);
5507     set_fpu_control_word(old_fpucw);
5508
5509     return hr;
5510 }
5511
5512 /*****************************************************************************
5513  * IDirect3DDevice7::PreLoad
5514  *
5515  * Allows the app to signal that a texture will be used soon, to allow
5516  * the Direct3DDevice to load it to the video card in the meantime.
5517  *
5518  * Version 7
5519  *
5520  * Params:
5521  *  Texture: The texture to preload
5522  *
5523  * Returns:
5524  *  D3D_OK on success
5525  *  DDERR_INVALIDPARAMS if Texture is NULL
5526  *  See IWineD3DSurface::PreLoad for details
5527  *
5528  *****************************************************************************/
5529 static HRESULT
5530 IDirect3DDeviceImpl_7_PreLoad(IDirect3DDevice7 *iface,
5531                               IDirectDrawSurface7 *Texture)
5532 {
5533     IDirectDrawSurfaceImpl *surf = unsafe_impl_from_IDirectDrawSurface7(Texture);
5534
5535     TRACE("iface %p, texture %p.\n", iface, Texture);
5536
5537     if(!Texture)
5538         return DDERR_INVALIDPARAMS;
5539
5540     EnterCriticalSection(&ddraw_cs);
5541     wined3d_surface_preload(surf->wined3d_surface);
5542     LeaveCriticalSection(&ddraw_cs);
5543     return D3D_OK;
5544 }
5545
5546 static HRESULT WINAPI
5547 IDirect3DDeviceImpl_7_PreLoad_FPUSetup(IDirect3DDevice7 *iface,
5548                               IDirectDrawSurface7 *Texture)
5549 {
5550     return IDirect3DDeviceImpl_7_PreLoad(iface, Texture);
5551 }
5552
5553 static HRESULT WINAPI
5554 IDirect3DDeviceImpl_7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface,
5555                               IDirectDrawSurface7 *Texture)
5556 {
5557     HRESULT hr;
5558     WORD old_fpucw;
5559
5560     old_fpucw = d3d_fpu_setup();
5561     hr = IDirect3DDeviceImpl_7_PreLoad(iface, Texture);
5562     set_fpu_control_word(old_fpucw);
5563
5564     return hr;
5565 }
5566
5567 /*****************************************************************************
5568  * IDirect3DDevice7::ApplyStateBlock
5569  *
5570  * Activates the state stored in a state block handle.
5571  *
5572  * Params:
5573  *  BlockHandle: The stateblock handle to activate
5574  *
5575  * Returns:
5576  *  D3D_OK on success
5577  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5578  *
5579  *****************************************************************************/
5580 static HRESULT
5581 IDirect3DDeviceImpl_7_ApplyStateBlock(IDirect3DDevice7 *iface,
5582                                       DWORD BlockHandle)
5583 {
5584     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5585     struct wined3d_stateblock *wined3d_sb;
5586     HRESULT hr;
5587
5588     TRACE("iface %p, stateblock %#x.\n", iface, BlockHandle);
5589
5590     EnterCriticalSection(&ddraw_cs);
5591
5592     wined3d_sb = ddraw_get_object(&This->handle_table, BlockHandle - 1, DDRAW_HANDLE_STATEBLOCK);
5593     if (!wined3d_sb)
5594     {
5595         WARN("Invalid stateblock handle.\n");
5596         LeaveCriticalSection(&ddraw_cs);
5597         return D3DERR_INVALIDSTATEBLOCK;
5598     }
5599
5600     hr = wined3d_stateblock_apply(wined3d_sb);
5601     LeaveCriticalSection(&ddraw_cs);
5602
5603     return hr_ddraw_from_wined3d(hr);
5604 }
5605
5606 static HRESULT WINAPI
5607 IDirect3DDeviceImpl_7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5608                                       DWORD BlockHandle)
5609 {
5610     return IDirect3DDeviceImpl_7_ApplyStateBlock(iface, BlockHandle);
5611 }
5612
5613 static HRESULT WINAPI
5614 IDirect3DDeviceImpl_7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5615                                       DWORD BlockHandle)
5616 {
5617     HRESULT hr;
5618     WORD old_fpucw;
5619
5620     old_fpucw = d3d_fpu_setup();
5621     hr = IDirect3DDeviceImpl_7_ApplyStateBlock(iface, BlockHandle);
5622     set_fpu_control_word(old_fpucw);
5623
5624     return hr;
5625 }
5626
5627 /*****************************************************************************
5628  * IDirect3DDevice7::CaptureStateBlock
5629  *
5630  * Updates a stateblock's values to the values currently set for the device
5631  *
5632  * Version 7
5633  *
5634  * Params:
5635  *  BlockHandle: Stateblock to update
5636  *
5637  * Returns:
5638  *  D3D_OK on success
5639  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5640  *  See IWineD3DDevice::CaptureStateBlock for more details
5641  *
5642  *****************************************************************************/
5643 static HRESULT
5644 IDirect3DDeviceImpl_7_CaptureStateBlock(IDirect3DDevice7 *iface,
5645                                         DWORD BlockHandle)
5646 {
5647     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5648     struct wined3d_stateblock *wined3d_sb;
5649     HRESULT hr;
5650
5651     TRACE("iface %p, stateblock %#x.\n", iface, BlockHandle);
5652
5653     EnterCriticalSection(&ddraw_cs);
5654
5655     wined3d_sb = ddraw_get_object(&This->handle_table, BlockHandle - 1, DDRAW_HANDLE_STATEBLOCK);
5656     if (!wined3d_sb)
5657     {
5658         WARN("Invalid stateblock handle.\n");
5659         LeaveCriticalSection(&ddraw_cs);
5660         return D3DERR_INVALIDSTATEBLOCK;
5661     }
5662
5663     hr = wined3d_stateblock_capture(wined3d_sb);
5664     LeaveCriticalSection(&ddraw_cs);
5665     return hr_ddraw_from_wined3d(hr);
5666 }
5667
5668 static HRESULT WINAPI
5669 IDirect3DDeviceImpl_7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5670                                         DWORD BlockHandle)
5671 {
5672     return IDirect3DDeviceImpl_7_CaptureStateBlock(iface, BlockHandle);
5673 }
5674
5675 static HRESULT WINAPI
5676 IDirect3DDeviceImpl_7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5677                                         DWORD BlockHandle)
5678 {
5679     HRESULT hr;
5680     WORD old_fpucw;
5681
5682     old_fpucw = d3d_fpu_setup();
5683     hr = IDirect3DDeviceImpl_7_CaptureStateBlock(iface, BlockHandle);
5684     set_fpu_control_word(old_fpucw);
5685
5686     return hr;
5687 }
5688
5689 /*****************************************************************************
5690  * IDirect3DDevice7::DeleteStateBlock
5691  *
5692  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5693  *
5694  * Version 7
5695  *
5696  * Params:
5697  *  BlockHandle: Stateblock handle to delete
5698  *
5699  * Returns:
5700  *  D3D_OK on success
5701  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5702  *
5703  *****************************************************************************/
5704 static HRESULT
5705 IDirect3DDeviceImpl_7_DeleteStateBlock(IDirect3DDevice7 *iface,
5706                                        DWORD BlockHandle)
5707 {
5708     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5709     struct wined3d_stateblock *wined3d_sb;
5710     ULONG ref;
5711
5712     TRACE("iface %p, stateblock %#x.\n", iface, BlockHandle);
5713
5714     EnterCriticalSection(&ddraw_cs);
5715
5716     wined3d_sb = ddraw_free_handle(&This->handle_table, BlockHandle - 1, DDRAW_HANDLE_STATEBLOCK);
5717     if (!wined3d_sb)
5718     {
5719         WARN("Invalid stateblock handle.\n");
5720         LeaveCriticalSection(&ddraw_cs);
5721         return D3DERR_INVALIDSTATEBLOCK;
5722     }
5723
5724     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5725     {
5726         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5727     }
5728
5729     LeaveCriticalSection(&ddraw_cs);
5730     return D3D_OK;
5731 }
5732
5733 static HRESULT WINAPI
5734 IDirect3DDeviceImpl_7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5735                                        DWORD BlockHandle)
5736 {
5737     return IDirect3DDeviceImpl_7_DeleteStateBlock(iface, BlockHandle);
5738 }
5739
5740 static HRESULT WINAPI
5741 IDirect3DDeviceImpl_7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5742                                        DWORD BlockHandle)
5743 {
5744     HRESULT hr;
5745     WORD old_fpucw;
5746
5747     old_fpucw = d3d_fpu_setup();
5748     hr = IDirect3DDeviceImpl_7_DeleteStateBlock(iface, BlockHandle);
5749     set_fpu_control_word(old_fpucw);
5750
5751     return hr;
5752 }
5753
5754 /*****************************************************************************
5755  * IDirect3DDevice7::CreateStateBlock
5756  *
5757  * Creates a new state block handle.
5758  *
5759  * Version 7
5760  *
5761  * Params:
5762  *  Type: The state block type
5763  *  BlockHandle: Address to write the created handle to
5764  *
5765  * Returns:
5766  *   D3D_OK on success
5767  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5768  *
5769  *****************************************************************************/
5770 static HRESULT
5771 IDirect3DDeviceImpl_7_CreateStateBlock(IDirect3DDevice7 *iface,
5772                                        D3DSTATEBLOCKTYPE Type,
5773                                        DWORD *BlockHandle)
5774 {
5775     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
5776     struct wined3d_stateblock *wined3d_sb;
5777     HRESULT hr;
5778     DWORD h;
5779
5780     TRACE("iface %p, type %#x, stateblock %p.\n", iface, Type, BlockHandle);
5781
5782     if(!BlockHandle)
5783     {
5784         WARN("BlockHandle == NULL, returning DDERR_INVALIDPARAMS\n");
5785         return DDERR_INVALIDPARAMS;
5786     }
5787     if(Type != D3DSBT_ALL         && Type != D3DSBT_PIXELSTATE &&
5788        Type != D3DSBT_VERTEXSTATE                              ) {
5789         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5790         return DDERR_INVALIDPARAMS;
5791     }
5792
5793     EnterCriticalSection(&ddraw_cs);
5794
5795     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5796     hr = wined3d_stateblock_create(This->wined3d_device, Type, &wined3d_sb);
5797     if (FAILED(hr))
5798     {
5799         WARN("Failed to create stateblock, hr %#x.\n", hr);
5800         LeaveCriticalSection(&ddraw_cs);
5801         return hr_ddraw_from_wined3d(hr);
5802     }
5803
5804     h = ddraw_allocate_handle(&This->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5805     if (h == DDRAW_INVALID_HANDLE)
5806     {
5807         ERR("Failed to allocate stateblock handle.\n");
5808         wined3d_stateblock_decref(wined3d_sb);
5809         LeaveCriticalSection(&ddraw_cs);
5810         return DDERR_OUTOFMEMORY;
5811     }
5812
5813     *BlockHandle = h + 1;
5814     LeaveCriticalSection(&ddraw_cs);
5815
5816     return hr_ddraw_from_wined3d(hr);
5817 }
5818
5819 static HRESULT WINAPI
5820 IDirect3DDeviceImpl_7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5821                                        D3DSTATEBLOCKTYPE Type,
5822                                        DWORD *BlockHandle)
5823 {
5824     return IDirect3DDeviceImpl_7_CreateStateBlock(iface, Type, BlockHandle);
5825 }
5826
5827 static HRESULT WINAPI
5828 IDirect3DDeviceImpl_7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5829                                        D3DSTATEBLOCKTYPE Type,
5830                                        DWORD *BlockHandle)
5831 {
5832     HRESULT hr;
5833     WORD old_fpucw;
5834
5835     old_fpucw = d3d_fpu_setup();
5836     hr =IDirect3DDeviceImpl_7_CreateStateBlock(iface, Type, BlockHandle);
5837     set_fpu_control_word(old_fpucw);
5838
5839     return hr;
5840 }
5841
5842 /* Helper function for IDirect3DDeviceImpl_7_Load. */
5843 static BOOL is_mip_level_subset(IDirectDrawSurfaceImpl *dest,
5844                                 IDirectDrawSurfaceImpl *src)
5845 {
5846     IDirectDrawSurfaceImpl *src_level, *dest_level;
5847     IDirectDrawSurface7 *temp;
5848     DDSURFACEDESC2 ddsd;
5849     BOOL levelFound; /* at least one suitable sublevel in dest found */
5850
5851     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5852      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5853      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5854      */
5855     levelFound = FALSE;
5856
5857     src_level = src;
5858     dest_level = dest;
5859
5860     for (;src_level && dest_level;)
5861     {
5862         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5863             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5864         {
5865             levelFound = TRUE;
5866
5867             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5868             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5869             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5870
5871             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5872
5873             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5874         }
5875
5876         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5877         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5878         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5879
5880         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5881
5882         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5883     }
5884
5885     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5886     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5887
5888     return !dest_level && levelFound;
5889 }
5890
5891 /* Helper function for IDirect3DDeviceImpl_7_Load. */
5892 static void copy_mipmap_chain(IDirect3DDeviceImpl *device,
5893                               IDirectDrawSurfaceImpl *dest,
5894                               IDirectDrawSurfaceImpl *src,
5895                               const POINT *DestPoint,
5896                               const RECT *SrcRect)
5897 {
5898     IDirectDrawSurfaceImpl *src_level, *dest_level;
5899     IDirectDrawSurface7 *temp;
5900     DDSURFACEDESC2 ddsd;
5901     POINT point;
5902     RECT rect;
5903     HRESULT hr;
5904     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
5905     DWORD ckeyflag;
5906     DDCOLORKEY ddckey;
5907     BOOL palette_missing = FALSE;
5908
5909     /* Copy palette, if possible. */
5910     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
5911     IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
5912
5913     if (pal_src != NULL && pal != NULL)
5914     {
5915         PALETTEENTRY palent[256];
5916
5917         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
5918         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
5919     }
5920
5921     if (dest->surface_desc.u4.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
5922             DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8) && !pal)
5923     {
5924         palette_missing = TRUE;
5925     }
5926
5927     if (pal) IDirectDrawPalette_Release(pal);
5928     if (pal_src) IDirectDrawPalette_Release(pal_src);
5929
5930     /* Copy colorkeys, if present. */
5931     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
5932     {
5933         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5934
5935         if (SUCCEEDED(hr))
5936         {
5937             IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5938         }
5939     }
5940
5941     src_level = src;
5942     dest_level = dest;
5943
5944     point = *DestPoint;
5945     rect = *SrcRect;
5946
5947     for (;src_level && dest_level;)
5948     {
5949         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5950             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5951         {
5952             /* Try UpdateSurface that may perform a more direct OpenGL
5953              * loading. But skip this if destination is paletted texture and
5954              * has no palette. Some games like Sacrifice set palette after
5955              * Load, and it is a waste of effort to try to load texture
5956              * without palette and generates warnings in wined3d. */
5957             if (!palette_missing)
5958                 hr = wined3d_device_update_surface(device->wined3d_device, src_level->wined3d_surface,
5959                         &rect, dest_level->wined3d_surface, &point);
5960
5961             if (palette_missing || FAILED(hr))
5962             {
5963                 /* UpdateSurface may fail e.g. if dest is in system memory. Fall back to BltFast that is less strict. */
5964                 wined3d_surface_bltfast(dest_level->wined3d_surface, point.x, point.y,
5965                         src_level->wined3d_surface, &rect, 0);
5966             }
5967
5968             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5969             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5970             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5971
5972             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5973
5974             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5975         }
5976
5977         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5978         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5979         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5980
5981         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5982
5983         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5984
5985         point.x /= 2;
5986         point.y /= 2;
5987
5988         rect.top /= 2;
5989         rect.left /= 2;
5990         rect.right = (rect.right + 1) / 2;
5991         rect.bottom = (rect.bottom + 1) / 2;
5992     }
5993
5994     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5995     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5996 }
5997
5998 /*****************************************************************************
5999  * IDirect3DDevice7::Load
6000  *
6001  * Loads a rectangular area from the source into the destination texture.
6002  * It can also copy the source to the faces of a cubic environment map
6003  *
6004  * Version 7
6005  *
6006  * Params:
6007  *  DestTex: Destination texture
6008  *  DestPoint: Point in the destination where the source image should be
6009  *             written to
6010  *  SrcTex: Source texture
6011  *  SrcRect: Source rectangle
6012  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6013  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6014  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6015  *
6016  * Returns:
6017  *  D3D_OK on success
6018  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
6019  *
6020  *
6021  *****************************************************************************/
6022
6023 static HRESULT
6024 IDirect3DDeviceImpl_7_Load(IDirect3DDevice7 *iface,
6025                            IDirectDrawSurface7 *DestTex,
6026                            POINT *DestPoint,
6027                            IDirectDrawSurface7 *SrcTex,
6028                            RECT *SrcRect,
6029                            DWORD Flags)
6030 {
6031     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6032     IDirectDrawSurfaceImpl *dest = unsafe_impl_from_IDirectDrawSurface7(DestTex);
6033     IDirectDrawSurfaceImpl *src = unsafe_impl_from_IDirectDrawSurface7(SrcTex);
6034     POINT destpoint;
6035     RECT srcrect;
6036
6037     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
6038             iface, DestTex, wine_dbgstr_point(DestPoint), SrcTex, wine_dbgstr_rect(SrcRect), Flags);
6039
6040     if( (!src) || (!dest) )
6041         return DDERR_INVALIDPARAMS;
6042
6043     EnterCriticalSection(&ddraw_cs);
6044
6045     if (SrcRect) srcrect = *SrcRect;
6046     else
6047     {
6048         srcrect.left = srcrect.top = 0;
6049         srcrect.right = src->surface_desc.dwWidth;
6050         srcrect.bottom = src->surface_desc.dwHeight;
6051     }
6052
6053     if (DestPoint) destpoint = *DestPoint;
6054     else
6055     {
6056         destpoint.x = destpoint.y = 0;
6057     }
6058     /* Check bad dimensions. DestPoint is validated against src, not dest, because
6059      * destination can be a subset of mip levels, in which case actual coordinates used
6060      * for it may be divided. If any dimension of dest is larger than source, it can't be
6061      * mip level subset, so an error can be returned early.
6062      */
6063     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
6064         srcrect.right > src->surface_desc.dwWidth ||
6065         srcrect.bottom > src->surface_desc.dwHeight ||
6066         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6067         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6068         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6069         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6070     {
6071         LeaveCriticalSection(&ddraw_cs);
6072         return DDERR_INVALIDPARAMS;
6073     }
6074
6075     /* Must be top level surfaces. */
6076     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6077         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6078     {
6079         LeaveCriticalSection(&ddraw_cs);
6080         return DDERR_INVALIDPARAMS;
6081     }
6082
6083     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6084     {
6085         DWORD src_face_flag, dest_face_flag;
6086         IDirectDrawSurfaceImpl *src_face, *dest_face;
6087         IDirectDrawSurface7 *temp;
6088         DDSURFACEDESC2 ddsd;
6089         int i;
6090
6091         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6092         {
6093             LeaveCriticalSection(&ddraw_cs);
6094             return DDERR_INVALIDPARAMS;
6095         }
6096
6097         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6098          * time it's actual surface loading. */
6099         for (i = 0; i < 2; i++)
6100         {
6101             dest_face = dest;
6102             src_face = src;
6103
6104             for (;dest_face && src_face;)
6105             {
6106                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6107                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6108
6109                 if (src_face_flag == dest_face_flag)
6110                 {
6111                     if (i == 0)
6112                     {
6113                         /* Destination mip levels must be subset of source mip levels. */
6114                         if (!is_mip_level_subset(dest_face, src_face))
6115                         {
6116                             LeaveCriticalSection(&ddraw_cs);
6117                             return DDERR_INVALIDPARAMS;
6118                         }
6119                     }
6120                     else if (Flags & dest_face_flag)
6121                     {
6122                         copy_mipmap_chain(This, dest_face, src_face, &destpoint, &srcrect);
6123                     }
6124
6125                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6126                     {
6127                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6128                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6129                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6130
6131                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6132
6133                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6134                     }
6135                     else
6136                     {
6137                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6138
6139                         src_face = NULL;
6140                     }
6141                 }
6142
6143                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6144                 {
6145                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6146                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6147                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6148
6149                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6150
6151                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6152                 }
6153                 else
6154                 {
6155                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6156
6157                     dest_face = NULL;
6158                 }
6159             }
6160
6161             if (i == 0)
6162             {
6163                 /* Native returns error if src faces are not subset of dest faces. */
6164                 if (src_face)
6165                 {
6166                     LeaveCriticalSection(&ddraw_cs);
6167                     return DDERR_INVALIDPARAMS;
6168                 }
6169             }
6170         }
6171
6172         LeaveCriticalSection(&ddraw_cs);
6173         return D3D_OK;
6174     }
6175     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6176     {
6177         LeaveCriticalSection(&ddraw_cs);
6178         return DDERR_INVALIDPARAMS;
6179     }
6180
6181     /* Handle non cube map textures. */
6182
6183     /* Destination mip levels must be subset of source mip levels. */
6184     if (!is_mip_level_subset(dest, src))
6185     {
6186         LeaveCriticalSection(&ddraw_cs);
6187         return DDERR_INVALIDPARAMS;
6188     }
6189
6190     copy_mipmap_chain(This, dest, src, &destpoint, &srcrect);
6191
6192     LeaveCriticalSection(&ddraw_cs);
6193     return D3D_OK;
6194 }
6195
6196 static HRESULT WINAPI
6197 IDirect3DDeviceImpl_7_Load_FPUSetup(IDirect3DDevice7 *iface,
6198                            IDirectDrawSurface7 *DestTex,
6199                            POINT *DestPoint,
6200                            IDirectDrawSurface7 *SrcTex,
6201                            RECT *SrcRect,
6202                            DWORD Flags)
6203 {
6204     return IDirect3DDeviceImpl_7_Load(iface, DestTex, DestPoint, SrcTex, SrcRect, Flags);
6205 }
6206
6207 static HRESULT WINAPI
6208 IDirect3DDeviceImpl_7_Load_FPUPreserve(IDirect3DDevice7 *iface,
6209                            IDirectDrawSurface7 *DestTex,
6210                            POINT *DestPoint,
6211                            IDirectDrawSurface7 *SrcTex,
6212                            RECT *SrcRect,
6213                            DWORD Flags)
6214 {
6215     HRESULT hr;
6216     WORD old_fpucw;
6217
6218     old_fpucw = d3d_fpu_setup();
6219     hr = IDirect3DDeviceImpl_7_Load(iface, DestTex, DestPoint, SrcTex, SrcRect, Flags);
6220     set_fpu_control_word(old_fpucw);
6221
6222     return hr;
6223 }
6224
6225 /*****************************************************************************
6226  * IDirect3DDevice7::LightEnable
6227  *
6228  * Enables or disables a light
6229  *
6230  * Version 7, IDirect3DLight uses this method too.
6231  *
6232  * Params:
6233  *  LightIndex: The index of the light to enable / disable
6234  *  Enable: Enable or disable the light
6235  *
6236  * Returns:
6237  *  D3D_OK on success
6238  *  For more details, see IWineD3DDevice::SetLightEnable
6239  *
6240  *****************************************************************************/
6241 static HRESULT
6242 IDirect3DDeviceImpl_7_LightEnable(IDirect3DDevice7 *iface,
6243                                   DWORD LightIndex,
6244                                   BOOL Enable)
6245 {
6246     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6247     HRESULT hr;
6248
6249     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, LightIndex, Enable);
6250
6251     EnterCriticalSection(&ddraw_cs);
6252     hr = wined3d_device_set_light_enable(This->wined3d_device, LightIndex, Enable);
6253     LeaveCriticalSection(&ddraw_cs);
6254     return hr_ddraw_from_wined3d(hr);
6255 }
6256
6257 static HRESULT WINAPI
6258 IDirect3DDeviceImpl_7_LightEnable_FPUSetup(IDirect3DDevice7 *iface,
6259                                   DWORD LightIndex,
6260                                   BOOL Enable)
6261 {
6262     return IDirect3DDeviceImpl_7_LightEnable(iface, LightIndex, Enable);
6263 }
6264
6265 static HRESULT WINAPI
6266 IDirect3DDeviceImpl_7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface,
6267                                   DWORD LightIndex,
6268                                   BOOL Enable)
6269 {
6270     HRESULT hr;
6271     WORD old_fpucw;
6272
6273     old_fpucw = d3d_fpu_setup();
6274     hr = IDirect3DDeviceImpl_7_LightEnable(iface, LightIndex, Enable);
6275     set_fpu_control_word(old_fpucw);
6276
6277     return hr;
6278 }
6279
6280 /*****************************************************************************
6281  * IDirect3DDevice7::GetLightEnable
6282  *
6283  * Retrieves if the light with the given index is enabled or not
6284  *
6285  * Version 7
6286  *
6287  * Params:
6288  *  LightIndex: Index of desired light
6289  *  Enable: Pointer to a BOOL which contains the result
6290  *
6291  * Returns:
6292  *  D3D_OK on success
6293  *  DDERR_INVALIDPARAMS if Enable is NULL
6294  *  See IWineD3DDevice::GetLightEnable for more details
6295  *
6296  *****************************************************************************/
6297 static HRESULT
6298 IDirect3DDeviceImpl_7_GetLightEnable(IDirect3DDevice7 *iface,
6299                                      DWORD LightIndex,
6300                                      BOOL* Enable)
6301 {
6302     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6303     HRESULT hr;
6304
6305     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, LightIndex, Enable);
6306
6307     if(!Enable)
6308         return DDERR_INVALIDPARAMS;
6309
6310     EnterCriticalSection(&ddraw_cs);
6311     hr = wined3d_device_get_light_enable(This->wined3d_device, LightIndex, Enable);
6312     LeaveCriticalSection(&ddraw_cs);
6313     return hr_ddraw_from_wined3d(hr);
6314 }
6315
6316 static HRESULT WINAPI
6317 IDirect3DDeviceImpl_7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface,
6318                                      DWORD LightIndex,
6319                                      BOOL* Enable)
6320 {
6321     return IDirect3DDeviceImpl_7_GetLightEnable(iface, LightIndex, Enable);
6322 }
6323
6324 static HRESULT WINAPI
6325 IDirect3DDeviceImpl_7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface,
6326                                      DWORD LightIndex,
6327                                      BOOL* Enable)
6328 {
6329     HRESULT hr;
6330     WORD old_fpucw;
6331
6332     old_fpucw = d3d_fpu_setup();
6333     hr = IDirect3DDeviceImpl_7_GetLightEnable(iface, LightIndex, Enable);
6334     set_fpu_control_word(old_fpucw);
6335
6336     return hr;
6337 }
6338
6339 /*****************************************************************************
6340  * IDirect3DDevice7::SetClipPlane
6341  *
6342  * Sets custom clipping plane
6343  *
6344  * Version 7
6345  *
6346  * Params:
6347  *  Index: The index of the clipping plane
6348  *  PlaneEquation: An equation defining the clipping plane
6349  *
6350  * Returns:
6351  *  D3D_OK on success
6352  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6353  *  See IWineD3DDevice::SetClipPlane for more details
6354  *
6355  *****************************************************************************/
6356 static HRESULT
6357 IDirect3DDeviceImpl_7_SetClipPlane(IDirect3DDevice7 *iface,
6358                                    DWORD Index,
6359                                    D3DVALUE* PlaneEquation)
6360 {
6361     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6362     HRESULT hr;
6363
6364     TRACE("iface %p, idx %u, plane %p.\n", iface, Index, PlaneEquation);
6365
6366     if(!PlaneEquation)
6367         return DDERR_INVALIDPARAMS;
6368
6369     EnterCriticalSection(&ddraw_cs);
6370     hr = wined3d_device_set_clip_plane(This->wined3d_device, Index, PlaneEquation);
6371     LeaveCriticalSection(&ddraw_cs);
6372     return hr;
6373 }
6374
6375 static HRESULT WINAPI
6376 IDirect3DDeviceImpl_7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface,
6377                                    DWORD Index,
6378                                    D3DVALUE* PlaneEquation)
6379 {
6380     return IDirect3DDeviceImpl_7_SetClipPlane(iface, Index, PlaneEquation);
6381 }
6382
6383 static HRESULT WINAPI
6384 IDirect3DDeviceImpl_7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface,
6385                                    DWORD Index,
6386                                    D3DVALUE* PlaneEquation)
6387 {
6388     HRESULT hr;
6389     WORD old_fpucw;
6390
6391     old_fpucw = d3d_fpu_setup();
6392     hr = IDirect3DDeviceImpl_7_SetClipPlane(iface, Index, PlaneEquation);
6393     set_fpu_control_word(old_fpucw);
6394
6395     return hr;
6396 }
6397
6398 /*****************************************************************************
6399  * IDirect3DDevice7::GetClipPlane
6400  *
6401  * Returns the clipping plane with a specific index
6402  *
6403  * Params:
6404  *  Index: The index of the desired plane
6405  *  PlaneEquation: Address to store the plane equation to
6406  *
6407  * Returns:
6408  *  D3D_OK on success
6409  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6410  *  See IWineD3DDevice::GetClipPlane for more details
6411  *
6412  *****************************************************************************/
6413 static HRESULT
6414 IDirect3DDeviceImpl_7_GetClipPlane(IDirect3DDevice7 *iface,
6415                                    DWORD Index,
6416                                    D3DVALUE* PlaneEquation)
6417 {
6418     IDirect3DDeviceImpl *This = (IDirect3DDeviceImpl *)iface;
6419     HRESULT hr;
6420
6421     TRACE("iface %p, idx %u, plane %p.\n", iface, Index, PlaneEquation);
6422
6423     if(!PlaneEquation)
6424         return DDERR_INVALIDPARAMS;
6425
6426     EnterCriticalSection(&ddraw_cs);
6427     hr = wined3d_device_get_clip_plane(This->wined3d_device, Index, PlaneEquation);
6428     LeaveCriticalSection(&ddraw_cs);
6429     return hr;
6430 }
6431
6432 static HRESULT WINAPI
6433 IDirect3DDeviceImpl_7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface,
6434                                    DWORD Index,
6435                                    D3DVALUE* PlaneEquation)
6436 {
6437     return IDirect3DDeviceImpl_7_GetClipPlane(iface, Index, PlaneEquation);
6438 }
6439
6440 static HRESULT WINAPI
6441 IDirect3DDeviceImpl_7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface,
6442                                    DWORD Index,
6443                                    D3DVALUE* PlaneEquation)
6444 {
6445     HRESULT hr;
6446     WORD old_fpucw;
6447
6448     old_fpucw = d3d_fpu_setup();
6449     hr = IDirect3DDeviceImpl_7_GetClipPlane(iface, Index, PlaneEquation);
6450     set_fpu_control_word(old_fpucw);
6451
6452     return hr;
6453 }
6454
6455 /*****************************************************************************
6456  * IDirect3DDevice7::GetInfo
6457  *
6458  * Retrieves some information about the device. The DirectX sdk says that
6459  * this version returns S_FALSE for all retail builds of DirectX, that's what
6460  * this implementation does.
6461  *
6462  * Params:
6463  *  DevInfoID: Information type requested
6464  *  DevInfoStruct: Pointer to a structure to store the info to
6465  *  Size: Size of the structure
6466  *
6467  * Returns:
6468  *  S_FALSE, because it's a non-debug driver
6469  *
6470  *****************************************************************************/
6471 static HRESULT WINAPI
6472 IDirect3DDeviceImpl_7_GetInfo(IDirect3DDevice7 *iface,
6473                               DWORD DevInfoID,
6474                               void *DevInfoStruct,
6475                               DWORD Size)
6476 {
6477     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6478             iface, DevInfoID, DevInfoStruct, Size);
6479
6480     if (TRACE_ON(ddraw))
6481     {
6482         TRACE(" info requested : ");
6483         switch (DevInfoID)
6484         {
6485             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6486             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6487             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6488             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6489         }
6490     }
6491
6492     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6493 }
6494
6495 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6496  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6497  * are not duplicated.
6498
6499  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6500  * has already been setup for optimal d3d operation.
6501
6502  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6503  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6504  * by Sacrifice (game). */
6505 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6506 {
6507     /*** IUnknown Methods ***/
6508     IDirect3DDeviceImpl_7_QueryInterface,
6509     IDirect3DDeviceImpl_7_AddRef,
6510     IDirect3DDeviceImpl_7_Release,
6511     /*** IDirect3DDevice7 ***/
6512     IDirect3DDeviceImpl_7_GetCaps_FPUSetup,
6513     IDirect3DDeviceImpl_7_EnumTextureFormats_FPUSetup,
6514     IDirect3DDeviceImpl_7_BeginScene_FPUSetup,
6515     IDirect3DDeviceImpl_7_EndScene_FPUSetup,
6516     IDirect3DDeviceImpl_7_GetDirect3D,
6517     IDirect3DDeviceImpl_7_SetRenderTarget_FPUSetup,
6518     IDirect3DDeviceImpl_7_GetRenderTarget,
6519     IDirect3DDeviceImpl_7_Clear_FPUSetup,
6520     IDirect3DDeviceImpl_7_SetTransform_FPUSetup,
6521     IDirect3DDeviceImpl_7_GetTransform_FPUSetup,
6522     IDirect3DDeviceImpl_7_SetViewport_FPUSetup,
6523     IDirect3DDeviceImpl_7_MultiplyTransform_FPUSetup,
6524     IDirect3DDeviceImpl_7_GetViewport_FPUSetup,
6525     IDirect3DDeviceImpl_7_SetMaterial_FPUSetup,
6526     IDirect3DDeviceImpl_7_GetMaterial_FPUSetup,
6527     IDirect3DDeviceImpl_7_SetLight_FPUSetup,
6528     IDirect3DDeviceImpl_7_GetLight_FPUSetup,
6529     IDirect3DDeviceImpl_7_SetRenderState_FPUSetup,
6530     IDirect3DDeviceImpl_7_GetRenderState_FPUSetup,
6531     IDirect3DDeviceImpl_7_BeginStateBlock_FPUSetup,
6532     IDirect3DDeviceImpl_7_EndStateBlock_FPUSetup,
6533     IDirect3DDeviceImpl_7_PreLoad_FPUSetup,
6534     IDirect3DDeviceImpl_7_DrawPrimitive_FPUSetup,
6535     IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUSetup,
6536     IDirect3DDeviceImpl_7_SetClipStatus,
6537     IDirect3DDeviceImpl_7_GetClipStatus,
6538     IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUSetup,
6539     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUSetup,
6540     IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUSetup,
6541     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUSetup,
6542     IDirect3DDeviceImpl_7_ComputeSphereVisibility,
6543     IDirect3DDeviceImpl_7_GetTexture_FPUSetup,
6544     IDirect3DDeviceImpl_7_SetTexture_FPUSetup,
6545     IDirect3DDeviceImpl_7_GetTextureStageState_FPUSetup,
6546     IDirect3DDeviceImpl_7_SetTextureStageState_FPUSetup,
6547     IDirect3DDeviceImpl_7_ValidateDevice_FPUSetup,
6548     IDirect3DDeviceImpl_7_ApplyStateBlock_FPUSetup,
6549     IDirect3DDeviceImpl_7_CaptureStateBlock_FPUSetup,
6550     IDirect3DDeviceImpl_7_DeleteStateBlock_FPUSetup,
6551     IDirect3DDeviceImpl_7_CreateStateBlock_FPUSetup,
6552     IDirect3DDeviceImpl_7_Load_FPUSetup,
6553     IDirect3DDeviceImpl_7_LightEnable_FPUSetup,
6554     IDirect3DDeviceImpl_7_GetLightEnable_FPUSetup,
6555     IDirect3DDeviceImpl_7_SetClipPlane_FPUSetup,
6556     IDirect3DDeviceImpl_7_GetClipPlane_FPUSetup,
6557     IDirect3DDeviceImpl_7_GetInfo
6558 };
6559
6560 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6561 {
6562     /*** IUnknown Methods ***/
6563     IDirect3DDeviceImpl_7_QueryInterface,
6564     IDirect3DDeviceImpl_7_AddRef,
6565     IDirect3DDeviceImpl_7_Release,
6566     /*** IDirect3DDevice7 ***/
6567     IDirect3DDeviceImpl_7_GetCaps_FPUPreserve,
6568     IDirect3DDeviceImpl_7_EnumTextureFormats_FPUPreserve,
6569     IDirect3DDeviceImpl_7_BeginScene_FPUPreserve,
6570     IDirect3DDeviceImpl_7_EndScene_FPUPreserve,
6571     IDirect3DDeviceImpl_7_GetDirect3D,
6572     IDirect3DDeviceImpl_7_SetRenderTarget_FPUPreserve,
6573     IDirect3DDeviceImpl_7_GetRenderTarget,
6574     IDirect3DDeviceImpl_7_Clear_FPUPreserve,
6575     IDirect3DDeviceImpl_7_SetTransform_FPUPreserve,
6576     IDirect3DDeviceImpl_7_GetTransform_FPUPreserve,
6577     IDirect3DDeviceImpl_7_SetViewport_FPUPreserve,
6578     IDirect3DDeviceImpl_7_MultiplyTransform_FPUPreserve,
6579     IDirect3DDeviceImpl_7_GetViewport_FPUPreserve,
6580     IDirect3DDeviceImpl_7_SetMaterial_FPUPreserve,
6581     IDirect3DDeviceImpl_7_GetMaterial_FPUPreserve,
6582     IDirect3DDeviceImpl_7_SetLight_FPUPreserve,
6583     IDirect3DDeviceImpl_7_GetLight_FPUPreserve,
6584     IDirect3DDeviceImpl_7_SetRenderState_FPUPreserve,
6585     IDirect3DDeviceImpl_7_GetRenderState_FPUPreserve,
6586     IDirect3DDeviceImpl_7_BeginStateBlock_FPUPreserve,
6587     IDirect3DDeviceImpl_7_EndStateBlock_FPUPreserve,
6588     IDirect3DDeviceImpl_7_PreLoad_FPUPreserve,
6589     IDirect3DDeviceImpl_7_DrawPrimitive_FPUPreserve,
6590     IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUPreserve,
6591     IDirect3DDeviceImpl_7_SetClipStatus,
6592     IDirect3DDeviceImpl_7_GetClipStatus,
6593     IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUPreserve,
6594     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUPreserve,
6595     IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUPreserve,
6596     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUPreserve,
6597     IDirect3DDeviceImpl_7_ComputeSphereVisibility,
6598     IDirect3DDeviceImpl_7_GetTexture_FPUPreserve,
6599     IDirect3DDeviceImpl_7_SetTexture_FPUPreserve,
6600     IDirect3DDeviceImpl_7_GetTextureStageState_FPUPreserve,
6601     IDirect3DDeviceImpl_7_SetTextureStageState_FPUPreserve,
6602     IDirect3DDeviceImpl_7_ValidateDevice_FPUPreserve,
6603     IDirect3DDeviceImpl_7_ApplyStateBlock_FPUPreserve,
6604     IDirect3DDeviceImpl_7_CaptureStateBlock_FPUPreserve,
6605     IDirect3DDeviceImpl_7_DeleteStateBlock_FPUPreserve,
6606     IDirect3DDeviceImpl_7_CreateStateBlock_FPUPreserve,
6607     IDirect3DDeviceImpl_7_Load_FPUPreserve,
6608     IDirect3DDeviceImpl_7_LightEnable_FPUPreserve,
6609     IDirect3DDeviceImpl_7_GetLightEnable_FPUPreserve,
6610     IDirect3DDeviceImpl_7_SetClipPlane_FPUPreserve,
6611     IDirect3DDeviceImpl_7_GetClipPlane_FPUPreserve,
6612     IDirect3DDeviceImpl_7_GetInfo
6613 };
6614
6615 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6616 {
6617     /*** IUnknown Methods ***/
6618     IDirect3DDeviceImpl_3_QueryInterface,
6619     IDirect3DDeviceImpl_3_AddRef,
6620     IDirect3DDeviceImpl_3_Release,
6621     /*** IDirect3DDevice3 ***/
6622     IDirect3DDeviceImpl_3_GetCaps,
6623     IDirect3DDeviceImpl_3_GetStats,
6624     IDirect3DDeviceImpl_3_AddViewport,
6625     IDirect3DDeviceImpl_3_DeleteViewport,
6626     IDirect3DDeviceImpl_3_NextViewport,
6627     IDirect3DDeviceImpl_3_EnumTextureFormats,
6628     IDirect3DDeviceImpl_3_BeginScene,
6629     IDirect3DDeviceImpl_3_EndScene,
6630     IDirect3DDeviceImpl_3_GetDirect3D,
6631     IDirect3DDeviceImpl_3_SetCurrentViewport,
6632     IDirect3DDeviceImpl_3_GetCurrentViewport,
6633     IDirect3DDeviceImpl_3_SetRenderTarget,
6634     IDirect3DDeviceImpl_3_GetRenderTarget,
6635     IDirect3DDeviceImpl_3_Begin,
6636     IDirect3DDeviceImpl_3_BeginIndexed,
6637     IDirect3DDeviceImpl_3_Vertex,
6638     IDirect3DDeviceImpl_3_Index,
6639     IDirect3DDeviceImpl_3_End,
6640     IDirect3DDeviceImpl_3_GetRenderState,
6641     IDirect3DDeviceImpl_3_SetRenderState,
6642     IDirect3DDeviceImpl_3_GetLightState,
6643     IDirect3DDeviceImpl_3_SetLightState,
6644     IDirect3DDeviceImpl_3_SetTransform,
6645     IDirect3DDeviceImpl_3_GetTransform,
6646     IDirect3DDeviceImpl_3_MultiplyTransform,
6647     IDirect3DDeviceImpl_3_DrawPrimitive,
6648     IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
6649     IDirect3DDeviceImpl_3_SetClipStatus,
6650     IDirect3DDeviceImpl_3_GetClipStatus,
6651     IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
6652     IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
6653     IDirect3DDeviceImpl_3_DrawPrimitiveVB,
6654     IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
6655     IDirect3DDeviceImpl_3_ComputeSphereVisibility,
6656     IDirect3DDeviceImpl_3_GetTexture,
6657     IDirect3DDeviceImpl_3_SetTexture,
6658     IDirect3DDeviceImpl_3_GetTextureStageState,
6659     IDirect3DDeviceImpl_3_SetTextureStageState,
6660     IDirect3DDeviceImpl_3_ValidateDevice
6661 };
6662
6663 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6664 {
6665     /*** IUnknown Methods ***/
6666     IDirect3DDeviceImpl_2_QueryInterface,
6667     IDirect3DDeviceImpl_2_AddRef,
6668     IDirect3DDeviceImpl_2_Release,
6669     /*** IDirect3DDevice2 ***/
6670     IDirect3DDeviceImpl_2_GetCaps,
6671     IDirect3DDeviceImpl_2_SwapTextureHandles,
6672     IDirect3DDeviceImpl_2_GetStats,
6673     IDirect3DDeviceImpl_2_AddViewport,
6674     IDirect3DDeviceImpl_2_DeleteViewport,
6675     IDirect3DDeviceImpl_2_NextViewport,
6676     IDirect3DDeviceImpl_2_EnumTextureFormats,
6677     IDirect3DDeviceImpl_2_BeginScene,
6678     IDirect3DDeviceImpl_2_EndScene,
6679     IDirect3DDeviceImpl_2_GetDirect3D,
6680     IDirect3DDeviceImpl_2_SetCurrentViewport,
6681     IDirect3DDeviceImpl_2_GetCurrentViewport,
6682     IDirect3DDeviceImpl_2_SetRenderTarget,
6683     IDirect3DDeviceImpl_2_GetRenderTarget,
6684     IDirect3DDeviceImpl_2_Begin,
6685     IDirect3DDeviceImpl_2_BeginIndexed,
6686     IDirect3DDeviceImpl_2_Vertex,
6687     IDirect3DDeviceImpl_2_Index,
6688     IDirect3DDeviceImpl_2_End,
6689     IDirect3DDeviceImpl_2_GetRenderState,
6690     IDirect3DDeviceImpl_2_SetRenderState,
6691     IDirect3DDeviceImpl_2_GetLightState,
6692     IDirect3DDeviceImpl_2_SetLightState,
6693     IDirect3DDeviceImpl_2_SetTransform,
6694     IDirect3DDeviceImpl_2_GetTransform,
6695     IDirect3DDeviceImpl_2_MultiplyTransform,
6696     IDirect3DDeviceImpl_2_DrawPrimitive,
6697     IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
6698     IDirect3DDeviceImpl_2_SetClipStatus,
6699     IDirect3DDeviceImpl_2_GetClipStatus
6700 };
6701
6702 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6703 {
6704     /*** IUnknown Methods ***/
6705     IDirect3DDeviceImpl_1_QueryInterface,
6706     IDirect3DDeviceImpl_1_AddRef,
6707     IDirect3DDeviceImpl_1_Release,
6708     /*** IDirect3DDevice1 ***/
6709     IDirect3DDeviceImpl_1_Initialize,
6710     IDirect3DDeviceImpl_1_GetCaps,
6711     IDirect3DDeviceImpl_1_SwapTextureHandles,
6712     IDirect3DDeviceImpl_1_CreateExecuteBuffer,
6713     IDirect3DDeviceImpl_1_GetStats,
6714     IDirect3DDeviceImpl_1_Execute,
6715     IDirect3DDeviceImpl_1_AddViewport,
6716     IDirect3DDeviceImpl_1_DeleteViewport,
6717     IDirect3DDeviceImpl_1_NextViewport,
6718     IDirect3DDeviceImpl_1_Pick,
6719     IDirect3DDeviceImpl_1_GetPickRecords,
6720     IDirect3DDeviceImpl_1_EnumTextureFormats,
6721     IDirect3DDeviceImpl_1_CreateMatrix,
6722     IDirect3DDeviceImpl_1_SetMatrix,
6723     IDirect3DDeviceImpl_1_GetMatrix,
6724     IDirect3DDeviceImpl_1_DeleteMatrix,
6725     IDirect3DDeviceImpl_1_BeginScene,
6726     IDirect3DDeviceImpl_1_EndScene,
6727     IDirect3DDeviceImpl_1_GetDirect3D
6728 };
6729
6730 /*****************************************************************************
6731  * IDirect3DDeviceImpl_UpdateDepthStencil
6732  *
6733  * Checks the current render target for attached depth stencils and sets the
6734  * WineD3D depth stencil accordingly.
6735  *
6736  * Returns:
6737  *  The depth stencil state to set if creating the device
6738  *
6739  *****************************************************************************/
6740 WINED3DZBUFFERTYPE
6741 IDirect3DDeviceImpl_UpdateDepthStencil(IDirect3DDeviceImpl *This)
6742 {
6743     IDirectDrawSurface7 *depthStencil = NULL;
6744     IDirectDrawSurfaceImpl *dsi;
6745     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6746
6747     IDirectDrawSurface7_GetAttachedSurface(&This->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
6748     if(!depthStencil)
6749     {
6750         TRACE("Setting wined3d depth stencil to NULL\n");
6751         wined3d_device_set_depth_stencil(This->wined3d_device, NULL);
6752         return WINED3DZB_FALSE;
6753     }
6754
6755     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6756     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6757     wined3d_device_set_depth_stencil(This->wined3d_device, dsi->wined3d_surface);
6758
6759     IDirectDrawSurface7_Release(depthStencil);
6760     return WINED3DZB_TRUE;
6761 }
6762
6763 HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *target)
6764 {
6765     HRESULT hr;
6766
6767     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6768         device->lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6769     else
6770         device->lpVtbl = &d3d_device7_fpu_setup_vtbl;
6771
6772     device->IDirect3DDevice3_vtbl = &d3d_device3_vtbl;
6773     device->IDirect3DDevice2_vtbl = &d3d_device2_vtbl;
6774     device->IDirect3DDevice_vtbl = &d3d_device1_vtbl;
6775     device->ref = 1;
6776     device->ddraw = ddraw;
6777     device->target = target;
6778     list_init(&device->viewport_list);
6779
6780     if (!ddraw_handle_table_init(&device->handle_table, 64))
6781     {
6782         ERR("Failed to initialize handle table.\n");
6783         return DDERR_OUTOFMEMORY;
6784     }
6785
6786     device->legacyTextureBlending = FALSE;
6787
6788     /* Create an index buffer, it's needed for indexed drawing */
6789     hr = wined3d_buffer_create_ib(ddraw->wined3d_device, 0x40000 /* Length. Don't know how long it should be */,
6790             WINED3DUSAGE_DYNAMIC /* Usage */, WINED3DPOOL_DEFAULT, NULL,
6791             &ddraw_null_wined3d_parent_ops, &device->indexbuffer);
6792     if (FAILED(hr))
6793     {
6794         ERR("Failed to create an index buffer, hr %#x.\n", hr);
6795         ddraw_handle_table_destroy(&device->handle_table);
6796         return hr;
6797     }
6798
6799     /* This is for convenience. */
6800     device->wined3d_device = ddraw->wined3d_device;
6801     wined3d_device_incref(ddraw->wined3d_device);
6802
6803     /* Render to the back buffer */
6804     hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6805     if (FAILED(hr))
6806     {
6807         ERR("Failed to set render target, hr %#x.\n", hr);
6808         wined3d_buffer_decref(device->indexbuffer);
6809         ddraw_handle_table_destroy(&device->handle_table);
6810         return hr;
6811     }
6812
6813     /* FIXME: This is broken. The target AddRef() makes some sense, because
6814      * we store a pointer during initialization, but then that's also where
6815      * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
6816     /* AddRef the render target. Also AddRef the render target from ddraw,
6817      * because if it is released before the app releases the D3D device, the
6818      * D3D capabilities of wined3d will be uninitialized, which has bad effects.
6819      *
6820      * In most cases, those surfaces are the same anyway, but this will simply
6821      * add another ref which is released when the device is destroyed. */
6822     IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6823     IDirectDrawSurface7_AddRef(&ddraw->d3d_target->IDirectDrawSurface7_iface);
6824
6825     ddraw->d3ddevice = device;
6826
6827     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3DRS_ZENABLE,
6828             IDirect3DDeviceImpl_UpdateDepthStencil(device));
6829
6830     return D3D_OK;
6831 }