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