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