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