jscript: Use bytecode for '|=' expression.
[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, WINED3DDEVTYPE_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                 WINED3DDEVTYPE_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, WINED3DDEVTYPE_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, WINED3DSAMP_MAGFILTER, &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, WINED3DSAMP_MINFILTER, &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, WINED3DSAMP_MIPFILTER, &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, WINED3DSAMP_ADDRESSU, Value);
2441             break;
2442         case D3DRENDERSTATE_TEXTUREADDRESSV:
2443             hr = wined3d_device_get_sampler_state(This->wined3d_device,
2444                     0, WINED3DSAMP_ADDRESSV, 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, WINED3DRS_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, WINED3DTSS_COLOROP, &colorop);
2547             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_COLORARG1, &colorarg1);
2548             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_COLORARG2, &colorarg2);
2549             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAOP, &alphaop);
2550             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAARG1, &alphaarg1);
2551             wined3d_device_get_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAARG2, &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, WINED3DSAMP_MAGFILTER, 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, WINED3DSAMP_MIPFILTER, tex_mip);
2736             hr = wined3d_device_set_sampler_state(This->wined3d_device,
2737                     0, WINED3DSAMP_MINFILTER, tex_min);
2738             break;
2739         }
2740
2741         case D3DRENDERSTATE_TEXTUREADDRESS:
2742             wined3d_device_set_sampler_state(This->wined3d_device,
2743                     0, WINED3DSAMP_ADDRESSV, Value);
2744             /* Drop through */
2745         case D3DRENDERSTATE_TEXTUREADDRESSU:
2746             hr = wined3d_device_set_sampler_state(This->wined3d_device,
2747                     0, WINED3DSAMP_ADDRESSU, Value);
2748             break;
2749         case D3DRENDERSTATE_TEXTUREADDRESSV:
2750             hr = wined3d_device_set_sampler_state(This->wined3d_device,
2751                     0, WINED3DSAMP_ADDRESSV, 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, WINED3DRS_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, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1);
2901                     else
2902                         wined3d_device_set_texture_stage_state(This->wined3d_device,
2903                                 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
2904                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2905                             0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
2906                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2907                             0, WINED3DTSS_ALPHAARG2, WINED3DTA_CURRENT);
2908                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2909                             0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2910                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2911                             0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2912                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2913                             0, WINED3DTSS_COLOROP, WINED3DTOP_MODULATE);
2914                     break;
2915                 }
2916
2917                 case D3DTBLEND_ADD:
2918                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2919                             0, WINED3DTSS_COLOROP, WINED3DTOP_ADD);
2920                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2921                             0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2922                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2923                             0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2924                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2925                             0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
2926                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2927                             0, WINED3DTSS_ALPHAARG2, WINED3DTA_CURRENT);
2928                     break;
2929
2930                 case D3DTBLEND_MODULATEALPHA:
2931                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2932                             0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2933                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2934                             0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
2935                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2936                             0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2937                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2938                             0, WINED3DTSS_ALPHAARG2, WINED3DTA_CURRENT);
2939                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2940                             0, WINED3DTSS_COLOROP, WINED3DTOP_MODULATE);
2941                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2942                             0, WINED3DTSS_ALPHAOP, 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, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2949                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2950                             0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE);
2951                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2952                             0, WINED3DTSS_COLOROP, WINED3DTOP_SELECTARG1);
2953                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2954                             0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1);
2955                     break;
2956
2957                 case D3DTBLEND_DECALALPHA:
2958                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2959                             0, WINED3DTSS_COLOROP, WINED3DTOP_BLENDTEXTUREALPHA);
2960                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2961                             0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE);
2962                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2963                             0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT);
2964                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2965                             0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
2966                     wined3d_device_set_texture_stage_state(This->wined3d_device,
2967                             0, WINED3DTSS_ALPHAARG2, 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 TransformStateType, D3DMATRIX *D3DMatrix)
3283 {
3284     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3285
3286     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3287
3288     return IDirect3DDevice7_SetTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
3289 }
3290
3291 static HRESULT WINAPI IDirect3DDeviceImpl_2_SetTransform(IDirect3DDevice2 *iface,
3292         D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
3293 {
3294     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3295
3296     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3297
3298     return IDirect3DDevice7_SetTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
3299 }
3300
3301 /*****************************************************************************
3302  * IDirect3DDevice7::GetTransform
3303  *
3304  * Returns the matrix assigned to a transform state
3305  * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3306  * SetTransform
3307  *
3308  * Params:
3309  *  TransformStateType: State to read the matrix from
3310  *  Matrix: Address to store the matrix at
3311  *
3312  * Returns:
3313  *  D3D_OK on success
3314  *  DDERR_INVALIDPARAMS if Matrix == NULL
3315  *  For details, see IWineD3DDevice::GetTransform
3316  *
3317  *****************************************************************************/
3318 static HRESULT
3319 IDirect3DDeviceImpl_7_GetTransform(IDirect3DDevice7 *iface,
3320                                    D3DTRANSFORMSTATETYPE TransformStateType,
3321                                    D3DMATRIX *Matrix)
3322 {
3323     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
3324     D3DTRANSFORMSTATETYPE type;
3325     HRESULT hr;
3326
3327     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, Matrix);
3328
3329     switch(TransformStateType)
3330     {
3331         case D3DTRANSFORMSTATE_WORLD :  type = WINED3DTS_WORLDMATRIX(0); break;
3332         case D3DTRANSFORMSTATE_WORLD1:  type = WINED3DTS_WORLDMATRIX(1); break;
3333         case D3DTRANSFORMSTATE_WORLD2:  type = WINED3DTS_WORLDMATRIX(2); break;
3334         case D3DTRANSFORMSTATE_WORLD3:  type = WINED3DTS_WORLDMATRIX(3); break;
3335         default:                        type = TransformStateType;
3336     }
3337
3338     if(!Matrix)
3339         return DDERR_INVALIDPARAMS;
3340
3341     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3342     wined3d_mutex_lock();
3343     hr = wined3d_device_get_transform(This->wined3d_device, type, (struct wined3d_matrix *)Matrix);
3344     wined3d_mutex_unlock();
3345
3346     return hr;
3347 }
3348
3349 static HRESULT WINAPI
3350 IDirect3DDeviceImpl_7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3351                                    D3DTRANSFORMSTATETYPE TransformStateType,
3352                                    D3DMATRIX *Matrix)
3353 {
3354     return IDirect3DDeviceImpl_7_GetTransform(iface, TransformStateType, Matrix);
3355 }
3356
3357 static HRESULT WINAPI
3358 IDirect3DDeviceImpl_7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3359                                    D3DTRANSFORMSTATETYPE TransformStateType,
3360                                    D3DMATRIX *Matrix)
3361 {
3362     HRESULT hr;
3363     WORD old_fpucw;
3364
3365     old_fpucw = d3d_fpu_setup();
3366     hr = IDirect3DDeviceImpl_7_GetTransform(iface, TransformStateType, Matrix);
3367     set_fpu_control_word(old_fpucw);
3368
3369     return hr;
3370 }
3371
3372 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetTransform(IDirect3DDevice3 *iface,
3373         D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
3374 {
3375     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3376
3377     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3378
3379     return IDirect3DDevice7_GetTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
3380 }
3381
3382 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetTransform(IDirect3DDevice2 *iface,
3383         D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
3384 {
3385     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3386
3387     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3388
3389     return IDirect3DDevice7_GetTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
3390 }
3391
3392 /*****************************************************************************
3393  * IDirect3DDevice7::MultiplyTransform
3394  *
3395  * Multiplies the already-set transform matrix of a transform state
3396  * with another matrix. For the world matrix, see SetTransform
3397  *
3398  * Version 2, 3 and 7
3399  *
3400  * Params:
3401  *  TransformStateType: Transform state to multiply
3402  *  D3DMatrix Matrix to multiply with.
3403  *
3404  * Returns
3405  *  D3D_OK on success
3406  *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
3407  *  For details, see IWineD3DDevice::MultiplyTransform
3408  *
3409  *****************************************************************************/
3410 static HRESULT
3411 IDirect3DDeviceImpl_7_MultiplyTransform(IDirect3DDevice7 *iface,
3412                                         D3DTRANSFORMSTATETYPE TransformStateType,
3413                                         D3DMATRIX *D3DMatrix)
3414 {
3415     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
3416     HRESULT hr;
3417     D3DTRANSFORMSTATETYPE type;
3418
3419     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3420
3421     switch(TransformStateType)
3422     {
3423         case D3DTRANSFORMSTATE_WORLD :  type = WINED3DTS_WORLDMATRIX(0); break;
3424         case D3DTRANSFORMSTATE_WORLD1:  type = WINED3DTS_WORLDMATRIX(1); break;
3425         case D3DTRANSFORMSTATE_WORLD2:  type = WINED3DTS_WORLDMATRIX(2); break;
3426         case D3DTRANSFORMSTATE_WORLD3:  type = WINED3DTS_WORLDMATRIX(3); break;
3427         default:                        type = TransformStateType;
3428     }
3429
3430     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3431     wined3d_mutex_lock();
3432     hr = wined3d_device_multiply_transform(This->wined3d_device,
3433             type, (struct wined3d_matrix *)D3DMatrix);
3434     wined3d_mutex_unlock();
3435
3436     return hr;
3437 }
3438
3439 static HRESULT WINAPI
3440 IDirect3DDeviceImpl_7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3441                                         D3DTRANSFORMSTATETYPE TransformStateType,
3442                                         D3DMATRIX *D3DMatrix)
3443 {
3444     return IDirect3DDeviceImpl_7_MultiplyTransform(iface, TransformStateType, D3DMatrix);
3445 }
3446
3447 static HRESULT WINAPI
3448 IDirect3DDeviceImpl_7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3449                                         D3DTRANSFORMSTATETYPE TransformStateType,
3450                                         D3DMATRIX *D3DMatrix)
3451 {
3452     HRESULT hr;
3453     WORD old_fpucw;
3454
3455     old_fpucw = d3d_fpu_setup();
3456     hr = IDirect3DDeviceImpl_7_MultiplyTransform(iface, TransformStateType, D3DMatrix);
3457     set_fpu_control_word(old_fpucw);
3458
3459     return hr;
3460 }
3461
3462 static HRESULT WINAPI IDirect3DDeviceImpl_3_MultiplyTransform(IDirect3DDevice3 *iface,
3463         D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
3464 {
3465     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3466
3467     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3468
3469     return IDirect3DDevice7_MultiplyTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
3470 }
3471
3472 static HRESULT WINAPI IDirect3DDeviceImpl_2_MultiplyTransform(IDirect3DDevice2 *iface,
3473         D3DTRANSFORMSTATETYPE TransformStateType, D3DMATRIX *D3DMatrix)
3474 {
3475     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3476
3477     TRACE("iface %p, state %#x, matrix %p.\n", iface, TransformStateType, D3DMatrix);
3478
3479     return IDirect3DDevice7_MultiplyTransform(&This->IDirect3DDevice7_iface, TransformStateType, D3DMatrix);
3480 }
3481
3482 /*****************************************************************************
3483  * IDirect3DDevice7::DrawPrimitive
3484  *
3485  * Draws primitives based on vertices in an application-provided pointer
3486  *
3487  * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3488  * an FVF format for D3D7
3489  *
3490  * Params:
3491  *  PrimitiveType: The type of the primitives to draw
3492  *  Vertex type: Flexible vertex format vertex description
3493  *  Vertices: Pointer to the vertex array
3494  *  VertexCount: The number of vertices to draw
3495  *  Flags: As usual a few flags
3496  *
3497  * Returns:
3498  *  D3D_OK on success
3499  *  DDERR_INVALIDPARAMS if Vertices is NULL
3500  *  For details, see IWineD3DDevice::DrawPrimitiveUP
3501  *
3502  *****************************************************************************/
3503 static HRESULT
3504 IDirect3DDeviceImpl_7_DrawPrimitive(IDirect3DDevice7 *iface,
3505                                     D3DPRIMITIVETYPE PrimitiveType,
3506                                     DWORD VertexType,
3507                                     void *Vertices,
3508                                     DWORD VertexCount,
3509                                     DWORD Flags)
3510 {
3511     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
3512     UINT stride;
3513     HRESULT hr;
3514
3515     TRACE("iface %p, primitive_type %#x, FVF %#x, vertices %p, vertex_count %u, flags %#x.\n",
3516             iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3517
3518     if(!Vertices)
3519         return DDERR_INVALIDPARAMS;
3520
3521     /* Get the stride */
3522     stride = get_flexible_vertex_size(VertexType);
3523
3524     /* Set the FVF */
3525     wined3d_mutex_lock();
3526     hr = wined3d_device_set_vertex_declaration(This->wined3d_device, ddraw_find_decl(This->ddraw, VertexType));
3527     if(hr != D3D_OK)
3528     {
3529         wined3d_mutex_unlock();
3530         return hr;
3531     }
3532
3533     /* This method translates to the user pointer draw of WineD3D */
3534     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
3535     hr = wined3d_device_draw_primitive_up(This->wined3d_device, VertexCount, Vertices, stride);
3536     wined3d_mutex_unlock();
3537
3538     return hr;
3539 }
3540
3541 static HRESULT WINAPI
3542 IDirect3DDeviceImpl_7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3543                                     D3DPRIMITIVETYPE PrimitiveType,
3544                                     DWORD VertexType,
3545                                     void *Vertices,
3546                                     DWORD VertexCount,
3547                                     DWORD Flags)
3548 {
3549     return IDirect3DDeviceImpl_7_DrawPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3550 }
3551
3552 static HRESULT WINAPI
3553 IDirect3DDeviceImpl_7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3554                                     D3DPRIMITIVETYPE PrimitiveType,
3555                                     DWORD VertexType,
3556                                     void *Vertices,
3557                                     DWORD VertexCount,
3558                                     DWORD Flags)
3559 {
3560     HRESULT hr;
3561     WORD old_fpucw;
3562
3563     old_fpucw = d3d_fpu_setup();
3564     hr = IDirect3DDeviceImpl_7_DrawPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3565     set_fpu_control_word(old_fpucw);
3566
3567     return hr;
3568 }
3569
3570 static HRESULT WINAPI IDirect3DDeviceImpl_3_DrawPrimitive(IDirect3DDevice3 *iface,
3571         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType, void *Vertices, DWORD VertexCount,
3572         DWORD Flags)
3573 {
3574     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3575     TRACE("iface %p, primitive_type %#x, FVF %#x, vertices %p, vertex_count %u, flags %#x.\n",
3576             iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3577
3578     return IDirect3DDevice7_DrawPrimitive(&This->IDirect3DDevice7_iface,
3579             PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3580 }
3581
3582 static HRESULT WINAPI IDirect3DDeviceImpl_2_DrawPrimitive(IDirect3DDevice2 *iface,
3583         D3DPRIMITIVETYPE PrimitiveType, D3DVERTEXTYPE VertexType, void *Vertices,
3584         DWORD VertexCount, DWORD Flags)
3585 {
3586     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3587     DWORD FVF;
3588
3589     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3590             iface, PrimitiveType, VertexType, Vertices, VertexCount, Flags);
3591
3592     switch(VertexType)
3593     {
3594         case D3DVT_VERTEX: FVF = D3DFVF_VERTEX; break;
3595         case D3DVT_LVERTEX: FVF = D3DFVF_LVERTEX; break;
3596         case D3DVT_TLVERTEX: FVF = D3DFVF_TLVERTEX; break;
3597         default:
3598             ERR("Unexpected vertex type %d\n", VertexType);
3599             return DDERR_INVALIDPARAMS;  /* Should never happen */
3600     }
3601
3602     return IDirect3DDevice7_DrawPrimitive(&This->IDirect3DDevice7_iface,
3603             PrimitiveType, FVF, Vertices, VertexCount, Flags);
3604 }
3605
3606 /*****************************************************************************
3607  * IDirect3DDevice7::DrawIndexedPrimitive
3608  *
3609  * Draws vertices from an application-provided pointer, based on the index
3610  * numbers in a WORD array.
3611  *
3612  * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3613  * an FVF format for D3D7
3614  *
3615  * Params:
3616  *  PrimitiveType: The primitive type to draw
3617  *  VertexType: The FVF vertex description
3618  *  Vertices: Pointer to the vertex array
3619  *  VertexCount: ?
3620  *  Indices: Pointer to the index array
3621  *  IndexCount: Number of indices = Number of vertices to draw
3622  *  Flags: As usual, some flags
3623  *
3624  * Returns:
3625  *  D3D_OK on success
3626  *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3627  *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
3628  *
3629  *****************************************************************************/
3630 static HRESULT
3631 IDirect3DDeviceImpl_7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3632                                            D3DPRIMITIVETYPE PrimitiveType,
3633                                            DWORD VertexType,
3634                                            void *Vertices,
3635                                            DWORD VertexCount,
3636                                            WORD *Indices,
3637                                            DWORD IndexCount,
3638                                            DWORD Flags)
3639 {
3640     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
3641     HRESULT hr;
3642
3643     TRACE("iface %p, primitive_type %#x, FVF %#x, vertices %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3644             iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3645
3646     /* Set the D3DDevice's FVF */
3647     wined3d_mutex_lock();
3648     hr = wined3d_device_set_vertex_declaration(This->wined3d_device, ddraw_find_decl(This->ddraw, VertexType));
3649     if(FAILED(hr))
3650     {
3651         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
3652         wined3d_mutex_unlock();
3653         return hr;
3654     }
3655
3656     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
3657     hr = wined3d_device_draw_indexed_primitive_up(This->wined3d_device, IndexCount, Indices,
3658             WINED3DFMT_R16_UINT, Vertices, get_flexible_vertex_size(VertexType));
3659     wined3d_mutex_unlock();
3660
3661     return hr;
3662 }
3663
3664 static HRESULT WINAPI
3665 IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3666                                            D3DPRIMITIVETYPE PrimitiveType,
3667                                            DWORD VertexType,
3668                                            void *Vertices,
3669                                            DWORD VertexCount,
3670                                            WORD *Indices,
3671                                            DWORD IndexCount,
3672                                            DWORD Flags)
3673 {
3674     return IDirect3DDeviceImpl_7_DrawIndexedPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3675 }
3676
3677 static HRESULT WINAPI
3678 IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUPreserve(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     HRESULT hr;
3688     WORD old_fpucw;
3689
3690     old_fpucw = d3d_fpu_setup();
3691     hr = IDirect3DDeviceImpl_7_DrawIndexedPrimitive(iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3692     set_fpu_control_word(old_fpucw);
3693
3694     return hr;
3695 }
3696
3697 static HRESULT WINAPI IDirect3DDeviceImpl_3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3698         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType, void *Vertices, DWORD VertexCount,
3699         WORD *Indices, DWORD IndexCount, DWORD Flags)
3700 {
3701     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3702     TRACE("iface %p, primitive_type %#x, FVF %#x, vertices %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3703             iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3704
3705     return IDirect3DDevice7_DrawIndexedPrimitive(&This->IDirect3DDevice7_iface,
3706             PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3707 }
3708
3709 static HRESULT WINAPI IDirect3DDeviceImpl_2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3710         D3DPRIMITIVETYPE PrimitiveType, D3DVERTEXTYPE VertexType, void *Vertices,
3711         DWORD VertexCount, WORD *Indices, DWORD IndexCount, DWORD Flags)
3712 {
3713     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3714     DWORD FVF;
3715
3716     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3717             iface, PrimitiveType, VertexType, Vertices, VertexCount, Indices, IndexCount, Flags);
3718
3719     switch(VertexType)
3720     {
3721         case D3DVT_VERTEX: FVF = D3DFVF_VERTEX; break;
3722         case D3DVT_LVERTEX: FVF = D3DFVF_LVERTEX; break;
3723         case D3DVT_TLVERTEX: FVF = D3DFVF_TLVERTEX; break;
3724         default:
3725             ERR("Unexpected vertex type %d\n", VertexType);
3726             return DDERR_INVALIDPARAMS;  /* Should never happen */
3727     }
3728
3729     return IDirect3DDevice7_DrawIndexedPrimitive(&This->IDirect3DDevice7_iface,
3730             PrimitiveType, FVF, Vertices, VertexCount, Indices, IndexCount, Flags);
3731 }
3732
3733 /*****************************************************************************
3734  * IDirect3DDevice7::SetClipStatus
3735  *
3736  * Sets the clip status. This defines things as clipping conditions and
3737  * the extents of the clipping region.
3738  *
3739  * Version 2, 3 and 7
3740  *
3741  * Params:
3742  *  ClipStatus:
3743  *
3744  * Returns:
3745  *  D3D_OK because it's a stub
3746  *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3747  *
3748  *****************************************************************************/
3749 static HRESULT WINAPI
3750 IDirect3DDeviceImpl_7_SetClipStatus(IDirect3DDevice7 *iface,
3751                                     D3DCLIPSTATUS *ClipStatus)
3752 {
3753     FIXME("iface %p, clip_status %p stub!\n", iface, ClipStatus);
3754
3755     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
3756      * Perhaps this needs a new data type and an additional IWineD3DDevice method
3757      */
3758     /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
3759     return D3D_OK;
3760 }
3761
3762 static HRESULT WINAPI IDirect3DDeviceImpl_3_SetClipStatus(IDirect3DDevice3 *iface,
3763         D3DCLIPSTATUS *ClipStatus)
3764 {
3765     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3766     TRACE("iface %p, clip_status %p.\n", iface, ClipStatus);
3767
3768     return IDirect3DDevice7_SetClipStatus(&This->IDirect3DDevice7_iface, ClipStatus);
3769 }
3770
3771 static HRESULT WINAPI IDirect3DDeviceImpl_2_SetClipStatus(IDirect3DDevice2 *iface,
3772         D3DCLIPSTATUS *ClipStatus)
3773 {
3774     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3775     TRACE("iface %p, clip_status %p.\n", iface, ClipStatus);
3776
3777     return IDirect3DDevice7_SetClipStatus(&This->IDirect3DDevice7_iface, ClipStatus);
3778 }
3779
3780 /*****************************************************************************
3781  * IDirect3DDevice7::GetClipStatus
3782  *
3783  * Returns the clip status
3784  *
3785  * Params:
3786  *  ClipStatus: Address to write the clip status to
3787  *
3788  * Returns:
3789  *  D3D_OK because it's a stub
3790  *
3791  *****************************************************************************/
3792 static HRESULT WINAPI
3793 IDirect3DDeviceImpl_7_GetClipStatus(IDirect3DDevice7 *iface,
3794                                     D3DCLIPSTATUS *ClipStatus)
3795 {
3796     FIXME("iface %p, clip_status %p stub!\n", iface, ClipStatus);
3797
3798     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
3799     /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
3800     return D3D_OK;
3801 }
3802
3803 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetClipStatus(IDirect3DDevice3 *iface,
3804         D3DCLIPSTATUS *ClipStatus)
3805 {
3806     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3807     TRACE("iface %p, clip_status %p.\n", iface, ClipStatus);
3808
3809     return IDirect3DDevice7_GetClipStatus(&This->IDirect3DDevice7_iface, ClipStatus);
3810 }
3811
3812 static HRESULT WINAPI IDirect3DDeviceImpl_2_GetClipStatus(IDirect3DDevice2 *iface,
3813         D3DCLIPSTATUS *ClipStatus)
3814 {
3815     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice2(iface);
3816     TRACE("iface %p, clip_status %p.\n", iface, ClipStatus);
3817
3818     return IDirect3DDevice7_GetClipStatus(&This->IDirect3DDevice7_iface, ClipStatus);
3819 }
3820
3821 /*****************************************************************************
3822  * IDirect3DDevice::DrawPrimitiveStrided
3823  *
3824  * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3825  *
3826  * Version 3 and 7
3827  *
3828  * Params:
3829  *  PrimitiveType: The primitive type to draw
3830  *  VertexType: The FVF description of the vertices to draw (for the stride??)
3831  *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3832  *                         the vertex data locations
3833  *  VertexCount: The number of vertices to draw
3834  *  Flags: Some flags
3835  *
3836  * Returns:
3837  *  D3D_OK, because it's a stub
3838  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3839  *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
3840  *
3841  *****************************************************************************/
3842 static HRESULT
3843 IDirect3DDeviceImpl_7_DrawPrimitiveStrided(IDirect3DDevice7 *iface,
3844                                            D3DPRIMITIVETYPE PrimitiveType,
3845                                            DWORD VertexType,
3846                                            D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3847                                            DWORD VertexCount,
3848                                            DWORD Flags)
3849 {
3850     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
3851     WineDirect3DVertexStridedData WineD3DStrided;
3852     DWORD i;
3853     HRESULT hr;
3854
3855     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3856             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3857
3858     memset(&WineD3DStrided, 0, sizeof(WineD3DStrided));
3859     /* Get the strided data right. the wined3d structure is a bit bigger
3860      * Watch out: The contents of the strided data are determined by the fvf,
3861      * not by the members set in D3DDrawPrimStrideData. So it's valid
3862      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3863      * not set in the fvf.
3864      */
3865     if(VertexType & D3DFVF_POSITION_MASK)
3866     {
3867         WineD3DStrided.position.format = WINED3DFMT_R32G32B32_FLOAT;
3868         WineD3DStrided.position.lpData = D3DDrawPrimStrideData->position.lpvData;
3869         WineD3DStrided.position.dwStride = D3DDrawPrimStrideData->position.dwStride;
3870         if (VertexType & D3DFVF_XYZRHW)
3871         {
3872             WineD3DStrided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
3873             WineD3DStrided.position_transformed = TRUE;
3874         } else
3875             WineD3DStrided.position_transformed = FALSE;
3876     }
3877
3878     if(VertexType & D3DFVF_NORMAL)
3879     {
3880         WineD3DStrided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
3881         WineD3DStrided.normal.lpData = D3DDrawPrimStrideData->normal.lpvData;
3882         WineD3DStrided.normal.dwStride = D3DDrawPrimStrideData->normal.dwStride;
3883     }
3884
3885     if(VertexType & D3DFVF_DIFFUSE)
3886     {
3887         WineD3DStrided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
3888         WineD3DStrided.diffuse.lpData = D3DDrawPrimStrideData->diffuse.lpvData;
3889         WineD3DStrided.diffuse.dwStride = D3DDrawPrimStrideData->diffuse.dwStride;
3890     }
3891
3892     if(VertexType & D3DFVF_SPECULAR)
3893     {
3894         WineD3DStrided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
3895         WineD3DStrided.specular.lpData = D3DDrawPrimStrideData->specular.lpvData;
3896         WineD3DStrided.specular.dwStride = D3DDrawPrimStrideData->specular.dwStride;
3897     }
3898
3899     for( i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); i++)
3900     {
3901         switch(GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3902         {
3903             case 1: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32_FLOAT; break;
3904             case 2: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32G32_FLOAT; break;
3905             case 3: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
3906             case 4: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3907             default: ERR("Unexpected texture coordinate size %d\n",
3908                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
3909         }
3910         WineD3DStrided.texCoords[i].lpData = D3DDrawPrimStrideData->textureCoords[i].lpvData;
3911         WineD3DStrided.texCoords[i].dwStride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3912     }
3913
3914     /* WineD3D doesn't need the FVF here */
3915     wined3d_mutex_lock();
3916     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
3917     hr = wined3d_device_draw_primitive_strided(This->wined3d_device, VertexCount, &WineD3DStrided);
3918     wined3d_mutex_unlock();
3919
3920     return hr;
3921 }
3922
3923 static HRESULT WINAPI
3924 IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3925                                            D3DPRIMITIVETYPE PrimitiveType,
3926                                            DWORD VertexType,
3927                                            D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3928                                            DWORD VertexCount,
3929                                            DWORD Flags)
3930 {
3931     return IDirect3DDeviceImpl_7_DrawPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3932 }
3933
3934 static HRESULT WINAPI
3935 IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3936                                            D3DPRIMITIVETYPE PrimitiveType,
3937                                            DWORD VertexType,
3938                                            D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3939                                            DWORD VertexCount,
3940                                            DWORD Flags)
3941 {
3942     HRESULT hr;
3943     WORD old_fpucw;
3944
3945     old_fpucw = d3d_fpu_setup();
3946     hr = IDirect3DDeviceImpl_7_DrawPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3947     set_fpu_control_word(old_fpucw);
3948
3949     return hr;
3950 }
3951
3952 static HRESULT WINAPI IDirect3DDeviceImpl_3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3953         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3954         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3955 {
3956     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
3957
3958     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3959             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3960
3961     return IDirect3DDevice7_DrawPrimitiveStrided(&This->IDirect3DDevice7_iface,
3962             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3963 }
3964
3965 /*****************************************************************************
3966  * IDirect3DDevice7::DrawIndexedPrimitiveStrided
3967  *
3968  * Draws primitives specified by strided data locations based on indices
3969  *
3970  * Version 3 and 7
3971  *
3972  * Params:
3973  *  PrimitiveType:
3974  *
3975  * Returns:
3976  *  D3D_OK, because it's a stub
3977  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3978  *  (DDERR_INVALIDPARAMS if Indices is NULL)
3979  *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
3980  *
3981  *****************************************************************************/
3982 static HRESULT
3983 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
3984                                                   D3DPRIMITIVETYPE PrimitiveType,
3985                                                   DWORD VertexType,
3986                                                   D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
3987                                                   DWORD VertexCount,
3988                                                   WORD *Indices,
3989                                                   DWORD IndexCount,
3990                                                   DWORD Flags)
3991 {
3992     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
3993     WineDirect3DVertexStridedData WineD3DStrided;
3994     DWORD i;
3995     HRESULT hr;
3996
3997     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3998             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3999
4000     memset(&WineD3DStrided, 0, sizeof(WineD3DStrided));
4001     /* Get the strided data right. the wined3d structure is a bit bigger
4002      * Watch out: The contents of the strided data are determined by the fvf,
4003      * not by the members set in D3DDrawPrimStrideData. So it's valid
4004      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
4005      * not set in the fvf.
4006      */
4007     if(VertexType & D3DFVF_POSITION_MASK)
4008     {
4009         WineD3DStrided.position.format = WINED3DFMT_R32G32B32_FLOAT;
4010         WineD3DStrided.position.lpData = D3DDrawPrimStrideData->position.lpvData;
4011         WineD3DStrided.position.dwStride = D3DDrawPrimStrideData->position.dwStride;
4012         if (VertexType & D3DFVF_XYZRHW)
4013         {
4014             WineD3DStrided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
4015             WineD3DStrided.position_transformed = TRUE;
4016         } else
4017             WineD3DStrided.position_transformed = FALSE;
4018     }
4019
4020     if(VertexType & D3DFVF_NORMAL)
4021     {
4022         WineD3DStrided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
4023         WineD3DStrided.normal.lpData = D3DDrawPrimStrideData->normal.lpvData;
4024         WineD3DStrided.normal.dwStride = D3DDrawPrimStrideData->normal.dwStride;
4025     }
4026
4027     if(VertexType & D3DFVF_DIFFUSE)
4028     {
4029         WineD3DStrided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
4030         WineD3DStrided.diffuse.lpData = D3DDrawPrimStrideData->diffuse.lpvData;
4031         WineD3DStrided.diffuse.dwStride = D3DDrawPrimStrideData->diffuse.dwStride;
4032     }
4033
4034     if(VertexType & D3DFVF_SPECULAR)
4035     {
4036         WineD3DStrided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
4037         WineD3DStrided.specular.lpData = D3DDrawPrimStrideData->specular.lpvData;
4038         WineD3DStrided.specular.dwStride = D3DDrawPrimStrideData->specular.dwStride;
4039     }
4040
4041     for( i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); i++)
4042     {
4043         switch(GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
4044         {
4045             case 1: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32_FLOAT; break;
4046             case 2: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32G32_FLOAT; break;
4047             case 3: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
4048             case 4: WineD3DStrided.texCoords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
4049             default: ERR("Unexpected texture coordinate size %d\n",
4050                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
4051         }
4052         WineD3DStrided.texCoords[i].lpData = D3DDrawPrimStrideData->textureCoords[i].lpvData;
4053         WineD3DStrided.texCoords[i].dwStride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
4054     }
4055
4056     /* WineD3D doesn't need the FVF here */
4057     wined3d_mutex_lock();
4058     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4059     hr = wined3d_device_draw_indexed_primitive_strided(This->wined3d_device,
4060             IndexCount, &WineD3DStrided, VertexCount, Indices, WINED3DFMT_R16_UINT);
4061     wined3d_mutex_unlock();
4062
4063     return hr;
4064 }
4065
4066 static HRESULT WINAPI
4067 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4068                                                   D3DPRIMITIVETYPE PrimitiveType,
4069                                                   DWORD VertexType,
4070                                                   D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4071                                                   DWORD VertexCount,
4072                                                   WORD *Indices,
4073                                                   DWORD IndexCount,
4074                                                   DWORD Flags)
4075 {
4076     return IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4077 }
4078
4079 static HRESULT WINAPI
4080 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4081                                                   D3DPRIMITIVETYPE PrimitiveType,
4082                                                   DWORD VertexType,
4083                                                   D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData,
4084                                                   DWORD VertexCount,
4085                                                   WORD *Indices,
4086                                                   DWORD IndexCount,
4087                                                   DWORD Flags)
4088 {
4089     HRESULT hr;
4090     WORD old_fpucw;
4091
4092     old_fpucw = d3d_fpu_setup();
4093     hr = IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4094     set_fpu_control_word(old_fpucw);
4095
4096     return hr;
4097 }
4098
4099 static HRESULT WINAPI IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4100         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4101         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4102         DWORD IndexCount, DWORD Flags)
4103 {
4104     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4105
4106     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4107             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4108
4109     return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&This->IDirect3DDevice7_iface,
4110             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4111 }
4112
4113 /*****************************************************************************
4114  * IDirect3DDevice7::DrawPrimitiveVB
4115  *
4116  * Draws primitives from a vertex buffer to the screen.
4117  *
4118  * Version 3 and 7
4119  *
4120  * Params:
4121  *  PrimitiveType: Type of primitive to be rendered.
4122  *  D3DVertexBuf: Source Vertex Buffer
4123  *  StartVertex: Index of the first vertex from the buffer to be rendered
4124  *  NumVertices: Number of vertices to be rendered
4125  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4126  *
4127  * Return values
4128  *  D3D_OK on success
4129  *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4130  *
4131  *****************************************************************************/
4132 static HRESULT
4133 IDirect3DDeviceImpl_7_DrawPrimitiveVB(IDirect3DDevice7 *iface,
4134                                       D3DPRIMITIVETYPE PrimitiveType,
4135                                       IDirect3DVertexBuffer7 *D3DVertexBuf,
4136                                       DWORD StartVertex,
4137                                       DWORD NumVertices,
4138                                       DWORD Flags)
4139 {
4140     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
4141     IDirect3DVertexBufferImpl *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4142     HRESULT hr;
4143     DWORD stride;
4144
4145     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4146             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4147
4148     /* Sanity checks */
4149     if(!vb)
4150     {
4151         ERR("(%p) No Vertex buffer specified\n", This);
4152         return DDERR_INVALIDPARAMS;
4153     }
4154     stride = get_flexible_vertex_size(vb->fvf);
4155
4156     wined3d_mutex_lock();
4157     hr = wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4158     if (FAILED(hr))
4159     {
4160         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
4161         wined3d_mutex_unlock();
4162         return hr;
4163     }
4164
4165     /* Set the vertex stream source */
4166     hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4167     if(hr != D3D_OK)
4168     {
4169         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4170         wined3d_mutex_unlock();
4171         return hr;
4172     }
4173
4174     /* Now draw the primitives */
4175     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4176     hr = wined3d_device_draw_primitive(This->wined3d_device, StartVertex, NumVertices);
4177     wined3d_mutex_unlock();
4178
4179     return hr;
4180 }
4181
4182 static HRESULT WINAPI
4183 IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4184                                       D3DPRIMITIVETYPE PrimitiveType,
4185                                       IDirect3DVertexBuffer7 *D3DVertexBuf,
4186                                       DWORD StartVertex,
4187                                       DWORD NumVertices,
4188                                       DWORD Flags)
4189 {
4190     return IDirect3DDeviceImpl_7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4191 }
4192
4193 static HRESULT WINAPI
4194 IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4195                                       D3DPRIMITIVETYPE PrimitiveType,
4196                                       IDirect3DVertexBuffer7 *D3DVertexBuf,
4197                                       DWORD StartVertex,
4198                                       DWORD NumVertices,
4199                                       DWORD Flags)
4200 {
4201     HRESULT hr;
4202     WORD old_fpucw;
4203
4204     old_fpucw = d3d_fpu_setup();
4205     hr = IDirect3DDeviceImpl_7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4206     set_fpu_control_word(old_fpucw);
4207
4208     return hr;
4209 }
4210
4211 static HRESULT WINAPI IDirect3DDeviceImpl_3_DrawPrimitiveVB(IDirect3DDevice3 *iface,
4212         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex,
4213         DWORD NumVertices, DWORD Flags)
4214 {
4215     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4216     IDirect3DVertexBufferImpl *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4217
4218     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4219             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4220
4221     return IDirect3DDevice7_DrawPrimitiveVB(&This->IDirect3DDevice7_iface,
4222             PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4223 }
4224
4225
4226 /*****************************************************************************
4227  * IDirect3DDevice7::DrawIndexedPrimitiveVB
4228  *
4229  * Draws primitives from a vertex buffer to the screen
4230  *
4231  * Params:
4232  *  PrimitiveType: Type of primitive to be rendered.
4233  *  D3DVertexBuf: Source Vertex Buffer
4234  *  StartVertex: Index of the first vertex from the buffer to be rendered
4235  *  NumVertices: Number of vertices to be rendered
4236  *  Indices: Array of DWORDs used to index into the Vertices
4237  *  IndexCount: Number of indices in Indices
4238  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4239  *
4240  * Return values
4241  *
4242  *****************************************************************************/
4243 static HRESULT
4244 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4245                                              D3DPRIMITIVETYPE PrimitiveType,
4246                                              IDirect3DVertexBuffer7 *D3DVertexBuf,
4247                                              DWORD StartVertex,
4248                                              DWORD NumVertices,
4249                                              WORD *Indices,
4250                                              DWORD IndexCount,
4251                                              DWORD Flags)
4252 {
4253     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
4254     IDirect3DVertexBufferImpl *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4255     DWORD stride = get_flexible_vertex_size(vb->fvf);
4256     struct wined3d_resource *wined3d_resource;
4257     struct wined3d_resource_desc desc;
4258     WORD *LockedIndices;
4259     HRESULT hr;
4260
4261     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4262             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4263
4264     /* Steps:
4265      * 1) Upload the Indices to the index buffer
4266      * 2) Set the index source
4267      * 3) Set the Vertex Buffer as the Stream source
4268      * 4) Call IWineD3DDevice::DrawIndexedPrimitive
4269      */
4270
4271     wined3d_mutex_lock();
4272
4273     hr = wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4274     if (FAILED(hr))
4275     {
4276         ERR(" (%p) Setting the FVF failed, hr = %x!\n", This, hr);
4277         wined3d_mutex_unlock();
4278         return hr;
4279     }
4280
4281     /* check that the buffer is large enough to hold the indices,
4282      * reallocate if necessary. */
4283     wined3d_resource = wined3d_buffer_get_resource(This->indexbuffer);
4284     wined3d_resource_get_desc(wined3d_resource, &desc);
4285     if (desc.size < IndexCount * sizeof(WORD))
4286     {
4287         UINT size = max(desc.size * 2, IndexCount * sizeof(WORD));
4288         struct wined3d_buffer *buffer;
4289
4290         TRACE("Growing index buffer to %u bytes\n", size);
4291
4292         hr = wined3d_buffer_create_ib(This->wined3d_device, size, WINED3DUSAGE_DYNAMIC /* Usage */,
4293                 WINED3DPOOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
4294         if (FAILED(hr))
4295         {
4296             ERR("(%p) IWineD3DDevice::CreateIndexBuffer failed with hr = %08x\n", This, hr);
4297             wined3d_mutex_unlock();
4298             return hr;
4299         }
4300
4301         wined3d_buffer_decref(This->indexbuffer);
4302         This->indexbuffer = buffer;
4303     }
4304
4305     /* Copy the index stream into the index buffer. A new IWineD3DDevice
4306      * method could be created which takes an user pointer containing the
4307      * indices or a SetData-Method for the index buffer, which overrides the
4308      * index buffer data with our pointer. */
4309     hr = wined3d_buffer_map(This->indexbuffer, 0, IndexCount * sizeof(WORD),
4310             (BYTE **)&LockedIndices, 0);
4311     if (FAILED(hr))
4312     {
4313         ERR("Failed to map buffer, hr %#x.\n", hr);
4314         wined3d_mutex_unlock();
4315         return hr;
4316     }
4317     memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4318     wined3d_buffer_unmap(This->indexbuffer);
4319
4320     /* Set the index stream */
4321     wined3d_device_set_base_vertex_index(This->wined3d_device, StartVertex);
4322     hr = wined3d_device_set_index_buffer(This->wined3d_device, This->indexbuffer, WINED3DFMT_R16_UINT);
4323
4324     /* Set the vertex stream source */
4325     hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4326     if (FAILED(hr))
4327     {
4328         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4329         wined3d_mutex_unlock();
4330         return hr;
4331     }
4332
4333
4334     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4335     hr = wined3d_device_draw_indexed_primitive(This->wined3d_device, 0, IndexCount);
4336
4337     wined3d_mutex_unlock();
4338
4339     return hr;
4340 }
4341
4342 static HRESULT WINAPI
4343 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4344                                              D3DPRIMITIVETYPE PrimitiveType,
4345                                              IDirect3DVertexBuffer7 *D3DVertexBuf,
4346                                              DWORD StartVertex,
4347                                              DWORD NumVertices,
4348                                              WORD *Indices,
4349                                              DWORD IndexCount,
4350                                              DWORD Flags)
4351 {
4352     return IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4353 }
4354
4355 static HRESULT WINAPI
4356 IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4357                                              D3DPRIMITIVETYPE PrimitiveType,
4358                                              IDirect3DVertexBuffer7 *D3DVertexBuf,
4359                                              DWORD StartVertex,
4360                                              DWORD NumVertices,
4361                                              WORD *Indices,
4362                                              DWORD IndexCount,
4363                                              DWORD Flags)
4364 {
4365     HRESULT hr;
4366     WORD old_fpucw;
4367
4368     old_fpucw = d3d_fpu_setup();
4369     hr = IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4370     set_fpu_control_word(old_fpucw);
4371
4372     return hr;
4373 }
4374
4375 static HRESULT WINAPI IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4376         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, WORD *Indices,
4377         DWORD IndexCount, DWORD Flags)
4378 {
4379     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4380     IDirect3DVertexBufferImpl *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4381
4382     TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4383             iface, PrimitiveType, D3DVertexBuf, Indices, IndexCount, Flags);
4384
4385     return IDirect3DDevice7_DrawIndexedPrimitiveVB(&This->IDirect3DDevice7_iface,
4386             PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount,
4387             Flags);
4388 }
4389
4390 /*****************************************************************************
4391  * IDirect3DDevice7::ComputeSphereVisibility
4392  *
4393  * Calculates the visibility of spheres in the current viewport. The spheres
4394  * are passed in the Centers and Radii arrays, the results are passed back
4395  * in the ReturnValues array. Return values are either completely visible,
4396  * partially visible or completely invisible.
4397  * The return value consist of a combination of D3DCLIP_* flags, or it's
4398  * 0 if the sphere is completely visible(according to the SDK, not checked)
4399  *
4400  * Version 3 and 7
4401  *
4402  * Params:
4403  *  Centers: Array containing the sphere centers
4404  *  Radii: Array containing the sphere radii
4405  *  NumSpheres: The number of centers and radii in the arrays
4406  *  Flags: Some flags
4407  *  ReturnValues: Array to write the results to
4408  *
4409  * Returns:
4410  *  D3D_OK
4411  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4412  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4413  *  is singular)
4414  *
4415  *****************************************************************************/
4416
4417 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4418 {
4419     float distance, norm;
4420
4421     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4422     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4423
4424     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4425     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4426     return 0;
4427 }
4428
4429 static HRESULT WINAPI
4430 IDirect3DDeviceImpl_7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4431                                               D3DVECTOR *Centers,
4432                                               D3DVALUE *Radii,
4433                                               DWORD NumSpheres,
4434                                               DWORD Flags,
4435                                               DWORD *ReturnValues)
4436 {
4437     D3DMATRIX m, temp;
4438     D3DVALUE origin_plane[6];
4439     D3DVECTOR vec[6];
4440     HRESULT hr;
4441     UINT i, j;
4442
4443     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4444             iface, Centers, Radii, NumSpheres, Flags, ReturnValues);
4445
4446     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4447     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4448     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4449     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4450     multiply_matrix(&m, &temp, &m);
4451
4452     hr = IDirect3DDeviceImpl_7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4453     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4454     multiply_matrix(&m, &temp, &m);
4455
4456 /* Left plane */
4457     vec[0].u1.x = m._14 + m._11;
4458     vec[0].u2.y = m._24 + m._21;
4459     vec[0].u3.z = m._34 + m._31;
4460     origin_plane[0] = m._44 + m._41;
4461
4462 /* Right plane */
4463     vec[1].u1.x = m._14 - m._11;
4464     vec[1].u2.y = m._24 - m._21;
4465     vec[1].u3.z = m._34 - m._31;
4466     origin_plane[1] = m._44 - m._41;
4467
4468 /* Top plane */
4469     vec[2].u1.x = m._14 - m._12;
4470     vec[2].u2.y = m._24 - m._22;
4471     vec[2].u3.z = m._34 - m._32;
4472     origin_plane[2] = m._44 - m._42;
4473
4474 /* Bottom plane */
4475     vec[3].u1.x = m._14 + m._12;
4476     vec[3].u2.y = m._24 + m._22;
4477     vec[3].u3.z = m._34 + m._32;
4478     origin_plane[3] = m._44 + m._42;
4479
4480 /* Front plane */
4481     vec[4].u1.x = m._13;
4482     vec[4].u2.y = m._23;
4483     vec[4].u3.z = m._33;
4484     origin_plane[4] = m._43;
4485
4486 /* Back plane*/
4487     vec[5].u1.x = m._14 - m._13;
4488     vec[5].u2.y = m._24 - m._23;
4489     vec[5].u3.z = m._34 - m._33;
4490     origin_plane[5] = m._44 - m._43;
4491
4492     for(i=0; i<NumSpheres; i++)
4493     {
4494         ReturnValues[i] = 0;
4495         for(j=0; j<6; j++) ReturnValues[i] |= in_plane(j, vec[j], origin_plane[j], Centers[i], Radii[i]);
4496     }
4497
4498     return D3D_OK;
4499 }
4500
4501 static HRESULT WINAPI IDirect3DDeviceImpl_3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4502         D3DVECTOR *Centers, D3DVALUE *Radii, DWORD NumSpheres, DWORD Flags, DWORD *ReturnValues)
4503 {
4504     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4505
4506     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4507             iface, Centers, Radii, NumSpheres, Flags, ReturnValues);
4508
4509     return IDirect3DDevice7_ComputeSphereVisibility(&This->IDirect3DDevice7_iface,
4510             Centers, Radii, NumSpheres, Flags, ReturnValues);
4511 }
4512
4513 /*****************************************************************************
4514  * IDirect3DDevice7::GetTexture
4515  *
4516  * Returns the texture interface handle assigned to a texture stage.
4517  * The returned texture is AddRefed. This is taken from old ddraw,
4518  * not checked in Windows.
4519  *
4520  * Version 3 and 7
4521  *
4522  * Params:
4523  *  Stage: Texture stage to read the texture from
4524  *  Texture: Address to store the interface pointer at
4525  *
4526  * Returns:
4527  *  D3D_OK on success
4528  *  DDERR_INVALIDPARAMS if Texture is NULL
4529  *  For details, see IWineD3DDevice::GetTexture
4530  *
4531  *****************************************************************************/
4532 static HRESULT
4533 IDirect3DDeviceImpl_7_GetTexture(IDirect3DDevice7 *iface,
4534                                  DWORD Stage,
4535                                  IDirectDrawSurface7 **Texture)
4536 {
4537     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
4538     struct wined3d_texture *wined3d_texture;
4539     HRESULT hr;
4540
4541     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture);
4542
4543     if(!Texture)
4544     {
4545         TRACE("Texture == NULL, failing with DDERR_INVALIDPARAMS\n");
4546         return DDERR_INVALIDPARAMS;
4547     }
4548
4549     wined3d_mutex_lock();
4550     hr = wined3d_device_get_texture(This->wined3d_device, Stage, &wined3d_texture);
4551     if (FAILED(hr) || !wined3d_texture)
4552     {
4553         *Texture = NULL;
4554         wined3d_mutex_unlock();
4555         return hr;
4556     }
4557
4558     *Texture = wined3d_texture_get_parent(wined3d_texture);
4559     IDirectDrawSurface7_AddRef(*Texture);
4560     wined3d_texture_decref(wined3d_texture);
4561     wined3d_mutex_unlock();
4562
4563     return hr;
4564 }
4565
4566 static HRESULT WINAPI
4567 IDirect3DDeviceImpl_7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4568                                  DWORD Stage,
4569                                  IDirectDrawSurface7 **Texture)
4570 {
4571     return IDirect3DDeviceImpl_7_GetTexture(iface, Stage, Texture);
4572 }
4573
4574 static HRESULT WINAPI
4575 IDirect3DDeviceImpl_7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4576                                  DWORD Stage,
4577                                  IDirectDrawSurface7 **Texture)
4578 {
4579     HRESULT hr;
4580     WORD old_fpucw;
4581
4582     old_fpucw = d3d_fpu_setup();
4583     hr = IDirect3DDeviceImpl_7_GetTexture(iface, Stage, Texture);
4584     set_fpu_control_word(old_fpucw);
4585
4586     return hr;
4587 }
4588
4589 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetTexture(IDirect3DDevice3 *iface, DWORD Stage,
4590         IDirect3DTexture2 **Texture2)
4591 {
4592     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4593     HRESULT ret;
4594     IDirectDrawSurface7 *ret_val;
4595     IDirectDrawSurfaceImpl *ret_val_impl;
4596
4597     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture2);
4598
4599     ret = IDirect3DDevice7_GetTexture(&This->IDirect3DDevice7_iface, Stage, &ret_val);
4600
4601     ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4602     *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4603
4604     TRACE("Returning texture %p.\n", *Texture2);
4605
4606     return ret;
4607 }
4608
4609 /*****************************************************************************
4610  * IDirect3DDevice7::SetTexture
4611  *
4612  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4613  *
4614  * Version 3 and 7
4615  *
4616  * Params:
4617  *  Stage: The stage to assign the texture to
4618  *  Texture: Interface pointer to the texture surface
4619  *
4620  * Returns
4621  * D3D_OK on success
4622  * For details, see IWineD3DDevice::SetTexture
4623  *
4624  *****************************************************************************/
4625 static HRESULT
4626 IDirect3DDeviceImpl_7_SetTexture(IDirect3DDevice7 *iface,
4627                                  DWORD Stage,
4628                                  IDirectDrawSurface7 *Texture)
4629 {
4630     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
4631     IDirectDrawSurfaceImpl *surf = unsafe_impl_from_IDirectDrawSurface7(Texture);
4632     HRESULT hr;
4633
4634     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture);
4635
4636     /* Texture may be NULL here */
4637     wined3d_mutex_lock();
4638     hr = wined3d_device_set_texture(This->wined3d_device,
4639             Stage, surf ? surf->wined3d_texture : NULL);
4640     wined3d_mutex_unlock();
4641
4642     return hr;
4643 }
4644
4645 static HRESULT WINAPI
4646 IDirect3DDeviceImpl_7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4647                                  DWORD Stage,
4648                                  IDirectDrawSurface7 *Texture)
4649 {
4650     return IDirect3DDeviceImpl_7_SetTexture(iface, Stage, Texture);
4651 }
4652
4653 static HRESULT WINAPI
4654 IDirect3DDeviceImpl_7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4655                                  DWORD Stage,
4656                                  IDirectDrawSurface7 *Texture)
4657 {
4658     HRESULT hr;
4659     WORD old_fpucw;
4660
4661     old_fpucw = d3d_fpu_setup();
4662     hr = IDirect3DDeviceImpl_7_SetTexture(iface, Stage, Texture);
4663     set_fpu_control_word(old_fpucw);
4664
4665     return hr;
4666 }
4667
4668 static HRESULT WINAPI
4669 IDirect3DDeviceImpl_3_SetTexture(IDirect3DDevice3 *iface,
4670                                  DWORD Stage,
4671                                  IDirect3DTexture2 *Texture2)
4672 {
4673     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4674     IDirectDrawSurfaceImpl *tex = unsafe_impl_from_IDirect3DTexture2(Texture2);
4675     DWORD texmapblend;
4676     HRESULT hr;
4677
4678     TRACE("iface %p, stage %u, texture %p.\n", iface, Stage, Texture2);
4679
4680     wined3d_mutex_lock();
4681
4682     if (This->legacyTextureBlending)
4683         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4684
4685     hr = IDirect3DDevice7_SetTexture(&This->IDirect3DDevice7_iface, Stage, &tex->IDirectDrawSurface7_iface);
4686
4687     if (This->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4688     {
4689         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4690            See IDirect3DDeviceImpl_3_SetRenderState for details. */
4691         struct wined3d_texture *tex = NULL;
4692         BOOL tex_alpha = FALSE;
4693         DDPIXELFORMAT ddfmt;
4694         HRESULT result;
4695
4696         result = wined3d_device_get_texture(This->wined3d_device, 0, &tex);
4697         if (result == WINED3D_OK && tex)
4698         {
4699             struct wined3d_resource *sub_resource;
4700
4701             if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4702             {
4703                 struct wined3d_resource_desc desc;
4704
4705                 wined3d_resource_get_desc(sub_resource, &desc);
4706                 ddfmt.dwSize = sizeof(ddfmt);
4707                 PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4708                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4709             }
4710
4711             wined3d_texture_decref(tex);
4712         }
4713
4714         /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4715         if (tex_alpha)
4716             wined3d_device_set_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1);
4717         else
4718             wined3d_device_set_texture_stage_state(This->wined3d_device, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG2);
4719     }
4720
4721     wined3d_mutex_unlock();
4722
4723     return hr;
4724 }
4725
4726 static const struct tss_lookup
4727 {
4728     BOOL sampler_state;
4729     DWORD state;
4730 }
4731 tss_lookup[] =
4732 {
4733     {FALSE, WINED3DTSS_FORCE_DWORD},            /*  0, unused */
4734     {FALSE, WINED3DTSS_COLOROP},                /*  1, D3DTSS_COLOROP */
4735     {FALSE, WINED3DTSS_COLORARG1},              /*  2, D3DTSS_COLORARG1 */
4736     {FALSE, WINED3DTSS_COLORARG2},              /*  3, D3DTSS_COLORARG2 */
4737     {FALSE, WINED3DTSS_ALPHAOP},                /*  4, D3DTSS_ALPHAOP */
4738     {FALSE, WINED3DTSS_ALPHAARG1},              /*  5, D3DTSS_ALPHAARG1 */
4739     {FALSE, WINED3DTSS_ALPHAARG2},              /*  6, D3DTSS_ALPHAARG2 */
4740     {FALSE, WINED3DTSS_BUMPENVMAT00},           /*  7, D3DTSS_BUMPENVMAT00 */
4741     {FALSE, WINED3DTSS_BUMPENVMAT01},           /*  8, D3DTSS_BUMPENVMAT01 */
4742     {FALSE, WINED3DTSS_BUMPENVMAT10},           /*  9, D3DTSS_BUMPENVMAT10 */
4743     {FALSE, WINED3DTSS_BUMPENVMAT11},           /* 10, D3DTSS_BUMPENVMAT11 */
4744     {FALSE, WINED3DTSS_TEXCOORDINDEX},          /* 11, D3DTSS_TEXCOORDINDEX */
4745     {TRUE,  WINED3DSAMP_ADDRESSU},              /* 12, D3DTSS_ADDRESS */
4746     {TRUE,  WINED3DSAMP_ADDRESSU},              /* 13, D3DTSS_ADDRESSU */
4747     {TRUE,  WINED3DSAMP_ADDRESSV},              /* 14, D3DTSS_ADDRESSV */
4748     {TRUE,  WINED3DSAMP_BORDERCOLOR},           /* 15, D3DTSS_BORDERCOLOR */
4749     {TRUE,  WINED3DSAMP_MAGFILTER},             /* 16, D3DTSS_MAGFILTER */
4750     {TRUE,  WINED3DSAMP_MINFILTER},             /* 17, D3DTSS_MINFILTER */
4751     {TRUE,  WINED3DSAMP_MIPFILTER},             /* 18, D3DTSS_MIPFILTER */
4752     {TRUE,  WINED3DSAMP_MIPMAPLODBIAS},         /* 19, D3DTSS_MIPMAPLODBIAS */
4753     {TRUE,  WINED3DSAMP_MAXMIPLEVEL},           /* 20, D3DTSS_MAXMIPLEVEL */
4754     {TRUE,  WINED3DSAMP_MAXANISOTROPY},         /* 21, D3DTSS_MAXANISOTROPY */
4755     {FALSE, WINED3DTSS_BUMPENVLSCALE},          /* 22, D3DTSS_BUMPENVLSCALE */
4756     {FALSE, WINED3DTSS_BUMPENVLOFFSET},         /* 23, D3DTSS_BUMPENVLOFFSET */
4757     {FALSE, WINED3DTSS_TEXTURETRANSFORMFLAGS},  /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4758 };
4759
4760 /*****************************************************************************
4761  * IDirect3DDevice7::GetTextureStageState
4762  *
4763  * Retrieves a state from a texture stage.
4764  *
4765  * Version 3 and 7
4766  *
4767  * Params:
4768  *  Stage: The stage to retrieve the state from
4769  *  TexStageStateType: The state type to retrieve
4770  *  State: Address to store the state's value at
4771  *
4772  * Returns:
4773  *  D3D_OK on success
4774  *  DDERR_INVALIDPARAMS if State is NULL
4775  *  For details, see IWineD3DDevice::GetTextureStageState
4776  *
4777  *****************************************************************************/
4778 static HRESULT
4779 IDirect3DDeviceImpl_7_GetTextureStageState(IDirect3DDevice7 *iface,
4780                                            DWORD Stage,
4781                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4782                                            DWORD *State)
4783 {
4784     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
4785     HRESULT hr;
4786     const struct tss_lookup *l;
4787
4788     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4789             iface, Stage, TexStageStateType, State);
4790
4791     if(!State)
4792         return DDERR_INVALIDPARAMS;
4793
4794     if (TexStageStateType > D3DTSS_TEXTURETRANSFORMFLAGS)
4795     {
4796         WARN("Invalid TexStageStateType %#x passed.\n", TexStageStateType);
4797         return DD_OK;
4798     }
4799
4800     l = &tss_lookup[TexStageStateType];
4801
4802     wined3d_mutex_lock();
4803
4804     if (l->sampler_state)
4805     {
4806         hr = wined3d_device_get_sampler_state(This->wined3d_device, Stage, l->state, State);
4807
4808         switch(TexStageStateType)
4809         {
4810             /* Mipfilter is a sampler state with different values */
4811             case D3DTSS_MIPFILTER:
4812             {
4813                 switch(*State)
4814                 {
4815                     case WINED3DTEXF_NONE: *State = D3DTFP_NONE; break;
4816                     case WINED3DTEXF_POINT: *State = D3DTFP_POINT; break;
4817                     case WINED3DTEXF_LINEAR: *State = D3DTFP_LINEAR; break;
4818                     default:
4819                         ERR("Unexpected mipfilter value %#x\n", *State);
4820                         *State = D3DTFP_NONE;
4821                         break;
4822                 }
4823                 break;
4824             }
4825
4826             /* Magfilter has slightly different values */
4827             case D3DTSS_MAGFILTER:
4828             {
4829                 switch(*State)
4830                 {
4831                     case WINED3DTEXF_POINT: *State = D3DTFG_POINT; break;
4832                     case WINED3DTEXF_LINEAR: *State = D3DTFG_LINEAR; break;
4833                     case WINED3DTEXF_ANISOTROPIC: *State = D3DTFG_ANISOTROPIC; break;
4834                     case WINED3DTEXF_FLATCUBIC: *State = D3DTFG_FLATCUBIC; break;
4835                     case WINED3DTEXF_GAUSSIANCUBIC: *State = D3DTFG_GAUSSIANCUBIC; break;
4836                     default:
4837                         ERR("Unexpected wined3d mag filter value %#x\n", *State);
4838                         *State = D3DTFG_POINT;
4839                         break;
4840                 }
4841                 break;
4842             }
4843
4844             default:
4845                 break;
4846         }
4847     }
4848     else
4849     {
4850         hr = wined3d_device_get_texture_stage_state(This->wined3d_device, Stage, l->state, State);
4851     }
4852
4853     wined3d_mutex_unlock();
4854
4855     return hr;
4856 }
4857
4858 static HRESULT WINAPI
4859 IDirect3DDeviceImpl_7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4860                                            DWORD Stage,
4861                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4862                                            DWORD *State)
4863 {
4864     return IDirect3DDeviceImpl_7_GetTextureStageState(iface, Stage, TexStageStateType, State);
4865 }
4866
4867 static HRESULT WINAPI
4868 IDirect3DDeviceImpl_7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4869                                            DWORD Stage,
4870                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4871                                            DWORD *State)
4872 {
4873     HRESULT hr;
4874     WORD old_fpucw;
4875
4876     old_fpucw = d3d_fpu_setup();
4877     hr = IDirect3DDeviceImpl_7_GetTextureStageState(iface, Stage, TexStageStateType, State);
4878     set_fpu_control_word(old_fpucw);
4879
4880     return hr;
4881 }
4882
4883 static HRESULT WINAPI IDirect3DDeviceImpl_3_GetTextureStageState(IDirect3DDevice3 *iface,
4884         DWORD Stage, D3DTEXTURESTAGESTATETYPE TexStageStateType, DWORD *State)
4885 {
4886     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
4887
4888     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4889             iface, Stage, TexStageStateType, State);
4890
4891     return IDirect3DDevice7_GetTextureStageState(&This->IDirect3DDevice7_iface,
4892             Stage, TexStageStateType, State);
4893 }
4894
4895 /*****************************************************************************
4896  * IDirect3DDevice7::SetTextureStageState
4897  *
4898  * Sets a texture stage state. Some stage types need to be handled specially,
4899  * because they do not exist in WineD3D and were moved to another place
4900  *
4901  * Version 3 and 7
4902  *
4903  * Params:
4904  *  Stage: The stage to modify
4905  *  TexStageStateType: The state to change
4906  *  State: The new value for the state
4907  *
4908  * Returns:
4909  *  D3D_OK on success
4910  *  For details, see IWineD3DDevice::SetTextureStageState
4911  *
4912  *****************************************************************************/
4913 static HRESULT
4914 IDirect3DDeviceImpl_7_SetTextureStageState(IDirect3DDevice7 *iface,
4915                                            DWORD Stage,
4916                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4917                                            DWORD State)
4918 {
4919     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
4920     const struct tss_lookup *l;
4921     HRESULT hr;
4922
4923     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4924             iface, Stage, TexStageStateType, State);
4925
4926     if (TexStageStateType > D3DTSS_TEXTURETRANSFORMFLAGS)
4927     {
4928         WARN("Invalid TexStageStateType %#x passed.\n", TexStageStateType);
4929         return DD_OK;
4930     }
4931
4932     l = &tss_lookup[TexStageStateType];
4933
4934     wined3d_mutex_lock();
4935
4936     if (l->sampler_state)
4937     {
4938         switch(TexStageStateType)
4939         {
4940             /* Mipfilter is a sampler state with different values */
4941             case D3DTSS_MIPFILTER:
4942             {
4943                 switch(State)
4944                 {
4945                     case D3DTFP_NONE: State = WINED3DTEXF_NONE; break;
4946                     case D3DTFP_POINT: State = WINED3DTEXF_POINT; break;
4947                     case 0: /* Unchecked */
4948                     case D3DTFP_LINEAR: State = WINED3DTEXF_LINEAR; break;
4949                     default:
4950                         ERR("Unexpected mipfilter value %d\n", State);
4951                         State = WINED3DTEXF_NONE;
4952                         break;
4953                 }
4954                 break;
4955             }
4956
4957             /* Magfilter has slightly different values */
4958             case D3DTSS_MAGFILTER:
4959             {
4960                 switch(State)
4961                 {
4962                     case D3DTFG_POINT: State = WINED3DTEXF_POINT; break;
4963                     case D3DTFG_LINEAR: State = WINED3DTEXF_LINEAR; break;
4964                     case D3DTFG_FLATCUBIC: State = WINED3DTEXF_FLATCUBIC; break;
4965                     case D3DTFG_GAUSSIANCUBIC: State = WINED3DTEXF_GAUSSIANCUBIC; break;
4966                     case D3DTFG_ANISOTROPIC: State = WINED3DTEXF_ANISOTROPIC; break;
4967                     default:
4968                         ERR("Unexpected d3d7 mag filter type %d\n", State);
4969                         State = WINED3DTEXF_POINT;
4970                         break;
4971                 }
4972                 break;
4973             }
4974
4975             case D3DTSS_ADDRESS:
4976                 wined3d_device_set_sampler_state(This->wined3d_device, Stage, WINED3DSAMP_ADDRESSV, State);
4977                 break;
4978
4979             default:
4980                 break;
4981         }
4982
4983         hr = wined3d_device_set_sampler_state(This->wined3d_device, Stage, l->state, State);
4984     }
4985     else
4986     {
4987         hr = wined3d_device_set_texture_stage_state(This->wined3d_device, Stage, l->state, State);
4988     }
4989
4990     wined3d_mutex_unlock();
4991
4992     return hr;
4993 }
4994
4995 static HRESULT WINAPI
4996 IDirect3DDeviceImpl_7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4997                                            DWORD Stage,
4998                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
4999                                            DWORD State)
5000 {
5001     return IDirect3DDeviceImpl_7_SetTextureStageState(iface, Stage, TexStageStateType, State);
5002 }
5003
5004 static HRESULT WINAPI
5005 IDirect3DDeviceImpl_7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5006                                            DWORD Stage,
5007                                            D3DTEXTURESTAGESTATETYPE TexStageStateType,
5008                                            DWORD State)
5009 {
5010     HRESULT hr;
5011     WORD old_fpucw;
5012
5013     old_fpucw = d3d_fpu_setup();
5014     hr = IDirect3DDeviceImpl_7_SetTextureStageState(iface, Stage, TexStageStateType, State);
5015     set_fpu_control_word(old_fpucw);
5016
5017     return hr;
5018 }
5019
5020 static HRESULT WINAPI IDirect3DDeviceImpl_3_SetTextureStageState(IDirect3DDevice3 *iface,
5021         DWORD Stage, D3DTEXTURESTAGESTATETYPE TexStageStateType, DWORD State)
5022 {
5023     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
5024
5025     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5026             iface, Stage, TexStageStateType, State);
5027
5028     return IDirect3DDevice7_SetTextureStageState(&This->IDirect3DDevice7_iface,
5029             Stage, TexStageStateType, State);
5030 }
5031
5032 /*****************************************************************************
5033  * IDirect3DDevice7::ValidateDevice
5034  *
5035  * SDK: "Reports the device's ability to render the currently set
5036  * texture-blending operations in a single pass". Whatever that means
5037  * exactly...
5038  *
5039  * Version 3 and 7
5040  *
5041  * Params:
5042  *  NumPasses: Address to write the number of necessary passes for the
5043  *             desired effect to.
5044  *
5045  * Returns:
5046  *  D3D_OK on success
5047  *  See IWineD3DDevice::ValidateDevice for more details
5048  *
5049  *****************************************************************************/
5050 static HRESULT
5051 IDirect3DDeviceImpl_7_ValidateDevice(IDirect3DDevice7 *iface,
5052                                      DWORD *NumPasses)
5053 {
5054     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5055     HRESULT hr;
5056
5057     TRACE("iface %p, pass_count %p.\n", iface, NumPasses);
5058
5059     wined3d_mutex_lock();
5060     hr = wined3d_device_validate_device(This->wined3d_device, NumPasses);
5061     wined3d_mutex_unlock();
5062
5063     return hr;
5064 }
5065
5066 static HRESULT WINAPI
5067 IDirect3DDeviceImpl_7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface,
5068                                      DWORD *NumPasses)
5069 {
5070     return IDirect3DDeviceImpl_7_ValidateDevice(iface, NumPasses);
5071 }
5072
5073 static HRESULT WINAPI
5074 IDirect3DDeviceImpl_7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface,
5075                                      DWORD *NumPasses)
5076 {
5077     HRESULT hr;
5078     WORD old_fpucw;
5079
5080     old_fpucw = d3d_fpu_setup();
5081     hr = IDirect3DDeviceImpl_7_ValidateDevice(iface, NumPasses);
5082     set_fpu_control_word(old_fpucw);
5083
5084     return hr;
5085 }
5086
5087 static HRESULT WINAPI IDirect3DDeviceImpl_3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *Passes)
5088 {
5089     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice3(iface);
5090
5091     TRACE("iface %p, pass_count %p.\n", iface, Passes);
5092
5093     return IDirect3DDevice7_ValidateDevice(&This->IDirect3DDevice7_iface, Passes);
5094 }
5095
5096 /*****************************************************************************
5097  * IDirect3DDevice7::Clear
5098  *
5099  * Fills the render target, the z buffer and the stencil buffer with a
5100  * clear color / value
5101  *
5102  * Version 7 only
5103  *
5104  * Params:
5105  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
5106  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
5107  *  Flags: Some flags, as usual
5108  *  Color: Clear color for the render target
5109  *  Z: Clear value for the Z buffer
5110  *  Stencil: Clear value to store in each stencil buffer entry
5111  *
5112  * Returns:
5113  *  D3D_OK on success
5114  *  For details, see IWineD3DDevice::Clear
5115  *
5116  *****************************************************************************/
5117 static HRESULT IDirect3DDeviceImpl_7_Clear(IDirect3DDevice7 *iface, DWORD count,
5118         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5119 {
5120     const struct wined3d_color c =
5121     {
5122         ((color >> 16) & 0xff) / 255.0f,
5123         ((color >>  8) & 0xff) / 255.0f,
5124         (color & 0xff) / 255.0f,
5125         ((color >> 24) & 0xff) / 255.0f,
5126     };
5127     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5128     HRESULT hr;
5129
5130     TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5131             iface, count, rects, flags, color, z, stencil);
5132
5133     wined3d_mutex_lock();
5134     hr = wined3d_device_clear(This->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5135     wined3d_mutex_unlock();
5136
5137     return hr;
5138 }
5139
5140 static HRESULT WINAPI
5141 IDirect3DDeviceImpl_7_Clear_FPUSetup(IDirect3DDevice7 *iface,
5142                             DWORD Count,
5143                             D3DRECT *Rects,
5144                             DWORD Flags,
5145                             D3DCOLOR Color,
5146                             D3DVALUE Z,
5147                             DWORD Stencil)
5148 {
5149     return IDirect3DDeviceImpl_7_Clear(iface, Count, Rects, Flags, Color, Z, Stencil);
5150 }
5151
5152 static HRESULT WINAPI
5153 IDirect3DDeviceImpl_7_Clear_FPUPreserve(IDirect3DDevice7 *iface,
5154                             DWORD Count,
5155                             D3DRECT *Rects,
5156                             DWORD Flags,
5157                             D3DCOLOR Color,
5158                             D3DVALUE Z,
5159                             DWORD Stencil)
5160 {
5161     HRESULT hr;
5162     WORD old_fpucw;
5163
5164     old_fpucw = d3d_fpu_setup();
5165     hr = IDirect3DDeviceImpl_7_Clear(iface, Count, Rects, Flags, Color, Z, Stencil);
5166     set_fpu_control_word(old_fpucw);
5167
5168     return hr;
5169 }
5170
5171 /*****************************************************************************
5172  * IDirect3DDevice7::SetViewport
5173  *
5174  * Sets the current viewport.
5175  *
5176  * Version 7 only, but IDirect3DViewport uses this call for older
5177  * versions
5178  *
5179  * Params:
5180  *  Data: The new viewport to set
5181  *
5182  * Returns:
5183  *  D3D_OK on success
5184  *  DDERR_INVALIDPARAMS if Data is NULL
5185  *  For more details, see IWineDDDevice::SetViewport
5186  *
5187  *****************************************************************************/
5188 static HRESULT
5189 IDirect3DDeviceImpl_7_SetViewport(IDirect3DDevice7 *iface,
5190                                   D3DVIEWPORT7 *Data)
5191 {
5192     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5193     HRESULT hr;
5194
5195     TRACE("iface %p, viewport %p.\n", iface, Data);
5196
5197     if(!Data)
5198         return DDERR_INVALIDPARAMS;
5199
5200     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5201     wined3d_mutex_lock();
5202     hr = wined3d_device_set_viewport(This->wined3d_device, (struct wined3d_viewport *)Data);
5203     wined3d_mutex_unlock();
5204
5205     return hr;
5206 }
5207
5208 static HRESULT WINAPI
5209 IDirect3DDeviceImpl_7_SetViewport_FPUSetup(IDirect3DDevice7 *iface,
5210                                   D3DVIEWPORT7 *Data)
5211 {
5212     return IDirect3DDeviceImpl_7_SetViewport(iface, Data);
5213 }
5214
5215 static HRESULT WINAPI
5216 IDirect3DDeviceImpl_7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface,
5217                                   D3DVIEWPORT7 *Data)
5218 {
5219     HRESULT hr;
5220     WORD old_fpucw;
5221
5222     old_fpucw = d3d_fpu_setup();
5223     hr = IDirect3DDeviceImpl_7_SetViewport(iface, Data);
5224     set_fpu_control_word(old_fpucw);
5225
5226     return hr;
5227 }
5228
5229 /*****************************************************************************
5230  * IDirect3DDevice::GetViewport
5231  *
5232  * Returns the current viewport
5233  *
5234  * Version 7
5235  *
5236  * Params:
5237  *  Data: D3D7Viewport structure to write the viewport information to
5238  *
5239  * Returns:
5240  *  D3D_OK on success
5241  *  DDERR_INVALIDPARAMS if Data is NULL
5242  *  For more details, see IWineD3DDevice::GetViewport
5243  *
5244  *****************************************************************************/
5245 static HRESULT
5246 IDirect3DDeviceImpl_7_GetViewport(IDirect3DDevice7 *iface,
5247                                   D3DVIEWPORT7 *Data)
5248 {
5249     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5250     HRESULT hr;
5251
5252     TRACE("iface %p, viewport %p.\n", iface, Data);
5253
5254     if(!Data)
5255         return DDERR_INVALIDPARAMS;
5256
5257     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5258     wined3d_mutex_lock();
5259     hr = wined3d_device_get_viewport(This->wined3d_device, (struct wined3d_viewport *)Data);
5260     wined3d_mutex_unlock();
5261
5262     return hr_ddraw_from_wined3d(hr);
5263 }
5264
5265 static HRESULT WINAPI
5266 IDirect3DDeviceImpl_7_GetViewport_FPUSetup(IDirect3DDevice7 *iface,
5267                                   D3DVIEWPORT7 *Data)
5268 {
5269     return IDirect3DDeviceImpl_7_GetViewport(iface, Data);
5270 }
5271
5272 static HRESULT WINAPI
5273 IDirect3DDeviceImpl_7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface,
5274                                   D3DVIEWPORT7 *Data)
5275 {
5276     HRESULT hr;
5277     WORD old_fpucw;
5278
5279     old_fpucw = d3d_fpu_setup();
5280     hr = IDirect3DDeviceImpl_7_GetViewport(iface, Data);
5281     set_fpu_control_word(old_fpucw);
5282
5283     return hr;
5284 }
5285
5286 /*****************************************************************************
5287  * IDirect3DDevice7::SetMaterial
5288  *
5289  * Sets the Material
5290  *
5291  * Version 7
5292  *
5293  * Params:
5294  *  Mat: The material to set
5295  *
5296  * Returns:
5297  *  D3D_OK on success
5298  *  DDERR_INVALIDPARAMS if Mat is NULL.
5299  *  For more details, see IWineD3DDevice::SetMaterial
5300  *
5301  *****************************************************************************/
5302 static HRESULT
5303 IDirect3DDeviceImpl_7_SetMaterial(IDirect3DDevice7 *iface,
5304                                   D3DMATERIAL7 *Mat)
5305 {
5306     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5307     HRESULT hr;
5308
5309     TRACE("iface %p, material %p.\n", iface, Mat);
5310
5311     if (!Mat) return DDERR_INVALIDPARAMS;
5312
5313     wined3d_mutex_lock();
5314     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5315     hr = wined3d_device_set_material(This->wined3d_device, (struct wined3d_material *)Mat);
5316     wined3d_mutex_unlock();
5317
5318     return hr_ddraw_from_wined3d(hr);
5319 }
5320
5321 static HRESULT WINAPI
5322 IDirect3DDeviceImpl_7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface,
5323                                   D3DMATERIAL7 *Mat)
5324 {
5325     return IDirect3DDeviceImpl_7_SetMaterial(iface, Mat);
5326 }
5327
5328 static HRESULT WINAPI
5329 IDirect3DDeviceImpl_7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface,
5330                                   D3DMATERIAL7 *Mat)
5331 {
5332     HRESULT hr;
5333     WORD old_fpucw;
5334
5335     old_fpucw = d3d_fpu_setup();
5336     hr = IDirect3DDeviceImpl_7_SetMaterial(iface, Mat);
5337     set_fpu_control_word(old_fpucw);
5338
5339     return hr;
5340 }
5341
5342 /*****************************************************************************
5343  * IDirect3DDevice7::GetMaterial
5344  *
5345  * Returns the current material
5346  *
5347  * Version 7
5348  *
5349  * Params:
5350  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5351  *
5352  * Returns:
5353  *  D3D_OK on success
5354  *  DDERR_INVALIDPARAMS if Mat is NULL
5355  *  For more details, see IWineD3DDevice::GetMaterial
5356  *
5357  *****************************************************************************/
5358 static HRESULT
5359 IDirect3DDeviceImpl_7_GetMaterial(IDirect3DDevice7 *iface,
5360                                   D3DMATERIAL7 *Mat)
5361 {
5362     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5363     HRESULT hr;
5364
5365     TRACE("iface %p, material %p.\n", iface, Mat);
5366
5367     wined3d_mutex_lock();
5368     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5369     hr = wined3d_device_get_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_GetMaterial_FPUSetup(IDirect3DDevice7 *iface,
5377                                   D3DMATERIAL7 *Mat)
5378 {
5379     return IDirect3DDeviceImpl_7_GetMaterial(iface, Mat);
5380 }
5381
5382 static HRESULT WINAPI
5383 IDirect3DDeviceImpl_7_GetMaterial_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_GetMaterial(iface, Mat);
5391     set_fpu_control_word(old_fpucw);
5392
5393     return hr;
5394 }
5395
5396 /*****************************************************************************
5397  * IDirect3DDevice7::SetLight
5398  *
5399  * Assigns a light to a light index, but doesn't activate it yet.
5400  *
5401  * Version 7, IDirect3DLight uses this method for older versions
5402  *
5403  * Params:
5404  *  LightIndex: The index of the new light
5405  *  Light: A D3DLIGHT7 structure describing the light
5406  *
5407  * Returns:
5408  *  D3D_OK on success
5409  *  For more details, see IWineD3DDevice::SetLight
5410  *
5411  *****************************************************************************/
5412 static HRESULT
5413 IDirect3DDeviceImpl_7_SetLight(IDirect3DDevice7 *iface,
5414                                DWORD LightIndex,
5415                                D3DLIGHT7 *Light)
5416 {
5417     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5418     HRESULT hr;
5419
5420     TRACE("iface %p, light_idx %u, light %p.\n", iface, LightIndex, Light);
5421
5422     wined3d_mutex_lock();
5423     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5424     hr = wined3d_device_set_light(This->wined3d_device, LightIndex, (struct wined3d_light *)Light);
5425     wined3d_mutex_unlock();
5426
5427     return hr_ddraw_from_wined3d(hr);
5428 }
5429
5430 static HRESULT WINAPI
5431 IDirect3DDeviceImpl_7_SetLight_FPUSetup(IDirect3DDevice7 *iface,
5432                                DWORD LightIndex,
5433                                D3DLIGHT7 *Light)
5434 {
5435     return IDirect3DDeviceImpl_7_SetLight(iface, LightIndex, Light);
5436 }
5437
5438 static HRESULT WINAPI
5439 IDirect3DDeviceImpl_7_SetLight_FPUPreserve(IDirect3DDevice7 *iface,
5440                                DWORD LightIndex,
5441                                D3DLIGHT7 *Light)
5442 {
5443     HRESULT hr;
5444     WORD old_fpucw;
5445
5446     old_fpucw = d3d_fpu_setup();
5447     hr = IDirect3DDeviceImpl_7_SetLight(iface, LightIndex, Light);
5448     set_fpu_control_word(old_fpucw);
5449
5450     return hr;
5451 }
5452
5453 /*****************************************************************************
5454  * IDirect3DDevice7::GetLight
5455  *
5456  * Returns the light assigned to a light index
5457  *
5458  * Params:
5459  *  Light: Structure to write the light information to
5460  *
5461  * Returns:
5462  *  D3D_OK on success
5463  *  DDERR_INVALIDPARAMS if Light is NULL
5464  *  For details, see IWineD3DDevice::GetLight
5465  *
5466  *****************************************************************************/
5467 static HRESULT
5468 IDirect3DDeviceImpl_7_GetLight(IDirect3DDevice7 *iface,
5469                                DWORD LightIndex,
5470                                D3DLIGHT7 *Light)
5471 {
5472     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5473     HRESULT rc;
5474
5475     TRACE("iface %p, light_idx %u, light %p.\n", iface, LightIndex, Light);
5476
5477     wined3d_mutex_lock();
5478     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5479     rc =  wined3d_device_get_light(This->wined3d_device, LightIndex, (struct wined3d_light *)Light);
5480     wined3d_mutex_unlock();
5481
5482     /* Translate the result. WineD3D returns other values than D3D7 */
5483     return hr_ddraw_from_wined3d(rc);
5484 }
5485
5486 static HRESULT WINAPI
5487 IDirect3DDeviceImpl_7_GetLight_FPUSetup(IDirect3DDevice7 *iface,
5488                                DWORD LightIndex,
5489                                D3DLIGHT7 *Light)
5490 {
5491     return IDirect3DDeviceImpl_7_GetLight(iface, LightIndex, Light);
5492 }
5493
5494 static HRESULT WINAPI
5495 IDirect3DDeviceImpl_7_GetLight_FPUPreserve(IDirect3DDevice7 *iface,
5496                                DWORD LightIndex,
5497                                D3DLIGHT7 *Light)
5498 {
5499     HRESULT hr;
5500     WORD old_fpucw;
5501
5502     old_fpucw = d3d_fpu_setup();
5503     hr = IDirect3DDeviceImpl_7_GetLight(iface, LightIndex, Light);
5504     set_fpu_control_word(old_fpucw);
5505
5506     return hr;
5507 }
5508
5509 /*****************************************************************************
5510  * IDirect3DDevice7::BeginStateBlock
5511  *
5512  * Begins recording to a stateblock
5513  *
5514  * Version 7
5515  *
5516  * Returns:
5517  *  D3D_OK on success
5518  *  For details see IWineD3DDevice::BeginStateBlock
5519  *
5520  *****************************************************************************/
5521 static HRESULT
5522 IDirect3DDeviceImpl_7_BeginStateBlock(IDirect3DDevice7 *iface)
5523 {
5524     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5525     HRESULT hr;
5526
5527     TRACE("iface %p.\n", iface);
5528
5529     wined3d_mutex_lock();
5530     hr = wined3d_device_begin_stateblock(This->wined3d_device);
5531     wined3d_mutex_unlock();
5532
5533     return hr_ddraw_from_wined3d(hr);
5534 }
5535
5536 static HRESULT WINAPI
5537 IDirect3DDeviceImpl_7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5538 {
5539     return IDirect3DDeviceImpl_7_BeginStateBlock(iface);
5540 }
5541
5542 static HRESULT WINAPI
5543 IDirect3DDeviceImpl_7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5544 {
5545     HRESULT hr;
5546     WORD old_fpucw;
5547
5548     old_fpucw = d3d_fpu_setup();
5549     hr = IDirect3DDeviceImpl_7_BeginStateBlock(iface);
5550     set_fpu_control_word(old_fpucw);
5551
5552     return hr;
5553 }
5554
5555 /*****************************************************************************
5556  * IDirect3DDevice7::EndStateBlock
5557  *
5558  * Stops recording to a state block and returns the created stateblock
5559  * handle.
5560  *
5561  * Version 7
5562  *
5563  * Params:
5564  *  BlockHandle: Address to store the stateblock's handle to
5565  *
5566  * Returns:
5567  *  D3D_OK on success
5568  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5569  *  See IWineD3DDevice::EndStateBlock for more details
5570  *
5571  *****************************************************************************/
5572 static HRESULT
5573 IDirect3DDeviceImpl_7_EndStateBlock(IDirect3DDevice7 *iface,
5574                                     DWORD *BlockHandle)
5575 {
5576     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5577     struct wined3d_stateblock *wined3d_sb;
5578     HRESULT hr;
5579     DWORD h;
5580
5581     TRACE("iface %p, stateblock %p.\n", iface, BlockHandle);
5582
5583     if(!BlockHandle)
5584     {
5585         WARN("BlockHandle == NULL, returning DDERR_INVALIDPARAMS\n");
5586         return DDERR_INVALIDPARAMS;
5587     }
5588
5589     wined3d_mutex_lock();
5590
5591     hr = wined3d_device_end_stateblock(This->wined3d_device, &wined3d_sb);
5592     if (FAILED(hr))
5593     {
5594         WARN("Failed to end stateblock, hr %#x.\n", hr);
5595         wined3d_mutex_unlock();
5596         *BlockHandle = 0;
5597         return hr_ddraw_from_wined3d(hr);
5598     }
5599
5600     h = ddraw_allocate_handle(&This->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5601     if (h == DDRAW_INVALID_HANDLE)
5602     {
5603         ERR("Failed to allocate a stateblock handle.\n");
5604         wined3d_stateblock_decref(wined3d_sb);
5605         wined3d_mutex_unlock();
5606         *BlockHandle = 0;
5607         return DDERR_OUTOFMEMORY;
5608     }
5609
5610     wined3d_mutex_unlock();
5611     *BlockHandle = h + 1;
5612
5613     return hr_ddraw_from_wined3d(hr);
5614 }
5615
5616 static HRESULT WINAPI
5617 IDirect3DDeviceImpl_7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5618                                     DWORD *BlockHandle)
5619 {
5620     return IDirect3DDeviceImpl_7_EndStateBlock(iface, BlockHandle);
5621 }
5622
5623 static HRESULT WINAPI
5624 IDirect3DDeviceImpl_7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5625                                     DWORD *BlockHandle)
5626 {
5627     HRESULT hr;
5628     WORD old_fpucw;
5629
5630     old_fpucw = d3d_fpu_setup();
5631     hr = IDirect3DDeviceImpl_7_EndStateBlock(iface, BlockHandle);
5632     set_fpu_control_word(old_fpucw);
5633
5634     return hr;
5635 }
5636
5637 /*****************************************************************************
5638  * IDirect3DDevice7::PreLoad
5639  *
5640  * Allows the app to signal that a texture will be used soon, to allow
5641  * the Direct3DDevice to load it to the video card in the meantime.
5642  *
5643  * Version 7
5644  *
5645  * Params:
5646  *  Texture: The texture to preload
5647  *
5648  * Returns:
5649  *  D3D_OK on success
5650  *  DDERR_INVALIDPARAMS if Texture is NULL
5651  *  See IWineD3DSurface::PreLoad for details
5652  *
5653  *****************************************************************************/
5654 static HRESULT
5655 IDirect3DDeviceImpl_7_PreLoad(IDirect3DDevice7 *iface,
5656                               IDirectDrawSurface7 *Texture)
5657 {
5658     IDirectDrawSurfaceImpl *surf = unsafe_impl_from_IDirectDrawSurface7(Texture);
5659
5660     TRACE("iface %p, texture %p.\n", iface, Texture);
5661
5662     if(!Texture)
5663         return DDERR_INVALIDPARAMS;
5664
5665     wined3d_mutex_lock();
5666     wined3d_surface_preload(surf->wined3d_surface);
5667     wined3d_mutex_unlock();
5668
5669     return D3D_OK;
5670 }
5671
5672 static HRESULT WINAPI
5673 IDirect3DDeviceImpl_7_PreLoad_FPUSetup(IDirect3DDevice7 *iface,
5674                               IDirectDrawSurface7 *Texture)
5675 {
5676     return IDirect3DDeviceImpl_7_PreLoad(iface, Texture);
5677 }
5678
5679 static HRESULT WINAPI
5680 IDirect3DDeviceImpl_7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface,
5681                               IDirectDrawSurface7 *Texture)
5682 {
5683     HRESULT hr;
5684     WORD old_fpucw;
5685
5686     old_fpucw = d3d_fpu_setup();
5687     hr = IDirect3DDeviceImpl_7_PreLoad(iface, Texture);
5688     set_fpu_control_word(old_fpucw);
5689
5690     return hr;
5691 }
5692
5693 /*****************************************************************************
5694  * IDirect3DDevice7::ApplyStateBlock
5695  *
5696  * Activates the state stored in a state block handle.
5697  *
5698  * Params:
5699  *  BlockHandle: The stateblock handle to activate
5700  *
5701  * Returns:
5702  *  D3D_OK on success
5703  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5704  *
5705  *****************************************************************************/
5706 static HRESULT
5707 IDirect3DDeviceImpl_7_ApplyStateBlock(IDirect3DDevice7 *iface,
5708                                       DWORD BlockHandle)
5709 {
5710     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5711     struct wined3d_stateblock *wined3d_sb;
5712     HRESULT hr;
5713
5714     TRACE("iface %p, stateblock %#x.\n", iface, BlockHandle);
5715
5716     wined3d_mutex_lock();
5717     wined3d_sb = ddraw_get_object(&This->handle_table, BlockHandle - 1, DDRAW_HANDLE_STATEBLOCK);
5718     if (!wined3d_sb)
5719     {
5720         WARN("Invalid stateblock handle.\n");
5721         wined3d_mutex_unlock();
5722         return D3DERR_INVALIDSTATEBLOCK;
5723     }
5724
5725     hr = wined3d_stateblock_apply(wined3d_sb);
5726     wined3d_mutex_unlock();
5727
5728     return hr_ddraw_from_wined3d(hr);
5729 }
5730
5731 static HRESULT WINAPI
5732 IDirect3DDeviceImpl_7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5733                                       DWORD BlockHandle)
5734 {
5735     return IDirect3DDeviceImpl_7_ApplyStateBlock(iface, BlockHandle);
5736 }
5737
5738 static HRESULT WINAPI
5739 IDirect3DDeviceImpl_7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5740                                       DWORD BlockHandle)
5741 {
5742     HRESULT hr;
5743     WORD old_fpucw;
5744
5745     old_fpucw = d3d_fpu_setup();
5746     hr = IDirect3DDeviceImpl_7_ApplyStateBlock(iface, BlockHandle);
5747     set_fpu_control_word(old_fpucw);
5748
5749     return hr;
5750 }
5751
5752 /*****************************************************************************
5753  * IDirect3DDevice7::CaptureStateBlock
5754  *
5755  * Updates a stateblock's values to the values currently set for the device
5756  *
5757  * Version 7
5758  *
5759  * Params:
5760  *  BlockHandle: Stateblock to update
5761  *
5762  * Returns:
5763  *  D3D_OK on success
5764  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5765  *  See IWineD3DDevice::CaptureStateBlock for more details
5766  *
5767  *****************************************************************************/
5768 static HRESULT
5769 IDirect3DDeviceImpl_7_CaptureStateBlock(IDirect3DDevice7 *iface,
5770                                         DWORD BlockHandle)
5771 {
5772     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5773     struct wined3d_stateblock *wined3d_sb;
5774     HRESULT hr;
5775
5776     TRACE("iface %p, stateblock %#x.\n", iface, BlockHandle);
5777
5778     wined3d_mutex_lock();
5779     wined3d_sb = ddraw_get_object(&This->handle_table, BlockHandle - 1, DDRAW_HANDLE_STATEBLOCK);
5780     if (!wined3d_sb)
5781     {
5782         WARN("Invalid stateblock handle.\n");
5783         wined3d_mutex_unlock();
5784         return D3DERR_INVALIDSTATEBLOCK;
5785     }
5786
5787     hr = wined3d_stateblock_capture(wined3d_sb);
5788     wined3d_mutex_unlock();
5789
5790     return hr_ddraw_from_wined3d(hr);
5791 }
5792
5793 static HRESULT WINAPI
5794 IDirect3DDeviceImpl_7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5795                                         DWORD BlockHandle)
5796 {
5797     return IDirect3DDeviceImpl_7_CaptureStateBlock(iface, BlockHandle);
5798 }
5799
5800 static HRESULT WINAPI
5801 IDirect3DDeviceImpl_7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5802                                         DWORD BlockHandle)
5803 {
5804     HRESULT hr;
5805     WORD old_fpucw;
5806
5807     old_fpucw = d3d_fpu_setup();
5808     hr = IDirect3DDeviceImpl_7_CaptureStateBlock(iface, BlockHandle);
5809     set_fpu_control_word(old_fpucw);
5810
5811     return hr;
5812 }
5813
5814 /*****************************************************************************
5815  * IDirect3DDevice7::DeleteStateBlock
5816  *
5817  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5818  *
5819  * Version 7
5820  *
5821  * Params:
5822  *  BlockHandle: Stateblock handle to delete
5823  *
5824  * Returns:
5825  *  D3D_OK on success
5826  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5827  *
5828  *****************************************************************************/
5829 static HRESULT
5830 IDirect3DDeviceImpl_7_DeleteStateBlock(IDirect3DDevice7 *iface,
5831                                        DWORD BlockHandle)
5832 {
5833     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5834     struct wined3d_stateblock *wined3d_sb;
5835     ULONG ref;
5836
5837     TRACE("iface %p, stateblock %#x.\n", iface, BlockHandle);
5838
5839     wined3d_mutex_lock();
5840
5841     wined3d_sb = ddraw_free_handle(&This->handle_table, BlockHandle - 1, DDRAW_HANDLE_STATEBLOCK);
5842     if (!wined3d_sb)
5843     {
5844         WARN("Invalid stateblock handle.\n");
5845         wined3d_mutex_unlock();
5846         return D3DERR_INVALIDSTATEBLOCK;
5847     }
5848
5849     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5850     {
5851         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5852     }
5853
5854     wined3d_mutex_unlock();
5855
5856     return D3D_OK;
5857 }
5858
5859 static HRESULT WINAPI
5860 IDirect3DDeviceImpl_7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5861                                        DWORD BlockHandle)
5862 {
5863     return IDirect3DDeviceImpl_7_DeleteStateBlock(iface, BlockHandle);
5864 }
5865
5866 static HRESULT WINAPI
5867 IDirect3DDeviceImpl_7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5868                                        DWORD BlockHandle)
5869 {
5870     HRESULT hr;
5871     WORD old_fpucw;
5872
5873     old_fpucw = d3d_fpu_setup();
5874     hr = IDirect3DDeviceImpl_7_DeleteStateBlock(iface, BlockHandle);
5875     set_fpu_control_word(old_fpucw);
5876
5877     return hr;
5878 }
5879
5880 /*****************************************************************************
5881  * IDirect3DDevice7::CreateStateBlock
5882  *
5883  * Creates a new state block handle.
5884  *
5885  * Version 7
5886  *
5887  * Params:
5888  *  Type: The state block type
5889  *  BlockHandle: Address to write the created handle to
5890  *
5891  * Returns:
5892  *   D3D_OK on success
5893  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5894  *
5895  *****************************************************************************/
5896 static HRESULT
5897 IDirect3DDeviceImpl_7_CreateStateBlock(IDirect3DDevice7 *iface,
5898                                        D3DSTATEBLOCKTYPE Type,
5899                                        DWORD *BlockHandle)
5900 {
5901     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
5902     struct wined3d_stateblock *wined3d_sb;
5903     HRESULT hr;
5904     DWORD h;
5905
5906     TRACE("iface %p, type %#x, stateblock %p.\n", iface, Type, BlockHandle);
5907
5908     if(!BlockHandle)
5909     {
5910         WARN("BlockHandle == NULL, returning DDERR_INVALIDPARAMS\n");
5911         return DDERR_INVALIDPARAMS;
5912     }
5913     if(Type != D3DSBT_ALL         && Type != D3DSBT_PIXELSTATE &&
5914        Type != D3DSBT_VERTEXSTATE                              ) {
5915         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5916         return DDERR_INVALIDPARAMS;
5917     }
5918
5919     wined3d_mutex_lock();
5920
5921     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5922     hr = wined3d_stateblock_create(This->wined3d_device, Type, &wined3d_sb);
5923     if (FAILED(hr))
5924     {
5925         WARN("Failed to create stateblock, hr %#x.\n", hr);
5926         wined3d_mutex_unlock();
5927         return hr_ddraw_from_wined3d(hr);
5928     }
5929
5930     h = ddraw_allocate_handle(&This->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5931     if (h == DDRAW_INVALID_HANDLE)
5932     {
5933         ERR("Failed to allocate stateblock handle.\n");
5934         wined3d_stateblock_decref(wined3d_sb);
5935         wined3d_mutex_unlock();
5936         return DDERR_OUTOFMEMORY;
5937     }
5938
5939     *BlockHandle = h + 1;
5940     wined3d_mutex_unlock();
5941
5942     return hr_ddraw_from_wined3d(hr);
5943 }
5944
5945 static HRESULT WINAPI
5946 IDirect3DDeviceImpl_7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5947                                        D3DSTATEBLOCKTYPE Type,
5948                                        DWORD *BlockHandle)
5949 {
5950     return IDirect3DDeviceImpl_7_CreateStateBlock(iface, Type, BlockHandle);
5951 }
5952
5953 static HRESULT WINAPI
5954 IDirect3DDeviceImpl_7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5955                                        D3DSTATEBLOCKTYPE Type,
5956                                        DWORD *BlockHandle)
5957 {
5958     HRESULT hr;
5959     WORD old_fpucw;
5960
5961     old_fpucw = d3d_fpu_setup();
5962     hr =IDirect3DDeviceImpl_7_CreateStateBlock(iface, Type, BlockHandle);
5963     set_fpu_control_word(old_fpucw);
5964
5965     return hr;
5966 }
5967
5968 /* Helper function for IDirect3DDeviceImpl_7_Load. */
5969 static BOOL is_mip_level_subset(IDirectDrawSurfaceImpl *dest,
5970                                 IDirectDrawSurfaceImpl *src)
5971 {
5972     IDirectDrawSurfaceImpl *src_level, *dest_level;
5973     IDirectDrawSurface7 *temp;
5974     DDSURFACEDESC2 ddsd;
5975     BOOL levelFound; /* at least one suitable sublevel in dest found */
5976
5977     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5978      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5979      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5980      */
5981     levelFound = FALSE;
5982
5983     src_level = src;
5984     dest_level = dest;
5985
5986     for (;src_level && dest_level;)
5987     {
5988         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5989             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5990         {
5991             levelFound = TRUE;
5992
5993             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5994             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5995             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5996
5997             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5998
5999             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6000         }
6001
6002         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6003         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6004         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6005
6006         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6007
6008         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6009     }
6010
6011     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6012     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6013
6014     return !dest_level && levelFound;
6015 }
6016
6017 /* Helper function for IDirect3DDeviceImpl_7_Load. */
6018 static void copy_mipmap_chain(IDirect3DDeviceImpl *device,
6019                               IDirectDrawSurfaceImpl *dest,
6020                               IDirectDrawSurfaceImpl *src,
6021                               const POINT *DestPoint,
6022                               const RECT *SrcRect)
6023 {
6024     IDirectDrawSurfaceImpl *src_level, *dest_level;
6025     IDirectDrawSurface7 *temp;
6026     DDSURFACEDESC2 ddsd;
6027     POINT point;
6028     RECT src_rect;
6029     HRESULT hr;
6030     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
6031     DWORD ckeyflag;
6032     DDCOLORKEY ddckey;
6033
6034     /* Copy palette, if possible. */
6035     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
6036     IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
6037
6038     if (pal_src != NULL && pal != NULL)
6039     {
6040         PALETTEENTRY palent[256];
6041
6042         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
6043         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
6044     }
6045
6046     if (pal) IDirectDrawPalette_Release(pal);
6047     if (pal_src) IDirectDrawPalette_Release(pal_src);
6048
6049     /* Copy colorkeys, if present. */
6050     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
6051     {
6052         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6053
6054         if (SUCCEEDED(hr))
6055         {
6056             IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6057         }
6058     }
6059
6060     src_level = src;
6061     dest_level = dest;
6062
6063     point = *DestPoint;
6064     src_rect = *SrcRect;
6065
6066     for (;src_level && dest_level;)
6067     {
6068         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6069             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6070         {
6071             UINT src_w = src_rect.right - src_rect.left;
6072             UINT src_h = src_rect.bottom - src_rect.top;
6073             RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
6074
6075             if (FAILED(hr = wined3d_surface_blt(dest_level->wined3d_surface, &dst_rect,
6076                     src_level->wined3d_surface, &src_rect, 0, NULL, WINED3DTEXF_POINT)))
6077                 ERR("Blit failed, hr %#x.\n", hr);
6078
6079             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6080             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6081             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6082
6083             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6084
6085             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6086         }
6087
6088         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6089         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6090         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6091
6092         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6093
6094         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6095
6096         point.x /= 2;
6097         point.y /= 2;
6098
6099         src_rect.top /= 2;
6100         src_rect.left /= 2;
6101         src_rect.right = (src_rect.right + 1) / 2;
6102         src_rect.bottom = (src_rect.bottom + 1) / 2;
6103     }
6104
6105     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6106     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6107 }
6108
6109 /*****************************************************************************
6110  * IDirect3DDevice7::Load
6111  *
6112  * Loads a rectangular area from the source into the destination texture.
6113  * It can also copy the source to the faces of a cubic environment map
6114  *
6115  * Version 7
6116  *
6117  * Params:
6118  *  DestTex: Destination texture
6119  *  DestPoint: Point in the destination where the source image should be
6120  *             written to
6121  *  SrcTex: Source texture
6122  *  SrcRect: Source rectangle
6123  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6124  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6125  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6126  *
6127  * Returns:
6128  *  D3D_OK on success
6129  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
6130  *
6131  *
6132  *****************************************************************************/
6133
6134 static HRESULT
6135 IDirect3DDeviceImpl_7_Load(IDirect3DDevice7 *iface,
6136                            IDirectDrawSurface7 *DestTex,
6137                            POINT *DestPoint,
6138                            IDirectDrawSurface7 *SrcTex,
6139                            RECT *SrcRect,
6140                            DWORD Flags)
6141 {
6142     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
6143     IDirectDrawSurfaceImpl *dest = unsafe_impl_from_IDirectDrawSurface7(DestTex);
6144     IDirectDrawSurfaceImpl *src = unsafe_impl_from_IDirectDrawSurface7(SrcTex);
6145     POINT destpoint;
6146     RECT srcrect;
6147
6148     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
6149             iface, DestTex, wine_dbgstr_point(DestPoint), SrcTex, wine_dbgstr_rect(SrcRect), Flags);
6150
6151     if( (!src) || (!dest) )
6152         return DDERR_INVALIDPARAMS;
6153
6154     wined3d_mutex_lock();
6155
6156     if (SrcRect) srcrect = *SrcRect;
6157     else
6158     {
6159         srcrect.left = srcrect.top = 0;
6160         srcrect.right = src->surface_desc.dwWidth;
6161         srcrect.bottom = src->surface_desc.dwHeight;
6162     }
6163
6164     if (DestPoint) destpoint = *DestPoint;
6165     else
6166     {
6167         destpoint.x = destpoint.y = 0;
6168     }
6169     /* Check bad dimensions. DestPoint is validated against src, not dest, because
6170      * destination can be a subset of mip levels, in which case actual coordinates used
6171      * for it may be divided. If any dimension of dest is larger than source, it can't be
6172      * mip level subset, so an error can be returned early.
6173      */
6174     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
6175         srcrect.right > src->surface_desc.dwWidth ||
6176         srcrect.bottom > src->surface_desc.dwHeight ||
6177         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6178         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6179         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6180         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6181     {
6182         wined3d_mutex_unlock();
6183         return DDERR_INVALIDPARAMS;
6184     }
6185
6186     /* Must be top level surfaces. */
6187     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6188         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6189     {
6190         wined3d_mutex_unlock();
6191         return DDERR_INVALIDPARAMS;
6192     }
6193
6194     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6195     {
6196         DWORD src_face_flag, dest_face_flag;
6197         IDirectDrawSurfaceImpl *src_face, *dest_face;
6198         IDirectDrawSurface7 *temp;
6199         DDSURFACEDESC2 ddsd;
6200         int i;
6201
6202         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6203         {
6204             wined3d_mutex_unlock();
6205             return DDERR_INVALIDPARAMS;
6206         }
6207
6208         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6209          * time it's actual surface loading. */
6210         for (i = 0; i < 2; i++)
6211         {
6212             dest_face = dest;
6213             src_face = src;
6214
6215             for (;dest_face && src_face;)
6216             {
6217                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6218                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6219
6220                 if (src_face_flag == dest_face_flag)
6221                 {
6222                     if (i == 0)
6223                     {
6224                         /* Destination mip levels must be subset of source mip levels. */
6225                         if (!is_mip_level_subset(dest_face, src_face))
6226                         {
6227                             wined3d_mutex_unlock();
6228                             return DDERR_INVALIDPARAMS;
6229                         }
6230                     }
6231                     else if (Flags & dest_face_flag)
6232                     {
6233                         copy_mipmap_chain(This, dest_face, src_face, &destpoint, &srcrect);
6234                     }
6235
6236                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6237                     {
6238                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6239                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6240                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6241
6242                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6243
6244                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6245                     }
6246                     else
6247                     {
6248                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6249
6250                         src_face = NULL;
6251                     }
6252                 }
6253
6254                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6255                 {
6256                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6257                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6258                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6259
6260                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6261
6262                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6263                 }
6264                 else
6265                 {
6266                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6267
6268                     dest_face = NULL;
6269                 }
6270             }
6271
6272             if (i == 0)
6273             {
6274                 /* Native returns error if src faces are not subset of dest faces. */
6275                 if (src_face)
6276                 {
6277                     wined3d_mutex_unlock();
6278                     return DDERR_INVALIDPARAMS;
6279                 }
6280             }
6281         }
6282
6283         wined3d_mutex_unlock();
6284         return D3D_OK;
6285     }
6286     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6287     {
6288         wined3d_mutex_unlock();
6289         return DDERR_INVALIDPARAMS;
6290     }
6291
6292     /* Handle non cube map textures. */
6293
6294     /* Destination mip levels must be subset of source mip levels. */
6295     if (!is_mip_level_subset(dest, src))
6296     {
6297         wined3d_mutex_unlock();
6298         return DDERR_INVALIDPARAMS;
6299     }
6300
6301     copy_mipmap_chain(This, dest, src, &destpoint, &srcrect);
6302
6303     wined3d_mutex_unlock();
6304
6305     return D3D_OK;
6306 }
6307
6308 static HRESULT WINAPI
6309 IDirect3DDeviceImpl_7_Load_FPUSetup(IDirect3DDevice7 *iface,
6310                            IDirectDrawSurface7 *DestTex,
6311                            POINT *DestPoint,
6312                            IDirectDrawSurface7 *SrcTex,
6313                            RECT *SrcRect,
6314                            DWORD Flags)
6315 {
6316     return IDirect3DDeviceImpl_7_Load(iface, DestTex, DestPoint, SrcTex, SrcRect, Flags);
6317 }
6318
6319 static HRESULT WINAPI
6320 IDirect3DDeviceImpl_7_Load_FPUPreserve(IDirect3DDevice7 *iface,
6321                            IDirectDrawSurface7 *DestTex,
6322                            POINT *DestPoint,
6323                            IDirectDrawSurface7 *SrcTex,
6324                            RECT *SrcRect,
6325                            DWORD Flags)
6326 {
6327     HRESULT hr;
6328     WORD old_fpucw;
6329
6330     old_fpucw = d3d_fpu_setup();
6331     hr = IDirect3DDeviceImpl_7_Load(iface, DestTex, DestPoint, SrcTex, SrcRect, Flags);
6332     set_fpu_control_word(old_fpucw);
6333
6334     return hr;
6335 }
6336
6337 /*****************************************************************************
6338  * IDirect3DDevice7::LightEnable
6339  *
6340  * Enables or disables a light
6341  *
6342  * Version 7, IDirect3DLight uses this method too.
6343  *
6344  * Params:
6345  *  LightIndex: The index of the light to enable / disable
6346  *  Enable: Enable or disable the light
6347  *
6348  * Returns:
6349  *  D3D_OK on success
6350  *  For more details, see IWineD3DDevice::SetLightEnable
6351  *
6352  *****************************************************************************/
6353 static HRESULT
6354 IDirect3DDeviceImpl_7_LightEnable(IDirect3DDevice7 *iface,
6355                                   DWORD LightIndex,
6356                                   BOOL Enable)
6357 {
6358     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
6359     HRESULT hr;
6360
6361     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, LightIndex, Enable);
6362
6363     wined3d_mutex_lock();
6364     hr = wined3d_device_set_light_enable(This->wined3d_device, LightIndex, Enable);
6365     wined3d_mutex_unlock();
6366
6367     return hr_ddraw_from_wined3d(hr);
6368 }
6369
6370 static HRESULT WINAPI
6371 IDirect3DDeviceImpl_7_LightEnable_FPUSetup(IDirect3DDevice7 *iface,
6372                                   DWORD LightIndex,
6373                                   BOOL Enable)
6374 {
6375     return IDirect3DDeviceImpl_7_LightEnable(iface, LightIndex, Enable);
6376 }
6377
6378 static HRESULT WINAPI
6379 IDirect3DDeviceImpl_7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface,
6380                                   DWORD LightIndex,
6381                                   BOOL Enable)
6382 {
6383     HRESULT hr;
6384     WORD old_fpucw;
6385
6386     old_fpucw = d3d_fpu_setup();
6387     hr = IDirect3DDeviceImpl_7_LightEnable(iface, LightIndex, Enable);
6388     set_fpu_control_word(old_fpucw);
6389
6390     return hr;
6391 }
6392
6393 /*****************************************************************************
6394  * IDirect3DDevice7::GetLightEnable
6395  *
6396  * Retrieves if the light with the given index is enabled or not
6397  *
6398  * Version 7
6399  *
6400  * Params:
6401  *  LightIndex: Index of desired light
6402  *  Enable: Pointer to a BOOL which contains the result
6403  *
6404  * Returns:
6405  *  D3D_OK on success
6406  *  DDERR_INVALIDPARAMS if Enable is NULL
6407  *  See IWineD3DDevice::GetLightEnable for more details
6408  *
6409  *****************************************************************************/
6410 static HRESULT
6411 IDirect3DDeviceImpl_7_GetLightEnable(IDirect3DDevice7 *iface,
6412                                      DWORD LightIndex,
6413                                      BOOL* Enable)
6414 {
6415     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
6416     HRESULT hr;
6417
6418     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, LightIndex, Enable);
6419
6420     if(!Enable)
6421         return DDERR_INVALIDPARAMS;
6422
6423     wined3d_mutex_lock();
6424     hr = wined3d_device_get_light_enable(This->wined3d_device, LightIndex, Enable);
6425     wined3d_mutex_unlock();
6426
6427     return hr_ddraw_from_wined3d(hr);
6428 }
6429
6430 static HRESULT WINAPI
6431 IDirect3DDeviceImpl_7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface,
6432                                      DWORD LightIndex,
6433                                      BOOL* Enable)
6434 {
6435     return IDirect3DDeviceImpl_7_GetLightEnable(iface, LightIndex, Enable);
6436 }
6437
6438 static HRESULT WINAPI
6439 IDirect3DDeviceImpl_7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface,
6440                                      DWORD LightIndex,
6441                                      BOOL* Enable)
6442 {
6443     HRESULT hr;
6444     WORD old_fpucw;
6445
6446     old_fpucw = d3d_fpu_setup();
6447     hr = IDirect3DDeviceImpl_7_GetLightEnable(iface, LightIndex, Enable);
6448     set_fpu_control_word(old_fpucw);
6449
6450     return hr;
6451 }
6452
6453 /*****************************************************************************
6454  * IDirect3DDevice7::SetClipPlane
6455  *
6456  * Sets custom clipping plane
6457  *
6458  * Version 7
6459  *
6460  * Params:
6461  *  Index: The index of the clipping plane
6462  *  PlaneEquation: An equation defining the clipping plane
6463  *
6464  * Returns:
6465  *  D3D_OK on success
6466  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6467  *  See IWineD3DDevice::SetClipPlane for more details
6468  *
6469  *****************************************************************************/
6470 static HRESULT
6471 IDirect3DDeviceImpl_7_SetClipPlane(IDirect3DDevice7 *iface,
6472                                    DWORD Index,
6473                                    D3DVALUE* PlaneEquation)
6474 {
6475     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
6476     HRESULT hr;
6477
6478     TRACE("iface %p, idx %u, plane %p.\n", iface, Index, PlaneEquation);
6479
6480     if(!PlaneEquation)
6481         return DDERR_INVALIDPARAMS;
6482
6483     wined3d_mutex_lock();
6484     hr = wined3d_device_set_clip_plane(This->wined3d_device, Index, PlaneEquation);
6485     wined3d_mutex_unlock();
6486
6487     return hr;
6488 }
6489
6490 static HRESULT WINAPI
6491 IDirect3DDeviceImpl_7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface,
6492                                    DWORD Index,
6493                                    D3DVALUE* PlaneEquation)
6494 {
6495     return IDirect3DDeviceImpl_7_SetClipPlane(iface, Index, PlaneEquation);
6496 }
6497
6498 static HRESULT WINAPI
6499 IDirect3DDeviceImpl_7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface,
6500                                    DWORD Index,
6501                                    D3DVALUE* PlaneEquation)
6502 {
6503     HRESULT hr;
6504     WORD old_fpucw;
6505
6506     old_fpucw = d3d_fpu_setup();
6507     hr = IDirect3DDeviceImpl_7_SetClipPlane(iface, Index, PlaneEquation);
6508     set_fpu_control_word(old_fpucw);
6509
6510     return hr;
6511 }
6512
6513 /*****************************************************************************
6514  * IDirect3DDevice7::GetClipPlane
6515  *
6516  * Returns the clipping plane with a specific index
6517  *
6518  * Params:
6519  *  Index: The index of the desired plane
6520  *  PlaneEquation: Address to store the plane equation to
6521  *
6522  * Returns:
6523  *  D3D_OK on success
6524  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6525  *  See IWineD3DDevice::GetClipPlane for more details
6526  *
6527  *****************************************************************************/
6528 static HRESULT
6529 IDirect3DDeviceImpl_7_GetClipPlane(IDirect3DDevice7 *iface,
6530                                    DWORD Index,
6531                                    D3DVALUE* PlaneEquation)
6532 {
6533     IDirect3DDeviceImpl *This = impl_from_IDirect3DDevice7(iface);
6534     HRESULT hr;
6535
6536     TRACE("iface %p, idx %u, plane %p.\n", iface, Index, PlaneEquation);
6537
6538     if(!PlaneEquation)
6539         return DDERR_INVALIDPARAMS;
6540
6541     wined3d_mutex_lock();
6542     hr = wined3d_device_get_clip_plane(This->wined3d_device, Index, PlaneEquation);
6543     wined3d_mutex_unlock();
6544
6545     return hr;
6546 }
6547
6548 static HRESULT WINAPI
6549 IDirect3DDeviceImpl_7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface,
6550                                    DWORD Index,
6551                                    D3DVALUE* PlaneEquation)
6552 {
6553     return IDirect3DDeviceImpl_7_GetClipPlane(iface, Index, PlaneEquation);
6554 }
6555
6556 static HRESULT WINAPI
6557 IDirect3DDeviceImpl_7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface,
6558                                    DWORD Index,
6559                                    D3DVALUE* PlaneEquation)
6560 {
6561     HRESULT hr;
6562     WORD old_fpucw;
6563
6564     old_fpucw = d3d_fpu_setup();
6565     hr = IDirect3DDeviceImpl_7_GetClipPlane(iface, Index, PlaneEquation);
6566     set_fpu_control_word(old_fpucw);
6567
6568     return hr;
6569 }
6570
6571 /*****************************************************************************
6572  * IDirect3DDevice7::GetInfo
6573  *
6574  * Retrieves some information about the device. The DirectX sdk says that
6575  * this version returns S_FALSE for all retail builds of DirectX, that's what
6576  * this implementation does.
6577  *
6578  * Params:
6579  *  DevInfoID: Information type requested
6580  *  DevInfoStruct: Pointer to a structure to store the info to
6581  *  Size: Size of the structure
6582  *
6583  * Returns:
6584  *  S_FALSE, because it's a non-debug driver
6585  *
6586  *****************************************************************************/
6587 static HRESULT WINAPI
6588 IDirect3DDeviceImpl_7_GetInfo(IDirect3DDevice7 *iface,
6589                               DWORD DevInfoID,
6590                               void *DevInfoStruct,
6591                               DWORD Size)
6592 {
6593     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6594             iface, DevInfoID, DevInfoStruct, Size);
6595
6596     if (TRACE_ON(ddraw))
6597     {
6598         TRACE(" info requested : ");
6599         switch (DevInfoID)
6600         {
6601             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6602             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6603             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6604             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6605         }
6606     }
6607
6608     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6609 }
6610
6611 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6612  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6613  * are not duplicated.
6614
6615  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6616  * has already been setup for optimal d3d operation.
6617
6618  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6619  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6620  * by Sacrifice (game). */
6621 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6622 {
6623     /*** IUnknown Methods ***/
6624     IDirect3DDeviceImpl_7_QueryInterface,
6625     IDirect3DDeviceImpl_7_AddRef,
6626     IDirect3DDeviceImpl_7_Release,
6627     /*** IDirect3DDevice7 ***/
6628     IDirect3DDeviceImpl_7_GetCaps_FPUSetup,
6629     IDirect3DDeviceImpl_7_EnumTextureFormats_FPUSetup,
6630     IDirect3DDeviceImpl_7_BeginScene_FPUSetup,
6631     IDirect3DDeviceImpl_7_EndScene_FPUSetup,
6632     IDirect3DDeviceImpl_7_GetDirect3D,
6633     IDirect3DDeviceImpl_7_SetRenderTarget_FPUSetup,
6634     IDirect3DDeviceImpl_7_GetRenderTarget,
6635     IDirect3DDeviceImpl_7_Clear_FPUSetup,
6636     IDirect3DDeviceImpl_7_SetTransform_FPUSetup,
6637     IDirect3DDeviceImpl_7_GetTransform_FPUSetup,
6638     IDirect3DDeviceImpl_7_SetViewport_FPUSetup,
6639     IDirect3DDeviceImpl_7_MultiplyTransform_FPUSetup,
6640     IDirect3DDeviceImpl_7_GetViewport_FPUSetup,
6641     IDirect3DDeviceImpl_7_SetMaterial_FPUSetup,
6642     IDirect3DDeviceImpl_7_GetMaterial_FPUSetup,
6643     IDirect3DDeviceImpl_7_SetLight_FPUSetup,
6644     IDirect3DDeviceImpl_7_GetLight_FPUSetup,
6645     IDirect3DDeviceImpl_7_SetRenderState_FPUSetup,
6646     IDirect3DDeviceImpl_7_GetRenderState_FPUSetup,
6647     IDirect3DDeviceImpl_7_BeginStateBlock_FPUSetup,
6648     IDirect3DDeviceImpl_7_EndStateBlock_FPUSetup,
6649     IDirect3DDeviceImpl_7_PreLoad_FPUSetup,
6650     IDirect3DDeviceImpl_7_DrawPrimitive_FPUSetup,
6651     IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUSetup,
6652     IDirect3DDeviceImpl_7_SetClipStatus,
6653     IDirect3DDeviceImpl_7_GetClipStatus,
6654     IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUSetup,
6655     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUSetup,
6656     IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUSetup,
6657     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUSetup,
6658     IDirect3DDeviceImpl_7_ComputeSphereVisibility,
6659     IDirect3DDeviceImpl_7_GetTexture_FPUSetup,
6660     IDirect3DDeviceImpl_7_SetTexture_FPUSetup,
6661     IDirect3DDeviceImpl_7_GetTextureStageState_FPUSetup,
6662     IDirect3DDeviceImpl_7_SetTextureStageState_FPUSetup,
6663     IDirect3DDeviceImpl_7_ValidateDevice_FPUSetup,
6664     IDirect3DDeviceImpl_7_ApplyStateBlock_FPUSetup,
6665     IDirect3DDeviceImpl_7_CaptureStateBlock_FPUSetup,
6666     IDirect3DDeviceImpl_7_DeleteStateBlock_FPUSetup,
6667     IDirect3DDeviceImpl_7_CreateStateBlock_FPUSetup,
6668     IDirect3DDeviceImpl_7_Load_FPUSetup,
6669     IDirect3DDeviceImpl_7_LightEnable_FPUSetup,
6670     IDirect3DDeviceImpl_7_GetLightEnable_FPUSetup,
6671     IDirect3DDeviceImpl_7_SetClipPlane_FPUSetup,
6672     IDirect3DDeviceImpl_7_GetClipPlane_FPUSetup,
6673     IDirect3DDeviceImpl_7_GetInfo
6674 };
6675
6676 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6677 {
6678     /*** IUnknown Methods ***/
6679     IDirect3DDeviceImpl_7_QueryInterface,
6680     IDirect3DDeviceImpl_7_AddRef,
6681     IDirect3DDeviceImpl_7_Release,
6682     /*** IDirect3DDevice7 ***/
6683     IDirect3DDeviceImpl_7_GetCaps_FPUPreserve,
6684     IDirect3DDeviceImpl_7_EnumTextureFormats_FPUPreserve,
6685     IDirect3DDeviceImpl_7_BeginScene_FPUPreserve,
6686     IDirect3DDeviceImpl_7_EndScene_FPUPreserve,
6687     IDirect3DDeviceImpl_7_GetDirect3D,
6688     IDirect3DDeviceImpl_7_SetRenderTarget_FPUPreserve,
6689     IDirect3DDeviceImpl_7_GetRenderTarget,
6690     IDirect3DDeviceImpl_7_Clear_FPUPreserve,
6691     IDirect3DDeviceImpl_7_SetTransform_FPUPreserve,
6692     IDirect3DDeviceImpl_7_GetTransform_FPUPreserve,
6693     IDirect3DDeviceImpl_7_SetViewport_FPUPreserve,
6694     IDirect3DDeviceImpl_7_MultiplyTransform_FPUPreserve,
6695     IDirect3DDeviceImpl_7_GetViewport_FPUPreserve,
6696     IDirect3DDeviceImpl_7_SetMaterial_FPUPreserve,
6697     IDirect3DDeviceImpl_7_GetMaterial_FPUPreserve,
6698     IDirect3DDeviceImpl_7_SetLight_FPUPreserve,
6699     IDirect3DDeviceImpl_7_GetLight_FPUPreserve,
6700     IDirect3DDeviceImpl_7_SetRenderState_FPUPreserve,
6701     IDirect3DDeviceImpl_7_GetRenderState_FPUPreserve,
6702     IDirect3DDeviceImpl_7_BeginStateBlock_FPUPreserve,
6703     IDirect3DDeviceImpl_7_EndStateBlock_FPUPreserve,
6704     IDirect3DDeviceImpl_7_PreLoad_FPUPreserve,
6705     IDirect3DDeviceImpl_7_DrawPrimitive_FPUPreserve,
6706     IDirect3DDeviceImpl_7_DrawIndexedPrimitive_FPUPreserve,
6707     IDirect3DDeviceImpl_7_SetClipStatus,
6708     IDirect3DDeviceImpl_7_GetClipStatus,
6709     IDirect3DDeviceImpl_7_DrawPrimitiveStrided_FPUPreserve,
6710     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveStrided_FPUPreserve,
6711     IDirect3DDeviceImpl_7_DrawPrimitiveVB_FPUPreserve,
6712     IDirect3DDeviceImpl_7_DrawIndexedPrimitiveVB_FPUPreserve,
6713     IDirect3DDeviceImpl_7_ComputeSphereVisibility,
6714     IDirect3DDeviceImpl_7_GetTexture_FPUPreserve,
6715     IDirect3DDeviceImpl_7_SetTexture_FPUPreserve,
6716     IDirect3DDeviceImpl_7_GetTextureStageState_FPUPreserve,
6717     IDirect3DDeviceImpl_7_SetTextureStageState_FPUPreserve,
6718     IDirect3DDeviceImpl_7_ValidateDevice_FPUPreserve,
6719     IDirect3DDeviceImpl_7_ApplyStateBlock_FPUPreserve,
6720     IDirect3DDeviceImpl_7_CaptureStateBlock_FPUPreserve,
6721     IDirect3DDeviceImpl_7_DeleteStateBlock_FPUPreserve,
6722     IDirect3DDeviceImpl_7_CreateStateBlock_FPUPreserve,
6723     IDirect3DDeviceImpl_7_Load_FPUPreserve,
6724     IDirect3DDeviceImpl_7_LightEnable_FPUPreserve,
6725     IDirect3DDeviceImpl_7_GetLightEnable_FPUPreserve,
6726     IDirect3DDeviceImpl_7_SetClipPlane_FPUPreserve,
6727     IDirect3DDeviceImpl_7_GetClipPlane_FPUPreserve,
6728     IDirect3DDeviceImpl_7_GetInfo
6729 };
6730
6731 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6732 {
6733     /*** IUnknown Methods ***/
6734     IDirect3DDeviceImpl_3_QueryInterface,
6735     IDirect3DDeviceImpl_3_AddRef,
6736     IDirect3DDeviceImpl_3_Release,
6737     /*** IDirect3DDevice3 ***/
6738     IDirect3DDeviceImpl_3_GetCaps,
6739     IDirect3DDeviceImpl_3_GetStats,
6740     IDirect3DDeviceImpl_3_AddViewport,
6741     IDirect3DDeviceImpl_3_DeleteViewport,
6742     IDirect3DDeviceImpl_3_NextViewport,
6743     IDirect3DDeviceImpl_3_EnumTextureFormats,
6744     IDirect3DDeviceImpl_3_BeginScene,
6745     IDirect3DDeviceImpl_3_EndScene,
6746     IDirect3DDeviceImpl_3_GetDirect3D,
6747     IDirect3DDeviceImpl_3_SetCurrentViewport,
6748     IDirect3DDeviceImpl_3_GetCurrentViewport,
6749     IDirect3DDeviceImpl_3_SetRenderTarget,
6750     IDirect3DDeviceImpl_3_GetRenderTarget,
6751     IDirect3DDeviceImpl_3_Begin,
6752     IDirect3DDeviceImpl_3_BeginIndexed,
6753     IDirect3DDeviceImpl_3_Vertex,
6754     IDirect3DDeviceImpl_3_Index,
6755     IDirect3DDeviceImpl_3_End,
6756     IDirect3DDeviceImpl_3_GetRenderState,
6757     IDirect3DDeviceImpl_3_SetRenderState,
6758     IDirect3DDeviceImpl_3_GetLightState,
6759     IDirect3DDeviceImpl_3_SetLightState,
6760     IDirect3DDeviceImpl_3_SetTransform,
6761     IDirect3DDeviceImpl_3_GetTransform,
6762     IDirect3DDeviceImpl_3_MultiplyTransform,
6763     IDirect3DDeviceImpl_3_DrawPrimitive,
6764     IDirect3DDeviceImpl_3_DrawIndexedPrimitive,
6765     IDirect3DDeviceImpl_3_SetClipStatus,
6766     IDirect3DDeviceImpl_3_GetClipStatus,
6767     IDirect3DDeviceImpl_3_DrawPrimitiveStrided,
6768     IDirect3DDeviceImpl_3_DrawIndexedPrimitiveStrided,
6769     IDirect3DDeviceImpl_3_DrawPrimitiveVB,
6770     IDirect3DDeviceImpl_3_DrawIndexedPrimitiveVB,
6771     IDirect3DDeviceImpl_3_ComputeSphereVisibility,
6772     IDirect3DDeviceImpl_3_GetTexture,
6773     IDirect3DDeviceImpl_3_SetTexture,
6774     IDirect3DDeviceImpl_3_GetTextureStageState,
6775     IDirect3DDeviceImpl_3_SetTextureStageState,
6776     IDirect3DDeviceImpl_3_ValidateDevice
6777 };
6778
6779 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6780 {
6781     /*** IUnknown Methods ***/
6782     IDirect3DDeviceImpl_2_QueryInterface,
6783     IDirect3DDeviceImpl_2_AddRef,
6784     IDirect3DDeviceImpl_2_Release,
6785     /*** IDirect3DDevice2 ***/
6786     IDirect3DDeviceImpl_2_GetCaps,
6787     IDirect3DDeviceImpl_2_SwapTextureHandles,
6788     IDirect3DDeviceImpl_2_GetStats,
6789     IDirect3DDeviceImpl_2_AddViewport,
6790     IDirect3DDeviceImpl_2_DeleteViewport,
6791     IDirect3DDeviceImpl_2_NextViewport,
6792     IDirect3DDeviceImpl_2_EnumTextureFormats,
6793     IDirect3DDeviceImpl_2_BeginScene,
6794     IDirect3DDeviceImpl_2_EndScene,
6795     IDirect3DDeviceImpl_2_GetDirect3D,
6796     IDirect3DDeviceImpl_2_SetCurrentViewport,
6797     IDirect3DDeviceImpl_2_GetCurrentViewport,
6798     IDirect3DDeviceImpl_2_SetRenderTarget,
6799     IDirect3DDeviceImpl_2_GetRenderTarget,
6800     IDirect3DDeviceImpl_2_Begin,
6801     IDirect3DDeviceImpl_2_BeginIndexed,
6802     IDirect3DDeviceImpl_2_Vertex,
6803     IDirect3DDeviceImpl_2_Index,
6804     IDirect3DDeviceImpl_2_End,
6805     IDirect3DDeviceImpl_2_GetRenderState,
6806     IDirect3DDeviceImpl_2_SetRenderState,
6807     IDirect3DDeviceImpl_2_GetLightState,
6808     IDirect3DDeviceImpl_2_SetLightState,
6809     IDirect3DDeviceImpl_2_SetTransform,
6810     IDirect3DDeviceImpl_2_GetTransform,
6811     IDirect3DDeviceImpl_2_MultiplyTransform,
6812     IDirect3DDeviceImpl_2_DrawPrimitive,
6813     IDirect3DDeviceImpl_2_DrawIndexedPrimitive,
6814     IDirect3DDeviceImpl_2_SetClipStatus,
6815     IDirect3DDeviceImpl_2_GetClipStatus
6816 };
6817
6818 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6819 {
6820     /*** IUnknown Methods ***/
6821     IDirect3DDeviceImpl_1_QueryInterface,
6822     IDirect3DDeviceImpl_1_AddRef,
6823     IDirect3DDeviceImpl_1_Release,
6824     /*** IDirect3DDevice1 ***/
6825     IDirect3DDeviceImpl_1_Initialize,
6826     IDirect3DDeviceImpl_1_GetCaps,
6827     IDirect3DDeviceImpl_1_SwapTextureHandles,
6828     IDirect3DDeviceImpl_1_CreateExecuteBuffer,
6829     IDirect3DDeviceImpl_1_GetStats,
6830     IDirect3DDeviceImpl_1_Execute,
6831     IDirect3DDeviceImpl_1_AddViewport,
6832     IDirect3DDeviceImpl_1_DeleteViewport,
6833     IDirect3DDeviceImpl_1_NextViewport,
6834     IDirect3DDeviceImpl_1_Pick,
6835     IDirect3DDeviceImpl_1_GetPickRecords,
6836     IDirect3DDeviceImpl_1_EnumTextureFormats,
6837     IDirect3DDeviceImpl_1_CreateMatrix,
6838     IDirect3DDeviceImpl_1_SetMatrix,
6839     IDirect3DDeviceImpl_1_GetMatrix,
6840     IDirect3DDeviceImpl_1_DeleteMatrix,
6841     IDirect3DDeviceImpl_1_BeginScene,
6842     IDirect3DDeviceImpl_1_EndScene,
6843     IDirect3DDeviceImpl_1_GetDirect3D
6844 };
6845
6846 IDirect3DDeviceImpl *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6847 {
6848     if (!iface) return NULL;
6849     assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6850     return CONTAINING_RECORD(iface, IDirect3DDeviceImpl, IDirect3DDevice7_iface);
6851 }
6852
6853 IDirect3DDeviceImpl *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6854 {
6855     if (!iface) return NULL;
6856     assert(iface->lpVtbl == &d3d_device3_vtbl);
6857     return CONTAINING_RECORD(iface, IDirect3DDeviceImpl, IDirect3DDevice3_iface);
6858 }
6859
6860 IDirect3DDeviceImpl *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6861 {
6862     if (!iface) return NULL;
6863     assert(iface->lpVtbl == &d3d_device2_vtbl);
6864     return CONTAINING_RECORD(iface, IDirect3DDeviceImpl, IDirect3DDevice2_iface);
6865 }
6866
6867 IDirect3DDeviceImpl *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6868 {
6869     if (!iface) return NULL;
6870     assert(iface->lpVtbl == &d3d_device1_vtbl);
6871     return CONTAINING_RECORD(iface, IDirect3DDeviceImpl, IDirect3DDevice_iface);
6872 }
6873
6874 /*****************************************************************************
6875  * IDirect3DDeviceImpl_UpdateDepthStencil
6876  *
6877  * Checks the current render target for attached depth stencils and sets the
6878  * WineD3D depth stencil accordingly.
6879  *
6880  * Returns:
6881  *  The depth stencil state to set if creating the device
6882  *
6883  *****************************************************************************/
6884 WINED3DZBUFFERTYPE
6885 IDirect3DDeviceImpl_UpdateDepthStencil(IDirect3DDeviceImpl *This)
6886 {
6887     IDirectDrawSurface7 *depthStencil = NULL;
6888     IDirectDrawSurfaceImpl *dsi;
6889     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6890
6891     IDirectDrawSurface7_GetAttachedSurface(&This->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
6892     if(!depthStencil)
6893     {
6894         TRACE("Setting wined3d depth stencil to NULL\n");
6895         wined3d_device_set_depth_stencil(This->wined3d_device, NULL);
6896         return WINED3DZB_FALSE;
6897     }
6898
6899     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6900     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6901     wined3d_device_set_depth_stencil(This->wined3d_device, dsi->wined3d_surface);
6902
6903     IDirectDrawSurface7_Release(depthStencil);
6904     return WINED3DZB_TRUE;
6905 }
6906
6907 HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *target)
6908 {
6909     HRESULT hr;
6910
6911     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6912         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6913     else
6914         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6915
6916     device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6917     device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6918     device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6919     device->ref = 1;
6920     device->ddraw = ddraw;
6921     device->target = target;
6922     list_init(&device->viewport_list);
6923
6924     if (!ddraw_handle_table_init(&device->handle_table, 64))
6925     {
6926         ERR("Failed to initialize handle table.\n");
6927         return DDERR_OUTOFMEMORY;
6928     }
6929
6930     device->legacyTextureBlending = FALSE;
6931
6932     /* Create an index buffer, it's needed for indexed drawing */
6933     hr = wined3d_buffer_create_ib(ddraw->wined3d_device, 0x40000 /* Length. Don't know how long it should be */,
6934             WINED3DUSAGE_DYNAMIC /* Usage */, WINED3DPOOL_DEFAULT, NULL,
6935             &ddraw_null_wined3d_parent_ops, &device->indexbuffer);
6936     if (FAILED(hr))
6937     {
6938         ERR("Failed to create an index buffer, hr %#x.\n", hr);
6939         ddraw_handle_table_destroy(&device->handle_table);
6940         return hr;
6941     }
6942
6943     /* This is for convenience. */
6944     device->wined3d_device = ddraw->wined3d_device;
6945     wined3d_device_incref(ddraw->wined3d_device);
6946
6947     /* Render to the back buffer */
6948     hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6949     if (FAILED(hr))
6950     {
6951         ERR("Failed to set render target, hr %#x.\n", hr);
6952         wined3d_buffer_decref(device->indexbuffer);
6953         ddraw_handle_table_destroy(&device->handle_table);
6954         return hr;
6955     }
6956
6957     /* FIXME: This is broken. The target AddRef() makes some sense, because
6958      * we store a pointer during initialization, but then that's also where
6959      * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
6960     /* AddRef the render target. Also AddRef the render target from ddraw,
6961      * because if it is released before the app releases the D3D device, the
6962      * D3D capabilities of wined3d will be uninitialized, which has bad effects.
6963      *
6964      * In most cases, those surfaces are the same anyway, but this will simply
6965      * add another ref which is released when the device is destroyed. */
6966     IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6967
6968     ddraw->d3ddevice = device;
6969
6970     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3DRS_ZENABLE,
6971             IDirect3DDeviceImpl_UpdateDepthStencil(device));
6972
6973     return D3D_OK;
6974 }