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