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