ddraw: Store wined3d state in d3d_device.
[wine.git] / dlls / ddraw / device.c
blob59027a34ae1248effcc032add5e54a32520540b3
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 %lu.\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 %lu.\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 static struct wined3d_rendertarget_view *const null_rtv;
274 DWORD i;
275 struct list *vp_entry, *vp_entry2;
277 wined3d_mutex_lock();
279 /* There is no need to unset any resources here, wined3d will take
280 * care of that on uninit_3d(). */
282 wined3d_streaming_buffer_cleanup(&This->index_buffer);
283 wined3d_streaming_buffer_cleanup(&This->vertex_buffer);
285 wined3d_device_context_set_rendertarget_views(This->immediate_context, 0, 1, &null_rtv, FALSE);
287 /* Release the wined3d device. This won't destroy it. */
288 if (!wined3d_device_decref(This->wined3d_device))
289 ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
291 /* The texture handles should be unset by now, but there might be some bits
292 * missing in our reference counting(needs test). Do a sanity check. */
293 for (i = 0; i < This->handle_table.entry_count; ++i)
295 struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
297 switch (entry->type)
299 case DDRAW_HANDLE_FREE:
300 break;
302 case DDRAW_HANDLE_STATEBLOCK:
304 /* No FIXME here because this might happen because of sloppy applications. */
305 WARN("Leftover stateblock handle %#lx (%p), deleting.\n", i + 1, entry->object);
306 IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
307 break;
310 default:
311 FIXME("Handle %#lx (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
312 break;
316 ddraw_handle_table_destroy(&This->handle_table);
318 LIST_FOR_EACH_SAFE(vp_entry, vp_entry2, &This->viewport_list)
320 struct d3d_viewport *vp = LIST_ENTRY(vp_entry, struct d3d_viewport, entry);
321 IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
324 wined3d_stateblock_decref(This->state);
325 if (This->recording)
326 wined3d_stateblock_decref(This->recording);
328 /* Releasing the render target below may release the last reference to the ddraw object. Detach
329 * the device from it before so it doesn't try to save / restore state on the teared down device. */
330 if (This->ddraw)
332 This->ddraw->d3ddevice = NULL;
333 This->ddraw = NULL;
336 TRACE("Releasing render target %p.\n", This->rt_iface);
337 rt_iface = This->rt_iface;
338 This->rt_iface = NULL;
339 if (This->version != 1)
340 IUnknown_Release(rt_iface);
341 TRACE("Render target release done.\n");
343 /* Now free the structure */
344 free(This);
345 wined3d_mutex_unlock();
348 TRACE("Done\n");
349 return ref;
352 static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
354 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
356 TRACE("iface %p.\n", iface);
358 return IUnknown_Release(device->outer_unknown);
361 static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
363 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
365 TRACE("iface %p.\n", iface);
367 return IUnknown_Release(device->outer_unknown);
370 static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
372 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
374 TRACE("iface %p.\n", iface);
376 return IUnknown_Release(device->outer_unknown);
379 static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
381 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
383 TRACE("iface %p.\n", iface);
385 return IUnknown_Release(device->outer_unknown);
388 /*****************************************************************************
389 * IDirect3DDevice Methods
390 *****************************************************************************/
392 /*****************************************************************************
393 * IDirect3DDevice::Initialize
395 * Initializes a Direct3DDevice. This implementation is a no-op, as all
396 * initialization is done at create time.
398 * Exists in Version 1
400 * Parameters:
401 * No idea what they mean, as the MSDN page is gone
403 * Returns: DD_OK
405 *****************************************************************************/
406 static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
407 IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
409 /* It shouldn't be crucial, but print a FIXME, I'm interested if
410 * any game calls it and when. */
411 FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
412 iface, d3d, debugstr_guid(guid), device_desc);
414 return D3D_OK;
417 static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *device_desc)
419 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
421 TRACE("iface %p, device_desc %p.\n", iface, device_desc);
423 if (!device_desc)
425 WARN("device_desc is NULL, returning DDERR_INVALIDPARAMS.\n");
426 return DDERR_INVALIDPARAMS;
429 /* Call the same function used by IDirect3D, this saves code */
430 return ddraw_get_d3dcaps(device->ddraw, device_desc);
433 static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
435 return d3d_device7_GetCaps(iface, desc);
438 static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
440 HRESULT hr;
441 WORD old_fpucw;
443 old_fpucw = d3d_fpu_setup();
444 hr = d3d_device7_GetCaps(iface, desc);
445 set_fpu_control_word(old_fpucw);
447 return hr;
449 /*****************************************************************************
450 * IDirect3DDevice3::GetCaps
452 * Retrieves the capabilities of the hardware device and the emulation
453 * device. For Wine, hardware and emulation are the same (it's all HW).
455 * This implementation is used for Version 1, 2, and 3. Version 7 has its own
457 * Parameters:
458 * HWDesc: Structure to fill with the HW caps
459 * HelDesc: Structure to fill with the hardware emulation caps
461 * Returns:
462 * D3D_OK on success
463 * D3DERR_* if a problem occurs. See WineD3D
465 *****************************************************************************/
467 /* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
468 * Microsoft just expanded the existing structure without naming them
469 * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
470 * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
471 * one with 252 bytes.
473 * All 3 versions are allowed as parameters and only the specified amount of
474 * bytes is written.
476 * Note that Direct3D7 and earlier are not available in native Win64
477 * ddraw.dll builds, so possible size differences between 32 bit and
478 * 64 bit are a non-issue.
480 static inline BOOL check_d3ddevicedesc_size(DWORD size)
482 if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
483 || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
484 || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
485 return FALSE;
488 static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
489 D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
491 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
492 D3DDEVICEDESC7 desc7;
493 D3DDEVICEDESC desc1;
494 HRESULT hr;
496 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
498 if (!HWDesc)
500 WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
501 return DDERR_INVALIDPARAMS;
503 if (!check_d3ddevicedesc_size(HWDesc->dwSize))
505 WARN("HWDesc->dwSize is %lu, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
506 return DDERR_INVALIDPARAMS;
508 if (!HelDesc)
510 WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
511 return DDERR_INVALIDPARAMS;
513 if (!check_d3ddevicedesc_size(HelDesc->dwSize))
515 WARN("HelDesc->dwSize is %lu, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
516 return DDERR_INVALIDPARAMS;
519 if (FAILED(hr = ddraw_get_d3dcaps(device->ddraw, &desc7)))
520 return hr;
522 ddraw_d3dcaps1_from_7(&desc1, &desc7);
523 DD_STRUCT_COPY_BYSIZE(HWDesc, &desc1);
524 DD_STRUCT_COPY_BYSIZE(HelDesc, &desc1);
525 return D3D_OK;
528 static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
529 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
531 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
533 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
535 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
538 static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
539 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
541 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
543 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
545 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
548 /*****************************************************************************
549 * IDirect3DDevice2::SwapTextureHandles
551 * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
553 * Parameters:
554 * Tex1, Tex2: The 2 Textures to swap
556 * Returns:
557 * D3D_OK
559 *****************************************************************************/
560 static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
561 IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
563 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
564 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
565 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
566 DWORD h1, h2;
568 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
570 wined3d_mutex_lock();
572 h1 = surf1->Handle - 1;
573 h2 = surf2->Handle - 1;
574 device->handle_table.entries[h1].object = surf2;
575 device->handle_table.entries[h2].object = surf1;
576 surf2->Handle = h1 + 1;
577 surf1->Handle = h2 + 1;
579 wined3d_mutex_unlock();
581 return D3D_OK;
584 static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
585 IDirect3DTexture *tex1, IDirect3DTexture *tex2)
587 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
588 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
589 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
590 IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
591 IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
593 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
595 return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
598 /*****************************************************************************
599 * IDirect3DDevice3::GetStats
601 * This method seems to retrieve some stats from the device.
602 * The MSDN documentation doesn't exist any more, but the D3DSTATS
603 * structure suggests that the amount of drawn primitives and processed
604 * vertices is returned.
606 * Exists in Version 1, 2 and 3
608 * Parameters:
609 * Stats: Pointer to a D3DSTATS structure to be filled
611 * Returns:
612 * D3D_OK on success
613 * DDERR_INVALIDPARAMS if Stats == NULL
615 *****************************************************************************/
616 static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
618 FIXME("iface %p, stats %p stub!\n", iface, Stats);
620 if(!Stats)
621 return DDERR_INVALIDPARAMS;
623 /* Fill the Stats with 0 */
624 Stats->dwTrianglesDrawn = 0;
625 Stats->dwLinesDrawn = 0;
626 Stats->dwPointsDrawn = 0;
627 Stats->dwSpansDrawn = 0;
628 Stats->dwVerticesProcessed = 0;
630 return D3D_OK;
633 static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
635 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
637 TRACE("iface %p, stats %p.\n", iface, stats);
639 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
642 static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
644 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
646 TRACE("iface %p, stats %p.\n", iface, stats);
648 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
651 /*****************************************************************************
652 * IDirect3DDevice::CreateExecuteBuffer
654 * Creates an IDirect3DExecuteBuffer, used for rendering with a
655 * Direct3DDevice.
657 * Version 1 only.
659 * Params:
660 * Desc: Buffer description
661 * ExecuteBuffer: Address to return the Interface pointer at
662 * UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
663 * support
665 * Returns:
666 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
667 * DDERR_OUTOFMEMORY if we ran out of memory
668 * D3D_OK on success
670 *****************************************************************************/
671 static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
672 D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
674 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
675 struct d3d_execute_buffer *object;
676 HRESULT hr;
678 TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
679 iface, buffer_desc, ExecuteBuffer, outer_unknown);
681 if (outer_unknown)
682 return CLASS_E_NOAGGREGATION;
684 /* Allocate the new Execute Buffer */
685 if (!(object = calloc(1, sizeof(*object))))
687 ERR("Failed to allocate execute buffer memory.\n");
688 return DDERR_OUTOFMEMORY;
691 hr = d3d_execute_buffer_init(object, device, buffer_desc);
692 if (FAILED(hr))
694 WARN("Failed to initialize execute buffer, hr %#lx.\n", hr);
695 free(object);
696 return hr;
699 *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
701 TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
703 return D3D_OK;
706 /*****************************************************************************
707 * IDirect3DDevice::Execute
709 * Executes all the stuff in an execute buffer.
711 * Params:
712 * ExecuteBuffer: The buffer to execute
713 * Viewport: The viewport used for rendering
714 * Flags: Some flags
716 * Returns:
717 * DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
718 * D3D_OK on success
720 *****************************************************************************/
721 static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
722 IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
724 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
725 struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
726 struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
727 HRESULT hr;
729 TRACE("iface %p, buffer %p, viewport %p, flags %#lx.\n", iface, ExecuteBuffer, viewport, flags);
731 if(!buffer)
732 return DDERR_INVALIDPARAMS;
734 if (FAILED(hr = IDirect3DDevice3_SetCurrentViewport
735 (&device->IDirect3DDevice3_iface, &viewport_impl->IDirect3DViewport3_iface)))
736 return hr;
738 /* Execute... */
739 wined3d_mutex_lock();
740 hr = d3d_execute_buffer_execute(buffer, device);
741 wined3d_mutex_unlock();
743 return hr;
746 /*****************************************************************************
747 * IDirect3DDevice3::AddViewport
749 * Add a Direct3DViewport to the device's viewport list. These viewports
750 * are wrapped to IDirect3DDevice7 viewports in viewport.c
752 * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
753 * are the same interfaces.
755 * Params:
756 * Viewport: The viewport to add
758 * Returns:
759 * DDERR_INVALIDPARAMS if Viewport == NULL
760 * D3D_OK on success
762 *****************************************************************************/
763 static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
765 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
766 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
768 TRACE("iface %p, viewport %p.\n", iface, viewport);
770 /* Sanity check */
771 if(!vp)
772 return DDERR_INVALIDPARAMS;
774 wined3d_mutex_lock();
775 IDirect3DViewport3_AddRef(viewport);
776 list_add_head(&device->viewport_list, &vp->entry);
777 /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
778 vp->active_device = device;
779 wined3d_mutex_unlock();
781 return D3D_OK;
784 static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
785 IDirect3DViewport2 *viewport)
787 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
788 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
790 TRACE("iface %p, viewport %p.\n", iface, viewport);
792 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
795 static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
797 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
798 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
800 TRACE("iface %p, viewport %p.\n", iface, viewport);
802 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
805 /*****************************************************************************
806 * IDirect3DDevice3::DeleteViewport
808 * Deletes a Direct3DViewport from the device's viewport list.
810 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
811 * are equal.
813 * Params:
814 * Viewport: The viewport to delete
816 * Returns:
817 * D3D_OK on success
818 * DDERR_INVALIDPARAMS if the viewport wasn't found in the list
820 *****************************************************************************/
821 static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
823 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
824 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
826 TRACE("iface %p, viewport %p.\n", iface, viewport);
828 if (!vp)
830 WARN("NULL viewport, returning DDERR_INVALIDPARAMS\n");
831 return DDERR_INVALIDPARAMS;
834 wined3d_mutex_lock();
836 if (vp->active_device != device)
838 WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
839 wined3d_mutex_unlock();
840 return DDERR_INVALIDPARAMS;
843 if (device->current_viewport == vp)
845 TRACE("Deleting current viewport, unsetting and releasing.\n");
847 viewport_deactivate(vp);
848 IDirect3DViewport3_Release(viewport);
849 device->current_viewport = NULL;
852 vp->active_device = NULL;
853 list_remove(&vp->entry);
855 IDirect3DViewport3_Release(viewport);
857 wined3d_mutex_unlock();
859 return D3D_OK;
862 static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
864 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
865 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
867 TRACE("iface %p, viewport %p.\n", iface, viewport);
869 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
870 vp ? &vp->IDirect3DViewport3_iface : NULL);
873 static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
875 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
876 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
878 TRACE("iface %p, viewport %p.\n", iface, viewport);
880 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
881 vp ? &vp->IDirect3DViewport3_iface : NULL);
884 /*****************************************************************************
885 * IDirect3DDevice3::NextViewport
887 * Returns a viewport from the viewport list, depending on the
888 * passed viewport and the flags.
890 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
891 * are equal.
893 * Params:
894 * Viewport: Viewport to use for beginning the search
895 * Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
897 * Returns:
898 * D3D_OK on success
899 * DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
901 *****************************************************************************/
902 static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
903 IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
905 struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
906 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
907 struct d3d_viewport *next;
908 struct list *entry;
910 TRACE("iface %p, viewport %p, next %p, flags %#lx.\n",
911 iface, Viewport3, lplpDirect3DViewport3, flags);
913 if(!vp)
915 *lplpDirect3DViewport3 = NULL;
916 return DDERR_INVALIDPARAMS;
920 wined3d_mutex_lock();
921 switch (flags)
923 case D3DNEXT_NEXT:
924 entry = list_next(&This->viewport_list, &vp->entry);
925 break;
927 case D3DNEXT_HEAD:
928 entry = list_head(&This->viewport_list);
929 break;
931 case D3DNEXT_TAIL:
932 entry = list_tail(&This->viewport_list);
933 break;
935 default:
936 WARN("Invalid flags %#lx.\n", flags);
937 *lplpDirect3DViewport3 = NULL;
938 wined3d_mutex_unlock();
939 return DDERR_INVALIDPARAMS;
942 if (entry)
944 next = LIST_ENTRY(entry, struct d3d_viewport, entry);
945 *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
947 else
948 *lplpDirect3DViewport3 = NULL;
950 wined3d_mutex_unlock();
952 return D3D_OK;
955 static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
956 IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
958 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
959 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
960 IDirect3DViewport3 *res;
961 HRESULT hr;
963 TRACE("iface %p, viewport %p, next %p, flags %#lx.\n",
964 iface, viewport, next, flags);
966 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
967 &vp->IDirect3DViewport3_iface, &res, flags);
968 *next = (IDirect3DViewport2 *)res;
969 return hr;
972 static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
973 IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
975 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
976 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
977 IDirect3DViewport3 *res;
978 HRESULT hr;
980 TRACE("iface %p, viewport %p, next %p, flags %#lx.\n",
981 iface, viewport, next, flags);
983 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
984 &vp->IDirect3DViewport3_iface, &res, flags);
985 *next = (IDirect3DViewport *)res;
986 return hr;
989 /*****************************************************************************
990 * IDirect3DDevice::Pick
992 * Executes an execute buffer without performing rendering. Instead, a
993 * list of primitives that intersect with (x1,y1) of the passed rectangle
994 * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
995 * this list.
997 * Version 1 only
999 * Params:
1000 * ExecuteBuffer: Buffer to execute
1001 * Viewport: Viewport to use for execution
1002 * Flags: None are defined, according to the SDK
1003 * Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
1004 * x2 and y2 are ignored.
1006 * Returns:
1007 * D3D_OK because it's a stub
1009 *****************************************************************************/
1010 static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
1011 IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
1013 FIXME("iface %p, buffer %p, viewport %p, flags %#lx, rect %s stub!\n",
1014 iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
1016 return D3D_OK;
1019 /*****************************************************************************
1020 * IDirect3DDevice::GetPickRecords
1022 * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
1024 * Version 1 only
1026 * Params:
1027 * Count: Pointer to a DWORD containing the numbers of pick records to
1028 * retrieve
1029 * D3DPickRec: Address to store the resulting D3DPICKRECORD array.
1031 * Returns:
1032 * D3D_OK, because it's a stub
1034 *****************************************************************************/
1035 static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
1036 DWORD *count, D3DPICKRECORD *records)
1038 FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1040 return D3D_OK;
1043 /*****************************************************************************
1044 * IDirect3DDevice7::EnumTextureformats
1046 * Enumerates the supported texture formats. It checks against a list of all possible
1047 * formats to see if WineD3D supports it. If so, then it is passed to the app.
1049 * This is for Version 7 and 3, older versions have a different
1050 * callback function and their own implementation
1052 * Params:
1053 * Callback: Callback to call for each enumerated format
1054 * Arg: Argument to pass to the callback
1056 * Returns:
1057 * D3D_OK on success
1058 * DDERR_INVALIDPARAMS if Callback == NULL
1060 *****************************************************************************/
1061 static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
1062 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1064 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1065 struct wined3d_display_mode mode;
1066 HRESULT hr;
1067 unsigned int i;
1069 static const enum wined3d_format_id FormatList[] =
1071 /* 16 bit */
1072 WINED3DFMT_B5G5R5X1_UNORM,
1073 WINED3DFMT_B5G5R5A1_UNORM,
1074 WINED3DFMT_B4G4R4A4_UNORM,
1075 WINED3DFMT_B5G6R5_UNORM,
1076 /* 32 bit */
1077 WINED3DFMT_B8G8R8X8_UNORM,
1078 WINED3DFMT_B8G8R8A8_UNORM,
1079 /* 8 bit */
1080 WINED3DFMT_B2G3R3_UNORM,
1081 WINED3DFMT_P8_UINT,
1082 /* FOURCC codes */
1083 WINED3DFMT_DXT1,
1084 WINED3DFMT_DXT2,
1085 WINED3DFMT_DXT3,
1086 WINED3DFMT_DXT4,
1087 WINED3DFMT_DXT5,
1090 static const enum wined3d_format_id BumpFormatList[] =
1092 WINED3DFMT_R8G8_SNORM,
1093 WINED3DFMT_R5G5_SNORM_L6_UNORM,
1094 WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1095 WINED3DFMT_R10G11B11_SNORM,
1096 WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1099 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1101 if (!callback)
1102 return DDERR_INVALIDPARAMS;
1104 wined3d_mutex_lock();
1106 memset(&mode, 0, sizeof(mode));
1107 if (FAILED(hr = wined3d_output_get_display_mode(device->ddraw->wined3d_output, &mode, NULL)))
1109 wined3d_mutex_unlock();
1110 WARN("Failed to get output display mode, hr %#lx.\n", hr);
1111 return hr;
1114 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1116 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1117 WINED3D_DEVICE_TYPE_HAL, mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE,
1118 WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1120 DDPIXELFORMAT pformat;
1122 memset(&pformat, 0, sizeof(pformat));
1123 pformat.dwSize = sizeof(pformat);
1124 ddrawformat_from_wined3dformat(&pformat, FormatList[i]);
1126 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1127 hr = callback(&pformat, context);
1128 if(hr != DDENUMRET_OK)
1130 TRACE("Format enumeration cancelled by application\n");
1131 wined3d_mutex_unlock();
1132 return D3D_OK;
1137 for (i = 0; i < ARRAY_SIZE(BumpFormatList); ++i)
1139 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1140 WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1141 WINED3D_BIND_SHADER_RESOURCE, WINED3D_RTYPE_TEXTURE_2D, BumpFormatList[i]) == D3D_OK)
1143 DDPIXELFORMAT pformat;
1145 memset(&pformat, 0, sizeof(pformat));
1146 pformat.dwSize = sizeof(pformat);
1147 ddrawformat_from_wined3dformat(&pformat, BumpFormatList[i]);
1149 TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1150 hr = callback(&pformat, context);
1151 if(hr != DDENUMRET_OK)
1153 TRACE("Format enumeration cancelled by application\n");
1154 wined3d_mutex_unlock();
1155 return D3D_OK;
1159 TRACE("End of enumeration\n");
1160 wined3d_mutex_unlock();
1162 return D3D_OK;
1165 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1166 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1168 return d3d_device7_EnumTextureFormats(iface, callback, context);
1171 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1172 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1174 HRESULT hr;
1175 WORD old_fpucw;
1177 old_fpucw = d3d_fpu_setup();
1178 hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1179 set_fpu_control_word(old_fpucw);
1181 return hr;
1184 static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
1185 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1187 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1189 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1191 return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1194 /*****************************************************************************
1195 * IDirect3DDevice2::EnumTextureformats
1197 * EnumTextureFormats for Version 1 and 2, see
1198 * IDirect3DDevice7::EnumTextureFormats for a more detailed description.
1200 * This version has a different callback and does not enumerate FourCC
1201 * formats
1203 *****************************************************************************/
1204 static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
1205 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1207 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1208 struct wined3d_display_mode mode;
1209 HRESULT hr;
1210 unsigned int i;
1212 static const enum wined3d_format_id FormatList[] =
1214 /* 16 bit */
1215 WINED3DFMT_B5G5R5X1_UNORM,
1216 WINED3DFMT_B5G5R5A1_UNORM,
1217 WINED3DFMT_B4G4R4A4_UNORM,
1218 WINED3DFMT_B5G6R5_UNORM,
1219 /* 32 bit */
1220 WINED3DFMT_B8G8R8X8_UNORM,
1221 WINED3DFMT_B8G8R8A8_UNORM,
1222 /* 8 bit */
1223 WINED3DFMT_B2G3R3_UNORM,
1224 WINED3DFMT_P8_UINT,
1225 /* FOURCC codes - Not in this version*/
1228 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1230 if (!callback)
1231 return DDERR_INVALIDPARAMS;
1233 wined3d_mutex_lock();
1235 memset(&mode, 0, sizeof(mode));
1236 if (FAILED(hr = wined3d_output_get_display_mode(device->ddraw->wined3d_output, &mode, NULL)))
1238 wined3d_mutex_unlock();
1239 WARN("Failed to get output display mode, hr %#lx.\n", hr);
1240 return hr;
1243 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1245 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1246 WINED3D_DEVICE_TYPE_HAL, mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE,
1247 WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1249 DDSURFACEDESC sdesc;
1251 memset(&sdesc, 0, sizeof(sdesc));
1252 sdesc.dwSize = sizeof(sdesc);
1253 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1254 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1255 sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1256 ddrawformat_from_wined3dformat(&sdesc.ddpfPixelFormat, FormatList[i]);
1258 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1259 hr = callback(&sdesc, context);
1260 if(hr != DDENUMRET_OK)
1262 TRACE("Format enumeration cancelled by application\n");
1263 wined3d_mutex_unlock();
1264 return D3D_OK;
1268 TRACE("End of enumeration\n");
1269 wined3d_mutex_unlock();
1271 return D3D_OK;
1274 static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
1275 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1277 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1279 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1281 return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1284 /*****************************************************************************
1285 * IDirect3DDevice::CreateMatrix
1287 * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1288 * allocated for the handle.
1290 * Version 1 only
1292 * Params
1293 * D3DMatHandle: Address to return the handle at
1295 * Returns:
1296 * D3D_OK on success
1297 * DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1299 *****************************************************************************/
1300 static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1302 D3DMATRIX *matrix;
1303 DWORD h;
1305 TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1307 if(!D3DMatHandle)
1308 return DDERR_INVALIDPARAMS;
1310 if (!(matrix = calloc(1, sizeof(*matrix))))
1312 ERR("Out of memory when allocating a D3DMATRIX\n");
1313 return DDERR_OUTOFMEMORY;
1316 wined3d_mutex_lock();
1318 h = ddraw_allocate_handle(NULL, matrix, DDRAW_HANDLE_MATRIX);
1319 if (h == DDRAW_INVALID_HANDLE)
1321 ERR("Failed to allocate a matrix handle.\n");
1322 free(matrix);
1323 wined3d_mutex_unlock();
1324 return DDERR_OUTOFMEMORY;
1327 *D3DMatHandle = h + 1;
1329 TRACE(" returning matrix handle %#lx\n", *D3DMatHandle);
1331 wined3d_mutex_unlock();
1333 return D3D_OK;
1336 /*****************************************************************************
1337 * IDirect3DDevice::SetMatrix
1339 * Sets a matrix for a matrix handle. The matrix is copied into the memory
1340 * allocated for the handle
1342 * Version 1 only
1344 * Params:
1345 * D3DMatHandle: Handle to set the matrix to
1346 * D3DMatrix: Matrix to set
1348 * Returns:
1349 * D3D_OK on success
1350 * DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1351 * to set is NULL
1353 *****************************************************************************/
1354 static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
1355 D3DMATRIXHANDLE matrix_handle, D3DMATRIX *matrix)
1357 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1358 D3DMATRIX *m;
1360 TRACE("iface %p, matrix_handle %#lx, matrix %p.\n", iface, matrix_handle, matrix);
1362 if (!matrix)
1363 return DDERR_INVALIDPARAMS;
1365 wined3d_mutex_lock();
1367 m = ddraw_get_object(NULL, matrix_handle - 1, DDRAW_HANDLE_MATRIX);
1368 if (!m)
1370 WARN("Invalid matrix handle.\n");
1371 wined3d_mutex_unlock();
1372 return DDERR_INVALIDPARAMS;
1375 if (TRACE_ON(ddraw))
1376 dump_D3DMATRIX(matrix);
1378 *m = *matrix;
1380 if (matrix_handle == device->world)
1381 wined3d_stateblock_set_transform(device->state,
1382 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)matrix);
1384 if (matrix_handle == device->view)
1385 wined3d_stateblock_set_transform(device->state,
1386 WINED3D_TS_VIEW, (struct wined3d_matrix *)matrix);
1388 if (matrix_handle == device->proj)
1389 wined3d_stateblock_set_transform(device->state,
1390 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)matrix);
1392 wined3d_mutex_unlock();
1394 return D3D_OK;
1397 /*****************************************************************************
1398 * IDirect3DDevice::GetMatrix
1400 * Returns the content of a D3DMATRIX handle
1402 * Version 1 only
1404 * Params:
1405 * D3DMatHandle: Matrix handle to read the content from
1406 * D3DMatrix: Address to store the content at
1408 * Returns:
1409 * D3D_OK on success
1410 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1412 *****************************************************************************/
1413 static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
1414 D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1416 D3DMATRIX *m;
1418 TRACE("iface %p, matrix_handle %#lx, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1420 if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1422 wined3d_mutex_lock();
1424 m = ddraw_get_object(NULL, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1425 if (!m)
1427 WARN("Invalid matrix handle.\n");
1428 wined3d_mutex_unlock();
1429 return DDERR_INVALIDPARAMS;
1432 *D3DMatrix = *m;
1434 wined3d_mutex_unlock();
1436 return D3D_OK;
1439 /*****************************************************************************
1440 * IDirect3DDevice::DeleteMatrix
1442 * Destroys a Matrix handle. Frees the memory and unsets the handle data
1444 * Version 1 only
1446 * Params:
1447 * D3DMatHandle: Handle to destroy
1449 * Returns:
1450 * D3D_OK on success
1451 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1453 *****************************************************************************/
1454 static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1456 D3DMATRIX *m;
1458 TRACE("iface %p, matrix_handle %#lx.\n", iface, D3DMatHandle);
1460 wined3d_mutex_lock();
1462 m = ddraw_free_handle(NULL, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1463 if (!m)
1465 WARN("Invalid matrix handle.\n");
1466 wined3d_mutex_unlock();
1467 return DDERR_INVALIDPARAMS;
1470 wined3d_mutex_unlock();
1472 free(m);
1474 return D3D_OK;
1477 /*****************************************************************************
1478 * IDirect3DDevice7::BeginScene
1480 * This method must be called before any rendering is performed.
1481 * IDirect3DDevice::EndScene has to be called after the scene is complete
1483 * Version 1, 2, 3 and 7
1485 * Returns:
1486 * D3D_OK on success,
1487 * D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1488 * started scene).
1490 *****************************************************************************/
1491 static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1493 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1494 HRESULT hr;
1496 TRACE("iface %p.\n", iface);
1498 wined3d_mutex_lock();
1499 hr = wined3d_device_begin_scene(device->wined3d_device);
1500 wined3d_mutex_unlock();
1502 if(hr == WINED3D_OK) return D3D_OK;
1503 else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1506 static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1508 return d3d_device7_BeginScene(iface);
1511 static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1513 HRESULT hr;
1514 WORD old_fpucw;
1516 old_fpucw = d3d_fpu_setup();
1517 hr = d3d_device7_BeginScene(iface);
1518 set_fpu_control_word(old_fpucw);
1520 return hr;
1523 static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1525 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1527 TRACE("iface %p.\n", iface);
1529 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1532 static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1534 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1536 TRACE("iface %p.\n", iface);
1538 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1541 static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1543 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1545 TRACE("iface %p.\n", iface);
1547 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1550 /*****************************************************************************
1551 * IDirect3DDevice7::EndScene
1553 * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1554 * This method must be called after rendering is finished.
1556 * Version 1, 2, 3 and 7
1558 * Returns:
1559 * D3D_OK on success,
1560 * D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1561 * that only if the scene was already ended.
1563 *****************************************************************************/
1564 static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1566 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1567 HRESULT hr;
1569 TRACE("iface %p.\n", iface);
1571 wined3d_mutex_lock();
1572 hr = wined3d_device_end_scene(device->wined3d_device);
1573 wined3d_mutex_unlock();
1575 if(hr == WINED3D_OK) return D3D_OK;
1576 else return D3DERR_SCENE_NOT_IN_SCENE;
1579 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1581 return d3d_device7_EndScene(iface);
1584 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1586 HRESULT hr;
1587 WORD old_fpucw;
1589 old_fpucw = d3d_fpu_setup();
1590 hr = d3d_device7_EndScene(iface);
1591 set_fpu_control_word(old_fpucw);
1593 return hr;
1596 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1598 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1600 TRACE("iface %p.\n", iface);
1602 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1605 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1607 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1609 TRACE("iface %p.\n", iface);
1611 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1614 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1616 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1618 TRACE("iface %p.\n", iface);
1620 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1623 /*****************************************************************************
1624 * IDirect3DDevice7::GetDirect3D
1626 * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1627 * this device.
1629 * Params:
1630 * Direct3D7: Address to store the interface pointer at
1632 * Returns:
1633 * D3D_OK on success
1634 * DDERR_INVALIDPARAMS if Direct3D7 == NULL
1636 *****************************************************************************/
1637 static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1639 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1641 TRACE("iface %p, d3d %p.\n", iface, d3d);
1643 if (!d3d)
1644 return DDERR_INVALIDPARAMS;
1646 *d3d = &device->ddraw->IDirect3D7_iface;
1647 IDirect3D7_AddRef(*d3d);
1649 TRACE("Returning interface %p.\n", *d3d);
1650 return D3D_OK;
1653 static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1655 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1657 TRACE("iface %p, d3d %p.\n", iface, d3d);
1659 if (!d3d)
1660 return DDERR_INVALIDPARAMS;
1662 *d3d = &device->ddraw->IDirect3D3_iface;
1663 IDirect3D3_AddRef(*d3d);
1665 TRACE("Returning interface %p.\n", *d3d);
1666 return D3D_OK;
1669 static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1671 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1673 TRACE("iface %p, d3d %p.\n", iface, d3d);
1675 if (!d3d)
1676 return DDERR_INVALIDPARAMS;
1678 *d3d = &device->ddraw->IDirect3D2_iface;
1679 IDirect3D2_AddRef(*d3d);
1681 TRACE("Returning interface %p.\n", *d3d);
1682 return D3D_OK;
1685 static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1687 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1689 TRACE("iface %p, d3d %p.\n", iface, d3d);
1691 if (!d3d)
1692 return DDERR_INVALIDPARAMS;
1694 *d3d = &device->ddraw->IDirect3D_iface;
1695 IDirect3D_AddRef(*d3d);
1697 TRACE("Returning interface %p.\n", *d3d);
1698 return D3D_OK;
1701 /*****************************************************************************
1702 * IDirect3DDevice3::SetCurrentViewport
1704 * Sets a Direct3DViewport as the current viewport.
1705 * For the thunks note that all viewport interface versions are equal
1707 * Params:
1708 * Direct3DViewport3: The viewport to set
1710 * Version 2 and 3
1712 * Returns:
1713 * D3D_OK on success
1714 * (Is a NULL viewport valid?)
1716 *****************************************************************************/
1717 static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
1719 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
1720 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1722 TRACE("iface %p, viewport %p, current_viewport %p.\n", iface, viewport, device->current_viewport);
1724 if (!vp)
1726 WARN("Direct3DViewport3 is NULL.\n");
1727 return DDERR_INVALIDPARAMS;
1730 wined3d_mutex_lock();
1731 /* Do nothing if the specified viewport is the same as the current one */
1732 if (device->current_viewport == vp)
1734 wined3d_mutex_unlock();
1735 return D3D_OK;
1738 if (vp->active_device != device)
1740 WARN("Viewport %p, active device %p.\n", vp, vp->active_device);
1741 wined3d_mutex_unlock();
1742 return DDERR_INVALIDPARAMS;
1745 IDirect3DViewport3_AddRef(viewport);
1746 if (device->current_viewport)
1748 viewport_deactivate(device->current_viewport);
1749 IDirect3DViewport3_Release(&device->current_viewport->IDirect3DViewport3_iface);
1751 device->current_viewport = vp;
1752 viewport_activate(device->current_viewport, FALSE);
1754 wined3d_mutex_unlock();
1756 return D3D_OK;
1759 static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1761 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1762 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1764 TRACE("iface %p, viewport %p.\n", iface, viewport);
1766 return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface,
1767 vp ? &vp->IDirect3DViewport3_iface : NULL);
1770 /*****************************************************************************
1771 * IDirect3DDevice3::GetCurrentViewport
1773 * Returns the currently active viewport.
1775 * Version 2 and 3
1777 * Params:
1778 * Direct3DViewport3: Address to return the interface pointer at
1780 * Returns:
1781 * D3D_OK on success
1782 * DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1784 *****************************************************************************/
1785 static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1787 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1789 TRACE("iface %p, viewport %p.\n", iface, viewport);
1791 wined3d_mutex_lock();
1792 if (!device->current_viewport)
1794 wined3d_mutex_unlock();
1795 WARN("No current viewport, returning D3DERR_NOCURRENTVIEWPORT\n");
1796 return D3DERR_NOCURRENTVIEWPORT;
1799 *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1800 IDirect3DViewport3_AddRef(*viewport);
1802 TRACE("Returning interface %p.\n", *viewport);
1803 wined3d_mutex_unlock();
1804 return D3D_OK;
1807 static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1809 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1811 TRACE("iface %p, viewport %p.\n", iface, viewport);
1813 return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
1814 (IDirect3DViewport3 **)viewport);
1817 static BOOL validate_surface_palette(struct ddraw_surface *surface)
1819 return !format_is_paletteindexed(&surface->surface_desc.ddpfPixelFormat)
1820 || surface->palette;
1823 static HRESULT d3d_device_set_render_target(struct d3d_device *device,
1824 struct ddraw_surface *target, IUnknown *rt_iface)
1826 struct wined3d_rendertarget_view *rtv;
1827 HRESULT hr;
1829 if (device->rt_iface == rt_iface)
1831 TRACE("No-op SetRenderTarget operation, not doing anything\n");
1832 return D3D_OK;
1834 if (!target)
1836 WARN("Trying to set render target to NULL.\n");
1837 return DDERR_INVALIDPARAMS;
1840 rtv = ddraw_surface_get_rendertarget_view(target);
1841 if (FAILED(hr = wined3d_device_context_set_rendertarget_views(device->immediate_context, 0, 1, &rtv, FALSE)))
1842 return hr;
1844 IUnknown_AddRef(rt_iface);
1845 IUnknown_Release(device->rt_iface);
1846 device->rt_iface = rt_iface;
1847 d3d_device_update_depth_stencil(device);
1849 return D3D_OK;
1852 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
1853 IDirectDrawSurface7 *target, DWORD flags)
1855 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface7(target);
1856 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1857 HRESULT hr;
1859 TRACE("iface %p, target %p, flags %#lx.\n", iface, target, flags);
1861 wined3d_mutex_lock();
1863 if (!validate_surface_palette(target_impl))
1865 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1866 wined3d_mutex_unlock();
1867 return DDERR_INVALIDCAPS;
1870 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1872 WARN("Surface %p is not a render target.\n", target_impl);
1873 wined3d_mutex_unlock();
1874 return DDERR_INVALIDCAPS;
1877 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1879 WARN("Surface %p is not in video memory.\n", target_impl);
1880 wined3d_mutex_unlock();
1881 return DDERR_INVALIDPARAMS;
1884 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1886 WARN("Surface %p is a depth buffer.\n", target_impl);
1887 IDirectDrawSurface7_AddRef(target);
1888 IUnknown_Release(device->rt_iface);
1889 device->rt_iface = (IUnknown *)target;
1890 wined3d_mutex_unlock();
1891 return DDERR_INVALIDPIXELFORMAT;
1894 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1895 wined3d_mutex_unlock();
1896 return hr;
1899 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1900 IDirectDrawSurface7 *NewTarget, DWORD flags)
1902 return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1905 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1906 IDirectDrawSurface7 *NewTarget, DWORD flags)
1908 HRESULT hr;
1909 WORD old_fpucw;
1911 old_fpucw = d3d_fpu_setup();
1912 hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1913 set_fpu_control_word(old_fpucw);
1915 return hr;
1918 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
1919 IDirectDrawSurface4 *target, DWORD flags)
1921 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface4(target);
1922 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1923 HRESULT hr;
1925 TRACE("iface %p, target %p, flags %#lx.\n", iface, target, flags);
1927 wined3d_mutex_lock();
1929 if (!validate_surface_palette(target_impl))
1931 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1932 wined3d_mutex_unlock();
1933 return DDERR_INVALIDCAPS;
1936 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1938 WARN("Surface %p is not a render target.\n", target_impl);
1939 wined3d_mutex_unlock();
1940 return DDERR_INVALIDCAPS;
1943 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1945 WARN("Surface %p is a depth buffer.\n", target_impl);
1946 IDirectDrawSurface4_AddRef(target);
1947 IUnknown_Release(device->rt_iface);
1948 device->rt_iface = (IUnknown *)target;
1949 wined3d_mutex_unlock();
1950 return DDERR_INVALIDPIXELFORMAT;
1953 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1955 WARN("Surface %p is not in video memory.\n", target_impl);
1956 IDirectDrawSurface4_AddRef(target);
1957 IUnknown_Release(device->rt_iface);
1958 device->rt_iface = (IUnknown *)target;
1959 wined3d_mutex_unlock();
1960 return D3D_OK;
1963 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1964 wined3d_mutex_unlock();
1965 return hr;
1968 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
1969 IDirectDrawSurface *target, DWORD flags)
1971 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface(target);
1972 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1973 HRESULT hr;
1975 TRACE("iface %p, target %p, flags %#lx.\n", iface, target, flags);
1977 wined3d_mutex_lock();
1979 if (!validate_surface_palette(target_impl))
1981 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1982 wined3d_mutex_unlock();
1983 return DDERR_INVALIDCAPS;
1986 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1988 WARN("Surface %p is not a render target.\n", target_impl);
1989 wined3d_mutex_unlock();
1990 return DDERR_INVALIDCAPS;
1993 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1995 WARN("Surface %p is a depth buffer.\n", target_impl);
1996 IUnknown_Release(device->rt_iface);
1997 device->rt_iface = (IUnknown *)target;
1998 wined3d_mutex_unlock();
1999 return DDERR_INVALIDPIXELFORMAT;
2002 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
2004 WARN("Surface %p is not in video memory.\n", target_impl);
2005 IDirectDrawSurface_AddRef(target);
2006 IUnknown_Release(device->rt_iface);
2007 device->rt_iface = (IUnknown *)target;
2008 wined3d_mutex_unlock();
2009 return D3D_OK;
2012 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
2013 wined3d_mutex_unlock();
2014 return hr;
2017 /*****************************************************************************
2018 * IDirect3DDevice7::GetRenderTarget
2020 * Returns the current render target.
2021 * This is handled locally, because the WineD3D render target's parent
2022 * is an IParent
2024 * Version 2, 3 and 7
2026 * Params:
2027 * RenderTarget: Address to store the surface interface pointer
2029 * Returns:
2030 * D3D_OK on success
2031 * DDERR_INVALIDPARAMS if RenderTarget == NULL
2033 *****************************************************************************/
2034 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
2036 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2037 HRESULT hr;
2039 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2041 if(!RenderTarget)
2042 return DDERR_INVALIDPARAMS;
2044 wined3d_mutex_lock();
2045 hr = IUnknown_QueryInterface(device->rt_iface, &IID_IDirectDrawSurface7, (void **)RenderTarget);
2046 wined3d_mutex_unlock();
2048 return hr;
2051 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
2053 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2054 IDirectDrawSurface7 *RenderTarget7;
2055 struct ddraw_surface *RenderTargetImpl;
2056 HRESULT hr;
2058 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2060 if(!RenderTarget)
2061 return DDERR_INVALIDPARAMS;
2063 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2064 if(hr != D3D_OK) return hr;
2065 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2066 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
2067 IDirectDrawSurface4_AddRef(*RenderTarget);
2068 IDirectDrawSurface7_Release(RenderTarget7);
2069 return D3D_OK;
2072 static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
2074 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2075 IDirectDrawSurface7 *RenderTarget7;
2076 struct ddraw_surface *RenderTargetImpl;
2077 HRESULT hr;
2079 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2081 if(!RenderTarget)
2082 return DDERR_INVALIDPARAMS;
2084 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2085 if(hr != D3D_OK) return hr;
2086 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2087 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
2088 IDirectDrawSurface_AddRef(*RenderTarget);
2089 IDirectDrawSurface7_Release(RenderTarget7);
2090 return D3D_OK;
2093 /*****************************************************************************
2094 * IDirect3DDevice3::Begin
2096 * Begins a description block of vertices. This is similar to glBegin()
2097 * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
2098 * described with IDirect3DDevice::Vertex are drawn.
2100 * Version 2 and 3
2102 * Params:
2103 * PrimitiveType: The type of primitives to draw
2104 * VertexTypeDesc: A flexible vertex format description of the vertices
2105 * Flags: Some flags..
2107 * Returns:
2108 * D3D_OK on success
2110 *****************************************************************************/
2111 static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
2112 D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
2114 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2116 TRACE("iface %p, primitive_type %#x, fvf %#lx, flags %#lx.\n",
2117 iface, primitive_type, fvf, flags);
2119 wined3d_mutex_lock();
2120 device->primitive_type = primitive_type;
2121 device->vertex_type = fvf;
2122 device->render_flags = flags;
2123 device->vertex_size = get_flexible_vertex_size(device->vertex_type);
2124 device->nb_vertices = 0;
2125 wined3d_mutex_unlock();
2127 return D3D_OK;
2130 static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
2131 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2133 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2134 DWORD fvf;
2136 TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#lx.\n",
2137 iface, primitive_type, vertex_type, flags);
2139 switch (vertex_type)
2141 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2142 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2143 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2144 default:
2145 ERR("Unexpected vertex type %#x.\n", vertex_type);
2146 return DDERR_INVALIDPARAMS; /* Should never happen */
2149 return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2152 /*****************************************************************************
2153 * IDirect3DDevice3::BeginIndexed
2155 * Draws primitives based on vertices in a vertex array which are specified
2156 * by indices.
2158 * Version 2 and 3
2160 * Params:
2161 * PrimitiveType: Primitive type to draw
2162 * VertexType: A FVF description of the vertex format
2163 * Vertices: pointer to an array containing the vertices
2164 * NumVertices: The number of vertices in the vertex array
2165 * Flags: Some flags ...
2167 * Returns:
2168 * D3D_OK, because it's a stub
2170 *****************************************************************************/
2171 static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
2172 D3DPRIMITIVETYPE primitive_type, DWORD fvf,
2173 void *vertices, DWORD vertex_count, DWORD flags)
2175 FIXME("iface %p, primitive_type %#x, fvf %#lx, vertices %p, vertex_count %lu, flags %#lx stub!\n",
2176 iface, primitive_type, fvf, vertices, vertex_count, flags);
2178 return D3D_OK;
2182 static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
2183 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
2184 void *vertices, DWORD vertex_count, DWORD flags)
2186 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2187 DWORD fvf;
2189 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %lu, flags %#lx.\n",
2190 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2192 switch (vertex_type)
2194 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2195 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2196 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2197 default:
2198 ERR("Unexpected vertex type %#x.\n", vertex_type);
2199 return DDERR_INVALIDPARAMS; /* Should never happen */
2202 return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
2203 primitive_type, fvf, vertices, vertex_count, flags);
2206 /*****************************************************************************
2207 * IDirect3DDevice3::Vertex
2209 * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2210 * drawn vertices in a vertex buffer. If the buffer is too small, its
2211 * size is increased.
2213 * Version 2 and 3
2215 * Params:
2216 * Vertex: Pointer to the vertex
2218 * Returns:
2219 * D3D_OK, on success
2220 * DDERR_INVALIDPARAMS if Vertex is NULL
2222 *****************************************************************************/
2223 static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2225 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2227 TRACE("iface %p, vertex %p.\n", iface, vertex);
2229 if (!vertex)
2230 return DDERR_INVALIDPARAMS;
2232 wined3d_mutex_lock();
2233 if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2235 BYTE *old_buffer;
2237 device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
2238 old_buffer = device->sysmem_vertex_buffer;
2239 device->sysmem_vertex_buffer = malloc(device->buffer_size);
2240 if (old_buffer)
2242 memcpy(device->sysmem_vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2243 free(old_buffer);
2247 memcpy(device->sysmem_vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2248 wined3d_mutex_unlock();
2250 return D3D_OK;
2253 static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2255 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2257 TRACE("iface %p, vertex %p.\n", iface, vertex);
2259 return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2262 /*****************************************************************************
2263 * IDirect3DDevice3::Index
2265 * Specifies an index to a vertex to be drawn. The vertex array has to
2266 * be specified with BeginIndexed first.
2268 * Parameters:
2269 * VertexIndex: The index of the vertex to draw
2271 * Returns:
2272 * D3D_OK because it's a stub
2274 *****************************************************************************/
2275 static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2277 FIXME("iface %p, index %#x stub!\n", iface, index);
2279 return D3D_OK;
2282 static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2284 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2286 TRACE("iface %p, index %#x.\n", iface, index);
2288 return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2291 /*****************************************************************************
2292 * IDirect3DDevice7::GetRenderState
2294 * Returns the value of a render state. The possible render states are
2295 * defined in include/d3dtypes.h
2297 * Version 2, 3 and 7
2299 * Params:
2300 * RenderStateType: Render state to return the current setting of
2301 * Value: Address to store the value at
2303 * Returns:
2304 * D3D_OK on success,
2305 * DDERR_INVALIDPARAMS if Value == NULL
2307 *****************************************************************************/
2308 static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
2309 D3DRENDERSTATETYPE state, DWORD *value)
2311 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2312 const struct wined3d_stateblock_state *device_state;
2313 HRESULT hr = D3D_OK;
2315 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2317 if (!value)
2318 return DDERR_INVALIDPARAMS;
2320 wined3d_mutex_lock();
2321 device_state = device->stateblock_state;
2322 switch (state)
2324 case D3DRENDERSTATE_TEXTUREMAG:
2326 enum wined3d_texture_filter_type tex_mag = device_state->sampler_states[0][WINED3D_SAMP_MAG_FILTER];
2328 switch (tex_mag)
2330 case WINED3D_TEXF_POINT:
2331 *value = D3DFILTER_NEAREST;
2332 break;
2333 case WINED3D_TEXF_LINEAR:
2334 *value = D3DFILTER_LINEAR;
2335 break;
2336 default:
2337 ERR("Unhandled texture mag %d !\n",tex_mag);
2338 *value = 0;
2340 break;
2343 case D3DRENDERSTATE_TEXTUREMIN:
2345 enum wined3d_texture_filter_type tex_min;
2346 enum wined3d_texture_filter_type tex_mip;
2348 tex_min = device_state->sampler_states[0][WINED3D_SAMP_MIN_FILTER];
2349 tex_mip = device_state->sampler_states[0][WINED3D_SAMP_MIP_FILTER];
2350 switch (tex_min)
2352 case WINED3D_TEXF_POINT:
2353 switch (tex_mip)
2355 case WINED3D_TEXF_NONE:
2356 *value = D3DFILTER_NEAREST;
2357 break;
2358 case WINED3D_TEXF_POINT:
2359 *value = D3DFILTER_MIPNEAREST;
2360 break;
2361 case WINED3D_TEXF_LINEAR:
2362 *value = D3DFILTER_LINEARMIPNEAREST;
2363 break;
2364 default:
2365 ERR("Unhandled mip filter %#x.\n", tex_mip);
2366 *value = D3DFILTER_NEAREST;
2367 break;
2369 break;
2370 case WINED3D_TEXF_LINEAR:
2371 switch (tex_mip)
2373 case WINED3D_TEXF_NONE:
2374 *value = D3DFILTER_LINEAR;
2375 break;
2376 case WINED3D_TEXF_POINT:
2377 *value = D3DFILTER_MIPLINEAR;
2378 break;
2379 case WINED3D_TEXF_LINEAR:
2380 *value = D3DFILTER_LINEARMIPLINEAR;
2381 break;
2382 default:
2383 ERR("Unhandled mip filter %#x.\n", tex_mip);
2384 *value = D3DFILTER_LINEAR;
2385 break;
2387 break;
2388 default:
2389 ERR("Unhandled texture min filter %#x.\n",tex_min);
2390 *value = D3DFILTER_NEAREST;
2391 break;
2393 break;
2396 case D3DRENDERSTATE_TEXTUREADDRESS:
2397 case D3DRENDERSTATE_TEXTUREADDRESSU:
2398 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_U];
2399 break;
2400 case D3DRENDERSTATE_TEXTUREADDRESSV:
2401 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_V];
2402 break;
2404 case D3DRENDERSTATE_BORDERCOLOR:
2405 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2406 hr = E_NOTIMPL;
2407 break;
2409 case D3DRENDERSTATE_TEXTUREHANDLE:
2410 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2411 WARN("Render state %#x is invalid in d3d7.\n", state);
2412 hr = DDERR_INVALIDPARAMS;
2413 break;
2415 default:
2416 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2417 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2419 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2420 hr = E_NOTIMPL;
2421 break;
2423 *value = device_state->rs[wined3d_render_state_from_ddraw(state)];
2425 wined3d_mutex_unlock();
2427 return hr;
2430 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2431 D3DRENDERSTATETYPE state, DWORD *value)
2433 return d3d_device7_GetRenderState(iface, state, value);
2436 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2437 D3DRENDERSTATETYPE state, DWORD *value)
2439 HRESULT hr;
2440 WORD old_fpucw;
2442 old_fpucw = d3d_fpu_setup();
2443 hr = d3d_device7_GetRenderState(iface, state, value);
2444 set_fpu_control_word(old_fpucw);
2446 return hr;
2449 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2450 D3DRENDERSTATETYPE state, DWORD *value)
2452 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2454 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2456 switch (state)
2458 case D3DRENDERSTATE_TEXTUREHANDLE:
2460 /* This state is wrapped to SetTexture in SetRenderState, so
2461 * it has to be wrapped to GetTexture here. */
2462 struct wined3d_texture *tex = NULL;
2463 *value = 0;
2465 wined3d_mutex_lock();
2466 if ((tex = device->stateblock_state->textures[0]))
2468 /* The parent of the texture is the IDirectDrawSurface7
2469 * interface of the ddraw surface. */
2470 struct ddraw_texture *parent = wined3d_texture_get_parent(tex);
2471 if (parent)
2472 *value = parent->root->Handle;
2474 wined3d_mutex_unlock();
2476 return D3D_OK;
2479 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2481 *value = device->texture_map_blend;
2482 return D3D_OK;
2485 case D3DRENDERSTATE_LIGHTING:
2486 case D3DRENDERSTATE_NORMALIZENORMALS:
2487 case D3DRENDERSTATE_LOCALVIEWER:
2488 *value = 0xffffffff;
2489 return D3D_OK;
2491 default:
2492 return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2496 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2497 D3DRENDERSTATETYPE state, DWORD *value)
2499 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2501 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2503 return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2506 /*****************************************************************************
2507 * IDirect3DDevice7::SetRenderState
2509 * Sets a render state. The possible render states are defined in
2510 * include/d3dtypes.h
2512 * Version 2, 3 and 7
2514 * Params:
2515 * RenderStateType: State to set
2516 * Value: Value to assign to that state
2518 *****************************************************************************/
2519 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2520 D3DRENDERSTATETYPE state, DWORD value)
2522 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2523 HRESULT hr = D3D_OK;
2525 TRACE("iface %p, state %#x, value %#lx.\n", iface, state, value);
2527 wined3d_mutex_lock();
2528 /* Some render states need special care */
2529 switch (state)
2532 * The ddraw texture filter mapping works like this:
2533 * D3DFILTER_NEAREST Point min/mag, no mip
2534 * D3DFILTER_MIPNEAREST Point min/mag, point mip
2535 * D3DFILTER_LINEARMIPNEAREST: Point min/mag, linear mip
2537 * D3DFILTER_LINEAR Linear min/mag, no mip
2538 * D3DFILTER_MIPLINEAR Linear min/mag, point mip
2539 * D3DFILTER_LINEARMIPLINEAR Linear min/mag, linear mip
2541 * This is the opposite of the GL naming convention,
2542 * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2544 case D3DRENDERSTATE_TEXTUREMAG:
2546 enum wined3d_texture_filter_type tex_mag;
2548 switch (value)
2550 case D3DFILTER_NEAREST:
2551 case D3DFILTER_MIPNEAREST:
2552 case D3DFILTER_LINEARMIPNEAREST:
2553 tex_mag = WINED3D_TEXF_POINT;
2554 break;
2555 case D3DFILTER_LINEAR:
2556 case D3DFILTER_MIPLINEAR:
2557 case D3DFILTER_LINEARMIPLINEAR:
2558 tex_mag = WINED3D_TEXF_LINEAR;
2559 break;
2560 default:
2561 tex_mag = WINED3D_TEXF_POINT;
2562 FIXME("Unhandled texture mag %#lx.\n", value);
2563 break;
2566 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2567 break;
2570 case D3DRENDERSTATE_TEXTUREMIN:
2572 enum wined3d_texture_filter_type tex_min;
2573 enum wined3d_texture_filter_type tex_mip;
2575 switch (value)
2577 case D3DFILTER_NEAREST:
2578 tex_min = WINED3D_TEXF_POINT;
2579 tex_mip = WINED3D_TEXF_NONE;
2580 break;
2581 case D3DFILTER_LINEAR:
2582 tex_min = WINED3D_TEXF_LINEAR;
2583 tex_mip = WINED3D_TEXF_NONE;
2584 break;
2585 case D3DFILTER_MIPNEAREST:
2586 tex_min = WINED3D_TEXF_POINT;
2587 tex_mip = WINED3D_TEXF_POINT;
2588 break;
2589 case D3DFILTER_MIPLINEAR:
2590 tex_min = WINED3D_TEXF_LINEAR;
2591 tex_mip = WINED3D_TEXF_POINT;
2592 break;
2593 case D3DFILTER_LINEARMIPNEAREST:
2594 tex_min = WINED3D_TEXF_POINT;
2595 tex_mip = WINED3D_TEXF_LINEAR;
2596 break;
2597 case D3DFILTER_LINEARMIPLINEAR:
2598 tex_min = WINED3D_TEXF_LINEAR;
2599 tex_mip = WINED3D_TEXF_LINEAR;
2600 break;
2602 default:
2603 FIXME("Unhandled texture min %#lx.\n",value);
2604 tex_min = WINED3D_TEXF_POINT;
2605 tex_mip = WINED3D_TEXF_NONE;
2606 break;
2609 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2610 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIN_FILTER, tex_min);
2611 break;
2614 case D3DRENDERSTATE_TEXTUREADDRESS:
2615 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2616 /* Drop through */
2617 case D3DRENDERSTATE_TEXTUREADDRESSU:
2618 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_U, value);
2619 break;
2620 case D3DRENDERSTATE_TEXTUREADDRESSV:
2621 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2622 break;
2624 case D3DRENDERSTATE_BORDERCOLOR:
2625 /* This should probably just forward to the corresponding sampler
2626 * state. Needs tests. */
2627 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2628 hr = E_NOTIMPL;
2629 break;
2631 case D3DRENDERSTATE_TEXTUREHANDLE:
2632 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2633 WARN("Render state %#x is invalid in d3d7.\n", state);
2634 hr = DDERR_INVALIDPARAMS;
2635 break;
2637 default:
2638 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2639 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2641 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2642 hr = E_NOTIMPL;
2643 break;
2646 wined3d_stateblock_set_render_state(device->update_state, wined3d_render_state_from_ddraw(state), value);
2647 break;
2649 wined3d_mutex_unlock();
2651 return hr;
2654 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2655 D3DRENDERSTATETYPE state, DWORD value)
2657 return d3d_device7_SetRenderState(iface, state, value);
2660 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2661 D3DRENDERSTATETYPE state, DWORD value)
2663 HRESULT hr;
2664 WORD old_fpucw;
2666 old_fpucw = d3d_fpu_setup();
2667 hr = d3d_device7_SetRenderState(iface, state, value);
2668 set_fpu_control_word(old_fpucw);
2670 return hr;
2673 static void fixup_texture_alpha_op(struct d3d_device *device)
2675 /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
2676 See d3d_device3_SetRenderState() for details. */
2677 struct wined3d_texture *tex;
2678 BOOL tex_alpha = TRUE;
2679 DDPIXELFORMAT ddfmt;
2681 if (!(device->legacyTextureBlending && device->texture_map_blend == D3DTBLEND_MODULATE))
2682 return;
2684 if ((tex = device->stateblock_state->textures[0]))
2686 struct wined3d_resource_desc desc;
2688 wined3d_resource_get_desc(wined3d_texture_get_resource(tex), &desc);
2689 ddfmt.dwSize = sizeof(ddfmt);
2690 ddrawformat_from_wined3dformat(&ddfmt, desc.format);
2691 if (!ddfmt.dwRGBAlphaBitMask)
2692 tex_alpha = FALSE;
2695 /* Args 1 and 2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
2696 wined3d_stateblock_set_texture_stage_state(device->state,
2697 0, WINED3D_TSS_ALPHA_OP, tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2);
2700 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2701 D3DRENDERSTATETYPE state, DWORD value)
2703 /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2704 for this state can be directly mapped to texture stage colorop and alphaop, but
2705 D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2706 from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2707 alphaarg when needed.
2709 Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2711 Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2712 TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2713 are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2714 requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2715 with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2716 in device - TRUE if the app is using TEXTUREMAPBLEND.
2718 Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2719 GetTextureStageState and vice versa. */
2721 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2722 HRESULT hr;
2724 TRACE("iface %p, state %#x, value %#lx.\n", iface, state, value);
2726 if (state >= D3DSTATE_OVERRIDE_BIAS)
2728 WARN("Unhandled state %#x.\n", state);
2729 return DDERR_INVALIDPARAMS;
2732 wined3d_mutex_lock();
2734 switch (state)
2736 case D3DRENDERSTATE_TEXTUREHANDLE:
2738 struct ddraw_surface *surf;
2740 if (value == 0)
2742 wined3d_stateblock_set_texture(device->state, 0, NULL);
2743 hr = D3D_OK;
2744 break;
2747 surf = ddraw_get_object(NULL, value - 1, DDRAW_HANDLE_SURFACE);
2748 if (!surf)
2750 WARN("Invalid texture handle.\n");
2751 hr = DDERR_INVALIDPARAMS;
2752 break;
2755 hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2756 break;
2759 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2761 if (value == device->texture_map_blend)
2763 TRACE("Application is setting the same value over, nothing to do.\n");
2765 hr = D3D_OK;
2766 break;
2769 device->legacyTextureBlending = TRUE;
2770 device->texture_map_blend = value;
2772 switch (value)
2774 case D3DTBLEND_MODULATE:
2776 fixup_texture_alpha_op(device);
2778 wined3d_stateblock_set_texture_stage_state(device->state,
2779 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2780 wined3d_stateblock_set_texture_stage_state(device->state,
2781 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2782 wined3d_stateblock_set_texture_stage_state(device->state,
2783 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2784 wined3d_stateblock_set_texture_stage_state(device->state,
2785 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2786 wined3d_stateblock_set_texture_stage_state(device->state,
2787 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2788 break;
2791 case D3DTBLEND_ADD:
2792 wined3d_stateblock_set_texture_stage_state(device->state,
2793 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2794 wined3d_stateblock_set_texture_stage_state(device->state,
2795 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2796 wined3d_stateblock_set_texture_stage_state(device->state,
2797 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2798 wined3d_stateblock_set_texture_stage_state(device->state,
2799 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2800 wined3d_stateblock_set_texture_stage_state(device->state,
2801 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2802 break;
2804 case D3DTBLEND_MODULATEALPHA:
2805 wined3d_stateblock_set_texture_stage_state(device->state,
2806 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2807 wined3d_stateblock_set_texture_stage_state(device->state,
2808 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2809 wined3d_stateblock_set_texture_stage_state(device->state,
2810 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2811 wined3d_stateblock_set_texture_stage_state(device->state,
2812 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2813 wined3d_stateblock_set_texture_stage_state(device->state,
2814 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2815 wined3d_stateblock_set_texture_stage_state(device->state,
2816 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2817 break;
2819 case D3DTBLEND_COPY:
2820 case D3DTBLEND_DECAL:
2821 wined3d_stateblock_set_texture_stage_state(device->state,
2822 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2823 wined3d_stateblock_set_texture_stage_state(device->state,
2824 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2825 wined3d_stateblock_set_texture_stage_state(device->state,
2826 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2827 wined3d_stateblock_set_texture_stage_state(device->state,
2828 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2829 break;
2831 case D3DTBLEND_DECALALPHA:
2832 wined3d_stateblock_set_texture_stage_state(device->state,
2833 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2834 wined3d_stateblock_set_texture_stage_state(device->state,
2835 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2836 wined3d_stateblock_set_texture_stage_state(device->state,
2837 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2838 wined3d_stateblock_set_texture_stage_state(device->state,
2839 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2840 wined3d_stateblock_set_texture_stage_state(device->state,
2841 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2842 break;
2844 default:
2845 FIXME("Unhandled texture environment %#lx.\n", value);
2847 hr = D3D_OK;
2848 break;
2851 case D3DRENDERSTATE_LIGHTING:
2852 case D3DRENDERSTATE_NORMALIZENORMALS:
2853 case D3DRENDERSTATE_LOCALVIEWER:
2854 hr = D3D_OK;
2855 break;
2857 default:
2858 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2859 break;
2861 wined3d_mutex_unlock();
2863 return hr;
2866 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2867 D3DRENDERSTATETYPE state, DWORD value)
2869 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2871 TRACE("iface %p, state %#x, value %#lx.\n", iface, state, value);
2873 return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2876 /*****************************************************************************
2877 * Direct3DDevice3::SetLightState
2879 * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2880 * light states are forwarded to Direct3DDevice7 render states
2882 * Version 2 and 3
2884 * Params:
2885 * LightStateType: The light state to change
2886 * Value: The value to assign to that light state
2888 * Returns:
2889 * D3D_OK on success
2890 * DDERR_INVALIDPARAMS if the parameters were incorrect
2891 * Also check IDirect3DDevice7::SetRenderState
2893 *****************************************************************************/
2894 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2895 D3DLIGHTSTATETYPE state, DWORD value)
2897 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2898 HRESULT hr;
2900 TRACE("iface %p, state %#x, value %#lx.\n", iface, state, value);
2902 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2904 TRACE("Unexpected Light State Type\n");
2905 return DDERR_INVALIDPARAMS;
2908 wined3d_mutex_lock();
2909 if (state == D3DLIGHTSTATE_MATERIAL)
2911 if (value)
2913 struct d3d_material *m;
2915 if (!(m = ddraw_get_object(NULL, value - 1, DDRAW_HANDLE_MATERIAL)))
2917 WARN("Invalid material handle.\n");
2918 wined3d_mutex_unlock();
2919 return DDERR_INVALIDPARAMS;
2922 material_activate(m);
2925 device->material = value;
2927 else if (state == D3DLIGHTSTATE_COLORMODEL)
2929 switch (value)
2931 case D3DCOLOR_MONO:
2932 ERR("DDCOLOR_MONO should not happen!\n");
2933 break;
2934 case D3DCOLOR_RGB:
2935 /* We are already in this mode */
2936 TRACE("Setting color model to RGB (no-op).\n");
2937 break;
2938 default:
2939 ERR("Unknown color model!\n");
2940 wined3d_mutex_unlock();
2941 return DDERR_INVALIDPARAMS;
2944 else
2946 D3DRENDERSTATETYPE rs;
2947 switch (state)
2949 case D3DLIGHTSTATE_AMBIENT: /* 2 */
2950 rs = D3DRENDERSTATE_AMBIENT;
2951 break;
2952 case D3DLIGHTSTATE_FOGMODE: /* 4 */
2953 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2954 break;
2955 case D3DLIGHTSTATE_FOGSTART: /* 5 */
2956 rs = D3DRENDERSTATE_FOGSTART;
2957 break;
2958 case D3DLIGHTSTATE_FOGEND: /* 6 */
2959 rs = D3DRENDERSTATE_FOGEND;
2960 break;
2961 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
2962 rs = D3DRENDERSTATE_FOGDENSITY;
2963 break;
2964 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
2965 rs = D3DRENDERSTATE_COLORVERTEX;
2966 break;
2967 default:
2968 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2969 wined3d_mutex_unlock();
2970 return DDERR_INVALIDPARAMS;
2973 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2974 wined3d_mutex_unlock();
2975 return hr;
2977 wined3d_mutex_unlock();
2979 return D3D_OK;
2982 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
2983 D3DLIGHTSTATETYPE state, DWORD value)
2985 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2987 TRACE("iface %p, state %#x, value %#lx.\n", iface, state, value);
2989 return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2992 /*****************************************************************************
2993 * IDirect3DDevice3::GetLightState
2995 * Returns the current setting of a light state. The state is read from
2996 * the Direct3DDevice7 render state.
2998 * Version 2 and 3
3000 * Params:
3001 * LightStateType: The light state to return
3002 * Value: The address to store the light state setting at
3004 * Returns:
3005 * D3D_OK on success
3006 * DDDERR_INVALIDPARAMS if the parameters were incorrect
3007 * Also see IDirect3DDevice7::GetRenderState
3009 *****************************************************************************/
3010 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
3011 D3DLIGHTSTATETYPE state, DWORD *value)
3013 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3014 HRESULT hr;
3016 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3018 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
3020 TRACE("Unexpected Light State Type\n");
3021 return DDERR_INVALIDPARAMS;
3024 if (!value)
3025 return DDERR_INVALIDPARAMS;
3027 wined3d_mutex_lock();
3028 if (state == D3DLIGHTSTATE_MATERIAL)
3030 *value = device->material;
3032 else if (state == D3DLIGHTSTATE_COLORMODEL)
3034 *value = D3DCOLOR_RGB;
3036 else
3038 D3DRENDERSTATETYPE rs;
3039 switch (state)
3041 case D3DLIGHTSTATE_AMBIENT: /* 2 */
3042 rs = D3DRENDERSTATE_AMBIENT;
3043 break;
3044 case D3DLIGHTSTATE_FOGMODE: /* 4 */
3045 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3046 break;
3047 case D3DLIGHTSTATE_FOGSTART: /* 5 */
3048 rs = D3DRENDERSTATE_FOGSTART;
3049 break;
3050 case D3DLIGHTSTATE_FOGEND: /* 6 */
3051 rs = D3DRENDERSTATE_FOGEND;
3052 break;
3053 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
3054 rs = D3DRENDERSTATE_FOGDENSITY;
3055 break;
3056 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
3057 rs = D3DRENDERSTATE_COLORVERTEX;
3058 break;
3059 default:
3060 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3061 wined3d_mutex_unlock();
3062 return DDERR_INVALIDPARAMS;
3065 hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3066 wined3d_mutex_unlock();
3067 return hr;
3069 wined3d_mutex_unlock();
3071 return D3D_OK;
3074 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3075 D3DLIGHTSTATETYPE state, DWORD *value)
3077 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3079 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3081 return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3084 /*****************************************************************************
3085 * IDirect3DDevice7::SetTransform
3087 * Assigns a D3DMATRIX to a transform type. The transform types are defined
3088 * in include/d3dtypes.h.
3089 * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3090 * (=255) for wined3d, because the 1 transform state was removed in d3d8
3091 * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3093 * Version 2, 3 and 7
3095 * Params:
3096 * TransformStateType: transform state to set
3097 * Matrix: Matrix to assign to the state
3099 * Returns:
3100 * D3D_OK on success
3101 * DDERR_INVALIDPARAMS if Matrix == NULL
3103 *****************************************************************************/
3104 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3105 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3107 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3109 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3111 if (!matrix)
3112 return DDERR_INVALIDPARAMS;
3114 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3115 wined3d_mutex_lock();
3116 wined3d_stateblock_set_transform(device->update_state,
3117 wined3d_transform_state_from_ddraw(state), (const struct wined3d_matrix *)matrix);
3118 wined3d_mutex_unlock();
3120 return D3D_OK;
3123 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3124 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3126 return d3d_device7_SetTransform(iface, state, matrix);
3129 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3130 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3132 HRESULT hr;
3133 WORD old_fpucw;
3135 old_fpucw = d3d_fpu_setup();
3136 hr = d3d_device7_SetTransform(iface, state, matrix);
3137 set_fpu_control_word(old_fpucw);
3139 return hr;
3142 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3143 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3145 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3147 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3149 if (!matrix)
3150 return DDERR_INVALIDPARAMS;
3152 if (state == D3DTRANSFORMSTATE_PROJECTION)
3154 struct wined3d_matrix projection;
3156 wined3d_mutex_lock();
3157 multiply_matrix(&projection, &device->legacy_clipspace, (struct wined3d_matrix *)matrix);
3158 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3159 memcpy(&device->legacy_projection, matrix, sizeof(*matrix));
3160 wined3d_mutex_unlock();
3162 return D3D_OK;
3165 return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3168 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3169 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3171 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3173 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3175 return IDirect3DDevice3_SetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3178 /*****************************************************************************
3179 * IDirect3DDevice7::GetTransform
3181 * Returns the matrix assigned to a transform state
3182 * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3183 * SetTransform
3185 * Params:
3186 * TransformStateType: State to read the matrix from
3187 * Matrix: Address to store the matrix at
3189 * Returns:
3190 * D3D_OK on success
3191 * DDERR_INVALIDPARAMS if Matrix == NULL
3193 *****************************************************************************/
3194 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3195 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3197 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3199 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3201 if (!matrix)
3202 return DDERR_INVALIDPARAMS;
3204 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3205 wined3d_mutex_lock();
3206 memcpy(matrix, &device->stateblock_state->transforms[wined3d_transform_state_from_ddraw(state)], sizeof(*matrix));
3207 wined3d_mutex_unlock();
3209 return D3D_OK;
3212 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3213 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3215 return d3d_device7_GetTransform(iface, state, matrix);
3218 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3219 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3221 HRESULT hr;
3222 WORD old_fpucw;
3224 old_fpucw = d3d_fpu_setup();
3225 hr = d3d_device7_GetTransform(iface, state, matrix);
3226 set_fpu_control_word(old_fpucw);
3228 return hr;
3231 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3232 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3234 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3236 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3238 if (!matrix)
3239 return DDERR_INVALIDPARAMS;
3241 if (state == D3DTRANSFORMSTATE_PROJECTION)
3243 wined3d_mutex_lock();
3244 memcpy(matrix, &device->legacy_projection, sizeof(*matrix));
3245 wined3d_mutex_unlock();
3246 return DD_OK;
3249 return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3252 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3253 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3255 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3257 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3259 return IDirect3DDevice3_GetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3262 /*****************************************************************************
3263 * IDirect3DDevice7::MultiplyTransform
3265 * Multiplies the already-set transform matrix of a transform state
3266 * with another matrix. For the world matrix, see SetTransform
3268 * Version 2, 3 and 7
3270 * Params:
3271 * TransformStateType: Transform state to multiply
3272 * D3DMatrix Matrix to multiply with.
3274 * Returns
3275 * D3D_OK on success
3276 * DDERR_INVALIDPARAMS if D3DMatrix is NULL
3278 *****************************************************************************/
3279 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3280 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3282 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3284 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3286 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3287 wined3d_mutex_lock();
3288 wined3d_stateblock_multiply_transform(device->state,
3289 wined3d_transform_state_from_ddraw(state), (struct wined3d_matrix *)matrix);
3290 wined3d_mutex_unlock();
3292 return D3D_OK;
3295 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3296 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3298 return d3d_device7_MultiplyTransform(iface, state, matrix);
3301 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3302 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3304 HRESULT hr;
3305 WORD old_fpucw;
3307 old_fpucw = d3d_fpu_setup();
3308 hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3309 set_fpu_control_word(old_fpucw);
3311 return hr;
3314 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3315 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3317 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3319 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3321 if (state == D3DTRANSFORMSTATE_PROJECTION)
3323 struct wined3d_matrix projection, tmp;
3325 wined3d_mutex_lock();
3326 multiply_matrix(&tmp, &device->legacy_projection, (struct wined3d_matrix *)matrix);
3327 multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3328 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3329 device->legacy_projection = tmp;
3330 wined3d_mutex_unlock();
3332 return D3D_OK;
3335 return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3338 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3339 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3341 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3343 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3345 return IDirect3DDevice3_MultiplyTransform(&device->IDirect3DDevice3_iface, state, matrix);
3348 /*****************************************************************************
3349 * IDirect3DDevice7::DrawPrimitive
3351 * Draws primitives based on vertices in an application-provided pointer
3353 * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3354 * an FVF format for D3D7
3356 * Params:
3357 * PrimitiveType: The type of the primitives to draw
3358 * Vertex type: Flexible vertex format vertex description
3359 * Vertices: Pointer to the vertex array
3360 * VertexCount: The number of vertices to draw
3361 * Flags: As usual a few flags
3363 * Returns:
3364 * D3D_OK on success
3365 * DDERR_INVALIDPARAMS if Vertices is NULL
3367 *****************************************************************************/
3368 static void d3d_device_sync_rendertarget(struct d3d_device *device)
3370 struct wined3d_rendertarget_view *rtv;
3372 if (device->hardware_device)
3373 return;
3375 if ((rtv = wined3d_device_context_get_rendertarget_view(device->immediate_context, 0)))
3376 ddraw_surface_get_draw_texture(wined3d_rendertarget_view_get_parent(rtv), DDRAW_SURFACE_RW);
3378 if ((rtv = wined3d_device_context_get_depth_stencil_view(device->immediate_context)))
3379 ddraw_surface_get_draw_texture(wined3d_rendertarget_view_get_parent(rtv), DDRAW_SURFACE_RW);
3382 void d3d_device_sync_surfaces(struct d3d_device *device)
3384 const struct wined3d_stateblock_state *state = device->stateblock_state;
3385 struct ddraw_surface *surface;
3386 unsigned int i, j;
3388 d3d_device_sync_rendertarget(device);
3390 if (!device->have_draw_textures)
3391 return;
3393 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
3395 if (!state->textures[i])
3396 continue;
3398 j = 0;
3399 while ((surface = wined3d_texture_get_sub_resource_parent(state->textures[i], j)))
3401 if (!surface->draw_texture)
3402 break;
3403 ddraw_surface_get_draw_texture(surface, DDRAW_SURFACE_READ);
3404 ++j;
3409 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3410 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3411 DWORD vertex_count, DWORD flags)
3413 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3414 UINT stride, vb_pos, size;
3415 HRESULT hr;
3417 TRACE("iface %p, primitive_type %#x, fvf %#lx, vertices %p, vertex_count %lu, flags %#lx.\n",
3418 iface, primitive_type, fvf, vertices, vertex_count, flags);
3420 if (!vertex_count)
3422 WARN("0 vertex count.\n");
3423 return D3D_OK;
3426 /* Get the stride */
3427 stride = get_flexible_vertex_size(fvf);
3428 size = vertex_count * stride;
3430 wined3d_mutex_lock();
3432 if (FAILED(hr = wined3d_streaming_buffer_upload(device->wined3d_device,
3433 &device->vertex_buffer, vertices, size, stride, &vb_pos)))
3434 goto done;
3436 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer.buffer, 0, stride);
3437 if (FAILED(hr))
3438 goto done;
3440 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3441 wined3d_device_context_set_primitive_type(device->immediate_context,
3442 wined3d_primitive_type_from_ddraw(primitive_type), 0);
3443 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3444 d3d_device_sync_surfaces(device);
3445 wined3d_device_context_draw(device->immediate_context, vb_pos / stride, vertex_count, 0, 0);
3447 done:
3448 wined3d_mutex_unlock();
3449 return hr;
3452 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3453 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3454 DWORD vertex_count, DWORD flags)
3456 return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3459 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3460 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3461 DWORD vertex_count, DWORD flags)
3463 HRESULT hr;
3464 WORD old_fpucw;
3466 old_fpucw = d3d_fpu_setup();
3467 hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3468 set_fpu_control_word(old_fpucw);
3470 return hr;
3473 static void setup_lighting(const struct d3d_device *device, DWORD fvf, DWORD flags)
3475 BOOL enable = TRUE;
3477 /* Ignore the D3DFVF_XYZRHW case here, wined3d takes care of that */
3478 if (!device->material || !(fvf & D3DFVF_NORMAL) || (flags & D3DDP_DONOTLIGHT))
3479 enable = FALSE;
3481 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_LIGHTING, enable);
3485 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3486 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3487 DWORD flags)
3489 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3491 TRACE("iface %p, primitive_type %#x, fvf %#lx, vertices %p, vertex_count %lu, flags %#lx.\n",
3492 iface, primitive_type, fvf, vertices, vertex_count, flags);
3494 setup_lighting(device, fvf, flags);
3496 return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3497 primitive_type, fvf, vertices, vertex_count, flags);
3500 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3501 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3502 DWORD vertex_count, DWORD flags)
3504 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3505 DWORD fvf;
3507 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %lu, flags %#lx.\n",
3508 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3510 switch (vertex_type)
3512 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3513 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3514 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3515 default:
3516 FIXME("Unhandled vertex type %#x.\n", vertex_type);
3517 return DDERR_INVALIDPARAMS; /* Should never happen */
3520 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface,
3521 primitive_type, fvf, vertices, vertex_count, flags);
3524 /*****************************************************************************
3525 * IDirect3DDevice7::DrawIndexedPrimitive
3527 * Draws vertices from an application-provided pointer, based on the index
3528 * numbers in a WORD array.
3530 * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3531 * an FVF format for D3D7
3533 * Params:
3534 * PrimitiveType: The primitive type to draw
3535 * VertexType: The FVF vertex description
3536 * Vertices: Pointer to the vertex array
3537 * VertexCount: ?
3538 * Indices: Pointer to the index array
3539 * IndexCount: Number of indices = Number of vertices to draw
3540 * Flags: As usual, some flags
3542 * Returns:
3543 * D3D_OK on success
3544 * DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3546 *****************************************************************************/
3547 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3548 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3549 WORD *indices, DWORD index_count, DWORD flags)
3551 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3552 HRESULT hr;
3553 UINT stride = get_flexible_vertex_size(fvf);
3554 UINT vtx_size = stride * vertex_count, idx_size = index_count * sizeof(*indices);
3555 UINT vb_pos, ib_pos;
3557 TRACE("iface %p, primitive_type %#x, fvf %#lx, vertices %p, vertex_count %lu, "
3558 "indices %p, index_count %lu, flags %#lx.\n",
3559 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3561 if (!vertex_count || !index_count)
3563 WARN("0 vertex or index count.\n");
3564 return D3D_OK;
3567 /* Set the D3DDevice's FVF */
3568 wined3d_mutex_lock();
3570 if (FAILED(hr = wined3d_streaming_buffer_upload(device->wined3d_device,
3571 &device->vertex_buffer, vertices, vtx_size, stride, &vb_pos)))
3572 goto done;
3574 if (FAILED(hr = wined3d_streaming_buffer_upload(device->wined3d_device,
3575 &device->index_buffer, indices, idx_size, sizeof(*indices), &ib_pos)))
3576 goto done;
3578 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer.buffer, 0, stride);
3579 if (FAILED(hr))
3580 goto done;
3581 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer.buffer, WINED3DFMT_R16_UINT);
3583 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3584 wined3d_device_context_set_primitive_type(device->immediate_context,
3585 wined3d_primitive_type_from_ddraw(primitive_type), 0);
3586 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3587 d3d_device_sync_surfaces(device);
3588 wined3d_device_context_draw_indexed(device->immediate_context, vb_pos / stride,
3589 ib_pos / sizeof(*indices), index_count, 0, 0);
3591 done:
3592 wined3d_mutex_unlock();
3593 return hr;
3596 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3597 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3598 WORD *indices, DWORD index_count, DWORD flags)
3600 return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3601 vertices, vertex_count, indices, index_count, flags);
3604 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3605 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3606 WORD *indices, DWORD index_count, DWORD flags)
3608 HRESULT hr;
3609 WORD old_fpucw;
3611 old_fpucw = d3d_fpu_setup();
3612 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3613 vertices, vertex_count, indices, index_count, flags);
3614 set_fpu_control_word(old_fpucw);
3616 return hr;
3619 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3620 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3621 WORD *indices, DWORD index_count, DWORD flags)
3623 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3625 TRACE("iface %p, primitive_type %#x, fvf %#lx, vertices %p, vertex_count %lu, "
3626 "indices %p, index_count %lu, flags %#lx.\n",
3627 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3629 setup_lighting(device, fvf, flags);
3631 return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3632 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3635 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3636 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3637 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3639 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3640 DWORD fvf;
3642 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %lu, "
3643 "indices %p, index_count %lu, flags %#lx.\n",
3644 iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3646 switch (vertex_type)
3648 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3649 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3650 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3651 default:
3652 ERR("Unhandled vertex type %#x.\n", vertex_type);
3653 return DDERR_INVALIDPARAMS; /* Should never happen */
3656 return d3d_device3_DrawIndexedPrimitive(&device->IDirect3DDevice3_iface,
3657 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3660 /*****************************************************************************
3661 * IDirect3DDevice3::End
3663 * Ends a draw begun with IDirect3DDevice3::Begin or
3664 * IDirect3DDevice::BeginIndexed. The vertices specified with
3665 * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
3666 * the IDirect3DDevice3::DrawPrimitive method. So far only
3667 * non-indexed mode is supported
3669 * Version 2 and 3
3671 * Params:
3672 * Flags: Some flags, as usual. Don't know which are defined
3674 * Returns:
3675 * The return value of IDirect3DDevice3::DrawPrimitive
3677 *****************************************************************************/
3678 static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
3680 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3682 TRACE("iface %p, flags %#lx.\n", iface, flags);
3684 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface, device->primitive_type,
3685 device->vertex_type, device->sysmem_vertex_buffer, device->nb_vertices, device->render_flags);
3688 static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
3690 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3692 TRACE("iface %p, flags %#lx.\n", iface, flags);
3694 return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
3697 /*****************************************************************************
3698 * IDirect3DDevice7::SetClipStatus
3700 * Sets the clip status. This defines things as clipping conditions and
3701 * the extents of the clipping region.
3703 * Version 2, 3 and 7
3705 * Params:
3706 * ClipStatus:
3708 * Returns:
3709 * D3D_OK because it's a stub
3710 * (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3712 *****************************************************************************/
3713 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3715 FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3717 return D3D_OK;
3720 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3722 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3724 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3726 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3729 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3731 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3733 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3735 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3738 /*****************************************************************************
3739 * IDirect3DDevice7::GetClipStatus
3741 * Returns the clip status
3743 * Params:
3744 * ClipStatus: Address to write the clip status to
3746 * Returns:
3747 * D3D_OK because it's a stub
3749 *****************************************************************************/
3750 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3752 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3753 struct wined3d_viewport vp;
3755 FIXME("iface %p, clip_status %p stub.\n", iface, clip_status);
3757 vp = device->stateblock_state->viewport;
3758 clip_status->minx = vp.x;
3759 clip_status->maxx = vp.x + vp.width;
3760 clip_status->miny = vp.y;
3761 clip_status->maxy = vp.y + vp.height;
3762 clip_status->minz = 0.0f;
3763 clip_status->maxz = 0.0f;
3764 clip_status->dwFlags = D3DCLIPSTATUS_EXTENTS2;
3765 clip_status->dwStatus = 0;
3767 return D3D_OK;
3770 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3772 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3774 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3776 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3779 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3781 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3783 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3785 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3788 /*****************************************************************************
3789 * IDirect3DDevice::DrawPrimitiveStrided
3791 * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3793 * Version 3 and 7
3795 * Params:
3796 * PrimitiveType: The primitive type to draw
3797 * VertexType: The FVF description of the vertices to draw (for the stride??)
3798 * D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3799 * the vertex data locations
3800 * VertexCount: The number of vertices to draw
3801 * Flags: Some flags
3803 * Returns:
3804 * D3D_OK, because it's a stub
3805 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3807 *****************************************************************************/
3808 static void pack_strided_data(BYTE *dst, DWORD count, const D3DDRAWPRIMITIVESTRIDEDDATA *src, DWORD fvf)
3810 DWORD i, tex, offset;
3812 for (i = 0; i < count; i++)
3814 /* The contents of the strided data are determined by the fvf,
3815 * not by the members set in src. So it's valid
3816 * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3817 * not set in the fvf. */
3818 if (fvf & D3DFVF_POSITION_MASK)
3820 offset = i * src->position.dwStride;
3821 if (fvf & D3DFVF_XYZRHW)
3823 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 4 * sizeof(float));
3824 dst += 4 * sizeof(float);
3826 else
3828 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 3 * sizeof(float));
3829 dst += 3 * sizeof(float);
3833 if (fvf & D3DFVF_NORMAL)
3835 offset = i * src->normal.dwStride;
3836 memcpy(dst, ((BYTE *)src->normal.lpvData) + offset, 3 * sizeof(float));
3837 dst += 3 * sizeof(float);
3840 if (fvf & D3DFVF_DIFFUSE)
3842 offset = i * src->diffuse.dwStride;
3843 memcpy(dst, ((BYTE *)src->diffuse.lpvData) + offset, sizeof(DWORD));
3844 dst += sizeof(DWORD);
3847 if (fvf & D3DFVF_SPECULAR)
3849 offset = i * src->specular.dwStride;
3850 memcpy(dst, ((BYTE *)src->specular.lpvData) + offset, sizeof(DWORD));
3851 dst += sizeof(DWORD);
3854 for (tex = 0; tex < GET_TEXCOUNT_FROM_FVF(fvf); ++tex)
3856 DWORD attrib_count = GET_TEXCOORD_SIZE_FROM_FVF(fvf, tex);
3857 offset = i * src->textureCoords[tex].dwStride;
3858 memcpy(dst, ((BYTE *)src->textureCoords[tex].lpvData) + offset, attrib_count * sizeof(float));
3859 dst += attrib_count * sizeof(float);
3864 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
3865 DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data, DWORD vertex_count, DWORD flags)
3867 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3868 HRESULT hr;
3869 UINT dst_stride = get_flexible_vertex_size(fvf);
3870 UINT dst_size = dst_stride * vertex_count;
3871 void *dst_data;
3872 UINT vb_pos;
3874 TRACE("iface %p, primitive_type %#x, fvf %#lx, strided_data %p, vertex_count %lu, flags %#lx.\n",
3875 iface, primitive_type, fvf, strided_data, vertex_count, flags);
3877 if (!vertex_count)
3879 WARN("0 vertex count.\n");
3880 return D3D_OK;
3883 wined3d_mutex_lock();
3885 if (FAILED(hr = wined3d_streaming_buffer_map(device->wined3d_device,
3886 &device->vertex_buffer, dst_size, dst_stride, &vb_pos, &dst_data)))
3887 goto done;
3888 pack_strided_data(dst_data, vertex_count, strided_data, fvf);
3889 wined3d_streaming_buffer_unmap(&device->vertex_buffer);
3891 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer.buffer, 0, dst_stride);
3892 if (FAILED(hr))
3893 goto done;
3894 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3896 wined3d_device_context_set_primitive_type(device->immediate_context,
3897 wined3d_primitive_type_from_ddraw(primitive_type), 0);
3898 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3899 d3d_device_sync_surfaces(device);
3900 wined3d_device_context_draw(device->immediate_context, vb_pos / dst_stride, vertex_count, 0, 0);
3902 done:
3903 wined3d_mutex_unlock();
3904 return hr;
3907 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3908 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3909 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3911 return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3912 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3915 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3916 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3917 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3919 HRESULT hr;
3920 WORD old_fpucw;
3922 old_fpucw = d3d_fpu_setup();
3923 hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3924 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3925 set_fpu_control_word(old_fpucw);
3927 return hr;
3930 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3931 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3932 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3934 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3936 TRACE("iface %p, primitive_type %#x, FVF %#lx, strided_data %p, vertex_count %lu, flags %#lx.\n",
3937 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3939 setup_lighting(device, VertexType, Flags);
3941 return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
3942 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3945 /*****************************************************************************
3946 * IDirect3DDevice7::DrawIndexedPrimitiveStrided
3948 * Draws primitives specified by strided data locations based on indices
3950 * Version 3 and 7
3952 * Params:
3953 * PrimitiveType:
3955 * Returns:
3956 * D3D_OK, because it's a stub
3957 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3958 * (DDERR_INVALIDPARAMS if Indices is NULL)
3960 *****************************************************************************/
3961 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
3962 D3DPRIMITIVETYPE primitive_type, DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data,
3963 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3965 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3966 UINT vtx_dst_stride = get_flexible_vertex_size(fvf);
3967 UINT vtx_dst_size = vertex_count * vtx_dst_stride;
3968 UINT idx_size = index_count * sizeof(WORD);
3969 void *dst_data;
3970 UINT vb_pos;
3971 UINT ib_pos;
3972 HRESULT hr;
3974 TRACE("iface %p, primitive_type %#x, fvf %#lx, strided_data %p, "
3975 "vertex_count %lu, indices %p, index_count %lu, flags %#lx.\n",
3976 iface, primitive_type, fvf, strided_data, vertex_count, indices, index_count, flags);
3978 if (!vertex_count || !index_count)
3980 WARN("0 vertex or index count.\n");
3981 return D3D_OK;
3984 wined3d_mutex_lock();
3986 if (FAILED(hr = wined3d_streaming_buffer_map(device->wined3d_device,
3987 &device->vertex_buffer, vtx_dst_size, vtx_dst_stride, &vb_pos, &dst_data)))
3988 goto done;
3989 pack_strided_data(dst_data, vertex_count, strided_data, fvf);
3990 wined3d_streaming_buffer_unmap(&device->vertex_buffer);
3992 if (FAILED(hr = wined3d_streaming_buffer_upload(device->wined3d_device,
3993 &device->index_buffer, indices, idx_size, sizeof(WORD), &ib_pos)))
3994 goto done;
3996 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer.buffer, 0, vtx_dst_stride);
3997 if (FAILED(hr))
3998 goto done;
3999 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer.buffer, WINED3DFMT_R16_UINT);
4001 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4002 wined3d_device_context_set_primitive_type(device->immediate_context,
4003 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4004 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4005 d3d_device_sync_surfaces(device);
4006 wined3d_device_context_draw_indexed(device->immediate_context,
4007 vb_pos / vtx_dst_stride, ib_pos / sizeof(WORD), index_count, 0, 0);
4009 done:
4010 wined3d_mutex_unlock();
4011 return hr;
4014 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4015 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4016 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4017 WORD *Indices, DWORD IndexCount, DWORD Flags)
4019 return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4020 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4023 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4024 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4025 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4026 WORD *Indices, DWORD IndexCount, DWORD Flags)
4028 HRESULT hr;
4029 WORD old_fpucw;
4031 old_fpucw = d3d_fpu_setup();
4032 hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4033 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4034 set_fpu_control_word(old_fpucw);
4036 return hr;
4039 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4040 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4041 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4042 DWORD IndexCount, DWORD Flags)
4044 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4046 TRACE("iface %p, primitive_type %#x, FVF %#lx, strided_data %p, vertex_count %lu, indices %p, index_count %lu, flags %#lx.\n",
4047 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4049 setup_lighting(device, VertexType, Flags);
4051 return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
4052 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4055 /*****************************************************************************
4056 * IDirect3DDevice7::DrawPrimitiveVB
4058 * Draws primitives from a vertex buffer to the screen.
4060 * Version 3 and 7
4062 * Params:
4063 * PrimitiveType: Type of primitive to be rendered.
4064 * D3DVertexBuf: Source Vertex Buffer
4065 * StartVertex: Index of the first vertex from the buffer to be rendered
4066 * NumVertices: Number of vertices to be rendered
4067 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4069 * Return values
4070 * D3D_OK on success
4071 * DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4073 *****************************************************************************/
4074 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
4075 IDirect3DVertexBuffer7 *vb, DWORD start_vertex, DWORD vertex_count, DWORD flags)
4077 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4078 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4079 struct wined3d_resource *wined3d_resource;
4080 struct wined3d_map_desc wined3d_map_desc;
4081 struct wined3d_box wined3d_box = {0};
4082 DWORD stride;
4083 HRESULT hr;
4085 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %lu, vertex_count %lu, flags %#lx.\n",
4086 iface, primitive_type, vb, start_vertex, vertex_count, flags);
4088 if (!vertex_count)
4090 WARN("0 vertex count.\n");
4091 return D3D_OK;
4094 vb_impl->discarded = false;
4096 stride = get_flexible_vertex_size(vb_impl->fvf);
4098 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4100 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawPrimitive().\n");
4101 wined3d_mutex_lock();
4102 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4103 wined3d_box.left = start_vertex * stride;
4104 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4105 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4106 &wined3d_box, WINED3D_MAP_READ)))
4108 wined3d_mutex_unlock();
4109 return D3DERR_VERTEXBUFFERLOCKED;
4111 hr = d3d_device7_DrawPrimitive(iface, primitive_type, vb_impl->fvf, wined3d_map_desc.data,
4112 vertex_count, flags);
4113 wined3d_resource_unmap(wined3d_resource, 0);
4114 wined3d_mutex_unlock();
4115 return hr;
4118 wined3d_mutex_lock();
4119 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4120 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4121 0, vb_impl->wined3d_buffer, 0, stride)))
4123 WARN("Failed to set stream source, hr %#lx.\n", hr);
4124 wined3d_mutex_unlock();
4125 return hr;
4128 /* Now draw the primitives */
4129 wined3d_device_context_set_primitive_type(device->immediate_context,
4130 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4131 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4132 d3d_device_sync_surfaces(device);
4133 wined3d_device_context_draw(device->immediate_context, start_vertex, vertex_count, 0, 0);
4135 wined3d_mutex_unlock();
4137 return hr;
4140 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4141 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4143 return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4146 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4147 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4149 HRESULT hr;
4150 WORD old_fpucw;
4152 old_fpucw = d3d_fpu_setup();
4153 hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4154 set_fpu_control_word(old_fpucw);
4156 return hr;
4159 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4160 IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4162 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4163 struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)D3DVertexBuf);
4165 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %lu, vertex_count %lu, flags %#lx.\n",
4166 iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4168 setup_lighting(device, vb->fvf, Flags);
4170 return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4171 PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4174 /*****************************************************************************
4175 * IDirect3DDevice7::DrawIndexedPrimitiveVB
4177 * Draws primitives from a vertex buffer to the screen
4179 * Params:
4180 * PrimitiveType: Type of primitive to be rendered.
4181 * D3DVertexBuf: Source Vertex Buffer
4182 * StartVertex: Index of the first vertex from the buffer to be rendered
4183 * NumVertices: Number of vertices to be rendered
4184 * Indices: Array of DWORDs used to index into the Vertices
4185 * IndexCount: Number of indices in Indices
4186 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4188 * Return values
4190 *****************************************************************************/
4191 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4192 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer7 *vb,
4193 DWORD start_vertex, DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4195 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4196 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4197 DWORD stride = get_flexible_vertex_size(vb_impl->fvf);
4198 struct wined3d_resource *wined3d_resource;
4199 struct wined3d_map_desc wined3d_map_desc;
4200 struct wined3d_box wined3d_box = {0};
4201 HRESULT hr;
4202 UINT ib_pos;
4204 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %lu, "
4205 "vertex_count %lu, indices %p, index_count %lu, flags %#lx.\n",
4206 iface, primitive_type, vb, start_vertex, vertex_count, indices, index_count, flags);
4208 if (!vertex_count || !index_count)
4210 WARN("0 vertex or index count.\n");
4211 return D3D_OK;
4214 vb_impl->discarded = false;
4216 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4218 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawIndexedPrimitive().\n");
4219 wined3d_mutex_lock();
4220 wined3d_box.left = start_vertex * stride;
4221 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4222 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4223 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4224 &wined3d_box, WINED3D_MAP_READ)))
4226 wined3d_mutex_unlock();
4227 return D3DERR_VERTEXBUFFERLOCKED;
4229 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, vb_impl->fvf,
4230 wined3d_map_desc.data, vertex_count, indices, index_count, flags);
4231 wined3d_resource_unmap(wined3d_resource, 0);
4232 wined3d_mutex_unlock();
4233 return hr;
4236 /* Steps:
4237 * 1) Upload the indices to the index buffer
4238 * 2) Set the index source
4239 * 3) Set the Vertex Buffer as the Stream source
4240 * 4) Call wined3d_device_context_draw_indexed()
4243 wined3d_mutex_lock();
4245 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4247 if (FAILED(hr = wined3d_streaming_buffer_upload(device->wined3d_device,
4248 &device->index_buffer, indices, index_count * sizeof(WORD), sizeof(WORD), &ib_pos)))
4250 wined3d_mutex_unlock();
4251 return hr;
4254 /* Set the index stream */
4255 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer.buffer, WINED3DFMT_R16_UINT);
4257 /* Set the vertex stream source */
4258 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4259 0, vb_impl->wined3d_buffer, 0, stride)))
4261 ERR("Failed to set stream source for device %p, hr %#lx.\n", device, hr);
4262 wined3d_mutex_unlock();
4263 return hr;
4266 wined3d_device_context_set_primitive_type(device->immediate_context,
4267 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4268 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4269 d3d_device_sync_surfaces(device);
4270 wined3d_device_context_draw_indexed(device->immediate_context, start_vertex,
4271 ib_pos / sizeof(WORD), index_count, 0, 0);
4273 wined3d_mutex_unlock();
4275 return hr;
4278 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4279 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4280 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4282 return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4283 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4286 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4287 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4288 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4290 HRESULT hr;
4291 WORD old_fpucw;
4293 old_fpucw = d3d_fpu_setup();
4294 hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4295 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4296 set_fpu_control_word(old_fpucw);
4298 return hr;
4301 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4302 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer *vertex_buffer,
4303 WORD *indices, DWORD index_count, DWORD flags)
4305 struct d3d_vertex_buffer *vb =
4306 unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)vertex_buffer);
4307 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4308 DWORD stride;
4310 TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %lu, flags %#lx.\n",
4311 iface, primitive_type, vertex_buffer, indices, index_count, flags);
4313 setup_lighting(device, vb->fvf, flags);
4315 if (!(stride = get_flexible_vertex_size(vb->fvf)))
4316 return D3D_OK;
4318 return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, primitive_type,
4319 &vb->IDirect3DVertexBuffer7_iface, 0, vb->size / stride, indices, index_count, flags);
4322 /*****************************************************************************
4323 * IDirect3DDevice7::ComputeSphereVisibility
4325 * Calculates the visibility of spheres in the current viewport. The spheres
4326 * are passed in the Centers and Radii arrays, the results are passed back
4327 * in the ReturnValues array. Return values are either completely visible,
4328 * partially visible or completely invisible.
4329 * The return value consists of a combination of D3DCLIP_* flags, or is
4330 * 0 if the sphere is completely visible (according to the SDK, not checked)
4332 * Version 3 and 7
4334 * Params:
4335 * Centers: Array containing the sphere centers
4336 * Radii: Array containing the sphere radii
4337 * NumSpheres: The number of centers and radii in the arrays
4338 * Flags: Some flags
4339 * ReturnValues: Array to write the results to
4341 * Returns:
4342 * D3D_OK
4343 * (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4344 * (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4345 * is singular)
4347 *****************************************************************************/
4349 static DWORD in_plane(UINT idx, struct wined3d_vec4 p, D3DVECTOR center, D3DVALUE radius, BOOL equality)
4351 float distance, norm;
4353 norm = sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
4354 distance = (p.x * center.x + p.y * center.y + p.z * center.z + p.w) / norm;
4356 if (equality)
4358 if (fabs(distance) <= radius)
4359 return D3DSTATUS_CLIPUNIONLEFT << idx;
4360 if (distance <= -radius)
4361 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4363 else
4365 if (fabs(distance) < radius)
4366 return D3DSTATUS_CLIPUNIONLEFT << idx;
4367 if (distance < -radius)
4368 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4370 return 0;
4373 static void prepare_clip_space_planes(struct d3d_device *device, struct wined3d_vec4 *plane)
4375 const struct wined3d_stateblock_state *state;
4376 struct wined3d_matrix m;
4378 /* We want the wined3d matrices since those include the legacy viewport
4379 * transformation. */
4380 wined3d_mutex_lock();
4381 state = device->stateblock_state;
4382 multiply_matrix(&m, &state->transforms[WINED3D_TS_VIEW], &state->transforms[WINED3D_TS_WORLD]);
4383 multiply_matrix(&m, &state->transforms[WINED3D_TS_PROJECTION], &m);
4384 wined3d_mutex_unlock();
4386 /* Left plane. */
4387 plane[0].x = m._14 + m._11;
4388 plane[0].y = m._24 + m._21;
4389 plane[0].z = m._34 + m._31;
4390 plane[0].w = m._44 + m._41;
4392 /* Right plane. */
4393 plane[1].x = m._14 - m._11;
4394 plane[1].y = m._24 - m._21;
4395 plane[1].z = m._34 - m._31;
4396 plane[1].w = m._44 - m._41;
4398 /* Top plane. */
4399 plane[2].x = m._14 - m._12;
4400 plane[2].y = m._24 - m._22;
4401 plane[2].z = m._34 - m._32;
4402 plane[2].w = m._44 - m._42;
4404 /* Bottom plane. */
4405 plane[3].x = m._14 + m._12;
4406 plane[3].y = m._24 + m._22;
4407 plane[3].z = m._34 + m._32;
4408 plane[3].w = m._44 + m._42;
4410 /* Front plane. */
4411 plane[4].x = m._13;
4412 plane[4].y = m._23;
4413 plane[4].z = m._33;
4414 plane[4].w = m._43;
4416 /* Back plane. */
4417 plane[5].x = m._14 - m._13;
4418 plane[5].y = m._24 - m._23;
4419 plane[5].z = m._34 - m._33;
4420 plane[5].w = m._44 - m._43;
4423 static void compute_sphere_visibility(const struct wined3d_vec4 *planes, DWORD enabled_planes, BOOL equality,
4424 const D3DVECTOR *centres, const D3DVALUE *radii, unsigned int sphere_count, DWORD *return_values)
4426 unsigned int mask, i, j;
4428 memset(return_values, 0, sphere_count * sizeof(*return_values));
4429 for (i = 0; i < sphere_count; ++i)
4431 mask = enabled_planes;
4432 while (mask)
4434 j = wined3d_bit_scan(&mask);
4435 return_values[i] |= in_plane(j, planes[j], centres[i], radii[i], equality);
4440 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4441 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4443 struct wined3d_vec4 plane[12];
4444 DWORD enabled_planes = 0x3f;
4445 DWORD user_clip_planes;
4446 UINT j;
4448 TRACE("iface %p, centers %p, radii %p, sphere_count %lu, flags %#lx, return_values %p.\n",
4449 iface, centers, radii, sphere_count, flags, return_values);
4451 prepare_clip_space_planes(impl_from_IDirect3DDevice7(iface), plane);
4453 IDirect3DDevice7_GetRenderState(iface, D3DRENDERSTATE_CLIPPLANEENABLE, &user_clip_planes);
4454 enabled_planes |= user_clip_planes << 6;
4455 for (j = 6; j < 12; ++j)
4456 IDirect3DDevice7_GetClipPlane(iface, j - 6, (D3DVALUE *)&plane[j]);
4458 compute_sphere_visibility(plane, enabled_planes, FALSE, centers, radii, sphere_count, return_values);
4459 return D3D_OK;
4462 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4463 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4465 static const DWORD enabled_planes = 0x3f;
4466 struct wined3d_vec4 plane[6];
4467 unsigned int i, j;
4469 TRACE("iface %p, centers %p, radii %p, sphere_count %lu, flags %#lx, return_values %p.\n",
4470 iface, centers, radii, sphere_count, flags, return_values);
4472 prepare_clip_space_planes(impl_from_IDirect3DDevice3(iface), plane);
4474 compute_sphere_visibility(plane, enabled_planes, TRUE, centers, radii, sphere_count, return_values);
4475 for (i = 0; i < sphere_count; ++i)
4477 BOOL intersect_frustum = FALSE, outside_frustum = FALSE;
4478 DWORD d3d7_result = return_values[i];
4480 return_values[i] = 0;
4482 for (j = 0; j < 6; ++j)
4484 DWORD clip = (d3d7_result >> j) & (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT);
4486 if (clip == D3DSTATUS_CLIPUNIONLEFT)
4488 return_values[i] |= D3DVIS_INTERSECT_LEFT << j * 2;
4489 intersect_frustum = TRUE;
4491 else if (clip)
4493 return_values[i] |= D3DVIS_OUTSIDE_LEFT << j * 2;
4494 outside_frustum = TRUE;
4497 if (outside_frustum)
4498 return_values[i] |= D3DVIS_OUTSIDE_FRUSTUM;
4499 else if (intersect_frustum)
4500 return_values[i] |= D3DVIS_INTERSECT_FRUSTUM;
4502 return D3D_OK;
4505 /*****************************************************************************
4506 * IDirect3DDevice7::GetTexture
4508 * Returns the texture interface handle assigned to a texture stage.
4509 * The returned texture is AddRefed. This is taken from old ddraw,
4510 * not checked in Windows.
4512 * Version 3 and 7
4514 * Params:
4515 * Stage: Texture stage to read the texture from
4516 * Texture: Address to store the interface pointer at
4518 * Returns:
4519 * D3D_OK on success
4520 * DDERR_INVALIDPARAMS if Texture is NULL
4522 *****************************************************************************/
4523 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4524 DWORD stage, IDirectDrawSurface7 **texture)
4526 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4527 struct wined3d_texture *wined3d_texture;
4528 struct ddraw_texture *ddraw_texture;
4530 TRACE("iface %p, stage %lu, texture %p.\n", iface, stage, texture);
4532 if (!texture)
4533 return DDERR_INVALIDPARAMS;
4535 if (stage >= DDRAW_MAX_TEXTURES)
4537 WARN("Invalid stage %lu.\n", stage);
4538 *texture = NULL;
4539 return D3D_OK;
4542 wined3d_mutex_lock();
4543 if (!(wined3d_texture = device->stateblock_state->textures[stage]))
4545 *texture = NULL;
4546 wined3d_mutex_unlock();
4547 return D3D_OK;
4550 ddraw_texture = wined3d_texture_get_parent(wined3d_texture);
4551 *texture = &ddraw_texture->root->IDirectDrawSurface7_iface;
4552 IDirectDrawSurface7_AddRef(*texture);
4553 wined3d_mutex_unlock();
4555 return D3D_OK;
4558 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4559 DWORD stage, IDirectDrawSurface7 **Texture)
4561 return d3d_device7_GetTexture(iface, stage, Texture);
4564 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4565 DWORD stage, IDirectDrawSurface7 **Texture)
4567 HRESULT hr;
4568 WORD old_fpucw;
4570 old_fpucw = d3d_fpu_setup();
4571 hr = d3d_device7_GetTexture(iface, stage, Texture);
4572 set_fpu_control_word(old_fpucw);
4574 return hr;
4577 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4579 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4580 struct ddraw_surface *ret_val_impl;
4581 HRESULT ret;
4582 IDirectDrawSurface7 *ret_val;
4584 TRACE("iface %p, stage %lu, texture %p.\n", iface, stage, Texture2);
4586 ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4588 ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4589 *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4591 TRACE("Returning texture %p.\n", *Texture2);
4593 return ret;
4596 /*****************************************************************************
4597 * IDirect3DDevice7::SetTexture
4599 * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4601 * Version 3 and 7
4603 * Params:
4604 * Stage: The stage to assign the texture to
4605 * Texture: Interface pointer to the texture surface
4607 * Returns
4608 * D3D_OK on success
4610 *****************************************************************************/
4611 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4612 DWORD stage, IDirectDrawSurface7 *texture)
4614 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4615 struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4616 struct wined3d_texture *wined3d_texture = NULL;
4618 TRACE("iface %p, stage %lu, texture %p.\n", iface, stage, texture);
4620 if (surf && (surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE))
4622 if (surf->draw_texture)
4624 wined3d_texture = surf->draw_texture;
4625 device->have_draw_textures = TRUE;
4627 else
4629 wined3d_texture = surf->wined3d_texture;
4633 wined3d_mutex_lock();
4634 wined3d_stateblock_set_texture(device->update_state, stage, wined3d_texture);
4635 wined3d_mutex_unlock();
4637 return D3D_OK;
4640 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4641 DWORD stage, IDirectDrawSurface7 *texture)
4643 return d3d_device7_SetTexture(iface, stage, texture);
4646 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4647 DWORD stage, IDirectDrawSurface7 *texture)
4649 HRESULT hr;
4650 WORD old_fpucw;
4652 old_fpucw = d3d_fpu_setup();
4653 hr = d3d_device7_SetTexture(iface, stage, texture);
4654 set_fpu_control_word(old_fpucw);
4656 return hr;
4659 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4660 DWORD stage, IDirect3DTexture2 *texture)
4662 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4663 struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4664 struct wined3d_texture *wined3d_texture = NULL;
4666 TRACE("iface %p, stage %lu, texture %p.\n", iface, stage, texture);
4668 wined3d_mutex_lock();
4670 if (tex && ((tex->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) || !device->hardware_device))
4672 if (tex->draw_texture)
4674 wined3d_texture = tex->draw_texture;
4675 device->have_draw_textures = TRUE;
4677 else
4679 wined3d_texture = tex->wined3d_texture;
4683 wined3d_stateblock_set_texture(device->state, stage, wined3d_texture);
4684 fixup_texture_alpha_op(device);
4686 wined3d_mutex_unlock();
4688 return D3D_OK;
4691 static const struct tss_lookup
4693 BOOL sampler_state;
4694 union
4696 enum wined3d_texture_stage_state texture_state;
4697 enum wined3d_sampler_state sampler_state;
4698 } u;
4700 tss_lookup[] =
4702 {FALSE, .u.texture_state = WINED3D_TSS_INVALID}, /* 0, unused */
4703 {FALSE, .u.texture_state = WINED3D_TSS_COLOR_OP}, /* 1, D3DTSS_COLOROP */
4704 {FALSE, .u.texture_state = WINED3D_TSS_COLOR_ARG1}, /* 2, D3DTSS_COLORARG1 */
4705 {FALSE, .u.texture_state = WINED3D_TSS_COLOR_ARG2}, /* 3, D3DTSS_COLORARG2 */
4706 {FALSE, .u.texture_state = WINED3D_TSS_ALPHA_OP}, /* 4, D3DTSS_ALPHAOP */
4707 {FALSE, .u.texture_state = WINED3D_TSS_ALPHA_ARG1}, /* 5, D3DTSS_ALPHAARG1 */
4708 {FALSE, .u.texture_state = WINED3D_TSS_ALPHA_ARG2}, /* 6, D3DTSS_ALPHAARG2 */
4709 {FALSE, .u.texture_state = WINED3D_TSS_BUMPENV_MAT00}, /* 7, D3DTSS_BUMPENVMAT00 */
4710 {FALSE, .u.texture_state = WINED3D_TSS_BUMPENV_MAT01}, /* 8, D3DTSS_BUMPENVMAT01 */
4711 {FALSE, .u.texture_state = WINED3D_TSS_BUMPENV_MAT10}, /* 9, D3DTSS_BUMPENVMAT10 */
4712 {FALSE, .u.texture_state = WINED3D_TSS_BUMPENV_MAT11}, /* 10, D3DTSS_BUMPENVMAT11 */
4713 {FALSE, .u.texture_state = WINED3D_TSS_TEXCOORD_INDEX}, /* 11, D3DTSS_TEXCOORDINDEX */
4714 {TRUE, .u.sampler_state = WINED3D_SAMP_ADDRESS_U}, /* 12, D3DTSS_ADDRESS */
4715 {TRUE, .u.sampler_state = WINED3D_SAMP_ADDRESS_U}, /* 13, D3DTSS_ADDRESSU */
4716 {TRUE, .u.sampler_state = WINED3D_SAMP_ADDRESS_V}, /* 14, D3DTSS_ADDRESSV */
4717 {TRUE, .u.sampler_state = WINED3D_SAMP_BORDER_COLOR}, /* 15, D3DTSS_BORDERCOLOR */
4718 {TRUE, .u.sampler_state = WINED3D_SAMP_MAG_FILTER}, /* 16, D3DTSS_MAGFILTER */
4719 {TRUE, .u.sampler_state = WINED3D_SAMP_MIN_FILTER}, /* 17, D3DTSS_MINFILTER */
4720 {TRUE, .u.sampler_state = WINED3D_SAMP_MIP_FILTER}, /* 18, D3DTSS_MIPFILTER */
4721 {TRUE, .u.sampler_state = WINED3D_SAMP_MIPMAP_LOD_BIAS}, /* 19, D3DTSS_MIPMAPLODBIAS */
4722 {TRUE, .u.sampler_state = WINED3D_SAMP_MAX_MIP_LEVEL}, /* 20, D3DTSS_MAXMIPLEVEL */
4723 {TRUE, .u.sampler_state = WINED3D_SAMP_MAX_ANISOTROPY}, /* 21, D3DTSS_MAXANISOTROPY */
4724 {FALSE, .u.texture_state = WINED3D_TSS_BUMPENV_LSCALE}, /* 22, D3DTSS_BUMPENVLSCALE */
4725 {FALSE, .u.texture_state = WINED3D_TSS_BUMPENV_LOFFSET}, /* 23, D3DTSS_BUMPENVLOFFSET */
4726 {FALSE, .u.texture_state = WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS}, /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4729 /*****************************************************************************
4730 * IDirect3DDevice7::GetTextureStageState
4732 * Retrieves a state from a texture stage.
4734 * Version 3 and 7
4736 * Params:
4737 * Stage: The stage to retrieve the state from
4738 * TexStageStateType: The state type to retrieve
4739 * State: Address to store the state's value at
4741 * Returns:
4742 * D3D_OK on success
4743 * DDERR_INVALIDPARAMS if State is NULL
4745 *****************************************************************************/
4746 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4747 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4749 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4750 const struct wined3d_stateblock_state *device_state;
4751 const struct tss_lookup *l;
4753 TRACE("iface %p, stage %lu, state %#x, value %p.\n",
4754 iface, stage, state, value);
4756 if (!value)
4757 return DDERR_INVALIDPARAMS;
4759 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4761 WARN("Invalid state %#x passed.\n", state);
4762 return DD_OK;
4765 if (stage >= DDRAW_MAX_TEXTURES)
4767 WARN("Invalid stage %lu.\n", stage);
4768 *value = 0;
4769 return D3D_OK;
4772 l = &tss_lookup[state];
4774 wined3d_mutex_lock();
4776 device_state = device->stateblock_state;
4778 if (l->sampler_state)
4780 *value = device_state->sampler_states[stage][l->u.sampler_state];
4782 switch (state)
4784 /* Mipfilter is a sampler state with different values */
4785 case D3DTSS_MIPFILTER:
4787 switch (*value)
4789 case WINED3D_TEXF_NONE:
4790 *value = D3DTFP_NONE;
4791 break;
4792 case WINED3D_TEXF_POINT:
4793 *value = D3DTFP_POINT;
4794 break;
4795 case WINED3D_TEXF_LINEAR:
4796 *value = D3DTFP_LINEAR;
4797 break;
4798 default:
4799 ERR("Unexpected mipfilter value %#lx.\n", *value);
4800 *value = D3DTFP_NONE;
4801 break;
4803 break;
4806 /* Magfilter has slightly different values */
4807 case D3DTSS_MAGFILTER:
4809 switch (*value)
4811 case WINED3D_TEXF_POINT:
4812 *value = D3DTFG_POINT;
4813 break;
4814 case WINED3D_TEXF_LINEAR:
4815 *value = D3DTFG_LINEAR;
4816 break;
4817 case WINED3D_TEXF_ANISOTROPIC:
4818 *value = D3DTFG_ANISOTROPIC;
4819 break;
4820 case WINED3D_TEXF_FLAT_CUBIC:
4821 *value = D3DTFG_FLATCUBIC;
4822 break;
4823 case WINED3D_TEXF_GAUSSIAN_CUBIC:
4824 *value = D3DTFG_GAUSSIANCUBIC;
4825 break;
4826 default:
4827 ERR("Unexpected wined3d mag filter value %#lx.\n", *value);
4828 *value = D3DTFG_POINT;
4829 break;
4831 break;
4834 default:
4835 break;
4838 else
4840 *value = device_state->texture_states[stage][l->u.texture_state];
4843 wined3d_mutex_unlock();
4845 return D3D_OK;
4848 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4849 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4851 return d3d_device7_GetTextureStageState(iface, stage, state, value);
4854 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4855 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4857 HRESULT hr;
4858 WORD old_fpucw;
4860 old_fpucw = d3d_fpu_setup();
4861 hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
4862 set_fpu_control_word(old_fpucw);
4864 return hr;
4867 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
4868 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4870 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4872 TRACE("iface %p, stage %lu, state %#x, value %p.\n",
4873 iface, stage, state, value);
4875 return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4878 /*****************************************************************************
4879 * IDirect3DDevice7::SetTextureStageState
4881 * Sets a texture stage state. Some stage types need to be handled specially,
4882 * because they do not exist in WineD3D and were moved to another place
4884 * Version 3 and 7
4886 * Params:
4887 * Stage: The stage to modify
4888 * TexStageStateType: The state to change
4889 * State: The new value for the state
4891 * Returns:
4892 * D3D_OK on success
4894 *****************************************************************************/
4895 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
4896 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4898 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4899 const struct tss_lookup *l;
4901 TRACE("iface %p, stage %lu, state %#x, value %#lx.\n",
4902 iface, stage, state, value);
4904 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4906 WARN("Invalid state %#x passed.\n", state);
4907 return DD_OK;
4910 l = &tss_lookup[state];
4912 wined3d_mutex_lock();
4914 if (l->sampler_state)
4916 switch (state)
4918 /* Mipfilter is a sampler state with different values */
4919 case D3DTSS_MIPFILTER:
4921 switch (value)
4923 case D3DTFP_NONE:
4924 value = WINED3D_TEXF_NONE;
4925 break;
4926 case D3DTFP_POINT:
4927 value = WINED3D_TEXF_POINT;
4928 break;
4929 case 0: /* Unchecked */
4930 case D3DTFP_LINEAR:
4931 value = WINED3D_TEXF_LINEAR;
4932 break;
4933 default:
4934 ERR("Unexpected mipfilter value %#lx.\n", value);
4935 value = WINED3D_TEXF_NONE;
4936 break;
4938 break;
4941 /* Magfilter has slightly different values */
4942 case D3DTSS_MAGFILTER:
4944 switch (value)
4946 case D3DTFG_POINT:
4947 value = WINED3D_TEXF_POINT;
4948 break;
4949 case D3DTFG_LINEAR:
4950 value = WINED3D_TEXF_LINEAR;
4951 break;
4952 case D3DTFG_FLATCUBIC:
4953 value = WINED3D_TEXF_FLAT_CUBIC;
4954 break;
4955 case D3DTFG_GAUSSIANCUBIC:
4956 value = WINED3D_TEXF_GAUSSIAN_CUBIC;
4957 break;
4958 case D3DTFG_ANISOTROPIC:
4959 value = WINED3D_TEXF_ANISOTROPIC;
4960 break;
4961 default:
4962 ERR("Unexpected d3d7 mag filter value %#lx.\n", value);
4963 value = WINED3D_TEXF_POINT;
4964 break;
4966 break;
4969 case D3DTSS_ADDRESS:
4970 wined3d_stateblock_set_sampler_state(device->state, stage, WINED3D_SAMP_ADDRESS_V, value);
4971 break;
4973 default:
4974 break;
4977 wined3d_stateblock_set_sampler_state(device->state, stage, l->u.sampler_state, value);
4979 else
4980 wined3d_stateblock_set_texture_stage_state(device->update_state, stage, l->u.texture_state, value);
4982 wined3d_mutex_unlock();
4984 return D3D_OK;
4987 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4988 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4990 return d3d_device7_SetTextureStageState(iface, stage, state, value);
4993 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4994 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4996 HRESULT hr;
4997 WORD old_fpucw;
4999 old_fpucw = d3d_fpu_setup();
5000 hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
5001 set_fpu_control_word(old_fpucw);
5003 return hr;
5006 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
5007 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5009 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5010 DWORD old_value;
5011 HRESULT hr;
5013 TRACE("iface %p, stage %lu, state %#x, value %#lx.\n",
5014 iface, stage, state, value);
5016 /* Tests show that legacy texture blending is not reset if the texture stage state
5017 * value is unchanged. */
5018 if (FAILED(hr = IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface,
5019 stage, state, &old_value)))
5020 return hr;
5022 if (old_value == value)
5024 TRACE("Application is setting the same value over, nothing to do.\n");
5025 return D3D_OK;
5028 device->legacyTextureBlending = FALSE;
5030 return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5033 /*****************************************************************************
5034 * IDirect3DDevice7::ValidateDevice
5036 * SDK: "Reports the device's ability to render the currently set
5037 * texture-blending operations in a single pass". Whatever that means
5038 * exactly...
5040 * Version 3 and 7
5042 * Params:
5043 * NumPasses: Address to write the number of necessary passes for the
5044 * desired effect to.
5046 * Returns:
5047 * D3D_OK on success
5049 *****************************************************************************/
5050 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
5052 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5053 HRESULT hr;
5055 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5057 wined3d_mutex_lock();
5058 hr = wined3d_device_validate_device(device->wined3d_device, device->stateblock_state, pass_count);
5059 wined3d_mutex_unlock();
5061 return hr;
5064 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
5066 return d3d_device7_ValidateDevice(iface, pass_count);
5069 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
5071 HRESULT hr;
5072 WORD old_fpucw;
5074 old_fpucw = d3d_fpu_setup();
5075 hr = d3d_device7_ValidateDevice(iface, pass_count);
5076 set_fpu_control_word(old_fpucw);
5078 return hr;
5081 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
5083 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5085 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5087 return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
5090 /*****************************************************************************
5091 * IDirect3DDevice7::Clear
5093 * Fills the render target, the z buffer and the stencil buffer with a
5094 * clear color / value
5096 * Version 7 only
5098 * Params:
5099 * Count: Number of rectangles in Rects must be 0 if Rects is NULL
5100 * Rects: Rectangles to clear. If NULL, the whole surface is cleared
5101 * Flags: Some flags, as usual
5102 * Color: Clear color for the render target
5103 * Z: Clear value for the Z buffer
5104 * Stencil: Clear value to store in each stencil buffer entry
5106 * Returns:
5107 * D3D_OK on success
5109 *****************************************************************************/
5110 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
5111 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5113 const struct wined3d_color c =
5115 ((color >> 16) & 0xff) / 255.0f,
5116 ((color >> 8) & 0xff) / 255.0f,
5117 (color & 0xff) / 255.0f,
5118 ((color >> 24) & 0xff) / 255.0f,
5120 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5121 HRESULT hr;
5123 TRACE("iface %p, count %lu, rects %p, flags %#lx, color 0x%08lx, z %.8e, stencil %#lx.\n",
5124 iface, count, rects, flags, color, z, stencil);
5126 if (count && !rects)
5128 WARN("count %lu with NULL rects.\n", count);
5129 count = 0;
5132 wined3d_mutex_lock();
5133 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5134 d3d_device_sync_rendertarget(device);
5135 hr = wined3d_device_clear(device->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5136 wined3d_mutex_unlock();
5138 return hr;
5141 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
5142 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5144 return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5147 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
5148 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5150 HRESULT hr;
5151 WORD old_fpucw;
5153 old_fpucw = d3d_fpu_setup();
5154 hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5155 set_fpu_control_word(old_fpucw);
5157 return hr;
5160 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5162 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5163 struct wined3d_sub_resource_desc rt_desc;
5164 struct wined3d_rendertarget_view *rtv;
5165 struct ddraw_surface *surface;
5166 struct wined3d_viewport vp;
5168 TRACE("iface %p, viewport %p.\n", iface, viewport);
5170 if (!viewport)
5171 return DDERR_INVALIDPARAMS;
5173 wined3d_mutex_lock();
5174 if (!(rtv = wined3d_device_context_get_rendertarget_view(device->immediate_context, 0)))
5176 wined3d_mutex_unlock();
5177 return DDERR_INVALIDCAPS;
5179 surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
5180 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc);
5182 if (!wined3d_bound_range(viewport->dwX, viewport->dwWidth, rt_desc.width)
5183 || !wined3d_bound_range(viewport->dwY, viewport->dwHeight, rt_desc.height))
5185 WARN("Invalid viewport, returning E_INVALIDARG.\n");
5186 wined3d_mutex_unlock();
5187 return E_INVALIDARG;
5190 vp.x = viewport->dwX;
5191 vp.y = viewport->dwY;
5192 vp.width = viewport->dwWidth;
5193 vp.height = viewport->dwHeight;
5194 vp.min_z = viewport->dvMinZ;
5195 vp.max_z = viewport->dvMaxZ;
5197 wined3d_stateblock_set_viewport(device->update_state, &vp);
5198 wined3d_mutex_unlock();
5200 return D3D_OK;
5203 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5205 return d3d_device7_SetViewport(iface, viewport);
5208 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5210 HRESULT hr;
5211 WORD old_fpucw;
5213 old_fpucw = d3d_fpu_setup();
5214 hr = d3d_device7_SetViewport(iface, viewport);
5215 set_fpu_control_word(old_fpucw);
5217 return hr;
5220 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5222 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5223 struct wined3d_viewport wined3d_viewport;
5225 TRACE("iface %p, viewport %p.\n", iface, viewport);
5227 if (!viewport)
5228 return DDERR_INVALIDPARAMS;
5230 wined3d_mutex_lock();
5231 wined3d_viewport = device->stateblock_state->viewport;
5232 wined3d_mutex_unlock();
5234 viewport->dwX = wined3d_viewport.x;
5235 viewport->dwY = wined3d_viewport.y;
5236 viewport->dwWidth = wined3d_viewport.width;
5237 viewport->dwHeight = wined3d_viewport.height;
5238 viewport->dvMinZ = wined3d_viewport.min_z;
5239 viewport->dvMaxZ = wined3d_viewport.max_z;
5241 return D3D_OK;
5244 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5246 return d3d_device7_GetViewport(iface, viewport);
5249 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5251 HRESULT hr;
5252 WORD old_fpucw;
5254 old_fpucw = d3d_fpu_setup();
5255 hr = d3d_device7_GetViewport(iface, viewport);
5256 set_fpu_control_word(old_fpucw);
5258 return hr;
5261 /*****************************************************************************
5262 * IDirect3DDevice7::SetMaterial
5264 * Sets the Material
5266 * Version 7
5268 * Params:
5269 * Mat: The material to set
5271 * Returns:
5272 * D3D_OK on success
5273 * DDERR_INVALIDPARAMS if Mat is NULL.
5275 *****************************************************************************/
5276 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5278 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5280 TRACE("iface %p, material %p.\n", iface, material);
5282 if (!material)
5283 return DDERR_INVALIDPARAMS;
5285 wined3d_mutex_lock();
5286 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5287 wined3d_stateblock_set_material(device->update_state, (const struct wined3d_material *)material);
5288 wined3d_mutex_unlock();
5290 return D3D_OK;
5293 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5295 return d3d_device7_SetMaterial(iface, material);
5298 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5300 HRESULT hr;
5301 WORD old_fpucw;
5303 old_fpucw = d3d_fpu_setup();
5304 hr = d3d_device7_SetMaterial(iface, material);
5305 set_fpu_control_word(old_fpucw);
5307 return hr;
5310 /*****************************************************************************
5311 * IDirect3DDevice7::GetMaterial
5313 * Returns the current material
5315 * Version 7
5317 * Params:
5318 * Mat: D3DMATERIAL7 structure to write the material parameters to
5320 * Returns:
5321 * D3D_OK on success
5322 * DDERR_INVALIDPARAMS if Mat is NULL
5324 *****************************************************************************/
5325 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5327 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5329 TRACE("iface %p, material %p.\n", iface, material);
5331 wined3d_mutex_lock();
5332 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5333 memcpy(material, &device->stateblock_state->material, sizeof(*material));
5334 wined3d_mutex_unlock();
5336 return D3D_OK;
5339 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5341 return d3d_device7_GetMaterial(iface, material);
5344 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5346 HRESULT hr;
5347 WORD old_fpucw;
5349 old_fpucw = d3d_fpu_setup();
5350 hr = d3d_device7_GetMaterial(iface, material);
5351 set_fpu_control_word(old_fpucw);
5353 return hr;
5356 /*****************************************************************************
5357 * IDirect3DDevice7::SetLight
5359 * Assigns a light to a light index, but doesn't activate it yet.
5361 * Version 7, IDirect3DLight uses this method for older versions
5363 * Params:
5364 * LightIndex: The index of the new light
5365 * Light: A D3DLIGHT7 structure describing the light
5367 * Returns:
5368 * D3D_OK on success
5370 *****************************************************************************/
5371 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5373 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5374 HRESULT hr;
5376 TRACE("iface %p, light_idx %lu, light %p.\n", iface, light_idx, light);
5378 wined3d_mutex_lock();
5379 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5380 hr = wined3d_stateblock_set_light(device->update_state, light_idx, (const struct wined3d_light *)light);
5381 wined3d_mutex_unlock();
5383 return hr_ddraw_from_wined3d(hr);
5386 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5388 return d3d_device7_SetLight(iface, light_idx, light);
5391 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5393 HRESULT hr;
5394 WORD old_fpucw;
5396 old_fpucw = d3d_fpu_setup();
5397 hr = d3d_device7_SetLight(iface, light_idx, light);
5398 set_fpu_control_word(old_fpucw);
5400 return hr;
5403 /*****************************************************************************
5404 * IDirect3DDevice7::GetLight
5406 * Returns the light assigned to a light index
5408 * Params:
5409 * Light: Structure to write the light information to
5411 * Returns:
5412 * D3D_OK on success
5413 * DDERR_INVALIDPARAMS if Light is NULL
5415 *****************************************************************************/
5416 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5418 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5419 BOOL enabled;
5420 HRESULT hr;
5422 TRACE("iface %p, light_idx %lu, light %p.\n", iface, light_idx, light);
5424 wined3d_mutex_lock();
5425 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5426 hr = wined3d_stateblock_get_light(device->state, light_idx, (struct wined3d_light *)light, &enabled);
5427 wined3d_mutex_unlock();
5429 return hr_ddraw_from_wined3d(hr);
5432 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5434 return d3d_device7_GetLight(iface, light_idx, light);
5437 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5439 HRESULT hr;
5440 WORD old_fpucw;
5442 old_fpucw = d3d_fpu_setup();
5443 hr = d3d_device7_GetLight(iface, light_idx, light);
5444 set_fpu_control_word(old_fpucw);
5446 return hr;
5449 /*****************************************************************************
5450 * IDirect3DDevice7::BeginStateBlock
5452 * Begins recording to a stateblock
5454 * Version 7
5456 * Returns:
5457 * D3D_OK on success
5459 *****************************************************************************/
5460 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5462 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5463 struct wined3d_stateblock *stateblock;
5464 HRESULT hr;
5466 TRACE("iface %p.\n", iface);
5468 wined3d_mutex_lock();
5469 if (device->recording)
5471 wined3d_mutex_unlock();
5472 WARN("Trying to begin a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5473 return D3DERR_INBEGINSTATEBLOCK;
5475 if (SUCCEEDED(hr = wined3d_stateblock_create(device->wined3d_device, NULL, WINED3D_SBT_RECORDED, &stateblock)))
5476 device->update_state = device->recording = stateblock;
5477 wined3d_mutex_unlock();
5479 return hr_ddraw_from_wined3d(hr);
5482 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5484 return d3d_device7_BeginStateBlock(iface);
5487 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5489 HRESULT hr;
5490 WORD old_fpucw;
5492 old_fpucw = d3d_fpu_setup();
5493 hr = d3d_device7_BeginStateBlock(iface);
5494 set_fpu_control_word(old_fpucw);
5496 return hr;
5499 /*****************************************************************************
5500 * IDirect3DDevice7::EndStateBlock
5502 * Stops recording to a state block and returns the created stateblock
5503 * handle.
5505 * Version 7
5507 * Params:
5508 * BlockHandle: Address to store the stateblock's handle to
5510 * Returns:
5511 * D3D_OK on success
5512 * DDERR_INVALIDPARAMS if BlockHandle is NULL
5514 *****************************************************************************/
5515 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5517 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5518 struct wined3d_stateblock *wined3d_sb;
5519 DWORD h;
5521 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5523 if (!stateblock)
5524 return DDERR_INVALIDPARAMS;
5526 wined3d_mutex_lock();
5527 if (!device->recording)
5529 wined3d_mutex_unlock();
5530 WARN("Trying to end a stateblock, but no stateblock is being recorded.\n");
5531 return D3DERR_NOTINBEGINSTATEBLOCK;
5533 wined3d_sb = device->recording;
5534 wined3d_stateblock_init_contained_states(wined3d_sb);
5535 device->recording = NULL;
5536 device->update_state = device->state;
5538 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5539 if (h == DDRAW_INVALID_HANDLE)
5541 ERR("Failed to allocate a stateblock handle.\n");
5542 wined3d_stateblock_decref(wined3d_sb);
5543 wined3d_mutex_unlock();
5544 *stateblock = 0;
5545 return DDERR_OUTOFMEMORY;
5548 wined3d_mutex_unlock();
5549 *stateblock = h + 1;
5551 return D3D_OK;
5554 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5556 return d3d_device7_EndStateBlock(iface, stateblock);
5559 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5561 HRESULT hr;
5562 WORD old_fpucw;
5564 old_fpucw = d3d_fpu_setup();
5565 hr = d3d_device7_EndStateBlock(iface, stateblock);
5566 set_fpu_control_word(old_fpucw);
5568 return hr;
5571 /*****************************************************************************
5572 * IDirect3DDevice7::PreLoad
5574 * Allows the app to signal that a texture will be used soon, to allow
5575 * the Direct3DDevice to load it to the video card in the meantime.
5577 * Version 7
5579 * Params:
5580 * Texture: The texture to preload
5582 * Returns:
5583 * D3D_OK on success
5584 * DDERR_INVALIDPARAMS if Texture is NULL
5586 *****************************************************************************/
5587 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5589 struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5591 TRACE("iface %p, texture %p.\n", iface, texture);
5593 if (!texture)
5594 return DDERR_INVALIDPARAMS;
5596 wined3d_mutex_lock();
5597 wined3d_resource_preload(wined3d_texture_get_resource(surface->draw_texture ? surface->draw_texture
5598 : surface->wined3d_texture));
5599 wined3d_mutex_unlock();
5601 return D3D_OK;
5604 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5606 return d3d_device7_PreLoad(iface, texture);
5609 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5611 HRESULT hr;
5612 WORD old_fpucw;
5614 old_fpucw = d3d_fpu_setup();
5615 hr = d3d_device7_PreLoad(iface, texture);
5616 set_fpu_control_word(old_fpucw);
5618 return hr;
5621 /*****************************************************************************
5622 * IDirect3DDevice7::ApplyStateBlock
5624 * Activates the state stored in a state block handle.
5626 * Params:
5627 * BlockHandle: The stateblock handle to activate
5629 * Returns:
5630 * D3D_OK on success
5631 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5633 *****************************************************************************/
5634 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5636 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5637 struct wined3d_stateblock *wined3d_sb;
5639 TRACE("iface %p, stateblock %#lx.\n", iface, stateblock);
5641 wined3d_mutex_lock();
5642 if (device->recording)
5644 wined3d_mutex_unlock();
5645 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5646 return D3DERR_INBEGINSTATEBLOCK;
5648 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5649 if (!wined3d_sb)
5651 WARN("Invalid stateblock handle.\n");
5652 wined3d_mutex_unlock();
5653 return D3DERR_INVALIDSTATEBLOCK;
5656 wined3d_stateblock_apply(wined3d_sb, device->state);
5657 wined3d_mutex_unlock();
5659 return D3D_OK;
5662 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5664 return d3d_device7_ApplyStateBlock(iface, stateblock);
5667 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5669 HRESULT hr;
5670 WORD old_fpucw;
5672 old_fpucw = d3d_fpu_setup();
5673 hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5674 set_fpu_control_word(old_fpucw);
5676 return hr;
5679 /*****************************************************************************
5680 * IDirect3DDevice7::CaptureStateBlock
5682 * Updates a stateblock's values to the values currently set for the device
5684 * Version 7
5686 * Params:
5687 * BlockHandle: Stateblock to update
5689 * Returns:
5690 * D3D_OK on success
5691 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5693 *****************************************************************************/
5694 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5696 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5697 struct wined3d_stateblock *wined3d_sb;
5699 TRACE("iface %p, stateblock %#lx.\n", iface, stateblock);
5701 wined3d_mutex_lock();
5702 if (device->recording)
5704 wined3d_mutex_unlock();
5705 WARN("Trying to capture a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5706 return D3DERR_INBEGINSTATEBLOCK;
5708 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5709 if (!wined3d_sb)
5711 WARN("Invalid stateblock handle.\n");
5712 wined3d_mutex_unlock();
5713 return D3DERR_INVALIDSTATEBLOCK;
5716 wined3d_stateblock_capture(wined3d_sb, device->state);
5717 wined3d_mutex_unlock();
5719 return D3D_OK;
5722 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5724 return d3d_device7_CaptureStateBlock(iface, stateblock);
5727 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5729 HRESULT hr;
5730 WORD old_fpucw;
5732 old_fpucw = d3d_fpu_setup();
5733 hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5734 set_fpu_control_word(old_fpucw);
5736 return hr;
5739 /*****************************************************************************
5740 * IDirect3DDevice7::DeleteStateBlock
5742 * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5744 * Version 7
5746 * Params:
5747 * BlockHandle: Stateblock handle to delete
5749 * Returns:
5750 * D3D_OK on success
5751 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5753 *****************************************************************************/
5754 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5756 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5757 struct wined3d_stateblock *wined3d_sb;
5758 ULONG ref;
5760 TRACE("iface %p, stateblock %#lx.\n", iface, stateblock);
5762 wined3d_mutex_lock();
5764 wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5765 if (!wined3d_sb)
5767 WARN("Invalid stateblock handle.\n");
5768 wined3d_mutex_unlock();
5769 return D3DERR_INVALIDSTATEBLOCK;
5772 if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5774 ERR("Something is still holding stateblock %p (refcount %lu).\n", wined3d_sb, ref);
5777 wined3d_mutex_unlock();
5779 return D3D_OK;
5782 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5784 return d3d_device7_DeleteStateBlock(iface, stateblock);
5787 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5789 HRESULT hr;
5790 WORD old_fpucw;
5792 old_fpucw = d3d_fpu_setup();
5793 hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5794 set_fpu_control_word(old_fpucw);
5796 return hr;
5799 /*****************************************************************************
5800 * IDirect3DDevice7::CreateStateBlock
5802 * Creates a new state block handle.
5804 * Version 7
5806 * Params:
5807 * Type: The state block type
5808 * BlockHandle: Address to write the created handle to
5810 * Returns:
5811 * D3D_OK on success
5812 * DDERR_INVALIDPARAMS if BlockHandle is NULL
5814 *****************************************************************************/
5815 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5816 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5818 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5819 struct wined3d_stateblock *wined3d_sb;
5820 HRESULT hr;
5821 DWORD h;
5823 TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5825 if (!stateblock)
5826 return DDERR_INVALIDPARAMS;
5828 if (type != D3DSBT_ALL
5829 && type != D3DSBT_PIXELSTATE
5830 && type != D3DSBT_VERTEXSTATE)
5832 WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5833 return DDERR_INVALIDPARAMS;
5836 wined3d_mutex_lock();
5838 if (device->recording)
5840 wined3d_mutex_unlock();
5841 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5842 return D3DERR_INBEGINSTATEBLOCK;
5845 if (FAILED(hr = wined3d_stateblock_create(device->wined3d_device,
5846 device->state, wined3d_stateblock_type_from_ddraw(type), &wined3d_sb)))
5848 WARN("Failed to create stateblock, hr %#lx.\n", hr);
5849 wined3d_mutex_unlock();
5850 return hr_ddraw_from_wined3d(hr);
5853 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5854 if (h == DDRAW_INVALID_HANDLE)
5856 ERR("Failed to allocate stateblock handle.\n");
5857 wined3d_stateblock_decref(wined3d_sb);
5858 wined3d_mutex_unlock();
5859 return DDERR_OUTOFMEMORY;
5862 *stateblock = h + 1;
5863 wined3d_mutex_unlock();
5865 return hr_ddraw_from_wined3d(hr);
5868 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5869 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5871 return d3d_device7_CreateStateBlock(iface, type, stateblock);
5874 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5875 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5877 HRESULT hr;
5878 WORD old_fpucw;
5880 old_fpucw = d3d_fpu_setup();
5881 hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5882 set_fpu_control_word(old_fpucw);
5884 return hr;
5887 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
5889 struct ddraw_surface *src_level, *dest_level;
5890 IDirectDrawSurface7 *temp;
5891 DDSURFACEDESC2 ddsd;
5892 BOOL levelFound; /* at least one suitable sublevel in dest found */
5894 /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5895 * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5896 * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5898 levelFound = FALSE;
5900 src_level = src;
5901 dest_level = dest;
5903 for (;src_level && dest_level;)
5905 if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5906 src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5908 levelFound = TRUE;
5910 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5911 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5912 IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5914 if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5916 dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5919 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5920 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5921 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5923 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5925 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5928 if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5929 if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5931 return !dest_level && levelFound;
5934 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dst,
5935 struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
5937 struct ddraw_surface *dst_level, *src_level;
5938 IDirectDrawSurface7 *temp;
5939 DDSURFACEDESC2 ddsd;
5940 POINT point;
5941 RECT src_rect;
5942 HRESULT hr;
5943 IDirectDrawPalette *pal = NULL, *pal_src = NULL;
5944 DWORD ckeyflag;
5945 DDCOLORKEY ddckey;
5947 /* Copy palette, if possible. */
5948 IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
5949 IDirectDrawSurface7_GetPalette(&dst->IDirectDrawSurface7_iface, &pal);
5951 if (pal_src != NULL && pal != NULL)
5953 PALETTEENTRY palent[256];
5955 IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
5956 IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
5959 if (pal) IDirectDrawPalette_Release(pal);
5960 if (pal_src) IDirectDrawPalette_Release(pal_src);
5962 /* Copy colorkeys, if present. */
5963 for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
5965 hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5967 if (SUCCEEDED(hr))
5969 IDirectDrawSurface7_SetColorKey(&dst->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5973 src_level = src;
5974 dst_level = dst;
5976 point = *DestPoint;
5977 src_rect = *SrcRect;
5979 for (;src_level && dst_level;)
5981 if (src_level->surface_desc.dwWidth == dst_level->surface_desc.dwWidth
5982 && src_level->surface_desc.dwHeight == dst_level->surface_desc.dwHeight)
5984 UINT src_w = src_rect.right - src_rect.left;
5985 UINT src_h = src_rect.bottom - src_rect.top;
5986 RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
5988 if (FAILED(hr = wined3d_device_context_blt(device->immediate_context,
5989 ddraw_surface_get_any_texture(dst_level, DDRAW_SURFACE_RW), dst_level->sub_resource_idx, &dst_rect,
5990 ddraw_surface_get_any_texture(src_level, DDRAW_SURFACE_READ),
5991 src_level->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
5992 ERR("Blit failed, hr %#lx.\n", hr);
5994 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5995 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5996 IDirectDrawSurface7_GetAttachedSurface(&dst_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5998 if (dst_level != dst)
5999 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6001 dst_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6004 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6005 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6006 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6008 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6010 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6012 point.x /= 2;
6013 point.y /= 2;
6015 src_rect.top /= 2;
6016 src_rect.left /= 2;
6017 src_rect.right = (src_rect.right + 1) / 2;
6018 src_rect.bottom = (src_rect.bottom + 1) / 2;
6021 if (src_level && src_level != src)
6022 IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6023 if (dst_level && dst_level != dst)
6024 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6027 /*****************************************************************************
6028 * IDirect3DDevice7::Load
6030 * Loads a rectangular area from the source into the destination texture.
6031 * It can also copy the source to the faces of a cubic environment map
6033 * Version 7
6035 * Params:
6036 * DestTex: Destination texture
6037 * DestPoint: Point in the destination where the source image should be
6038 * written to
6039 * SrcTex: Source texture
6040 * SrcRect: Source rectangle
6041 * Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6042 * DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6043 * DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6045 * Returns:
6046 * D3D_OK on success
6047 * DDERR_INVALIDPARAMS if dst_texture or src_texture is NULL, broken coordinates or anything unexpected.
6050 *****************************************************************************/
6051 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
6052 IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6054 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6055 struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
6056 struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
6057 POINT destpoint;
6058 RECT srcrect;
6060 TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#lx.\n",
6061 iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
6063 if( (!src) || (!dest) )
6064 return DDERR_INVALIDPARAMS;
6066 wined3d_mutex_lock();
6068 if (!src_rect)
6069 SetRect(&srcrect, 0, 0, src->surface_desc.dwWidth, src->surface_desc.dwHeight);
6070 else
6071 srcrect = *src_rect;
6073 if (!dst_pos)
6074 destpoint.x = destpoint.y = 0;
6075 else
6076 destpoint = *dst_pos;
6078 /* Check bad dimensions. dst_pos is validated against src, not dest, because
6079 * destination can be a subset of mip levels, in which case actual coordinates used
6080 * for it may be divided. If any dimension of dest is larger than source, it can't be
6081 * mip level subset, so an error can be returned early.
6083 if (IsRectEmpty(&srcrect) || srcrect.right > src->surface_desc.dwWidth ||
6084 srcrect.bottom > src->surface_desc.dwHeight ||
6085 destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6086 destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6087 dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6088 dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6090 wined3d_mutex_unlock();
6091 return DDERR_INVALIDPARAMS;
6094 /* Must be top level surfaces. */
6095 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6096 dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6098 wined3d_mutex_unlock();
6099 return DDERR_INVALIDPARAMS;
6102 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6104 struct ddraw_surface *src_face, *dest_face;
6105 DWORD src_face_flag, dest_face_flag;
6106 IDirectDrawSurface7 *temp;
6107 DDSURFACEDESC2 ddsd;
6108 int i;
6110 if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6112 wined3d_mutex_unlock();
6113 return DDERR_INVALIDPARAMS;
6116 /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6117 * time it's actual surface loading. */
6118 for (i = 0; i < 2; i++)
6120 dest_face = dest;
6121 src_face = src;
6123 for (;dest_face && src_face;)
6125 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6126 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6128 if (src_face_flag == dest_face_flag)
6130 if (i == 0)
6132 /* Destination mip levels must be subset of source mip levels. */
6133 if (!is_mip_level_subset(dest_face, src_face))
6135 wined3d_mutex_unlock();
6136 return DDERR_INVALIDPARAMS;
6139 else if (flags & dest_face_flag)
6141 copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6144 if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6146 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6147 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6148 IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6150 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6152 src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6154 else
6156 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6158 src_face = NULL;
6162 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6164 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6165 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6166 IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6168 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6170 dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6172 else
6174 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6176 dest_face = NULL;
6180 if (i == 0)
6182 /* Native returns error if src faces are not subset of dest faces. */
6183 if (src_face)
6185 wined3d_mutex_unlock();
6186 return DDERR_INVALIDPARAMS;
6191 wined3d_mutex_unlock();
6192 return D3D_OK;
6194 else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6196 wined3d_mutex_unlock();
6197 return DDERR_INVALIDPARAMS;
6200 /* Handle non cube map textures. */
6202 /* Destination mip levels must be subset of source mip levels. */
6203 if (!is_mip_level_subset(dest, src))
6205 wined3d_mutex_unlock();
6206 return DDERR_INVALIDPARAMS;
6209 copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6211 wined3d_mutex_unlock();
6213 return D3D_OK;
6216 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6217 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6219 return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6222 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6223 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6225 HRESULT hr;
6226 WORD old_fpucw;
6228 old_fpucw = d3d_fpu_setup();
6229 hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6230 set_fpu_control_word(old_fpucw);
6232 return hr;
6235 /*****************************************************************************
6236 * IDirect3DDevice7::LightEnable
6238 * Enables or disables a light
6240 * Version 7, IDirect3DLight uses this method too.
6242 * Params:
6243 * LightIndex: The index of the light to enable / disable
6244 * Enable: Enable or disable the light
6246 * Returns:
6247 * D3D_OK on success
6249 *****************************************************************************/
6250 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6252 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6253 HRESULT hr;
6255 TRACE("iface %p, light_idx %lu, enabled %#x.\n", iface, light_idx, enabled);
6257 wined3d_mutex_lock();
6258 hr = wined3d_stateblock_set_light_enable(device->update_state, light_idx, enabled);
6259 wined3d_mutex_unlock();
6261 return hr_ddraw_from_wined3d(hr);
6264 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6266 return d3d_device7_LightEnable(iface, light_idx, enabled);
6269 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6271 HRESULT hr;
6272 WORD old_fpucw;
6274 old_fpucw = d3d_fpu_setup();
6275 hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6276 set_fpu_control_word(old_fpucw);
6278 return hr;
6281 /*****************************************************************************
6282 * IDirect3DDevice7::GetLightEnable
6284 * Retrieves if the light with the given index is enabled or not
6286 * Version 7
6288 * Params:
6289 * LightIndex: Index of desired light
6290 * Enable: Pointer to a BOOL which contains the result
6292 * Returns:
6293 * D3D_OK on success
6294 * DDERR_INVALIDPARAMS if Enable is NULL
6296 *****************************************************************************/
6297 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6299 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6300 struct wined3d_light light;
6301 HRESULT hr;
6303 TRACE("iface %p, light_idx %lu, enabled %p.\n", iface, light_idx, enabled);
6305 if (!enabled)
6306 return DDERR_INVALIDPARAMS;
6308 wined3d_mutex_lock();
6309 hr = wined3d_stateblock_get_light(device->state, light_idx, &light, enabled);
6310 wined3d_mutex_unlock();
6312 return hr_ddraw_from_wined3d(hr);
6315 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6317 return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6320 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6322 HRESULT hr;
6323 WORD old_fpucw;
6325 old_fpucw = d3d_fpu_setup();
6326 hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6327 set_fpu_control_word(old_fpucw);
6329 return hr;
6332 /*****************************************************************************
6333 * IDirect3DDevice7::SetClipPlane
6335 * Sets custom clipping plane
6337 * Version 7
6339 * Params:
6340 * Index: The index of the clipping plane
6341 * PlaneEquation: An equation defining the clipping plane
6343 * Returns:
6344 * D3D_OK on success
6345 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6347 *****************************************************************************/
6348 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6350 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6351 const struct wined3d_vec4 *wined3d_plane;
6352 HRESULT hr;
6354 TRACE("iface %p, idx %lu, plane %p.\n", iface, idx, plane);
6356 if (!plane)
6357 return DDERR_INVALIDPARAMS;
6359 wined3d_plane = (struct wined3d_vec4 *)plane;
6361 wined3d_mutex_lock();
6362 hr = wined3d_stateblock_set_clip_plane(device->update_state, idx, wined3d_plane);
6363 if (idx < ARRAY_SIZE(device->user_clip_planes))
6365 device->user_clip_planes[idx] = *wined3d_plane;
6366 if (hr == WINED3DERR_INVALIDCALL)
6368 WARN("Clip plane %lu is not supported.\n", idx);
6369 hr = D3D_OK;
6372 wined3d_mutex_unlock();
6374 return hr;
6377 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6379 return d3d_device7_SetClipPlane(iface, idx, plane);
6382 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6384 HRESULT hr;
6385 WORD old_fpucw;
6387 old_fpucw = d3d_fpu_setup();
6388 hr = d3d_device7_SetClipPlane(iface, idx, plane);
6389 set_fpu_control_word(old_fpucw);
6391 return hr;
6394 /*****************************************************************************
6395 * IDirect3DDevice7::GetClipPlane
6397 * Returns the clipping plane with a specific index
6399 * Params:
6400 * Index: The index of the desired plane
6401 * PlaneEquation: Address to store the plane equation to
6403 * Returns:
6404 * D3D_OK on success
6405 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6407 *****************************************************************************/
6408 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6410 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6412 TRACE("iface %p, idx %lu, plane %p.\n", iface, idx, plane);
6414 if (!plane)
6415 return DDERR_INVALIDPARAMS;
6417 wined3d_mutex_lock();
6418 if (idx < WINED3D_MAX_CLIP_DISTANCES)
6419 memcpy(plane, &device->stateblock_state->clip_planes[idx], sizeof(struct wined3d_vec4));
6420 else
6422 WARN("Clip plane %lu is not supported.\n", idx);
6423 if (idx < ARRAY_SIZE(device->user_clip_planes))
6424 memcpy(plane, &device->user_clip_planes[idx], sizeof(struct wined3d_vec4));
6426 wined3d_mutex_unlock();
6428 return D3D_OK;
6431 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6433 return d3d_device7_GetClipPlane(iface, idx, plane);
6436 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6438 HRESULT hr;
6439 WORD old_fpucw;
6441 old_fpucw = d3d_fpu_setup();
6442 hr = d3d_device7_GetClipPlane(iface, idx, plane);
6443 set_fpu_control_word(old_fpucw);
6445 return hr;
6448 /*****************************************************************************
6449 * IDirect3DDevice7::GetInfo
6451 * Retrieves some information about the device. The DirectX sdk says that
6452 * this version returns S_FALSE for all retail builds of DirectX, that's what
6453 * this implementation does.
6455 * Params:
6456 * DevInfoID: Information type requested
6457 * DevInfoStruct: Pointer to a structure to store the info to
6458 * Size: Size of the structure
6460 * Returns:
6461 * S_FALSE, because it's a non-debug driver
6463 *****************************************************************************/
6464 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6466 TRACE("iface %p, info_id %#lx, info %p, info_size %lu.\n",
6467 iface, info_id, info, info_size);
6469 if (TRACE_ON(ddraw))
6471 TRACE(" info requested : ");
6472 switch (info_id)
6474 case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6475 case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6476 case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6477 default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6481 return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6484 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6485 * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6486 * are not duplicated.
6488 * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6489 * has already been setup for optimal d3d operation.
6491 * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6492 * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6493 * by Sacrifice (game). */
6494 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6496 /*** IUnknown Methods ***/
6497 d3d_device7_QueryInterface,
6498 d3d_device7_AddRef,
6499 d3d_device7_Release,
6500 /*** IDirect3DDevice7 ***/
6501 d3d_device7_GetCaps_FPUSetup,
6502 d3d_device7_EnumTextureFormats_FPUSetup,
6503 d3d_device7_BeginScene_FPUSetup,
6504 d3d_device7_EndScene_FPUSetup,
6505 d3d_device7_GetDirect3D,
6506 d3d_device7_SetRenderTarget_FPUSetup,
6507 d3d_device7_GetRenderTarget,
6508 d3d_device7_Clear_FPUSetup,
6509 d3d_device7_SetTransform_FPUSetup,
6510 d3d_device7_GetTransform_FPUSetup,
6511 d3d_device7_SetViewport_FPUSetup,
6512 d3d_device7_MultiplyTransform_FPUSetup,
6513 d3d_device7_GetViewport_FPUSetup,
6514 d3d_device7_SetMaterial_FPUSetup,
6515 d3d_device7_GetMaterial_FPUSetup,
6516 d3d_device7_SetLight_FPUSetup,
6517 d3d_device7_GetLight_FPUSetup,
6518 d3d_device7_SetRenderState_FPUSetup,
6519 d3d_device7_GetRenderState_FPUSetup,
6520 d3d_device7_BeginStateBlock_FPUSetup,
6521 d3d_device7_EndStateBlock_FPUSetup,
6522 d3d_device7_PreLoad_FPUSetup,
6523 d3d_device7_DrawPrimitive_FPUSetup,
6524 d3d_device7_DrawIndexedPrimitive_FPUSetup,
6525 d3d_device7_SetClipStatus,
6526 d3d_device7_GetClipStatus,
6527 d3d_device7_DrawPrimitiveStrided_FPUSetup,
6528 d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6529 d3d_device7_DrawPrimitiveVB_FPUSetup,
6530 d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6531 d3d_device7_ComputeSphereVisibility,
6532 d3d_device7_GetTexture_FPUSetup,
6533 d3d_device7_SetTexture_FPUSetup,
6534 d3d_device7_GetTextureStageState_FPUSetup,
6535 d3d_device7_SetTextureStageState_FPUSetup,
6536 d3d_device7_ValidateDevice_FPUSetup,
6537 d3d_device7_ApplyStateBlock_FPUSetup,
6538 d3d_device7_CaptureStateBlock_FPUSetup,
6539 d3d_device7_DeleteStateBlock_FPUSetup,
6540 d3d_device7_CreateStateBlock_FPUSetup,
6541 d3d_device7_Load_FPUSetup,
6542 d3d_device7_LightEnable_FPUSetup,
6543 d3d_device7_GetLightEnable_FPUSetup,
6544 d3d_device7_SetClipPlane_FPUSetup,
6545 d3d_device7_GetClipPlane_FPUSetup,
6546 d3d_device7_GetInfo
6549 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6551 /*** IUnknown Methods ***/
6552 d3d_device7_QueryInterface,
6553 d3d_device7_AddRef,
6554 d3d_device7_Release,
6555 /*** IDirect3DDevice7 ***/
6556 d3d_device7_GetCaps_FPUPreserve,
6557 d3d_device7_EnumTextureFormats_FPUPreserve,
6558 d3d_device7_BeginScene_FPUPreserve,
6559 d3d_device7_EndScene_FPUPreserve,
6560 d3d_device7_GetDirect3D,
6561 d3d_device7_SetRenderTarget_FPUPreserve,
6562 d3d_device7_GetRenderTarget,
6563 d3d_device7_Clear_FPUPreserve,
6564 d3d_device7_SetTransform_FPUPreserve,
6565 d3d_device7_GetTransform_FPUPreserve,
6566 d3d_device7_SetViewport_FPUPreserve,
6567 d3d_device7_MultiplyTransform_FPUPreserve,
6568 d3d_device7_GetViewport_FPUPreserve,
6569 d3d_device7_SetMaterial_FPUPreserve,
6570 d3d_device7_GetMaterial_FPUPreserve,
6571 d3d_device7_SetLight_FPUPreserve,
6572 d3d_device7_GetLight_FPUPreserve,
6573 d3d_device7_SetRenderState_FPUPreserve,
6574 d3d_device7_GetRenderState_FPUPreserve,
6575 d3d_device7_BeginStateBlock_FPUPreserve,
6576 d3d_device7_EndStateBlock_FPUPreserve,
6577 d3d_device7_PreLoad_FPUPreserve,
6578 d3d_device7_DrawPrimitive_FPUPreserve,
6579 d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6580 d3d_device7_SetClipStatus,
6581 d3d_device7_GetClipStatus,
6582 d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6583 d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6584 d3d_device7_DrawPrimitiveVB_FPUPreserve,
6585 d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6586 d3d_device7_ComputeSphereVisibility,
6587 d3d_device7_GetTexture_FPUPreserve,
6588 d3d_device7_SetTexture_FPUPreserve,
6589 d3d_device7_GetTextureStageState_FPUPreserve,
6590 d3d_device7_SetTextureStageState_FPUPreserve,
6591 d3d_device7_ValidateDevice_FPUPreserve,
6592 d3d_device7_ApplyStateBlock_FPUPreserve,
6593 d3d_device7_CaptureStateBlock_FPUPreserve,
6594 d3d_device7_DeleteStateBlock_FPUPreserve,
6595 d3d_device7_CreateStateBlock_FPUPreserve,
6596 d3d_device7_Load_FPUPreserve,
6597 d3d_device7_LightEnable_FPUPreserve,
6598 d3d_device7_GetLightEnable_FPUPreserve,
6599 d3d_device7_SetClipPlane_FPUPreserve,
6600 d3d_device7_GetClipPlane_FPUPreserve,
6601 d3d_device7_GetInfo
6604 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6606 /*** IUnknown Methods ***/
6607 d3d_device3_QueryInterface,
6608 d3d_device3_AddRef,
6609 d3d_device3_Release,
6610 /*** IDirect3DDevice3 ***/
6611 d3d_device3_GetCaps,
6612 d3d_device3_GetStats,
6613 d3d_device3_AddViewport,
6614 d3d_device3_DeleteViewport,
6615 d3d_device3_NextViewport,
6616 d3d_device3_EnumTextureFormats,
6617 d3d_device3_BeginScene,
6618 d3d_device3_EndScene,
6619 d3d_device3_GetDirect3D,
6620 d3d_device3_SetCurrentViewport,
6621 d3d_device3_GetCurrentViewport,
6622 d3d_device3_SetRenderTarget,
6623 d3d_device3_GetRenderTarget,
6624 d3d_device3_Begin,
6625 d3d_device3_BeginIndexed,
6626 d3d_device3_Vertex,
6627 d3d_device3_Index,
6628 d3d_device3_End,
6629 d3d_device3_GetRenderState,
6630 d3d_device3_SetRenderState,
6631 d3d_device3_GetLightState,
6632 d3d_device3_SetLightState,
6633 d3d_device3_SetTransform,
6634 d3d_device3_GetTransform,
6635 d3d_device3_MultiplyTransform,
6636 d3d_device3_DrawPrimitive,
6637 d3d_device3_DrawIndexedPrimitive,
6638 d3d_device3_SetClipStatus,
6639 d3d_device3_GetClipStatus,
6640 d3d_device3_DrawPrimitiveStrided,
6641 d3d_device3_DrawIndexedPrimitiveStrided,
6642 d3d_device3_DrawPrimitiveVB,
6643 d3d_device3_DrawIndexedPrimitiveVB,
6644 d3d_device3_ComputeSphereVisibility,
6645 d3d_device3_GetTexture,
6646 d3d_device3_SetTexture,
6647 d3d_device3_GetTextureStageState,
6648 d3d_device3_SetTextureStageState,
6649 d3d_device3_ValidateDevice
6652 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6654 /*** IUnknown Methods ***/
6655 d3d_device2_QueryInterface,
6656 d3d_device2_AddRef,
6657 d3d_device2_Release,
6658 /*** IDirect3DDevice2 ***/
6659 d3d_device2_GetCaps,
6660 d3d_device2_SwapTextureHandles,
6661 d3d_device2_GetStats,
6662 d3d_device2_AddViewport,
6663 d3d_device2_DeleteViewport,
6664 d3d_device2_NextViewport,
6665 d3d_device2_EnumTextureFormats,
6666 d3d_device2_BeginScene,
6667 d3d_device2_EndScene,
6668 d3d_device2_GetDirect3D,
6669 d3d_device2_SetCurrentViewport,
6670 d3d_device2_GetCurrentViewport,
6671 d3d_device2_SetRenderTarget,
6672 d3d_device2_GetRenderTarget,
6673 d3d_device2_Begin,
6674 d3d_device2_BeginIndexed,
6675 d3d_device2_Vertex,
6676 d3d_device2_Index,
6677 d3d_device2_End,
6678 d3d_device2_GetRenderState,
6679 d3d_device2_SetRenderState,
6680 d3d_device2_GetLightState,
6681 d3d_device2_SetLightState,
6682 d3d_device2_SetTransform,
6683 d3d_device2_GetTransform,
6684 d3d_device2_MultiplyTransform,
6685 d3d_device2_DrawPrimitive,
6686 d3d_device2_DrawIndexedPrimitive,
6687 d3d_device2_SetClipStatus,
6688 d3d_device2_GetClipStatus
6691 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6693 /*** IUnknown Methods ***/
6694 d3d_device1_QueryInterface,
6695 d3d_device1_AddRef,
6696 d3d_device1_Release,
6697 /*** IDirect3DDevice1 ***/
6698 d3d_device1_Initialize,
6699 d3d_device1_GetCaps,
6700 d3d_device1_SwapTextureHandles,
6701 d3d_device1_CreateExecuteBuffer,
6702 d3d_device1_GetStats,
6703 d3d_device1_Execute,
6704 d3d_device1_AddViewport,
6705 d3d_device1_DeleteViewport,
6706 d3d_device1_NextViewport,
6707 d3d_device1_Pick,
6708 d3d_device1_GetPickRecords,
6709 d3d_device1_EnumTextureFormats,
6710 d3d_device1_CreateMatrix,
6711 d3d_device1_SetMatrix,
6712 d3d_device1_GetMatrix,
6713 d3d_device1_DeleteMatrix,
6714 d3d_device1_BeginScene,
6715 d3d_device1_EndScene,
6716 d3d_device1_GetDirect3D
6719 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6721 d3d_device_inner_QueryInterface,
6722 d3d_device_inner_AddRef,
6723 d3d_device_inner_Release,
6726 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6728 if (!iface) return NULL;
6729 assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6730 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6733 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6735 if (!iface) return NULL;
6736 assert(iface->lpVtbl == &d3d_device3_vtbl);
6737 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6740 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6742 if (!iface) return NULL;
6743 assert(iface->lpVtbl == &d3d_device2_vtbl);
6744 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6747 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6749 if (!iface) return NULL;
6750 assert(iface->lpVtbl == &d3d_device1_vtbl);
6751 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6754 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6756 IDirectDrawSurface7 *depthStencil = NULL;
6757 IDirectDrawSurface7 *render_target;
6758 static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, {0} };
6759 struct ddraw_surface *dsi;
6761 if (device->rt_iface && SUCCEEDED(IUnknown_QueryInterface(device->rt_iface,
6762 &IID_IDirectDrawSurface7, (void **)&render_target)))
6764 IDirectDrawSurface7_GetAttachedSurface(render_target, &depthcaps, &depthStencil);
6765 IDirectDrawSurface7_Release(render_target);
6767 if (!depthStencil)
6769 TRACE("Setting wined3d depth stencil to NULL\n");
6770 wined3d_device_context_set_depth_stencil_view(device->immediate_context, NULL);
6771 return WINED3D_ZB_FALSE;
6774 dsi = impl_from_IDirectDrawSurface7(depthStencil);
6775 wined3d_device_context_set_depth_stencil_view(device->immediate_context,
6776 ddraw_surface_get_rendertarget_view(dsi));
6778 IDirectDrawSurface7_Release(depthStencil);
6779 return WINED3D_ZB_TRUE;
6782 static void device_reset_viewport_state(struct d3d_device *device)
6784 struct wined3d_viewport vp;
6785 RECT rect;
6787 wined3d_device_context_get_viewports(device->immediate_context, NULL, &vp);
6788 wined3d_stateblock_set_viewport(device->state, &vp);
6789 wined3d_device_context_get_scissor_rects(device->immediate_context, NULL, &rect);
6790 wined3d_stateblock_set_scissor_rect(device->state, &rect);
6793 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, const GUID *guid,
6794 struct ddraw_surface *target, IUnknown *rt_iface, UINT version, IUnknown *outer_unknown)
6796 static const struct wined3d_matrix ident =
6798 1.0f, 0.0f, 0.0f, 0.0f,
6799 0.0f, 1.0f, 0.0f, 0.0f,
6800 0.0f, 0.0f, 1.0f, 0.0f,
6801 0.0f, 0.0f, 0.0f, 1.0f,
6803 struct wined3d_rendertarget_view *rtv;
6804 HRESULT hr;
6806 if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6807 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6808 else
6809 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6811 device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6812 device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6813 device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6814 device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6815 device->ref = 1;
6816 device->version = version;
6817 device->hardware_device = IsEqualGUID(&IID_IDirect3DTnLHalDevice, guid)
6818 || IsEqualGUID(&IID_IDirect3DHALDevice, guid);
6820 if (device->hardware_device && !(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
6822 WARN("Surface %p is not in video memory.\n", target);
6823 return D3DERR_SURFACENOTINVIDMEM;
6826 if (outer_unknown)
6827 device->outer_unknown = outer_unknown;
6828 else
6829 device->outer_unknown = &device->IUnknown_inner;
6831 device->ddraw = ddraw;
6832 list_init(&device->viewport_list);
6834 if (!ddraw_handle_table_init(&device->handle_table, 64))
6836 ERR("Failed to initialize handle table.\n");
6837 return DDERR_OUTOFMEMORY;
6840 device->legacyTextureBlending = FALSE;
6841 device->legacy_projection = ident;
6842 device->legacy_clipspace = ident;
6844 if (FAILED(hr = wined3d_stateblock_create(ddraw->wined3d_device, NULL, WINED3D_SBT_PRIMARY, &device->state)))
6846 ERR("Failed to create the primary stateblock, hr %#lx.\n", hr);
6847 ddraw_handle_table_destroy(&device->handle_table);
6848 return hr;
6850 device->stateblock_state = wined3d_stateblock_get_state(device->state);
6851 device->update_state = device->state;
6853 /* This is for convenience. */
6854 device->wined3d_device = ddraw->wined3d_device;
6855 device->immediate_context = ddraw->immediate_context;
6856 wined3d_device_incref(ddraw->wined3d_device);
6858 wined3d_streaming_buffer_init(&device->vertex_buffer, WINED3D_BIND_VERTEX_BUFFER);
6859 wined3d_streaming_buffer_init(&device->index_buffer, WINED3D_BIND_INDEX_BUFFER);
6861 /* Render to the back buffer */
6862 rtv = ddraw_surface_get_rendertarget_view(target);
6863 if (FAILED(hr = wined3d_device_context_set_rendertarget_views(device->immediate_context, 0, 1, &rtv, TRUE)))
6865 ERR("Failed to set render target, hr %#lx.\n", hr);
6866 wined3d_stateblock_decref(device->state);
6867 ddraw_handle_table_destroy(&device->handle_table);
6868 return hr;
6871 device->rt_iface = rt_iface;
6872 if (version != 1)
6873 IUnknown_AddRef(device->rt_iface);
6875 ddraw->d3ddevice = device;
6877 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_ZENABLE,
6878 d3d_device_update_depth_stencil(device));
6879 if (version == 1) /* Color keying is initially enabled for version 1 devices. */
6880 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_COLORKEYENABLE, TRUE);
6881 else if (version == 2)
6882 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_SPECULARENABLE, TRUE);
6883 if (version < 7)
6885 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_NORMALIZENORMALS, TRUE);
6886 IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface,
6887 D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
6889 device_reset_viewport_state(device);
6890 return D3D_OK;
6893 HRESULT d3d_device_create(struct ddraw *ddraw, const GUID *guid, struct ddraw_surface *target, IUnknown *rt_iface,
6894 UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6896 struct d3d_device *object;
6897 HRESULT hr;
6899 TRACE("ddraw %p, guid %s, target %p, version %u, device %p, outer_unknown %p.\n",
6900 ddraw, debugstr_guid(guid), target, version, device, outer_unknown);
6902 if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
6903 || (target->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
6905 WARN("Surface %p is not a render target.\n", target);
6906 return DDERR_INVALIDCAPS;
6909 if (!validate_surface_palette(target))
6911 WARN("Surface %p has an indexed pixel format, but no palette.\n", target);
6912 return DDERR_NOPALETTEATTACHED;
6915 if (ddraw->flags & DDRAW_NO3D)
6917 ERR_(winediag)("The application wants to create a Direct3D device, "
6918 "but the current DirectDrawRenderer does not support this.\n");
6920 return DDERR_OUTOFMEMORY;
6923 if (ddraw->d3ddevice)
6925 FIXME("Only one Direct3D device per DirectDraw object supported.\n");
6926 return DDERR_INVALIDPARAMS;
6929 if (!(object = calloc(1, sizeof(*object))))
6931 ERR("Failed to allocate device memory.\n");
6932 return DDERR_OUTOFMEMORY;
6935 if (FAILED(hr = d3d_device_init(object, ddraw, guid, target, rt_iface, version, outer_unknown)))
6937 WARN("Failed to initialize device, hr %#lx.\n", hr);
6938 free(object);
6939 return hr;
6942 TRACE("Created device %p.\n", object);
6943 *device = object;
6945 return D3D_OK;