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