mfreadwrite/reader: Add missing allocation check (Coverity).
[wine/zf.git] / dlls / ddraw / device.c
blob52d20fc5a62f3acd7fbd50239540f3464365165e
1 /*
2 * Copyright (c) 1998-2004 Lionel Ulmer
3 * Copyright (c) 2002-2005 Christian Costa
4 * Copyright (c) 2006-2009, 2011-2013 Stefan Dösinger
5 * Copyright (c) 2008 Alexander Dorofeyev
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.
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.
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
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.
30 #include "ddraw_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
33 WINE_DECLARE_DEBUG_CHANNEL(winediag);
35 /* The device ID */
36 const GUID IID_D3DDEVICE_WineD3D = {
37 0xaef72d43,
38 0xb09a,
39 0x4b7b,
40 { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
43 static inline void set_fpu_control_word(WORD fpucw)
45 #if defined(__i386__) && defined(__GNUC__)
46 __asm__ volatile ("fldcw %0" : : "m" (fpucw));
47 #elif defined(__i386__) && defined(_MSC_VER)
48 __asm fldcw fpucw;
49 #endif
52 static inline WORD d3d_fpu_setup(void)
54 WORD oldcw;
56 #if defined(__i386__) && defined(__GNUC__)
57 __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
58 #elif defined(__i386__) && defined(_MSC_VER)
59 __asm fnstcw oldcw;
60 #else
61 static BOOL warned = FALSE;
62 if(!warned)
64 FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
65 warned = TRUE;
67 return 0;
68 #endif
70 set_fpu_control_word(0x37f);
72 return oldcw;
75 static enum wined3d_render_state wined3d_render_state_from_ddraw(D3DRENDERSTATETYPE state)
77 switch (state)
79 case D3DRENDERSTATE_ZBIAS:
80 return WINED3D_RS_DEPTHBIAS;
81 case D3DRENDERSTATE_EDGEANTIALIAS:
82 return WINED3D_RS_ANTIALIASEDLINEENABLE;
83 default:
84 return (enum wined3d_render_state)state;
88 static enum wined3d_transform_state wined3d_transform_state_from_ddraw(D3DTRANSFORMSTATETYPE state)
90 switch (state)
92 case D3DTRANSFORMSTATE_WORLD:
93 return WINED3D_TS_WORLD_MATRIX(0);
94 case D3DTRANSFORMSTATE_WORLD1:
95 return WINED3D_TS_WORLD_MATRIX(1);
96 case D3DTRANSFORMSTATE_WORLD2:
97 return WINED3D_TS_WORLD_MATRIX(2);
98 case D3DTRANSFORMSTATE_WORLD3:
99 return WINED3D_TS_WORLD_MATRIX(3);
100 default:
101 return (enum wined3d_transform_state)state;
105 static enum wined3d_primitive_type wined3d_primitive_type_from_ddraw(D3DPRIMITIVETYPE type)
107 return (enum wined3d_primitive_type)type;
110 static enum wined3d_stateblock_type wined3d_stateblock_type_from_ddraw(D3DSTATEBLOCKTYPE type)
112 return (enum wined3d_stateblock_type)type;
115 static inline struct d3d_device *impl_from_IUnknown(IUnknown *iface)
117 return CONTAINING_RECORD(iface, struct d3d_device, IUnknown_inner);
120 static HRESULT WINAPI d3d_device_inner_QueryInterface(IUnknown *iface, REFIID riid, void **out)
122 struct d3d_device *device = impl_from_IUnknown(iface);
124 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
126 if (!riid)
128 *out = NULL;
129 return DDERR_INVALIDPARAMS;
132 if (IsEqualGUID(&IID_IUnknown, riid))
134 IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
135 *out = &device->IDirect3DDevice7_iface;
136 return S_OK;
139 if (device->version == 7)
141 if (IsEqualGUID(&IID_IDirect3DDevice7, riid))
143 IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
144 *out = &device->IDirect3DDevice7_iface;
145 return S_OK;
148 else
150 if (IsEqualGUID(&IID_IDirect3DDevice3, riid) && device->version == 3)
152 IDirect3DDevice3_AddRef(&device->IDirect3DDevice3_iface);
153 *out = &device->IDirect3DDevice3_iface;
154 return S_OK;
157 if (IsEqualGUID(&IID_IDirect3DDevice2, riid) && device->version >= 2)
159 IDirect3DDevice2_AddRef(&device->IDirect3DDevice2_iface);
160 *out = &device->IDirect3DDevice2_iface;
161 return S_OK;
164 if (IsEqualGUID(&IID_IDirect3DDevice, riid))
166 IDirect3DDevice_AddRef(&device->IDirect3DDevice_iface);
167 *out = &device->IDirect3DDevice_iface;
168 return S_OK;
172 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
174 *out = NULL;
175 return E_NOINTERFACE;
178 static HRESULT WINAPI d3d_device7_QueryInterface(IDirect3DDevice7 *iface, REFIID riid, void **out)
180 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
182 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
184 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
187 static HRESULT WINAPI d3d_device3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid, void **out)
189 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
191 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
193 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
196 static HRESULT WINAPI d3d_device2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid, void **out)
198 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
200 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
202 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
205 static HRESULT WINAPI d3d_device1_QueryInterface(IDirect3DDevice *iface, REFIID riid, void **out)
207 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
209 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
211 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
214 static ULONG WINAPI d3d_device_inner_AddRef(IUnknown *iface)
216 struct d3d_device *device = impl_from_IUnknown(iface);
217 ULONG ref = InterlockedIncrement(&device->ref);
219 TRACE("%p increasing refcount to %u.\n", device, ref);
221 return ref;
224 static ULONG WINAPI d3d_device7_AddRef(IDirect3DDevice7 *iface)
226 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
228 TRACE("iface %p.\n", iface);
230 return IUnknown_AddRef(device->outer_unknown);
233 static ULONG WINAPI d3d_device3_AddRef(IDirect3DDevice3 *iface)
235 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
237 TRACE("iface %p.\n", iface);
239 return IUnknown_AddRef(device->outer_unknown);
242 static ULONG WINAPI d3d_device2_AddRef(IDirect3DDevice2 *iface)
244 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
246 TRACE("iface %p.\n", iface);
248 return IUnknown_AddRef(device->outer_unknown);
251 static ULONG WINAPI d3d_device1_AddRef(IDirect3DDevice *iface)
253 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
255 TRACE("iface %p.\n", iface);
257 return IUnknown_AddRef(device->outer_unknown);
260 static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
262 struct d3d_device *This = impl_from_IUnknown(iface);
263 ULONG ref = InterlockedDecrement(&This->ref);
264 IUnknown *rt_iface;
266 TRACE("%p decreasing refcount to %u.\n", This, ref);
268 /* This method doesn't destroy the wined3d device, because it's still in
269 * use for 2D rendering. IDirectDrawSurface7::Release will destroy the
270 * wined3d device when the render target is released. */
271 if (!ref)
273 DWORD i;
274 struct list *vp_entry, *vp_entry2;
276 wined3d_mutex_lock();
278 /* There is no need to unset any resources here, wined3d will take
279 * care of that on uninit_3d(). */
281 if (This->index_buffer)
282 wined3d_buffer_decref(This->index_buffer);
283 if (This->vertex_buffer)
284 wined3d_buffer_decref(This->vertex_buffer);
286 wined3d_device_context_set_rendertarget_view(This->immediate_context, 0, NULL, FALSE);
288 wined3d_stateblock_decref(This->state);
289 if (This->recording)
290 wined3d_stateblock_decref(This->recording);
292 /* Release the wined3d device. This won't destroy it. */
293 if (!wined3d_device_decref(This->wined3d_device))
294 ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
296 /* The texture handles should be unset by now, but there might be some bits
297 * missing in our reference counting(needs test). Do a sanity check. */
298 for (i = 0; i < This->handle_table.entry_count; ++i)
300 struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
302 switch (entry->type)
304 case DDRAW_HANDLE_FREE:
305 break;
307 case DDRAW_HANDLE_MATERIAL:
309 struct d3d_material *m = entry->object;
310 FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
311 m->Handle = 0;
312 break;
315 case DDRAW_HANDLE_MATRIX:
317 /* No FIXME here because this might happen because of sloppy applications. */
318 WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
319 IDirect3DDevice_DeleteMatrix(&This->IDirect3DDevice_iface, i + 1);
320 break;
323 case DDRAW_HANDLE_STATEBLOCK:
325 /* No FIXME here because this might happen because of sloppy applications. */
326 WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
327 IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
328 break;
331 case DDRAW_HANDLE_SURFACE:
333 struct ddraw_surface *surf = entry->object;
334 FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
335 surf->Handle = 0;
336 break;
339 default:
340 FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
341 break;
345 ddraw_handle_table_destroy(&This->handle_table);
347 LIST_FOR_EACH_SAFE(vp_entry, vp_entry2, &This->viewport_list)
349 struct d3d_viewport *vp = LIST_ENTRY(vp_entry, struct d3d_viewport, entry);
350 IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
353 TRACE("Releasing render target %p.\n", This->rt_iface);
354 rt_iface = This->rt_iface;
355 This->rt_iface = NULL;
356 if (This->version != 1)
357 IUnknown_Release(rt_iface);
358 TRACE("Render target release done.\n");
360 /* Releasing the render target above may have released the last
361 * reference to the ddraw object. */
362 if (This->ddraw)
363 This->ddraw->d3ddevice = NULL;
365 /* Now free the structure */
366 heap_free(This);
367 wined3d_mutex_unlock();
370 TRACE("Done\n");
371 return ref;
374 static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
376 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
378 TRACE("iface %p.\n", iface);
380 return IUnknown_Release(device->outer_unknown);
383 static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
385 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
387 TRACE("iface %p.\n", iface);
389 return IUnknown_Release(device->outer_unknown);
392 static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
394 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
396 TRACE("iface %p.\n", iface);
398 return IUnknown_Release(device->outer_unknown);
401 static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
403 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
405 TRACE("iface %p.\n", iface);
407 return IUnknown_Release(device->outer_unknown);
410 /*****************************************************************************
411 * IDirect3DDevice Methods
412 *****************************************************************************/
414 /*****************************************************************************
415 * IDirect3DDevice::Initialize
417 * Initializes a Direct3DDevice. This implementation is a no-op, as all
418 * initialization is done at create time.
420 * Exists in Version 1
422 * Parameters:
423 * No idea what they mean, as the MSDN page is gone
425 * Returns: DD_OK
427 *****************************************************************************/
428 static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
429 IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
431 /* It shouldn't be crucial, but print a FIXME, I'm interested if
432 * any game calls it and when. */
433 FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
434 iface, d3d, debugstr_guid(guid), device_desc);
436 return D3D_OK;
439 static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *device_desc)
441 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
443 TRACE("iface %p, device_desc %p.\n", iface, device_desc);
445 if (!device_desc)
447 WARN("device_desc is NULL, returning DDERR_INVALIDPARAMS.\n");
448 return DDERR_INVALIDPARAMS;
451 /* Call the same function used by IDirect3D, this saves code */
452 return ddraw_get_d3dcaps(device->ddraw, device_desc);
455 static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
457 return d3d_device7_GetCaps(iface, desc);
460 static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
462 HRESULT hr;
463 WORD old_fpucw;
465 old_fpucw = d3d_fpu_setup();
466 hr = d3d_device7_GetCaps(iface, desc);
467 set_fpu_control_word(old_fpucw);
469 return hr;
471 /*****************************************************************************
472 * IDirect3DDevice3::GetCaps
474 * Retrieves the capabilities of the hardware device and the emulation
475 * device. For Wine, hardware and emulation are the same (it's all HW).
477 * This implementation is used for Version 1, 2, and 3. Version 7 has its own
479 * Parameters:
480 * HWDesc: Structure to fill with the HW caps
481 * HelDesc: Structure to fill with the hardware emulation caps
483 * Returns:
484 * D3D_OK on success
485 * D3DERR_* if a problem occurs. See WineD3D
487 *****************************************************************************/
489 /* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
490 * Microsoft just expanded the existing structure without naming them
491 * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
492 * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
493 * one with 252 bytes.
495 * All 3 versions are allowed as parameters and only the specified amount of
496 * bytes is written.
498 * Note that Direct3D7 and earlier are not available in native Win64
499 * ddraw.dll builds, so possible size differences between 32 bit and
500 * 64 bit are a non-issue.
502 static inline BOOL check_d3ddevicedesc_size(DWORD size)
504 if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
505 || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
506 || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
507 return FALSE;
510 static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
511 D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
513 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
514 D3DDEVICEDESC7 desc7;
515 D3DDEVICEDESC desc1;
516 HRESULT hr;
518 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
520 if (!HWDesc)
522 WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
523 return DDERR_INVALIDPARAMS;
525 if (!check_d3ddevicedesc_size(HWDesc->dwSize))
527 WARN("HWDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
528 return DDERR_INVALIDPARAMS;
530 if (!HelDesc)
532 WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
533 return DDERR_INVALIDPARAMS;
535 if (!check_d3ddevicedesc_size(HelDesc->dwSize))
537 WARN("HelDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
538 return DDERR_INVALIDPARAMS;
541 if (FAILED(hr = ddraw_get_d3dcaps(device->ddraw, &desc7)))
542 return hr;
544 ddraw_d3dcaps1_from_7(&desc1, &desc7);
545 DD_STRUCT_COPY_BYSIZE(HWDesc, &desc1);
546 DD_STRUCT_COPY_BYSIZE(HelDesc, &desc1);
547 return D3D_OK;
550 static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
551 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
553 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
555 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
557 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
560 static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
561 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
563 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
565 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
567 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
570 /*****************************************************************************
571 * IDirect3DDevice2::SwapTextureHandles
573 * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
575 * Parameters:
576 * Tex1, Tex2: The 2 Textures to swap
578 * Returns:
579 * D3D_OK
581 *****************************************************************************/
582 static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
583 IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
585 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
586 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
587 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
588 DWORD h1, h2;
590 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
592 wined3d_mutex_lock();
594 h1 = surf1->Handle - 1;
595 h2 = surf2->Handle - 1;
596 device->handle_table.entries[h1].object = surf2;
597 device->handle_table.entries[h2].object = surf1;
598 surf2->Handle = h1 + 1;
599 surf1->Handle = h2 + 1;
601 wined3d_mutex_unlock();
603 return D3D_OK;
606 static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
607 IDirect3DTexture *tex1, IDirect3DTexture *tex2)
609 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
610 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
611 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
612 IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
613 IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
615 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
617 return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
620 /*****************************************************************************
621 * IDirect3DDevice3::GetStats
623 * This method seems to retrieve some stats from the device.
624 * The MSDN documentation doesn't exist any more, but the D3DSTATS
625 * structure suggests that the amount of drawn primitives and processed
626 * vertices is returned.
628 * Exists in Version 1, 2 and 3
630 * Parameters:
631 * Stats: Pointer to a D3DSTATS structure to be filled
633 * Returns:
634 * D3D_OK on success
635 * DDERR_INVALIDPARAMS if Stats == NULL
637 *****************************************************************************/
638 static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
640 FIXME("iface %p, stats %p stub!\n", iface, Stats);
642 if(!Stats)
643 return DDERR_INVALIDPARAMS;
645 /* Fill the Stats with 0 */
646 Stats->dwTrianglesDrawn = 0;
647 Stats->dwLinesDrawn = 0;
648 Stats->dwPointsDrawn = 0;
649 Stats->dwSpansDrawn = 0;
650 Stats->dwVerticesProcessed = 0;
652 return D3D_OK;
655 static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
657 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
659 TRACE("iface %p, stats %p.\n", iface, stats);
661 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
664 static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
666 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
668 TRACE("iface %p, stats %p.\n", iface, stats);
670 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
673 /*****************************************************************************
674 * IDirect3DDevice::CreateExecuteBuffer
676 * Creates an IDirect3DExecuteBuffer, used for rendering with a
677 * Direct3DDevice.
679 * Version 1 only.
681 * Params:
682 * Desc: Buffer description
683 * ExecuteBuffer: Address to return the Interface pointer at
684 * UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
685 * support
687 * Returns:
688 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
689 * DDERR_OUTOFMEMORY if we ran out of memory
690 * D3D_OK on success
692 *****************************************************************************/
693 static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
694 D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
696 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
697 struct d3d_execute_buffer *object;
698 HRESULT hr;
700 TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
701 iface, buffer_desc, ExecuteBuffer, outer_unknown);
703 if (outer_unknown)
704 return CLASS_E_NOAGGREGATION;
706 /* Allocate the new Execute Buffer */
707 if (!(object = heap_alloc_zero(sizeof(*object))))
709 ERR("Failed to allocate execute buffer memory.\n");
710 return DDERR_OUTOFMEMORY;
713 hr = d3d_execute_buffer_init(object, device, buffer_desc);
714 if (FAILED(hr))
716 WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
717 heap_free(object);
718 return hr;
721 *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
723 TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
725 return D3D_OK;
728 /*****************************************************************************
729 * IDirect3DDevice::Execute
731 * Executes all the stuff in an execute buffer.
733 * Params:
734 * ExecuteBuffer: The buffer to execute
735 * Viewport: The viewport used for rendering
736 * Flags: Some flags
738 * Returns:
739 * DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
740 * D3D_OK on success
742 *****************************************************************************/
743 static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
744 IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
746 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
747 struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
748 struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
749 HRESULT hr;
751 TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, viewport, flags);
753 if(!buffer)
754 return DDERR_INVALIDPARAMS;
756 if (FAILED(hr = IDirect3DDevice3_SetCurrentViewport
757 (&device->IDirect3DDevice3_iface, &viewport_impl->IDirect3DViewport3_iface)))
758 return hr;
760 /* Execute... */
761 wined3d_mutex_lock();
762 hr = d3d_execute_buffer_execute(buffer, device);
763 wined3d_mutex_unlock();
765 return hr;
768 /*****************************************************************************
769 * IDirect3DDevice3::AddViewport
771 * Add a Direct3DViewport to the device's viewport list. These viewports
772 * are wrapped to IDirect3DDevice7 viewports in viewport.c
774 * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
775 * are the same interfaces.
777 * Params:
778 * Viewport: The viewport to add
780 * Returns:
781 * DDERR_INVALIDPARAMS if Viewport == NULL
782 * D3D_OK on success
784 *****************************************************************************/
785 static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
787 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
788 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
790 TRACE("iface %p, viewport %p.\n", iface, viewport);
792 /* Sanity check */
793 if(!vp)
794 return DDERR_INVALIDPARAMS;
796 wined3d_mutex_lock();
797 IDirect3DViewport3_AddRef(viewport);
798 list_add_head(&device->viewport_list, &vp->entry);
799 /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
800 vp->active_device = device;
801 wined3d_mutex_unlock();
803 return D3D_OK;
806 static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
807 IDirect3DViewport2 *viewport)
809 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
810 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
812 TRACE("iface %p, viewport %p.\n", iface, viewport);
814 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
817 static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
819 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
820 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
822 TRACE("iface %p, viewport %p.\n", iface, viewport);
824 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
827 /*****************************************************************************
828 * IDirect3DDevice3::DeleteViewport
830 * Deletes a Direct3DViewport from the device's viewport list.
832 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
833 * are equal.
835 * Params:
836 * Viewport: The viewport to delete
838 * Returns:
839 * D3D_OK on success
840 * DDERR_INVALIDPARAMS if the viewport wasn't found in the list
842 *****************************************************************************/
843 static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
845 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
846 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
848 TRACE("iface %p, viewport %p.\n", iface, viewport);
850 if (!vp)
852 WARN("NULL viewport, returning DDERR_INVALIDPARAMS\n");
853 return DDERR_INVALIDPARAMS;
856 wined3d_mutex_lock();
858 if (vp->active_device != device)
860 WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
861 wined3d_mutex_unlock();
862 return DDERR_INVALIDPARAMS;
865 if (device->current_viewport == vp)
867 TRACE("Deleting current viewport, unsetting and releasing.\n");
869 viewport_deactivate(vp);
870 IDirect3DViewport3_Release(viewport);
871 device->current_viewport = NULL;
874 vp->active_device = NULL;
875 list_remove(&vp->entry);
877 IDirect3DViewport3_Release(viewport);
879 wined3d_mutex_unlock();
881 return D3D_OK;
884 static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
886 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
887 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
889 TRACE("iface %p, viewport %p.\n", iface, viewport);
891 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
892 vp ? &vp->IDirect3DViewport3_iface : NULL);
895 static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
897 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
898 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
900 TRACE("iface %p, viewport %p.\n", iface, viewport);
902 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
903 vp ? &vp->IDirect3DViewport3_iface : NULL);
906 /*****************************************************************************
907 * IDirect3DDevice3::NextViewport
909 * Returns a viewport from the viewport list, depending on the
910 * passed viewport and the flags.
912 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
913 * are equal.
915 * Params:
916 * Viewport: Viewport to use for beginning the search
917 * Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
919 * Returns:
920 * D3D_OK on success
921 * DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
923 *****************************************************************************/
924 static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
925 IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
927 struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
928 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
929 struct d3d_viewport *next;
930 struct list *entry;
932 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
933 iface, Viewport3, lplpDirect3DViewport3, flags);
935 if(!vp)
937 *lplpDirect3DViewport3 = NULL;
938 return DDERR_INVALIDPARAMS;
942 wined3d_mutex_lock();
943 switch (flags)
945 case D3DNEXT_NEXT:
946 entry = list_next(&This->viewport_list, &vp->entry);
947 break;
949 case D3DNEXT_HEAD:
950 entry = list_head(&This->viewport_list);
951 break;
953 case D3DNEXT_TAIL:
954 entry = list_tail(&This->viewport_list);
955 break;
957 default:
958 WARN("Invalid flags %#x.\n", flags);
959 *lplpDirect3DViewport3 = NULL;
960 wined3d_mutex_unlock();
961 return DDERR_INVALIDPARAMS;
964 if (entry)
966 next = LIST_ENTRY(entry, struct d3d_viewport, entry);
967 *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
969 else
970 *lplpDirect3DViewport3 = NULL;
972 wined3d_mutex_unlock();
974 return D3D_OK;
977 static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
978 IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
980 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
981 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
982 IDirect3DViewport3 *res;
983 HRESULT hr;
985 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
986 iface, viewport, next, flags);
988 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
989 &vp->IDirect3DViewport3_iface, &res, flags);
990 *next = (IDirect3DViewport2 *)res;
991 return hr;
994 static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
995 IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
997 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
998 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
999 IDirect3DViewport3 *res;
1000 HRESULT hr;
1002 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
1003 iface, viewport, next, flags);
1005 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
1006 &vp->IDirect3DViewport3_iface, &res, flags);
1007 *next = (IDirect3DViewport *)res;
1008 return hr;
1011 /*****************************************************************************
1012 * IDirect3DDevice::Pick
1014 * Executes an execute buffer without performing rendering. Instead, a
1015 * list of primitives that intersect with (x1,y1) of the passed rectangle
1016 * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
1017 * this list.
1019 * Version 1 only
1021 * Params:
1022 * ExecuteBuffer: Buffer to execute
1023 * Viewport: Viewport to use for execution
1024 * Flags: None are defined, according to the SDK
1025 * Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
1026 * x2 and y2 are ignored.
1028 * Returns:
1029 * D3D_OK because it's a stub
1031 *****************************************************************************/
1032 static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
1033 IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
1035 FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
1036 iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
1038 return D3D_OK;
1041 /*****************************************************************************
1042 * IDirect3DDevice::GetPickRecords
1044 * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
1046 * Version 1 only
1048 * Params:
1049 * Count: Pointer to a DWORD containing the numbers of pick records to
1050 * retrieve
1051 * D3DPickRec: Address to store the resulting D3DPICKRECORD array.
1053 * Returns:
1054 * D3D_OK, because it's a stub
1056 *****************************************************************************/
1057 static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
1058 DWORD *count, D3DPICKRECORD *records)
1060 FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1062 return D3D_OK;
1065 /*****************************************************************************
1066 * IDirect3DDevice7::EnumTextureformats
1068 * Enumerates the supported texture formats. It checks against a list of all possible
1069 * formats to see if WineD3D supports it. If so, then it is passed to the app.
1071 * This is for Version 7 and 3, older versions have a different
1072 * callback function and their own implementation
1074 * Params:
1075 * Callback: Callback to call for each enumerated format
1076 * Arg: Argument to pass to the callback
1078 * Returns:
1079 * D3D_OK on success
1080 * DDERR_INVALIDPARAMS if Callback == NULL
1082 *****************************************************************************/
1083 static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
1084 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1086 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1087 struct wined3d_display_mode mode;
1088 HRESULT hr;
1089 unsigned int i;
1091 static const enum wined3d_format_id FormatList[] =
1093 /* 16 bit */
1094 WINED3DFMT_B5G5R5X1_UNORM,
1095 WINED3DFMT_B5G5R5A1_UNORM,
1096 WINED3DFMT_B4G4R4A4_UNORM,
1097 WINED3DFMT_B5G6R5_UNORM,
1098 /* 32 bit */
1099 WINED3DFMT_B8G8R8X8_UNORM,
1100 WINED3DFMT_B8G8R8A8_UNORM,
1101 /* 8 bit */
1102 WINED3DFMT_B2G3R3_UNORM,
1103 WINED3DFMT_P8_UINT,
1104 /* FOURCC codes */
1105 WINED3DFMT_DXT1,
1106 WINED3DFMT_DXT2,
1107 WINED3DFMT_DXT3,
1108 WINED3DFMT_DXT4,
1109 WINED3DFMT_DXT5,
1112 static const enum wined3d_format_id BumpFormatList[] =
1114 WINED3DFMT_R8G8_SNORM,
1115 WINED3DFMT_R5G5_SNORM_L6_UNORM,
1116 WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1117 WINED3DFMT_R10G11B11_SNORM,
1118 WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1121 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1123 if (!callback)
1124 return DDERR_INVALIDPARAMS;
1126 wined3d_mutex_lock();
1128 memset(&mode, 0, sizeof(mode));
1129 if (FAILED(hr = wined3d_output_get_display_mode(device->ddraw->wined3d_output, &mode, NULL)))
1131 wined3d_mutex_unlock();
1132 WARN("Failed to get output display mode, hr %#x.\n", hr);
1133 return hr;
1136 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1138 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1139 WINED3D_DEVICE_TYPE_HAL, mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE,
1140 WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1142 DDPIXELFORMAT pformat;
1144 memset(&pformat, 0, sizeof(pformat));
1145 pformat.dwSize = sizeof(pformat);
1146 ddrawformat_from_wined3dformat(&pformat, FormatList[i]);
1148 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1149 hr = callback(&pformat, context);
1150 if(hr != DDENUMRET_OK)
1152 TRACE("Format enumeration cancelled by application\n");
1153 wined3d_mutex_unlock();
1154 return D3D_OK;
1159 for (i = 0; i < ARRAY_SIZE(BumpFormatList); ++i)
1161 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1162 WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1163 WINED3D_BIND_SHADER_RESOURCE, WINED3D_RTYPE_TEXTURE_2D, BumpFormatList[i]) == D3D_OK)
1165 DDPIXELFORMAT pformat;
1167 memset(&pformat, 0, sizeof(pformat));
1168 pformat.dwSize = sizeof(pformat);
1169 ddrawformat_from_wined3dformat(&pformat, BumpFormatList[i]);
1171 TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1172 hr = callback(&pformat, context);
1173 if(hr != DDENUMRET_OK)
1175 TRACE("Format enumeration cancelled by application\n");
1176 wined3d_mutex_unlock();
1177 return D3D_OK;
1181 TRACE("End of enumeration\n");
1182 wined3d_mutex_unlock();
1184 return D3D_OK;
1187 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1188 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1190 return d3d_device7_EnumTextureFormats(iface, callback, context);
1193 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1194 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1196 HRESULT hr;
1197 WORD old_fpucw;
1199 old_fpucw = d3d_fpu_setup();
1200 hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1201 set_fpu_control_word(old_fpucw);
1203 return hr;
1206 static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
1207 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1209 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1211 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1213 return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1216 /*****************************************************************************
1217 * IDirect3DDevice2::EnumTextureformats
1219 * EnumTextureFormats for Version 1 and 2, see
1220 * IDirect3DDevice7::EnumTextureFormats for a more detailed description.
1222 * This version has a different callback and does not enumerate FourCC
1223 * formats
1225 *****************************************************************************/
1226 static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
1227 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1229 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1230 struct wined3d_display_mode mode;
1231 HRESULT hr;
1232 unsigned int i;
1234 static const enum wined3d_format_id FormatList[] =
1236 /* 16 bit */
1237 WINED3DFMT_B5G5R5X1_UNORM,
1238 WINED3DFMT_B5G5R5A1_UNORM,
1239 WINED3DFMT_B4G4R4A4_UNORM,
1240 WINED3DFMT_B5G6R5_UNORM,
1241 /* 32 bit */
1242 WINED3DFMT_B8G8R8X8_UNORM,
1243 WINED3DFMT_B8G8R8A8_UNORM,
1244 /* 8 bit */
1245 WINED3DFMT_B2G3R3_UNORM,
1246 WINED3DFMT_P8_UINT,
1247 /* FOURCC codes - Not in this version*/
1250 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1252 if (!callback)
1253 return DDERR_INVALIDPARAMS;
1255 wined3d_mutex_lock();
1257 memset(&mode, 0, sizeof(mode));
1258 if (FAILED(hr = wined3d_output_get_display_mode(device->ddraw->wined3d_output, &mode, NULL)))
1260 wined3d_mutex_unlock();
1261 WARN("Failed to get output display mode, hr %#x.\n", hr);
1262 return hr;
1265 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1267 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1268 WINED3D_DEVICE_TYPE_HAL, mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE,
1269 WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1271 DDSURFACEDESC sdesc;
1273 memset(&sdesc, 0, sizeof(sdesc));
1274 sdesc.dwSize = sizeof(sdesc);
1275 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1276 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1277 sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1278 ddrawformat_from_wined3dformat(&sdesc.ddpfPixelFormat, FormatList[i]);
1280 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1281 hr = callback(&sdesc, context);
1282 if(hr != DDENUMRET_OK)
1284 TRACE("Format enumeration cancelled by application\n");
1285 wined3d_mutex_unlock();
1286 return D3D_OK;
1290 TRACE("End of enumeration\n");
1291 wined3d_mutex_unlock();
1293 return D3D_OK;
1296 static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
1297 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1299 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1301 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1303 return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1306 /*****************************************************************************
1307 * IDirect3DDevice::CreateMatrix
1309 * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1310 * allocated for the handle.
1312 * Version 1 only
1314 * Params
1315 * D3DMatHandle: Address to return the handle at
1317 * Returns:
1318 * D3D_OK on success
1319 * DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1321 *****************************************************************************/
1322 static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1324 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1325 D3DMATRIX *matrix;
1326 DWORD h;
1328 TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1330 if(!D3DMatHandle)
1331 return DDERR_INVALIDPARAMS;
1333 if (!(matrix = heap_alloc_zero(sizeof(*matrix))))
1335 ERR("Out of memory when allocating a D3DMATRIX\n");
1336 return DDERR_OUTOFMEMORY;
1339 wined3d_mutex_lock();
1341 h = ddraw_allocate_handle(&device->handle_table, matrix, DDRAW_HANDLE_MATRIX);
1342 if (h == DDRAW_INVALID_HANDLE)
1344 ERR("Failed to allocate a matrix handle.\n");
1345 heap_free(matrix);
1346 wined3d_mutex_unlock();
1347 return DDERR_OUTOFMEMORY;
1350 *D3DMatHandle = h + 1;
1352 TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1354 wined3d_mutex_unlock();
1356 return D3D_OK;
1359 /*****************************************************************************
1360 * IDirect3DDevice::SetMatrix
1362 * Sets a matrix for a matrix handle. The matrix is copied into the memory
1363 * allocated for the handle
1365 * Version 1 only
1367 * Params:
1368 * D3DMatHandle: Handle to set the matrix to
1369 * D3DMatrix: Matrix to set
1371 * Returns:
1372 * D3D_OK on success
1373 * DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1374 * to set is NULL
1376 *****************************************************************************/
1377 static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
1378 D3DMATRIXHANDLE matrix_handle, D3DMATRIX *matrix)
1380 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1381 D3DMATRIX *m;
1383 TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, matrix_handle, matrix);
1385 if (!matrix)
1386 return DDERR_INVALIDPARAMS;
1388 wined3d_mutex_lock();
1390 m = ddraw_get_object(&device->handle_table, matrix_handle - 1, DDRAW_HANDLE_MATRIX);
1391 if (!m)
1393 WARN("Invalid matrix handle.\n");
1394 wined3d_mutex_unlock();
1395 return DDERR_INVALIDPARAMS;
1398 if (TRACE_ON(ddraw))
1399 dump_D3DMATRIX(matrix);
1401 *m = *matrix;
1403 if (matrix_handle == device->world)
1404 wined3d_stateblock_set_transform(device->state,
1405 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)matrix);
1407 if (matrix_handle == device->view)
1408 wined3d_stateblock_set_transform(device->state,
1409 WINED3D_TS_VIEW, (struct wined3d_matrix *)matrix);
1411 if (matrix_handle == device->proj)
1412 wined3d_stateblock_set_transform(device->state,
1413 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)matrix);
1415 wined3d_mutex_unlock();
1417 return D3D_OK;
1420 /*****************************************************************************
1421 * IDirect3DDevice::GetMatrix
1423 * Returns the content of a D3DMATRIX handle
1425 * Version 1 only
1427 * Params:
1428 * D3DMatHandle: Matrix handle to read the content from
1429 * D3DMatrix: Address to store the content at
1431 * Returns:
1432 * D3D_OK on success
1433 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1435 *****************************************************************************/
1436 static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
1437 D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1439 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1440 D3DMATRIX *m;
1442 TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1444 if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1446 wined3d_mutex_lock();
1448 m = ddraw_get_object(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1449 if (!m)
1451 WARN("Invalid matrix handle.\n");
1452 wined3d_mutex_unlock();
1453 return DDERR_INVALIDPARAMS;
1456 *D3DMatrix = *m;
1458 wined3d_mutex_unlock();
1460 return D3D_OK;
1463 /*****************************************************************************
1464 * IDirect3DDevice::DeleteMatrix
1466 * Destroys a Matrix handle. Frees the memory and unsets the handle data
1468 * Version 1 only
1470 * Params:
1471 * D3DMatHandle: Handle to destroy
1473 * Returns:
1474 * D3D_OK on success
1475 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1477 *****************************************************************************/
1478 static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1480 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1481 D3DMATRIX *m;
1483 TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1485 wined3d_mutex_lock();
1487 m = ddraw_free_handle(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1488 if (!m)
1490 WARN("Invalid matrix handle.\n");
1491 wined3d_mutex_unlock();
1492 return DDERR_INVALIDPARAMS;
1495 wined3d_mutex_unlock();
1497 heap_free(m);
1499 return D3D_OK;
1502 /*****************************************************************************
1503 * IDirect3DDevice7::BeginScene
1505 * This method must be called before any rendering is performed.
1506 * IDirect3DDevice::EndScene has to be called after the scene is complete
1508 * Version 1, 2, 3 and 7
1510 * Returns:
1511 * D3D_OK on success,
1512 * D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1513 * started scene).
1515 *****************************************************************************/
1516 static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1518 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1519 HRESULT hr;
1521 TRACE("iface %p.\n", iface);
1523 wined3d_mutex_lock();
1524 hr = wined3d_device_begin_scene(device->wined3d_device);
1525 wined3d_mutex_unlock();
1527 if(hr == WINED3D_OK) return D3D_OK;
1528 else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1531 static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1533 return d3d_device7_BeginScene(iface);
1536 static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1538 HRESULT hr;
1539 WORD old_fpucw;
1541 old_fpucw = d3d_fpu_setup();
1542 hr = d3d_device7_BeginScene(iface);
1543 set_fpu_control_word(old_fpucw);
1545 return hr;
1548 static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1550 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1552 TRACE("iface %p.\n", iface);
1554 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1557 static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1559 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1561 TRACE("iface %p.\n", iface);
1563 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1566 static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1568 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1570 TRACE("iface %p.\n", iface);
1572 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1575 /*****************************************************************************
1576 * IDirect3DDevice7::EndScene
1578 * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1579 * This method must be called after rendering is finished.
1581 * Version 1, 2, 3 and 7
1583 * Returns:
1584 * D3D_OK on success,
1585 * D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1586 * that only if the scene was already ended.
1588 *****************************************************************************/
1589 static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1591 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1592 HRESULT hr;
1594 TRACE("iface %p.\n", iface);
1596 wined3d_mutex_lock();
1597 hr = wined3d_device_end_scene(device->wined3d_device);
1598 wined3d_mutex_unlock();
1600 if(hr == WINED3D_OK) return D3D_OK;
1601 else return D3DERR_SCENE_NOT_IN_SCENE;
1604 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1606 return d3d_device7_EndScene(iface);
1609 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1611 HRESULT hr;
1612 WORD old_fpucw;
1614 old_fpucw = d3d_fpu_setup();
1615 hr = d3d_device7_EndScene(iface);
1616 set_fpu_control_word(old_fpucw);
1618 return hr;
1621 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1623 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1625 TRACE("iface %p.\n", iface);
1627 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1630 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1632 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1634 TRACE("iface %p.\n", iface);
1636 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1639 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1641 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1643 TRACE("iface %p.\n", iface);
1645 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1648 /*****************************************************************************
1649 * IDirect3DDevice7::GetDirect3D
1651 * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1652 * this device.
1654 * Params:
1655 * Direct3D7: Address to store the interface pointer at
1657 * Returns:
1658 * D3D_OK on success
1659 * DDERR_INVALIDPARAMS if Direct3D7 == NULL
1661 *****************************************************************************/
1662 static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1664 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1666 TRACE("iface %p, d3d %p.\n", iface, d3d);
1668 if (!d3d)
1669 return DDERR_INVALIDPARAMS;
1671 *d3d = &device->ddraw->IDirect3D7_iface;
1672 IDirect3D7_AddRef(*d3d);
1674 TRACE("Returning interface %p.\n", *d3d);
1675 return D3D_OK;
1678 static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1680 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1682 TRACE("iface %p, d3d %p.\n", iface, d3d);
1684 if (!d3d)
1685 return DDERR_INVALIDPARAMS;
1687 *d3d = &device->ddraw->IDirect3D3_iface;
1688 IDirect3D3_AddRef(*d3d);
1690 TRACE("Returning interface %p.\n", *d3d);
1691 return D3D_OK;
1694 static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1696 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1698 TRACE("iface %p, d3d %p.\n", iface, d3d);
1700 if (!d3d)
1701 return DDERR_INVALIDPARAMS;
1703 *d3d = &device->ddraw->IDirect3D2_iface;
1704 IDirect3D2_AddRef(*d3d);
1706 TRACE("Returning interface %p.\n", *d3d);
1707 return D3D_OK;
1710 static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1712 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1714 TRACE("iface %p, d3d %p.\n", iface, d3d);
1716 if (!d3d)
1717 return DDERR_INVALIDPARAMS;
1719 *d3d = &device->ddraw->IDirect3D_iface;
1720 IDirect3D_AddRef(*d3d);
1722 TRACE("Returning interface %p.\n", *d3d);
1723 return D3D_OK;
1726 /*****************************************************************************
1727 * IDirect3DDevice3::SetCurrentViewport
1729 * Sets a Direct3DViewport as the current viewport.
1730 * For the thunks note that all viewport interface versions are equal
1732 * Params:
1733 * Direct3DViewport3: The viewport to set
1735 * Version 2 and 3
1737 * Returns:
1738 * D3D_OK on success
1739 * (Is a NULL viewport valid?)
1741 *****************************************************************************/
1742 static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
1744 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
1745 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1747 TRACE("iface %p, viewport %p, current_viewport %p.\n", iface, viewport, device->current_viewport);
1749 if (!vp)
1751 WARN("Direct3DViewport3 is NULL.\n");
1752 return DDERR_INVALIDPARAMS;
1755 wined3d_mutex_lock();
1756 /* Do nothing if the specified viewport is the same as the current one */
1757 if (device->current_viewport == vp)
1759 wined3d_mutex_unlock();
1760 return D3D_OK;
1763 if (vp->active_device != device)
1765 WARN("Viewport %p, active device %p.\n", vp, vp->active_device);
1766 wined3d_mutex_unlock();
1767 return DDERR_INVALIDPARAMS;
1770 IDirect3DViewport3_AddRef(viewport);
1771 if (device->current_viewport)
1773 viewport_deactivate(device->current_viewport);
1774 IDirect3DViewport3_Release(&device->current_viewport->IDirect3DViewport3_iface);
1776 device->current_viewport = vp;
1777 viewport_activate(device->current_viewport, FALSE);
1779 wined3d_mutex_unlock();
1781 return D3D_OK;
1784 static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1786 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1787 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1789 TRACE("iface %p, viewport %p.\n", iface, viewport);
1791 return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface,
1792 vp ? &vp->IDirect3DViewport3_iface : NULL);
1795 /*****************************************************************************
1796 * IDirect3DDevice3::GetCurrentViewport
1798 * Returns the currently active viewport.
1800 * Version 2 and 3
1802 * Params:
1803 * Direct3DViewport3: Address to return the interface pointer at
1805 * Returns:
1806 * D3D_OK on success
1807 * DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1809 *****************************************************************************/
1810 static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1812 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1814 TRACE("iface %p, viewport %p.\n", iface, viewport);
1816 wined3d_mutex_lock();
1817 if (!device->current_viewport)
1819 wined3d_mutex_unlock();
1820 WARN("No current viewport, returning D3DERR_NOCURRENTVIEWPORT\n");
1821 return D3DERR_NOCURRENTVIEWPORT;
1824 *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1825 IDirect3DViewport3_AddRef(*viewport);
1827 TRACE("Returning interface %p.\n", *viewport);
1828 wined3d_mutex_unlock();
1829 return D3D_OK;
1832 static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1834 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1836 TRACE("iface %p, viewport %p.\n", iface, viewport);
1838 return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
1839 (IDirect3DViewport3 **)viewport);
1842 static BOOL validate_surface_palette(struct ddraw_surface *surface)
1844 return !format_is_paletteindexed(&surface->surface_desc.u4.ddpfPixelFormat)
1845 || surface->palette;
1848 static HRESULT d3d_device_set_render_target(struct d3d_device *device,
1849 struct ddraw_surface *target, IUnknown *rt_iface)
1851 HRESULT hr;
1853 if (device->rt_iface == rt_iface)
1855 TRACE("No-op SetRenderTarget operation, not doing anything\n");
1856 return D3D_OK;
1858 if (!target)
1860 WARN("Trying to set render target to NULL.\n");
1861 return DDERR_INVALIDPARAMS;
1864 if (FAILED(hr = wined3d_device_context_set_rendertarget_view(device->immediate_context,
1865 0, ddraw_surface_get_rendertarget_view(target), FALSE)))
1866 return hr;
1868 IUnknown_AddRef(rt_iface);
1869 IUnknown_Release(device->rt_iface);
1870 device->rt_iface = rt_iface;
1871 d3d_device_update_depth_stencil(device);
1873 return D3D_OK;
1876 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
1877 IDirectDrawSurface7 *target, DWORD flags)
1879 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface7(target);
1880 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1881 HRESULT hr;
1883 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1885 wined3d_mutex_lock();
1887 if (!validate_surface_palette(target_impl))
1889 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1890 wined3d_mutex_unlock();
1891 return DDERR_INVALIDCAPS;
1894 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1896 WARN("Surface %p is not a render target.\n", target_impl);
1897 wined3d_mutex_unlock();
1898 return DDERR_INVALIDCAPS;
1901 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1903 WARN("Surface %p is not in video memory.\n", target_impl);
1904 wined3d_mutex_unlock();
1905 return DDERR_INVALIDPARAMS;
1908 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1910 WARN("Surface %p is a depth buffer.\n", target_impl);
1911 IDirectDrawSurface7_AddRef(target);
1912 IUnknown_Release(device->rt_iface);
1913 device->rt_iface = (IUnknown *)target;
1914 wined3d_mutex_unlock();
1915 return DDERR_INVALIDPIXELFORMAT;
1918 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1919 wined3d_mutex_unlock();
1920 return hr;
1923 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1924 IDirectDrawSurface7 *NewTarget, DWORD flags)
1926 return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1929 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1930 IDirectDrawSurface7 *NewTarget, DWORD flags)
1932 HRESULT hr;
1933 WORD old_fpucw;
1935 old_fpucw = d3d_fpu_setup();
1936 hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1937 set_fpu_control_word(old_fpucw);
1939 return hr;
1942 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
1943 IDirectDrawSurface4 *target, DWORD flags)
1945 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface4(target);
1946 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1947 HRESULT hr;
1949 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1951 wined3d_mutex_lock();
1953 if (!validate_surface_palette(target_impl))
1955 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1956 wined3d_mutex_unlock();
1957 return DDERR_INVALIDCAPS;
1960 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1962 WARN("Surface %p is not a render target.\n", target_impl);
1963 wined3d_mutex_unlock();
1964 return DDERR_INVALIDCAPS;
1967 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1969 WARN("Surface %p is a depth buffer.\n", target_impl);
1970 IDirectDrawSurface4_AddRef(target);
1971 IUnknown_Release(device->rt_iface);
1972 device->rt_iface = (IUnknown *)target;
1973 wined3d_mutex_unlock();
1974 return DDERR_INVALIDPIXELFORMAT;
1977 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1979 WARN("Surface %p is not in video memory.\n", target_impl);
1980 IDirectDrawSurface4_AddRef(target);
1981 IUnknown_Release(device->rt_iface);
1982 device->rt_iface = (IUnknown *)target;
1983 wined3d_mutex_unlock();
1984 return D3D_OK;
1987 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1988 wined3d_mutex_unlock();
1989 return hr;
1992 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
1993 IDirectDrawSurface *target, DWORD flags)
1995 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface(target);
1996 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1997 HRESULT hr;
1999 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
2001 wined3d_mutex_lock();
2003 if (!validate_surface_palette(target_impl))
2005 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
2006 wined3d_mutex_unlock();
2007 return DDERR_INVALIDCAPS;
2010 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
2012 WARN("Surface %p is not a render target.\n", target_impl);
2013 wined3d_mutex_unlock();
2014 return DDERR_INVALIDCAPS;
2017 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
2019 WARN("Surface %p is a depth buffer.\n", target_impl);
2020 IUnknown_Release(device->rt_iface);
2021 device->rt_iface = (IUnknown *)target;
2022 wined3d_mutex_unlock();
2023 return DDERR_INVALIDPIXELFORMAT;
2026 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
2028 WARN("Surface %p is not in video memory.\n", target_impl);
2029 IDirectDrawSurface_AddRef(target);
2030 IUnknown_Release(device->rt_iface);
2031 device->rt_iface = (IUnknown *)target;
2032 wined3d_mutex_unlock();
2033 return D3D_OK;
2036 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
2037 wined3d_mutex_unlock();
2038 return hr;
2041 /*****************************************************************************
2042 * IDirect3DDevice7::GetRenderTarget
2044 * Returns the current render target.
2045 * This is handled locally, because the WineD3D render target's parent
2046 * is an IParent
2048 * Version 2, 3 and 7
2050 * Params:
2051 * RenderTarget: Address to store the surface interface pointer
2053 * Returns:
2054 * D3D_OK on success
2055 * DDERR_INVALIDPARAMS if RenderTarget == NULL
2057 *****************************************************************************/
2058 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
2060 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2061 HRESULT hr;
2063 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2065 if(!RenderTarget)
2066 return DDERR_INVALIDPARAMS;
2068 wined3d_mutex_lock();
2069 hr = IUnknown_QueryInterface(device->rt_iface, &IID_IDirectDrawSurface7, (void **)RenderTarget);
2070 wined3d_mutex_unlock();
2072 return hr;
2075 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
2077 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2078 IDirectDrawSurface7 *RenderTarget7;
2079 struct ddraw_surface *RenderTargetImpl;
2080 HRESULT hr;
2082 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2084 if(!RenderTarget)
2085 return DDERR_INVALIDPARAMS;
2087 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2088 if(hr != D3D_OK) return hr;
2089 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2090 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
2091 IDirectDrawSurface4_AddRef(*RenderTarget);
2092 IDirectDrawSurface7_Release(RenderTarget7);
2093 return D3D_OK;
2096 static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
2098 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2099 IDirectDrawSurface7 *RenderTarget7;
2100 struct ddraw_surface *RenderTargetImpl;
2101 HRESULT hr;
2103 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2105 if(!RenderTarget)
2106 return DDERR_INVALIDPARAMS;
2108 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2109 if(hr != D3D_OK) return hr;
2110 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2111 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
2112 IDirectDrawSurface_AddRef(*RenderTarget);
2113 IDirectDrawSurface7_Release(RenderTarget7);
2114 return D3D_OK;
2117 /*****************************************************************************
2118 * IDirect3DDevice3::Begin
2120 * Begins a description block of vertices. This is similar to glBegin()
2121 * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
2122 * described with IDirect3DDevice::Vertex are drawn.
2124 * Version 2 and 3
2126 * Params:
2127 * PrimitiveType: The type of primitives to draw
2128 * VertexTypeDesc: A flexible vertex format description of the vertices
2129 * Flags: Some flags..
2131 * Returns:
2132 * D3D_OK on success
2134 *****************************************************************************/
2135 static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
2136 D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
2138 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2140 TRACE("iface %p, primitive_type %#x, fvf %#x, flags %#x.\n",
2141 iface, primitive_type, fvf, flags);
2143 wined3d_mutex_lock();
2144 device->primitive_type = primitive_type;
2145 device->vertex_type = fvf;
2146 device->render_flags = flags;
2147 device->vertex_size = get_flexible_vertex_size(device->vertex_type);
2148 device->nb_vertices = 0;
2149 wined3d_mutex_unlock();
2151 return D3D_OK;
2154 static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
2155 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2157 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2158 DWORD fvf;
2160 TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2161 iface, primitive_type, vertex_type, flags);
2163 switch (vertex_type)
2165 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2166 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2167 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2168 default:
2169 ERR("Unexpected vertex type %#x.\n", vertex_type);
2170 return DDERR_INVALIDPARAMS; /* Should never happen */
2173 return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2176 /*****************************************************************************
2177 * IDirect3DDevice3::BeginIndexed
2179 * Draws primitives based on vertices in a vertex array which are specified
2180 * by indices.
2182 * Version 2 and 3
2184 * Params:
2185 * PrimitiveType: Primitive type to draw
2186 * VertexType: A FVF description of the vertex format
2187 * Vertices: pointer to an array containing the vertices
2188 * NumVertices: The number of vertices in the vertex array
2189 * Flags: Some flags ...
2191 * Returns:
2192 * D3D_OK, because it's a stub
2194 *****************************************************************************/
2195 static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
2196 D3DPRIMITIVETYPE primitive_type, DWORD fvf,
2197 void *vertices, DWORD vertex_count, DWORD flags)
2199 FIXME("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2200 iface, primitive_type, fvf, vertices, vertex_count, flags);
2202 return D3D_OK;
2206 static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
2207 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
2208 void *vertices, DWORD vertex_count, DWORD flags)
2210 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2211 DWORD fvf;
2213 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2214 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2216 switch (vertex_type)
2218 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2219 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2220 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2221 default:
2222 ERR("Unexpected vertex type %#x.\n", vertex_type);
2223 return DDERR_INVALIDPARAMS; /* Should never happen */
2226 return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
2227 primitive_type, fvf, vertices, vertex_count, flags);
2230 /*****************************************************************************
2231 * IDirect3DDevice3::Vertex
2233 * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2234 * drawn vertices in a vertex buffer. If the buffer is too small, its
2235 * size is increased.
2237 * Version 2 and 3
2239 * Params:
2240 * Vertex: Pointer to the vertex
2242 * Returns:
2243 * D3D_OK, on success
2244 * DDERR_INVALIDPARAMS if Vertex is NULL
2246 *****************************************************************************/
2247 static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2249 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2251 TRACE("iface %p, vertex %p.\n", iface, vertex);
2253 if (!vertex)
2254 return DDERR_INVALIDPARAMS;
2256 wined3d_mutex_lock();
2257 if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2259 BYTE *old_buffer;
2261 device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
2262 old_buffer = device->sysmem_vertex_buffer;
2263 device->sysmem_vertex_buffer = heap_alloc(device->buffer_size);
2264 if (old_buffer)
2266 memcpy(device->sysmem_vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2267 heap_free(old_buffer);
2271 memcpy(device->sysmem_vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2272 wined3d_mutex_unlock();
2274 return D3D_OK;
2277 static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2279 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2281 TRACE("iface %p, vertex %p.\n", iface, vertex);
2283 return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2286 /*****************************************************************************
2287 * IDirect3DDevice3::Index
2289 * Specifies an index to a vertex to be drawn. The vertex array has to
2290 * be specified with BeginIndexed first.
2292 * Parameters:
2293 * VertexIndex: The index of the vertex to draw
2295 * Returns:
2296 * D3D_OK because it's a stub
2298 *****************************************************************************/
2299 static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2301 FIXME("iface %p, index %#x stub!\n", iface, index);
2303 return D3D_OK;
2306 static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2308 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2310 TRACE("iface %p, index %#x.\n", iface, index);
2312 return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2315 /*****************************************************************************
2316 * IDirect3DDevice7::GetRenderState
2318 * Returns the value of a render state. The possible render states are
2319 * defined in include/d3dtypes.h
2321 * Version 2, 3 and 7
2323 * Params:
2324 * RenderStateType: Render state to return the current setting of
2325 * Value: Address to store the value at
2327 * Returns:
2328 * D3D_OK on success,
2329 * DDERR_INVALIDPARAMS if Value == NULL
2331 *****************************************************************************/
2332 static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
2333 D3DRENDERSTATETYPE state, DWORD *value)
2335 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2336 const struct wined3d_stateblock_state *device_state;
2337 HRESULT hr = D3D_OK;
2339 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2341 if (!value)
2342 return DDERR_INVALIDPARAMS;
2344 wined3d_mutex_lock();
2345 device_state = device->stateblock_state;
2346 switch (state)
2348 case D3DRENDERSTATE_TEXTUREMAG:
2350 enum wined3d_texture_filter_type tex_mag = device_state->sampler_states[0][WINED3D_SAMP_MAG_FILTER];
2352 switch (tex_mag)
2354 case WINED3D_TEXF_POINT:
2355 *value = D3DFILTER_NEAREST;
2356 break;
2357 case WINED3D_TEXF_LINEAR:
2358 *value = D3DFILTER_LINEAR;
2359 break;
2360 default:
2361 ERR("Unhandled texture mag %d !\n",tex_mag);
2362 *value = 0;
2364 break;
2367 case D3DRENDERSTATE_TEXTUREMIN:
2369 enum wined3d_texture_filter_type tex_min;
2370 enum wined3d_texture_filter_type tex_mip;
2372 tex_min = device_state->sampler_states[0][WINED3D_SAMP_MIN_FILTER];
2373 tex_mip = device_state->sampler_states[0][WINED3D_SAMP_MIP_FILTER];
2374 switch (tex_min)
2376 case WINED3D_TEXF_POINT:
2377 switch (tex_mip)
2379 case WINED3D_TEXF_NONE:
2380 *value = D3DFILTER_NEAREST;
2381 break;
2382 case WINED3D_TEXF_POINT:
2383 *value = D3DFILTER_MIPNEAREST;
2384 break;
2385 case WINED3D_TEXF_LINEAR:
2386 *value = D3DFILTER_LINEARMIPNEAREST;
2387 break;
2388 default:
2389 ERR("Unhandled mip filter %#x.\n", tex_mip);
2390 *value = D3DFILTER_NEAREST;
2391 break;
2393 break;
2394 case WINED3D_TEXF_LINEAR:
2395 switch (tex_mip)
2397 case WINED3D_TEXF_NONE:
2398 *value = D3DFILTER_LINEAR;
2399 break;
2400 case WINED3D_TEXF_POINT:
2401 *value = D3DFILTER_MIPLINEAR;
2402 break;
2403 case WINED3D_TEXF_LINEAR:
2404 *value = D3DFILTER_LINEARMIPLINEAR;
2405 break;
2406 default:
2407 ERR("Unhandled mip filter %#x.\n", tex_mip);
2408 *value = D3DFILTER_LINEAR;
2409 break;
2411 break;
2412 default:
2413 ERR("Unhandled texture min filter %#x.\n",tex_min);
2414 *value = D3DFILTER_NEAREST;
2415 break;
2417 break;
2420 case D3DRENDERSTATE_TEXTUREADDRESS:
2421 case D3DRENDERSTATE_TEXTUREADDRESSU:
2422 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_U];
2423 break;
2424 case D3DRENDERSTATE_TEXTUREADDRESSV:
2425 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_V];
2426 break;
2428 case D3DRENDERSTATE_BORDERCOLOR:
2429 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2430 hr = E_NOTIMPL;
2431 break;
2433 case D3DRENDERSTATE_TEXTUREHANDLE:
2434 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2435 WARN("Render state %#x is invalid in d3d7.\n", state);
2436 hr = DDERR_INVALIDPARAMS;
2437 break;
2439 default:
2440 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2441 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2443 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2444 hr = E_NOTIMPL;
2445 break;
2447 *value = device_state->rs[wined3d_render_state_from_ddraw(state)];
2449 wined3d_mutex_unlock();
2451 return hr;
2454 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2455 D3DRENDERSTATETYPE state, DWORD *value)
2457 return d3d_device7_GetRenderState(iface, state, value);
2460 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2461 D3DRENDERSTATETYPE state, DWORD *value)
2463 HRESULT hr;
2464 WORD old_fpucw;
2466 old_fpucw = d3d_fpu_setup();
2467 hr = d3d_device7_GetRenderState(iface, state, value);
2468 set_fpu_control_word(old_fpucw);
2470 return hr;
2473 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2474 D3DRENDERSTATETYPE state, DWORD *value)
2476 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2478 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2480 switch (state)
2482 case D3DRENDERSTATE_TEXTUREHANDLE:
2484 /* This state is wrapped to SetTexture in SetRenderState, so
2485 * it has to be wrapped to GetTexture here. */
2486 struct wined3d_texture *tex = NULL;
2487 *value = 0;
2489 wined3d_mutex_lock();
2490 if ((tex = device->stateblock_state->textures[0]))
2492 /* The parent of the texture is the IDirectDrawSurface7
2493 * interface of the ddraw surface. */
2494 struct ddraw_texture *parent = wined3d_texture_get_parent(tex);
2495 if (parent)
2496 *value = parent->root->Handle;
2498 wined3d_mutex_unlock();
2500 return D3D_OK;
2503 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2505 *value = device->texture_map_blend;
2506 return D3D_OK;
2509 case D3DRENDERSTATE_LIGHTING:
2510 case D3DRENDERSTATE_NORMALIZENORMALS:
2511 case D3DRENDERSTATE_LOCALVIEWER:
2512 *value = 0xffffffff;
2513 return D3D_OK;
2515 default:
2516 return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2520 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2521 D3DRENDERSTATETYPE state, DWORD *value)
2523 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2525 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2527 return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2530 /*****************************************************************************
2531 * IDirect3DDevice7::SetRenderState
2533 * Sets a render state. The possible render states are defined in
2534 * include/d3dtypes.h
2536 * Version 2, 3 and 7
2538 * Params:
2539 * RenderStateType: State to set
2540 * Value: Value to assign to that state
2542 *****************************************************************************/
2543 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2544 D3DRENDERSTATETYPE state, DWORD value)
2546 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2547 HRESULT hr = D3D_OK;
2549 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2551 wined3d_mutex_lock();
2552 /* Some render states need special care */
2553 switch (state)
2556 * The ddraw texture filter mapping works like this:
2557 * D3DFILTER_NEAREST Point min/mag, no mip
2558 * D3DFILTER_MIPNEAREST Point min/mag, point mip
2559 * D3DFILTER_LINEARMIPNEAREST: Point min/mag, linear mip
2561 * D3DFILTER_LINEAR Linear min/mag, no mip
2562 * D3DFILTER_MIPLINEAR Linear min/mag, point mip
2563 * D3DFILTER_LINEARMIPLINEAR Linear min/mag, linear mip
2565 * This is the opposite of the GL naming convention,
2566 * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2568 case D3DRENDERSTATE_TEXTUREMAG:
2570 enum wined3d_texture_filter_type tex_mag;
2572 switch (value)
2574 case D3DFILTER_NEAREST:
2575 case D3DFILTER_MIPNEAREST:
2576 case D3DFILTER_LINEARMIPNEAREST:
2577 tex_mag = WINED3D_TEXF_POINT;
2578 break;
2579 case D3DFILTER_LINEAR:
2580 case D3DFILTER_MIPLINEAR:
2581 case D3DFILTER_LINEARMIPLINEAR:
2582 tex_mag = WINED3D_TEXF_LINEAR;
2583 break;
2584 default:
2585 tex_mag = WINED3D_TEXF_POINT;
2586 FIXME("Unhandled texture mag %#x.\n", value);
2587 break;
2590 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2591 break;
2594 case D3DRENDERSTATE_TEXTUREMIN:
2596 enum wined3d_texture_filter_type tex_min;
2597 enum wined3d_texture_filter_type tex_mip;
2599 switch (value)
2601 case D3DFILTER_NEAREST:
2602 tex_min = WINED3D_TEXF_POINT;
2603 tex_mip = WINED3D_TEXF_NONE;
2604 break;
2605 case D3DFILTER_LINEAR:
2606 tex_min = WINED3D_TEXF_LINEAR;
2607 tex_mip = WINED3D_TEXF_NONE;
2608 break;
2609 case D3DFILTER_MIPNEAREST:
2610 tex_min = WINED3D_TEXF_POINT;
2611 tex_mip = WINED3D_TEXF_POINT;
2612 break;
2613 case D3DFILTER_MIPLINEAR:
2614 tex_min = WINED3D_TEXF_LINEAR;
2615 tex_mip = WINED3D_TEXF_POINT;
2616 break;
2617 case D3DFILTER_LINEARMIPNEAREST:
2618 tex_min = WINED3D_TEXF_POINT;
2619 tex_mip = WINED3D_TEXF_LINEAR;
2620 break;
2621 case D3DFILTER_LINEARMIPLINEAR:
2622 tex_min = WINED3D_TEXF_LINEAR;
2623 tex_mip = WINED3D_TEXF_LINEAR;
2624 break;
2626 default:
2627 FIXME("Unhandled texture min %#x.\n",value);
2628 tex_min = WINED3D_TEXF_POINT;
2629 tex_mip = WINED3D_TEXF_NONE;
2630 break;
2633 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2634 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIN_FILTER, tex_min);
2635 break;
2638 case D3DRENDERSTATE_TEXTUREADDRESS:
2639 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2640 /* Drop through */
2641 case D3DRENDERSTATE_TEXTUREADDRESSU:
2642 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_U, value);
2643 break;
2644 case D3DRENDERSTATE_TEXTUREADDRESSV:
2645 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2646 break;
2648 case D3DRENDERSTATE_BORDERCOLOR:
2649 /* This should probably just forward to the corresponding sampler
2650 * state. Needs tests. */
2651 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2652 hr = E_NOTIMPL;
2653 break;
2655 case D3DRENDERSTATE_TEXTUREHANDLE:
2656 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2657 WARN("Render state %#x is invalid in d3d7.\n", state);
2658 hr = DDERR_INVALIDPARAMS;
2659 break;
2661 default:
2662 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2663 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2665 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2666 hr = E_NOTIMPL;
2667 break;
2670 wined3d_stateblock_set_render_state(device->update_state, wined3d_render_state_from_ddraw(state), value);
2671 break;
2673 wined3d_mutex_unlock();
2675 return hr;
2678 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2679 D3DRENDERSTATETYPE state, DWORD value)
2681 return d3d_device7_SetRenderState(iface, state, value);
2684 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2685 D3DRENDERSTATETYPE state, DWORD value)
2687 HRESULT hr;
2688 WORD old_fpucw;
2690 old_fpucw = d3d_fpu_setup();
2691 hr = d3d_device7_SetRenderState(iface, state, value);
2692 set_fpu_control_word(old_fpucw);
2694 return hr;
2697 static void fixup_texture_alpha_op(struct d3d_device *device)
2699 /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
2700 See d3d_device3_SetRenderState() for details. */
2701 struct wined3d_texture *tex;
2702 BOOL tex_alpha = TRUE;
2703 DDPIXELFORMAT ddfmt;
2705 if (!(device->legacyTextureBlending && device->texture_map_blend == D3DTBLEND_MODULATE))
2706 return;
2708 if ((tex = device->stateblock_state->textures[0]))
2710 struct wined3d_resource_desc desc;
2712 wined3d_resource_get_desc(wined3d_texture_get_resource(tex), &desc);
2713 ddfmt.dwSize = sizeof(ddfmt);
2714 ddrawformat_from_wined3dformat(&ddfmt, desc.format);
2715 if (!ddfmt.u5.dwRGBAlphaBitMask)
2716 tex_alpha = FALSE;
2719 /* Args 1 and 2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
2720 wined3d_stateblock_set_texture_stage_state(device->state,
2721 0, WINED3D_TSS_ALPHA_OP, tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2);
2724 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2725 D3DRENDERSTATETYPE state, DWORD value)
2727 /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2728 for this state can be directly mapped to texture stage colorop and alphaop, but
2729 D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2730 from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2731 alphaarg when needed.
2733 Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2735 Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2736 TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2737 are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2738 requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2739 with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2740 in device - TRUE if the app is using TEXTUREMAPBLEND.
2742 Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2743 GetTextureStageState and vice versa. */
2745 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2746 HRESULT hr;
2748 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2750 if (state >= D3DSTATE_OVERRIDE_BIAS)
2752 WARN("Unhandled state %#x.\n", state);
2753 return DDERR_INVALIDPARAMS;
2756 wined3d_mutex_lock();
2758 switch (state)
2760 case D3DRENDERSTATE_TEXTUREHANDLE:
2762 struct ddraw_surface *surf;
2764 if (value == 0)
2766 wined3d_stateblock_set_texture(device->state, 0, NULL);
2767 hr = D3D_OK;
2768 break;
2771 surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2772 if (!surf)
2774 WARN("Invalid texture handle.\n");
2775 hr = DDERR_INVALIDPARAMS;
2776 break;
2779 hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2780 break;
2783 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2785 if (value == device->texture_map_blend)
2787 TRACE("Application is setting the same value over, nothing to do.\n");
2789 hr = D3D_OK;
2790 break;
2793 device->legacyTextureBlending = TRUE;
2794 device->texture_map_blend = value;
2796 switch (value)
2798 case D3DTBLEND_MODULATE:
2800 fixup_texture_alpha_op(device);
2802 wined3d_stateblock_set_texture_stage_state(device->state,
2803 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2804 wined3d_stateblock_set_texture_stage_state(device->state,
2805 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2806 wined3d_stateblock_set_texture_stage_state(device->state,
2807 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2808 wined3d_stateblock_set_texture_stage_state(device->state,
2809 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2810 wined3d_stateblock_set_texture_stage_state(device->state,
2811 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2812 break;
2815 case D3DTBLEND_ADD:
2816 wined3d_stateblock_set_texture_stage_state(device->state,
2817 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2818 wined3d_stateblock_set_texture_stage_state(device->state,
2819 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2820 wined3d_stateblock_set_texture_stage_state(device->state,
2821 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2822 wined3d_stateblock_set_texture_stage_state(device->state,
2823 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2824 wined3d_stateblock_set_texture_stage_state(device->state,
2825 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2826 break;
2828 case D3DTBLEND_MODULATEALPHA:
2829 wined3d_stateblock_set_texture_stage_state(device->state,
2830 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2831 wined3d_stateblock_set_texture_stage_state(device->state,
2832 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2833 wined3d_stateblock_set_texture_stage_state(device->state,
2834 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2835 wined3d_stateblock_set_texture_stage_state(device->state,
2836 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2837 wined3d_stateblock_set_texture_stage_state(device->state,
2838 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2839 wined3d_stateblock_set_texture_stage_state(device->state,
2840 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2841 break;
2843 case D3DTBLEND_COPY:
2844 case D3DTBLEND_DECAL:
2845 wined3d_stateblock_set_texture_stage_state(device->state,
2846 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2847 wined3d_stateblock_set_texture_stage_state(device->state,
2848 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2849 wined3d_stateblock_set_texture_stage_state(device->state,
2850 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2851 wined3d_stateblock_set_texture_stage_state(device->state,
2852 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2853 break;
2855 case D3DTBLEND_DECALALPHA:
2856 wined3d_stateblock_set_texture_stage_state(device->state,
2857 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2858 wined3d_stateblock_set_texture_stage_state(device->state,
2859 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2860 wined3d_stateblock_set_texture_stage_state(device->state,
2861 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2862 wined3d_stateblock_set_texture_stage_state(device->state,
2863 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2864 wined3d_stateblock_set_texture_stage_state(device->state,
2865 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2866 break;
2868 default:
2869 FIXME("Unhandled texture environment %#x.\n", value);
2871 hr = D3D_OK;
2872 break;
2875 case D3DRENDERSTATE_LIGHTING:
2876 case D3DRENDERSTATE_NORMALIZENORMALS:
2877 case D3DRENDERSTATE_LOCALVIEWER:
2878 hr = D3D_OK;
2879 break;
2881 default:
2882 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2883 break;
2885 wined3d_mutex_unlock();
2887 return hr;
2890 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2891 D3DRENDERSTATETYPE state, DWORD value)
2893 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2895 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2897 return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2900 /*****************************************************************************
2901 * Direct3DDevice3::SetLightState
2903 * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2904 * light states are forwarded to Direct3DDevice7 render states
2906 * Version 2 and 3
2908 * Params:
2909 * LightStateType: The light state to change
2910 * Value: The value to assign to that light state
2912 * Returns:
2913 * D3D_OK on success
2914 * DDERR_INVALIDPARAMS if the parameters were incorrect
2915 * Also check IDirect3DDevice7::SetRenderState
2917 *****************************************************************************/
2918 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2919 D3DLIGHTSTATETYPE state, DWORD value)
2921 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2922 HRESULT hr;
2924 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2926 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2928 TRACE("Unexpected Light State Type\n");
2929 return DDERR_INVALIDPARAMS;
2932 wined3d_mutex_lock();
2933 if (state == D3DLIGHTSTATE_MATERIAL)
2935 if (value)
2937 struct d3d_material *m;
2939 if (!(m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL)))
2941 WARN("Invalid material handle.\n");
2942 wined3d_mutex_unlock();
2943 return DDERR_INVALIDPARAMS;
2946 material_activate(m);
2949 device->material = value;
2951 else if (state == D3DLIGHTSTATE_COLORMODEL)
2953 switch (value)
2955 case D3DCOLOR_MONO:
2956 ERR("DDCOLOR_MONO should not happen!\n");
2957 break;
2958 case D3DCOLOR_RGB:
2959 /* We are already in this mode */
2960 TRACE("Setting color model to RGB (no-op).\n");
2961 break;
2962 default:
2963 ERR("Unknown color model!\n");
2964 wined3d_mutex_unlock();
2965 return DDERR_INVALIDPARAMS;
2968 else
2970 D3DRENDERSTATETYPE rs;
2971 switch (state)
2973 case D3DLIGHTSTATE_AMBIENT: /* 2 */
2974 rs = D3DRENDERSTATE_AMBIENT;
2975 break;
2976 case D3DLIGHTSTATE_FOGMODE: /* 4 */
2977 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2978 break;
2979 case D3DLIGHTSTATE_FOGSTART: /* 5 */
2980 rs = D3DRENDERSTATE_FOGSTART;
2981 break;
2982 case D3DLIGHTSTATE_FOGEND: /* 6 */
2983 rs = D3DRENDERSTATE_FOGEND;
2984 break;
2985 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
2986 rs = D3DRENDERSTATE_FOGDENSITY;
2987 break;
2988 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
2989 rs = D3DRENDERSTATE_COLORVERTEX;
2990 break;
2991 default:
2992 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2993 wined3d_mutex_unlock();
2994 return DDERR_INVALIDPARAMS;
2997 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2998 wined3d_mutex_unlock();
2999 return hr;
3001 wined3d_mutex_unlock();
3003 return D3D_OK;
3006 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
3007 D3DLIGHTSTATETYPE state, DWORD value)
3009 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3011 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
3013 return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
3016 /*****************************************************************************
3017 * IDirect3DDevice3::GetLightState
3019 * Returns the current setting of a light state. The state is read from
3020 * the Direct3DDevice7 render state.
3022 * Version 2 and 3
3024 * Params:
3025 * LightStateType: The light state to return
3026 * Value: The address to store the light state setting at
3028 * Returns:
3029 * D3D_OK on success
3030 * DDDERR_INVALIDPARAMS if the parameters were incorrect
3031 * Also see IDirect3DDevice7::GetRenderState
3033 *****************************************************************************/
3034 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
3035 D3DLIGHTSTATETYPE state, DWORD *value)
3037 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3038 HRESULT hr;
3040 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3042 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
3044 TRACE("Unexpected Light State Type\n");
3045 return DDERR_INVALIDPARAMS;
3048 if (!value)
3049 return DDERR_INVALIDPARAMS;
3051 wined3d_mutex_lock();
3052 if (state == D3DLIGHTSTATE_MATERIAL)
3054 *value = device->material;
3056 else if (state == D3DLIGHTSTATE_COLORMODEL)
3058 *value = D3DCOLOR_RGB;
3060 else
3062 D3DRENDERSTATETYPE rs;
3063 switch (state)
3065 case D3DLIGHTSTATE_AMBIENT: /* 2 */
3066 rs = D3DRENDERSTATE_AMBIENT;
3067 break;
3068 case D3DLIGHTSTATE_FOGMODE: /* 4 */
3069 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3070 break;
3071 case D3DLIGHTSTATE_FOGSTART: /* 5 */
3072 rs = D3DRENDERSTATE_FOGSTART;
3073 break;
3074 case D3DLIGHTSTATE_FOGEND: /* 6 */
3075 rs = D3DRENDERSTATE_FOGEND;
3076 break;
3077 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
3078 rs = D3DRENDERSTATE_FOGDENSITY;
3079 break;
3080 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
3081 rs = D3DRENDERSTATE_COLORVERTEX;
3082 break;
3083 default:
3084 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3085 wined3d_mutex_unlock();
3086 return DDERR_INVALIDPARAMS;
3089 hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3090 wined3d_mutex_unlock();
3091 return hr;
3093 wined3d_mutex_unlock();
3095 return D3D_OK;
3098 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3099 D3DLIGHTSTATETYPE state, DWORD *value)
3101 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3103 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3105 return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3108 /*****************************************************************************
3109 * IDirect3DDevice7::SetTransform
3111 * Assigns a D3DMATRIX to a transform type. The transform types are defined
3112 * in include/d3dtypes.h.
3113 * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3114 * (=255) for wined3d, because the 1 transform state was removed in d3d8
3115 * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3117 * Version 2, 3 and 7
3119 * Params:
3120 * TransformStateType: transform state to set
3121 * Matrix: Matrix to assign to the state
3123 * Returns:
3124 * D3D_OK on success
3125 * DDERR_INVALIDPARAMS if Matrix == NULL
3127 *****************************************************************************/
3128 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3129 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3131 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3133 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3135 if (!matrix)
3136 return DDERR_INVALIDPARAMS;
3138 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3139 wined3d_mutex_lock();
3140 wined3d_stateblock_set_transform(device->update_state,
3141 wined3d_transform_state_from_ddraw(state), (const struct wined3d_matrix *)matrix);
3142 wined3d_mutex_unlock();
3144 return D3D_OK;
3147 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3148 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3150 return d3d_device7_SetTransform(iface, state, matrix);
3153 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3154 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3156 HRESULT hr;
3157 WORD old_fpucw;
3159 old_fpucw = d3d_fpu_setup();
3160 hr = d3d_device7_SetTransform(iface, state, matrix);
3161 set_fpu_control_word(old_fpucw);
3163 return hr;
3166 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3167 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3169 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3171 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3173 if (!matrix)
3174 return DDERR_INVALIDPARAMS;
3176 if (state == D3DTRANSFORMSTATE_PROJECTION)
3178 struct wined3d_matrix projection;
3180 wined3d_mutex_lock();
3181 multiply_matrix(&projection, &device->legacy_clipspace, (struct wined3d_matrix *)matrix);
3182 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3183 memcpy(&device->legacy_projection, matrix, sizeof(*matrix));
3184 wined3d_mutex_unlock();
3186 return D3D_OK;
3189 return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3192 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3193 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3195 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3197 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3199 return IDirect3DDevice3_SetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3202 /*****************************************************************************
3203 * IDirect3DDevice7::GetTransform
3205 * Returns the matrix assigned to a transform state
3206 * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3207 * SetTransform
3209 * Params:
3210 * TransformStateType: State to read the matrix from
3211 * Matrix: Address to store the matrix at
3213 * Returns:
3214 * D3D_OK on success
3215 * DDERR_INVALIDPARAMS if Matrix == NULL
3217 *****************************************************************************/
3218 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3219 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3221 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3223 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3225 if (!matrix)
3226 return DDERR_INVALIDPARAMS;
3228 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3229 wined3d_mutex_lock();
3230 memcpy(matrix, &device->stateblock_state->transforms[wined3d_transform_state_from_ddraw(state)], sizeof(*matrix));
3231 wined3d_mutex_unlock();
3233 return D3D_OK;
3236 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3237 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3239 return d3d_device7_GetTransform(iface, state, matrix);
3242 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3243 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3245 HRESULT hr;
3246 WORD old_fpucw;
3248 old_fpucw = d3d_fpu_setup();
3249 hr = d3d_device7_GetTransform(iface, state, matrix);
3250 set_fpu_control_word(old_fpucw);
3252 return hr;
3255 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3256 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3258 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3260 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3262 if (!matrix)
3263 return DDERR_INVALIDPARAMS;
3265 if (state == D3DTRANSFORMSTATE_PROJECTION)
3267 wined3d_mutex_lock();
3268 memcpy(matrix, &device->legacy_projection, sizeof(*matrix));
3269 wined3d_mutex_unlock();
3270 return DD_OK;
3273 return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3276 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3277 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3279 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3281 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3283 return IDirect3DDevice3_GetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3286 /*****************************************************************************
3287 * IDirect3DDevice7::MultiplyTransform
3289 * Multiplies the already-set transform matrix of a transform state
3290 * with another matrix. For the world matrix, see SetTransform
3292 * Version 2, 3 and 7
3294 * Params:
3295 * TransformStateType: Transform state to multiply
3296 * D3DMatrix Matrix to multiply with.
3298 * Returns
3299 * D3D_OK on success
3300 * DDERR_INVALIDPARAMS if D3DMatrix is NULL
3302 *****************************************************************************/
3303 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3304 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3306 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3308 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3310 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3311 wined3d_mutex_lock();
3312 wined3d_stateblock_multiply_transform(device->state,
3313 wined3d_transform_state_from_ddraw(state), (struct wined3d_matrix *)matrix);
3314 wined3d_mutex_unlock();
3316 return D3D_OK;
3319 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3320 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3322 return d3d_device7_MultiplyTransform(iface, state, matrix);
3325 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3326 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3328 HRESULT hr;
3329 WORD old_fpucw;
3331 old_fpucw = d3d_fpu_setup();
3332 hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3333 set_fpu_control_word(old_fpucw);
3335 return hr;
3338 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3339 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3341 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3343 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3345 if (state == D3DTRANSFORMSTATE_PROJECTION)
3347 struct wined3d_matrix projection, tmp;
3349 wined3d_mutex_lock();
3350 multiply_matrix(&tmp, &device->legacy_projection, (struct wined3d_matrix *)matrix);
3351 multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3352 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3353 device->legacy_projection = tmp;
3354 wined3d_mutex_unlock();
3356 return D3D_OK;
3359 return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3362 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3363 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3365 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3367 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3369 return IDirect3DDevice3_MultiplyTransform(&device->IDirect3DDevice3_iface, state, matrix);
3372 /*****************************************************************************
3373 * IDirect3DDevice7::DrawPrimitive
3375 * Draws primitives based on vertices in an application-provided pointer
3377 * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3378 * an FVF format for D3D7
3380 * Params:
3381 * PrimitiveType: The type of the primitives to draw
3382 * Vertex type: Flexible vertex format vertex description
3383 * Vertices: Pointer to the vertex array
3384 * VertexCount: The number of vertices to draw
3385 * Flags: As usual a few flags
3387 * Returns:
3388 * D3D_OK on success
3389 * DDERR_INVALIDPARAMS if Vertices is NULL
3391 *****************************************************************************/
3393 /* The caller is responsible for wined3d locking */
3394 static HRESULT d3d_device_prepare_vertex_buffer(struct d3d_device *device, UINT min_size)
3396 HRESULT hr;
3398 if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
3400 UINT size = max(device->vertex_buffer_size * 2, min_size);
3401 struct wined3d_buffer_desc desc;
3402 struct wined3d_buffer *buffer;
3404 TRACE("Growing vertex buffer to %u bytes\n", size);
3406 desc.byte_width = size;
3407 desc.usage = WINED3DUSAGE_DYNAMIC;
3408 desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
3409 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W;
3410 desc.misc_flags = 0;
3411 desc.structure_byte_stride = 0;
3413 if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
3414 NULL, NULL, &ddraw_null_wined3d_parent_ops, &buffer)))
3416 ERR("Failed to create vertex buffer, hr %#x.\n", hr);
3417 return hr;
3420 if (device->vertex_buffer)
3421 wined3d_buffer_decref(device->vertex_buffer);
3423 device->vertex_buffer = buffer;
3424 device->vertex_buffer_size = size;
3425 device->vertex_buffer_pos = 0;
3427 return D3D_OK;
3430 static void d3d_device_sync_rendertarget(struct d3d_device *device)
3432 struct wined3d_rendertarget_view *rtv;
3434 if (device->hardware_device)
3435 return;
3437 if ((rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
3438 ddraw_surface_get_draw_texture(wined3d_rendertarget_view_get_parent(rtv), DDRAW_SURFACE_RW);
3440 if ((rtv = wined3d_device_get_depth_stencil_view(device->wined3d_device)))
3441 ddraw_surface_get_draw_texture(wined3d_rendertarget_view_get_parent(rtv), DDRAW_SURFACE_RW);
3444 void d3d_device_sync_surfaces(struct d3d_device *device)
3446 const struct wined3d_stateblock_state *state = device->stateblock_state;
3447 struct ddraw_surface *surface;
3448 unsigned int i, j;
3450 if (device->hardware_device)
3451 return;
3453 d3d_device_sync_rendertarget(device);
3455 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
3457 if (!state->textures[i])
3458 continue;
3460 j = 0;
3461 while ((surface = wined3d_texture_get_sub_resource_parent(state->textures[i], j)))
3463 if (!surface->draw_texture)
3464 break;
3465 ddraw_surface_get_draw_texture(surface, DDRAW_SURFACE_READ);
3466 ++j;
3471 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3472 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3473 DWORD vertex_count, DWORD flags)
3475 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3476 struct wined3d_map_desc wined3d_map_desc;
3477 struct wined3d_box wined3d_box = {0};
3478 UINT stride, vb_pos, size, align;
3479 struct wined3d_resource *vb;
3480 HRESULT hr;
3482 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3483 iface, primitive_type, fvf, vertices, vertex_count, flags);
3485 if (!vertex_count)
3487 WARN("0 vertex count.\n");
3488 return D3D_OK;
3491 /* Get the stride */
3492 stride = get_flexible_vertex_size(fvf);
3493 size = vertex_count * stride;
3495 wined3d_mutex_lock();
3496 hr = d3d_device_prepare_vertex_buffer(device, size);
3497 if (FAILED(hr))
3498 goto done;
3500 vb_pos = device->vertex_buffer_pos;
3501 align = vb_pos % stride;
3502 if (align) align = stride - align;
3503 if (vb_pos + size + align > device->vertex_buffer_size)
3504 vb_pos = 0;
3505 else
3506 vb_pos += align;
3508 wined3d_box.left = vb_pos;
3509 wined3d_box.right = vb_pos + size;
3510 vb = wined3d_buffer_get_resource(device->vertex_buffer);
3511 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
3512 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3513 goto done;
3514 memcpy(wined3d_map_desc.data, vertices, size);
3515 wined3d_resource_unmap(vb, 0);
3516 device->vertex_buffer_pos = vb_pos + size;
3518 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, stride);
3519 if (FAILED(hr))
3520 goto done;
3522 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3523 wined3d_device_set_primitive_type(device->wined3d_device, wined3d_primitive_type_from_ddraw(primitive_type), 0);
3524 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3525 d3d_device_sync_surfaces(device);
3526 wined3d_device_context_draw(device->immediate_context, vb_pos / stride, vertex_count, 0, 0);
3528 done:
3529 wined3d_mutex_unlock();
3530 return hr;
3533 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3534 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3535 DWORD vertex_count, DWORD flags)
3537 return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3540 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3541 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3542 DWORD vertex_count, DWORD flags)
3544 HRESULT hr;
3545 WORD old_fpucw;
3547 old_fpucw = d3d_fpu_setup();
3548 hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3549 set_fpu_control_word(old_fpucw);
3551 return hr;
3554 static void setup_lighting(const struct d3d_device *device, DWORD fvf, DWORD flags)
3556 BOOL enable = TRUE;
3558 /* Ignore the D3DFVF_XYZRHW case here, wined3d takes care of that */
3559 if (!device->material || !(fvf & D3DFVF_NORMAL) || (flags & D3DDP_DONOTLIGHT))
3560 enable = FALSE;
3562 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_LIGHTING, enable);
3566 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3567 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3568 DWORD flags)
3570 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3572 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3573 iface, primitive_type, fvf, vertices, vertex_count, flags);
3575 setup_lighting(device, fvf, flags);
3577 return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3578 primitive_type, fvf, vertices, vertex_count, flags);
3581 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3582 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3583 DWORD vertex_count, DWORD flags)
3585 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3586 DWORD fvf;
3588 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3589 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3591 switch (vertex_type)
3593 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3594 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3595 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3596 default:
3597 FIXME("Unhandled vertex type %#x.\n", vertex_type);
3598 return DDERR_INVALIDPARAMS; /* Should never happen */
3601 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface,
3602 primitive_type, fvf, vertices, vertex_count, flags);
3605 /*****************************************************************************
3606 * IDirect3DDevice7::DrawIndexedPrimitive
3608 * Draws vertices from an application-provided pointer, based on the index
3609 * numbers in a WORD array.
3611 * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3612 * an FVF format for D3D7
3614 * Params:
3615 * PrimitiveType: The primitive type to draw
3616 * VertexType: The FVF vertex description
3617 * Vertices: Pointer to the vertex array
3618 * VertexCount: ?
3619 * Indices: Pointer to the index array
3620 * IndexCount: Number of indices = Number of vertices to draw
3621 * Flags: As usual, some flags
3623 * Returns:
3624 * D3D_OK on success
3625 * DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3627 *****************************************************************************/
3628 /* The caller is responsible for wined3d locking */
3629 static HRESULT d3d_device_prepare_index_buffer(struct d3d_device *device, UINT min_size)
3631 HRESULT hr;
3633 if (device->index_buffer_size < min_size || !device->index_buffer)
3635 UINT size = max(device->index_buffer_size * 2, min_size);
3636 struct wined3d_buffer_desc desc;
3637 struct wined3d_buffer *buffer;
3639 TRACE("Growing index buffer to %u bytes\n", size);
3641 desc.byte_width = size;
3642 desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_STATICDECL;
3643 desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
3644 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W;
3645 desc.misc_flags = 0;
3646 desc.structure_byte_stride = 0;
3648 if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
3649 NULL, NULL, &ddraw_null_wined3d_parent_ops, &buffer)))
3651 ERR("Failed to create index buffer, hr %#x.\n", hr);
3652 return hr;
3655 if (device->index_buffer)
3656 wined3d_buffer_decref(device->index_buffer);
3657 device->index_buffer = buffer;
3658 device->index_buffer_size = size;
3659 device->index_buffer_pos = 0;
3661 return D3D_OK;
3664 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3665 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3666 WORD *indices, DWORD index_count, DWORD flags)
3668 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3669 HRESULT hr;
3670 UINT stride = get_flexible_vertex_size(fvf);
3671 UINT vtx_size = stride * vertex_count, idx_size = index_count * sizeof(*indices);
3672 struct wined3d_map_desc wined3d_map_desc;
3673 struct wined3d_box wined3d_box = {0};
3674 struct wined3d_resource *ib, *vb;
3675 UINT vb_pos, ib_pos, align;
3677 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3678 "indices %p, index_count %u, flags %#x.\n",
3679 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3681 if (!vertex_count || !index_count)
3683 WARN("0 vertex or index count.\n");
3684 return D3D_OK;
3687 /* Set the D3DDevice's FVF */
3688 wined3d_mutex_lock();
3690 hr = d3d_device_prepare_vertex_buffer(device, vtx_size);
3691 if (FAILED(hr))
3692 goto done;
3694 vb_pos = device->vertex_buffer_pos;
3695 align = vb_pos % stride;
3696 if (align) align = stride - align;
3697 if (vb_pos + vtx_size + align > device->vertex_buffer_size)
3698 vb_pos = 0;
3699 else
3700 vb_pos += align;
3702 wined3d_box.left = vb_pos;
3703 wined3d_box.right = vb_pos + vtx_size;
3704 vb = wined3d_buffer_get_resource(device->vertex_buffer);
3705 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
3706 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3707 goto done;
3708 memcpy(wined3d_map_desc.data, vertices, vtx_size);
3709 wined3d_resource_unmap(vb, 0);
3710 device->vertex_buffer_pos = vb_pos + vtx_size;
3712 hr = d3d_device_prepare_index_buffer(device, idx_size);
3713 if (FAILED(hr))
3714 goto done;
3715 ib_pos = device->index_buffer_pos;
3716 if (device->index_buffer_size - idx_size < ib_pos)
3717 ib_pos = 0;
3719 wined3d_box.left = ib_pos;
3720 wined3d_box.right = ib_pos + idx_size;
3721 ib = wined3d_buffer_get_resource(device->index_buffer);
3722 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
3723 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3724 goto done;
3725 memcpy(wined3d_map_desc.data, indices, idx_size);
3726 wined3d_resource_unmap(ib, 0);
3727 device->index_buffer_pos = ib_pos + idx_size;
3729 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, stride);
3730 if (FAILED(hr))
3731 goto done;
3732 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
3734 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3735 wined3d_device_set_primitive_type(device->wined3d_device, wined3d_primitive_type_from_ddraw(primitive_type), 0);
3736 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3737 d3d_device_sync_surfaces(device);
3738 wined3d_device_context_draw_indexed(device->immediate_context, vb_pos / stride,
3739 ib_pos / sizeof(*indices), index_count, 0, 0);
3741 done:
3742 wined3d_mutex_unlock();
3743 return hr;
3746 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3747 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3748 WORD *indices, DWORD index_count, DWORD flags)
3750 return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3751 vertices, vertex_count, indices, index_count, flags);
3754 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3755 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3756 WORD *indices, DWORD index_count, DWORD flags)
3758 HRESULT hr;
3759 WORD old_fpucw;
3761 old_fpucw = d3d_fpu_setup();
3762 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3763 vertices, vertex_count, indices, index_count, flags);
3764 set_fpu_control_word(old_fpucw);
3766 return hr;
3769 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3770 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3771 WORD *indices, DWORD index_count, DWORD flags)
3773 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3775 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3776 "indices %p, index_count %u, flags %#x.\n",
3777 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3779 setup_lighting(device, fvf, flags);
3781 return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3782 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3785 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3786 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3787 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3789 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3790 DWORD fvf;
3792 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3793 "indices %p, index_count %u, flags %#x.\n",
3794 iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3796 switch (vertex_type)
3798 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3799 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3800 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3801 default:
3802 ERR("Unhandled vertex type %#x.\n", vertex_type);
3803 return DDERR_INVALIDPARAMS; /* Should never happen */
3806 return d3d_device3_DrawIndexedPrimitive(&device->IDirect3DDevice3_iface,
3807 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3810 /*****************************************************************************
3811 * IDirect3DDevice3::End
3813 * Ends a draw begun with IDirect3DDevice3::Begin or
3814 * IDirect3DDevice::BeginIndexed. The vertices specified with
3815 * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
3816 * the IDirect3DDevice3::DrawPrimitive method. So far only
3817 * non-indexed mode is supported
3819 * Version 2 and 3
3821 * Params:
3822 * Flags: Some flags, as usual. Don't know which are defined
3824 * Returns:
3825 * The return value of IDirect3DDevice3::DrawPrimitive
3827 *****************************************************************************/
3828 static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
3830 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3832 TRACE("iface %p, flags %#x.\n", iface, flags);
3834 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface, device->primitive_type,
3835 device->vertex_type, device->sysmem_vertex_buffer, device->nb_vertices, device->render_flags);
3838 static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
3840 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3842 TRACE("iface %p, flags %#x.\n", iface, flags);
3844 return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
3847 /*****************************************************************************
3848 * IDirect3DDevice7::SetClipStatus
3850 * Sets the clip status. This defines things as clipping conditions and
3851 * the extents of the clipping region.
3853 * Version 2, 3 and 7
3855 * Params:
3856 * ClipStatus:
3858 * Returns:
3859 * D3D_OK because it's a stub
3860 * (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3862 *****************************************************************************/
3863 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3865 FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3867 return D3D_OK;
3870 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3872 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3874 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3876 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3879 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3881 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3883 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3885 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3888 /*****************************************************************************
3889 * IDirect3DDevice7::GetClipStatus
3891 * Returns the clip status
3893 * Params:
3894 * ClipStatus: Address to write the clip status to
3896 * Returns:
3897 * D3D_OK because it's a stub
3899 *****************************************************************************/
3900 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3902 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3903 struct wined3d_viewport vp;
3905 FIXME("iface %p, clip_status %p stub.\n", iface, clip_status);
3907 vp = device->stateblock_state->viewport;
3908 clip_status->minx = vp.x;
3909 clip_status->maxx = vp.x + vp.width;
3910 clip_status->miny = vp.y;
3911 clip_status->maxy = vp.y + vp.height;
3912 clip_status->minz = 0.0f;
3913 clip_status->maxz = 0.0f;
3914 clip_status->dwFlags = D3DCLIPSTATUS_EXTENTS2;
3915 clip_status->dwStatus = 0;
3917 return D3D_OK;
3920 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3922 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3924 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3926 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3929 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3931 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3933 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3935 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3938 /*****************************************************************************
3939 * IDirect3DDevice::DrawPrimitiveStrided
3941 * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3943 * Version 3 and 7
3945 * Params:
3946 * PrimitiveType: The primitive type to draw
3947 * VertexType: The FVF description of the vertices to draw (for the stride??)
3948 * D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3949 * the vertex data locations
3950 * VertexCount: The number of vertices to draw
3951 * Flags: Some flags
3953 * Returns:
3954 * D3D_OK, because it's a stub
3955 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3957 *****************************************************************************/
3958 static void pack_strided_data(BYTE *dst, DWORD count, const D3DDRAWPRIMITIVESTRIDEDDATA *src, DWORD fvf)
3960 DWORD i, tex, offset;
3962 for (i = 0; i < count; i++)
3964 /* The contents of the strided data are determined by the fvf,
3965 * not by the members set in src. So it's valid
3966 * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3967 * not set in the fvf. */
3968 if (fvf & D3DFVF_POSITION_MASK)
3970 offset = i * src->position.dwStride;
3971 if (fvf & D3DFVF_XYZRHW)
3973 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 4 * sizeof(float));
3974 dst += 4 * sizeof(float);
3976 else
3978 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 3 * sizeof(float));
3979 dst += 3 * sizeof(float);
3983 if (fvf & D3DFVF_NORMAL)
3985 offset = i * src->normal.dwStride;
3986 memcpy(dst, ((BYTE *)src->normal.lpvData) + offset, 3 * sizeof(float));
3987 dst += 3 * sizeof(float);
3990 if (fvf & D3DFVF_DIFFUSE)
3992 offset = i * src->diffuse.dwStride;
3993 memcpy(dst, ((BYTE *)src->diffuse.lpvData) + offset, sizeof(DWORD));
3994 dst += sizeof(DWORD);
3997 if (fvf & D3DFVF_SPECULAR)
3999 offset = i * src->specular.dwStride;
4000 memcpy(dst, ((BYTE *)src->specular.lpvData) + offset, sizeof(DWORD));
4001 dst += sizeof(DWORD);
4004 for (tex = 0; tex < GET_TEXCOUNT_FROM_FVF(fvf); ++tex)
4006 DWORD attrib_count = GET_TEXCOORD_SIZE_FROM_FVF(fvf, tex);
4007 offset = i * src->textureCoords[tex].dwStride;
4008 memcpy(dst, ((BYTE *)src->textureCoords[tex].lpvData) + offset, attrib_count * sizeof(float));
4009 dst += attrib_count * sizeof(float);
4014 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
4015 DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data, DWORD vertex_count, DWORD flags)
4017 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4018 HRESULT hr;
4019 UINT dst_stride = get_flexible_vertex_size(fvf);
4020 UINT dst_size = dst_stride * vertex_count;
4021 struct wined3d_map_desc wined3d_map_desc;
4022 struct wined3d_box wined3d_box = {0};
4023 struct wined3d_resource *vb;
4024 UINT vb_pos, align;
4026 TRACE("iface %p, primitive_type %#x, fvf %#x, strided_data %p, vertex_count %u, flags %#x.\n",
4027 iface, primitive_type, fvf, strided_data, vertex_count, flags);
4029 if (!vertex_count)
4031 WARN("0 vertex count.\n");
4032 return D3D_OK;
4035 wined3d_mutex_lock();
4036 hr = d3d_device_prepare_vertex_buffer(device, dst_size);
4037 if (FAILED(hr))
4038 goto done;
4040 vb_pos = device->vertex_buffer_pos;
4041 align = vb_pos % dst_stride;
4042 if (align) align = dst_stride - align;
4043 if (vb_pos + dst_size + align > device->vertex_buffer_size)
4044 vb_pos = 0;
4045 else
4046 vb_pos += align;
4048 wined3d_box.left = vb_pos;
4049 wined3d_box.right = vb_pos + dst_size;
4050 vb = wined3d_buffer_get_resource(device->vertex_buffer);
4051 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
4052 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4053 goto done;
4054 pack_strided_data(wined3d_map_desc.data, vertex_count, strided_data, fvf);
4055 wined3d_resource_unmap(vb, 0);
4056 device->vertex_buffer_pos = vb_pos + dst_size;
4058 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, dst_stride);
4059 if (FAILED(hr))
4060 goto done;
4061 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4063 wined3d_device_set_primitive_type(device->wined3d_device, wined3d_primitive_type_from_ddraw(primitive_type), 0);
4064 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4065 d3d_device_sync_surfaces(device);
4066 wined3d_device_context_draw(device->immediate_context, vb_pos / dst_stride, vertex_count, 0, 0);
4068 done:
4069 wined3d_mutex_unlock();
4070 return hr;
4073 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4074 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4075 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4077 return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
4078 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4081 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4082 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4083 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4085 HRESULT hr;
4086 WORD old_fpucw;
4088 old_fpucw = d3d_fpu_setup();
4089 hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
4090 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4091 set_fpu_control_word(old_fpucw);
4093 return hr;
4096 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
4097 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4098 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4100 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4102 TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
4103 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4105 setup_lighting(device, VertexType, Flags);
4107 return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
4108 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4111 /*****************************************************************************
4112 * IDirect3DDevice7::DrawIndexedPrimitiveStrided
4114 * Draws primitives specified by strided data locations based on indices
4116 * Version 3 and 7
4118 * Params:
4119 * PrimitiveType:
4121 * Returns:
4122 * D3D_OK, because it's a stub
4123 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
4124 * (DDERR_INVALIDPARAMS if Indices is NULL)
4126 *****************************************************************************/
4127 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
4128 D3DPRIMITIVETYPE primitive_type, DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data,
4129 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4131 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4132 UINT vtx_dst_stride = get_flexible_vertex_size(fvf);
4133 UINT vtx_dst_size = vertex_count * vtx_dst_stride;
4134 UINT idx_size = index_count * sizeof(WORD);
4135 struct wined3d_map_desc wined3d_map_desc;
4136 struct wined3d_box wined3d_box = {0};
4137 struct wined3d_resource *ib, *vb;
4138 UINT vb_pos, align;
4139 UINT ib_pos;
4140 HRESULT hr;
4142 TRACE("iface %p, primitive_type %#x, fvf %#x, strided_data %p, "
4143 "vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4144 iface, primitive_type, fvf, strided_data, vertex_count, indices, index_count, flags);
4146 if (!vertex_count || !index_count)
4148 WARN("0 vertex or index count.\n");
4149 return D3D_OK;
4152 wined3d_mutex_lock();
4154 hr = d3d_device_prepare_vertex_buffer(device, vtx_dst_size);
4155 if (FAILED(hr))
4156 goto done;
4158 vb_pos = device->vertex_buffer_pos;
4159 align = vb_pos % vtx_dst_stride;
4160 if (align) align = vtx_dst_stride - align;
4161 if (vb_pos + vtx_dst_size + align > device->vertex_buffer_size)
4162 vb_pos = 0;
4163 else
4164 vb_pos += align;
4166 wined3d_box.left = vb_pos;
4167 wined3d_box.right = vb_pos + vtx_dst_size;
4168 vb = wined3d_buffer_get_resource(device->vertex_buffer);
4169 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
4170 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4171 goto done;
4172 pack_strided_data(wined3d_map_desc.data, vertex_count, strided_data, fvf);
4173 wined3d_resource_unmap(vb, 0);
4174 device->vertex_buffer_pos = vb_pos + vtx_dst_size;
4176 hr = d3d_device_prepare_index_buffer(device, idx_size);
4177 if (FAILED(hr))
4178 goto done;
4179 ib_pos = device->index_buffer_pos;
4180 if (device->index_buffer_size - idx_size < ib_pos)
4181 ib_pos = 0;
4183 wined3d_box.left = ib_pos;
4184 wined3d_box.right = ib_pos + idx_size;
4185 ib = wined3d_buffer_get_resource(device->index_buffer);
4186 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
4187 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4188 goto done;
4189 memcpy(wined3d_map_desc.data, indices, idx_size);
4190 wined3d_resource_unmap(ib, 0);
4191 device->index_buffer_pos = ib_pos + idx_size;
4193 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, vtx_dst_stride);
4194 if (FAILED(hr))
4195 goto done;
4196 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
4198 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4199 wined3d_device_set_primitive_type(device->wined3d_device, wined3d_primitive_type_from_ddraw(primitive_type), 0);
4200 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4201 d3d_device_sync_surfaces(device);
4202 wined3d_device_context_draw_indexed(device->immediate_context,
4203 vb_pos / vtx_dst_stride, ib_pos / sizeof(WORD), index_count, 0, 0);
4205 done:
4206 wined3d_mutex_unlock();
4207 return hr;
4210 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4211 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4212 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4213 WORD *Indices, DWORD IndexCount, DWORD Flags)
4215 return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4216 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4219 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4220 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4221 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4222 WORD *Indices, DWORD IndexCount, DWORD Flags)
4224 HRESULT hr;
4225 WORD old_fpucw;
4227 old_fpucw = d3d_fpu_setup();
4228 hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4229 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4230 set_fpu_control_word(old_fpucw);
4232 return hr;
4235 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4236 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4237 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4238 DWORD IndexCount, DWORD Flags)
4240 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4242 TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4243 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4245 setup_lighting(device, VertexType, Flags);
4247 return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
4248 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4251 /*****************************************************************************
4252 * IDirect3DDevice7::DrawPrimitiveVB
4254 * Draws primitives from a vertex buffer to the screen.
4256 * Version 3 and 7
4258 * Params:
4259 * PrimitiveType: Type of primitive to be rendered.
4260 * D3DVertexBuf: Source Vertex Buffer
4261 * StartVertex: Index of the first vertex from the buffer to be rendered
4262 * NumVertices: Number of vertices to be rendered
4263 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4265 * Return values
4266 * D3D_OK on success
4267 * DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4269 *****************************************************************************/
4270 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
4271 IDirect3DVertexBuffer7 *vb, DWORD start_vertex, DWORD vertex_count, DWORD flags)
4273 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4274 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4275 struct wined3d_resource *wined3d_resource;
4276 struct wined3d_map_desc wined3d_map_desc;
4277 struct wined3d_box wined3d_box = {0};
4278 DWORD stride;
4279 HRESULT hr;
4281 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4282 iface, primitive_type, vb, start_vertex, vertex_count, flags);
4284 if (!vertex_count)
4286 WARN("0 vertex count.\n");
4287 return D3D_OK;
4290 stride = get_flexible_vertex_size(vb_impl->fvf);
4292 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4294 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawPrimitive().\n");
4295 wined3d_mutex_lock();
4296 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4297 wined3d_box.left = start_vertex * stride;
4298 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4299 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4300 &wined3d_box, WINED3D_MAP_READ)))
4302 wined3d_mutex_unlock();
4303 return D3DERR_VERTEXBUFFERLOCKED;
4305 hr = d3d_device7_DrawPrimitive(iface, primitive_type, vb_impl->fvf, wined3d_map_desc.data,
4306 vertex_count, flags);
4307 wined3d_resource_unmap(wined3d_resource, 0);
4308 wined3d_mutex_unlock();
4309 return hr;
4312 wined3d_mutex_lock();
4313 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4314 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4315 0, vb_impl->wined3d_buffer, 0, stride)))
4317 WARN("Failed to set stream source, hr %#x.\n", hr);
4318 wined3d_mutex_unlock();
4319 return hr;
4322 /* Now draw the primitives */
4323 wined3d_device_set_primitive_type(device->wined3d_device, wined3d_primitive_type_from_ddraw(primitive_type), 0);
4324 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4325 d3d_device_sync_surfaces(device);
4326 wined3d_device_context_draw(device->immediate_context, start_vertex, vertex_count, 0, 0);
4328 wined3d_mutex_unlock();
4330 return hr;
4333 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4334 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4336 return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4339 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4340 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4342 HRESULT hr;
4343 WORD old_fpucw;
4345 old_fpucw = d3d_fpu_setup();
4346 hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4347 set_fpu_control_word(old_fpucw);
4349 return hr;
4352 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4353 IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4355 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4356 struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)D3DVertexBuf);
4358 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4359 iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4361 setup_lighting(device, vb->fvf, Flags);
4363 return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4364 PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4367 /*****************************************************************************
4368 * IDirect3DDevice7::DrawIndexedPrimitiveVB
4370 * Draws primitives from a vertex buffer to the screen
4372 * Params:
4373 * PrimitiveType: Type of primitive to be rendered.
4374 * D3DVertexBuf: Source Vertex Buffer
4375 * StartVertex: Index of the first vertex from the buffer to be rendered
4376 * NumVertices: Number of vertices to be rendered
4377 * Indices: Array of DWORDs used to index into the Vertices
4378 * IndexCount: Number of indices in Indices
4379 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4381 * Return values
4383 *****************************************************************************/
4384 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4385 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer7 *vb,
4386 DWORD start_vertex, DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4388 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4389 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4390 DWORD stride = get_flexible_vertex_size(vb_impl->fvf);
4391 struct wined3d_resource *wined3d_resource;
4392 struct wined3d_map_desc wined3d_map_desc;
4393 struct wined3d_box wined3d_box = {0};
4394 struct wined3d_resource *ib;
4395 HRESULT hr;
4396 UINT ib_pos;
4398 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, "
4399 "vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4400 iface, primitive_type, vb, start_vertex, vertex_count, indices, index_count, flags);
4402 if (!vertex_count || !index_count)
4404 WARN("0 vertex or index count.\n");
4405 return D3D_OK;
4408 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4410 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawIndexedPrimitive().\n");
4411 wined3d_mutex_lock();
4412 wined3d_box.left = start_vertex * stride;
4413 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4414 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4415 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4416 &wined3d_box, WINED3D_MAP_READ)))
4418 wined3d_mutex_unlock();
4419 return D3DERR_VERTEXBUFFERLOCKED;
4421 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, vb_impl->fvf,
4422 wined3d_map_desc.data, vertex_count, indices, index_count, flags);
4423 wined3d_resource_unmap(wined3d_resource, 0);
4424 wined3d_mutex_unlock();
4425 return hr;
4428 /* Steps:
4429 * 1) Upload the indices to the index buffer
4430 * 2) Set the index source
4431 * 3) Set the Vertex Buffer as the Stream source
4432 * 4) Call wined3d_device_context_draw_indexed()
4435 wined3d_mutex_lock();
4437 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4439 hr = d3d_device_prepare_index_buffer(device, index_count * sizeof(WORD));
4440 if (FAILED(hr))
4442 wined3d_mutex_unlock();
4443 return hr;
4445 ib_pos = device->index_buffer_pos;
4447 if (device->index_buffer_size - index_count * sizeof(WORD) < ib_pos)
4448 ib_pos = 0;
4450 /* Copy the index stream into the index buffer. */
4451 wined3d_box.left = ib_pos;
4452 wined3d_box.right = ib_pos + index_count * sizeof(WORD);
4453 ib = wined3d_buffer_get_resource(device->index_buffer);
4454 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
4455 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4457 ERR("Failed to map buffer, hr %#x.\n", hr);
4458 wined3d_mutex_unlock();
4459 return hr;
4461 memcpy(wined3d_map_desc.data, indices, index_count * sizeof(WORD));
4462 wined3d_resource_unmap(ib, 0);
4463 device->index_buffer_pos = ib_pos + index_count * sizeof(WORD);
4465 /* Set the index stream */
4466 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
4468 /* Set the vertex stream source */
4469 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4470 0, vb_impl->wined3d_buffer, 0, stride)))
4472 ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", device, hr);
4473 wined3d_mutex_unlock();
4474 return hr;
4477 wined3d_device_set_primitive_type(device->wined3d_device, wined3d_primitive_type_from_ddraw(primitive_type), 0);
4478 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4479 d3d_device_sync_surfaces(device);
4480 wined3d_device_context_draw_indexed(device->immediate_context, start_vertex,
4481 ib_pos / sizeof(WORD), index_count, 0, 0);
4483 wined3d_mutex_unlock();
4485 return hr;
4488 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4489 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4490 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4492 return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4493 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4496 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4497 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4498 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4500 HRESULT hr;
4501 WORD old_fpucw;
4503 old_fpucw = d3d_fpu_setup();
4504 hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4505 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4506 set_fpu_control_word(old_fpucw);
4508 return hr;
4511 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4512 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer *vertex_buffer,
4513 WORD *indices, DWORD index_count, DWORD flags)
4515 struct d3d_vertex_buffer *vb =
4516 unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)vertex_buffer);
4517 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4518 DWORD stride;
4520 TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4521 iface, primitive_type, vertex_buffer, indices, index_count, flags);
4523 setup_lighting(device, vb->fvf, flags);
4525 if (!(stride = get_flexible_vertex_size(vb->fvf)))
4526 return D3D_OK;
4528 return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, primitive_type,
4529 &vb->IDirect3DVertexBuffer7_iface, 0, vb->size / stride, indices, index_count, flags);
4532 /*****************************************************************************
4533 * IDirect3DDevice7::ComputeSphereVisibility
4535 * Calculates the visibility of spheres in the current viewport. The spheres
4536 * are passed in the Centers and Radii arrays, the results are passed back
4537 * in the ReturnValues array. Return values are either completely visible,
4538 * partially visible or completely invisible.
4539 * The return value consists of a combination of D3DCLIP_* flags, or is
4540 * 0 if the sphere is completely visible (according to the SDK, not checked)
4542 * Version 3 and 7
4544 * Params:
4545 * Centers: Array containing the sphere centers
4546 * Radii: Array containing the sphere radii
4547 * NumSpheres: The number of centers and radii in the arrays
4548 * Flags: Some flags
4549 * ReturnValues: Array to write the results to
4551 * Returns:
4552 * D3D_OK
4553 * (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4554 * (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4555 * is singular)
4557 *****************************************************************************/
4559 static DWORD in_plane(UINT idx, struct wined3d_vec4 p, D3DVECTOR center, D3DVALUE radius, BOOL equality)
4561 float distance, norm;
4563 norm = sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
4564 distance = (p.x * center.u1.x + p.y * center.u2.y + p.z * center.u3.z + p.w) / norm;
4566 if (equality)
4568 if (fabs(distance) <= radius)
4569 return D3DSTATUS_CLIPUNIONLEFT << idx;
4570 if (distance <= -radius)
4571 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4573 else
4575 if (fabs(distance) < radius)
4576 return D3DSTATUS_CLIPUNIONLEFT << idx;
4577 if (distance < -radius)
4578 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4580 return 0;
4583 static void prepare_clip_space_planes(struct d3d_device *device, struct wined3d_vec4 *plane)
4585 const struct wined3d_stateblock_state *state;
4586 struct wined3d_matrix m;
4588 /* We want the wined3d matrices since those include the legacy viewport
4589 * transformation. */
4590 wined3d_mutex_lock();
4591 state = device->stateblock_state;
4592 multiply_matrix(&m, &state->transforms[WINED3D_TS_VIEW], &state->transforms[WINED3D_TS_WORLD]);
4593 multiply_matrix(&m, &state->transforms[WINED3D_TS_PROJECTION], &m);
4594 wined3d_mutex_unlock();
4596 /* Left plane. */
4597 plane[0].x = m._14 + m._11;
4598 plane[0].y = m._24 + m._21;
4599 plane[0].z = m._34 + m._31;
4600 plane[0].w = m._44 + m._41;
4602 /* Right plane. */
4603 plane[1].x = m._14 - m._11;
4604 plane[1].y = m._24 - m._21;
4605 plane[1].z = m._34 - m._31;
4606 plane[1].w = m._44 - m._41;
4608 /* Top plane. */
4609 plane[2].x = m._14 - m._12;
4610 plane[2].y = m._24 - m._22;
4611 plane[2].z = m._34 - m._32;
4612 plane[2].w = m._44 - m._42;
4614 /* Bottom plane. */
4615 plane[3].x = m._14 + m._12;
4616 plane[3].y = m._24 + m._22;
4617 plane[3].z = m._34 + m._32;
4618 plane[3].w = m._44 + m._42;
4620 /* Front plane. */
4621 plane[4].x = m._13;
4622 plane[4].y = m._23;
4623 plane[4].z = m._33;
4624 plane[4].w = m._43;
4626 /* Back plane. */
4627 plane[5].x = m._14 - m._13;
4628 plane[5].y = m._24 - m._23;
4629 plane[5].z = m._34 - m._33;
4630 plane[5].w = m._44 - m._43;
4633 static void compute_sphere_visibility(struct wined3d_vec4 plane[12], DWORD enabled_planes, BOOL equality,
4634 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD *return_values)
4636 UINT i, j;
4638 for (i = 0; i < sphere_count; ++i)
4640 return_values[i] = 0;
4641 for (j = 0; j < 12; ++j)
4642 if (enabled_planes & 1u << j)
4643 return_values[i] |= in_plane(j, plane[j], centers[i], radii[i], equality);
4647 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4648 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4650 struct wined3d_vec4 plane[12];
4651 DWORD enabled_planes = 0x3f;
4652 DWORD user_clip_planes;
4653 UINT j;
4655 TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4656 iface, centers, radii, sphere_count, flags, return_values);
4658 prepare_clip_space_planes(impl_from_IDirect3DDevice7(iface), plane);
4660 IDirect3DDevice7_GetRenderState(iface, D3DRENDERSTATE_CLIPPLANEENABLE, &user_clip_planes);
4661 enabled_planes |= user_clip_planes << 6;
4662 for (j = 6; j < 12; ++j)
4663 IDirect3DDevice7_GetClipPlane(iface, j - 6, (D3DVALUE *)&plane[j]);
4665 compute_sphere_visibility(plane, enabled_planes, FALSE, centers, radii, sphere_count, return_values);
4666 return D3D_OK;
4669 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4670 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4672 static const DWORD enabled_planes = 0x3f;
4673 struct wined3d_vec4 plane[6];
4674 unsigned int i, j;
4676 TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4677 iface, centers, radii, sphere_count, flags, return_values);
4679 prepare_clip_space_planes(impl_from_IDirect3DDevice3(iface), plane);
4681 compute_sphere_visibility(plane, enabled_planes, TRUE, centers, radii, sphere_count, return_values);
4682 for (i = 0; i < sphere_count; ++i)
4684 BOOL intersect_frustum = FALSE, outside_frustum = FALSE;
4685 DWORD d3d7_result = return_values[i];
4687 return_values[i] = 0;
4689 for (j = 0; j < 6; ++j)
4691 DWORD clip = (d3d7_result >> j) & (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT);
4693 if (clip == D3DSTATUS_CLIPUNIONLEFT)
4695 return_values[i] |= D3DVIS_INTERSECT_LEFT << j * 2;
4696 intersect_frustum = TRUE;
4698 else if (clip)
4700 return_values[i] |= D3DVIS_OUTSIDE_LEFT << j * 2;
4701 outside_frustum = TRUE;
4704 if (outside_frustum)
4705 return_values[i] |= D3DVIS_OUTSIDE_FRUSTUM;
4706 else if (intersect_frustum)
4707 return_values[i] |= D3DVIS_INTERSECT_FRUSTUM;
4709 return D3D_OK;
4712 /*****************************************************************************
4713 * IDirect3DDevice7::GetTexture
4715 * Returns the texture interface handle assigned to a texture stage.
4716 * The returned texture is AddRefed. This is taken from old ddraw,
4717 * not checked in Windows.
4719 * Version 3 and 7
4721 * Params:
4722 * Stage: Texture stage to read the texture from
4723 * Texture: Address to store the interface pointer at
4725 * Returns:
4726 * D3D_OK on success
4727 * DDERR_INVALIDPARAMS if Texture is NULL
4729 *****************************************************************************/
4730 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4731 DWORD stage, IDirectDrawSurface7 **texture)
4733 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4734 struct wined3d_texture *wined3d_texture;
4735 struct ddraw_texture *ddraw_texture;
4737 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4739 if (!texture)
4740 return DDERR_INVALIDPARAMS;
4742 if (stage >= DDRAW_MAX_TEXTURES)
4744 WARN("Invalid stage %u.\n", stage);
4745 *texture = NULL;
4746 return D3D_OK;
4749 wined3d_mutex_lock();
4750 if (!(wined3d_texture = device->stateblock_state->textures[stage]))
4752 *texture = NULL;
4753 wined3d_mutex_unlock();
4754 return D3D_OK;
4757 ddraw_texture = wined3d_texture_get_parent(wined3d_texture);
4758 *texture = &ddraw_texture->root->IDirectDrawSurface7_iface;
4759 IDirectDrawSurface7_AddRef(*texture);
4760 wined3d_mutex_unlock();
4762 return D3D_OK;
4765 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4766 DWORD stage, IDirectDrawSurface7 **Texture)
4768 return d3d_device7_GetTexture(iface, stage, Texture);
4771 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4772 DWORD stage, IDirectDrawSurface7 **Texture)
4774 HRESULT hr;
4775 WORD old_fpucw;
4777 old_fpucw = d3d_fpu_setup();
4778 hr = d3d_device7_GetTexture(iface, stage, Texture);
4779 set_fpu_control_word(old_fpucw);
4781 return hr;
4784 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4786 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4787 struct ddraw_surface *ret_val_impl;
4788 HRESULT ret;
4789 IDirectDrawSurface7 *ret_val;
4791 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4793 ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4795 ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4796 *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4798 TRACE("Returning texture %p.\n", *Texture2);
4800 return ret;
4803 /*****************************************************************************
4804 * IDirect3DDevice7::SetTexture
4806 * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4808 * Version 3 and 7
4810 * Params:
4811 * Stage: The stage to assign the texture to
4812 * Texture: Interface pointer to the texture surface
4814 * Returns
4815 * D3D_OK on success
4817 *****************************************************************************/
4818 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4819 DWORD stage, IDirectDrawSurface7 *texture)
4821 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4822 struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4823 struct wined3d_texture *wined3d_texture = NULL;
4825 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4827 if (surf && (surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE))
4828 wined3d_texture = surf->draw_texture ? surf->draw_texture : surf->wined3d_texture;
4830 wined3d_mutex_lock();
4831 wined3d_stateblock_set_texture(device->update_state, stage, wined3d_texture);
4832 wined3d_mutex_unlock();
4834 return D3D_OK;
4837 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4838 DWORD stage, IDirectDrawSurface7 *texture)
4840 return d3d_device7_SetTexture(iface, stage, texture);
4843 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4844 DWORD stage, IDirectDrawSurface7 *texture)
4846 HRESULT hr;
4847 WORD old_fpucw;
4849 old_fpucw = d3d_fpu_setup();
4850 hr = d3d_device7_SetTexture(iface, stage, texture);
4851 set_fpu_control_word(old_fpucw);
4853 return hr;
4856 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4857 DWORD stage, IDirect3DTexture2 *texture)
4859 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4860 struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4861 struct wined3d_texture *wined3d_texture = NULL;
4863 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4865 wined3d_mutex_lock();
4867 if (tex && ((tex->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) || !device->hardware_device))
4868 wined3d_texture = tex->draw_texture ? tex->draw_texture : tex->wined3d_texture;
4870 wined3d_stateblock_set_texture(device->state, stage, wined3d_texture);
4871 fixup_texture_alpha_op(device);
4873 wined3d_mutex_unlock();
4875 return D3D_OK;
4878 static const struct tss_lookup
4880 BOOL sampler_state;
4881 union
4883 enum wined3d_texture_stage_state texture_state;
4884 enum wined3d_sampler_state sampler_state;
4885 } u;
4887 tss_lookup[] =
4889 {FALSE, {WINED3D_TSS_INVALID}}, /* 0, unused */
4890 {FALSE, {WINED3D_TSS_COLOR_OP}}, /* 1, D3DTSS_COLOROP */
4891 {FALSE, {WINED3D_TSS_COLOR_ARG1}}, /* 2, D3DTSS_COLORARG1 */
4892 {FALSE, {WINED3D_TSS_COLOR_ARG2}}, /* 3, D3DTSS_COLORARG2 */
4893 {FALSE, {WINED3D_TSS_ALPHA_OP}}, /* 4, D3DTSS_ALPHAOP */
4894 {FALSE, {WINED3D_TSS_ALPHA_ARG1}}, /* 5, D3DTSS_ALPHAARG1 */
4895 {FALSE, {WINED3D_TSS_ALPHA_ARG2}}, /* 6, D3DTSS_ALPHAARG2 */
4896 {FALSE, {WINED3D_TSS_BUMPENV_MAT00}}, /* 7, D3DTSS_BUMPENVMAT00 */
4897 {FALSE, {WINED3D_TSS_BUMPENV_MAT01}}, /* 8, D3DTSS_BUMPENVMAT01 */
4898 {FALSE, {WINED3D_TSS_BUMPENV_MAT10}}, /* 9, D3DTSS_BUMPENVMAT10 */
4899 {FALSE, {WINED3D_TSS_BUMPENV_MAT11}}, /* 10, D3DTSS_BUMPENVMAT11 */
4900 {FALSE, {WINED3D_TSS_TEXCOORD_INDEX}}, /* 11, D3DTSS_TEXCOORDINDEX */
4901 {TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 12, D3DTSS_ADDRESS */
4902 {TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 13, D3DTSS_ADDRESSU */
4903 {TRUE, {WINED3D_SAMP_ADDRESS_V}}, /* 14, D3DTSS_ADDRESSV */
4904 {TRUE, {WINED3D_SAMP_BORDER_COLOR}}, /* 15, D3DTSS_BORDERCOLOR */
4905 {TRUE, {WINED3D_SAMP_MAG_FILTER}}, /* 16, D3DTSS_MAGFILTER */
4906 {TRUE, {WINED3D_SAMP_MIN_FILTER}}, /* 17, D3DTSS_MINFILTER */
4907 {TRUE, {WINED3D_SAMP_MIP_FILTER}}, /* 18, D3DTSS_MIPFILTER */
4908 {TRUE, {WINED3D_SAMP_MIPMAP_LOD_BIAS}}, /* 19, D3DTSS_MIPMAPLODBIAS */
4909 {TRUE, {WINED3D_SAMP_MAX_MIP_LEVEL}}, /* 20, D3DTSS_MAXMIPLEVEL */
4910 {TRUE, {WINED3D_SAMP_MAX_ANISOTROPY}}, /* 21, D3DTSS_MAXANISOTROPY */
4911 {FALSE, {WINED3D_TSS_BUMPENV_LSCALE}}, /* 22, D3DTSS_BUMPENVLSCALE */
4912 {FALSE, {WINED3D_TSS_BUMPENV_LOFFSET}}, /* 23, D3DTSS_BUMPENVLOFFSET */
4913 {FALSE, {WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS}}, /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4916 /*****************************************************************************
4917 * IDirect3DDevice7::GetTextureStageState
4919 * Retrieves a state from a texture stage.
4921 * Version 3 and 7
4923 * Params:
4924 * Stage: The stage to retrieve the state from
4925 * TexStageStateType: The state type to retrieve
4926 * State: Address to store the state's value at
4928 * Returns:
4929 * D3D_OK on success
4930 * DDERR_INVALIDPARAMS if State is NULL
4932 *****************************************************************************/
4933 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4934 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4936 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4937 const struct wined3d_stateblock_state *device_state;
4938 const struct tss_lookup *l;
4940 TRACE("iface %p, stage %u, state %#x, value %p.\n",
4941 iface, stage, state, value);
4943 if (!value)
4944 return DDERR_INVALIDPARAMS;
4946 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4948 WARN("Invalid state %#x passed.\n", state);
4949 return DD_OK;
4952 if (stage >= DDRAW_MAX_TEXTURES)
4954 WARN("Invalid stage %u.\n", stage);
4955 *value = 0;
4956 return D3D_OK;
4959 l = &tss_lookup[state];
4961 wined3d_mutex_lock();
4963 device_state = device->stateblock_state;
4965 if (l->sampler_state)
4967 *value = device_state->sampler_states[stage][l->u.sampler_state];
4969 switch (state)
4971 /* Mipfilter is a sampler state with different values */
4972 case D3DTSS_MIPFILTER:
4974 switch (*value)
4976 case WINED3D_TEXF_NONE:
4977 *value = D3DTFP_NONE;
4978 break;
4979 case WINED3D_TEXF_POINT:
4980 *value = D3DTFP_POINT;
4981 break;
4982 case WINED3D_TEXF_LINEAR:
4983 *value = D3DTFP_LINEAR;
4984 break;
4985 default:
4986 ERR("Unexpected mipfilter value %#x.\n", *value);
4987 *value = D3DTFP_NONE;
4988 break;
4990 break;
4993 /* Magfilter has slightly different values */
4994 case D3DTSS_MAGFILTER:
4996 switch (*value)
4998 case WINED3D_TEXF_POINT:
4999 *value = D3DTFG_POINT;
5000 break;
5001 case WINED3D_TEXF_LINEAR:
5002 *value = D3DTFG_LINEAR;
5003 break;
5004 case WINED3D_TEXF_ANISOTROPIC:
5005 *value = D3DTFG_ANISOTROPIC;
5006 break;
5007 case WINED3D_TEXF_FLAT_CUBIC:
5008 *value = D3DTFG_FLATCUBIC;
5009 break;
5010 case WINED3D_TEXF_GAUSSIAN_CUBIC:
5011 *value = D3DTFG_GAUSSIANCUBIC;
5012 break;
5013 default:
5014 ERR("Unexpected wined3d mag filter value %#x.\n", *value);
5015 *value = D3DTFG_POINT;
5016 break;
5018 break;
5021 default:
5022 break;
5025 else
5027 *value = device_state->texture_states[stage][l->u.texture_state];
5030 wined3d_mutex_unlock();
5032 return D3D_OK;
5035 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5036 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5038 return d3d_device7_GetTextureStageState(iface, stage, state, value);
5041 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5042 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5044 HRESULT hr;
5045 WORD old_fpucw;
5047 old_fpucw = d3d_fpu_setup();
5048 hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
5049 set_fpu_control_word(old_fpucw);
5051 return hr;
5054 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
5055 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5057 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5059 TRACE("iface %p, stage %u, state %#x, value %p.\n",
5060 iface, stage, state, value);
5062 return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5065 /*****************************************************************************
5066 * IDirect3DDevice7::SetTextureStageState
5068 * Sets a texture stage state. Some stage types need to be handled specially,
5069 * because they do not exist in WineD3D and were moved to another place
5071 * Version 3 and 7
5073 * Params:
5074 * Stage: The stage to modify
5075 * TexStageStateType: The state to change
5076 * State: The new value for the state
5078 * Returns:
5079 * D3D_OK on success
5081 *****************************************************************************/
5082 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
5083 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5085 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5086 const struct tss_lookup *l;
5088 TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5089 iface, stage, state, value);
5091 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
5093 WARN("Invalid state %#x passed.\n", state);
5094 return DD_OK;
5097 l = &tss_lookup[state];
5099 wined3d_mutex_lock();
5101 if (l->sampler_state)
5103 switch (state)
5105 /* Mipfilter is a sampler state with different values */
5106 case D3DTSS_MIPFILTER:
5108 switch (value)
5110 case D3DTFP_NONE:
5111 value = WINED3D_TEXF_NONE;
5112 break;
5113 case D3DTFP_POINT:
5114 value = WINED3D_TEXF_POINT;
5115 break;
5116 case 0: /* Unchecked */
5117 case D3DTFP_LINEAR:
5118 value = WINED3D_TEXF_LINEAR;
5119 break;
5120 default:
5121 ERR("Unexpected mipfilter value %#x.\n", value);
5122 value = WINED3D_TEXF_NONE;
5123 break;
5125 break;
5128 /* Magfilter has slightly different values */
5129 case D3DTSS_MAGFILTER:
5131 switch (value)
5133 case D3DTFG_POINT:
5134 value = WINED3D_TEXF_POINT;
5135 break;
5136 case D3DTFG_LINEAR:
5137 value = WINED3D_TEXF_LINEAR;
5138 break;
5139 case D3DTFG_FLATCUBIC:
5140 value = WINED3D_TEXF_FLAT_CUBIC;
5141 break;
5142 case D3DTFG_GAUSSIANCUBIC:
5143 value = WINED3D_TEXF_GAUSSIAN_CUBIC;
5144 break;
5145 case D3DTFG_ANISOTROPIC:
5146 value = WINED3D_TEXF_ANISOTROPIC;
5147 break;
5148 default:
5149 ERR("Unexpected d3d7 mag filter value %#x.\n", value);
5150 value = WINED3D_TEXF_POINT;
5151 break;
5153 break;
5156 case D3DTSS_ADDRESS:
5157 wined3d_stateblock_set_sampler_state(device->state, stage, WINED3D_SAMP_ADDRESS_V, value);
5158 break;
5160 default:
5161 break;
5164 wined3d_stateblock_set_sampler_state(device->state, stage, l->u.sampler_state, value);
5166 else
5167 wined3d_stateblock_set_texture_stage_state(device->update_state, stage, l->u.texture_state, value);
5169 wined3d_mutex_unlock();
5171 return D3D_OK;
5174 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5175 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5177 return d3d_device7_SetTextureStageState(iface, stage, state, value);
5180 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5181 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5183 HRESULT hr;
5184 WORD old_fpucw;
5186 old_fpucw = d3d_fpu_setup();
5187 hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
5188 set_fpu_control_word(old_fpucw);
5190 return hr;
5193 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
5194 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5196 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5197 DWORD old_value;
5198 HRESULT hr;
5200 TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5201 iface, stage, state, value);
5203 /* Tests show that legacy texture blending is not reset if the texture stage state
5204 * value is unchanged. */
5205 if (FAILED(hr = IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface,
5206 stage, state, &old_value)))
5207 return hr;
5209 if (old_value == value)
5211 TRACE("Application is setting the same value over, nothing to do.\n");
5212 return D3D_OK;
5215 device->legacyTextureBlending = FALSE;
5217 return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5220 /*****************************************************************************
5221 * IDirect3DDevice7::ValidateDevice
5223 * SDK: "Reports the device's ability to render the currently set
5224 * texture-blending operations in a single pass". Whatever that means
5225 * exactly...
5227 * Version 3 and 7
5229 * Params:
5230 * NumPasses: Address to write the number of necessary passes for the
5231 * desired effect to.
5233 * Returns:
5234 * D3D_OK on success
5236 *****************************************************************************/
5237 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
5239 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5240 HRESULT hr;
5242 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5244 wined3d_mutex_lock();
5245 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5246 hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
5247 wined3d_mutex_unlock();
5249 return hr;
5252 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
5254 return d3d_device7_ValidateDevice(iface, pass_count);
5257 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
5259 HRESULT hr;
5260 WORD old_fpucw;
5262 old_fpucw = d3d_fpu_setup();
5263 hr = d3d_device7_ValidateDevice(iface, pass_count);
5264 set_fpu_control_word(old_fpucw);
5266 return hr;
5269 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
5271 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5273 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5275 return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
5278 /*****************************************************************************
5279 * IDirect3DDevice7::Clear
5281 * Fills the render target, the z buffer and the stencil buffer with a
5282 * clear color / value
5284 * Version 7 only
5286 * Params:
5287 * Count: Number of rectangles in Rects must be 0 if Rects is NULL
5288 * Rects: Rectangles to clear. If NULL, the whole surface is cleared
5289 * Flags: Some flags, as usual
5290 * Color: Clear color for the render target
5291 * Z: Clear value for the Z buffer
5292 * Stencil: Clear value to store in each stencil buffer entry
5294 * Returns:
5295 * D3D_OK on success
5297 *****************************************************************************/
5298 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
5299 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5301 const struct wined3d_color c =
5303 ((color >> 16) & 0xff) / 255.0f,
5304 ((color >> 8) & 0xff) / 255.0f,
5305 (color & 0xff) / 255.0f,
5306 ((color >> 24) & 0xff) / 255.0f,
5308 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5309 HRESULT hr;
5311 TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5312 iface, count, rects, flags, color, z, stencil);
5314 if (count && !rects)
5316 WARN("count %u with NULL rects.\n", count);
5317 count = 0;
5320 wined3d_mutex_lock();
5321 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5322 d3d_device_sync_rendertarget(device);
5323 hr = wined3d_device_clear(device->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5324 wined3d_mutex_unlock();
5326 return hr;
5329 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
5330 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5332 return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5335 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
5336 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5338 HRESULT hr;
5339 WORD old_fpucw;
5341 old_fpucw = d3d_fpu_setup();
5342 hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5343 set_fpu_control_word(old_fpucw);
5345 return hr;
5348 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5350 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5351 struct wined3d_sub_resource_desc rt_desc;
5352 struct wined3d_rendertarget_view *rtv;
5353 struct ddraw_surface *surface;
5354 struct wined3d_viewport vp;
5356 TRACE("iface %p, viewport %p.\n", iface, viewport);
5358 if (!viewport)
5359 return DDERR_INVALIDPARAMS;
5361 wined3d_mutex_lock();
5362 if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
5364 wined3d_mutex_unlock();
5365 return DDERR_INVALIDCAPS;
5367 surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
5368 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc);
5370 if (viewport->dwX > rt_desc.width || viewport->dwWidth > rt_desc.width - viewport->dwX
5371 || viewport->dwY > rt_desc.height || viewport->dwHeight > rt_desc.height - viewport->dwY)
5373 WARN("Invalid viewport, returning E_INVALIDARG.\n");
5374 wined3d_mutex_unlock();
5375 return E_INVALIDARG;
5378 vp.x = viewport->dwX;
5379 vp.y = viewport->dwY;
5380 vp.width = viewport->dwWidth;
5381 vp.height = viewport->dwHeight;
5382 vp.min_z = viewport->dvMinZ;
5383 vp.max_z = viewport->dvMaxZ;
5385 wined3d_stateblock_set_viewport(device->update_state, &vp);
5386 wined3d_mutex_unlock();
5388 return D3D_OK;
5391 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5393 return d3d_device7_SetViewport(iface, viewport);
5396 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5398 HRESULT hr;
5399 WORD old_fpucw;
5401 old_fpucw = d3d_fpu_setup();
5402 hr = d3d_device7_SetViewport(iface, viewport);
5403 set_fpu_control_word(old_fpucw);
5405 return hr;
5408 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5410 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5411 struct wined3d_viewport wined3d_viewport;
5413 TRACE("iface %p, viewport %p.\n", iface, viewport);
5415 if (!viewport)
5416 return DDERR_INVALIDPARAMS;
5418 wined3d_mutex_lock();
5419 wined3d_viewport = device->stateblock_state->viewport;
5420 wined3d_mutex_unlock();
5422 viewport->dwX = wined3d_viewport.x;
5423 viewport->dwY = wined3d_viewport.y;
5424 viewport->dwWidth = wined3d_viewport.width;
5425 viewport->dwHeight = wined3d_viewport.height;
5426 viewport->dvMinZ = wined3d_viewport.min_z;
5427 viewport->dvMaxZ = wined3d_viewport.max_z;
5429 return D3D_OK;
5432 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5434 return d3d_device7_GetViewport(iface, viewport);
5437 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5439 HRESULT hr;
5440 WORD old_fpucw;
5442 old_fpucw = d3d_fpu_setup();
5443 hr = d3d_device7_GetViewport(iface, viewport);
5444 set_fpu_control_word(old_fpucw);
5446 return hr;
5449 /*****************************************************************************
5450 * IDirect3DDevice7::SetMaterial
5452 * Sets the Material
5454 * Version 7
5456 * Params:
5457 * Mat: The material to set
5459 * Returns:
5460 * D3D_OK on success
5461 * DDERR_INVALIDPARAMS if Mat is NULL.
5463 *****************************************************************************/
5464 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5466 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5468 TRACE("iface %p, material %p.\n", iface, material);
5470 if (!material)
5471 return DDERR_INVALIDPARAMS;
5473 wined3d_mutex_lock();
5474 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5475 wined3d_stateblock_set_material(device->update_state, (const struct wined3d_material *)material);
5476 wined3d_mutex_unlock();
5478 return D3D_OK;
5481 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5483 return d3d_device7_SetMaterial(iface, material);
5486 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5488 HRESULT hr;
5489 WORD old_fpucw;
5491 old_fpucw = d3d_fpu_setup();
5492 hr = d3d_device7_SetMaterial(iface, material);
5493 set_fpu_control_word(old_fpucw);
5495 return hr;
5498 /*****************************************************************************
5499 * IDirect3DDevice7::GetMaterial
5501 * Returns the current material
5503 * Version 7
5505 * Params:
5506 * Mat: D3DMATERIAL7 structure to write the material parameters to
5508 * Returns:
5509 * D3D_OK on success
5510 * DDERR_INVALIDPARAMS if Mat is NULL
5512 *****************************************************************************/
5513 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5515 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5517 TRACE("iface %p, material %p.\n", iface, material);
5519 wined3d_mutex_lock();
5520 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5521 memcpy(material, &device->stateblock_state->material, sizeof(*material));
5522 wined3d_mutex_unlock();
5524 return D3D_OK;
5527 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5529 return d3d_device7_GetMaterial(iface, material);
5532 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5534 HRESULT hr;
5535 WORD old_fpucw;
5537 old_fpucw = d3d_fpu_setup();
5538 hr = d3d_device7_GetMaterial(iface, material);
5539 set_fpu_control_word(old_fpucw);
5541 return hr;
5544 /*****************************************************************************
5545 * IDirect3DDevice7::SetLight
5547 * Assigns a light to a light index, but doesn't activate it yet.
5549 * Version 7, IDirect3DLight uses this method for older versions
5551 * Params:
5552 * LightIndex: The index of the new light
5553 * Light: A D3DLIGHT7 structure describing the light
5555 * Returns:
5556 * D3D_OK on success
5558 *****************************************************************************/
5559 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5561 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5562 HRESULT hr;
5564 TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5566 wined3d_mutex_lock();
5567 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5568 hr = wined3d_stateblock_set_light(device->update_state, light_idx, (const struct wined3d_light *)light);
5569 wined3d_mutex_unlock();
5571 return hr_ddraw_from_wined3d(hr);
5574 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5576 return d3d_device7_SetLight(iface, light_idx, light);
5579 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5581 HRESULT hr;
5582 WORD old_fpucw;
5584 old_fpucw = d3d_fpu_setup();
5585 hr = d3d_device7_SetLight(iface, light_idx, light);
5586 set_fpu_control_word(old_fpucw);
5588 return hr;
5591 /*****************************************************************************
5592 * IDirect3DDevice7::GetLight
5594 * Returns the light assigned to a light index
5596 * Params:
5597 * Light: Structure to write the light information to
5599 * Returns:
5600 * D3D_OK on success
5601 * DDERR_INVALIDPARAMS if Light is NULL
5603 *****************************************************************************/
5604 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5606 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5607 BOOL enabled;
5608 HRESULT hr;
5610 TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5612 wined3d_mutex_lock();
5613 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5614 hr = wined3d_stateblock_get_light(device->state, light_idx, (struct wined3d_light *)light, &enabled);
5615 wined3d_mutex_unlock();
5617 return hr_ddraw_from_wined3d(hr);
5620 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5622 return d3d_device7_GetLight(iface, light_idx, light);
5625 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5627 HRESULT hr;
5628 WORD old_fpucw;
5630 old_fpucw = d3d_fpu_setup();
5631 hr = d3d_device7_GetLight(iface, light_idx, light);
5632 set_fpu_control_word(old_fpucw);
5634 return hr;
5637 /*****************************************************************************
5638 * IDirect3DDevice7::BeginStateBlock
5640 * Begins recording to a stateblock
5642 * Version 7
5644 * Returns:
5645 * D3D_OK on success
5647 *****************************************************************************/
5648 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5650 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5651 struct wined3d_stateblock *stateblock;
5652 HRESULT hr;
5654 TRACE("iface %p.\n", iface);
5656 wined3d_mutex_lock();
5657 if (device->recording)
5659 wined3d_mutex_unlock();
5660 WARN("Trying to begin a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5661 return D3DERR_INBEGINSTATEBLOCK;
5663 if (SUCCEEDED(hr = wined3d_stateblock_create(device->wined3d_device, NULL, WINED3D_SBT_RECORDED, &stateblock)))
5664 device->update_state = device->recording = stateblock;
5665 wined3d_mutex_unlock();
5667 return hr_ddraw_from_wined3d(hr);
5670 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5672 return d3d_device7_BeginStateBlock(iface);
5675 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5677 HRESULT hr;
5678 WORD old_fpucw;
5680 old_fpucw = d3d_fpu_setup();
5681 hr = d3d_device7_BeginStateBlock(iface);
5682 set_fpu_control_word(old_fpucw);
5684 return hr;
5687 /*****************************************************************************
5688 * IDirect3DDevice7::EndStateBlock
5690 * Stops recording to a state block and returns the created stateblock
5691 * handle.
5693 * Version 7
5695 * Params:
5696 * BlockHandle: Address to store the stateblock's handle to
5698 * Returns:
5699 * D3D_OK on success
5700 * DDERR_INVALIDPARAMS if BlockHandle is NULL
5702 *****************************************************************************/
5703 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5705 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5706 struct wined3d_stateblock *wined3d_sb;
5707 DWORD h;
5709 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5711 if (!stateblock)
5712 return DDERR_INVALIDPARAMS;
5714 wined3d_mutex_lock();
5715 if (!device->recording)
5717 wined3d_mutex_unlock();
5718 WARN("Trying to end a stateblock, but no stateblock is being recorded.\n");
5719 return D3DERR_NOTINBEGINSTATEBLOCK;
5721 wined3d_sb = device->recording;
5722 wined3d_stateblock_init_contained_states(wined3d_sb);
5723 device->recording = NULL;
5724 device->update_state = device->state;
5726 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5727 if (h == DDRAW_INVALID_HANDLE)
5729 ERR("Failed to allocate a stateblock handle.\n");
5730 wined3d_stateblock_decref(wined3d_sb);
5731 wined3d_mutex_unlock();
5732 *stateblock = 0;
5733 return DDERR_OUTOFMEMORY;
5736 wined3d_mutex_unlock();
5737 *stateblock = h + 1;
5739 return D3D_OK;
5742 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5744 return d3d_device7_EndStateBlock(iface, stateblock);
5747 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5749 HRESULT hr;
5750 WORD old_fpucw;
5752 old_fpucw = d3d_fpu_setup();
5753 hr = d3d_device7_EndStateBlock(iface, stateblock);
5754 set_fpu_control_word(old_fpucw);
5756 return hr;
5759 /*****************************************************************************
5760 * IDirect3DDevice7::PreLoad
5762 * Allows the app to signal that a texture will be used soon, to allow
5763 * the Direct3DDevice to load it to the video card in the meantime.
5765 * Version 7
5767 * Params:
5768 * Texture: The texture to preload
5770 * Returns:
5771 * D3D_OK on success
5772 * DDERR_INVALIDPARAMS if Texture is NULL
5774 *****************************************************************************/
5775 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5777 struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5779 TRACE("iface %p, texture %p.\n", iface, texture);
5781 if (!texture)
5782 return DDERR_INVALIDPARAMS;
5784 wined3d_mutex_lock();
5785 wined3d_resource_preload(wined3d_texture_get_resource(surface->draw_texture ? surface->draw_texture
5786 : surface->wined3d_texture));
5787 wined3d_mutex_unlock();
5789 return D3D_OK;
5792 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5794 return d3d_device7_PreLoad(iface, texture);
5797 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5799 HRESULT hr;
5800 WORD old_fpucw;
5802 old_fpucw = d3d_fpu_setup();
5803 hr = d3d_device7_PreLoad(iface, texture);
5804 set_fpu_control_word(old_fpucw);
5806 return hr;
5809 /*****************************************************************************
5810 * IDirect3DDevice7::ApplyStateBlock
5812 * Activates the state stored in a state block handle.
5814 * Params:
5815 * BlockHandle: The stateblock handle to activate
5817 * Returns:
5818 * D3D_OK on success
5819 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5821 *****************************************************************************/
5822 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5824 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5825 struct wined3d_stateblock *wined3d_sb;
5827 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5829 wined3d_mutex_lock();
5830 if (device->recording)
5832 wined3d_mutex_unlock();
5833 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5834 return D3DERR_INBEGINSTATEBLOCK;
5836 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5837 if (!wined3d_sb)
5839 WARN("Invalid stateblock handle.\n");
5840 wined3d_mutex_unlock();
5841 return D3DERR_INVALIDSTATEBLOCK;
5844 wined3d_stateblock_apply(wined3d_sb, device->state);
5845 wined3d_mutex_unlock();
5847 return D3D_OK;
5850 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5852 return d3d_device7_ApplyStateBlock(iface, stateblock);
5855 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5857 HRESULT hr;
5858 WORD old_fpucw;
5860 old_fpucw = d3d_fpu_setup();
5861 hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5862 set_fpu_control_word(old_fpucw);
5864 return hr;
5867 /*****************************************************************************
5868 * IDirect3DDevice7::CaptureStateBlock
5870 * Updates a stateblock's values to the values currently set for the device
5872 * Version 7
5874 * Params:
5875 * BlockHandle: Stateblock to update
5877 * Returns:
5878 * D3D_OK on success
5879 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5881 *****************************************************************************/
5882 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5884 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5885 struct wined3d_stateblock *wined3d_sb;
5887 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5889 wined3d_mutex_lock();
5890 if (device->recording)
5892 wined3d_mutex_unlock();
5893 WARN("Trying to capture a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5894 return D3DERR_INBEGINSTATEBLOCK;
5896 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5897 if (!wined3d_sb)
5899 WARN("Invalid stateblock handle.\n");
5900 wined3d_mutex_unlock();
5901 return D3DERR_INVALIDSTATEBLOCK;
5904 wined3d_stateblock_capture(wined3d_sb, device->state);
5905 wined3d_mutex_unlock();
5907 return D3D_OK;
5910 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5912 return d3d_device7_CaptureStateBlock(iface, stateblock);
5915 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5917 HRESULT hr;
5918 WORD old_fpucw;
5920 old_fpucw = d3d_fpu_setup();
5921 hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5922 set_fpu_control_word(old_fpucw);
5924 return hr;
5927 /*****************************************************************************
5928 * IDirect3DDevice7::DeleteStateBlock
5930 * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5932 * Version 7
5934 * Params:
5935 * BlockHandle: Stateblock handle to delete
5937 * Returns:
5938 * D3D_OK on success
5939 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5941 *****************************************************************************/
5942 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5944 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5945 struct wined3d_stateblock *wined3d_sb;
5946 ULONG ref;
5948 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5950 wined3d_mutex_lock();
5952 wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5953 if (!wined3d_sb)
5955 WARN("Invalid stateblock handle.\n");
5956 wined3d_mutex_unlock();
5957 return D3DERR_INVALIDSTATEBLOCK;
5960 if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5962 ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5965 wined3d_mutex_unlock();
5967 return D3D_OK;
5970 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5972 return d3d_device7_DeleteStateBlock(iface, stateblock);
5975 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5977 HRESULT hr;
5978 WORD old_fpucw;
5980 old_fpucw = d3d_fpu_setup();
5981 hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5982 set_fpu_control_word(old_fpucw);
5984 return hr;
5987 /*****************************************************************************
5988 * IDirect3DDevice7::CreateStateBlock
5990 * Creates a new state block handle.
5992 * Version 7
5994 * Params:
5995 * Type: The state block type
5996 * BlockHandle: Address to write the created handle to
5998 * Returns:
5999 * D3D_OK on success
6000 * DDERR_INVALIDPARAMS if BlockHandle is NULL
6002 *****************************************************************************/
6003 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
6004 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6006 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6007 struct wined3d_stateblock *wined3d_sb;
6008 HRESULT hr;
6009 DWORD h;
6011 TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
6013 if (!stateblock)
6014 return DDERR_INVALIDPARAMS;
6016 if (type != D3DSBT_ALL
6017 && type != D3DSBT_PIXELSTATE
6018 && type != D3DSBT_VERTEXSTATE)
6020 WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
6021 return DDERR_INVALIDPARAMS;
6024 wined3d_mutex_lock();
6026 if (device->recording)
6028 wined3d_mutex_unlock();
6029 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
6030 return D3DERR_INBEGINSTATEBLOCK;
6033 if (FAILED(hr = wined3d_stateblock_create(device->wined3d_device,
6034 device->state, wined3d_stateblock_type_from_ddraw(type), &wined3d_sb)))
6036 WARN("Failed to create stateblock, hr %#x.\n", hr);
6037 wined3d_mutex_unlock();
6038 return hr_ddraw_from_wined3d(hr);
6041 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
6042 if (h == DDRAW_INVALID_HANDLE)
6044 ERR("Failed to allocate stateblock handle.\n");
6045 wined3d_stateblock_decref(wined3d_sb);
6046 wined3d_mutex_unlock();
6047 return DDERR_OUTOFMEMORY;
6050 *stateblock = h + 1;
6051 wined3d_mutex_unlock();
6053 return hr_ddraw_from_wined3d(hr);
6056 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
6057 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6059 return d3d_device7_CreateStateBlock(iface, type, stateblock);
6062 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
6063 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6065 HRESULT hr;
6066 WORD old_fpucw;
6068 old_fpucw = d3d_fpu_setup();
6069 hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
6070 set_fpu_control_word(old_fpucw);
6072 return hr;
6075 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
6077 struct ddraw_surface *src_level, *dest_level;
6078 IDirectDrawSurface7 *temp;
6079 DDSURFACEDESC2 ddsd;
6080 BOOL levelFound; /* at least one suitable sublevel in dest found */
6082 /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
6083 * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
6084 * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
6086 levelFound = FALSE;
6088 src_level = src;
6089 dest_level = dest;
6091 for (;src_level && dest_level;)
6093 if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6094 src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6096 levelFound = TRUE;
6098 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6099 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6100 IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6102 if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6104 dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6107 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6108 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6109 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6111 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6113 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6116 if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6117 if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6119 return !dest_level && levelFound;
6122 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dst,
6123 struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
6125 struct ddraw_surface *dst_level, *src_level;
6126 IDirectDrawSurface7 *temp;
6127 DDSURFACEDESC2 ddsd;
6128 POINT point;
6129 RECT src_rect;
6130 HRESULT hr;
6131 IDirectDrawPalette *pal = NULL, *pal_src = NULL;
6132 DWORD ckeyflag;
6133 DDCOLORKEY ddckey;
6135 /* Copy palette, if possible. */
6136 IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
6137 IDirectDrawSurface7_GetPalette(&dst->IDirectDrawSurface7_iface, &pal);
6139 if (pal_src != NULL && pal != NULL)
6141 PALETTEENTRY palent[256];
6143 IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
6144 IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
6147 if (pal) IDirectDrawPalette_Release(pal);
6148 if (pal_src) IDirectDrawPalette_Release(pal_src);
6150 /* Copy colorkeys, if present. */
6151 for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
6153 hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6155 if (SUCCEEDED(hr))
6157 IDirectDrawSurface7_SetColorKey(&dst->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6161 src_level = src;
6162 dst_level = dst;
6164 point = *DestPoint;
6165 src_rect = *SrcRect;
6167 for (;src_level && dst_level;)
6169 if (src_level->surface_desc.dwWidth == dst_level->surface_desc.dwWidth
6170 && src_level->surface_desc.dwHeight == dst_level->surface_desc.dwHeight)
6172 UINT src_w = src_rect.right - src_rect.left;
6173 UINT src_h = src_rect.bottom - src_rect.top;
6174 RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
6176 if (FAILED(hr = wined3d_device_context_blt(device->immediate_context,
6177 ddraw_surface_get_any_texture(dst_level, DDRAW_SURFACE_RW), dst_level->sub_resource_idx, &dst_rect,
6178 ddraw_surface_get_any_texture(src_level, DDRAW_SURFACE_READ),
6179 src_level->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
6180 ERR("Blit failed, hr %#x.\n", hr);
6182 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6183 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6184 IDirectDrawSurface7_GetAttachedSurface(&dst_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6186 if (dst_level != dst)
6187 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6189 dst_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6192 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6193 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6194 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6196 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6198 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6200 point.x /= 2;
6201 point.y /= 2;
6203 src_rect.top /= 2;
6204 src_rect.left /= 2;
6205 src_rect.right = (src_rect.right + 1) / 2;
6206 src_rect.bottom = (src_rect.bottom + 1) / 2;
6209 if (src_level && src_level != src)
6210 IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6211 if (dst_level && dst_level != dst)
6212 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6215 /*****************************************************************************
6216 * IDirect3DDevice7::Load
6218 * Loads a rectangular area from the source into the destination texture.
6219 * It can also copy the source to the faces of a cubic environment map
6221 * Version 7
6223 * Params:
6224 * DestTex: Destination texture
6225 * DestPoint: Point in the destination where the source image should be
6226 * written to
6227 * SrcTex: Source texture
6228 * SrcRect: Source rectangle
6229 * Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6230 * DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6231 * DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6233 * Returns:
6234 * D3D_OK on success
6235 * DDERR_INVALIDPARAMS if dst_texture or src_texture is NULL, broken coordinates or anything unexpected.
6238 *****************************************************************************/
6239 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
6240 IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6242 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6243 struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
6244 struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
6245 POINT destpoint;
6246 RECT srcrect;
6248 TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
6249 iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
6251 if( (!src) || (!dest) )
6252 return DDERR_INVALIDPARAMS;
6254 wined3d_mutex_lock();
6256 if (!src_rect)
6257 SetRect(&srcrect, 0, 0, src->surface_desc.dwWidth, src->surface_desc.dwHeight);
6258 else
6259 srcrect = *src_rect;
6261 if (!dst_pos)
6262 destpoint.x = destpoint.y = 0;
6263 else
6264 destpoint = *dst_pos;
6266 /* Check bad dimensions. dst_pos is validated against src, not dest, because
6267 * destination can be a subset of mip levels, in which case actual coordinates used
6268 * for it may be divided. If any dimension of dest is larger than source, it can't be
6269 * mip level subset, so an error can be returned early.
6271 if (IsRectEmpty(&srcrect) || srcrect.right > src->surface_desc.dwWidth ||
6272 srcrect.bottom > src->surface_desc.dwHeight ||
6273 destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6274 destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6275 dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6276 dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6278 wined3d_mutex_unlock();
6279 return DDERR_INVALIDPARAMS;
6282 /* Must be top level surfaces. */
6283 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6284 dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6286 wined3d_mutex_unlock();
6287 return DDERR_INVALIDPARAMS;
6290 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6292 struct ddraw_surface *src_face, *dest_face;
6293 DWORD src_face_flag, dest_face_flag;
6294 IDirectDrawSurface7 *temp;
6295 DDSURFACEDESC2 ddsd;
6296 int i;
6298 if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6300 wined3d_mutex_unlock();
6301 return DDERR_INVALIDPARAMS;
6304 /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6305 * time it's actual surface loading. */
6306 for (i = 0; i < 2; i++)
6308 dest_face = dest;
6309 src_face = src;
6311 for (;dest_face && src_face;)
6313 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6314 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6316 if (src_face_flag == dest_face_flag)
6318 if (i == 0)
6320 /* Destination mip levels must be subset of source mip levels. */
6321 if (!is_mip_level_subset(dest_face, src_face))
6323 wined3d_mutex_unlock();
6324 return DDERR_INVALIDPARAMS;
6327 else if (flags & dest_face_flag)
6329 copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6332 if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6334 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6335 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6336 IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6338 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6340 src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6342 else
6344 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6346 src_face = NULL;
6350 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6352 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6353 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6354 IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6356 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6358 dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6360 else
6362 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6364 dest_face = NULL;
6368 if (i == 0)
6370 /* Native returns error if src faces are not subset of dest faces. */
6371 if (src_face)
6373 wined3d_mutex_unlock();
6374 return DDERR_INVALIDPARAMS;
6379 wined3d_mutex_unlock();
6380 return D3D_OK;
6382 else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6384 wined3d_mutex_unlock();
6385 return DDERR_INVALIDPARAMS;
6388 /* Handle non cube map textures. */
6390 /* Destination mip levels must be subset of source mip levels. */
6391 if (!is_mip_level_subset(dest, src))
6393 wined3d_mutex_unlock();
6394 return DDERR_INVALIDPARAMS;
6397 copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6399 wined3d_mutex_unlock();
6401 return D3D_OK;
6404 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6405 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6407 return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6410 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6411 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6413 HRESULT hr;
6414 WORD old_fpucw;
6416 old_fpucw = d3d_fpu_setup();
6417 hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6418 set_fpu_control_word(old_fpucw);
6420 return hr;
6423 /*****************************************************************************
6424 * IDirect3DDevice7::LightEnable
6426 * Enables or disables a light
6428 * Version 7, IDirect3DLight uses this method too.
6430 * Params:
6431 * LightIndex: The index of the light to enable / disable
6432 * Enable: Enable or disable the light
6434 * Returns:
6435 * D3D_OK on success
6437 *****************************************************************************/
6438 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6440 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6441 HRESULT hr;
6443 TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6445 wined3d_mutex_lock();
6446 hr = wined3d_stateblock_set_light_enable(device->update_state, light_idx, enabled);
6447 wined3d_mutex_unlock();
6449 return hr_ddraw_from_wined3d(hr);
6452 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6454 return d3d_device7_LightEnable(iface, light_idx, enabled);
6457 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6459 HRESULT hr;
6460 WORD old_fpucw;
6462 old_fpucw = d3d_fpu_setup();
6463 hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6464 set_fpu_control_word(old_fpucw);
6466 return hr;
6469 /*****************************************************************************
6470 * IDirect3DDevice7::GetLightEnable
6472 * Retrieves if the light with the given index is enabled or not
6474 * Version 7
6476 * Params:
6477 * LightIndex: Index of desired light
6478 * Enable: Pointer to a BOOL which contains the result
6480 * Returns:
6481 * D3D_OK on success
6482 * DDERR_INVALIDPARAMS if Enable is NULL
6484 *****************************************************************************/
6485 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6487 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6488 struct wined3d_light light;
6489 HRESULT hr;
6491 TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6493 if (!enabled)
6494 return DDERR_INVALIDPARAMS;
6496 wined3d_mutex_lock();
6497 hr = wined3d_stateblock_get_light(device->state, light_idx, &light, enabled);
6498 wined3d_mutex_unlock();
6500 return hr_ddraw_from_wined3d(hr);
6503 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6505 return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6508 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6510 HRESULT hr;
6511 WORD old_fpucw;
6513 old_fpucw = d3d_fpu_setup();
6514 hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6515 set_fpu_control_word(old_fpucw);
6517 return hr;
6520 /*****************************************************************************
6521 * IDirect3DDevice7::SetClipPlane
6523 * Sets custom clipping plane
6525 * Version 7
6527 * Params:
6528 * Index: The index of the clipping plane
6529 * PlaneEquation: An equation defining the clipping plane
6531 * Returns:
6532 * D3D_OK on success
6533 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6535 *****************************************************************************/
6536 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6538 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6539 const struct wined3d_vec4 *wined3d_plane;
6540 HRESULT hr;
6542 TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6544 if (!plane)
6545 return DDERR_INVALIDPARAMS;
6547 wined3d_plane = (struct wined3d_vec4 *)plane;
6549 wined3d_mutex_lock();
6550 hr = wined3d_stateblock_set_clip_plane(device->update_state, idx, wined3d_plane);
6551 if (idx < ARRAY_SIZE(device->user_clip_planes))
6553 device->user_clip_planes[idx] = *wined3d_plane;
6554 if (hr == WINED3DERR_INVALIDCALL)
6556 WARN("Clip plane %u is not supported.\n", idx);
6557 hr = D3D_OK;
6560 wined3d_mutex_unlock();
6562 return hr;
6565 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6567 return d3d_device7_SetClipPlane(iface, idx, plane);
6570 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6572 HRESULT hr;
6573 WORD old_fpucw;
6575 old_fpucw = d3d_fpu_setup();
6576 hr = d3d_device7_SetClipPlane(iface, idx, plane);
6577 set_fpu_control_word(old_fpucw);
6579 return hr;
6582 /*****************************************************************************
6583 * IDirect3DDevice7::GetClipPlane
6585 * Returns the clipping plane with a specific index
6587 * Params:
6588 * Index: The index of the desired plane
6589 * PlaneEquation: Address to store the plane equation to
6591 * Returns:
6592 * D3D_OK on success
6593 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6595 *****************************************************************************/
6596 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6598 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6600 TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6602 if (!plane)
6603 return DDERR_INVALIDPARAMS;
6605 wined3d_mutex_lock();
6606 if (idx < WINED3D_MAX_CLIP_DISTANCES)
6607 memcpy(plane, &device->stateblock_state->clip_planes[idx], sizeof(struct wined3d_vec4));
6608 else
6610 WARN("Clip plane %u is not supported.\n", idx);
6611 if (idx < ARRAY_SIZE(device->user_clip_planes))
6612 memcpy(plane, &device->user_clip_planes[idx], sizeof(struct wined3d_vec4));
6614 wined3d_mutex_unlock();
6616 return D3D_OK;
6619 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6621 return d3d_device7_GetClipPlane(iface, idx, plane);
6624 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6626 HRESULT hr;
6627 WORD old_fpucw;
6629 old_fpucw = d3d_fpu_setup();
6630 hr = d3d_device7_GetClipPlane(iface, idx, plane);
6631 set_fpu_control_word(old_fpucw);
6633 return hr;
6636 /*****************************************************************************
6637 * IDirect3DDevice7::GetInfo
6639 * Retrieves some information about the device. The DirectX sdk says that
6640 * this version returns S_FALSE for all retail builds of DirectX, that's what
6641 * this implementation does.
6643 * Params:
6644 * DevInfoID: Information type requested
6645 * DevInfoStruct: Pointer to a structure to store the info to
6646 * Size: Size of the structure
6648 * Returns:
6649 * S_FALSE, because it's a non-debug driver
6651 *****************************************************************************/
6652 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6654 TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6655 iface, info_id, info, info_size);
6657 if (TRACE_ON(ddraw))
6659 TRACE(" info requested : ");
6660 switch (info_id)
6662 case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6663 case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6664 case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6665 default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6669 return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6672 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6673 * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6674 * are not duplicated.
6676 * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6677 * has already been setup for optimal d3d operation.
6679 * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6680 * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6681 * by Sacrifice (game). */
6682 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6684 /*** IUnknown Methods ***/
6685 d3d_device7_QueryInterface,
6686 d3d_device7_AddRef,
6687 d3d_device7_Release,
6688 /*** IDirect3DDevice7 ***/
6689 d3d_device7_GetCaps_FPUSetup,
6690 d3d_device7_EnumTextureFormats_FPUSetup,
6691 d3d_device7_BeginScene_FPUSetup,
6692 d3d_device7_EndScene_FPUSetup,
6693 d3d_device7_GetDirect3D,
6694 d3d_device7_SetRenderTarget_FPUSetup,
6695 d3d_device7_GetRenderTarget,
6696 d3d_device7_Clear_FPUSetup,
6697 d3d_device7_SetTransform_FPUSetup,
6698 d3d_device7_GetTransform_FPUSetup,
6699 d3d_device7_SetViewport_FPUSetup,
6700 d3d_device7_MultiplyTransform_FPUSetup,
6701 d3d_device7_GetViewport_FPUSetup,
6702 d3d_device7_SetMaterial_FPUSetup,
6703 d3d_device7_GetMaterial_FPUSetup,
6704 d3d_device7_SetLight_FPUSetup,
6705 d3d_device7_GetLight_FPUSetup,
6706 d3d_device7_SetRenderState_FPUSetup,
6707 d3d_device7_GetRenderState_FPUSetup,
6708 d3d_device7_BeginStateBlock_FPUSetup,
6709 d3d_device7_EndStateBlock_FPUSetup,
6710 d3d_device7_PreLoad_FPUSetup,
6711 d3d_device7_DrawPrimitive_FPUSetup,
6712 d3d_device7_DrawIndexedPrimitive_FPUSetup,
6713 d3d_device7_SetClipStatus,
6714 d3d_device7_GetClipStatus,
6715 d3d_device7_DrawPrimitiveStrided_FPUSetup,
6716 d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6717 d3d_device7_DrawPrimitiveVB_FPUSetup,
6718 d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6719 d3d_device7_ComputeSphereVisibility,
6720 d3d_device7_GetTexture_FPUSetup,
6721 d3d_device7_SetTexture_FPUSetup,
6722 d3d_device7_GetTextureStageState_FPUSetup,
6723 d3d_device7_SetTextureStageState_FPUSetup,
6724 d3d_device7_ValidateDevice_FPUSetup,
6725 d3d_device7_ApplyStateBlock_FPUSetup,
6726 d3d_device7_CaptureStateBlock_FPUSetup,
6727 d3d_device7_DeleteStateBlock_FPUSetup,
6728 d3d_device7_CreateStateBlock_FPUSetup,
6729 d3d_device7_Load_FPUSetup,
6730 d3d_device7_LightEnable_FPUSetup,
6731 d3d_device7_GetLightEnable_FPUSetup,
6732 d3d_device7_SetClipPlane_FPUSetup,
6733 d3d_device7_GetClipPlane_FPUSetup,
6734 d3d_device7_GetInfo
6737 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6739 /*** IUnknown Methods ***/
6740 d3d_device7_QueryInterface,
6741 d3d_device7_AddRef,
6742 d3d_device7_Release,
6743 /*** IDirect3DDevice7 ***/
6744 d3d_device7_GetCaps_FPUPreserve,
6745 d3d_device7_EnumTextureFormats_FPUPreserve,
6746 d3d_device7_BeginScene_FPUPreserve,
6747 d3d_device7_EndScene_FPUPreserve,
6748 d3d_device7_GetDirect3D,
6749 d3d_device7_SetRenderTarget_FPUPreserve,
6750 d3d_device7_GetRenderTarget,
6751 d3d_device7_Clear_FPUPreserve,
6752 d3d_device7_SetTransform_FPUPreserve,
6753 d3d_device7_GetTransform_FPUPreserve,
6754 d3d_device7_SetViewport_FPUPreserve,
6755 d3d_device7_MultiplyTransform_FPUPreserve,
6756 d3d_device7_GetViewport_FPUPreserve,
6757 d3d_device7_SetMaterial_FPUPreserve,
6758 d3d_device7_GetMaterial_FPUPreserve,
6759 d3d_device7_SetLight_FPUPreserve,
6760 d3d_device7_GetLight_FPUPreserve,
6761 d3d_device7_SetRenderState_FPUPreserve,
6762 d3d_device7_GetRenderState_FPUPreserve,
6763 d3d_device7_BeginStateBlock_FPUPreserve,
6764 d3d_device7_EndStateBlock_FPUPreserve,
6765 d3d_device7_PreLoad_FPUPreserve,
6766 d3d_device7_DrawPrimitive_FPUPreserve,
6767 d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6768 d3d_device7_SetClipStatus,
6769 d3d_device7_GetClipStatus,
6770 d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6771 d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6772 d3d_device7_DrawPrimitiveVB_FPUPreserve,
6773 d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6774 d3d_device7_ComputeSphereVisibility,
6775 d3d_device7_GetTexture_FPUPreserve,
6776 d3d_device7_SetTexture_FPUPreserve,
6777 d3d_device7_GetTextureStageState_FPUPreserve,
6778 d3d_device7_SetTextureStageState_FPUPreserve,
6779 d3d_device7_ValidateDevice_FPUPreserve,
6780 d3d_device7_ApplyStateBlock_FPUPreserve,
6781 d3d_device7_CaptureStateBlock_FPUPreserve,
6782 d3d_device7_DeleteStateBlock_FPUPreserve,
6783 d3d_device7_CreateStateBlock_FPUPreserve,
6784 d3d_device7_Load_FPUPreserve,
6785 d3d_device7_LightEnable_FPUPreserve,
6786 d3d_device7_GetLightEnable_FPUPreserve,
6787 d3d_device7_SetClipPlane_FPUPreserve,
6788 d3d_device7_GetClipPlane_FPUPreserve,
6789 d3d_device7_GetInfo
6792 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6794 /*** IUnknown Methods ***/
6795 d3d_device3_QueryInterface,
6796 d3d_device3_AddRef,
6797 d3d_device3_Release,
6798 /*** IDirect3DDevice3 ***/
6799 d3d_device3_GetCaps,
6800 d3d_device3_GetStats,
6801 d3d_device3_AddViewport,
6802 d3d_device3_DeleteViewport,
6803 d3d_device3_NextViewport,
6804 d3d_device3_EnumTextureFormats,
6805 d3d_device3_BeginScene,
6806 d3d_device3_EndScene,
6807 d3d_device3_GetDirect3D,
6808 d3d_device3_SetCurrentViewport,
6809 d3d_device3_GetCurrentViewport,
6810 d3d_device3_SetRenderTarget,
6811 d3d_device3_GetRenderTarget,
6812 d3d_device3_Begin,
6813 d3d_device3_BeginIndexed,
6814 d3d_device3_Vertex,
6815 d3d_device3_Index,
6816 d3d_device3_End,
6817 d3d_device3_GetRenderState,
6818 d3d_device3_SetRenderState,
6819 d3d_device3_GetLightState,
6820 d3d_device3_SetLightState,
6821 d3d_device3_SetTransform,
6822 d3d_device3_GetTransform,
6823 d3d_device3_MultiplyTransform,
6824 d3d_device3_DrawPrimitive,
6825 d3d_device3_DrawIndexedPrimitive,
6826 d3d_device3_SetClipStatus,
6827 d3d_device3_GetClipStatus,
6828 d3d_device3_DrawPrimitiveStrided,
6829 d3d_device3_DrawIndexedPrimitiveStrided,
6830 d3d_device3_DrawPrimitiveVB,
6831 d3d_device3_DrawIndexedPrimitiveVB,
6832 d3d_device3_ComputeSphereVisibility,
6833 d3d_device3_GetTexture,
6834 d3d_device3_SetTexture,
6835 d3d_device3_GetTextureStageState,
6836 d3d_device3_SetTextureStageState,
6837 d3d_device3_ValidateDevice
6840 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6842 /*** IUnknown Methods ***/
6843 d3d_device2_QueryInterface,
6844 d3d_device2_AddRef,
6845 d3d_device2_Release,
6846 /*** IDirect3DDevice2 ***/
6847 d3d_device2_GetCaps,
6848 d3d_device2_SwapTextureHandles,
6849 d3d_device2_GetStats,
6850 d3d_device2_AddViewport,
6851 d3d_device2_DeleteViewport,
6852 d3d_device2_NextViewport,
6853 d3d_device2_EnumTextureFormats,
6854 d3d_device2_BeginScene,
6855 d3d_device2_EndScene,
6856 d3d_device2_GetDirect3D,
6857 d3d_device2_SetCurrentViewport,
6858 d3d_device2_GetCurrentViewport,
6859 d3d_device2_SetRenderTarget,
6860 d3d_device2_GetRenderTarget,
6861 d3d_device2_Begin,
6862 d3d_device2_BeginIndexed,
6863 d3d_device2_Vertex,
6864 d3d_device2_Index,
6865 d3d_device2_End,
6866 d3d_device2_GetRenderState,
6867 d3d_device2_SetRenderState,
6868 d3d_device2_GetLightState,
6869 d3d_device2_SetLightState,
6870 d3d_device2_SetTransform,
6871 d3d_device2_GetTransform,
6872 d3d_device2_MultiplyTransform,
6873 d3d_device2_DrawPrimitive,
6874 d3d_device2_DrawIndexedPrimitive,
6875 d3d_device2_SetClipStatus,
6876 d3d_device2_GetClipStatus
6879 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6881 /*** IUnknown Methods ***/
6882 d3d_device1_QueryInterface,
6883 d3d_device1_AddRef,
6884 d3d_device1_Release,
6885 /*** IDirect3DDevice1 ***/
6886 d3d_device1_Initialize,
6887 d3d_device1_GetCaps,
6888 d3d_device1_SwapTextureHandles,
6889 d3d_device1_CreateExecuteBuffer,
6890 d3d_device1_GetStats,
6891 d3d_device1_Execute,
6892 d3d_device1_AddViewport,
6893 d3d_device1_DeleteViewport,
6894 d3d_device1_NextViewport,
6895 d3d_device1_Pick,
6896 d3d_device1_GetPickRecords,
6897 d3d_device1_EnumTextureFormats,
6898 d3d_device1_CreateMatrix,
6899 d3d_device1_SetMatrix,
6900 d3d_device1_GetMatrix,
6901 d3d_device1_DeleteMatrix,
6902 d3d_device1_BeginScene,
6903 d3d_device1_EndScene,
6904 d3d_device1_GetDirect3D
6907 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6909 d3d_device_inner_QueryInterface,
6910 d3d_device_inner_AddRef,
6911 d3d_device_inner_Release,
6914 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6916 if (!iface) return NULL;
6917 assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6918 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6921 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6923 if (!iface) return NULL;
6924 assert(iface->lpVtbl == &d3d_device3_vtbl);
6925 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6928 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6930 if (!iface) return NULL;
6931 assert(iface->lpVtbl == &d3d_device2_vtbl);
6932 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6935 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6937 if (!iface) return NULL;
6938 assert(iface->lpVtbl == &d3d_device1_vtbl);
6939 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6942 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6944 IDirectDrawSurface7 *depthStencil = NULL;
6945 IDirectDrawSurface7 *render_target;
6946 static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, {0} };
6947 struct ddraw_surface *dsi;
6949 if (device->rt_iface && SUCCEEDED(IUnknown_QueryInterface(device->rt_iface,
6950 &IID_IDirectDrawSurface7, (void **)&render_target)))
6952 IDirectDrawSurface7_GetAttachedSurface(render_target, &depthcaps, &depthStencil);
6953 IDirectDrawSurface7_Release(render_target);
6955 if (!depthStencil)
6957 TRACE("Setting wined3d depth stencil to NULL\n");
6958 wined3d_device_context_set_depth_stencil_view(device->immediate_context, NULL);
6959 return WINED3D_ZB_FALSE;
6962 dsi = impl_from_IDirectDrawSurface7(depthStencil);
6963 wined3d_device_context_set_depth_stencil_view(device->immediate_context,
6964 ddraw_surface_get_rendertarget_view(dsi));
6966 IDirectDrawSurface7_Release(depthStencil);
6967 return WINED3D_ZB_TRUE;
6970 static void ddraw_reset_viewport_state(struct ddraw *ddraw)
6972 struct wined3d_viewport vp;
6973 RECT rect;
6975 wined3d_device_get_viewports(ddraw->wined3d_device, NULL, &vp);
6976 wined3d_stateblock_set_viewport(ddraw->state, &vp);
6977 wined3d_device_get_scissor_rects(ddraw->wined3d_device, NULL, &rect);
6978 wined3d_stateblock_set_scissor_rect(ddraw->state, &rect);
6981 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, const GUID *guid,
6982 struct ddraw_surface *target, IUnknown *rt_iface, UINT version, IUnknown *outer_unknown)
6984 static const struct wined3d_matrix ident =
6986 1.0f, 0.0f, 0.0f, 0.0f,
6987 0.0f, 1.0f, 0.0f, 0.0f,
6988 0.0f, 0.0f, 1.0f, 0.0f,
6989 0.0f, 0.0f, 0.0f, 1.0f,
6991 HRESULT hr;
6993 if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6994 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6995 else
6996 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6998 device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6999 device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
7000 device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
7001 device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
7002 device->ref = 1;
7003 device->version = version;
7004 device->hardware_device = IsEqualGUID(&IID_IDirect3DTnLHalDevice, guid)
7005 || IsEqualGUID(&IID_IDirect3DHALDevice, guid);
7007 if (device->hardware_device && !(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
7009 WARN("Surface %p is not in video memory.\n", target);
7010 return D3DERR_SURFACENOTINVIDMEM;
7013 if (outer_unknown)
7014 device->outer_unknown = outer_unknown;
7015 else
7016 device->outer_unknown = &device->IUnknown_inner;
7018 device->ddraw = ddraw;
7019 list_init(&device->viewport_list);
7021 if (!ddraw_handle_table_init(&device->handle_table, 64))
7023 ERR("Failed to initialize handle table.\n");
7024 return DDERR_OUTOFMEMORY;
7027 device->legacyTextureBlending = FALSE;
7028 device->legacy_projection = ident;
7029 device->legacy_clipspace = ident;
7031 /* This is for convenience. */
7032 device->wined3d_device = ddraw->wined3d_device;
7033 device->immediate_context = ddraw->immediate_context;
7034 wined3d_device_incref(ddraw->wined3d_device);
7035 device->update_state = device->state = ddraw->state;
7036 device->stateblock_state = ddraw->stateblock_state;
7037 wined3d_stateblock_incref(ddraw->state);
7039 /* Render to the back buffer */
7040 if (FAILED(hr = wined3d_device_context_set_rendertarget_view(device->immediate_context,
7041 0, ddraw_surface_get_rendertarget_view(target), TRUE)))
7043 ERR("Failed to set render target, hr %#x.\n", hr);
7044 wined3d_stateblock_decref(device->state);
7045 ddraw_handle_table_destroy(&device->handle_table);
7046 return hr;
7049 device->rt_iface = rt_iface;
7050 if (version != 1)
7051 IUnknown_AddRef(device->rt_iface);
7053 ddraw->d3ddevice = device;
7055 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_ZENABLE,
7056 d3d_device_update_depth_stencil(device));
7057 if (version == 1) /* Color keying is initially enabled for version 1 devices. */
7058 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_COLORKEYENABLE, TRUE);
7059 else if (version == 2)
7060 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_SPECULARENABLE, TRUE);
7061 if (version < 7)
7063 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_NORMALIZENORMALS, TRUE);
7064 IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface,
7065 D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
7067 ddraw_reset_viewport_state(ddraw);
7068 return D3D_OK;
7071 HRESULT d3d_device_create(struct ddraw *ddraw, const GUID *guid, struct ddraw_surface *target, IUnknown *rt_iface,
7072 UINT version, struct d3d_device **device, IUnknown *outer_unknown)
7074 struct d3d_device *object;
7075 HRESULT hr;
7077 TRACE("ddraw %p, guid %s, target %p, version %u, device %p, outer_unknown %p.\n",
7078 ddraw, debugstr_guid(guid), target, version, device, outer_unknown);
7080 if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
7081 || (target->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
7083 WARN("Surface %p is not a render target.\n", target);
7084 return DDERR_INVALIDCAPS;
7087 if (!validate_surface_palette(target))
7089 WARN("Surface %p has an indexed pixel format, but no palette.\n", target);
7090 return DDERR_NOPALETTEATTACHED;
7093 if (ddraw->flags & DDRAW_NO3D)
7095 ERR_(winediag)("The application wants to create a Direct3D device, "
7096 "but the current DirectDrawRenderer does not support this.\n");
7098 return DDERR_OUTOFMEMORY;
7101 if (ddraw->d3ddevice)
7103 FIXME("Only one Direct3D device per DirectDraw object supported.\n");
7104 return DDERR_INVALIDPARAMS;
7107 if (!(object = heap_alloc_zero(sizeof(*object))))
7109 ERR("Failed to allocate device memory.\n");
7110 return DDERR_OUTOFMEMORY;
7113 if (FAILED(hr = d3d_device_init(object, ddraw, guid, target, rt_iface, version, outer_unknown)))
7115 WARN("Failed to initialize device, hr %#x.\n", hr);
7116 heap_free(object);
7117 return hr;
7120 TRACE("Created device %p.\n", object);
7121 *device = object;
7123 return D3D_OK;