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