version/tests: Enable compilation with long types.
[wine.git] / dlls / ddraw / device.c
blob860dffc504508de9735a7c46cbc13b113dfa104c
1 /*
2 * Copyright (c) 1998-2004 Lionel Ulmer
3 * Copyright (c) 2002-2005 Christian Costa
4 * Copyright (c) 2006-2009, 2011-2013 Stefan Dösinger
5 * Copyright (c) 2008 Alexander Dorofeyev
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * IDirect3DDevice implementation, version 1, 2, 3 and 7. Rendering is relayed
22 * to WineD3D, some minimal DirectDraw specific management is handled here.
23 * The Direct3DDevice is NOT the parent of the WineD3DDevice, because d3d
24 * is initialized when DirectDraw creates the primary surface.
25 * Some type management is necessary, because some D3D types changed between
26 * D3D7 and D3D9.
30 #include "ddraw_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
33 WINE_DECLARE_DEBUG_CHANNEL(winediag);
35 /* The device ID */
36 const GUID IID_D3DDEVICE_WineD3D = {
37 0xaef72d43,
38 0xb09a,
39 0x4b7b,
40 { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
43 static inline void set_fpu_control_word(WORD fpucw)
45 #if defined(__i386__) && defined(__GNUC__)
46 __asm__ volatile ("fldcw %0" : : "m" (fpucw));
47 #elif defined(__i386__) && defined(_MSC_VER)
48 __asm fldcw fpucw;
49 #endif
52 static inline WORD d3d_fpu_setup(void)
54 WORD oldcw;
56 #if defined(__i386__) && defined(__GNUC__)
57 __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
58 #elif defined(__i386__) && defined(_MSC_VER)
59 __asm fnstcw oldcw;
60 #else
61 static BOOL warned = FALSE;
62 if(!warned)
64 FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
65 warned = TRUE;
67 return 0;
68 #endif
70 set_fpu_control_word(0x37f);
72 return oldcw;
75 static enum wined3d_render_state wined3d_render_state_from_ddraw(D3DRENDERSTATETYPE state)
77 switch (state)
79 case D3DRENDERSTATE_ZBIAS:
80 return WINED3D_RS_DEPTHBIAS;
81 case D3DRENDERSTATE_EDGEANTIALIAS:
82 return WINED3D_RS_ANTIALIASEDLINEENABLE;
83 default:
84 return (enum wined3d_render_state)state;
88 static enum wined3d_transform_state wined3d_transform_state_from_ddraw(D3DTRANSFORMSTATETYPE state)
90 switch (state)
92 case D3DTRANSFORMSTATE_WORLD:
93 return WINED3D_TS_WORLD_MATRIX(0);
94 case D3DTRANSFORMSTATE_WORLD1:
95 return WINED3D_TS_WORLD_MATRIX(1);
96 case D3DTRANSFORMSTATE_WORLD2:
97 return WINED3D_TS_WORLD_MATRIX(2);
98 case D3DTRANSFORMSTATE_WORLD3:
99 return WINED3D_TS_WORLD_MATRIX(3);
100 default:
101 return (enum wined3d_transform_state)state;
105 static enum wined3d_primitive_type wined3d_primitive_type_from_ddraw(D3DPRIMITIVETYPE type)
107 return (enum wined3d_primitive_type)type;
110 static enum wined3d_stateblock_type wined3d_stateblock_type_from_ddraw(D3DSTATEBLOCKTYPE type)
112 return (enum wined3d_stateblock_type)type;
115 static inline struct d3d_device *impl_from_IUnknown(IUnknown *iface)
117 return CONTAINING_RECORD(iface, struct d3d_device, IUnknown_inner);
120 static HRESULT WINAPI d3d_device_inner_QueryInterface(IUnknown *iface, REFIID riid, void **out)
122 struct d3d_device *device = impl_from_IUnknown(iface);
124 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
126 if (!riid)
128 *out = NULL;
129 return DDERR_INVALIDPARAMS;
132 if (IsEqualGUID(&IID_IUnknown, riid))
134 IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
135 *out = &device->IDirect3DDevice7_iface;
136 return S_OK;
139 if (device->version == 7)
141 if (IsEqualGUID(&IID_IDirect3DDevice7, riid))
143 IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
144 *out = &device->IDirect3DDevice7_iface;
145 return S_OK;
148 else
150 if (IsEqualGUID(&IID_IDirect3DDevice3, riid) && device->version == 3)
152 IDirect3DDevice3_AddRef(&device->IDirect3DDevice3_iface);
153 *out = &device->IDirect3DDevice3_iface;
154 return S_OK;
157 if (IsEqualGUID(&IID_IDirect3DDevice2, riid) && device->version >= 2)
159 IDirect3DDevice2_AddRef(&device->IDirect3DDevice2_iface);
160 *out = &device->IDirect3DDevice2_iface;
161 return S_OK;
164 if (IsEqualGUID(&IID_IDirect3DDevice, riid))
166 IDirect3DDevice_AddRef(&device->IDirect3DDevice_iface);
167 *out = &device->IDirect3DDevice_iface;
168 return S_OK;
172 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
174 *out = NULL;
175 return E_NOINTERFACE;
178 static HRESULT WINAPI d3d_device7_QueryInterface(IDirect3DDevice7 *iface, REFIID riid, void **out)
180 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
182 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
184 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
187 static HRESULT WINAPI d3d_device3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid, void **out)
189 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
191 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
193 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
196 static HRESULT WINAPI d3d_device2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid, void **out)
198 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
200 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
202 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
205 static HRESULT WINAPI d3d_device1_QueryInterface(IDirect3DDevice *iface, REFIID riid, void **out)
207 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
209 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
211 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
214 static ULONG WINAPI d3d_device_inner_AddRef(IUnknown *iface)
216 struct d3d_device *device = impl_from_IUnknown(iface);
217 ULONG ref = InterlockedIncrement(&device->ref);
219 TRACE("%p increasing refcount to %u.\n", device, ref);
221 return ref;
224 static ULONG WINAPI d3d_device7_AddRef(IDirect3DDevice7 *iface)
226 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
228 TRACE("iface %p.\n", iface);
230 return IUnknown_AddRef(device->outer_unknown);
233 static ULONG WINAPI d3d_device3_AddRef(IDirect3DDevice3 *iface)
235 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
237 TRACE("iface %p.\n", iface);
239 return IUnknown_AddRef(device->outer_unknown);
242 static ULONG WINAPI d3d_device2_AddRef(IDirect3DDevice2 *iface)
244 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
246 TRACE("iface %p.\n", iface);
248 return IUnknown_AddRef(device->outer_unknown);
251 static ULONG WINAPI d3d_device1_AddRef(IDirect3DDevice *iface)
253 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
255 TRACE("iface %p.\n", iface);
257 return IUnknown_AddRef(device->outer_unknown);
260 static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
262 struct d3d_device *This = impl_from_IUnknown(iface);
263 ULONG ref = InterlockedDecrement(&This->ref);
264 IUnknown *rt_iface;
266 TRACE("%p decreasing refcount to %u.\n", This, ref);
268 /* This method doesn't destroy the wined3d device, because it's still in
269 * use for 2D rendering. IDirectDrawSurface7::Release will destroy the
270 * wined3d device when the render target is released. */
271 if (!ref)
273 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 if (This->index_buffer)
283 wined3d_buffer_decref(This->index_buffer);
284 if (This->vertex_buffer)
285 wined3d_buffer_decref(This->vertex_buffer);
287 wined3d_device_context_set_rendertarget_views(This->immediate_context, 0, 1, &null_rtv, FALSE);
289 wined3d_stateblock_decref(This->state);
290 if (This->recording)
291 wined3d_stateblock_decref(This->recording);
293 /* Release the wined3d device. This won't destroy it. */
294 if (!wined3d_device_decref(This->wined3d_device))
295 ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
297 /* The texture handles should be unset by now, but there might be some bits
298 * missing in our reference counting(needs test). Do a sanity check. */
299 for (i = 0; i < This->handle_table.entry_count; ++i)
301 struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
303 switch (entry->type)
305 case DDRAW_HANDLE_FREE:
306 break;
308 case DDRAW_HANDLE_MATERIAL:
310 struct d3d_material *m = entry->object;
311 FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
312 m->Handle = 0;
313 break;
316 case DDRAW_HANDLE_MATRIX:
318 /* No FIXME here because this might happen because of sloppy applications. */
319 WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
320 IDirect3DDevice_DeleteMatrix(&This->IDirect3DDevice_iface, i + 1);
321 break;
324 case DDRAW_HANDLE_STATEBLOCK:
326 /* No FIXME here because this might happen because of sloppy applications. */
327 WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
328 IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
329 break;
332 case DDRAW_HANDLE_SURFACE:
334 struct ddraw_surface *surf = entry->object;
335 FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
336 surf->Handle = 0;
337 break;
340 default:
341 FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
342 break;
346 ddraw_handle_table_destroy(&This->handle_table);
348 LIST_FOR_EACH_SAFE(vp_entry, vp_entry2, &This->viewport_list)
350 struct d3d_viewport *vp = LIST_ENTRY(vp_entry, struct d3d_viewport, entry);
351 IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
354 TRACE("Releasing render target %p.\n", This->rt_iface);
355 rt_iface = This->rt_iface;
356 This->rt_iface = NULL;
357 if (This->version != 1)
358 IUnknown_Release(rt_iface);
359 TRACE("Render target release done.\n");
361 /* Releasing the render target above may have released the last
362 * reference to the ddraw object. */
363 if (This->ddraw)
364 This->ddraw->d3ddevice = NULL;
366 /* Now free the structure */
367 heap_free(This);
368 wined3d_mutex_unlock();
371 TRACE("Done\n");
372 return ref;
375 static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
377 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
379 TRACE("iface %p.\n", iface);
381 return IUnknown_Release(device->outer_unknown);
384 static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
386 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
388 TRACE("iface %p.\n", iface);
390 return IUnknown_Release(device->outer_unknown);
393 static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
395 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
397 TRACE("iface %p.\n", iface);
399 return IUnknown_Release(device->outer_unknown);
402 static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
404 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
406 TRACE("iface %p.\n", iface);
408 return IUnknown_Release(device->outer_unknown);
411 /*****************************************************************************
412 * IDirect3DDevice Methods
413 *****************************************************************************/
415 /*****************************************************************************
416 * IDirect3DDevice::Initialize
418 * Initializes a Direct3DDevice. This implementation is a no-op, as all
419 * initialization is done at create time.
421 * Exists in Version 1
423 * Parameters:
424 * No idea what they mean, as the MSDN page is gone
426 * Returns: DD_OK
428 *****************************************************************************/
429 static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
430 IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
432 /* It shouldn't be crucial, but print a FIXME, I'm interested if
433 * any game calls it and when. */
434 FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
435 iface, d3d, debugstr_guid(guid), device_desc);
437 return D3D_OK;
440 static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *device_desc)
442 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
444 TRACE("iface %p, device_desc %p.\n", iface, device_desc);
446 if (!device_desc)
448 WARN("device_desc is NULL, returning DDERR_INVALIDPARAMS.\n");
449 return DDERR_INVALIDPARAMS;
452 /* Call the same function used by IDirect3D, this saves code */
453 return ddraw_get_d3dcaps(device->ddraw, device_desc);
456 static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
458 return d3d_device7_GetCaps(iface, desc);
461 static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
463 HRESULT hr;
464 WORD old_fpucw;
466 old_fpucw = d3d_fpu_setup();
467 hr = d3d_device7_GetCaps(iface, desc);
468 set_fpu_control_word(old_fpucw);
470 return hr;
472 /*****************************************************************************
473 * IDirect3DDevice3::GetCaps
475 * Retrieves the capabilities of the hardware device and the emulation
476 * device. For Wine, hardware and emulation are the same (it's all HW).
478 * This implementation is used for Version 1, 2, and 3. Version 7 has its own
480 * Parameters:
481 * HWDesc: Structure to fill with the HW caps
482 * HelDesc: Structure to fill with the hardware emulation caps
484 * Returns:
485 * D3D_OK on success
486 * D3DERR_* if a problem occurs. See WineD3D
488 *****************************************************************************/
490 /* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
491 * Microsoft just expanded the existing structure without naming them
492 * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
493 * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
494 * one with 252 bytes.
496 * All 3 versions are allowed as parameters and only the specified amount of
497 * bytes is written.
499 * Note that Direct3D7 and earlier are not available in native Win64
500 * ddraw.dll builds, so possible size differences between 32 bit and
501 * 64 bit are a non-issue.
503 static inline BOOL check_d3ddevicedesc_size(DWORD size)
505 if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
506 || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
507 || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
508 return FALSE;
511 static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
512 D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
514 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
515 D3DDEVICEDESC7 desc7;
516 D3DDEVICEDESC desc1;
517 HRESULT hr;
519 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
521 if (!HWDesc)
523 WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
524 return DDERR_INVALIDPARAMS;
526 if (!check_d3ddevicedesc_size(HWDesc->dwSize))
528 WARN("HWDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
529 return DDERR_INVALIDPARAMS;
531 if (!HelDesc)
533 WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
534 return DDERR_INVALIDPARAMS;
536 if (!check_d3ddevicedesc_size(HelDesc->dwSize))
538 WARN("HelDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
539 return DDERR_INVALIDPARAMS;
542 if (FAILED(hr = ddraw_get_d3dcaps(device->ddraw, &desc7)))
543 return hr;
545 ddraw_d3dcaps1_from_7(&desc1, &desc7);
546 DD_STRUCT_COPY_BYSIZE(HWDesc, &desc1);
547 DD_STRUCT_COPY_BYSIZE(HelDesc, &desc1);
548 return D3D_OK;
551 static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
552 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
554 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
556 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
558 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
561 static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
562 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
564 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
566 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
568 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
571 /*****************************************************************************
572 * IDirect3DDevice2::SwapTextureHandles
574 * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
576 * Parameters:
577 * Tex1, Tex2: The 2 Textures to swap
579 * Returns:
580 * D3D_OK
582 *****************************************************************************/
583 static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
584 IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
586 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
587 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
588 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
589 DWORD h1, h2;
591 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
593 wined3d_mutex_lock();
595 h1 = surf1->Handle - 1;
596 h2 = surf2->Handle - 1;
597 device->handle_table.entries[h1].object = surf2;
598 device->handle_table.entries[h2].object = surf1;
599 surf2->Handle = h1 + 1;
600 surf1->Handle = h2 + 1;
602 wined3d_mutex_unlock();
604 return D3D_OK;
607 static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
608 IDirect3DTexture *tex1, IDirect3DTexture *tex2)
610 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
611 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
612 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
613 IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
614 IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
616 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
618 return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
621 /*****************************************************************************
622 * IDirect3DDevice3::GetStats
624 * This method seems to retrieve some stats from the device.
625 * The MSDN documentation doesn't exist any more, but the D3DSTATS
626 * structure suggests that the amount of drawn primitives and processed
627 * vertices is returned.
629 * Exists in Version 1, 2 and 3
631 * Parameters:
632 * Stats: Pointer to a D3DSTATS structure to be filled
634 * Returns:
635 * D3D_OK on success
636 * DDERR_INVALIDPARAMS if Stats == NULL
638 *****************************************************************************/
639 static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
641 FIXME("iface %p, stats %p stub!\n", iface, Stats);
643 if(!Stats)
644 return DDERR_INVALIDPARAMS;
646 /* Fill the Stats with 0 */
647 Stats->dwTrianglesDrawn = 0;
648 Stats->dwLinesDrawn = 0;
649 Stats->dwPointsDrawn = 0;
650 Stats->dwSpansDrawn = 0;
651 Stats->dwVerticesProcessed = 0;
653 return D3D_OK;
656 static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
658 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
660 TRACE("iface %p, stats %p.\n", iface, stats);
662 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
665 static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
667 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
669 TRACE("iface %p, stats %p.\n", iface, stats);
671 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
674 /*****************************************************************************
675 * IDirect3DDevice::CreateExecuteBuffer
677 * Creates an IDirect3DExecuteBuffer, used for rendering with a
678 * Direct3DDevice.
680 * Version 1 only.
682 * Params:
683 * Desc: Buffer description
684 * ExecuteBuffer: Address to return the Interface pointer at
685 * UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
686 * support
688 * Returns:
689 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
690 * DDERR_OUTOFMEMORY if we ran out of memory
691 * D3D_OK on success
693 *****************************************************************************/
694 static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
695 D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
697 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
698 struct d3d_execute_buffer *object;
699 HRESULT hr;
701 TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
702 iface, buffer_desc, ExecuteBuffer, outer_unknown);
704 if (outer_unknown)
705 return CLASS_E_NOAGGREGATION;
707 /* Allocate the new Execute Buffer */
708 if (!(object = heap_alloc_zero(sizeof(*object))))
710 ERR("Failed to allocate execute buffer memory.\n");
711 return DDERR_OUTOFMEMORY;
714 hr = d3d_execute_buffer_init(object, device, buffer_desc);
715 if (FAILED(hr))
717 WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
718 heap_free(object);
719 return hr;
722 *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
724 TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
726 return D3D_OK;
729 /*****************************************************************************
730 * IDirect3DDevice::Execute
732 * Executes all the stuff in an execute buffer.
734 * Params:
735 * ExecuteBuffer: The buffer to execute
736 * Viewport: The viewport used for rendering
737 * Flags: Some flags
739 * Returns:
740 * DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
741 * D3D_OK on success
743 *****************************************************************************/
744 static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
745 IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
747 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
748 struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
749 struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
750 HRESULT hr;
752 TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, viewport, flags);
754 if(!buffer)
755 return DDERR_INVALIDPARAMS;
757 if (FAILED(hr = IDirect3DDevice3_SetCurrentViewport
758 (&device->IDirect3DDevice3_iface, &viewport_impl->IDirect3DViewport3_iface)))
759 return hr;
761 /* Execute... */
762 wined3d_mutex_lock();
763 hr = d3d_execute_buffer_execute(buffer, device);
764 wined3d_mutex_unlock();
766 return hr;
769 /*****************************************************************************
770 * IDirect3DDevice3::AddViewport
772 * Add a Direct3DViewport to the device's viewport list. These viewports
773 * are wrapped to IDirect3DDevice7 viewports in viewport.c
775 * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
776 * are the same interfaces.
778 * Params:
779 * Viewport: The viewport to add
781 * Returns:
782 * DDERR_INVALIDPARAMS if Viewport == NULL
783 * D3D_OK on success
785 *****************************************************************************/
786 static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
788 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
789 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
791 TRACE("iface %p, viewport %p.\n", iface, viewport);
793 /* Sanity check */
794 if(!vp)
795 return DDERR_INVALIDPARAMS;
797 wined3d_mutex_lock();
798 IDirect3DViewport3_AddRef(viewport);
799 list_add_head(&device->viewport_list, &vp->entry);
800 /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
801 vp->active_device = device;
802 wined3d_mutex_unlock();
804 return D3D_OK;
807 static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
808 IDirect3DViewport2 *viewport)
810 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
811 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
813 TRACE("iface %p, viewport %p.\n", iface, viewport);
815 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
818 static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
820 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
821 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
823 TRACE("iface %p, viewport %p.\n", iface, viewport);
825 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
828 /*****************************************************************************
829 * IDirect3DDevice3::DeleteViewport
831 * Deletes a Direct3DViewport from the device's viewport list.
833 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
834 * are equal.
836 * Params:
837 * Viewport: The viewport to delete
839 * Returns:
840 * D3D_OK on success
841 * DDERR_INVALIDPARAMS if the viewport wasn't found in the list
843 *****************************************************************************/
844 static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
846 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
847 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
849 TRACE("iface %p, viewport %p.\n", iface, viewport);
851 if (!vp)
853 WARN("NULL viewport, returning DDERR_INVALIDPARAMS\n");
854 return DDERR_INVALIDPARAMS;
857 wined3d_mutex_lock();
859 if (vp->active_device != device)
861 WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
862 wined3d_mutex_unlock();
863 return DDERR_INVALIDPARAMS;
866 if (device->current_viewport == vp)
868 TRACE("Deleting current viewport, unsetting and releasing.\n");
870 viewport_deactivate(vp);
871 IDirect3DViewport3_Release(viewport);
872 device->current_viewport = NULL;
875 vp->active_device = NULL;
876 list_remove(&vp->entry);
878 IDirect3DViewport3_Release(viewport);
880 wined3d_mutex_unlock();
882 return D3D_OK;
885 static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
887 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
888 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
890 TRACE("iface %p, viewport %p.\n", iface, viewport);
892 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
893 vp ? &vp->IDirect3DViewport3_iface : NULL);
896 static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
898 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
899 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
901 TRACE("iface %p, viewport %p.\n", iface, viewport);
903 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
904 vp ? &vp->IDirect3DViewport3_iface : NULL);
907 /*****************************************************************************
908 * IDirect3DDevice3::NextViewport
910 * Returns a viewport from the viewport list, depending on the
911 * passed viewport and the flags.
913 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
914 * are equal.
916 * Params:
917 * Viewport: Viewport to use for beginning the search
918 * Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
920 * Returns:
921 * D3D_OK on success
922 * DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
924 *****************************************************************************/
925 static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
926 IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
928 struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
929 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
930 struct d3d_viewport *next;
931 struct list *entry;
933 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
934 iface, Viewport3, lplpDirect3DViewport3, flags);
936 if(!vp)
938 *lplpDirect3DViewport3 = NULL;
939 return DDERR_INVALIDPARAMS;
943 wined3d_mutex_lock();
944 switch (flags)
946 case D3DNEXT_NEXT:
947 entry = list_next(&This->viewport_list, &vp->entry);
948 break;
950 case D3DNEXT_HEAD:
951 entry = list_head(&This->viewport_list);
952 break;
954 case D3DNEXT_TAIL:
955 entry = list_tail(&This->viewport_list);
956 break;
958 default:
959 WARN("Invalid flags %#x.\n", flags);
960 *lplpDirect3DViewport3 = NULL;
961 wined3d_mutex_unlock();
962 return DDERR_INVALIDPARAMS;
965 if (entry)
967 next = LIST_ENTRY(entry, struct d3d_viewport, entry);
968 *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
970 else
971 *lplpDirect3DViewport3 = NULL;
973 wined3d_mutex_unlock();
975 return D3D_OK;
978 static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
979 IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
981 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
982 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
983 IDirect3DViewport3 *res;
984 HRESULT hr;
986 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
987 iface, viewport, next, flags);
989 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
990 &vp->IDirect3DViewport3_iface, &res, flags);
991 *next = (IDirect3DViewport2 *)res;
992 return hr;
995 static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
996 IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
998 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
999 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
1000 IDirect3DViewport3 *res;
1001 HRESULT hr;
1003 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
1004 iface, viewport, next, flags);
1006 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
1007 &vp->IDirect3DViewport3_iface, &res, flags);
1008 *next = (IDirect3DViewport *)res;
1009 return hr;
1012 /*****************************************************************************
1013 * IDirect3DDevice::Pick
1015 * Executes an execute buffer without performing rendering. Instead, a
1016 * list of primitives that intersect with (x1,y1) of the passed rectangle
1017 * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
1018 * this list.
1020 * Version 1 only
1022 * Params:
1023 * ExecuteBuffer: Buffer to execute
1024 * Viewport: Viewport to use for execution
1025 * Flags: None are defined, according to the SDK
1026 * Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
1027 * x2 and y2 are ignored.
1029 * Returns:
1030 * D3D_OK because it's a stub
1032 *****************************************************************************/
1033 static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
1034 IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
1036 FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
1037 iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
1039 return D3D_OK;
1042 /*****************************************************************************
1043 * IDirect3DDevice::GetPickRecords
1045 * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
1047 * Version 1 only
1049 * Params:
1050 * Count: Pointer to a DWORD containing the numbers of pick records to
1051 * retrieve
1052 * D3DPickRec: Address to store the resulting D3DPICKRECORD array.
1054 * Returns:
1055 * D3D_OK, because it's a stub
1057 *****************************************************************************/
1058 static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
1059 DWORD *count, D3DPICKRECORD *records)
1061 FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1063 return D3D_OK;
1066 /*****************************************************************************
1067 * IDirect3DDevice7::EnumTextureformats
1069 * Enumerates the supported texture formats. It checks against a list of all possible
1070 * formats to see if WineD3D supports it. If so, then it is passed to the app.
1072 * This is for Version 7 and 3, older versions have a different
1073 * callback function and their own implementation
1075 * Params:
1076 * Callback: Callback to call for each enumerated format
1077 * Arg: Argument to pass to the callback
1079 * Returns:
1080 * D3D_OK on success
1081 * DDERR_INVALIDPARAMS if Callback == NULL
1083 *****************************************************************************/
1084 static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
1085 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1087 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1088 struct wined3d_display_mode mode;
1089 HRESULT hr;
1090 unsigned int i;
1092 static const enum wined3d_format_id FormatList[] =
1094 /* 16 bit */
1095 WINED3DFMT_B5G5R5X1_UNORM,
1096 WINED3DFMT_B5G5R5A1_UNORM,
1097 WINED3DFMT_B4G4R4A4_UNORM,
1098 WINED3DFMT_B5G6R5_UNORM,
1099 /* 32 bit */
1100 WINED3DFMT_B8G8R8X8_UNORM,
1101 WINED3DFMT_B8G8R8A8_UNORM,
1102 /* 8 bit */
1103 WINED3DFMT_B2G3R3_UNORM,
1104 WINED3DFMT_P8_UINT,
1105 /* FOURCC codes */
1106 WINED3DFMT_DXT1,
1107 WINED3DFMT_DXT2,
1108 WINED3DFMT_DXT3,
1109 WINED3DFMT_DXT4,
1110 WINED3DFMT_DXT5,
1113 static const enum wined3d_format_id BumpFormatList[] =
1115 WINED3DFMT_R8G8_SNORM,
1116 WINED3DFMT_R5G5_SNORM_L6_UNORM,
1117 WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1118 WINED3DFMT_R10G11B11_SNORM,
1119 WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1122 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1124 if (!callback)
1125 return DDERR_INVALIDPARAMS;
1127 wined3d_mutex_lock();
1129 memset(&mode, 0, sizeof(mode));
1130 if (FAILED(hr = wined3d_output_get_display_mode(device->ddraw->wined3d_output, &mode, NULL)))
1132 wined3d_mutex_unlock();
1133 WARN("Failed to get output display mode, hr %#x.\n", hr);
1134 return hr;
1137 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1139 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1140 WINED3D_DEVICE_TYPE_HAL, mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE,
1141 WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1143 DDPIXELFORMAT pformat;
1145 memset(&pformat, 0, sizeof(pformat));
1146 pformat.dwSize = sizeof(pformat);
1147 ddrawformat_from_wined3dformat(&pformat, FormatList[i]);
1149 TRACE("Enumerating WineD3DFormat %d\n", FormatList[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;
1160 for (i = 0; i < ARRAY_SIZE(BumpFormatList); ++i)
1162 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1163 WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1164 WINED3D_BIND_SHADER_RESOURCE, WINED3D_RTYPE_TEXTURE_2D, BumpFormatList[i]) == D3D_OK)
1166 DDPIXELFORMAT pformat;
1168 memset(&pformat, 0, sizeof(pformat));
1169 pformat.dwSize = sizeof(pformat);
1170 ddrawformat_from_wined3dformat(&pformat, BumpFormatList[i]);
1172 TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1173 hr = callback(&pformat, context);
1174 if(hr != DDENUMRET_OK)
1176 TRACE("Format enumeration cancelled by application\n");
1177 wined3d_mutex_unlock();
1178 return D3D_OK;
1182 TRACE("End of enumeration\n");
1183 wined3d_mutex_unlock();
1185 return D3D_OK;
1188 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1189 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1191 return d3d_device7_EnumTextureFormats(iface, callback, context);
1194 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1195 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1197 HRESULT hr;
1198 WORD old_fpucw;
1200 old_fpucw = d3d_fpu_setup();
1201 hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1202 set_fpu_control_word(old_fpucw);
1204 return hr;
1207 static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
1208 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1210 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1212 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1214 return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1217 /*****************************************************************************
1218 * IDirect3DDevice2::EnumTextureformats
1220 * EnumTextureFormats for Version 1 and 2, see
1221 * IDirect3DDevice7::EnumTextureFormats for a more detailed description.
1223 * This version has a different callback and does not enumerate FourCC
1224 * formats
1226 *****************************************************************************/
1227 static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
1228 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1230 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1231 struct wined3d_display_mode mode;
1232 HRESULT hr;
1233 unsigned int i;
1235 static const enum wined3d_format_id FormatList[] =
1237 /* 16 bit */
1238 WINED3DFMT_B5G5R5X1_UNORM,
1239 WINED3DFMT_B5G5R5A1_UNORM,
1240 WINED3DFMT_B4G4R4A4_UNORM,
1241 WINED3DFMT_B5G6R5_UNORM,
1242 /* 32 bit */
1243 WINED3DFMT_B8G8R8X8_UNORM,
1244 WINED3DFMT_B8G8R8A8_UNORM,
1245 /* 8 bit */
1246 WINED3DFMT_B2G3R3_UNORM,
1247 WINED3DFMT_P8_UINT,
1248 /* FOURCC codes - Not in this version*/
1251 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1253 if (!callback)
1254 return DDERR_INVALIDPARAMS;
1256 wined3d_mutex_lock();
1258 memset(&mode, 0, sizeof(mode));
1259 if (FAILED(hr = wined3d_output_get_display_mode(device->ddraw->wined3d_output, &mode, NULL)))
1261 wined3d_mutex_unlock();
1262 WARN("Failed to get output display mode, hr %#x.\n", hr);
1263 return hr;
1266 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1268 if (wined3d_check_device_format(device->ddraw->wined3d, device->ddraw->wined3d_adapter,
1269 WINED3D_DEVICE_TYPE_HAL, mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE,
1270 WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1272 DDSURFACEDESC sdesc;
1274 memset(&sdesc, 0, sizeof(sdesc));
1275 sdesc.dwSize = sizeof(sdesc);
1276 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1277 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1278 sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1279 ddrawformat_from_wined3dformat(&sdesc.ddpfPixelFormat, FormatList[i]);
1281 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1282 hr = callback(&sdesc, context);
1283 if(hr != DDENUMRET_OK)
1285 TRACE("Format enumeration cancelled by application\n");
1286 wined3d_mutex_unlock();
1287 return D3D_OK;
1291 TRACE("End of enumeration\n");
1292 wined3d_mutex_unlock();
1294 return D3D_OK;
1297 static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
1298 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1300 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1302 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1304 return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1307 /*****************************************************************************
1308 * IDirect3DDevice::CreateMatrix
1310 * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1311 * allocated for the handle.
1313 * Version 1 only
1315 * Params
1316 * D3DMatHandle: Address to return the handle at
1318 * Returns:
1319 * D3D_OK on success
1320 * DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1322 *****************************************************************************/
1323 static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1325 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1326 D3DMATRIX *matrix;
1327 DWORD h;
1329 TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1331 if(!D3DMatHandle)
1332 return DDERR_INVALIDPARAMS;
1334 if (!(matrix = heap_alloc_zero(sizeof(*matrix))))
1336 ERR("Out of memory when allocating a D3DMATRIX\n");
1337 return DDERR_OUTOFMEMORY;
1340 wined3d_mutex_lock();
1342 h = ddraw_allocate_handle(&device->handle_table, matrix, DDRAW_HANDLE_MATRIX);
1343 if (h == DDRAW_INVALID_HANDLE)
1345 ERR("Failed to allocate a matrix handle.\n");
1346 heap_free(matrix);
1347 wined3d_mutex_unlock();
1348 return DDERR_OUTOFMEMORY;
1351 *D3DMatHandle = h + 1;
1353 TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1355 wined3d_mutex_unlock();
1357 return D3D_OK;
1360 /*****************************************************************************
1361 * IDirect3DDevice::SetMatrix
1363 * Sets a matrix for a matrix handle. The matrix is copied into the memory
1364 * allocated for the handle
1366 * Version 1 only
1368 * Params:
1369 * D3DMatHandle: Handle to set the matrix to
1370 * D3DMatrix: Matrix to set
1372 * Returns:
1373 * D3D_OK on success
1374 * DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1375 * to set is NULL
1377 *****************************************************************************/
1378 static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
1379 D3DMATRIXHANDLE matrix_handle, D3DMATRIX *matrix)
1381 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1382 D3DMATRIX *m;
1384 TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, matrix_handle, matrix);
1386 if (!matrix)
1387 return DDERR_INVALIDPARAMS;
1389 wined3d_mutex_lock();
1391 m = ddraw_get_object(&device->handle_table, matrix_handle - 1, DDRAW_HANDLE_MATRIX);
1392 if (!m)
1394 WARN("Invalid matrix handle.\n");
1395 wined3d_mutex_unlock();
1396 return DDERR_INVALIDPARAMS;
1399 if (TRACE_ON(ddraw))
1400 dump_D3DMATRIX(matrix);
1402 *m = *matrix;
1404 if (matrix_handle == device->world)
1405 wined3d_stateblock_set_transform(device->state,
1406 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)matrix);
1408 if (matrix_handle == device->view)
1409 wined3d_stateblock_set_transform(device->state,
1410 WINED3D_TS_VIEW, (struct wined3d_matrix *)matrix);
1412 if (matrix_handle == device->proj)
1413 wined3d_stateblock_set_transform(device->state,
1414 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)matrix);
1416 wined3d_mutex_unlock();
1418 return D3D_OK;
1421 /*****************************************************************************
1422 * IDirect3DDevice::GetMatrix
1424 * Returns the content of a D3DMATRIX handle
1426 * Version 1 only
1428 * Params:
1429 * D3DMatHandle: Matrix handle to read the content from
1430 * D3DMatrix: Address to store the content at
1432 * Returns:
1433 * D3D_OK on success
1434 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1436 *****************************************************************************/
1437 static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
1438 D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1440 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1441 D3DMATRIX *m;
1443 TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1445 if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1447 wined3d_mutex_lock();
1449 m = ddraw_get_object(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1450 if (!m)
1452 WARN("Invalid matrix handle.\n");
1453 wined3d_mutex_unlock();
1454 return DDERR_INVALIDPARAMS;
1457 *D3DMatrix = *m;
1459 wined3d_mutex_unlock();
1461 return D3D_OK;
1464 /*****************************************************************************
1465 * IDirect3DDevice::DeleteMatrix
1467 * Destroys a Matrix handle. Frees the memory and unsets the handle data
1469 * Version 1 only
1471 * Params:
1472 * D3DMatHandle: Handle to destroy
1474 * Returns:
1475 * D3D_OK on success
1476 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1478 *****************************************************************************/
1479 static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1481 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1482 D3DMATRIX *m;
1484 TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1486 wined3d_mutex_lock();
1488 m = ddraw_free_handle(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1489 if (!m)
1491 WARN("Invalid matrix handle.\n");
1492 wined3d_mutex_unlock();
1493 return DDERR_INVALIDPARAMS;
1496 wined3d_mutex_unlock();
1498 heap_free(m);
1500 return D3D_OK;
1503 /*****************************************************************************
1504 * IDirect3DDevice7::BeginScene
1506 * This method must be called before any rendering is performed.
1507 * IDirect3DDevice::EndScene has to be called after the scene is complete
1509 * Version 1, 2, 3 and 7
1511 * Returns:
1512 * D3D_OK on success,
1513 * D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1514 * started scene).
1516 *****************************************************************************/
1517 static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1519 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1520 HRESULT hr;
1522 TRACE("iface %p.\n", iface);
1524 wined3d_mutex_lock();
1525 hr = wined3d_device_begin_scene(device->wined3d_device);
1526 wined3d_mutex_unlock();
1528 if(hr == WINED3D_OK) return D3D_OK;
1529 else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1532 static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1534 return d3d_device7_BeginScene(iface);
1537 static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1539 HRESULT hr;
1540 WORD old_fpucw;
1542 old_fpucw = d3d_fpu_setup();
1543 hr = d3d_device7_BeginScene(iface);
1544 set_fpu_control_word(old_fpucw);
1546 return hr;
1549 static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1551 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1553 TRACE("iface %p.\n", iface);
1555 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1558 static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1560 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1562 TRACE("iface %p.\n", iface);
1564 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1567 static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1569 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1571 TRACE("iface %p.\n", iface);
1573 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1576 /*****************************************************************************
1577 * IDirect3DDevice7::EndScene
1579 * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1580 * This method must be called after rendering is finished.
1582 * Version 1, 2, 3 and 7
1584 * Returns:
1585 * D3D_OK on success,
1586 * D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1587 * that only if the scene was already ended.
1589 *****************************************************************************/
1590 static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1592 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1593 HRESULT hr;
1595 TRACE("iface %p.\n", iface);
1597 wined3d_mutex_lock();
1598 hr = wined3d_device_end_scene(device->wined3d_device);
1599 wined3d_mutex_unlock();
1601 if(hr == WINED3D_OK) return D3D_OK;
1602 else return D3DERR_SCENE_NOT_IN_SCENE;
1605 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1607 return d3d_device7_EndScene(iface);
1610 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1612 HRESULT hr;
1613 WORD old_fpucw;
1615 old_fpucw = d3d_fpu_setup();
1616 hr = d3d_device7_EndScene(iface);
1617 set_fpu_control_word(old_fpucw);
1619 return hr;
1622 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1624 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1626 TRACE("iface %p.\n", iface);
1628 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1631 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1633 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1635 TRACE("iface %p.\n", iface);
1637 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1640 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1642 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1644 TRACE("iface %p.\n", iface);
1646 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1649 /*****************************************************************************
1650 * IDirect3DDevice7::GetDirect3D
1652 * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1653 * this device.
1655 * Params:
1656 * Direct3D7: Address to store the interface pointer at
1658 * Returns:
1659 * D3D_OK on success
1660 * DDERR_INVALIDPARAMS if Direct3D7 == NULL
1662 *****************************************************************************/
1663 static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1665 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1667 TRACE("iface %p, d3d %p.\n", iface, d3d);
1669 if (!d3d)
1670 return DDERR_INVALIDPARAMS;
1672 *d3d = &device->ddraw->IDirect3D7_iface;
1673 IDirect3D7_AddRef(*d3d);
1675 TRACE("Returning interface %p.\n", *d3d);
1676 return D3D_OK;
1679 static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1681 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1683 TRACE("iface %p, d3d %p.\n", iface, d3d);
1685 if (!d3d)
1686 return DDERR_INVALIDPARAMS;
1688 *d3d = &device->ddraw->IDirect3D3_iface;
1689 IDirect3D3_AddRef(*d3d);
1691 TRACE("Returning interface %p.\n", *d3d);
1692 return D3D_OK;
1695 static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1697 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1699 TRACE("iface %p, d3d %p.\n", iface, d3d);
1701 if (!d3d)
1702 return DDERR_INVALIDPARAMS;
1704 *d3d = &device->ddraw->IDirect3D2_iface;
1705 IDirect3D2_AddRef(*d3d);
1707 TRACE("Returning interface %p.\n", *d3d);
1708 return D3D_OK;
1711 static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1713 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1715 TRACE("iface %p, d3d %p.\n", iface, d3d);
1717 if (!d3d)
1718 return DDERR_INVALIDPARAMS;
1720 *d3d = &device->ddraw->IDirect3D_iface;
1721 IDirect3D_AddRef(*d3d);
1723 TRACE("Returning interface %p.\n", *d3d);
1724 return D3D_OK;
1727 /*****************************************************************************
1728 * IDirect3DDevice3::SetCurrentViewport
1730 * Sets a Direct3DViewport as the current viewport.
1731 * For the thunks note that all viewport interface versions are equal
1733 * Params:
1734 * Direct3DViewport3: The viewport to set
1736 * Version 2 and 3
1738 * Returns:
1739 * D3D_OK on success
1740 * (Is a NULL viewport valid?)
1742 *****************************************************************************/
1743 static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
1745 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
1746 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1748 TRACE("iface %p, viewport %p, current_viewport %p.\n", iface, viewport, device->current_viewport);
1750 if (!vp)
1752 WARN("Direct3DViewport3 is NULL.\n");
1753 return DDERR_INVALIDPARAMS;
1756 wined3d_mutex_lock();
1757 /* Do nothing if the specified viewport is the same as the current one */
1758 if (device->current_viewport == vp)
1760 wined3d_mutex_unlock();
1761 return D3D_OK;
1764 if (vp->active_device != device)
1766 WARN("Viewport %p, active device %p.\n", vp, vp->active_device);
1767 wined3d_mutex_unlock();
1768 return DDERR_INVALIDPARAMS;
1771 IDirect3DViewport3_AddRef(viewport);
1772 if (device->current_viewport)
1774 viewport_deactivate(device->current_viewport);
1775 IDirect3DViewport3_Release(&device->current_viewport->IDirect3DViewport3_iface);
1777 device->current_viewport = vp;
1778 viewport_activate(device->current_viewport, FALSE);
1780 wined3d_mutex_unlock();
1782 return D3D_OK;
1785 static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1787 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1788 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1790 TRACE("iface %p, viewport %p.\n", iface, viewport);
1792 return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface,
1793 vp ? &vp->IDirect3DViewport3_iface : NULL);
1796 /*****************************************************************************
1797 * IDirect3DDevice3::GetCurrentViewport
1799 * Returns the currently active viewport.
1801 * Version 2 and 3
1803 * Params:
1804 * Direct3DViewport3: Address to return the interface pointer at
1806 * Returns:
1807 * D3D_OK on success
1808 * DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1810 *****************************************************************************/
1811 static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1813 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1815 TRACE("iface %p, viewport %p.\n", iface, viewport);
1817 wined3d_mutex_lock();
1818 if (!device->current_viewport)
1820 wined3d_mutex_unlock();
1821 WARN("No current viewport, returning D3DERR_NOCURRENTVIEWPORT\n");
1822 return D3DERR_NOCURRENTVIEWPORT;
1825 *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1826 IDirect3DViewport3_AddRef(*viewport);
1828 TRACE("Returning interface %p.\n", *viewport);
1829 wined3d_mutex_unlock();
1830 return D3D_OK;
1833 static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1835 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1837 TRACE("iface %p, viewport %p.\n", iface, viewport);
1839 return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
1840 (IDirect3DViewport3 **)viewport);
1843 static BOOL validate_surface_palette(struct ddraw_surface *surface)
1845 return !format_is_paletteindexed(&surface->surface_desc.u4.ddpfPixelFormat)
1846 || surface->palette;
1849 static HRESULT d3d_device_set_render_target(struct d3d_device *device,
1850 struct ddraw_surface *target, IUnknown *rt_iface)
1852 struct wined3d_rendertarget_view *rtv;
1853 HRESULT hr;
1855 if (device->rt_iface == rt_iface)
1857 TRACE("No-op SetRenderTarget operation, not doing anything\n");
1858 return D3D_OK;
1860 if (!target)
1862 WARN("Trying to set render target to NULL.\n");
1863 return DDERR_INVALIDPARAMS;
1866 rtv = ddraw_surface_get_rendertarget_view(target);
1867 if (FAILED(hr = wined3d_device_context_set_rendertarget_views(device->immediate_context, 0, 1, &rtv, FALSE)))
1868 return hr;
1870 IUnknown_AddRef(rt_iface);
1871 IUnknown_Release(device->rt_iface);
1872 device->rt_iface = rt_iface;
1873 d3d_device_update_depth_stencil(device);
1875 return D3D_OK;
1878 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
1879 IDirectDrawSurface7 *target, DWORD flags)
1881 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface7(target);
1882 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1883 HRESULT hr;
1885 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1887 wined3d_mutex_lock();
1889 if (!validate_surface_palette(target_impl))
1891 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1892 wined3d_mutex_unlock();
1893 return DDERR_INVALIDCAPS;
1896 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1898 WARN("Surface %p is not a render target.\n", target_impl);
1899 wined3d_mutex_unlock();
1900 return DDERR_INVALIDCAPS;
1903 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1905 WARN("Surface %p is not in video memory.\n", target_impl);
1906 wined3d_mutex_unlock();
1907 return DDERR_INVALIDPARAMS;
1910 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1912 WARN("Surface %p is a depth buffer.\n", target_impl);
1913 IDirectDrawSurface7_AddRef(target);
1914 IUnknown_Release(device->rt_iface);
1915 device->rt_iface = (IUnknown *)target;
1916 wined3d_mutex_unlock();
1917 return DDERR_INVALIDPIXELFORMAT;
1920 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1921 wined3d_mutex_unlock();
1922 return hr;
1925 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1926 IDirectDrawSurface7 *NewTarget, DWORD flags)
1928 return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1931 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1932 IDirectDrawSurface7 *NewTarget, DWORD flags)
1934 HRESULT hr;
1935 WORD old_fpucw;
1937 old_fpucw = d3d_fpu_setup();
1938 hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1939 set_fpu_control_word(old_fpucw);
1941 return hr;
1944 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
1945 IDirectDrawSurface4 *target, DWORD flags)
1947 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface4(target);
1948 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1949 HRESULT hr;
1951 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1953 wined3d_mutex_lock();
1955 if (!validate_surface_palette(target_impl))
1957 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1958 wined3d_mutex_unlock();
1959 return DDERR_INVALIDCAPS;
1962 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1964 WARN("Surface %p is not a render target.\n", target_impl);
1965 wined3d_mutex_unlock();
1966 return DDERR_INVALIDCAPS;
1969 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1971 WARN("Surface %p is a depth buffer.\n", target_impl);
1972 IDirectDrawSurface4_AddRef(target);
1973 IUnknown_Release(device->rt_iface);
1974 device->rt_iface = (IUnknown *)target;
1975 wined3d_mutex_unlock();
1976 return DDERR_INVALIDPIXELFORMAT;
1979 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1981 WARN("Surface %p is not in video memory.\n", target_impl);
1982 IDirectDrawSurface4_AddRef(target);
1983 IUnknown_Release(device->rt_iface);
1984 device->rt_iface = (IUnknown *)target;
1985 wined3d_mutex_unlock();
1986 return D3D_OK;
1989 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1990 wined3d_mutex_unlock();
1991 return hr;
1994 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
1995 IDirectDrawSurface *target, DWORD flags)
1997 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface(target);
1998 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1999 HRESULT hr;
2001 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
2003 wined3d_mutex_lock();
2005 if (!validate_surface_palette(target_impl))
2007 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
2008 wined3d_mutex_unlock();
2009 return DDERR_INVALIDCAPS;
2012 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
2014 WARN("Surface %p is not a render target.\n", target_impl);
2015 wined3d_mutex_unlock();
2016 return DDERR_INVALIDCAPS;
2019 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
2021 WARN("Surface %p is a depth buffer.\n", target_impl);
2022 IUnknown_Release(device->rt_iface);
2023 device->rt_iface = (IUnknown *)target;
2024 wined3d_mutex_unlock();
2025 return DDERR_INVALIDPIXELFORMAT;
2028 if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
2030 WARN("Surface %p is not in video memory.\n", target_impl);
2031 IDirectDrawSurface_AddRef(target);
2032 IUnknown_Release(device->rt_iface);
2033 device->rt_iface = (IUnknown *)target;
2034 wined3d_mutex_unlock();
2035 return D3D_OK;
2038 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
2039 wined3d_mutex_unlock();
2040 return hr;
2043 /*****************************************************************************
2044 * IDirect3DDevice7::GetRenderTarget
2046 * Returns the current render target.
2047 * This is handled locally, because the WineD3D render target's parent
2048 * is an IParent
2050 * Version 2, 3 and 7
2052 * Params:
2053 * RenderTarget: Address to store the surface interface pointer
2055 * Returns:
2056 * D3D_OK on success
2057 * DDERR_INVALIDPARAMS if RenderTarget == NULL
2059 *****************************************************************************/
2060 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
2062 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2063 HRESULT hr;
2065 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2067 if(!RenderTarget)
2068 return DDERR_INVALIDPARAMS;
2070 wined3d_mutex_lock();
2071 hr = IUnknown_QueryInterface(device->rt_iface, &IID_IDirectDrawSurface7, (void **)RenderTarget);
2072 wined3d_mutex_unlock();
2074 return hr;
2077 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
2079 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2080 IDirectDrawSurface7 *RenderTarget7;
2081 struct ddraw_surface *RenderTargetImpl;
2082 HRESULT hr;
2084 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2086 if(!RenderTarget)
2087 return DDERR_INVALIDPARAMS;
2089 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2090 if(hr != D3D_OK) return hr;
2091 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2092 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
2093 IDirectDrawSurface4_AddRef(*RenderTarget);
2094 IDirectDrawSurface7_Release(RenderTarget7);
2095 return D3D_OK;
2098 static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
2100 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2101 IDirectDrawSurface7 *RenderTarget7;
2102 struct ddraw_surface *RenderTargetImpl;
2103 HRESULT hr;
2105 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2107 if(!RenderTarget)
2108 return DDERR_INVALIDPARAMS;
2110 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2111 if(hr != D3D_OK) return hr;
2112 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2113 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
2114 IDirectDrawSurface_AddRef(*RenderTarget);
2115 IDirectDrawSurface7_Release(RenderTarget7);
2116 return D3D_OK;
2119 /*****************************************************************************
2120 * IDirect3DDevice3::Begin
2122 * Begins a description block of vertices. This is similar to glBegin()
2123 * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
2124 * described with IDirect3DDevice::Vertex are drawn.
2126 * Version 2 and 3
2128 * Params:
2129 * PrimitiveType: The type of primitives to draw
2130 * VertexTypeDesc: A flexible vertex format description of the vertices
2131 * Flags: Some flags..
2133 * Returns:
2134 * D3D_OK on success
2136 *****************************************************************************/
2137 static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
2138 D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
2140 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2142 TRACE("iface %p, primitive_type %#x, fvf %#x, flags %#x.\n",
2143 iface, primitive_type, fvf, flags);
2145 wined3d_mutex_lock();
2146 device->primitive_type = primitive_type;
2147 device->vertex_type = fvf;
2148 device->render_flags = flags;
2149 device->vertex_size = get_flexible_vertex_size(device->vertex_type);
2150 device->nb_vertices = 0;
2151 wined3d_mutex_unlock();
2153 return D3D_OK;
2156 static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
2157 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2159 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2160 DWORD fvf;
2162 TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2163 iface, primitive_type, vertex_type, flags);
2165 switch (vertex_type)
2167 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2168 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2169 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2170 default:
2171 ERR("Unexpected vertex type %#x.\n", vertex_type);
2172 return DDERR_INVALIDPARAMS; /* Should never happen */
2175 return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2178 /*****************************************************************************
2179 * IDirect3DDevice3::BeginIndexed
2181 * Draws primitives based on vertices in a vertex array which are specified
2182 * by indices.
2184 * Version 2 and 3
2186 * Params:
2187 * PrimitiveType: Primitive type to draw
2188 * VertexType: A FVF description of the vertex format
2189 * Vertices: pointer to an array containing the vertices
2190 * NumVertices: The number of vertices in the vertex array
2191 * Flags: Some flags ...
2193 * Returns:
2194 * D3D_OK, because it's a stub
2196 *****************************************************************************/
2197 static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
2198 D3DPRIMITIVETYPE primitive_type, DWORD fvf,
2199 void *vertices, DWORD vertex_count, DWORD flags)
2201 FIXME("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2202 iface, primitive_type, fvf, vertices, vertex_count, flags);
2204 return D3D_OK;
2208 static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
2209 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
2210 void *vertices, DWORD vertex_count, DWORD flags)
2212 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2213 DWORD fvf;
2215 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2216 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2218 switch (vertex_type)
2220 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2221 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2222 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2223 default:
2224 ERR("Unexpected vertex type %#x.\n", vertex_type);
2225 return DDERR_INVALIDPARAMS; /* Should never happen */
2228 return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
2229 primitive_type, fvf, vertices, vertex_count, flags);
2232 /*****************************************************************************
2233 * IDirect3DDevice3::Vertex
2235 * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2236 * drawn vertices in a vertex buffer. If the buffer is too small, its
2237 * size is increased.
2239 * Version 2 and 3
2241 * Params:
2242 * Vertex: Pointer to the vertex
2244 * Returns:
2245 * D3D_OK, on success
2246 * DDERR_INVALIDPARAMS if Vertex is NULL
2248 *****************************************************************************/
2249 static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2251 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2253 TRACE("iface %p, vertex %p.\n", iface, vertex);
2255 if (!vertex)
2256 return DDERR_INVALIDPARAMS;
2258 wined3d_mutex_lock();
2259 if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2261 BYTE *old_buffer;
2263 device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
2264 old_buffer = device->sysmem_vertex_buffer;
2265 device->sysmem_vertex_buffer = heap_alloc(device->buffer_size);
2266 if (old_buffer)
2268 memcpy(device->sysmem_vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2269 heap_free(old_buffer);
2273 memcpy(device->sysmem_vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2274 wined3d_mutex_unlock();
2276 return D3D_OK;
2279 static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2281 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2283 TRACE("iface %p, vertex %p.\n", iface, vertex);
2285 return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2288 /*****************************************************************************
2289 * IDirect3DDevice3::Index
2291 * Specifies an index to a vertex to be drawn. The vertex array has to
2292 * be specified with BeginIndexed first.
2294 * Parameters:
2295 * VertexIndex: The index of the vertex to draw
2297 * Returns:
2298 * D3D_OK because it's a stub
2300 *****************************************************************************/
2301 static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2303 FIXME("iface %p, index %#x stub!\n", iface, index);
2305 return D3D_OK;
2308 static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2310 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2312 TRACE("iface %p, index %#x.\n", iface, index);
2314 return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2317 /*****************************************************************************
2318 * IDirect3DDevice7::GetRenderState
2320 * Returns the value of a render state. The possible render states are
2321 * defined in include/d3dtypes.h
2323 * Version 2, 3 and 7
2325 * Params:
2326 * RenderStateType: Render state to return the current setting of
2327 * Value: Address to store the value at
2329 * Returns:
2330 * D3D_OK on success,
2331 * DDERR_INVALIDPARAMS if Value == NULL
2333 *****************************************************************************/
2334 static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
2335 D3DRENDERSTATETYPE state, DWORD *value)
2337 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2338 const struct wined3d_stateblock_state *device_state;
2339 HRESULT hr = D3D_OK;
2341 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2343 if (!value)
2344 return DDERR_INVALIDPARAMS;
2346 wined3d_mutex_lock();
2347 device_state = device->stateblock_state;
2348 switch (state)
2350 case D3DRENDERSTATE_TEXTUREMAG:
2352 enum wined3d_texture_filter_type tex_mag = device_state->sampler_states[0][WINED3D_SAMP_MAG_FILTER];
2354 switch (tex_mag)
2356 case WINED3D_TEXF_POINT:
2357 *value = D3DFILTER_NEAREST;
2358 break;
2359 case WINED3D_TEXF_LINEAR:
2360 *value = D3DFILTER_LINEAR;
2361 break;
2362 default:
2363 ERR("Unhandled texture mag %d !\n",tex_mag);
2364 *value = 0;
2366 break;
2369 case D3DRENDERSTATE_TEXTUREMIN:
2371 enum wined3d_texture_filter_type tex_min;
2372 enum wined3d_texture_filter_type tex_mip;
2374 tex_min = device_state->sampler_states[0][WINED3D_SAMP_MIN_FILTER];
2375 tex_mip = device_state->sampler_states[0][WINED3D_SAMP_MIP_FILTER];
2376 switch (tex_min)
2378 case WINED3D_TEXF_POINT:
2379 switch (tex_mip)
2381 case WINED3D_TEXF_NONE:
2382 *value = D3DFILTER_NEAREST;
2383 break;
2384 case WINED3D_TEXF_POINT:
2385 *value = D3DFILTER_MIPNEAREST;
2386 break;
2387 case WINED3D_TEXF_LINEAR:
2388 *value = D3DFILTER_LINEARMIPNEAREST;
2389 break;
2390 default:
2391 ERR("Unhandled mip filter %#x.\n", tex_mip);
2392 *value = D3DFILTER_NEAREST;
2393 break;
2395 break;
2396 case WINED3D_TEXF_LINEAR:
2397 switch (tex_mip)
2399 case WINED3D_TEXF_NONE:
2400 *value = D3DFILTER_LINEAR;
2401 break;
2402 case WINED3D_TEXF_POINT:
2403 *value = D3DFILTER_MIPLINEAR;
2404 break;
2405 case WINED3D_TEXF_LINEAR:
2406 *value = D3DFILTER_LINEARMIPLINEAR;
2407 break;
2408 default:
2409 ERR("Unhandled mip filter %#x.\n", tex_mip);
2410 *value = D3DFILTER_LINEAR;
2411 break;
2413 break;
2414 default:
2415 ERR("Unhandled texture min filter %#x.\n",tex_min);
2416 *value = D3DFILTER_NEAREST;
2417 break;
2419 break;
2422 case D3DRENDERSTATE_TEXTUREADDRESS:
2423 case D3DRENDERSTATE_TEXTUREADDRESSU:
2424 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_U];
2425 break;
2426 case D3DRENDERSTATE_TEXTUREADDRESSV:
2427 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_V];
2428 break;
2430 case D3DRENDERSTATE_BORDERCOLOR:
2431 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2432 hr = E_NOTIMPL;
2433 break;
2435 case D3DRENDERSTATE_TEXTUREHANDLE:
2436 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2437 WARN("Render state %#x is invalid in d3d7.\n", state);
2438 hr = DDERR_INVALIDPARAMS;
2439 break;
2441 default:
2442 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2443 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2445 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2446 hr = E_NOTIMPL;
2447 break;
2449 *value = device_state->rs[wined3d_render_state_from_ddraw(state)];
2451 wined3d_mutex_unlock();
2453 return hr;
2456 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2457 D3DRENDERSTATETYPE state, DWORD *value)
2459 return d3d_device7_GetRenderState(iface, state, value);
2462 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2463 D3DRENDERSTATETYPE state, DWORD *value)
2465 HRESULT hr;
2466 WORD old_fpucw;
2468 old_fpucw = d3d_fpu_setup();
2469 hr = d3d_device7_GetRenderState(iface, state, value);
2470 set_fpu_control_word(old_fpucw);
2472 return hr;
2475 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2476 D3DRENDERSTATETYPE state, DWORD *value)
2478 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2480 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2482 switch (state)
2484 case D3DRENDERSTATE_TEXTUREHANDLE:
2486 /* This state is wrapped to SetTexture in SetRenderState, so
2487 * it has to be wrapped to GetTexture here. */
2488 struct wined3d_texture *tex = NULL;
2489 *value = 0;
2491 wined3d_mutex_lock();
2492 if ((tex = device->stateblock_state->textures[0]))
2494 /* The parent of the texture is the IDirectDrawSurface7
2495 * interface of the ddraw surface. */
2496 struct ddraw_texture *parent = wined3d_texture_get_parent(tex);
2497 if (parent)
2498 *value = parent->root->Handle;
2500 wined3d_mutex_unlock();
2502 return D3D_OK;
2505 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2507 *value = device->texture_map_blend;
2508 return D3D_OK;
2511 case D3DRENDERSTATE_LIGHTING:
2512 case D3DRENDERSTATE_NORMALIZENORMALS:
2513 case D3DRENDERSTATE_LOCALVIEWER:
2514 *value = 0xffffffff;
2515 return D3D_OK;
2517 default:
2518 return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2522 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2523 D3DRENDERSTATETYPE state, DWORD *value)
2525 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2527 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2529 return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2532 /*****************************************************************************
2533 * IDirect3DDevice7::SetRenderState
2535 * Sets a render state. The possible render states are defined in
2536 * include/d3dtypes.h
2538 * Version 2, 3 and 7
2540 * Params:
2541 * RenderStateType: State to set
2542 * Value: Value to assign to that state
2544 *****************************************************************************/
2545 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2546 D3DRENDERSTATETYPE state, DWORD value)
2548 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2549 HRESULT hr = D3D_OK;
2551 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2553 wined3d_mutex_lock();
2554 /* Some render states need special care */
2555 switch (state)
2558 * The ddraw texture filter mapping works like this:
2559 * D3DFILTER_NEAREST Point min/mag, no mip
2560 * D3DFILTER_MIPNEAREST Point min/mag, point mip
2561 * D3DFILTER_LINEARMIPNEAREST: Point min/mag, linear mip
2563 * D3DFILTER_LINEAR Linear min/mag, no mip
2564 * D3DFILTER_MIPLINEAR Linear min/mag, point mip
2565 * D3DFILTER_LINEARMIPLINEAR Linear min/mag, linear mip
2567 * This is the opposite of the GL naming convention,
2568 * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2570 case D3DRENDERSTATE_TEXTUREMAG:
2572 enum wined3d_texture_filter_type tex_mag;
2574 switch (value)
2576 case D3DFILTER_NEAREST:
2577 case D3DFILTER_MIPNEAREST:
2578 case D3DFILTER_LINEARMIPNEAREST:
2579 tex_mag = WINED3D_TEXF_POINT;
2580 break;
2581 case D3DFILTER_LINEAR:
2582 case D3DFILTER_MIPLINEAR:
2583 case D3DFILTER_LINEARMIPLINEAR:
2584 tex_mag = WINED3D_TEXF_LINEAR;
2585 break;
2586 default:
2587 tex_mag = WINED3D_TEXF_POINT;
2588 FIXME("Unhandled texture mag %#x.\n", value);
2589 break;
2592 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2593 break;
2596 case D3DRENDERSTATE_TEXTUREMIN:
2598 enum wined3d_texture_filter_type tex_min;
2599 enum wined3d_texture_filter_type tex_mip;
2601 switch (value)
2603 case D3DFILTER_NEAREST:
2604 tex_min = WINED3D_TEXF_POINT;
2605 tex_mip = WINED3D_TEXF_NONE;
2606 break;
2607 case D3DFILTER_LINEAR:
2608 tex_min = WINED3D_TEXF_LINEAR;
2609 tex_mip = WINED3D_TEXF_NONE;
2610 break;
2611 case D3DFILTER_MIPNEAREST:
2612 tex_min = WINED3D_TEXF_POINT;
2613 tex_mip = WINED3D_TEXF_POINT;
2614 break;
2615 case D3DFILTER_MIPLINEAR:
2616 tex_min = WINED3D_TEXF_LINEAR;
2617 tex_mip = WINED3D_TEXF_POINT;
2618 break;
2619 case D3DFILTER_LINEARMIPNEAREST:
2620 tex_min = WINED3D_TEXF_POINT;
2621 tex_mip = WINED3D_TEXF_LINEAR;
2622 break;
2623 case D3DFILTER_LINEARMIPLINEAR:
2624 tex_min = WINED3D_TEXF_LINEAR;
2625 tex_mip = WINED3D_TEXF_LINEAR;
2626 break;
2628 default:
2629 FIXME("Unhandled texture min %#x.\n",value);
2630 tex_min = WINED3D_TEXF_POINT;
2631 tex_mip = WINED3D_TEXF_NONE;
2632 break;
2635 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2636 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIN_FILTER, tex_min);
2637 break;
2640 case D3DRENDERSTATE_TEXTUREADDRESS:
2641 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2642 /* Drop through */
2643 case D3DRENDERSTATE_TEXTUREADDRESSU:
2644 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_U, value);
2645 break;
2646 case D3DRENDERSTATE_TEXTUREADDRESSV:
2647 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2648 break;
2650 case D3DRENDERSTATE_BORDERCOLOR:
2651 /* This should probably just forward to the corresponding sampler
2652 * state. Needs tests. */
2653 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2654 hr = E_NOTIMPL;
2655 break;
2657 case D3DRENDERSTATE_TEXTUREHANDLE:
2658 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2659 WARN("Render state %#x is invalid in d3d7.\n", state);
2660 hr = DDERR_INVALIDPARAMS;
2661 break;
2663 default:
2664 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2665 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2667 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2668 hr = E_NOTIMPL;
2669 break;
2672 wined3d_stateblock_set_render_state(device->update_state, wined3d_render_state_from_ddraw(state), value);
2673 break;
2675 wined3d_mutex_unlock();
2677 return hr;
2680 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2681 D3DRENDERSTATETYPE state, DWORD value)
2683 return d3d_device7_SetRenderState(iface, state, value);
2686 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2687 D3DRENDERSTATETYPE state, DWORD value)
2689 HRESULT hr;
2690 WORD old_fpucw;
2692 old_fpucw = d3d_fpu_setup();
2693 hr = d3d_device7_SetRenderState(iface, state, value);
2694 set_fpu_control_word(old_fpucw);
2696 return hr;
2699 static void fixup_texture_alpha_op(struct d3d_device *device)
2701 /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
2702 See d3d_device3_SetRenderState() for details. */
2703 struct wined3d_texture *tex;
2704 BOOL tex_alpha = TRUE;
2705 DDPIXELFORMAT ddfmt;
2707 if (!(device->legacyTextureBlending && device->texture_map_blend == D3DTBLEND_MODULATE))
2708 return;
2710 if ((tex = device->stateblock_state->textures[0]))
2712 struct wined3d_resource_desc desc;
2714 wined3d_resource_get_desc(wined3d_texture_get_resource(tex), &desc);
2715 ddfmt.dwSize = sizeof(ddfmt);
2716 ddrawformat_from_wined3dformat(&ddfmt, desc.format);
2717 if (!ddfmt.u5.dwRGBAlphaBitMask)
2718 tex_alpha = FALSE;
2721 /* Args 1 and 2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
2722 wined3d_stateblock_set_texture_stage_state(device->state,
2723 0, WINED3D_TSS_ALPHA_OP, tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2);
2726 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2727 D3DRENDERSTATETYPE state, DWORD value)
2729 /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2730 for this state can be directly mapped to texture stage colorop and alphaop, but
2731 D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2732 from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2733 alphaarg when needed.
2735 Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2737 Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2738 TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2739 are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2740 requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2741 with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2742 in device - TRUE if the app is using TEXTUREMAPBLEND.
2744 Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2745 GetTextureStageState and vice versa. */
2747 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2748 HRESULT hr;
2750 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2752 if (state >= D3DSTATE_OVERRIDE_BIAS)
2754 WARN("Unhandled state %#x.\n", state);
2755 return DDERR_INVALIDPARAMS;
2758 wined3d_mutex_lock();
2760 switch (state)
2762 case D3DRENDERSTATE_TEXTUREHANDLE:
2764 struct ddraw_surface *surf;
2766 if (value == 0)
2768 wined3d_stateblock_set_texture(device->state, 0, NULL);
2769 hr = D3D_OK;
2770 break;
2773 surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2774 if (!surf)
2776 WARN("Invalid texture handle.\n");
2777 hr = DDERR_INVALIDPARAMS;
2778 break;
2781 hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2782 break;
2785 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2787 if (value == device->texture_map_blend)
2789 TRACE("Application is setting the same value over, nothing to do.\n");
2791 hr = D3D_OK;
2792 break;
2795 device->legacyTextureBlending = TRUE;
2796 device->texture_map_blend = value;
2798 switch (value)
2800 case D3DTBLEND_MODULATE:
2802 fixup_texture_alpha_op(device);
2804 wined3d_stateblock_set_texture_stage_state(device->state,
2805 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2806 wined3d_stateblock_set_texture_stage_state(device->state,
2807 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2808 wined3d_stateblock_set_texture_stage_state(device->state,
2809 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2810 wined3d_stateblock_set_texture_stage_state(device->state,
2811 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2812 wined3d_stateblock_set_texture_stage_state(device->state,
2813 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2814 break;
2817 case D3DTBLEND_ADD:
2818 wined3d_stateblock_set_texture_stage_state(device->state,
2819 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2820 wined3d_stateblock_set_texture_stage_state(device->state,
2821 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2822 wined3d_stateblock_set_texture_stage_state(device->state,
2823 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2824 wined3d_stateblock_set_texture_stage_state(device->state,
2825 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2826 wined3d_stateblock_set_texture_stage_state(device->state,
2827 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2828 break;
2830 case D3DTBLEND_MODULATEALPHA:
2831 wined3d_stateblock_set_texture_stage_state(device->state,
2832 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2833 wined3d_stateblock_set_texture_stage_state(device->state,
2834 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2835 wined3d_stateblock_set_texture_stage_state(device->state,
2836 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2837 wined3d_stateblock_set_texture_stage_state(device->state,
2838 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2839 wined3d_stateblock_set_texture_stage_state(device->state,
2840 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2841 wined3d_stateblock_set_texture_stage_state(device->state,
2842 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2843 break;
2845 case D3DTBLEND_COPY:
2846 case D3DTBLEND_DECAL:
2847 wined3d_stateblock_set_texture_stage_state(device->state,
2848 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2849 wined3d_stateblock_set_texture_stage_state(device->state,
2850 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2851 wined3d_stateblock_set_texture_stage_state(device->state,
2852 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2853 wined3d_stateblock_set_texture_stage_state(device->state,
2854 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2855 break;
2857 case D3DTBLEND_DECALALPHA:
2858 wined3d_stateblock_set_texture_stage_state(device->state,
2859 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2860 wined3d_stateblock_set_texture_stage_state(device->state,
2861 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2862 wined3d_stateblock_set_texture_stage_state(device->state,
2863 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2864 wined3d_stateblock_set_texture_stage_state(device->state,
2865 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2866 wined3d_stateblock_set_texture_stage_state(device->state,
2867 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2868 break;
2870 default:
2871 FIXME("Unhandled texture environment %#x.\n", value);
2873 hr = D3D_OK;
2874 break;
2877 case D3DRENDERSTATE_LIGHTING:
2878 case D3DRENDERSTATE_NORMALIZENORMALS:
2879 case D3DRENDERSTATE_LOCALVIEWER:
2880 hr = D3D_OK;
2881 break;
2883 default:
2884 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2885 break;
2887 wined3d_mutex_unlock();
2889 return hr;
2892 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2893 D3DRENDERSTATETYPE state, DWORD value)
2895 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2897 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2899 return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2902 /*****************************************************************************
2903 * Direct3DDevice3::SetLightState
2905 * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2906 * light states are forwarded to Direct3DDevice7 render states
2908 * Version 2 and 3
2910 * Params:
2911 * LightStateType: The light state to change
2912 * Value: The value to assign to that light state
2914 * Returns:
2915 * D3D_OK on success
2916 * DDERR_INVALIDPARAMS if the parameters were incorrect
2917 * Also check IDirect3DDevice7::SetRenderState
2919 *****************************************************************************/
2920 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2921 D3DLIGHTSTATETYPE state, DWORD value)
2923 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2924 HRESULT hr;
2926 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2928 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2930 TRACE("Unexpected Light State Type\n");
2931 return DDERR_INVALIDPARAMS;
2934 wined3d_mutex_lock();
2935 if (state == D3DLIGHTSTATE_MATERIAL)
2937 if (value)
2939 struct d3d_material *m;
2941 if (!(m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL)))
2943 WARN("Invalid material handle.\n");
2944 wined3d_mutex_unlock();
2945 return DDERR_INVALIDPARAMS;
2948 material_activate(m);
2951 device->material = value;
2953 else if (state == D3DLIGHTSTATE_COLORMODEL)
2955 switch (value)
2957 case D3DCOLOR_MONO:
2958 ERR("DDCOLOR_MONO should not happen!\n");
2959 break;
2960 case D3DCOLOR_RGB:
2961 /* We are already in this mode */
2962 TRACE("Setting color model to RGB (no-op).\n");
2963 break;
2964 default:
2965 ERR("Unknown color model!\n");
2966 wined3d_mutex_unlock();
2967 return DDERR_INVALIDPARAMS;
2970 else
2972 D3DRENDERSTATETYPE rs;
2973 switch (state)
2975 case D3DLIGHTSTATE_AMBIENT: /* 2 */
2976 rs = D3DRENDERSTATE_AMBIENT;
2977 break;
2978 case D3DLIGHTSTATE_FOGMODE: /* 4 */
2979 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2980 break;
2981 case D3DLIGHTSTATE_FOGSTART: /* 5 */
2982 rs = D3DRENDERSTATE_FOGSTART;
2983 break;
2984 case D3DLIGHTSTATE_FOGEND: /* 6 */
2985 rs = D3DRENDERSTATE_FOGEND;
2986 break;
2987 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
2988 rs = D3DRENDERSTATE_FOGDENSITY;
2989 break;
2990 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
2991 rs = D3DRENDERSTATE_COLORVERTEX;
2992 break;
2993 default:
2994 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2995 wined3d_mutex_unlock();
2996 return DDERR_INVALIDPARAMS;
2999 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3000 wined3d_mutex_unlock();
3001 return hr;
3003 wined3d_mutex_unlock();
3005 return D3D_OK;
3008 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
3009 D3DLIGHTSTATETYPE state, DWORD value)
3011 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3013 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
3015 return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
3018 /*****************************************************************************
3019 * IDirect3DDevice3::GetLightState
3021 * Returns the current setting of a light state. The state is read from
3022 * the Direct3DDevice7 render state.
3024 * Version 2 and 3
3026 * Params:
3027 * LightStateType: The light state to return
3028 * Value: The address to store the light state setting at
3030 * Returns:
3031 * D3D_OK on success
3032 * DDDERR_INVALIDPARAMS if the parameters were incorrect
3033 * Also see IDirect3DDevice7::GetRenderState
3035 *****************************************************************************/
3036 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
3037 D3DLIGHTSTATETYPE state, DWORD *value)
3039 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3040 HRESULT hr;
3042 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3044 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
3046 TRACE("Unexpected Light State Type\n");
3047 return DDERR_INVALIDPARAMS;
3050 if (!value)
3051 return DDERR_INVALIDPARAMS;
3053 wined3d_mutex_lock();
3054 if (state == D3DLIGHTSTATE_MATERIAL)
3056 *value = device->material;
3058 else if (state == D3DLIGHTSTATE_COLORMODEL)
3060 *value = D3DCOLOR_RGB;
3062 else
3064 D3DRENDERSTATETYPE rs;
3065 switch (state)
3067 case D3DLIGHTSTATE_AMBIENT: /* 2 */
3068 rs = D3DRENDERSTATE_AMBIENT;
3069 break;
3070 case D3DLIGHTSTATE_FOGMODE: /* 4 */
3071 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3072 break;
3073 case D3DLIGHTSTATE_FOGSTART: /* 5 */
3074 rs = D3DRENDERSTATE_FOGSTART;
3075 break;
3076 case D3DLIGHTSTATE_FOGEND: /* 6 */
3077 rs = D3DRENDERSTATE_FOGEND;
3078 break;
3079 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
3080 rs = D3DRENDERSTATE_FOGDENSITY;
3081 break;
3082 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
3083 rs = D3DRENDERSTATE_COLORVERTEX;
3084 break;
3085 default:
3086 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3087 wined3d_mutex_unlock();
3088 return DDERR_INVALIDPARAMS;
3091 hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3092 wined3d_mutex_unlock();
3093 return hr;
3095 wined3d_mutex_unlock();
3097 return D3D_OK;
3100 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3101 D3DLIGHTSTATETYPE state, DWORD *value)
3103 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3105 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3107 return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3110 /*****************************************************************************
3111 * IDirect3DDevice7::SetTransform
3113 * Assigns a D3DMATRIX to a transform type. The transform types are defined
3114 * in include/d3dtypes.h.
3115 * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3116 * (=255) for wined3d, because the 1 transform state was removed in d3d8
3117 * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3119 * Version 2, 3 and 7
3121 * Params:
3122 * TransformStateType: transform state to set
3123 * Matrix: Matrix to assign to the state
3125 * Returns:
3126 * D3D_OK on success
3127 * DDERR_INVALIDPARAMS if Matrix == NULL
3129 *****************************************************************************/
3130 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3131 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3133 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3135 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3137 if (!matrix)
3138 return DDERR_INVALIDPARAMS;
3140 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3141 wined3d_mutex_lock();
3142 wined3d_stateblock_set_transform(device->update_state,
3143 wined3d_transform_state_from_ddraw(state), (const struct wined3d_matrix *)matrix);
3144 wined3d_mutex_unlock();
3146 return D3D_OK;
3149 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3150 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3152 return d3d_device7_SetTransform(iface, state, matrix);
3155 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3156 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3158 HRESULT hr;
3159 WORD old_fpucw;
3161 old_fpucw = d3d_fpu_setup();
3162 hr = d3d_device7_SetTransform(iface, state, matrix);
3163 set_fpu_control_word(old_fpucw);
3165 return hr;
3168 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3169 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3171 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3173 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3175 if (!matrix)
3176 return DDERR_INVALIDPARAMS;
3178 if (state == D3DTRANSFORMSTATE_PROJECTION)
3180 struct wined3d_matrix projection;
3182 wined3d_mutex_lock();
3183 multiply_matrix(&projection, &device->legacy_clipspace, (struct wined3d_matrix *)matrix);
3184 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3185 memcpy(&device->legacy_projection, matrix, sizeof(*matrix));
3186 wined3d_mutex_unlock();
3188 return D3D_OK;
3191 return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3194 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3195 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3197 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3199 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3201 return IDirect3DDevice3_SetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3204 /*****************************************************************************
3205 * IDirect3DDevice7::GetTransform
3207 * Returns the matrix assigned to a transform state
3208 * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3209 * SetTransform
3211 * Params:
3212 * TransformStateType: State to read the matrix from
3213 * Matrix: Address to store the matrix at
3215 * Returns:
3216 * D3D_OK on success
3217 * DDERR_INVALIDPARAMS if Matrix == NULL
3219 *****************************************************************************/
3220 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3221 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3223 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3225 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3227 if (!matrix)
3228 return DDERR_INVALIDPARAMS;
3230 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3231 wined3d_mutex_lock();
3232 memcpy(matrix, &device->stateblock_state->transforms[wined3d_transform_state_from_ddraw(state)], sizeof(*matrix));
3233 wined3d_mutex_unlock();
3235 return D3D_OK;
3238 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3239 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3241 return d3d_device7_GetTransform(iface, state, matrix);
3244 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3245 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3247 HRESULT hr;
3248 WORD old_fpucw;
3250 old_fpucw = d3d_fpu_setup();
3251 hr = d3d_device7_GetTransform(iface, state, matrix);
3252 set_fpu_control_word(old_fpucw);
3254 return hr;
3257 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3258 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3260 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3262 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3264 if (!matrix)
3265 return DDERR_INVALIDPARAMS;
3267 if (state == D3DTRANSFORMSTATE_PROJECTION)
3269 wined3d_mutex_lock();
3270 memcpy(matrix, &device->legacy_projection, sizeof(*matrix));
3271 wined3d_mutex_unlock();
3272 return DD_OK;
3275 return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3278 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3279 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3281 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3283 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3285 return IDirect3DDevice3_GetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3288 /*****************************************************************************
3289 * IDirect3DDevice7::MultiplyTransform
3291 * Multiplies the already-set transform matrix of a transform state
3292 * with another matrix. For the world matrix, see SetTransform
3294 * Version 2, 3 and 7
3296 * Params:
3297 * TransformStateType: Transform state to multiply
3298 * D3DMatrix Matrix to multiply with.
3300 * Returns
3301 * D3D_OK on success
3302 * DDERR_INVALIDPARAMS if D3DMatrix is NULL
3304 *****************************************************************************/
3305 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3306 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3308 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3310 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3312 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3313 wined3d_mutex_lock();
3314 wined3d_stateblock_multiply_transform(device->state,
3315 wined3d_transform_state_from_ddraw(state), (struct wined3d_matrix *)matrix);
3316 wined3d_mutex_unlock();
3318 return D3D_OK;
3321 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3322 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3324 return d3d_device7_MultiplyTransform(iface, state, matrix);
3327 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3328 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3330 HRESULT hr;
3331 WORD old_fpucw;
3333 old_fpucw = d3d_fpu_setup();
3334 hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3335 set_fpu_control_word(old_fpucw);
3337 return hr;
3340 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3341 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3343 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3345 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3347 if (state == D3DTRANSFORMSTATE_PROJECTION)
3349 struct wined3d_matrix projection, tmp;
3351 wined3d_mutex_lock();
3352 multiply_matrix(&tmp, &device->legacy_projection, (struct wined3d_matrix *)matrix);
3353 multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3354 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3355 device->legacy_projection = tmp;
3356 wined3d_mutex_unlock();
3358 return D3D_OK;
3361 return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3364 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3365 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3367 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3369 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3371 return IDirect3DDevice3_MultiplyTransform(&device->IDirect3DDevice3_iface, state, matrix);
3374 /*****************************************************************************
3375 * IDirect3DDevice7::DrawPrimitive
3377 * Draws primitives based on vertices in an application-provided pointer
3379 * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3380 * an FVF format for D3D7
3382 * Params:
3383 * PrimitiveType: The type of the primitives to draw
3384 * Vertex type: Flexible vertex format vertex description
3385 * Vertices: Pointer to the vertex array
3386 * VertexCount: The number of vertices to draw
3387 * Flags: As usual a few flags
3389 * Returns:
3390 * D3D_OK on success
3391 * DDERR_INVALIDPARAMS if Vertices is NULL
3393 *****************************************************************************/
3395 /* The caller is responsible for wined3d locking */
3396 static HRESULT d3d_device_prepare_vertex_buffer(struct d3d_device *device, UINT min_size)
3398 HRESULT hr;
3400 if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
3402 UINT size = max(device->vertex_buffer_size * 2, min_size);
3403 struct wined3d_buffer_desc desc;
3404 struct wined3d_buffer *buffer;
3406 TRACE("Growing vertex buffer to %u bytes\n", size);
3408 desc.byte_width = size;
3409 desc.usage = WINED3DUSAGE_DYNAMIC;
3410 desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
3411 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W;
3412 desc.misc_flags = 0;
3413 desc.structure_byte_stride = 0;
3415 if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
3416 NULL, NULL, &ddraw_null_wined3d_parent_ops, &buffer)))
3418 ERR("Failed to create vertex buffer, hr %#x.\n", hr);
3419 return hr;
3422 if (device->vertex_buffer)
3423 wined3d_buffer_decref(device->vertex_buffer);
3425 device->vertex_buffer = buffer;
3426 device->vertex_buffer_size = size;
3427 device->vertex_buffer_pos = 0;
3429 return D3D_OK;
3432 static void d3d_device_sync_rendertarget(struct d3d_device *device)
3434 struct wined3d_rendertarget_view *rtv;
3436 if (device->hardware_device)
3437 return;
3439 if ((rtv = wined3d_device_context_get_rendertarget_view(device->immediate_context, 0)))
3440 ddraw_surface_get_draw_texture(wined3d_rendertarget_view_get_parent(rtv), DDRAW_SURFACE_RW);
3442 if ((rtv = wined3d_device_context_get_depth_stencil_view(device->immediate_context)))
3443 ddraw_surface_get_draw_texture(wined3d_rendertarget_view_get_parent(rtv), DDRAW_SURFACE_RW);
3446 void d3d_device_sync_surfaces(struct d3d_device *device)
3448 const struct wined3d_stateblock_state *state = device->stateblock_state;
3449 struct ddraw_surface *surface;
3450 unsigned int i, j;
3452 if (device->hardware_device)
3453 return;
3455 d3d_device_sync_rendertarget(device);
3457 for (i = 0; i < ARRAY_SIZE(state->textures); ++i)
3459 if (!state->textures[i])
3460 continue;
3462 j = 0;
3463 while ((surface = wined3d_texture_get_sub_resource_parent(state->textures[i], j)))
3465 if (!surface->draw_texture)
3466 break;
3467 ddraw_surface_get_draw_texture(surface, DDRAW_SURFACE_READ);
3468 ++j;
3473 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3474 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3475 DWORD vertex_count, DWORD flags)
3477 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3478 struct wined3d_map_desc wined3d_map_desc;
3479 struct wined3d_box wined3d_box = {0};
3480 UINT stride, vb_pos, size, align;
3481 struct wined3d_resource *vb;
3482 HRESULT hr;
3484 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3485 iface, primitive_type, fvf, vertices, vertex_count, flags);
3487 if (!vertex_count)
3489 WARN("0 vertex count.\n");
3490 return D3D_OK;
3493 /* Get the stride */
3494 stride = get_flexible_vertex_size(fvf);
3495 size = vertex_count * stride;
3497 wined3d_mutex_lock();
3498 hr = d3d_device_prepare_vertex_buffer(device, size);
3499 if (FAILED(hr))
3500 goto done;
3502 vb_pos = device->vertex_buffer_pos;
3503 align = vb_pos % stride;
3504 if (align) align = stride - align;
3505 if (vb_pos + size + align > device->vertex_buffer_size)
3506 vb_pos = 0;
3507 else
3508 vb_pos += align;
3510 wined3d_box.left = vb_pos;
3511 wined3d_box.right = vb_pos + size;
3512 vb = wined3d_buffer_get_resource(device->vertex_buffer);
3513 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
3514 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3515 goto done;
3516 memcpy(wined3d_map_desc.data, vertices, size);
3517 wined3d_resource_unmap(vb, 0);
3518 device->vertex_buffer_pos = vb_pos + size;
3520 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, stride);
3521 if (FAILED(hr))
3522 goto done;
3524 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3525 wined3d_device_context_set_primitive_type(device->immediate_context,
3526 wined3d_primitive_type_from_ddraw(primitive_type), 0);
3527 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3528 d3d_device_sync_surfaces(device);
3529 wined3d_device_context_draw(device->immediate_context, vb_pos / stride, vertex_count, 0, 0);
3531 done:
3532 wined3d_mutex_unlock();
3533 return hr;
3536 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3537 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3538 DWORD vertex_count, DWORD flags)
3540 return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3543 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3544 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3545 DWORD vertex_count, DWORD flags)
3547 HRESULT hr;
3548 WORD old_fpucw;
3550 old_fpucw = d3d_fpu_setup();
3551 hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3552 set_fpu_control_word(old_fpucw);
3554 return hr;
3557 static void setup_lighting(const struct d3d_device *device, DWORD fvf, DWORD flags)
3559 BOOL enable = TRUE;
3561 /* Ignore the D3DFVF_XYZRHW case here, wined3d takes care of that */
3562 if (!device->material || !(fvf & D3DFVF_NORMAL) || (flags & D3DDP_DONOTLIGHT))
3563 enable = FALSE;
3565 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_LIGHTING, enable);
3569 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3570 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3571 DWORD flags)
3573 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3575 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3576 iface, primitive_type, fvf, vertices, vertex_count, flags);
3578 setup_lighting(device, fvf, flags);
3580 return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3581 primitive_type, fvf, vertices, vertex_count, flags);
3584 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3585 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3586 DWORD vertex_count, DWORD flags)
3588 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3589 DWORD fvf;
3591 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3592 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3594 switch (vertex_type)
3596 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3597 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3598 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3599 default:
3600 FIXME("Unhandled vertex type %#x.\n", vertex_type);
3601 return DDERR_INVALIDPARAMS; /* Should never happen */
3604 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface,
3605 primitive_type, fvf, vertices, vertex_count, flags);
3608 /*****************************************************************************
3609 * IDirect3DDevice7::DrawIndexedPrimitive
3611 * Draws vertices from an application-provided pointer, based on the index
3612 * numbers in a WORD array.
3614 * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3615 * an FVF format for D3D7
3617 * Params:
3618 * PrimitiveType: The primitive type to draw
3619 * VertexType: The FVF vertex description
3620 * Vertices: Pointer to the vertex array
3621 * VertexCount: ?
3622 * Indices: Pointer to the index array
3623 * IndexCount: Number of indices = Number of vertices to draw
3624 * Flags: As usual, some flags
3626 * Returns:
3627 * D3D_OK on success
3628 * DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3630 *****************************************************************************/
3631 /* The caller is responsible for wined3d locking */
3632 static HRESULT d3d_device_prepare_index_buffer(struct d3d_device *device, UINT min_size)
3634 HRESULT hr;
3636 if (device->index_buffer_size < min_size || !device->index_buffer)
3638 UINT size = max(device->index_buffer_size * 2, min_size);
3639 struct wined3d_buffer_desc desc;
3640 struct wined3d_buffer *buffer;
3642 TRACE("Growing index buffer to %u bytes\n", size);
3644 desc.byte_width = size;
3645 desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_STATICDECL;
3646 desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
3647 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W;
3648 desc.misc_flags = 0;
3649 desc.structure_byte_stride = 0;
3651 if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
3652 NULL, NULL, &ddraw_null_wined3d_parent_ops, &buffer)))
3654 ERR("Failed to create index buffer, hr %#x.\n", hr);
3655 return hr;
3658 if (device->index_buffer)
3659 wined3d_buffer_decref(device->index_buffer);
3660 device->index_buffer = buffer;
3661 device->index_buffer_size = size;
3662 device->index_buffer_pos = 0;
3664 return D3D_OK;
3667 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3668 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3669 WORD *indices, DWORD index_count, DWORD flags)
3671 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3672 HRESULT hr;
3673 UINT stride = get_flexible_vertex_size(fvf);
3674 UINT vtx_size = stride * vertex_count, idx_size = index_count * sizeof(*indices);
3675 struct wined3d_map_desc wined3d_map_desc;
3676 struct wined3d_box wined3d_box = {0};
3677 struct wined3d_resource *ib, *vb;
3678 UINT vb_pos, ib_pos, align;
3680 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3681 "indices %p, index_count %u, flags %#x.\n",
3682 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3684 if (!vertex_count || !index_count)
3686 WARN("0 vertex or index count.\n");
3687 return D3D_OK;
3690 /* Set the D3DDevice's FVF */
3691 wined3d_mutex_lock();
3693 hr = d3d_device_prepare_vertex_buffer(device, vtx_size);
3694 if (FAILED(hr))
3695 goto done;
3697 vb_pos = device->vertex_buffer_pos;
3698 align = vb_pos % stride;
3699 if (align) align = stride - align;
3700 if (vb_pos + vtx_size + align > device->vertex_buffer_size)
3701 vb_pos = 0;
3702 else
3703 vb_pos += align;
3705 wined3d_box.left = vb_pos;
3706 wined3d_box.right = vb_pos + vtx_size;
3707 vb = wined3d_buffer_get_resource(device->vertex_buffer);
3708 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
3709 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3710 goto done;
3711 memcpy(wined3d_map_desc.data, vertices, vtx_size);
3712 wined3d_resource_unmap(vb, 0);
3713 device->vertex_buffer_pos = vb_pos + vtx_size;
3715 hr = d3d_device_prepare_index_buffer(device, idx_size);
3716 if (FAILED(hr))
3717 goto done;
3718 ib_pos = device->index_buffer_pos;
3719 if (device->index_buffer_size - idx_size < ib_pos)
3720 ib_pos = 0;
3722 wined3d_box.left = ib_pos;
3723 wined3d_box.right = ib_pos + idx_size;
3724 ib = wined3d_buffer_get_resource(device->index_buffer);
3725 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
3726 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3727 goto done;
3728 memcpy(wined3d_map_desc.data, indices, idx_size);
3729 wined3d_resource_unmap(ib, 0);
3730 device->index_buffer_pos = ib_pos + idx_size;
3732 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, stride);
3733 if (FAILED(hr))
3734 goto done;
3735 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
3737 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3738 wined3d_device_context_set_primitive_type(device->immediate_context,
3739 wined3d_primitive_type_from_ddraw(primitive_type), 0);
3740 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3741 d3d_device_sync_surfaces(device);
3742 wined3d_device_context_draw_indexed(device->immediate_context, vb_pos / stride,
3743 ib_pos / sizeof(*indices), index_count, 0, 0);
3745 done:
3746 wined3d_mutex_unlock();
3747 return hr;
3750 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3751 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3752 WORD *indices, DWORD index_count, DWORD flags)
3754 return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3755 vertices, vertex_count, indices, index_count, flags);
3758 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3759 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3760 WORD *indices, DWORD index_count, DWORD flags)
3762 HRESULT hr;
3763 WORD old_fpucw;
3765 old_fpucw = d3d_fpu_setup();
3766 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3767 vertices, vertex_count, indices, index_count, flags);
3768 set_fpu_control_word(old_fpucw);
3770 return hr;
3773 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3774 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3775 WORD *indices, DWORD index_count, DWORD flags)
3777 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3779 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3780 "indices %p, index_count %u, flags %#x.\n",
3781 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3783 setup_lighting(device, fvf, flags);
3785 return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3786 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3789 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3790 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3791 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3793 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3794 DWORD fvf;
3796 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3797 "indices %p, index_count %u, flags %#x.\n",
3798 iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3800 switch (vertex_type)
3802 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3803 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3804 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3805 default:
3806 ERR("Unhandled vertex type %#x.\n", vertex_type);
3807 return DDERR_INVALIDPARAMS; /* Should never happen */
3810 return d3d_device3_DrawIndexedPrimitive(&device->IDirect3DDevice3_iface,
3811 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3814 /*****************************************************************************
3815 * IDirect3DDevice3::End
3817 * Ends a draw begun with IDirect3DDevice3::Begin or
3818 * IDirect3DDevice::BeginIndexed. The vertices specified with
3819 * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
3820 * the IDirect3DDevice3::DrawPrimitive method. So far only
3821 * non-indexed mode is supported
3823 * Version 2 and 3
3825 * Params:
3826 * Flags: Some flags, as usual. Don't know which are defined
3828 * Returns:
3829 * The return value of IDirect3DDevice3::DrawPrimitive
3831 *****************************************************************************/
3832 static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
3834 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3836 TRACE("iface %p, flags %#x.\n", iface, flags);
3838 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface, device->primitive_type,
3839 device->vertex_type, device->sysmem_vertex_buffer, device->nb_vertices, device->render_flags);
3842 static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
3844 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3846 TRACE("iface %p, flags %#x.\n", iface, flags);
3848 return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
3851 /*****************************************************************************
3852 * IDirect3DDevice7::SetClipStatus
3854 * Sets the clip status. This defines things as clipping conditions and
3855 * the extents of the clipping region.
3857 * Version 2, 3 and 7
3859 * Params:
3860 * ClipStatus:
3862 * Returns:
3863 * D3D_OK because it's a stub
3864 * (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3866 *****************************************************************************/
3867 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3869 FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3871 return D3D_OK;
3874 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3876 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3878 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3880 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3883 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3885 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3887 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3889 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3892 /*****************************************************************************
3893 * IDirect3DDevice7::GetClipStatus
3895 * Returns the clip status
3897 * Params:
3898 * ClipStatus: Address to write the clip status to
3900 * Returns:
3901 * D3D_OK because it's a stub
3903 *****************************************************************************/
3904 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3906 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3907 struct wined3d_viewport vp;
3909 FIXME("iface %p, clip_status %p stub.\n", iface, clip_status);
3911 vp = device->stateblock_state->viewport;
3912 clip_status->minx = vp.x;
3913 clip_status->maxx = vp.x + vp.width;
3914 clip_status->miny = vp.y;
3915 clip_status->maxy = vp.y + vp.height;
3916 clip_status->minz = 0.0f;
3917 clip_status->maxz = 0.0f;
3918 clip_status->dwFlags = D3DCLIPSTATUS_EXTENTS2;
3919 clip_status->dwStatus = 0;
3921 return D3D_OK;
3924 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3926 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3928 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3930 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3933 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3935 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3937 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3939 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3942 /*****************************************************************************
3943 * IDirect3DDevice::DrawPrimitiveStrided
3945 * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3947 * Version 3 and 7
3949 * Params:
3950 * PrimitiveType: The primitive type to draw
3951 * VertexType: The FVF description of the vertices to draw (for the stride??)
3952 * D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3953 * the vertex data locations
3954 * VertexCount: The number of vertices to draw
3955 * Flags: Some flags
3957 * Returns:
3958 * D3D_OK, because it's a stub
3959 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3961 *****************************************************************************/
3962 static void pack_strided_data(BYTE *dst, DWORD count, const D3DDRAWPRIMITIVESTRIDEDDATA *src, DWORD fvf)
3964 DWORD i, tex, offset;
3966 for (i = 0; i < count; i++)
3968 /* The contents of the strided data are determined by the fvf,
3969 * not by the members set in src. So it's valid
3970 * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3971 * not set in the fvf. */
3972 if (fvf & D3DFVF_POSITION_MASK)
3974 offset = i * src->position.dwStride;
3975 if (fvf & D3DFVF_XYZRHW)
3977 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 4 * sizeof(float));
3978 dst += 4 * sizeof(float);
3980 else
3982 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 3 * sizeof(float));
3983 dst += 3 * sizeof(float);
3987 if (fvf & D3DFVF_NORMAL)
3989 offset = i * src->normal.dwStride;
3990 memcpy(dst, ((BYTE *)src->normal.lpvData) + offset, 3 * sizeof(float));
3991 dst += 3 * sizeof(float);
3994 if (fvf & D3DFVF_DIFFUSE)
3996 offset = i * src->diffuse.dwStride;
3997 memcpy(dst, ((BYTE *)src->diffuse.lpvData) + offset, sizeof(DWORD));
3998 dst += sizeof(DWORD);
4001 if (fvf & D3DFVF_SPECULAR)
4003 offset = i * src->specular.dwStride;
4004 memcpy(dst, ((BYTE *)src->specular.lpvData) + offset, sizeof(DWORD));
4005 dst += sizeof(DWORD);
4008 for (tex = 0; tex < GET_TEXCOUNT_FROM_FVF(fvf); ++tex)
4010 DWORD attrib_count = GET_TEXCOORD_SIZE_FROM_FVF(fvf, tex);
4011 offset = i * src->textureCoords[tex].dwStride;
4012 memcpy(dst, ((BYTE *)src->textureCoords[tex].lpvData) + offset, attrib_count * sizeof(float));
4013 dst += attrib_count * sizeof(float);
4018 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
4019 DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data, DWORD vertex_count, DWORD flags)
4021 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4022 HRESULT hr;
4023 UINT dst_stride = get_flexible_vertex_size(fvf);
4024 UINT dst_size = dst_stride * vertex_count;
4025 struct wined3d_map_desc wined3d_map_desc;
4026 struct wined3d_box wined3d_box = {0};
4027 struct wined3d_resource *vb;
4028 UINT vb_pos, align;
4030 TRACE("iface %p, primitive_type %#x, fvf %#x, strided_data %p, vertex_count %u, flags %#x.\n",
4031 iface, primitive_type, fvf, strided_data, vertex_count, flags);
4033 if (!vertex_count)
4035 WARN("0 vertex count.\n");
4036 return D3D_OK;
4039 wined3d_mutex_lock();
4040 hr = d3d_device_prepare_vertex_buffer(device, dst_size);
4041 if (FAILED(hr))
4042 goto done;
4044 vb_pos = device->vertex_buffer_pos;
4045 align = vb_pos % dst_stride;
4046 if (align) align = dst_stride - align;
4047 if (vb_pos + dst_size + align > device->vertex_buffer_size)
4048 vb_pos = 0;
4049 else
4050 vb_pos += align;
4052 wined3d_box.left = vb_pos;
4053 wined3d_box.right = vb_pos + dst_size;
4054 vb = wined3d_buffer_get_resource(device->vertex_buffer);
4055 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
4056 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4057 goto done;
4058 pack_strided_data(wined3d_map_desc.data, vertex_count, strided_data, fvf);
4059 wined3d_resource_unmap(vb, 0);
4060 device->vertex_buffer_pos = vb_pos + dst_size;
4062 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, dst_stride);
4063 if (FAILED(hr))
4064 goto done;
4065 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4067 wined3d_device_context_set_primitive_type(device->immediate_context,
4068 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4069 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4070 d3d_device_sync_surfaces(device);
4071 wined3d_device_context_draw(device->immediate_context, vb_pos / dst_stride, vertex_count, 0, 0);
4073 done:
4074 wined3d_mutex_unlock();
4075 return hr;
4078 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4079 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4080 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4082 return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
4083 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4086 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4087 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4088 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4090 HRESULT hr;
4091 WORD old_fpucw;
4093 old_fpucw = d3d_fpu_setup();
4094 hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
4095 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4096 set_fpu_control_word(old_fpucw);
4098 return hr;
4101 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
4102 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4103 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4105 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4107 TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
4108 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4110 setup_lighting(device, VertexType, Flags);
4112 return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
4113 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4116 /*****************************************************************************
4117 * IDirect3DDevice7::DrawIndexedPrimitiveStrided
4119 * Draws primitives specified by strided data locations based on indices
4121 * Version 3 and 7
4123 * Params:
4124 * PrimitiveType:
4126 * Returns:
4127 * D3D_OK, because it's a stub
4128 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
4129 * (DDERR_INVALIDPARAMS if Indices is NULL)
4131 *****************************************************************************/
4132 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
4133 D3DPRIMITIVETYPE primitive_type, DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data,
4134 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4136 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4137 UINT vtx_dst_stride = get_flexible_vertex_size(fvf);
4138 UINT vtx_dst_size = vertex_count * vtx_dst_stride;
4139 UINT idx_size = index_count * sizeof(WORD);
4140 struct wined3d_map_desc wined3d_map_desc;
4141 struct wined3d_box wined3d_box = {0};
4142 struct wined3d_resource *ib, *vb;
4143 UINT vb_pos, align;
4144 UINT ib_pos;
4145 HRESULT hr;
4147 TRACE("iface %p, primitive_type %#x, fvf %#x, strided_data %p, "
4148 "vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4149 iface, primitive_type, fvf, strided_data, vertex_count, indices, index_count, flags);
4151 if (!vertex_count || !index_count)
4153 WARN("0 vertex or index count.\n");
4154 return D3D_OK;
4157 wined3d_mutex_lock();
4159 hr = d3d_device_prepare_vertex_buffer(device, vtx_dst_size);
4160 if (FAILED(hr))
4161 goto done;
4163 vb_pos = device->vertex_buffer_pos;
4164 align = vb_pos % vtx_dst_stride;
4165 if (align) align = vtx_dst_stride - align;
4166 if (vb_pos + vtx_dst_size + align > device->vertex_buffer_size)
4167 vb_pos = 0;
4168 else
4169 vb_pos += align;
4171 wined3d_box.left = vb_pos;
4172 wined3d_box.right = vb_pos + vtx_dst_size;
4173 vb = wined3d_buffer_get_resource(device->vertex_buffer);
4174 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
4175 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4176 goto done;
4177 pack_strided_data(wined3d_map_desc.data, vertex_count, strided_data, fvf);
4178 wined3d_resource_unmap(vb, 0);
4179 device->vertex_buffer_pos = vb_pos + vtx_dst_size;
4181 hr = d3d_device_prepare_index_buffer(device, idx_size);
4182 if (FAILED(hr))
4183 goto done;
4184 ib_pos = device->index_buffer_pos;
4185 if (device->index_buffer_size - idx_size < ib_pos)
4186 ib_pos = 0;
4188 wined3d_box.left = ib_pos;
4189 wined3d_box.right = ib_pos + idx_size;
4190 ib = wined3d_buffer_get_resource(device->index_buffer);
4191 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
4192 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4193 goto done;
4194 memcpy(wined3d_map_desc.data, indices, idx_size);
4195 wined3d_resource_unmap(ib, 0);
4196 device->index_buffer_pos = ib_pos + idx_size;
4198 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, vtx_dst_stride);
4199 if (FAILED(hr))
4200 goto done;
4201 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
4203 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4204 wined3d_device_context_set_primitive_type(device->immediate_context,
4205 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4206 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4207 d3d_device_sync_surfaces(device);
4208 wined3d_device_context_draw_indexed(device->immediate_context,
4209 vb_pos / vtx_dst_stride, ib_pos / sizeof(WORD), index_count, 0, 0);
4211 done:
4212 wined3d_mutex_unlock();
4213 return hr;
4216 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4217 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4218 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4219 WORD *Indices, DWORD IndexCount, DWORD Flags)
4221 return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4222 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4225 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4226 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4227 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4228 WORD *Indices, DWORD IndexCount, DWORD Flags)
4230 HRESULT hr;
4231 WORD old_fpucw;
4233 old_fpucw = d3d_fpu_setup();
4234 hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4235 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4236 set_fpu_control_word(old_fpucw);
4238 return hr;
4241 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4242 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4243 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4244 DWORD IndexCount, DWORD Flags)
4246 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4248 TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4249 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4251 setup_lighting(device, VertexType, Flags);
4253 return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
4254 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4257 /*****************************************************************************
4258 * IDirect3DDevice7::DrawPrimitiveVB
4260 * Draws primitives from a vertex buffer to the screen.
4262 * Version 3 and 7
4264 * Params:
4265 * PrimitiveType: Type of primitive to be rendered.
4266 * D3DVertexBuf: Source Vertex Buffer
4267 * StartVertex: Index of the first vertex from the buffer to be rendered
4268 * NumVertices: Number of vertices to be rendered
4269 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4271 * Return values
4272 * D3D_OK on success
4273 * DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4275 *****************************************************************************/
4276 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
4277 IDirect3DVertexBuffer7 *vb, DWORD start_vertex, DWORD vertex_count, DWORD flags)
4279 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4280 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4281 struct wined3d_resource *wined3d_resource;
4282 struct wined3d_map_desc wined3d_map_desc;
4283 struct wined3d_box wined3d_box = {0};
4284 DWORD stride;
4285 HRESULT hr;
4287 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4288 iface, primitive_type, vb, start_vertex, vertex_count, flags);
4290 if (!vertex_count)
4292 WARN("0 vertex count.\n");
4293 return D3D_OK;
4296 vb_impl->discarded = false;
4298 stride = get_flexible_vertex_size(vb_impl->fvf);
4300 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4302 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawPrimitive().\n");
4303 wined3d_mutex_lock();
4304 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4305 wined3d_box.left = start_vertex * stride;
4306 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4307 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4308 &wined3d_box, WINED3D_MAP_READ)))
4310 wined3d_mutex_unlock();
4311 return D3DERR_VERTEXBUFFERLOCKED;
4313 hr = d3d_device7_DrawPrimitive(iface, primitive_type, vb_impl->fvf, wined3d_map_desc.data,
4314 vertex_count, flags);
4315 wined3d_resource_unmap(wined3d_resource, 0);
4316 wined3d_mutex_unlock();
4317 return hr;
4320 wined3d_mutex_lock();
4321 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4322 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4323 0, vb_impl->wined3d_buffer, 0, stride)))
4325 WARN("Failed to set stream source, hr %#x.\n", hr);
4326 wined3d_mutex_unlock();
4327 return hr;
4330 /* Now draw the primitives */
4331 wined3d_device_context_set_primitive_type(device->immediate_context,
4332 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4333 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4334 d3d_device_sync_surfaces(device);
4335 wined3d_device_context_draw(device->immediate_context, start_vertex, vertex_count, 0, 0);
4337 wined3d_mutex_unlock();
4339 return hr;
4342 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4343 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4345 return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4348 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4349 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4351 HRESULT hr;
4352 WORD old_fpucw;
4354 old_fpucw = d3d_fpu_setup();
4355 hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4356 set_fpu_control_word(old_fpucw);
4358 return hr;
4361 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4362 IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4364 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4365 struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)D3DVertexBuf);
4367 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4368 iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4370 setup_lighting(device, vb->fvf, Flags);
4372 return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4373 PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4376 /*****************************************************************************
4377 * IDirect3DDevice7::DrawIndexedPrimitiveVB
4379 * Draws primitives from a vertex buffer to the screen
4381 * Params:
4382 * PrimitiveType: Type of primitive to be rendered.
4383 * D3DVertexBuf: Source Vertex Buffer
4384 * StartVertex: Index of the first vertex from the buffer to be rendered
4385 * NumVertices: Number of vertices to be rendered
4386 * Indices: Array of DWORDs used to index into the Vertices
4387 * IndexCount: Number of indices in Indices
4388 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4390 * Return values
4392 *****************************************************************************/
4393 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4394 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer7 *vb,
4395 DWORD start_vertex, DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4397 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4398 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4399 DWORD stride = get_flexible_vertex_size(vb_impl->fvf);
4400 struct wined3d_resource *wined3d_resource;
4401 struct wined3d_map_desc wined3d_map_desc;
4402 struct wined3d_box wined3d_box = {0};
4403 struct wined3d_resource *ib;
4404 HRESULT hr;
4405 UINT ib_pos;
4407 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, "
4408 "vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4409 iface, primitive_type, vb, start_vertex, vertex_count, indices, index_count, flags);
4411 if (!vertex_count || !index_count)
4413 WARN("0 vertex or index count.\n");
4414 return D3D_OK;
4417 vb_impl->discarded = false;
4419 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4421 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawIndexedPrimitive().\n");
4422 wined3d_mutex_lock();
4423 wined3d_box.left = start_vertex * stride;
4424 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4425 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4426 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4427 &wined3d_box, WINED3D_MAP_READ)))
4429 wined3d_mutex_unlock();
4430 return D3DERR_VERTEXBUFFERLOCKED;
4432 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, vb_impl->fvf,
4433 wined3d_map_desc.data, vertex_count, indices, index_count, flags);
4434 wined3d_resource_unmap(wined3d_resource, 0);
4435 wined3d_mutex_unlock();
4436 return hr;
4439 /* Steps:
4440 * 1) Upload the indices to the index buffer
4441 * 2) Set the index source
4442 * 3) Set the Vertex Buffer as the Stream source
4443 * 4) Call wined3d_device_context_draw_indexed()
4446 wined3d_mutex_lock();
4448 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4450 hr = d3d_device_prepare_index_buffer(device, index_count * sizeof(WORD));
4451 if (FAILED(hr))
4453 wined3d_mutex_unlock();
4454 return hr;
4456 ib_pos = device->index_buffer_pos;
4458 if (device->index_buffer_size - index_count * sizeof(WORD) < ib_pos)
4459 ib_pos = 0;
4461 /* Copy the index stream into the index buffer. */
4462 wined3d_box.left = ib_pos;
4463 wined3d_box.right = ib_pos + index_count * sizeof(WORD);
4464 ib = wined3d_buffer_get_resource(device->index_buffer);
4465 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
4466 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4468 ERR("Failed to map buffer, hr %#x.\n", hr);
4469 wined3d_mutex_unlock();
4470 return hr;
4472 memcpy(wined3d_map_desc.data, indices, index_count * sizeof(WORD));
4473 wined3d_resource_unmap(ib, 0);
4474 device->index_buffer_pos = ib_pos + index_count * sizeof(WORD);
4476 /* Set the index stream */
4477 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
4479 /* Set the vertex stream source */
4480 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4481 0, vb_impl->wined3d_buffer, 0, stride)))
4483 ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", device, hr);
4484 wined3d_mutex_unlock();
4485 return hr;
4488 wined3d_device_context_set_primitive_type(device->immediate_context,
4489 wined3d_primitive_type_from_ddraw(primitive_type), 0);
4490 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4491 d3d_device_sync_surfaces(device);
4492 wined3d_device_context_draw_indexed(device->immediate_context, start_vertex,
4493 ib_pos / sizeof(WORD), index_count, 0, 0);
4495 wined3d_mutex_unlock();
4497 return hr;
4500 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4501 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4502 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4504 return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4505 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4508 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4509 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4510 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4512 HRESULT hr;
4513 WORD old_fpucw;
4515 old_fpucw = d3d_fpu_setup();
4516 hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4517 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4518 set_fpu_control_word(old_fpucw);
4520 return hr;
4523 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4524 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer *vertex_buffer,
4525 WORD *indices, DWORD index_count, DWORD flags)
4527 struct d3d_vertex_buffer *vb =
4528 unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)vertex_buffer);
4529 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4530 DWORD stride;
4532 TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4533 iface, primitive_type, vertex_buffer, indices, index_count, flags);
4535 setup_lighting(device, vb->fvf, flags);
4537 if (!(stride = get_flexible_vertex_size(vb->fvf)))
4538 return D3D_OK;
4540 return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, primitive_type,
4541 &vb->IDirect3DVertexBuffer7_iface, 0, vb->size / stride, indices, index_count, flags);
4544 /*****************************************************************************
4545 * IDirect3DDevice7::ComputeSphereVisibility
4547 * Calculates the visibility of spheres in the current viewport. The spheres
4548 * are passed in the Centers and Radii arrays, the results are passed back
4549 * in the ReturnValues array. Return values are either completely visible,
4550 * partially visible or completely invisible.
4551 * The return value consists of a combination of D3DCLIP_* flags, or is
4552 * 0 if the sphere is completely visible (according to the SDK, not checked)
4554 * Version 3 and 7
4556 * Params:
4557 * Centers: Array containing the sphere centers
4558 * Radii: Array containing the sphere radii
4559 * NumSpheres: The number of centers and radii in the arrays
4560 * Flags: Some flags
4561 * ReturnValues: Array to write the results to
4563 * Returns:
4564 * D3D_OK
4565 * (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4566 * (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4567 * is singular)
4569 *****************************************************************************/
4571 static DWORD in_plane(UINT idx, struct wined3d_vec4 p, D3DVECTOR center, D3DVALUE radius, BOOL equality)
4573 float distance, norm;
4575 norm = sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
4576 distance = (p.x * center.u1.x + p.y * center.u2.y + p.z * center.u3.z + p.w) / norm;
4578 if (equality)
4580 if (fabs(distance) <= radius)
4581 return D3DSTATUS_CLIPUNIONLEFT << idx;
4582 if (distance <= -radius)
4583 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4585 else
4587 if (fabs(distance) < radius)
4588 return D3DSTATUS_CLIPUNIONLEFT << idx;
4589 if (distance < -radius)
4590 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4592 return 0;
4595 static void prepare_clip_space_planes(struct d3d_device *device, struct wined3d_vec4 *plane)
4597 const struct wined3d_stateblock_state *state;
4598 struct wined3d_matrix m;
4600 /* We want the wined3d matrices since those include the legacy viewport
4601 * transformation. */
4602 wined3d_mutex_lock();
4603 state = device->stateblock_state;
4604 multiply_matrix(&m, &state->transforms[WINED3D_TS_VIEW], &state->transforms[WINED3D_TS_WORLD]);
4605 multiply_matrix(&m, &state->transforms[WINED3D_TS_PROJECTION], &m);
4606 wined3d_mutex_unlock();
4608 /* Left plane. */
4609 plane[0].x = m._14 + m._11;
4610 plane[0].y = m._24 + m._21;
4611 plane[0].z = m._34 + m._31;
4612 plane[0].w = m._44 + m._41;
4614 /* Right plane. */
4615 plane[1].x = m._14 - m._11;
4616 plane[1].y = m._24 - m._21;
4617 plane[1].z = m._34 - m._31;
4618 plane[1].w = m._44 - m._41;
4620 /* Top plane. */
4621 plane[2].x = m._14 - m._12;
4622 plane[2].y = m._24 - m._22;
4623 plane[2].z = m._34 - m._32;
4624 plane[2].w = m._44 - m._42;
4626 /* Bottom plane. */
4627 plane[3].x = m._14 + m._12;
4628 plane[3].y = m._24 + m._22;
4629 plane[3].z = m._34 + m._32;
4630 plane[3].w = m._44 + m._42;
4632 /* Front plane. */
4633 plane[4].x = m._13;
4634 plane[4].y = m._23;
4635 plane[4].z = m._33;
4636 plane[4].w = m._43;
4638 /* Back plane. */
4639 plane[5].x = m._14 - m._13;
4640 plane[5].y = m._24 - m._23;
4641 plane[5].z = m._34 - m._33;
4642 plane[5].w = m._44 - m._43;
4645 static void compute_sphere_visibility(const struct wined3d_vec4 *planes, DWORD enabled_planes, BOOL equality,
4646 const D3DVECTOR *centres, const D3DVALUE *radii, unsigned int sphere_count, DWORD *return_values)
4648 unsigned int mask, i, j;
4650 memset(return_values, 0, sphere_count * sizeof(*return_values));
4651 for (i = 0; i < sphere_count; ++i)
4653 mask = enabled_planes;
4654 while (mask)
4656 j = wined3d_bit_scan(&mask);
4657 return_values[i] |= in_plane(j, planes[j], centres[i], radii[i], equality);
4662 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4663 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4665 struct wined3d_vec4 plane[12];
4666 DWORD enabled_planes = 0x3f;
4667 DWORD user_clip_planes;
4668 UINT j;
4670 TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4671 iface, centers, radii, sphere_count, flags, return_values);
4673 prepare_clip_space_planes(impl_from_IDirect3DDevice7(iface), plane);
4675 IDirect3DDevice7_GetRenderState(iface, D3DRENDERSTATE_CLIPPLANEENABLE, &user_clip_planes);
4676 enabled_planes |= user_clip_planes << 6;
4677 for (j = 6; j < 12; ++j)
4678 IDirect3DDevice7_GetClipPlane(iface, j - 6, (D3DVALUE *)&plane[j]);
4680 compute_sphere_visibility(plane, enabled_planes, FALSE, centers, radii, sphere_count, return_values);
4681 return D3D_OK;
4684 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4685 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4687 static const DWORD enabled_planes = 0x3f;
4688 struct wined3d_vec4 plane[6];
4689 unsigned int i, j;
4691 TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4692 iface, centers, radii, sphere_count, flags, return_values);
4694 prepare_clip_space_planes(impl_from_IDirect3DDevice3(iface), plane);
4696 compute_sphere_visibility(plane, enabled_planes, TRUE, centers, radii, sphere_count, return_values);
4697 for (i = 0; i < sphere_count; ++i)
4699 BOOL intersect_frustum = FALSE, outside_frustum = FALSE;
4700 DWORD d3d7_result = return_values[i];
4702 return_values[i] = 0;
4704 for (j = 0; j < 6; ++j)
4706 DWORD clip = (d3d7_result >> j) & (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT);
4708 if (clip == D3DSTATUS_CLIPUNIONLEFT)
4710 return_values[i] |= D3DVIS_INTERSECT_LEFT << j * 2;
4711 intersect_frustum = TRUE;
4713 else if (clip)
4715 return_values[i] |= D3DVIS_OUTSIDE_LEFT << j * 2;
4716 outside_frustum = TRUE;
4719 if (outside_frustum)
4720 return_values[i] |= D3DVIS_OUTSIDE_FRUSTUM;
4721 else if (intersect_frustum)
4722 return_values[i] |= D3DVIS_INTERSECT_FRUSTUM;
4724 return D3D_OK;
4727 /*****************************************************************************
4728 * IDirect3DDevice7::GetTexture
4730 * Returns the texture interface handle assigned to a texture stage.
4731 * The returned texture is AddRefed. This is taken from old ddraw,
4732 * not checked in Windows.
4734 * Version 3 and 7
4736 * Params:
4737 * Stage: Texture stage to read the texture from
4738 * Texture: Address to store the interface pointer at
4740 * Returns:
4741 * D3D_OK on success
4742 * DDERR_INVALIDPARAMS if Texture is NULL
4744 *****************************************************************************/
4745 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4746 DWORD stage, IDirectDrawSurface7 **texture)
4748 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4749 struct wined3d_texture *wined3d_texture;
4750 struct ddraw_texture *ddraw_texture;
4752 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4754 if (!texture)
4755 return DDERR_INVALIDPARAMS;
4757 if (stage >= DDRAW_MAX_TEXTURES)
4759 WARN("Invalid stage %u.\n", stage);
4760 *texture = NULL;
4761 return D3D_OK;
4764 wined3d_mutex_lock();
4765 if (!(wined3d_texture = device->stateblock_state->textures[stage]))
4767 *texture = NULL;
4768 wined3d_mutex_unlock();
4769 return D3D_OK;
4772 ddraw_texture = wined3d_texture_get_parent(wined3d_texture);
4773 *texture = &ddraw_texture->root->IDirectDrawSurface7_iface;
4774 IDirectDrawSurface7_AddRef(*texture);
4775 wined3d_mutex_unlock();
4777 return D3D_OK;
4780 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4781 DWORD stage, IDirectDrawSurface7 **Texture)
4783 return d3d_device7_GetTexture(iface, stage, Texture);
4786 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4787 DWORD stage, IDirectDrawSurface7 **Texture)
4789 HRESULT hr;
4790 WORD old_fpucw;
4792 old_fpucw = d3d_fpu_setup();
4793 hr = d3d_device7_GetTexture(iface, stage, Texture);
4794 set_fpu_control_word(old_fpucw);
4796 return hr;
4799 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4801 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4802 struct ddraw_surface *ret_val_impl;
4803 HRESULT ret;
4804 IDirectDrawSurface7 *ret_val;
4806 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4808 ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4810 ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4811 *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4813 TRACE("Returning texture %p.\n", *Texture2);
4815 return ret;
4818 /*****************************************************************************
4819 * IDirect3DDevice7::SetTexture
4821 * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4823 * Version 3 and 7
4825 * Params:
4826 * Stage: The stage to assign the texture to
4827 * Texture: Interface pointer to the texture surface
4829 * Returns
4830 * D3D_OK on success
4832 *****************************************************************************/
4833 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4834 DWORD stage, IDirectDrawSurface7 *texture)
4836 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4837 struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4838 struct wined3d_texture *wined3d_texture = NULL;
4840 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4842 if (surf && (surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE))
4843 wined3d_texture = surf->draw_texture ? surf->draw_texture : surf->wined3d_texture;
4845 wined3d_mutex_lock();
4846 wined3d_stateblock_set_texture(device->update_state, stage, wined3d_texture);
4847 wined3d_mutex_unlock();
4849 return D3D_OK;
4852 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4853 DWORD stage, IDirectDrawSurface7 *texture)
4855 return d3d_device7_SetTexture(iface, stage, texture);
4858 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4859 DWORD stage, IDirectDrawSurface7 *texture)
4861 HRESULT hr;
4862 WORD old_fpucw;
4864 old_fpucw = d3d_fpu_setup();
4865 hr = d3d_device7_SetTexture(iface, stage, texture);
4866 set_fpu_control_word(old_fpucw);
4868 return hr;
4871 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4872 DWORD stage, IDirect3DTexture2 *texture)
4874 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4875 struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4876 struct wined3d_texture *wined3d_texture = NULL;
4878 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4880 wined3d_mutex_lock();
4882 if (tex && ((tex->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE) || !device->hardware_device))
4883 wined3d_texture = tex->draw_texture ? tex->draw_texture : tex->wined3d_texture;
4885 wined3d_stateblock_set_texture(device->state, stage, wined3d_texture);
4886 fixup_texture_alpha_op(device);
4888 wined3d_mutex_unlock();
4890 return D3D_OK;
4893 static const struct tss_lookup
4895 BOOL sampler_state;
4896 union
4898 enum wined3d_texture_stage_state texture_state;
4899 enum wined3d_sampler_state sampler_state;
4900 } u;
4902 tss_lookup[] =
4904 {FALSE, {WINED3D_TSS_INVALID}}, /* 0, unused */
4905 {FALSE, {WINED3D_TSS_COLOR_OP}}, /* 1, D3DTSS_COLOROP */
4906 {FALSE, {WINED3D_TSS_COLOR_ARG1}}, /* 2, D3DTSS_COLORARG1 */
4907 {FALSE, {WINED3D_TSS_COLOR_ARG2}}, /* 3, D3DTSS_COLORARG2 */
4908 {FALSE, {WINED3D_TSS_ALPHA_OP}}, /* 4, D3DTSS_ALPHAOP */
4909 {FALSE, {WINED3D_TSS_ALPHA_ARG1}}, /* 5, D3DTSS_ALPHAARG1 */
4910 {FALSE, {WINED3D_TSS_ALPHA_ARG2}}, /* 6, D3DTSS_ALPHAARG2 */
4911 {FALSE, {WINED3D_TSS_BUMPENV_MAT00}}, /* 7, D3DTSS_BUMPENVMAT00 */
4912 {FALSE, {WINED3D_TSS_BUMPENV_MAT01}}, /* 8, D3DTSS_BUMPENVMAT01 */
4913 {FALSE, {WINED3D_TSS_BUMPENV_MAT10}}, /* 9, D3DTSS_BUMPENVMAT10 */
4914 {FALSE, {WINED3D_TSS_BUMPENV_MAT11}}, /* 10, D3DTSS_BUMPENVMAT11 */
4915 {FALSE, {WINED3D_TSS_TEXCOORD_INDEX}}, /* 11, D3DTSS_TEXCOORDINDEX */
4916 {TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 12, D3DTSS_ADDRESS */
4917 {TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 13, D3DTSS_ADDRESSU */
4918 {TRUE, {WINED3D_SAMP_ADDRESS_V}}, /* 14, D3DTSS_ADDRESSV */
4919 {TRUE, {WINED3D_SAMP_BORDER_COLOR}}, /* 15, D3DTSS_BORDERCOLOR */
4920 {TRUE, {WINED3D_SAMP_MAG_FILTER}}, /* 16, D3DTSS_MAGFILTER */
4921 {TRUE, {WINED3D_SAMP_MIN_FILTER}}, /* 17, D3DTSS_MINFILTER */
4922 {TRUE, {WINED3D_SAMP_MIP_FILTER}}, /* 18, D3DTSS_MIPFILTER */
4923 {TRUE, {WINED3D_SAMP_MIPMAP_LOD_BIAS}}, /* 19, D3DTSS_MIPMAPLODBIAS */
4924 {TRUE, {WINED3D_SAMP_MAX_MIP_LEVEL}}, /* 20, D3DTSS_MAXMIPLEVEL */
4925 {TRUE, {WINED3D_SAMP_MAX_ANISOTROPY}}, /* 21, D3DTSS_MAXANISOTROPY */
4926 {FALSE, {WINED3D_TSS_BUMPENV_LSCALE}}, /* 22, D3DTSS_BUMPENVLSCALE */
4927 {FALSE, {WINED3D_TSS_BUMPENV_LOFFSET}}, /* 23, D3DTSS_BUMPENVLOFFSET */
4928 {FALSE, {WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS}}, /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4931 /*****************************************************************************
4932 * IDirect3DDevice7::GetTextureStageState
4934 * Retrieves a state from a texture stage.
4936 * Version 3 and 7
4938 * Params:
4939 * Stage: The stage to retrieve the state from
4940 * TexStageStateType: The state type to retrieve
4941 * State: Address to store the state's value at
4943 * Returns:
4944 * D3D_OK on success
4945 * DDERR_INVALIDPARAMS if State is NULL
4947 *****************************************************************************/
4948 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4949 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4951 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4952 const struct wined3d_stateblock_state *device_state;
4953 const struct tss_lookup *l;
4955 TRACE("iface %p, stage %u, state %#x, value %p.\n",
4956 iface, stage, state, value);
4958 if (!value)
4959 return DDERR_INVALIDPARAMS;
4961 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4963 WARN("Invalid state %#x passed.\n", state);
4964 return DD_OK;
4967 if (stage >= DDRAW_MAX_TEXTURES)
4969 WARN("Invalid stage %u.\n", stage);
4970 *value = 0;
4971 return D3D_OK;
4974 l = &tss_lookup[state];
4976 wined3d_mutex_lock();
4978 device_state = device->stateblock_state;
4980 if (l->sampler_state)
4982 *value = device_state->sampler_states[stage][l->u.sampler_state];
4984 switch (state)
4986 /* Mipfilter is a sampler state with different values */
4987 case D3DTSS_MIPFILTER:
4989 switch (*value)
4991 case WINED3D_TEXF_NONE:
4992 *value = D3DTFP_NONE;
4993 break;
4994 case WINED3D_TEXF_POINT:
4995 *value = D3DTFP_POINT;
4996 break;
4997 case WINED3D_TEXF_LINEAR:
4998 *value = D3DTFP_LINEAR;
4999 break;
5000 default:
5001 ERR("Unexpected mipfilter value %#x.\n", *value);
5002 *value = D3DTFP_NONE;
5003 break;
5005 break;
5008 /* Magfilter has slightly different values */
5009 case D3DTSS_MAGFILTER:
5011 switch (*value)
5013 case WINED3D_TEXF_POINT:
5014 *value = D3DTFG_POINT;
5015 break;
5016 case WINED3D_TEXF_LINEAR:
5017 *value = D3DTFG_LINEAR;
5018 break;
5019 case WINED3D_TEXF_ANISOTROPIC:
5020 *value = D3DTFG_ANISOTROPIC;
5021 break;
5022 case WINED3D_TEXF_FLAT_CUBIC:
5023 *value = D3DTFG_FLATCUBIC;
5024 break;
5025 case WINED3D_TEXF_GAUSSIAN_CUBIC:
5026 *value = D3DTFG_GAUSSIANCUBIC;
5027 break;
5028 default:
5029 ERR("Unexpected wined3d mag filter value %#x.\n", *value);
5030 *value = D3DTFG_POINT;
5031 break;
5033 break;
5036 default:
5037 break;
5040 else
5042 *value = device_state->texture_states[stage][l->u.texture_state];
5045 wined3d_mutex_unlock();
5047 return D3D_OK;
5050 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5051 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5053 return d3d_device7_GetTextureStageState(iface, stage, state, value);
5056 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5057 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5059 HRESULT hr;
5060 WORD old_fpucw;
5062 old_fpucw = d3d_fpu_setup();
5063 hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
5064 set_fpu_control_word(old_fpucw);
5066 return hr;
5069 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
5070 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5072 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5074 TRACE("iface %p, stage %u, state %#x, value %p.\n",
5075 iface, stage, state, value);
5077 return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5080 /*****************************************************************************
5081 * IDirect3DDevice7::SetTextureStageState
5083 * Sets a texture stage state. Some stage types need to be handled specially,
5084 * because they do not exist in WineD3D and were moved to another place
5086 * Version 3 and 7
5088 * Params:
5089 * Stage: The stage to modify
5090 * TexStageStateType: The state to change
5091 * State: The new value for the state
5093 * Returns:
5094 * D3D_OK on success
5096 *****************************************************************************/
5097 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
5098 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5100 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5101 const struct tss_lookup *l;
5103 TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5104 iface, stage, state, value);
5106 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
5108 WARN("Invalid state %#x passed.\n", state);
5109 return DD_OK;
5112 l = &tss_lookup[state];
5114 wined3d_mutex_lock();
5116 if (l->sampler_state)
5118 switch (state)
5120 /* Mipfilter is a sampler state with different values */
5121 case D3DTSS_MIPFILTER:
5123 switch (value)
5125 case D3DTFP_NONE:
5126 value = WINED3D_TEXF_NONE;
5127 break;
5128 case D3DTFP_POINT:
5129 value = WINED3D_TEXF_POINT;
5130 break;
5131 case 0: /* Unchecked */
5132 case D3DTFP_LINEAR:
5133 value = WINED3D_TEXF_LINEAR;
5134 break;
5135 default:
5136 ERR("Unexpected mipfilter value %#x.\n", value);
5137 value = WINED3D_TEXF_NONE;
5138 break;
5140 break;
5143 /* Magfilter has slightly different values */
5144 case D3DTSS_MAGFILTER:
5146 switch (value)
5148 case D3DTFG_POINT:
5149 value = WINED3D_TEXF_POINT;
5150 break;
5151 case D3DTFG_LINEAR:
5152 value = WINED3D_TEXF_LINEAR;
5153 break;
5154 case D3DTFG_FLATCUBIC:
5155 value = WINED3D_TEXF_FLAT_CUBIC;
5156 break;
5157 case D3DTFG_GAUSSIANCUBIC:
5158 value = WINED3D_TEXF_GAUSSIAN_CUBIC;
5159 break;
5160 case D3DTFG_ANISOTROPIC:
5161 value = WINED3D_TEXF_ANISOTROPIC;
5162 break;
5163 default:
5164 ERR("Unexpected d3d7 mag filter value %#x.\n", value);
5165 value = WINED3D_TEXF_POINT;
5166 break;
5168 break;
5171 case D3DTSS_ADDRESS:
5172 wined3d_stateblock_set_sampler_state(device->state, stage, WINED3D_SAMP_ADDRESS_V, value);
5173 break;
5175 default:
5176 break;
5179 wined3d_stateblock_set_sampler_state(device->state, stage, l->u.sampler_state, value);
5181 else
5182 wined3d_stateblock_set_texture_stage_state(device->update_state, stage, l->u.texture_state, value);
5184 wined3d_mutex_unlock();
5186 return D3D_OK;
5189 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5190 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5192 return d3d_device7_SetTextureStageState(iface, stage, state, value);
5195 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5196 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5198 HRESULT hr;
5199 WORD old_fpucw;
5201 old_fpucw = d3d_fpu_setup();
5202 hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
5203 set_fpu_control_word(old_fpucw);
5205 return hr;
5208 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
5209 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5211 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5212 DWORD old_value;
5213 HRESULT hr;
5215 TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5216 iface, stage, state, value);
5218 /* Tests show that legacy texture blending is not reset if the texture stage state
5219 * value is unchanged. */
5220 if (FAILED(hr = IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface,
5221 stage, state, &old_value)))
5222 return hr;
5224 if (old_value == value)
5226 TRACE("Application is setting the same value over, nothing to do.\n");
5227 return D3D_OK;
5230 device->legacyTextureBlending = FALSE;
5232 return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5235 /*****************************************************************************
5236 * IDirect3DDevice7::ValidateDevice
5238 * SDK: "Reports the device's ability to render the currently set
5239 * texture-blending operations in a single pass". Whatever that means
5240 * exactly...
5242 * Version 3 and 7
5244 * Params:
5245 * NumPasses: Address to write the number of necessary passes for the
5246 * desired effect to.
5248 * Returns:
5249 * D3D_OK on success
5251 *****************************************************************************/
5252 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
5254 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5255 HRESULT hr;
5257 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5259 wined3d_mutex_lock();
5260 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5261 hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
5262 wined3d_mutex_unlock();
5264 return hr;
5267 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
5269 return d3d_device7_ValidateDevice(iface, pass_count);
5272 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
5274 HRESULT hr;
5275 WORD old_fpucw;
5277 old_fpucw = d3d_fpu_setup();
5278 hr = d3d_device7_ValidateDevice(iface, pass_count);
5279 set_fpu_control_word(old_fpucw);
5281 return hr;
5284 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
5286 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5288 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5290 return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
5293 /*****************************************************************************
5294 * IDirect3DDevice7::Clear
5296 * Fills the render target, the z buffer and the stencil buffer with a
5297 * clear color / value
5299 * Version 7 only
5301 * Params:
5302 * Count: Number of rectangles in Rects must be 0 if Rects is NULL
5303 * Rects: Rectangles to clear. If NULL, the whole surface is cleared
5304 * Flags: Some flags, as usual
5305 * Color: Clear color for the render target
5306 * Z: Clear value for the Z buffer
5307 * Stencil: Clear value to store in each stencil buffer entry
5309 * Returns:
5310 * D3D_OK on success
5312 *****************************************************************************/
5313 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
5314 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5316 const struct wined3d_color c =
5318 ((color >> 16) & 0xff) / 255.0f,
5319 ((color >> 8) & 0xff) / 255.0f,
5320 (color & 0xff) / 255.0f,
5321 ((color >> 24) & 0xff) / 255.0f,
5323 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5324 HRESULT hr;
5326 TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5327 iface, count, rects, flags, color, z, stencil);
5329 if (count && !rects)
5331 WARN("count %u with NULL rects.\n", count);
5332 count = 0;
5335 wined3d_mutex_lock();
5336 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5337 d3d_device_sync_rendertarget(device);
5338 hr = wined3d_device_clear(device->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5339 wined3d_mutex_unlock();
5341 return hr;
5344 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
5345 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5347 return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5350 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
5351 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5353 HRESULT hr;
5354 WORD old_fpucw;
5356 old_fpucw = d3d_fpu_setup();
5357 hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5358 set_fpu_control_word(old_fpucw);
5360 return hr;
5363 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5365 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5366 struct wined3d_sub_resource_desc rt_desc;
5367 struct wined3d_rendertarget_view *rtv;
5368 struct ddraw_surface *surface;
5369 struct wined3d_viewport vp;
5371 TRACE("iface %p, viewport %p.\n", iface, viewport);
5373 if (!viewport)
5374 return DDERR_INVALIDPARAMS;
5376 wined3d_mutex_lock();
5377 if (!(rtv = wined3d_device_context_get_rendertarget_view(device->immediate_context, 0)))
5379 wined3d_mutex_unlock();
5380 return DDERR_INVALIDCAPS;
5382 surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
5383 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc);
5385 if (!wined3d_bound_range(viewport->dwX, viewport->dwWidth, rt_desc.width)
5386 || !wined3d_bound_range(viewport->dwY, viewport->dwHeight, rt_desc.height))
5388 WARN("Invalid viewport, returning E_INVALIDARG.\n");
5389 wined3d_mutex_unlock();
5390 return E_INVALIDARG;
5393 vp.x = viewport->dwX;
5394 vp.y = viewport->dwY;
5395 vp.width = viewport->dwWidth;
5396 vp.height = viewport->dwHeight;
5397 vp.min_z = viewport->dvMinZ;
5398 vp.max_z = viewport->dvMaxZ;
5400 wined3d_stateblock_set_viewport(device->update_state, &vp);
5401 wined3d_mutex_unlock();
5403 return D3D_OK;
5406 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5408 return d3d_device7_SetViewport(iface, viewport);
5411 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5413 HRESULT hr;
5414 WORD old_fpucw;
5416 old_fpucw = d3d_fpu_setup();
5417 hr = d3d_device7_SetViewport(iface, viewport);
5418 set_fpu_control_word(old_fpucw);
5420 return hr;
5423 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5425 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5426 struct wined3d_viewport wined3d_viewport;
5428 TRACE("iface %p, viewport %p.\n", iface, viewport);
5430 if (!viewport)
5431 return DDERR_INVALIDPARAMS;
5433 wined3d_mutex_lock();
5434 wined3d_viewport = device->stateblock_state->viewport;
5435 wined3d_mutex_unlock();
5437 viewport->dwX = wined3d_viewport.x;
5438 viewport->dwY = wined3d_viewport.y;
5439 viewport->dwWidth = wined3d_viewport.width;
5440 viewport->dwHeight = wined3d_viewport.height;
5441 viewport->dvMinZ = wined3d_viewport.min_z;
5442 viewport->dvMaxZ = wined3d_viewport.max_z;
5444 return D3D_OK;
5447 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5449 return d3d_device7_GetViewport(iface, viewport);
5452 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5454 HRESULT hr;
5455 WORD old_fpucw;
5457 old_fpucw = d3d_fpu_setup();
5458 hr = d3d_device7_GetViewport(iface, viewport);
5459 set_fpu_control_word(old_fpucw);
5461 return hr;
5464 /*****************************************************************************
5465 * IDirect3DDevice7::SetMaterial
5467 * Sets the Material
5469 * Version 7
5471 * Params:
5472 * Mat: The material to set
5474 * Returns:
5475 * D3D_OK on success
5476 * DDERR_INVALIDPARAMS if Mat is NULL.
5478 *****************************************************************************/
5479 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5481 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5483 TRACE("iface %p, material %p.\n", iface, material);
5485 if (!material)
5486 return DDERR_INVALIDPARAMS;
5488 wined3d_mutex_lock();
5489 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5490 wined3d_stateblock_set_material(device->update_state, (const struct wined3d_material *)material);
5491 wined3d_mutex_unlock();
5493 return D3D_OK;
5496 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5498 return d3d_device7_SetMaterial(iface, material);
5501 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5503 HRESULT hr;
5504 WORD old_fpucw;
5506 old_fpucw = d3d_fpu_setup();
5507 hr = d3d_device7_SetMaterial(iface, material);
5508 set_fpu_control_word(old_fpucw);
5510 return hr;
5513 /*****************************************************************************
5514 * IDirect3DDevice7::GetMaterial
5516 * Returns the current material
5518 * Version 7
5520 * Params:
5521 * Mat: D3DMATERIAL7 structure to write the material parameters to
5523 * Returns:
5524 * D3D_OK on success
5525 * DDERR_INVALIDPARAMS if Mat is NULL
5527 *****************************************************************************/
5528 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5530 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5532 TRACE("iface %p, material %p.\n", iface, material);
5534 wined3d_mutex_lock();
5535 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5536 memcpy(material, &device->stateblock_state->material, sizeof(*material));
5537 wined3d_mutex_unlock();
5539 return D3D_OK;
5542 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5544 return d3d_device7_GetMaterial(iface, material);
5547 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5549 HRESULT hr;
5550 WORD old_fpucw;
5552 old_fpucw = d3d_fpu_setup();
5553 hr = d3d_device7_GetMaterial(iface, material);
5554 set_fpu_control_word(old_fpucw);
5556 return hr;
5559 /*****************************************************************************
5560 * IDirect3DDevice7::SetLight
5562 * Assigns a light to a light index, but doesn't activate it yet.
5564 * Version 7, IDirect3DLight uses this method for older versions
5566 * Params:
5567 * LightIndex: The index of the new light
5568 * Light: A D3DLIGHT7 structure describing the light
5570 * Returns:
5571 * D3D_OK on success
5573 *****************************************************************************/
5574 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5576 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5577 HRESULT hr;
5579 TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5581 wined3d_mutex_lock();
5582 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5583 hr = wined3d_stateblock_set_light(device->update_state, light_idx, (const struct wined3d_light *)light);
5584 wined3d_mutex_unlock();
5586 return hr_ddraw_from_wined3d(hr);
5589 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5591 return d3d_device7_SetLight(iface, light_idx, light);
5594 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5596 HRESULT hr;
5597 WORD old_fpucw;
5599 old_fpucw = d3d_fpu_setup();
5600 hr = d3d_device7_SetLight(iface, light_idx, light);
5601 set_fpu_control_word(old_fpucw);
5603 return hr;
5606 /*****************************************************************************
5607 * IDirect3DDevice7::GetLight
5609 * Returns the light assigned to a light index
5611 * Params:
5612 * Light: Structure to write the light information to
5614 * Returns:
5615 * D3D_OK on success
5616 * DDERR_INVALIDPARAMS if Light is NULL
5618 *****************************************************************************/
5619 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5621 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5622 BOOL enabled;
5623 HRESULT hr;
5625 TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5627 wined3d_mutex_lock();
5628 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5629 hr = wined3d_stateblock_get_light(device->state, light_idx, (struct wined3d_light *)light, &enabled);
5630 wined3d_mutex_unlock();
5632 return hr_ddraw_from_wined3d(hr);
5635 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5637 return d3d_device7_GetLight(iface, light_idx, light);
5640 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5642 HRESULT hr;
5643 WORD old_fpucw;
5645 old_fpucw = d3d_fpu_setup();
5646 hr = d3d_device7_GetLight(iface, light_idx, light);
5647 set_fpu_control_word(old_fpucw);
5649 return hr;
5652 /*****************************************************************************
5653 * IDirect3DDevice7::BeginStateBlock
5655 * Begins recording to a stateblock
5657 * Version 7
5659 * Returns:
5660 * D3D_OK on success
5662 *****************************************************************************/
5663 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5665 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5666 struct wined3d_stateblock *stateblock;
5667 HRESULT hr;
5669 TRACE("iface %p.\n", iface);
5671 wined3d_mutex_lock();
5672 if (device->recording)
5674 wined3d_mutex_unlock();
5675 WARN("Trying to begin a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5676 return D3DERR_INBEGINSTATEBLOCK;
5678 if (SUCCEEDED(hr = wined3d_stateblock_create(device->wined3d_device, NULL, WINED3D_SBT_RECORDED, &stateblock)))
5679 device->update_state = device->recording = stateblock;
5680 wined3d_mutex_unlock();
5682 return hr_ddraw_from_wined3d(hr);
5685 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5687 return d3d_device7_BeginStateBlock(iface);
5690 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5692 HRESULT hr;
5693 WORD old_fpucw;
5695 old_fpucw = d3d_fpu_setup();
5696 hr = d3d_device7_BeginStateBlock(iface);
5697 set_fpu_control_word(old_fpucw);
5699 return hr;
5702 /*****************************************************************************
5703 * IDirect3DDevice7::EndStateBlock
5705 * Stops recording to a state block and returns the created stateblock
5706 * handle.
5708 * Version 7
5710 * Params:
5711 * BlockHandle: Address to store the stateblock's handle to
5713 * Returns:
5714 * D3D_OK on success
5715 * DDERR_INVALIDPARAMS if BlockHandle is NULL
5717 *****************************************************************************/
5718 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5720 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5721 struct wined3d_stateblock *wined3d_sb;
5722 DWORD h;
5724 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5726 if (!stateblock)
5727 return DDERR_INVALIDPARAMS;
5729 wined3d_mutex_lock();
5730 if (!device->recording)
5732 wined3d_mutex_unlock();
5733 WARN("Trying to end a stateblock, but no stateblock is being recorded.\n");
5734 return D3DERR_NOTINBEGINSTATEBLOCK;
5736 wined3d_sb = device->recording;
5737 wined3d_stateblock_init_contained_states(wined3d_sb);
5738 device->recording = NULL;
5739 device->update_state = device->state;
5741 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5742 if (h == DDRAW_INVALID_HANDLE)
5744 ERR("Failed to allocate a stateblock handle.\n");
5745 wined3d_stateblock_decref(wined3d_sb);
5746 wined3d_mutex_unlock();
5747 *stateblock = 0;
5748 return DDERR_OUTOFMEMORY;
5751 wined3d_mutex_unlock();
5752 *stateblock = h + 1;
5754 return D3D_OK;
5757 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5759 return d3d_device7_EndStateBlock(iface, stateblock);
5762 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5764 HRESULT hr;
5765 WORD old_fpucw;
5767 old_fpucw = d3d_fpu_setup();
5768 hr = d3d_device7_EndStateBlock(iface, stateblock);
5769 set_fpu_control_word(old_fpucw);
5771 return hr;
5774 /*****************************************************************************
5775 * IDirect3DDevice7::PreLoad
5777 * Allows the app to signal that a texture will be used soon, to allow
5778 * the Direct3DDevice to load it to the video card in the meantime.
5780 * Version 7
5782 * Params:
5783 * Texture: The texture to preload
5785 * Returns:
5786 * D3D_OK on success
5787 * DDERR_INVALIDPARAMS if Texture is NULL
5789 *****************************************************************************/
5790 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5792 struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5794 TRACE("iface %p, texture %p.\n", iface, texture);
5796 if (!texture)
5797 return DDERR_INVALIDPARAMS;
5799 wined3d_mutex_lock();
5800 wined3d_resource_preload(wined3d_texture_get_resource(surface->draw_texture ? surface->draw_texture
5801 : surface->wined3d_texture));
5802 wined3d_mutex_unlock();
5804 return D3D_OK;
5807 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5809 return d3d_device7_PreLoad(iface, texture);
5812 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5814 HRESULT hr;
5815 WORD old_fpucw;
5817 old_fpucw = d3d_fpu_setup();
5818 hr = d3d_device7_PreLoad(iface, texture);
5819 set_fpu_control_word(old_fpucw);
5821 return hr;
5824 /*****************************************************************************
5825 * IDirect3DDevice7::ApplyStateBlock
5827 * Activates the state stored in a state block handle.
5829 * Params:
5830 * BlockHandle: The stateblock handle to activate
5832 * Returns:
5833 * D3D_OK on success
5834 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5836 *****************************************************************************/
5837 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5839 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5840 struct wined3d_stateblock *wined3d_sb;
5842 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5844 wined3d_mutex_lock();
5845 if (device->recording)
5847 wined3d_mutex_unlock();
5848 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5849 return D3DERR_INBEGINSTATEBLOCK;
5851 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5852 if (!wined3d_sb)
5854 WARN("Invalid stateblock handle.\n");
5855 wined3d_mutex_unlock();
5856 return D3DERR_INVALIDSTATEBLOCK;
5859 wined3d_stateblock_apply(wined3d_sb, device->state);
5860 wined3d_mutex_unlock();
5862 return D3D_OK;
5865 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5867 return d3d_device7_ApplyStateBlock(iface, stateblock);
5870 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5872 HRESULT hr;
5873 WORD old_fpucw;
5875 old_fpucw = d3d_fpu_setup();
5876 hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5877 set_fpu_control_word(old_fpucw);
5879 return hr;
5882 /*****************************************************************************
5883 * IDirect3DDevice7::CaptureStateBlock
5885 * Updates a stateblock's values to the values currently set for the device
5887 * Version 7
5889 * Params:
5890 * BlockHandle: Stateblock to update
5892 * Returns:
5893 * D3D_OK on success
5894 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5896 *****************************************************************************/
5897 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5899 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5900 struct wined3d_stateblock *wined3d_sb;
5902 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5904 wined3d_mutex_lock();
5905 if (device->recording)
5907 wined3d_mutex_unlock();
5908 WARN("Trying to capture a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5909 return D3DERR_INBEGINSTATEBLOCK;
5911 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5912 if (!wined3d_sb)
5914 WARN("Invalid stateblock handle.\n");
5915 wined3d_mutex_unlock();
5916 return D3DERR_INVALIDSTATEBLOCK;
5919 wined3d_stateblock_capture(wined3d_sb, device->state);
5920 wined3d_mutex_unlock();
5922 return D3D_OK;
5925 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5927 return d3d_device7_CaptureStateBlock(iface, stateblock);
5930 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5932 HRESULT hr;
5933 WORD old_fpucw;
5935 old_fpucw = d3d_fpu_setup();
5936 hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5937 set_fpu_control_word(old_fpucw);
5939 return hr;
5942 /*****************************************************************************
5943 * IDirect3DDevice7::DeleteStateBlock
5945 * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5947 * Version 7
5949 * Params:
5950 * BlockHandle: Stateblock handle to delete
5952 * Returns:
5953 * D3D_OK on success
5954 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5956 *****************************************************************************/
5957 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5959 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5960 struct wined3d_stateblock *wined3d_sb;
5961 ULONG ref;
5963 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5965 wined3d_mutex_lock();
5967 wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5968 if (!wined3d_sb)
5970 WARN("Invalid stateblock handle.\n");
5971 wined3d_mutex_unlock();
5972 return D3DERR_INVALIDSTATEBLOCK;
5975 if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5977 ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5980 wined3d_mutex_unlock();
5982 return D3D_OK;
5985 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5987 return d3d_device7_DeleteStateBlock(iface, stateblock);
5990 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5992 HRESULT hr;
5993 WORD old_fpucw;
5995 old_fpucw = d3d_fpu_setup();
5996 hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5997 set_fpu_control_word(old_fpucw);
5999 return hr;
6002 /*****************************************************************************
6003 * IDirect3DDevice7::CreateStateBlock
6005 * Creates a new state block handle.
6007 * Version 7
6009 * Params:
6010 * Type: The state block type
6011 * BlockHandle: Address to write the created handle to
6013 * Returns:
6014 * D3D_OK on success
6015 * DDERR_INVALIDPARAMS if BlockHandle is NULL
6017 *****************************************************************************/
6018 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
6019 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6021 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6022 struct wined3d_stateblock *wined3d_sb;
6023 HRESULT hr;
6024 DWORD h;
6026 TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
6028 if (!stateblock)
6029 return DDERR_INVALIDPARAMS;
6031 if (type != D3DSBT_ALL
6032 && type != D3DSBT_PIXELSTATE
6033 && type != D3DSBT_VERTEXSTATE)
6035 WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
6036 return DDERR_INVALIDPARAMS;
6039 wined3d_mutex_lock();
6041 if (device->recording)
6043 wined3d_mutex_unlock();
6044 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
6045 return D3DERR_INBEGINSTATEBLOCK;
6048 if (FAILED(hr = wined3d_stateblock_create(device->wined3d_device,
6049 device->state, wined3d_stateblock_type_from_ddraw(type), &wined3d_sb)))
6051 WARN("Failed to create stateblock, hr %#x.\n", hr);
6052 wined3d_mutex_unlock();
6053 return hr_ddraw_from_wined3d(hr);
6056 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
6057 if (h == DDRAW_INVALID_HANDLE)
6059 ERR("Failed to allocate stateblock handle.\n");
6060 wined3d_stateblock_decref(wined3d_sb);
6061 wined3d_mutex_unlock();
6062 return DDERR_OUTOFMEMORY;
6065 *stateblock = h + 1;
6066 wined3d_mutex_unlock();
6068 return hr_ddraw_from_wined3d(hr);
6071 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
6072 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6074 return d3d_device7_CreateStateBlock(iface, type, stateblock);
6077 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
6078 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6080 HRESULT hr;
6081 WORD old_fpucw;
6083 old_fpucw = d3d_fpu_setup();
6084 hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
6085 set_fpu_control_word(old_fpucw);
6087 return hr;
6090 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
6092 struct ddraw_surface *src_level, *dest_level;
6093 IDirectDrawSurface7 *temp;
6094 DDSURFACEDESC2 ddsd;
6095 BOOL levelFound; /* at least one suitable sublevel in dest found */
6097 /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
6098 * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
6099 * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
6101 levelFound = FALSE;
6103 src_level = src;
6104 dest_level = dest;
6106 for (;src_level && dest_level;)
6108 if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6109 src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6111 levelFound = TRUE;
6113 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6114 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6115 IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6117 if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6119 dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6122 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6123 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6124 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6126 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6128 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6131 if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6132 if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6134 return !dest_level && levelFound;
6137 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dst,
6138 struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
6140 struct ddraw_surface *dst_level, *src_level;
6141 IDirectDrawSurface7 *temp;
6142 DDSURFACEDESC2 ddsd;
6143 POINT point;
6144 RECT src_rect;
6145 HRESULT hr;
6146 IDirectDrawPalette *pal = NULL, *pal_src = NULL;
6147 DWORD ckeyflag;
6148 DDCOLORKEY ddckey;
6150 /* Copy palette, if possible. */
6151 IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
6152 IDirectDrawSurface7_GetPalette(&dst->IDirectDrawSurface7_iface, &pal);
6154 if (pal_src != NULL && pal != NULL)
6156 PALETTEENTRY palent[256];
6158 IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
6159 IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
6162 if (pal) IDirectDrawPalette_Release(pal);
6163 if (pal_src) IDirectDrawPalette_Release(pal_src);
6165 /* Copy colorkeys, if present. */
6166 for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
6168 hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6170 if (SUCCEEDED(hr))
6172 IDirectDrawSurface7_SetColorKey(&dst->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6176 src_level = src;
6177 dst_level = dst;
6179 point = *DestPoint;
6180 src_rect = *SrcRect;
6182 for (;src_level && dst_level;)
6184 if (src_level->surface_desc.dwWidth == dst_level->surface_desc.dwWidth
6185 && src_level->surface_desc.dwHeight == dst_level->surface_desc.dwHeight)
6187 UINT src_w = src_rect.right - src_rect.left;
6188 UINT src_h = src_rect.bottom - src_rect.top;
6189 RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
6191 if (FAILED(hr = wined3d_device_context_blt(device->immediate_context,
6192 ddraw_surface_get_any_texture(dst_level, DDRAW_SURFACE_RW), dst_level->sub_resource_idx, &dst_rect,
6193 ddraw_surface_get_any_texture(src_level, DDRAW_SURFACE_READ),
6194 src_level->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
6195 ERR("Blit failed, hr %#x.\n", hr);
6197 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6198 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6199 IDirectDrawSurface7_GetAttachedSurface(&dst_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6201 if (dst_level != dst)
6202 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6204 dst_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6207 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6208 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6209 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6211 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6213 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6215 point.x /= 2;
6216 point.y /= 2;
6218 src_rect.top /= 2;
6219 src_rect.left /= 2;
6220 src_rect.right = (src_rect.right + 1) / 2;
6221 src_rect.bottom = (src_rect.bottom + 1) / 2;
6224 if (src_level && src_level != src)
6225 IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6226 if (dst_level && dst_level != dst)
6227 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6230 /*****************************************************************************
6231 * IDirect3DDevice7::Load
6233 * Loads a rectangular area from the source into the destination texture.
6234 * It can also copy the source to the faces of a cubic environment map
6236 * Version 7
6238 * Params:
6239 * DestTex: Destination texture
6240 * DestPoint: Point in the destination where the source image should be
6241 * written to
6242 * SrcTex: Source texture
6243 * SrcRect: Source rectangle
6244 * Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6245 * DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6246 * DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6248 * Returns:
6249 * D3D_OK on success
6250 * DDERR_INVALIDPARAMS if dst_texture or src_texture is NULL, broken coordinates or anything unexpected.
6253 *****************************************************************************/
6254 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
6255 IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6257 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6258 struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
6259 struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
6260 POINT destpoint;
6261 RECT srcrect;
6263 TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
6264 iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
6266 if( (!src) || (!dest) )
6267 return DDERR_INVALIDPARAMS;
6269 wined3d_mutex_lock();
6271 if (!src_rect)
6272 SetRect(&srcrect, 0, 0, src->surface_desc.dwWidth, src->surface_desc.dwHeight);
6273 else
6274 srcrect = *src_rect;
6276 if (!dst_pos)
6277 destpoint.x = destpoint.y = 0;
6278 else
6279 destpoint = *dst_pos;
6281 /* Check bad dimensions. dst_pos is validated against src, not dest, because
6282 * destination can be a subset of mip levels, in which case actual coordinates used
6283 * for it may be divided. If any dimension of dest is larger than source, it can't be
6284 * mip level subset, so an error can be returned early.
6286 if (IsRectEmpty(&srcrect) || srcrect.right > src->surface_desc.dwWidth ||
6287 srcrect.bottom > src->surface_desc.dwHeight ||
6288 destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6289 destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6290 dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6291 dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6293 wined3d_mutex_unlock();
6294 return DDERR_INVALIDPARAMS;
6297 /* Must be top level surfaces. */
6298 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6299 dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6301 wined3d_mutex_unlock();
6302 return DDERR_INVALIDPARAMS;
6305 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6307 struct ddraw_surface *src_face, *dest_face;
6308 DWORD src_face_flag, dest_face_flag;
6309 IDirectDrawSurface7 *temp;
6310 DDSURFACEDESC2 ddsd;
6311 int i;
6313 if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6315 wined3d_mutex_unlock();
6316 return DDERR_INVALIDPARAMS;
6319 /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6320 * time it's actual surface loading. */
6321 for (i = 0; i < 2; i++)
6323 dest_face = dest;
6324 src_face = src;
6326 for (;dest_face && src_face;)
6328 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6329 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6331 if (src_face_flag == dest_face_flag)
6333 if (i == 0)
6335 /* Destination mip levels must be subset of source mip levels. */
6336 if (!is_mip_level_subset(dest_face, src_face))
6338 wined3d_mutex_unlock();
6339 return DDERR_INVALIDPARAMS;
6342 else if (flags & dest_face_flag)
6344 copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6347 if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6349 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6350 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6351 IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6353 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6355 src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6357 else
6359 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6361 src_face = NULL;
6365 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6367 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6368 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6369 IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6371 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6373 dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6375 else
6377 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6379 dest_face = NULL;
6383 if (i == 0)
6385 /* Native returns error if src faces are not subset of dest faces. */
6386 if (src_face)
6388 wined3d_mutex_unlock();
6389 return DDERR_INVALIDPARAMS;
6394 wined3d_mutex_unlock();
6395 return D3D_OK;
6397 else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6399 wined3d_mutex_unlock();
6400 return DDERR_INVALIDPARAMS;
6403 /* Handle non cube map textures. */
6405 /* Destination mip levels must be subset of source mip levels. */
6406 if (!is_mip_level_subset(dest, src))
6408 wined3d_mutex_unlock();
6409 return DDERR_INVALIDPARAMS;
6412 copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6414 wined3d_mutex_unlock();
6416 return D3D_OK;
6419 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6420 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6422 return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6425 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6426 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6428 HRESULT hr;
6429 WORD old_fpucw;
6431 old_fpucw = d3d_fpu_setup();
6432 hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6433 set_fpu_control_word(old_fpucw);
6435 return hr;
6438 /*****************************************************************************
6439 * IDirect3DDevice7::LightEnable
6441 * Enables or disables a light
6443 * Version 7, IDirect3DLight uses this method too.
6445 * Params:
6446 * LightIndex: The index of the light to enable / disable
6447 * Enable: Enable or disable the light
6449 * Returns:
6450 * D3D_OK on success
6452 *****************************************************************************/
6453 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6455 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6456 HRESULT hr;
6458 TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6460 wined3d_mutex_lock();
6461 hr = wined3d_stateblock_set_light_enable(device->update_state, light_idx, enabled);
6462 wined3d_mutex_unlock();
6464 return hr_ddraw_from_wined3d(hr);
6467 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6469 return d3d_device7_LightEnable(iface, light_idx, enabled);
6472 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6474 HRESULT hr;
6475 WORD old_fpucw;
6477 old_fpucw = d3d_fpu_setup();
6478 hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6479 set_fpu_control_word(old_fpucw);
6481 return hr;
6484 /*****************************************************************************
6485 * IDirect3DDevice7::GetLightEnable
6487 * Retrieves if the light with the given index is enabled or not
6489 * Version 7
6491 * Params:
6492 * LightIndex: Index of desired light
6493 * Enable: Pointer to a BOOL which contains the result
6495 * Returns:
6496 * D3D_OK on success
6497 * DDERR_INVALIDPARAMS if Enable is NULL
6499 *****************************************************************************/
6500 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6502 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6503 struct wined3d_light light;
6504 HRESULT hr;
6506 TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6508 if (!enabled)
6509 return DDERR_INVALIDPARAMS;
6511 wined3d_mutex_lock();
6512 hr = wined3d_stateblock_get_light(device->state, light_idx, &light, enabled);
6513 wined3d_mutex_unlock();
6515 return hr_ddraw_from_wined3d(hr);
6518 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6520 return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6523 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6525 HRESULT hr;
6526 WORD old_fpucw;
6528 old_fpucw = d3d_fpu_setup();
6529 hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6530 set_fpu_control_word(old_fpucw);
6532 return hr;
6535 /*****************************************************************************
6536 * IDirect3DDevice7::SetClipPlane
6538 * Sets custom clipping plane
6540 * Version 7
6542 * Params:
6543 * Index: The index of the clipping plane
6544 * PlaneEquation: An equation defining the clipping plane
6546 * Returns:
6547 * D3D_OK on success
6548 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6550 *****************************************************************************/
6551 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6553 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6554 const struct wined3d_vec4 *wined3d_plane;
6555 HRESULT hr;
6557 TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6559 if (!plane)
6560 return DDERR_INVALIDPARAMS;
6562 wined3d_plane = (struct wined3d_vec4 *)plane;
6564 wined3d_mutex_lock();
6565 hr = wined3d_stateblock_set_clip_plane(device->update_state, idx, wined3d_plane);
6566 if (idx < ARRAY_SIZE(device->user_clip_planes))
6568 device->user_clip_planes[idx] = *wined3d_plane;
6569 if (hr == WINED3DERR_INVALIDCALL)
6571 WARN("Clip plane %u is not supported.\n", idx);
6572 hr = D3D_OK;
6575 wined3d_mutex_unlock();
6577 return hr;
6580 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6582 return d3d_device7_SetClipPlane(iface, idx, plane);
6585 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6587 HRESULT hr;
6588 WORD old_fpucw;
6590 old_fpucw = d3d_fpu_setup();
6591 hr = d3d_device7_SetClipPlane(iface, idx, plane);
6592 set_fpu_control_word(old_fpucw);
6594 return hr;
6597 /*****************************************************************************
6598 * IDirect3DDevice7::GetClipPlane
6600 * Returns the clipping plane with a specific index
6602 * Params:
6603 * Index: The index of the desired plane
6604 * PlaneEquation: Address to store the plane equation to
6606 * Returns:
6607 * D3D_OK on success
6608 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6610 *****************************************************************************/
6611 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6613 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6615 TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6617 if (!plane)
6618 return DDERR_INVALIDPARAMS;
6620 wined3d_mutex_lock();
6621 if (idx < WINED3D_MAX_CLIP_DISTANCES)
6622 memcpy(plane, &device->stateblock_state->clip_planes[idx], sizeof(struct wined3d_vec4));
6623 else
6625 WARN("Clip plane %u is not supported.\n", idx);
6626 if (idx < ARRAY_SIZE(device->user_clip_planes))
6627 memcpy(plane, &device->user_clip_planes[idx], sizeof(struct wined3d_vec4));
6629 wined3d_mutex_unlock();
6631 return D3D_OK;
6634 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6636 return d3d_device7_GetClipPlane(iface, idx, plane);
6639 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6641 HRESULT hr;
6642 WORD old_fpucw;
6644 old_fpucw = d3d_fpu_setup();
6645 hr = d3d_device7_GetClipPlane(iface, idx, plane);
6646 set_fpu_control_word(old_fpucw);
6648 return hr;
6651 /*****************************************************************************
6652 * IDirect3DDevice7::GetInfo
6654 * Retrieves some information about the device. The DirectX sdk says that
6655 * this version returns S_FALSE for all retail builds of DirectX, that's what
6656 * this implementation does.
6658 * Params:
6659 * DevInfoID: Information type requested
6660 * DevInfoStruct: Pointer to a structure to store the info to
6661 * Size: Size of the structure
6663 * Returns:
6664 * S_FALSE, because it's a non-debug driver
6666 *****************************************************************************/
6667 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6669 TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6670 iface, info_id, info, info_size);
6672 if (TRACE_ON(ddraw))
6674 TRACE(" info requested : ");
6675 switch (info_id)
6677 case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6678 case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6679 case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6680 default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6684 return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6687 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6688 * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6689 * are not duplicated.
6691 * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6692 * has already been setup for optimal d3d operation.
6694 * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6695 * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6696 * by Sacrifice (game). */
6697 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6699 /*** IUnknown Methods ***/
6700 d3d_device7_QueryInterface,
6701 d3d_device7_AddRef,
6702 d3d_device7_Release,
6703 /*** IDirect3DDevice7 ***/
6704 d3d_device7_GetCaps_FPUSetup,
6705 d3d_device7_EnumTextureFormats_FPUSetup,
6706 d3d_device7_BeginScene_FPUSetup,
6707 d3d_device7_EndScene_FPUSetup,
6708 d3d_device7_GetDirect3D,
6709 d3d_device7_SetRenderTarget_FPUSetup,
6710 d3d_device7_GetRenderTarget,
6711 d3d_device7_Clear_FPUSetup,
6712 d3d_device7_SetTransform_FPUSetup,
6713 d3d_device7_GetTransform_FPUSetup,
6714 d3d_device7_SetViewport_FPUSetup,
6715 d3d_device7_MultiplyTransform_FPUSetup,
6716 d3d_device7_GetViewport_FPUSetup,
6717 d3d_device7_SetMaterial_FPUSetup,
6718 d3d_device7_GetMaterial_FPUSetup,
6719 d3d_device7_SetLight_FPUSetup,
6720 d3d_device7_GetLight_FPUSetup,
6721 d3d_device7_SetRenderState_FPUSetup,
6722 d3d_device7_GetRenderState_FPUSetup,
6723 d3d_device7_BeginStateBlock_FPUSetup,
6724 d3d_device7_EndStateBlock_FPUSetup,
6725 d3d_device7_PreLoad_FPUSetup,
6726 d3d_device7_DrawPrimitive_FPUSetup,
6727 d3d_device7_DrawIndexedPrimitive_FPUSetup,
6728 d3d_device7_SetClipStatus,
6729 d3d_device7_GetClipStatus,
6730 d3d_device7_DrawPrimitiveStrided_FPUSetup,
6731 d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6732 d3d_device7_DrawPrimitiveVB_FPUSetup,
6733 d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6734 d3d_device7_ComputeSphereVisibility,
6735 d3d_device7_GetTexture_FPUSetup,
6736 d3d_device7_SetTexture_FPUSetup,
6737 d3d_device7_GetTextureStageState_FPUSetup,
6738 d3d_device7_SetTextureStageState_FPUSetup,
6739 d3d_device7_ValidateDevice_FPUSetup,
6740 d3d_device7_ApplyStateBlock_FPUSetup,
6741 d3d_device7_CaptureStateBlock_FPUSetup,
6742 d3d_device7_DeleteStateBlock_FPUSetup,
6743 d3d_device7_CreateStateBlock_FPUSetup,
6744 d3d_device7_Load_FPUSetup,
6745 d3d_device7_LightEnable_FPUSetup,
6746 d3d_device7_GetLightEnable_FPUSetup,
6747 d3d_device7_SetClipPlane_FPUSetup,
6748 d3d_device7_GetClipPlane_FPUSetup,
6749 d3d_device7_GetInfo
6752 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6754 /*** IUnknown Methods ***/
6755 d3d_device7_QueryInterface,
6756 d3d_device7_AddRef,
6757 d3d_device7_Release,
6758 /*** IDirect3DDevice7 ***/
6759 d3d_device7_GetCaps_FPUPreserve,
6760 d3d_device7_EnumTextureFormats_FPUPreserve,
6761 d3d_device7_BeginScene_FPUPreserve,
6762 d3d_device7_EndScene_FPUPreserve,
6763 d3d_device7_GetDirect3D,
6764 d3d_device7_SetRenderTarget_FPUPreserve,
6765 d3d_device7_GetRenderTarget,
6766 d3d_device7_Clear_FPUPreserve,
6767 d3d_device7_SetTransform_FPUPreserve,
6768 d3d_device7_GetTransform_FPUPreserve,
6769 d3d_device7_SetViewport_FPUPreserve,
6770 d3d_device7_MultiplyTransform_FPUPreserve,
6771 d3d_device7_GetViewport_FPUPreserve,
6772 d3d_device7_SetMaterial_FPUPreserve,
6773 d3d_device7_GetMaterial_FPUPreserve,
6774 d3d_device7_SetLight_FPUPreserve,
6775 d3d_device7_GetLight_FPUPreserve,
6776 d3d_device7_SetRenderState_FPUPreserve,
6777 d3d_device7_GetRenderState_FPUPreserve,
6778 d3d_device7_BeginStateBlock_FPUPreserve,
6779 d3d_device7_EndStateBlock_FPUPreserve,
6780 d3d_device7_PreLoad_FPUPreserve,
6781 d3d_device7_DrawPrimitive_FPUPreserve,
6782 d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6783 d3d_device7_SetClipStatus,
6784 d3d_device7_GetClipStatus,
6785 d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6786 d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6787 d3d_device7_DrawPrimitiveVB_FPUPreserve,
6788 d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6789 d3d_device7_ComputeSphereVisibility,
6790 d3d_device7_GetTexture_FPUPreserve,
6791 d3d_device7_SetTexture_FPUPreserve,
6792 d3d_device7_GetTextureStageState_FPUPreserve,
6793 d3d_device7_SetTextureStageState_FPUPreserve,
6794 d3d_device7_ValidateDevice_FPUPreserve,
6795 d3d_device7_ApplyStateBlock_FPUPreserve,
6796 d3d_device7_CaptureStateBlock_FPUPreserve,
6797 d3d_device7_DeleteStateBlock_FPUPreserve,
6798 d3d_device7_CreateStateBlock_FPUPreserve,
6799 d3d_device7_Load_FPUPreserve,
6800 d3d_device7_LightEnable_FPUPreserve,
6801 d3d_device7_GetLightEnable_FPUPreserve,
6802 d3d_device7_SetClipPlane_FPUPreserve,
6803 d3d_device7_GetClipPlane_FPUPreserve,
6804 d3d_device7_GetInfo
6807 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6809 /*** IUnknown Methods ***/
6810 d3d_device3_QueryInterface,
6811 d3d_device3_AddRef,
6812 d3d_device3_Release,
6813 /*** IDirect3DDevice3 ***/
6814 d3d_device3_GetCaps,
6815 d3d_device3_GetStats,
6816 d3d_device3_AddViewport,
6817 d3d_device3_DeleteViewport,
6818 d3d_device3_NextViewport,
6819 d3d_device3_EnumTextureFormats,
6820 d3d_device3_BeginScene,
6821 d3d_device3_EndScene,
6822 d3d_device3_GetDirect3D,
6823 d3d_device3_SetCurrentViewport,
6824 d3d_device3_GetCurrentViewport,
6825 d3d_device3_SetRenderTarget,
6826 d3d_device3_GetRenderTarget,
6827 d3d_device3_Begin,
6828 d3d_device3_BeginIndexed,
6829 d3d_device3_Vertex,
6830 d3d_device3_Index,
6831 d3d_device3_End,
6832 d3d_device3_GetRenderState,
6833 d3d_device3_SetRenderState,
6834 d3d_device3_GetLightState,
6835 d3d_device3_SetLightState,
6836 d3d_device3_SetTransform,
6837 d3d_device3_GetTransform,
6838 d3d_device3_MultiplyTransform,
6839 d3d_device3_DrawPrimitive,
6840 d3d_device3_DrawIndexedPrimitive,
6841 d3d_device3_SetClipStatus,
6842 d3d_device3_GetClipStatus,
6843 d3d_device3_DrawPrimitiveStrided,
6844 d3d_device3_DrawIndexedPrimitiveStrided,
6845 d3d_device3_DrawPrimitiveVB,
6846 d3d_device3_DrawIndexedPrimitiveVB,
6847 d3d_device3_ComputeSphereVisibility,
6848 d3d_device3_GetTexture,
6849 d3d_device3_SetTexture,
6850 d3d_device3_GetTextureStageState,
6851 d3d_device3_SetTextureStageState,
6852 d3d_device3_ValidateDevice
6855 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6857 /*** IUnknown Methods ***/
6858 d3d_device2_QueryInterface,
6859 d3d_device2_AddRef,
6860 d3d_device2_Release,
6861 /*** IDirect3DDevice2 ***/
6862 d3d_device2_GetCaps,
6863 d3d_device2_SwapTextureHandles,
6864 d3d_device2_GetStats,
6865 d3d_device2_AddViewport,
6866 d3d_device2_DeleteViewport,
6867 d3d_device2_NextViewport,
6868 d3d_device2_EnumTextureFormats,
6869 d3d_device2_BeginScene,
6870 d3d_device2_EndScene,
6871 d3d_device2_GetDirect3D,
6872 d3d_device2_SetCurrentViewport,
6873 d3d_device2_GetCurrentViewport,
6874 d3d_device2_SetRenderTarget,
6875 d3d_device2_GetRenderTarget,
6876 d3d_device2_Begin,
6877 d3d_device2_BeginIndexed,
6878 d3d_device2_Vertex,
6879 d3d_device2_Index,
6880 d3d_device2_End,
6881 d3d_device2_GetRenderState,
6882 d3d_device2_SetRenderState,
6883 d3d_device2_GetLightState,
6884 d3d_device2_SetLightState,
6885 d3d_device2_SetTransform,
6886 d3d_device2_GetTransform,
6887 d3d_device2_MultiplyTransform,
6888 d3d_device2_DrawPrimitive,
6889 d3d_device2_DrawIndexedPrimitive,
6890 d3d_device2_SetClipStatus,
6891 d3d_device2_GetClipStatus
6894 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6896 /*** IUnknown Methods ***/
6897 d3d_device1_QueryInterface,
6898 d3d_device1_AddRef,
6899 d3d_device1_Release,
6900 /*** IDirect3DDevice1 ***/
6901 d3d_device1_Initialize,
6902 d3d_device1_GetCaps,
6903 d3d_device1_SwapTextureHandles,
6904 d3d_device1_CreateExecuteBuffer,
6905 d3d_device1_GetStats,
6906 d3d_device1_Execute,
6907 d3d_device1_AddViewport,
6908 d3d_device1_DeleteViewport,
6909 d3d_device1_NextViewport,
6910 d3d_device1_Pick,
6911 d3d_device1_GetPickRecords,
6912 d3d_device1_EnumTextureFormats,
6913 d3d_device1_CreateMatrix,
6914 d3d_device1_SetMatrix,
6915 d3d_device1_GetMatrix,
6916 d3d_device1_DeleteMatrix,
6917 d3d_device1_BeginScene,
6918 d3d_device1_EndScene,
6919 d3d_device1_GetDirect3D
6922 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6924 d3d_device_inner_QueryInterface,
6925 d3d_device_inner_AddRef,
6926 d3d_device_inner_Release,
6929 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6931 if (!iface) return NULL;
6932 assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6933 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6936 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6938 if (!iface) return NULL;
6939 assert(iface->lpVtbl == &d3d_device3_vtbl);
6940 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6943 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6945 if (!iface) return NULL;
6946 assert(iface->lpVtbl == &d3d_device2_vtbl);
6947 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6950 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6952 if (!iface) return NULL;
6953 assert(iface->lpVtbl == &d3d_device1_vtbl);
6954 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6957 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6959 IDirectDrawSurface7 *depthStencil = NULL;
6960 IDirectDrawSurface7 *render_target;
6961 static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, {0} };
6962 struct ddraw_surface *dsi;
6964 if (device->rt_iface && SUCCEEDED(IUnknown_QueryInterface(device->rt_iface,
6965 &IID_IDirectDrawSurface7, (void **)&render_target)))
6967 IDirectDrawSurface7_GetAttachedSurface(render_target, &depthcaps, &depthStencil);
6968 IDirectDrawSurface7_Release(render_target);
6970 if (!depthStencil)
6972 TRACE("Setting wined3d depth stencil to NULL\n");
6973 wined3d_device_context_set_depth_stencil_view(device->immediate_context, NULL);
6974 return WINED3D_ZB_FALSE;
6977 dsi = impl_from_IDirectDrawSurface7(depthStencil);
6978 wined3d_device_context_set_depth_stencil_view(device->immediate_context,
6979 ddraw_surface_get_rendertarget_view(dsi));
6981 IDirectDrawSurface7_Release(depthStencil);
6982 return WINED3D_ZB_TRUE;
6985 static void ddraw_reset_viewport_state(struct ddraw *ddraw)
6987 struct wined3d_viewport vp;
6988 RECT rect;
6990 wined3d_device_context_get_viewports(ddraw->immediate_context, NULL, &vp);
6991 wined3d_stateblock_set_viewport(ddraw->state, &vp);
6992 wined3d_device_context_get_scissor_rects(ddraw->immediate_context, NULL, &rect);
6993 wined3d_stateblock_set_scissor_rect(ddraw->state, &rect);
6996 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, const GUID *guid,
6997 struct ddraw_surface *target, IUnknown *rt_iface, UINT version, IUnknown *outer_unknown)
6999 static const struct wined3d_matrix ident =
7001 1.0f, 0.0f, 0.0f, 0.0f,
7002 0.0f, 1.0f, 0.0f, 0.0f,
7003 0.0f, 0.0f, 1.0f, 0.0f,
7004 0.0f, 0.0f, 0.0f, 1.0f,
7006 struct wined3d_rendertarget_view *rtv;
7007 HRESULT hr;
7009 if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
7010 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
7011 else
7012 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
7014 device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
7015 device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
7016 device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
7017 device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
7018 device->ref = 1;
7019 device->version = version;
7020 device->hardware_device = IsEqualGUID(&IID_IDirect3DTnLHalDevice, guid)
7021 || IsEqualGUID(&IID_IDirect3DHALDevice, guid);
7023 if (device->hardware_device && !(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
7025 WARN("Surface %p is not in video memory.\n", target);
7026 return D3DERR_SURFACENOTINVIDMEM;
7029 if (outer_unknown)
7030 device->outer_unknown = outer_unknown;
7031 else
7032 device->outer_unknown = &device->IUnknown_inner;
7034 device->ddraw = ddraw;
7035 list_init(&device->viewport_list);
7037 if (!ddraw_handle_table_init(&device->handle_table, 64))
7039 ERR("Failed to initialize handle table.\n");
7040 return DDERR_OUTOFMEMORY;
7043 device->legacyTextureBlending = FALSE;
7044 device->legacy_projection = ident;
7045 device->legacy_clipspace = ident;
7047 /* This is for convenience. */
7048 device->wined3d_device = ddraw->wined3d_device;
7049 device->immediate_context = ddraw->immediate_context;
7050 wined3d_device_incref(ddraw->wined3d_device);
7051 device->update_state = device->state = ddraw->state;
7052 device->stateblock_state = ddraw->stateblock_state;
7053 wined3d_stateblock_incref(ddraw->state);
7055 /* Render to the back buffer */
7056 rtv = ddraw_surface_get_rendertarget_view(target);
7057 if (FAILED(hr = wined3d_device_context_set_rendertarget_views(device->immediate_context, 0, 1, &rtv, TRUE)))
7059 ERR("Failed to set render target, hr %#x.\n", hr);
7060 wined3d_stateblock_decref(device->state);
7061 ddraw_handle_table_destroy(&device->handle_table);
7062 return hr;
7065 device->rt_iface = rt_iface;
7066 if (version != 1)
7067 IUnknown_AddRef(device->rt_iface);
7069 ddraw->d3ddevice = device;
7071 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_ZENABLE,
7072 d3d_device_update_depth_stencil(device));
7073 if (version == 1) /* Color keying is initially enabled for version 1 devices. */
7074 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_COLORKEYENABLE, TRUE);
7075 else if (version == 2)
7076 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_SPECULARENABLE, TRUE);
7077 if (version < 7)
7079 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_NORMALIZENORMALS, TRUE);
7080 IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface,
7081 D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
7083 ddraw_reset_viewport_state(ddraw);
7084 return D3D_OK;
7087 HRESULT d3d_device_create(struct ddraw *ddraw, const GUID *guid, struct ddraw_surface *target, IUnknown *rt_iface,
7088 UINT version, struct d3d_device **device, IUnknown *outer_unknown)
7090 struct d3d_device *object;
7091 HRESULT hr;
7093 TRACE("ddraw %p, guid %s, target %p, version %u, device %p, outer_unknown %p.\n",
7094 ddraw, debugstr_guid(guid), target, version, device, outer_unknown);
7096 if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
7097 || (target->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
7099 WARN("Surface %p is not a render target.\n", target);
7100 return DDERR_INVALIDCAPS;
7103 if (!validate_surface_palette(target))
7105 WARN("Surface %p has an indexed pixel format, but no palette.\n", target);
7106 return DDERR_NOPALETTEATTACHED;
7109 if (ddraw->flags & DDRAW_NO3D)
7111 ERR_(winediag)("The application wants to create a Direct3D device, "
7112 "but the current DirectDrawRenderer does not support this.\n");
7114 return DDERR_OUTOFMEMORY;
7117 if (ddraw->d3ddevice)
7119 FIXME("Only one Direct3D device per DirectDraw object supported.\n");
7120 return DDERR_INVALIDPARAMS;
7123 if (!(object = heap_alloc_zero(sizeof(*object))))
7125 ERR("Failed to allocate device memory.\n");
7126 return DDERR_OUTOFMEMORY;
7129 if (FAILED(hr = d3d_device_init(object, ddraw, guid, target, rt_iface, version, outer_unknown)))
7131 WARN("Failed to initialize device, hr %#x.\n", hr);
7132 heap_free(object);
7133 return hr;
7136 TRACE("Created device %p.\n", object);
7137 *device = object;
7139 return D3D_OK;