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