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