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