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