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