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