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