ddraw: Retrieve the viewport from the primary stateblock.
[wine.git] / dlls / ddraw / device.c
blob240f79b4325297cce82bbf594976394f42a4e74c
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 inline struct d3d_device *impl_from_IUnknown(IUnknown *iface)
77 return CONTAINING_RECORD(iface, struct d3d_device, IUnknown_inner);
80 static HRESULT WINAPI d3d_device_inner_QueryInterface(IUnknown *iface, REFIID riid, void **out)
82 struct d3d_device *device = impl_from_IUnknown(iface);
84 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
86 if (!riid)
88 *out = NULL;
89 return DDERR_INVALIDPARAMS;
92 if (IsEqualGUID(&IID_IUnknown, riid))
94 IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
95 *out = &device->IDirect3DDevice7_iface;
96 return S_OK;
99 if (device->version == 7)
101 if (IsEqualGUID(&IID_IDirect3DDevice7, riid))
103 IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
104 *out = &device->IDirect3DDevice7_iface;
105 return S_OK;
108 else
110 if (IsEqualGUID(&IID_IDirect3DDevice3, riid) && device->version == 3)
112 IDirect3DDevice3_AddRef(&device->IDirect3DDevice3_iface);
113 *out = &device->IDirect3DDevice3_iface;
114 return S_OK;
117 if (IsEqualGUID(&IID_IDirect3DDevice2, riid) && device->version >= 2)
119 IDirect3DDevice2_AddRef(&device->IDirect3DDevice2_iface);
120 *out = &device->IDirect3DDevice2_iface;
121 return S_OK;
124 if (IsEqualGUID(&IID_IDirect3DDevice, riid))
126 IDirect3DDevice_AddRef(&device->IDirect3DDevice_iface);
127 *out = &device->IDirect3DDevice_iface;
128 return S_OK;
132 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
134 *out = NULL;
135 return E_NOINTERFACE;
138 static HRESULT WINAPI d3d_device7_QueryInterface(IDirect3DDevice7 *iface, REFIID riid, void **out)
140 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
142 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
144 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
147 static HRESULT WINAPI d3d_device3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid, void **out)
149 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
151 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
153 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
156 static HRESULT WINAPI d3d_device2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid, void **out)
158 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
160 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
162 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
165 static HRESULT WINAPI d3d_device1_QueryInterface(IDirect3DDevice *iface, REFIID riid, void **out)
167 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
169 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
171 return IUnknown_QueryInterface(device->outer_unknown, riid, out);
174 static ULONG WINAPI d3d_device_inner_AddRef(IUnknown *iface)
176 struct d3d_device *device = impl_from_IUnknown(iface);
177 ULONG ref = InterlockedIncrement(&device->ref);
179 TRACE("%p increasing refcount to %u.\n", device, ref);
181 return ref;
184 static ULONG WINAPI d3d_device7_AddRef(IDirect3DDevice7 *iface)
186 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
188 TRACE("iface %p.\n", iface);
190 return IUnknown_AddRef(device->outer_unknown);
193 static ULONG WINAPI d3d_device3_AddRef(IDirect3DDevice3 *iface)
195 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
197 TRACE("iface %p.\n", iface);
199 return IUnknown_AddRef(device->outer_unknown);
202 static ULONG WINAPI d3d_device2_AddRef(IDirect3DDevice2 *iface)
204 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
206 TRACE("iface %p.\n", iface);
208 return IUnknown_AddRef(device->outer_unknown);
211 static ULONG WINAPI d3d_device1_AddRef(IDirect3DDevice *iface)
213 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
215 TRACE("iface %p.\n", iface);
217 return IUnknown_AddRef(device->outer_unknown);
220 static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
222 struct d3d_device *This = impl_from_IUnknown(iface);
223 ULONG ref = InterlockedDecrement(&This->ref);
224 IUnknown *rt_iface;
226 TRACE("%p decreasing refcount to %u.\n", This, ref);
228 /* This method doesn't destroy the wined3d device, because it's still in
229 * use for 2D rendering. IDirectDrawSurface7::Release will destroy the
230 * wined3d device when the render target is released. */
231 if (!ref)
233 DWORD i;
234 struct list *vp_entry, *vp_entry2;
236 wined3d_mutex_lock();
238 /* There is no need to unset any resources here, wined3d will take
239 * care of that on uninit_3d(). */
241 if (This->index_buffer)
242 wined3d_buffer_decref(This->index_buffer);
243 if (This->vertex_buffer)
244 wined3d_buffer_decref(This->vertex_buffer);
246 wined3d_device_set_rendertarget_view(This->wined3d_device, 0, NULL, FALSE);
248 wined3d_stateblock_decref(This->state);
249 if (This->recording)
250 wined3d_stateblock_decref(This->recording);
252 /* Release the wined3d device. This won't destroy it. */
253 if (!wined3d_device_decref(This->wined3d_device))
254 ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
256 /* The texture handles should be unset by now, but there might be some bits
257 * missing in our reference counting(needs test). Do a sanity check. */
258 for (i = 0; i < This->handle_table.entry_count; ++i)
260 struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
262 switch (entry->type)
264 case DDRAW_HANDLE_FREE:
265 break;
267 case DDRAW_HANDLE_MATERIAL:
269 struct d3d_material *m = entry->object;
270 FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
271 m->Handle = 0;
272 break;
275 case DDRAW_HANDLE_MATRIX:
277 /* No FIXME here because this might happen because of sloppy applications. */
278 WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
279 IDirect3DDevice_DeleteMatrix(&This->IDirect3DDevice_iface, i + 1);
280 break;
283 case DDRAW_HANDLE_STATEBLOCK:
285 /* No FIXME here because this might happen because of sloppy applications. */
286 WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
287 IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
288 break;
291 case DDRAW_HANDLE_SURFACE:
293 struct ddraw_surface *surf = entry->object;
294 FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
295 surf->Handle = 0;
296 break;
299 default:
300 FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
301 break;
305 ddraw_handle_table_destroy(&This->handle_table);
307 LIST_FOR_EACH_SAFE(vp_entry, vp_entry2, &This->viewport_list)
309 struct d3d_viewport *vp = LIST_ENTRY(vp_entry, struct d3d_viewport, entry);
310 IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
313 TRACE("Releasing render target %p.\n", This->rt_iface);
314 rt_iface = This->rt_iface;
315 This->rt_iface = NULL;
316 if (This->version != 1)
317 IUnknown_Release(rt_iface);
318 TRACE("Render target release done.\n");
320 /* Releasing the render target above may have released the last
321 * reference to the ddraw object. */
322 if (This->ddraw)
323 This->ddraw->d3ddevice = NULL;
325 /* Now free the structure */
326 heap_free(This);
327 wined3d_mutex_unlock();
330 TRACE("Done\n");
331 return ref;
334 static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
336 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
338 TRACE("iface %p.\n", iface);
340 return IUnknown_Release(device->outer_unknown);
343 static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
345 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
347 TRACE("iface %p.\n", iface);
349 return IUnknown_Release(device->outer_unknown);
352 static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
354 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
356 TRACE("iface %p.\n", iface);
358 return IUnknown_Release(device->outer_unknown);
361 static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
363 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
365 TRACE("iface %p.\n", iface);
367 return IUnknown_Release(device->outer_unknown);
370 /*****************************************************************************
371 * IDirect3DDevice Methods
372 *****************************************************************************/
374 /*****************************************************************************
375 * IDirect3DDevice::Initialize
377 * Initializes a Direct3DDevice. This implementation is a no-op, as all
378 * initialization is done at create time.
380 * Exists in Version 1
382 * Parameters:
383 * No idea what they mean, as the MSDN page is gone
385 * Returns: DD_OK
387 *****************************************************************************/
388 static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
389 IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
391 /* It shouldn't be crucial, but print a FIXME, I'm interested if
392 * any game calls it and when. */
393 FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
394 iface, d3d, debugstr_guid(guid), device_desc);
396 return D3D_OK;
399 static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *device_desc)
401 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
403 TRACE("iface %p, device_desc %p.\n", iface, device_desc);
405 if (!device_desc)
407 WARN("device_desc is NULL, returning DDERR_INVALIDPARAMS.\n");
408 return DDERR_INVALIDPARAMS;
411 /* Call the same function used by IDirect3D, this saves code */
412 return ddraw_get_d3dcaps(device->ddraw, device_desc);
415 static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
417 return d3d_device7_GetCaps(iface, desc);
420 static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
422 HRESULT hr;
423 WORD old_fpucw;
425 old_fpucw = d3d_fpu_setup();
426 hr = d3d_device7_GetCaps(iface, desc);
427 set_fpu_control_word(old_fpucw);
429 return hr;
431 /*****************************************************************************
432 * IDirect3DDevice3::GetCaps
434 * Retrieves the capabilities of the hardware device and the emulation
435 * device. For Wine, hardware and emulation are the same (it's all HW).
437 * This implementation is used for Version 1, 2, and 3. Version 7 has its own
439 * Parameters:
440 * HWDesc: Structure to fill with the HW caps
441 * HelDesc: Structure to fill with the hardware emulation caps
443 * Returns:
444 * D3D_OK on success
445 * D3DERR_* if a problem occurs. See WineD3D
447 *****************************************************************************/
449 /* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
450 * Microsoft just expanded the existing structure without naming them
451 * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
452 * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
453 * one with 252 bytes.
455 * All 3 versions are allowed as parameters and only the specified amount of
456 * bytes is written.
458 * Note that Direct3D7 and earlier are not available in native Win64
459 * ddraw.dll builds, so possible size differences between 32 bit and
460 * 64 bit are a non-issue.
462 static inline BOOL check_d3ddevicedesc_size(DWORD size)
464 if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
465 || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
466 || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
467 return FALSE;
470 static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
471 D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
473 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
474 D3DDEVICEDESC7 desc7;
475 D3DDEVICEDESC desc1;
476 HRESULT hr;
478 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
480 if (!HWDesc)
482 WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
483 return DDERR_INVALIDPARAMS;
485 if (!check_d3ddevicedesc_size(HWDesc->dwSize))
487 WARN("HWDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
488 return DDERR_INVALIDPARAMS;
490 if (!HelDesc)
492 WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
493 return DDERR_INVALIDPARAMS;
495 if (!check_d3ddevicedesc_size(HelDesc->dwSize))
497 WARN("HelDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
498 return DDERR_INVALIDPARAMS;
501 if (FAILED(hr = ddraw_get_d3dcaps(device->ddraw, &desc7)))
502 return hr;
504 ddraw_d3dcaps1_from_7(&desc1, &desc7);
505 DD_STRUCT_COPY_BYSIZE(HWDesc, &desc1);
506 DD_STRUCT_COPY_BYSIZE(HelDesc, &desc1);
507 return D3D_OK;
510 static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
511 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
513 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
515 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
517 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
520 static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
521 D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
523 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
525 TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
527 return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
530 /*****************************************************************************
531 * IDirect3DDevice2::SwapTextureHandles
533 * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
535 * Parameters:
536 * Tex1, Tex2: The 2 Textures to swap
538 * Returns:
539 * D3D_OK
541 *****************************************************************************/
542 static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
543 IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
545 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
546 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
547 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
548 DWORD h1, h2;
550 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
552 wined3d_mutex_lock();
554 h1 = surf1->Handle - 1;
555 h2 = surf2->Handle - 1;
556 device->handle_table.entries[h1].object = surf2;
557 device->handle_table.entries[h2].object = surf1;
558 surf2->Handle = h1 + 1;
559 surf1->Handle = h2 + 1;
561 wined3d_mutex_unlock();
563 return D3D_OK;
566 static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
567 IDirect3DTexture *tex1, IDirect3DTexture *tex2)
569 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
570 struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
571 struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
572 IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
573 IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
575 TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
577 return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
580 /*****************************************************************************
581 * IDirect3DDevice3::GetStats
583 * This method seems to retrieve some stats from the device.
584 * The MSDN documentation doesn't exist any more, but the D3DSTATS
585 * structure suggests that the amount of drawn primitives and processed
586 * vertices is returned.
588 * Exists in Version 1, 2 and 3
590 * Parameters:
591 * Stats: Pointer to a D3DSTATS structure to be filled
593 * Returns:
594 * D3D_OK on success
595 * DDERR_INVALIDPARAMS if Stats == NULL
597 *****************************************************************************/
598 static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
600 FIXME("iface %p, stats %p stub!\n", iface, Stats);
602 if(!Stats)
603 return DDERR_INVALIDPARAMS;
605 /* Fill the Stats with 0 */
606 Stats->dwTrianglesDrawn = 0;
607 Stats->dwLinesDrawn = 0;
608 Stats->dwPointsDrawn = 0;
609 Stats->dwSpansDrawn = 0;
610 Stats->dwVerticesProcessed = 0;
612 return D3D_OK;
615 static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
617 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
619 TRACE("iface %p, stats %p.\n", iface, stats);
621 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
624 static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
626 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
628 TRACE("iface %p, stats %p.\n", iface, stats);
630 return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
633 /*****************************************************************************
634 * IDirect3DDevice::CreateExecuteBuffer
636 * Creates an IDirect3DExecuteBuffer, used for rendering with a
637 * Direct3DDevice.
639 * Version 1 only.
641 * Params:
642 * Desc: Buffer description
643 * ExecuteBuffer: Address to return the Interface pointer at
644 * UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
645 * support
647 * Returns:
648 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
649 * DDERR_OUTOFMEMORY if we ran out of memory
650 * D3D_OK on success
652 *****************************************************************************/
653 static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
654 D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
656 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
657 struct d3d_execute_buffer *object;
658 HRESULT hr;
660 TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
661 iface, buffer_desc, ExecuteBuffer, outer_unknown);
663 if (outer_unknown)
664 return CLASS_E_NOAGGREGATION;
666 /* Allocate the new Execute Buffer */
667 if (!(object = heap_alloc_zero(sizeof(*object))))
669 ERR("Failed to allocate execute buffer memory.\n");
670 return DDERR_OUTOFMEMORY;
673 hr = d3d_execute_buffer_init(object, device, buffer_desc);
674 if (FAILED(hr))
676 WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
677 heap_free(object);
678 return hr;
681 *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
683 TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
685 return D3D_OK;
688 /*****************************************************************************
689 * IDirect3DDevice::Execute
691 * Executes all the stuff in an execute buffer.
693 * Params:
694 * ExecuteBuffer: The buffer to execute
695 * Viewport: The viewport used for rendering
696 * Flags: Some flags
698 * Returns:
699 * DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
700 * D3D_OK on success
702 *****************************************************************************/
703 static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
704 IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
706 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
707 struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
708 struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
709 HRESULT hr;
711 TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, viewport, flags);
713 if(!buffer)
714 return DDERR_INVALIDPARAMS;
716 if (FAILED(hr = IDirect3DDevice3_SetCurrentViewport
717 (&device->IDirect3DDevice3_iface, &viewport_impl->IDirect3DViewport3_iface)))
718 return hr;
720 /* Execute... */
721 wined3d_mutex_lock();
722 hr = d3d_execute_buffer_execute(buffer, device);
723 wined3d_mutex_unlock();
725 return hr;
728 /*****************************************************************************
729 * IDirect3DDevice3::AddViewport
731 * Add a Direct3DViewport to the device's viewport list. These viewports
732 * are wrapped to IDirect3DDevice7 viewports in viewport.c
734 * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
735 * are the same interfaces.
737 * Params:
738 * Viewport: The viewport to add
740 * Returns:
741 * DDERR_INVALIDPARAMS if Viewport == NULL
742 * D3D_OK on success
744 *****************************************************************************/
745 static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
747 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
748 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
750 TRACE("iface %p, viewport %p.\n", iface, viewport);
752 /* Sanity check */
753 if(!vp)
754 return DDERR_INVALIDPARAMS;
756 wined3d_mutex_lock();
757 IDirect3DViewport3_AddRef(viewport);
758 list_add_head(&device->viewport_list, &vp->entry);
759 /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
760 vp->active_device = device;
761 wined3d_mutex_unlock();
763 return D3D_OK;
766 static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
767 IDirect3DViewport2 *viewport)
769 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
770 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
772 TRACE("iface %p, viewport %p.\n", iface, viewport);
774 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
777 static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
779 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
780 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
782 TRACE("iface %p, viewport %p.\n", iface, viewport);
784 return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
787 /*****************************************************************************
788 * IDirect3DDevice3::DeleteViewport
790 * Deletes a Direct3DViewport from the device's viewport list.
792 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
793 * are equal.
795 * Params:
796 * Viewport: The viewport to delete
798 * Returns:
799 * D3D_OK on success
800 * DDERR_INVALIDPARAMS if the viewport wasn't found in the list
802 *****************************************************************************/
803 static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
805 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
806 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
808 TRACE("iface %p, viewport %p.\n", iface, viewport);
810 if (!vp)
812 WARN("NULL viewport, returning DDERR_INVALIDPARAMS\n");
813 return DDERR_INVALIDPARAMS;
816 wined3d_mutex_lock();
818 if (vp->active_device != device)
820 WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
821 wined3d_mutex_unlock();
822 return DDERR_INVALIDPARAMS;
825 if (device->current_viewport == vp)
827 TRACE("Deleting current viewport, unsetting and releasing.\n");
829 viewport_deactivate(vp);
830 IDirect3DViewport3_Release(viewport);
831 device->current_viewport = NULL;
834 vp->active_device = NULL;
835 list_remove(&vp->entry);
837 IDirect3DViewport3_Release(viewport);
839 wined3d_mutex_unlock();
841 return D3D_OK;
844 static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
846 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
847 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
849 TRACE("iface %p, viewport %p.\n", iface, viewport);
851 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
852 vp ? &vp->IDirect3DViewport3_iface : NULL);
855 static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
857 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
858 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
860 TRACE("iface %p, viewport %p.\n", iface, viewport);
862 return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
863 vp ? &vp->IDirect3DViewport3_iface : NULL);
866 /*****************************************************************************
867 * IDirect3DDevice3::NextViewport
869 * Returns a viewport from the viewport list, depending on the
870 * passed viewport and the flags.
872 * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
873 * are equal.
875 * Params:
876 * Viewport: Viewport to use for beginning the search
877 * Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
879 * Returns:
880 * D3D_OK on success
881 * DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
883 *****************************************************************************/
884 static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
885 IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
887 struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
888 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
889 struct d3d_viewport *next;
890 struct list *entry;
892 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
893 iface, Viewport3, lplpDirect3DViewport3, flags);
895 if(!vp)
897 *lplpDirect3DViewport3 = NULL;
898 return DDERR_INVALIDPARAMS;
902 wined3d_mutex_lock();
903 switch (flags)
905 case D3DNEXT_NEXT:
906 entry = list_next(&This->viewport_list, &vp->entry);
907 break;
909 case D3DNEXT_HEAD:
910 entry = list_head(&This->viewport_list);
911 break;
913 case D3DNEXT_TAIL:
914 entry = list_tail(&This->viewport_list);
915 break;
917 default:
918 WARN("Invalid flags %#x.\n", flags);
919 *lplpDirect3DViewport3 = NULL;
920 wined3d_mutex_unlock();
921 return DDERR_INVALIDPARAMS;
924 if (entry)
926 next = LIST_ENTRY(entry, struct d3d_viewport, entry);
927 *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
929 else
930 *lplpDirect3DViewport3 = NULL;
932 wined3d_mutex_unlock();
934 return D3D_OK;
937 static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
938 IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
940 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
941 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
942 IDirect3DViewport3 *res;
943 HRESULT hr;
945 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
946 iface, viewport, next, flags);
948 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
949 &vp->IDirect3DViewport3_iface, &res, flags);
950 *next = (IDirect3DViewport2 *)res;
951 return hr;
954 static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
955 IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
957 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
958 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
959 IDirect3DViewport3 *res;
960 HRESULT hr;
962 TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
963 iface, viewport, next, flags);
965 hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
966 &vp->IDirect3DViewport3_iface, &res, flags);
967 *next = (IDirect3DViewport *)res;
968 return hr;
971 /*****************************************************************************
972 * IDirect3DDevice::Pick
974 * Executes an execute buffer without performing rendering. Instead, a
975 * list of primitives that intersect with (x1,y1) of the passed rectangle
976 * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
977 * this list.
979 * Version 1 only
981 * Params:
982 * ExecuteBuffer: Buffer to execute
983 * Viewport: Viewport to use for execution
984 * Flags: None are defined, according to the SDK
985 * Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
986 * x2 and y2 are ignored.
988 * Returns:
989 * D3D_OK because it's a stub
991 *****************************************************************************/
992 static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
993 IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
995 FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
996 iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
998 return D3D_OK;
1001 /*****************************************************************************
1002 * IDirect3DDevice::GetPickRecords
1004 * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
1006 * Version 1 only
1008 * Params:
1009 * Count: Pointer to a DWORD containing the numbers of pick records to
1010 * retrieve
1011 * D3DPickRec: Address to store the resulting D3DPICKRECORD array.
1013 * Returns:
1014 * D3D_OK, because it's a stub
1016 *****************************************************************************/
1017 static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
1018 DWORD *count, D3DPICKRECORD *records)
1020 FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1022 return D3D_OK;
1025 /*****************************************************************************
1026 * IDirect3DDevice7::EnumTextureformats
1028 * Enumerates the supported texture formats. It checks against a list of all possible
1029 * formats to see if WineD3D supports it. If so, then it is passed to the app.
1031 * This is for Version 7 and 3, older versions have a different
1032 * callback function and their own implementation
1034 * Params:
1035 * Callback: Callback to call for each enumerated format
1036 * Arg: Argument to pass to the callback
1038 * Returns:
1039 * D3D_OK on success
1040 * DDERR_INVALIDPARAMS if Callback == NULL
1042 *****************************************************************************/
1043 static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
1044 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1046 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1047 struct wined3d_display_mode mode;
1048 HRESULT hr;
1049 unsigned int i;
1051 static const enum wined3d_format_id FormatList[] =
1053 /* 16 bit */
1054 WINED3DFMT_B5G5R5X1_UNORM,
1055 WINED3DFMT_B5G5R5A1_UNORM,
1056 WINED3DFMT_B4G4R4A4_UNORM,
1057 WINED3DFMT_B5G6R5_UNORM,
1058 /* 32 bit */
1059 WINED3DFMT_B8G8R8X8_UNORM,
1060 WINED3DFMT_B8G8R8A8_UNORM,
1061 /* 8 bit */
1062 WINED3DFMT_B2G3R3_UNORM,
1063 WINED3DFMT_P8_UINT,
1064 /* FOURCC codes */
1065 WINED3DFMT_DXT1,
1066 WINED3DFMT_DXT2,
1067 WINED3DFMT_DXT3,
1068 WINED3DFMT_DXT4,
1069 WINED3DFMT_DXT5,
1072 static const enum wined3d_format_id BumpFormatList[] =
1074 WINED3DFMT_R8G8_SNORM,
1075 WINED3DFMT_R5G5_SNORM_L6_UNORM,
1076 WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1077 WINED3DFMT_R10G11B11_SNORM,
1078 WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1081 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1083 if (!callback)
1084 return DDERR_INVALIDPARAMS;
1086 wined3d_mutex_lock();
1088 memset(&mode, 0, sizeof(mode));
1089 if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1091 wined3d_mutex_unlock();
1092 WARN("Cannot get the current adapter format\n");
1093 return hr;
1096 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1098 if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, WINED3D_DEVICE_TYPE_HAL,
1099 mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE, WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1101 DDPIXELFORMAT pformat;
1103 memset(&pformat, 0, sizeof(pformat));
1104 pformat.dwSize = sizeof(pformat);
1105 ddrawformat_from_wined3dformat(&pformat, FormatList[i]);
1107 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1108 hr = callback(&pformat, context);
1109 if(hr != DDENUMRET_OK)
1111 TRACE("Format enumeration cancelled by application\n");
1112 wined3d_mutex_unlock();
1113 return D3D_OK;
1118 for (i = 0; i < ARRAY_SIZE(BumpFormatList); ++i)
1120 if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT,
1121 WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1122 WINED3D_BIND_SHADER_RESOURCE, WINED3D_RTYPE_TEXTURE_2D, BumpFormatList[i]) == D3D_OK)
1124 DDPIXELFORMAT pformat;
1126 memset(&pformat, 0, sizeof(pformat));
1127 pformat.dwSize = sizeof(pformat);
1128 ddrawformat_from_wined3dformat(&pformat, BumpFormatList[i]);
1130 TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1131 hr = callback(&pformat, context);
1132 if(hr != DDENUMRET_OK)
1134 TRACE("Format enumeration cancelled by application\n");
1135 wined3d_mutex_unlock();
1136 return D3D_OK;
1140 TRACE("End of enumeration\n");
1141 wined3d_mutex_unlock();
1143 return D3D_OK;
1146 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1147 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1149 return d3d_device7_EnumTextureFormats(iface, callback, context);
1152 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1153 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1155 HRESULT hr;
1156 WORD old_fpucw;
1158 old_fpucw = d3d_fpu_setup();
1159 hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1160 set_fpu_control_word(old_fpucw);
1162 return hr;
1165 static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
1166 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1168 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1170 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1172 return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1175 /*****************************************************************************
1176 * IDirect3DDevice2::EnumTextureformats
1178 * EnumTextureFormats for Version 1 and 2, see
1179 * IDirect3DDevice7::EnumTextureFormats for a more detailed description.
1181 * This version has a different callback and does not enumerate FourCC
1182 * formats
1184 *****************************************************************************/
1185 static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
1186 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1188 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1189 struct wined3d_display_mode mode;
1190 HRESULT hr;
1191 unsigned int i;
1193 static const enum wined3d_format_id FormatList[] =
1195 /* 16 bit */
1196 WINED3DFMT_B5G5R5X1_UNORM,
1197 WINED3DFMT_B5G5R5A1_UNORM,
1198 WINED3DFMT_B4G4R4A4_UNORM,
1199 WINED3DFMT_B5G6R5_UNORM,
1200 /* 32 bit */
1201 WINED3DFMT_B8G8R8X8_UNORM,
1202 WINED3DFMT_B8G8R8A8_UNORM,
1203 /* 8 bit */
1204 WINED3DFMT_B2G3R3_UNORM,
1205 WINED3DFMT_P8_UINT,
1206 /* FOURCC codes - Not in this version*/
1209 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1211 if (!callback)
1212 return DDERR_INVALIDPARAMS;
1214 wined3d_mutex_lock();
1216 memset(&mode, 0, sizeof(mode));
1217 if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1219 wined3d_mutex_unlock();
1220 WARN("Cannot get the current adapter format\n");
1221 return hr;
1224 for (i = 0; i < ARRAY_SIZE(FormatList); ++i)
1226 if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, WINED3D_DEVICE_TYPE_HAL,
1227 mode.format_id, 0, WINED3D_BIND_SHADER_RESOURCE, WINED3D_RTYPE_TEXTURE_2D, FormatList[i]) == D3D_OK)
1229 DDSURFACEDESC sdesc;
1231 memset(&sdesc, 0, sizeof(sdesc));
1232 sdesc.dwSize = sizeof(sdesc);
1233 sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1234 sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1235 sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1236 ddrawformat_from_wined3dformat(&sdesc.ddpfPixelFormat, FormatList[i]);
1238 TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1239 hr = callback(&sdesc, context);
1240 if(hr != DDENUMRET_OK)
1242 TRACE("Format enumeration cancelled by application\n");
1243 wined3d_mutex_unlock();
1244 return D3D_OK;
1248 TRACE("End of enumeration\n");
1249 wined3d_mutex_unlock();
1251 return D3D_OK;
1254 static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
1255 LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1257 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1259 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1261 return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1264 /*****************************************************************************
1265 * IDirect3DDevice::CreateMatrix
1267 * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1268 * allocated for the handle.
1270 * Version 1 only
1272 * Params
1273 * D3DMatHandle: Address to return the handle at
1275 * Returns:
1276 * D3D_OK on success
1277 * DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1279 *****************************************************************************/
1280 static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1282 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1283 D3DMATRIX *matrix;
1284 DWORD h;
1286 TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1288 if(!D3DMatHandle)
1289 return DDERR_INVALIDPARAMS;
1291 if (!(matrix = heap_alloc_zero(sizeof(*matrix))))
1293 ERR("Out of memory when allocating a D3DMATRIX\n");
1294 return DDERR_OUTOFMEMORY;
1297 wined3d_mutex_lock();
1299 h = ddraw_allocate_handle(&device->handle_table, matrix, DDRAW_HANDLE_MATRIX);
1300 if (h == DDRAW_INVALID_HANDLE)
1302 ERR("Failed to allocate a matrix handle.\n");
1303 heap_free(matrix);
1304 wined3d_mutex_unlock();
1305 return DDERR_OUTOFMEMORY;
1308 *D3DMatHandle = h + 1;
1310 TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1312 wined3d_mutex_unlock();
1314 return D3D_OK;
1317 /*****************************************************************************
1318 * IDirect3DDevice::SetMatrix
1320 * Sets a matrix for a matrix handle. The matrix is copied into the memory
1321 * allocated for the handle
1323 * Version 1 only
1325 * Params:
1326 * D3DMatHandle: Handle to set the matrix to
1327 * D3DMatrix: Matrix to set
1329 * Returns:
1330 * D3D_OK on success
1331 * DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1332 * to set is NULL
1334 *****************************************************************************/
1335 static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
1336 D3DMATRIXHANDLE matrix_handle, D3DMATRIX *matrix)
1338 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1339 D3DMATRIX *m;
1341 TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, matrix_handle, matrix);
1343 if (!matrix)
1344 return DDERR_INVALIDPARAMS;
1346 wined3d_mutex_lock();
1348 m = ddraw_get_object(&device->handle_table, matrix_handle - 1, DDRAW_HANDLE_MATRIX);
1349 if (!m)
1351 WARN("Invalid matrix handle.\n");
1352 wined3d_mutex_unlock();
1353 return DDERR_INVALIDPARAMS;
1356 if (TRACE_ON(ddraw))
1357 dump_D3DMATRIX(matrix);
1359 *m = *matrix;
1361 if (matrix_handle == device->world)
1362 wined3d_stateblock_set_transform(device->state,
1363 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)matrix);
1365 if (matrix_handle == device->view)
1366 wined3d_stateblock_set_transform(device->state,
1367 WINED3D_TS_VIEW, (struct wined3d_matrix *)matrix);
1369 if (matrix_handle == device->proj)
1370 wined3d_stateblock_set_transform(device->state,
1371 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)matrix);
1373 wined3d_mutex_unlock();
1375 return D3D_OK;
1378 /*****************************************************************************
1379 * IDirect3DDevice::GetMatrix
1381 * Returns the content of a D3DMATRIX handle
1383 * Version 1 only
1385 * Params:
1386 * D3DMatHandle: Matrix handle to read the content from
1387 * D3DMatrix: Address to store the content at
1389 * Returns:
1390 * D3D_OK on success
1391 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1393 *****************************************************************************/
1394 static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
1395 D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1397 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1398 D3DMATRIX *m;
1400 TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1402 if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1404 wined3d_mutex_lock();
1406 m = ddraw_get_object(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1407 if (!m)
1409 WARN("Invalid matrix handle.\n");
1410 wined3d_mutex_unlock();
1411 return DDERR_INVALIDPARAMS;
1414 *D3DMatrix = *m;
1416 wined3d_mutex_unlock();
1418 return D3D_OK;
1421 /*****************************************************************************
1422 * IDirect3DDevice::DeleteMatrix
1424 * Destroys a Matrix handle. Frees the memory and unsets the handle data
1426 * Version 1 only
1428 * Params:
1429 * D3DMatHandle: Handle to destroy
1431 * Returns:
1432 * D3D_OK on success
1433 * DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1435 *****************************************************************************/
1436 static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1438 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1439 D3DMATRIX *m;
1441 TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1443 wined3d_mutex_lock();
1445 m = ddraw_free_handle(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1446 if (!m)
1448 WARN("Invalid matrix handle.\n");
1449 wined3d_mutex_unlock();
1450 return DDERR_INVALIDPARAMS;
1453 wined3d_mutex_unlock();
1455 heap_free(m);
1457 return D3D_OK;
1460 /*****************************************************************************
1461 * IDirect3DDevice7::BeginScene
1463 * This method must be called before any rendering is performed.
1464 * IDirect3DDevice::EndScene has to be called after the scene is complete
1466 * Version 1, 2, 3 and 7
1468 * Returns:
1469 * D3D_OK on success,
1470 * D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1471 * started scene).
1473 *****************************************************************************/
1474 static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1476 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1477 HRESULT hr;
1479 TRACE("iface %p.\n", iface);
1481 wined3d_mutex_lock();
1482 hr = wined3d_device_begin_scene(device->wined3d_device);
1483 wined3d_mutex_unlock();
1485 if(hr == WINED3D_OK) return D3D_OK;
1486 else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1489 static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1491 return d3d_device7_BeginScene(iface);
1494 static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1496 HRESULT hr;
1497 WORD old_fpucw;
1499 old_fpucw = d3d_fpu_setup();
1500 hr = d3d_device7_BeginScene(iface);
1501 set_fpu_control_word(old_fpucw);
1503 return hr;
1506 static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1508 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1510 TRACE("iface %p.\n", iface);
1512 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1515 static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1517 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1519 TRACE("iface %p.\n", iface);
1521 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1524 static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1526 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1528 TRACE("iface %p.\n", iface);
1530 return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1533 /*****************************************************************************
1534 * IDirect3DDevice7::EndScene
1536 * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1537 * This method must be called after rendering is finished.
1539 * Version 1, 2, 3 and 7
1541 * Returns:
1542 * D3D_OK on success,
1543 * D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1544 * that only if the scene was already ended.
1546 *****************************************************************************/
1547 static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1549 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1550 HRESULT hr;
1552 TRACE("iface %p.\n", iface);
1554 wined3d_mutex_lock();
1555 hr = wined3d_device_end_scene(device->wined3d_device);
1556 wined3d_mutex_unlock();
1558 if(hr == WINED3D_OK) return D3D_OK;
1559 else return D3DERR_SCENE_NOT_IN_SCENE;
1562 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1564 return d3d_device7_EndScene(iface);
1567 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1569 HRESULT hr;
1570 WORD old_fpucw;
1572 old_fpucw = d3d_fpu_setup();
1573 hr = d3d_device7_EndScene(iface);
1574 set_fpu_control_word(old_fpucw);
1576 return hr;
1579 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1581 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1583 TRACE("iface %p.\n", iface);
1585 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1588 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1590 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1592 TRACE("iface %p.\n", iface);
1594 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1597 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1599 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1601 TRACE("iface %p.\n", iface);
1603 return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1606 /*****************************************************************************
1607 * IDirect3DDevice7::GetDirect3D
1609 * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1610 * this device.
1612 * Params:
1613 * Direct3D7: Address to store the interface pointer at
1615 * Returns:
1616 * D3D_OK on success
1617 * DDERR_INVALIDPARAMS if Direct3D7 == NULL
1619 *****************************************************************************/
1620 static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1622 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1624 TRACE("iface %p, d3d %p.\n", iface, d3d);
1626 if (!d3d)
1627 return DDERR_INVALIDPARAMS;
1629 *d3d = &device->ddraw->IDirect3D7_iface;
1630 IDirect3D7_AddRef(*d3d);
1632 TRACE("Returning interface %p.\n", *d3d);
1633 return D3D_OK;
1636 static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1638 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1640 TRACE("iface %p, d3d %p.\n", iface, d3d);
1642 if (!d3d)
1643 return DDERR_INVALIDPARAMS;
1645 *d3d = &device->ddraw->IDirect3D3_iface;
1646 IDirect3D3_AddRef(*d3d);
1648 TRACE("Returning interface %p.\n", *d3d);
1649 return D3D_OK;
1652 static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1654 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1656 TRACE("iface %p, d3d %p.\n", iface, d3d);
1658 if (!d3d)
1659 return DDERR_INVALIDPARAMS;
1661 *d3d = &device->ddraw->IDirect3D2_iface;
1662 IDirect3D2_AddRef(*d3d);
1664 TRACE("Returning interface %p.\n", *d3d);
1665 return D3D_OK;
1668 static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1670 struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1672 TRACE("iface %p, d3d %p.\n", iface, d3d);
1674 if (!d3d)
1675 return DDERR_INVALIDPARAMS;
1677 *d3d = &device->ddraw->IDirect3D_iface;
1678 IDirect3D_AddRef(*d3d);
1680 TRACE("Returning interface %p.\n", *d3d);
1681 return D3D_OK;
1684 /*****************************************************************************
1685 * IDirect3DDevice3::SetCurrentViewport
1687 * Sets a Direct3DViewport as the current viewport.
1688 * For the thunks note that all viewport interface versions are equal
1690 * Params:
1691 * Direct3DViewport3: The viewport to set
1693 * Version 2 and 3
1695 * Returns:
1696 * D3D_OK on success
1697 * (Is a NULL viewport valid?)
1699 *****************************************************************************/
1700 static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
1702 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
1703 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1705 TRACE("iface %p, viewport %p, current_viewport %p.\n", iface, viewport, device->current_viewport);
1707 if (!vp)
1709 WARN("Direct3DViewport3 is NULL.\n");
1710 return DDERR_INVALIDPARAMS;
1713 wined3d_mutex_lock();
1714 /* Do nothing if the specified viewport is the same as the current one */
1715 if (device->current_viewport == vp)
1717 wined3d_mutex_unlock();
1718 return D3D_OK;
1721 if (vp->active_device != device)
1723 WARN("Viewport %p, active device %p.\n", vp, vp->active_device);
1724 wined3d_mutex_unlock();
1725 return DDERR_INVALIDPARAMS;
1728 IDirect3DViewport3_AddRef(viewport);
1729 if (device->current_viewport)
1731 viewport_deactivate(device->current_viewport);
1732 IDirect3DViewport3_Release(&device->current_viewport->IDirect3DViewport3_iface);
1734 device->current_viewport = vp;
1735 viewport_activate(device->current_viewport, FALSE);
1737 wined3d_mutex_unlock();
1739 return D3D_OK;
1742 static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1744 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1745 struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1747 TRACE("iface %p, viewport %p.\n", iface, viewport);
1749 return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface,
1750 vp ? &vp->IDirect3DViewport3_iface : NULL);
1753 /*****************************************************************************
1754 * IDirect3DDevice3::GetCurrentViewport
1756 * Returns the currently active viewport.
1758 * Version 2 and 3
1760 * Params:
1761 * Direct3DViewport3: Address to return the interface pointer at
1763 * Returns:
1764 * D3D_OK on success
1765 * DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1767 *****************************************************************************/
1768 static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1770 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1772 TRACE("iface %p, viewport %p.\n", iface, viewport);
1774 wined3d_mutex_lock();
1775 if (!device->current_viewport)
1777 wined3d_mutex_unlock();
1778 WARN("No current viewport, returning D3DERR_NOCURRENTVIEWPORT\n");
1779 return D3DERR_NOCURRENTVIEWPORT;
1782 *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1783 IDirect3DViewport3_AddRef(*viewport);
1785 TRACE("Returning interface %p.\n", *viewport);
1786 wined3d_mutex_unlock();
1787 return D3D_OK;
1790 static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1792 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1794 TRACE("iface %p, viewport %p.\n", iface, viewport);
1796 return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
1797 (IDirect3DViewport3 **)viewport);
1800 static BOOL validate_surface_palette(struct ddraw_surface *surface)
1802 return !format_is_paletteindexed(&surface->surface_desc.u4.ddpfPixelFormat)
1803 || surface->palette;
1806 static HRESULT d3d_device_set_render_target(struct d3d_device *device,
1807 struct ddraw_surface *target, IUnknown *rt_iface)
1809 HRESULT hr;
1811 if (device->rt_iface == rt_iface)
1813 TRACE("No-op SetRenderTarget operation, not doing anything\n");
1814 return D3D_OK;
1816 if (!target)
1818 WARN("Trying to set render target to NULL.\n");
1819 return DDERR_INVALIDPARAMS;
1822 if (FAILED(hr = wined3d_device_set_rendertarget_view(device->wined3d_device,
1823 0, ddraw_surface_get_rendertarget_view(target), FALSE)))
1824 return hr;
1826 IUnknown_AddRef(rt_iface);
1827 IUnknown_Release(device->rt_iface);
1828 device->rt_iface = rt_iface;
1829 d3d_device_update_depth_stencil(device);
1831 return D3D_OK;
1834 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
1835 IDirectDrawSurface7 *target, DWORD flags)
1837 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface7(target);
1838 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1839 HRESULT hr;
1841 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1843 wined3d_mutex_lock();
1845 if (!validate_surface_palette(target_impl))
1847 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1848 wined3d_mutex_unlock();
1849 return DDERR_INVALIDCAPS;
1852 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1854 WARN("Surface %p is not a render target.\n", target_impl);
1855 wined3d_mutex_unlock();
1856 return DDERR_INVALIDCAPS;
1859 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1861 WARN("Surface %p is not in video memory.\n", target_impl);
1862 wined3d_mutex_unlock();
1863 return DDERR_INVALIDPARAMS;
1866 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1868 WARN("Surface %p is a depth buffer.\n", target_impl);
1869 IDirectDrawSurface7_AddRef(target);
1870 IUnknown_Release(device->rt_iface);
1871 device->rt_iface = (IUnknown *)target;
1872 wined3d_mutex_unlock();
1873 return DDERR_INVALIDPIXELFORMAT;
1876 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1877 wined3d_mutex_unlock();
1878 return hr;
1881 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1882 IDirectDrawSurface7 *NewTarget, DWORD flags)
1884 return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1887 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1888 IDirectDrawSurface7 *NewTarget, DWORD flags)
1890 HRESULT hr;
1891 WORD old_fpucw;
1893 old_fpucw = d3d_fpu_setup();
1894 hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1895 set_fpu_control_word(old_fpucw);
1897 return hr;
1900 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
1901 IDirectDrawSurface4 *target, DWORD flags)
1903 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface4(target);
1904 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1905 HRESULT hr;
1907 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1909 wined3d_mutex_lock();
1911 if (!validate_surface_palette(target_impl))
1913 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1914 wined3d_mutex_unlock();
1915 return DDERR_INVALIDCAPS;
1918 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1920 WARN("Surface %p is not a render target.\n", target_impl);
1921 wined3d_mutex_unlock();
1922 return DDERR_INVALIDCAPS;
1925 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1927 WARN("Surface %p is a depth buffer.\n", target_impl);
1928 IDirectDrawSurface4_AddRef(target);
1929 IUnknown_Release(device->rt_iface);
1930 device->rt_iface = (IUnknown *)target;
1931 wined3d_mutex_unlock();
1932 return DDERR_INVALIDPIXELFORMAT;
1935 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1937 WARN("Surface %p is not in video memory.\n", target_impl);
1938 IDirectDrawSurface4_AddRef(target);
1939 IUnknown_Release(device->rt_iface);
1940 device->rt_iface = (IUnknown *)target;
1941 wined3d_mutex_unlock();
1942 return D3D_OK;
1945 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1946 wined3d_mutex_unlock();
1947 return hr;
1950 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
1951 IDirectDrawSurface *target, DWORD flags)
1953 struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface(target);
1954 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1955 HRESULT hr;
1957 TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
1959 wined3d_mutex_lock();
1961 if (!validate_surface_palette(target_impl))
1963 WARN("Surface %p has an indexed pixel format, but no palette.\n", target_impl);
1964 wined3d_mutex_unlock();
1965 return DDERR_INVALIDCAPS;
1968 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE))
1970 WARN("Surface %p is not a render target.\n", target_impl);
1971 wined3d_mutex_unlock();
1972 return DDERR_INVALIDCAPS;
1975 if (target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
1977 WARN("Surface %p is a depth buffer.\n", target_impl);
1978 IUnknown_Release(device->rt_iface);
1979 device->rt_iface = (IUnknown *)target;
1980 wined3d_mutex_unlock();
1981 return DDERR_INVALIDPIXELFORMAT;
1984 if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
1986 WARN("Surface %p is not in video memory.\n", target_impl);
1987 IDirectDrawSurface_AddRef(target);
1988 IUnknown_Release(device->rt_iface);
1989 device->rt_iface = (IUnknown *)target;
1990 wined3d_mutex_unlock();
1991 return D3D_OK;
1994 hr = d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
1995 wined3d_mutex_unlock();
1996 return hr;
1999 /*****************************************************************************
2000 * IDirect3DDevice7::GetRenderTarget
2002 * Returns the current render target.
2003 * This is handled locally, because the WineD3D render target's parent
2004 * is an IParent
2006 * Version 2, 3 and 7
2008 * Params:
2009 * RenderTarget: Address to store the surface interface pointer
2011 * Returns:
2012 * D3D_OK on success
2013 * DDERR_INVALIDPARAMS if RenderTarget == NULL
2015 *****************************************************************************/
2016 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
2018 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2019 HRESULT hr;
2021 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2023 if(!RenderTarget)
2024 return DDERR_INVALIDPARAMS;
2026 wined3d_mutex_lock();
2027 hr = IUnknown_QueryInterface(device->rt_iface, &IID_IDirectDrawSurface7, (void **)RenderTarget);
2028 wined3d_mutex_unlock();
2030 return hr;
2033 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
2035 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2036 IDirectDrawSurface7 *RenderTarget7;
2037 struct ddraw_surface *RenderTargetImpl;
2038 HRESULT hr;
2040 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2042 if(!RenderTarget)
2043 return DDERR_INVALIDPARAMS;
2045 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2046 if(hr != D3D_OK) return hr;
2047 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2048 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
2049 IDirectDrawSurface4_AddRef(*RenderTarget);
2050 IDirectDrawSurface7_Release(RenderTarget7);
2051 return D3D_OK;
2054 static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
2056 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2057 IDirectDrawSurface7 *RenderTarget7;
2058 struct ddraw_surface *RenderTargetImpl;
2059 HRESULT hr;
2061 TRACE("iface %p, target %p.\n", iface, RenderTarget);
2063 if(!RenderTarget)
2064 return DDERR_INVALIDPARAMS;
2066 hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
2067 if(hr != D3D_OK) return hr;
2068 RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
2069 *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
2070 IDirectDrawSurface_AddRef(*RenderTarget);
2071 IDirectDrawSurface7_Release(RenderTarget7);
2072 return D3D_OK;
2075 /*****************************************************************************
2076 * IDirect3DDevice3::Begin
2078 * Begins a description block of vertices. This is similar to glBegin()
2079 * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
2080 * described with IDirect3DDevice::Vertex are drawn.
2082 * Version 2 and 3
2084 * Params:
2085 * PrimitiveType: The type of primitives to draw
2086 * VertexTypeDesc: A flexible vertex format description of the vertices
2087 * Flags: Some flags..
2089 * Returns:
2090 * D3D_OK on success
2092 *****************************************************************************/
2093 static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
2094 D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
2096 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2098 TRACE("iface %p, primitive_type %#x, fvf %#x, flags %#x.\n",
2099 iface, primitive_type, fvf, flags);
2101 wined3d_mutex_lock();
2102 device->primitive_type = primitive_type;
2103 device->vertex_type = fvf;
2104 device->render_flags = flags;
2105 device->vertex_size = get_flexible_vertex_size(device->vertex_type);
2106 device->nb_vertices = 0;
2107 wined3d_mutex_unlock();
2109 return D3D_OK;
2112 static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
2113 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2115 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2116 DWORD fvf;
2118 TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2119 iface, primitive_type, vertex_type, flags);
2121 switch (vertex_type)
2123 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2124 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2125 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2126 default:
2127 ERR("Unexpected vertex type %#x.\n", vertex_type);
2128 return DDERR_INVALIDPARAMS; /* Should never happen */
2131 return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2134 /*****************************************************************************
2135 * IDirect3DDevice3::BeginIndexed
2137 * Draws primitives based on vertices in a vertex array which are specified
2138 * by indices.
2140 * Version 2 and 3
2142 * Params:
2143 * PrimitiveType: Primitive type to draw
2144 * VertexType: A FVF description of the vertex format
2145 * Vertices: pointer to an array containing the vertices
2146 * NumVertices: The number of vertices in the vertex array
2147 * Flags: Some flags ...
2149 * Returns:
2150 * D3D_OK, because it's a stub
2152 *****************************************************************************/
2153 static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
2154 D3DPRIMITIVETYPE primitive_type, DWORD fvf,
2155 void *vertices, DWORD vertex_count, DWORD flags)
2157 FIXME("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2158 iface, primitive_type, fvf, vertices, vertex_count, flags);
2160 return D3D_OK;
2164 static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
2165 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
2166 void *vertices, DWORD vertex_count, DWORD flags)
2168 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2169 DWORD fvf;
2171 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2172 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2174 switch (vertex_type)
2176 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2177 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2178 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2179 default:
2180 ERR("Unexpected vertex type %#x.\n", vertex_type);
2181 return DDERR_INVALIDPARAMS; /* Should never happen */
2184 return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
2185 primitive_type, fvf, vertices, vertex_count, flags);
2188 /*****************************************************************************
2189 * IDirect3DDevice3::Vertex
2191 * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2192 * drawn vertices in a vertex buffer. If the buffer is too small, its
2193 * size is increased.
2195 * Version 2 and 3
2197 * Params:
2198 * Vertex: Pointer to the vertex
2200 * Returns:
2201 * D3D_OK, on success
2202 * DDERR_INVALIDPARAMS if Vertex is NULL
2204 *****************************************************************************/
2205 static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2207 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2209 TRACE("iface %p, vertex %p.\n", iface, vertex);
2211 if (!vertex)
2212 return DDERR_INVALIDPARAMS;
2214 wined3d_mutex_lock();
2215 if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2217 BYTE *old_buffer;
2219 device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
2220 old_buffer = device->sysmem_vertex_buffer;
2221 device->sysmem_vertex_buffer = heap_alloc(device->buffer_size);
2222 if (old_buffer)
2224 memcpy(device->sysmem_vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2225 heap_free(old_buffer);
2229 memcpy(device->sysmem_vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2230 wined3d_mutex_unlock();
2232 return D3D_OK;
2235 static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2237 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2239 TRACE("iface %p, vertex %p.\n", iface, vertex);
2241 return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2244 /*****************************************************************************
2245 * IDirect3DDevice3::Index
2247 * Specifies an index to a vertex to be drawn. The vertex array has to
2248 * be specified with BeginIndexed first.
2250 * Parameters:
2251 * VertexIndex: The index of the vertex to draw
2253 * Returns:
2254 * D3D_OK because it's a stub
2256 *****************************************************************************/
2257 static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2259 FIXME("iface %p, index %#x stub!\n", iface, index);
2261 return D3D_OK;
2264 static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2266 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2268 TRACE("iface %p, index %#x.\n", iface, index);
2270 return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2273 /*****************************************************************************
2274 * IDirect3DDevice7::GetRenderState
2276 * Returns the value of a render state. The possible render states are
2277 * defined in include/d3dtypes.h
2279 * Version 2, 3 and 7
2281 * Params:
2282 * RenderStateType: Render state to return the current setting of
2283 * Value: Address to store the value at
2285 * Returns:
2286 * D3D_OK on success,
2287 * DDERR_INVALIDPARAMS if Value == NULL
2289 *****************************************************************************/
2290 static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
2291 D3DRENDERSTATETYPE state, DWORD *value)
2293 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2294 const struct wined3d_stateblock_state *device_state;
2295 HRESULT hr = D3D_OK;
2297 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2299 if (!value)
2300 return DDERR_INVALIDPARAMS;
2302 wined3d_mutex_lock();
2303 device_state = wined3d_stateblock_get_state(device->state);
2304 switch (state)
2306 case D3DRENDERSTATE_TEXTUREMAG:
2308 enum wined3d_texture_filter_type tex_mag = device_state->sampler_states[0][WINED3D_SAMP_MAG_FILTER];
2310 switch (tex_mag)
2312 case WINED3D_TEXF_POINT:
2313 *value = D3DFILTER_NEAREST;
2314 break;
2315 case WINED3D_TEXF_LINEAR:
2316 *value = D3DFILTER_LINEAR;
2317 break;
2318 default:
2319 ERR("Unhandled texture mag %d !\n",tex_mag);
2320 *value = 0;
2322 break;
2325 case D3DRENDERSTATE_TEXTUREMIN:
2327 enum wined3d_texture_filter_type tex_min;
2328 enum wined3d_texture_filter_type tex_mip;
2330 tex_min = device_state->sampler_states[0][WINED3D_SAMP_MIN_FILTER];
2331 tex_mip = device_state->sampler_states[0][WINED3D_SAMP_MIP_FILTER];
2332 switch (tex_min)
2334 case WINED3D_TEXF_POINT:
2335 switch (tex_mip)
2337 case WINED3D_TEXF_NONE:
2338 *value = D3DFILTER_NEAREST;
2339 break;
2340 case WINED3D_TEXF_POINT:
2341 *value = D3DFILTER_MIPNEAREST;
2342 break;
2343 case WINED3D_TEXF_LINEAR:
2344 *value = D3DFILTER_LINEARMIPNEAREST;
2345 break;
2346 default:
2347 ERR("Unhandled mip filter %#x.\n", tex_mip);
2348 *value = D3DFILTER_NEAREST;
2349 break;
2351 break;
2352 case WINED3D_TEXF_LINEAR:
2353 switch (tex_mip)
2355 case WINED3D_TEXF_NONE:
2356 *value = D3DFILTER_LINEAR;
2357 break;
2358 case WINED3D_TEXF_POINT:
2359 *value = D3DFILTER_MIPLINEAR;
2360 break;
2361 case WINED3D_TEXF_LINEAR:
2362 *value = D3DFILTER_LINEARMIPLINEAR;
2363 break;
2364 default:
2365 ERR("Unhandled mip filter %#x.\n", tex_mip);
2366 *value = D3DFILTER_LINEAR;
2367 break;
2369 break;
2370 default:
2371 ERR("Unhandled texture min filter %#x.\n",tex_min);
2372 *value = D3DFILTER_NEAREST;
2373 break;
2375 break;
2378 case D3DRENDERSTATE_TEXTUREADDRESS:
2379 case D3DRENDERSTATE_TEXTUREADDRESSU:
2380 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_U];
2381 break;
2382 case D3DRENDERSTATE_TEXTUREADDRESSV:
2383 *value = device_state->sampler_states[0][WINED3D_SAMP_ADDRESS_V];
2384 break;
2386 case D3DRENDERSTATE_BORDERCOLOR:
2387 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2388 hr = E_NOTIMPL;
2389 break;
2391 case D3DRENDERSTATE_TEXTUREHANDLE:
2392 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2393 WARN("Render state %#x is invalid in d3d7.\n", state);
2394 hr = DDERR_INVALIDPARAMS;
2395 break;
2397 case D3DRENDERSTATE_ZBIAS:
2398 *value = device_state->rs[WINED3D_RS_DEPTHBIAS];
2399 break;
2401 default:
2402 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2403 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2405 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2406 hr = E_NOTIMPL;
2407 break;
2409 *value = device_state->rs[state];
2411 wined3d_mutex_unlock();
2413 return hr;
2416 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2417 D3DRENDERSTATETYPE state, DWORD *value)
2419 return d3d_device7_GetRenderState(iface, state, value);
2422 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2423 D3DRENDERSTATETYPE state, DWORD *value)
2425 HRESULT hr;
2426 WORD old_fpucw;
2428 old_fpucw = d3d_fpu_setup();
2429 hr = d3d_device7_GetRenderState(iface, state, value);
2430 set_fpu_control_word(old_fpucw);
2432 return hr;
2435 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2436 D3DRENDERSTATETYPE state, DWORD *value)
2438 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2440 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2442 switch (state)
2444 case D3DRENDERSTATE_TEXTUREHANDLE:
2446 /* This state is wrapped to SetTexture in SetRenderState, so
2447 * it has to be wrapped to GetTexture here. */
2448 struct wined3d_texture *tex = NULL;
2449 *value = 0;
2451 wined3d_mutex_lock();
2452 if ((tex = wined3d_stateblock_get_state(device->state)->textures[0]))
2454 /* The parent of the texture is the IDirectDrawSurface7
2455 * interface of the ddraw surface. */
2456 struct ddraw_texture *parent = wined3d_texture_get_parent(tex);
2457 if (parent)
2458 *value = parent->root->Handle;
2460 wined3d_mutex_unlock();
2462 return D3D_OK;
2465 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2467 *value = device->texture_map_blend;
2468 return D3D_OK;
2471 case D3DRENDERSTATE_LIGHTING:
2472 case D3DRENDERSTATE_NORMALIZENORMALS:
2473 case D3DRENDERSTATE_LOCALVIEWER:
2474 *value = 0xffffffff;
2475 return D3D_OK;
2477 default:
2478 return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2482 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2483 D3DRENDERSTATETYPE state, DWORD *value)
2485 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2487 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2489 return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2492 /*****************************************************************************
2493 * IDirect3DDevice7::SetRenderState
2495 * Sets a render state. The possible render states are defined in
2496 * include/d3dtypes.h
2498 * Version 2, 3 and 7
2500 * Params:
2501 * RenderStateType: State to set
2502 * Value: Value to assign to that state
2504 *****************************************************************************/
2505 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2506 D3DRENDERSTATETYPE state, DWORD value)
2508 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2509 HRESULT hr = D3D_OK;
2511 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2513 wined3d_mutex_lock();
2514 /* Some render states need special care */
2515 switch (state)
2518 * The ddraw texture filter mapping works like this:
2519 * D3DFILTER_NEAREST Point min/mag, no mip
2520 * D3DFILTER_MIPNEAREST Point min/mag, point mip
2521 * D3DFILTER_LINEARMIPNEAREST: Point min/mag, linear mip
2523 * D3DFILTER_LINEAR Linear min/mag, no mip
2524 * D3DFILTER_MIPLINEAR Linear min/mag, point mip
2525 * D3DFILTER_LINEARMIPLINEAR Linear min/mag, linear mip
2527 * This is the opposite of the GL naming convention,
2528 * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2530 case D3DRENDERSTATE_TEXTUREMAG:
2532 enum wined3d_texture_filter_type tex_mag;
2534 switch (value)
2536 case D3DFILTER_NEAREST:
2537 case D3DFILTER_MIPNEAREST:
2538 case D3DFILTER_LINEARMIPNEAREST:
2539 tex_mag = WINED3D_TEXF_POINT;
2540 break;
2541 case D3DFILTER_LINEAR:
2542 case D3DFILTER_MIPLINEAR:
2543 case D3DFILTER_LINEARMIPLINEAR:
2544 tex_mag = WINED3D_TEXF_LINEAR;
2545 break;
2546 default:
2547 tex_mag = WINED3D_TEXF_POINT;
2548 FIXME("Unhandled texture mag %#x.\n", value);
2549 break;
2552 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2553 break;
2556 case D3DRENDERSTATE_TEXTUREMIN:
2558 enum wined3d_texture_filter_type tex_min;
2559 enum wined3d_texture_filter_type tex_mip;
2561 switch (value)
2563 case D3DFILTER_NEAREST:
2564 tex_min = WINED3D_TEXF_POINT;
2565 tex_mip = WINED3D_TEXF_NONE;
2566 break;
2567 case D3DFILTER_LINEAR:
2568 tex_min = WINED3D_TEXF_LINEAR;
2569 tex_mip = WINED3D_TEXF_NONE;
2570 break;
2571 case D3DFILTER_MIPNEAREST:
2572 tex_min = WINED3D_TEXF_POINT;
2573 tex_mip = WINED3D_TEXF_POINT;
2574 break;
2575 case D3DFILTER_MIPLINEAR:
2576 tex_min = WINED3D_TEXF_LINEAR;
2577 tex_mip = WINED3D_TEXF_POINT;
2578 break;
2579 case D3DFILTER_LINEARMIPNEAREST:
2580 tex_min = WINED3D_TEXF_POINT;
2581 tex_mip = WINED3D_TEXF_LINEAR;
2582 break;
2583 case D3DFILTER_LINEARMIPLINEAR:
2584 tex_min = WINED3D_TEXF_LINEAR;
2585 tex_mip = WINED3D_TEXF_LINEAR;
2586 break;
2588 default:
2589 FIXME("Unhandled texture min %#x.\n",value);
2590 tex_min = WINED3D_TEXF_POINT;
2591 tex_mip = WINED3D_TEXF_NONE;
2592 break;
2595 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2596 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_MIN_FILTER, tex_min);
2597 break;
2600 case D3DRENDERSTATE_TEXTUREADDRESS:
2601 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2602 /* Drop through */
2603 case D3DRENDERSTATE_TEXTUREADDRESSU:
2604 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_U, value);
2605 break;
2606 case D3DRENDERSTATE_TEXTUREADDRESSV:
2607 wined3d_stateblock_set_sampler_state(device->state, 0, WINED3D_SAMP_ADDRESS_V, value);
2608 break;
2610 case D3DRENDERSTATE_BORDERCOLOR:
2611 /* This should probably just forward to the corresponding sampler
2612 * state. Needs tests. */
2613 FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2614 hr = E_NOTIMPL;
2615 break;
2617 case D3DRENDERSTATE_TEXTUREHANDLE:
2618 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2619 WARN("Render state %#x is invalid in d3d7.\n", state);
2620 hr = DDERR_INVALIDPARAMS;
2621 break;
2623 case D3DRENDERSTATE_ZBIAS:
2624 wined3d_stateblock_set_render_state(device->update_state, WINED3D_RS_DEPTHBIAS, value);
2625 break;
2627 default:
2628 if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2629 && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2631 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2632 hr = E_NOTIMPL;
2633 break;
2636 wined3d_stateblock_set_render_state(device->update_state, state, value);
2637 break;
2639 wined3d_mutex_unlock();
2641 return hr;
2644 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2645 D3DRENDERSTATETYPE state, DWORD value)
2647 return d3d_device7_SetRenderState(iface, state, value);
2650 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2651 D3DRENDERSTATETYPE state, DWORD value)
2653 HRESULT hr;
2654 WORD old_fpucw;
2656 old_fpucw = d3d_fpu_setup();
2657 hr = d3d_device7_SetRenderState(iface, state, value);
2658 set_fpu_control_word(old_fpucw);
2660 return hr;
2663 static void fixup_texture_alpha_op(struct d3d_device *device)
2665 /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
2666 See d3d_device3_SetRenderState() for details. */
2667 struct wined3d_texture *tex;
2668 BOOL tex_alpha = TRUE;
2669 DDPIXELFORMAT ddfmt;
2671 if (!(device->legacyTextureBlending && device->texture_map_blend == D3DTBLEND_MODULATE))
2672 return;
2674 if ((tex = wined3d_stateblock_get_state(device->state)->textures[0]))
2676 struct wined3d_resource_desc desc;
2678 wined3d_resource_get_desc(wined3d_texture_get_resource(tex), &desc);
2679 ddfmt.dwSize = sizeof(ddfmt);
2680 ddrawformat_from_wined3dformat(&ddfmt, desc.format);
2681 if (!ddfmt.u5.dwRGBAlphaBitMask)
2682 tex_alpha = FALSE;
2685 /* Args 1 and 2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
2686 wined3d_stateblock_set_texture_stage_state(device->state,
2687 0, WINED3D_TSS_ALPHA_OP, tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2);
2690 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2691 D3DRENDERSTATETYPE state, DWORD value)
2693 /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2694 for this state can be directly mapped to texture stage colorop and alphaop, but
2695 D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2696 from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2697 alphaarg when needed.
2699 Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2701 Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2702 TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2703 are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2704 requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2705 with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2706 in device - TRUE if the app is using TEXTUREMAPBLEND.
2708 Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2709 GetTextureStageState and vice versa. */
2711 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2712 HRESULT hr;
2714 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2716 if (state >= D3DSTATE_OVERRIDE_BIAS)
2718 WARN("Unhandled state %#x.\n", state);
2719 return DDERR_INVALIDPARAMS;
2722 wined3d_mutex_lock();
2724 switch (state)
2726 case D3DRENDERSTATE_TEXTUREHANDLE:
2728 struct ddraw_surface *surf;
2730 if (value == 0)
2732 wined3d_stateblock_set_texture(device->state, 0, NULL);
2733 hr = D3D_OK;
2734 break;
2737 surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2738 if (!surf)
2740 WARN("Invalid texture handle.\n");
2741 hr = DDERR_INVALIDPARAMS;
2742 break;
2745 hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2746 break;
2749 case D3DRENDERSTATE_TEXTUREMAPBLEND:
2751 if (value == device->texture_map_blend)
2753 TRACE("Application is setting the same value over, nothing to do.\n");
2755 hr = D3D_OK;
2756 break;
2759 device->legacyTextureBlending = TRUE;
2760 device->texture_map_blend = value;
2762 switch (value)
2764 case D3DTBLEND_MODULATE:
2766 fixup_texture_alpha_op(device);
2768 wined3d_stateblock_set_texture_stage_state(device->state,
2769 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2770 wined3d_stateblock_set_texture_stage_state(device->state,
2771 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2772 wined3d_stateblock_set_texture_stage_state(device->state,
2773 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2774 wined3d_stateblock_set_texture_stage_state(device->state,
2775 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2776 wined3d_stateblock_set_texture_stage_state(device->state,
2777 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2778 break;
2781 case D3DTBLEND_ADD:
2782 wined3d_stateblock_set_texture_stage_state(device->state,
2783 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2784 wined3d_stateblock_set_texture_stage_state(device->state,
2785 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2786 wined3d_stateblock_set_texture_stage_state(device->state,
2787 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2788 wined3d_stateblock_set_texture_stage_state(device->state,
2789 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2790 wined3d_stateblock_set_texture_stage_state(device->state,
2791 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2792 break;
2794 case D3DTBLEND_MODULATEALPHA:
2795 wined3d_stateblock_set_texture_stage_state(device->state,
2796 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2797 wined3d_stateblock_set_texture_stage_state(device->state,
2798 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2799 wined3d_stateblock_set_texture_stage_state(device->state,
2800 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2801 wined3d_stateblock_set_texture_stage_state(device->state,
2802 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2803 wined3d_stateblock_set_texture_stage_state(device->state,
2804 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2805 wined3d_stateblock_set_texture_stage_state(device->state,
2806 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2807 break;
2809 case D3DTBLEND_COPY:
2810 case D3DTBLEND_DECAL:
2811 wined3d_stateblock_set_texture_stage_state(device->state,
2812 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2813 wined3d_stateblock_set_texture_stage_state(device->state,
2814 0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2815 wined3d_stateblock_set_texture_stage_state(device->state,
2816 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2817 wined3d_stateblock_set_texture_stage_state(device->state,
2818 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2819 break;
2821 case D3DTBLEND_DECALALPHA:
2822 wined3d_stateblock_set_texture_stage_state(device->state,
2823 0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2824 wined3d_stateblock_set_texture_stage_state(device->state,
2825 0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2826 wined3d_stateblock_set_texture_stage_state(device->state,
2827 0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2828 wined3d_stateblock_set_texture_stage_state(device->state,
2829 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2830 wined3d_stateblock_set_texture_stage_state(device->state,
2831 0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2832 break;
2834 default:
2835 FIXME("Unhandled texture environment %#x.\n", value);
2837 hr = D3D_OK;
2838 break;
2841 case D3DRENDERSTATE_LIGHTING:
2842 case D3DRENDERSTATE_NORMALIZENORMALS:
2843 case D3DRENDERSTATE_LOCALVIEWER:
2844 hr = D3D_OK;
2845 break;
2847 default:
2848 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2849 break;
2851 wined3d_mutex_unlock();
2853 return hr;
2856 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2857 D3DRENDERSTATETYPE state, DWORD value)
2859 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2861 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2863 return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2866 /*****************************************************************************
2867 * Direct3DDevice3::SetLightState
2869 * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2870 * light states are forwarded to Direct3DDevice7 render states
2872 * Version 2 and 3
2874 * Params:
2875 * LightStateType: The light state to change
2876 * Value: The value to assign to that light state
2878 * Returns:
2879 * D3D_OK on success
2880 * DDERR_INVALIDPARAMS if the parameters were incorrect
2881 * Also check IDirect3DDevice7::SetRenderState
2883 *****************************************************************************/
2884 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2885 D3DLIGHTSTATETYPE state, DWORD value)
2887 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2888 HRESULT hr;
2890 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2892 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2894 TRACE("Unexpected Light State Type\n");
2895 return DDERR_INVALIDPARAMS;
2898 wined3d_mutex_lock();
2899 if (state == D3DLIGHTSTATE_MATERIAL)
2901 if (value)
2903 struct d3d_material *m;
2905 if (!(m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL)))
2907 WARN("Invalid material handle.\n");
2908 wined3d_mutex_unlock();
2909 return DDERR_INVALIDPARAMS;
2912 material_activate(m);
2915 device->material = value;
2917 else if (state == D3DLIGHTSTATE_COLORMODEL)
2919 switch (value)
2921 case D3DCOLOR_MONO:
2922 ERR("DDCOLOR_MONO should not happen!\n");
2923 break;
2924 case D3DCOLOR_RGB:
2925 /* We are already in this mode */
2926 TRACE("Setting color model to RGB (no-op).\n");
2927 break;
2928 default:
2929 ERR("Unknown color model!\n");
2930 wined3d_mutex_unlock();
2931 return DDERR_INVALIDPARAMS;
2934 else
2936 D3DRENDERSTATETYPE rs;
2937 switch (state)
2939 case D3DLIGHTSTATE_AMBIENT: /* 2 */
2940 rs = D3DRENDERSTATE_AMBIENT;
2941 break;
2942 case D3DLIGHTSTATE_FOGMODE: /* 4 */
2943 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2944 break;
2945 case D3DLIGHTSTATE_FOGSTART: /* 5 */
2946 rs = D3DRENDERSTATE_FOGSTART;
2947 break;
2948 case D3DLIGHTSTATE_FOGEND: /* 6 */
2949 rs = D3DRENDERSTATE_FOGEND;
2950 break;
2951 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
2952 rs = D3DRENDERSTATE_FOGDENSITY;
2953 break;
2954 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
2955 rs = D3DRENDERSTATE_COLORVERTEX;
2956 break;
2957 default:
2958 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2959 wined3d_mutex_unlock();
2960 return DDERR_INVALIDPARAMS;
2963 hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2964 wined3d_mutex_unlock();
2965 return hr;
2967 wined3d_mutex_unlock();
2969 return D3D_OK;
2972 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
2973 D3DLIGHTSTATETYPE state, DWORD value)
2975 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2977 TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2979 return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2982 /*****************************************************************************
2983 * IDirect3DDevice3::GetLightState
2985 * Returns the current setting of a light state. The state is read from
2986 * the Direct3DDevice7 render state.
2988 * Version 2 and 3
2990 * Params:
2991 * LightStateType: The light state to return
2992 * Value: The address to store the light state setting at
2994 * Returns:
2995 * D3D_OK on success
2996 * DDDERR_INVALIDPARAMS if the parameters were incorrect
2997 * Also see IDirect3DDevice7::GetRenderState
2999 *****************************************************************************/
3000 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
3001 D3DLIGHTSTATETYPE state, DWORD *value)
3003 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3004 HRESULT hr;
3006 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3008 if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
3010 TRACE("Unexpected Light State Type\n");
3011 return DDERR_INVALIDPARAMS;
3014 if (!value)
3015 return DDERR_INVALIDPARAMS;
3017 wined3d_mutex_lock();
3018 if (state == D3DLIGHTSTATE_MATERIAL)
3020 *value = device->material;
3022 else if (state == D3DLIGHTSTATE_COLORMODEL)
3024 *value = D3DCOLOR_RGB;
3026 else
3028 D3DRENDERSTATETYPE rs;
3029 switch (state)
3031 case D3DLIGHTSTATE_AMBIENT: /* 2 */
3032 rs = D3DRENDERSTATE_AMBIENT;
3033 break;
3034 case D3DLIGHTSTATE_FOGMODE: /* 4 */
3035 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3036 break;
3037 case D3DLIGHTSTATE_FOGSTART: /* 5 */
3038 rs = D3DRENDERSTATE_FOGSTART;
3039 break;
3040 case D3DLIGHTSTATE_FOGEND: /* 6 */
3041 rs = D3DRENDERSTATE_FOGEND;
3042 break;
3043 case D3DLIGHTSTATE_FOGDENSITY: /* 7 */
3044 rs = D3DRENDERSTATE_FOGDENSITY;
3045 break;
3046 case D3DLIGHTSTATE_COLORVERTEX: /* 8 */
3047 rs = D3DRENDERSTATE_COLORVERTEX;
3048 break;
3049 default:
3050 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3051 wined3d_mutex_unlock();
3052 return DDERR_INVALIDPARAMS;
3055 hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3056 wined3d_mutex_unlock();
3057 return hr;
3059 wined3d_mutex_unlock();
3061 return D3D_OK;
3064 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3065 D3DLIGHTSTATETYPE state, DWORD *value)
3067 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3069 TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3071 return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3074 /*****************************************************************************
3075 * IDirect3DDevice7::SetTransform
3077 * Assigns a D3DMATRIX to a transform type. The transform types are defined
3078 * in include/d3dtypes.h.
3079 * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3080 * (=255) for wined3d, because the 1 transform state was removed in d3d8
3081 * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3083 * Version 2, 3 and 7
3085 * Params:
3086 * TransformStateType: transform state to set
3087 * Matrix: Matrix to assign to the state
3089 * Returns:
3090 * D3D_OK on success
3091 * DDERR_INVALIDPARAMS if Matrix == NULL
3093 *****************************************************************************/
3094 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3095 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3097 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3098 enum wined3d_transform_state wined3d_state;
3100 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3102 switch (state)
3104 case D3DTRANSFORMSTATE_WORLD:
3105 wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3106 break;
3107 case D3DTRANSFORMSTATE_WORLD1:
3108 wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3109 break;
3110 case D3DTRANSFORMSTATE_WORLD2:
3111 wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3112 break;
3113 case D3DTRANSFORMSTATE_WORLD3:
3114 wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3115 break;
3116 default:
3117 wined3d_state = state;
3120 if (!matrix)
3121 return DDERR_INVALIDPARAMS;
3123 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3124 wined3d_mutex_lock();
3125 wined3d_stateblock_set_transform(device->update_state, wined3d_state, (const struct wined3d_matrix *)matrix);
3126 wined3d_mutex_unlock();
3128 return D3D_OK;
3131 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3132 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3134 return d3d_device7_SetTransform(iface, state, matrix);
3137 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3138 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3140 HRESULT hr;
3141 WORD old_fpucw;
3143 old_fpucw = d3d_fpu_setup();
3144 hr = d3d_device7_SetTransform(iface, state, matrix);
3145 set_fpu_control_word(old_fpucw);
3147 return hr;
3150 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3151 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3153 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3155 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3157 if (!matrix)
3158 return DDERR_INVALIDPARAMS;
3160 if (state == D3DTRANSFORMSTATE_PROJECTION)
3162 struct wined3d_matrix projection;
3164 wined3d_mutex_lock();
3165 multiply_matrix(&projection, &device->legacy_clipspace, (struct wined3d_matrix *)matrix);
3166 wined3d_stateblock_set_transform(device->state,
3167 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3168 memcpy(&device->legacy_projection, matrix, sizeof(*matrix));
3169 wined3d_mutex_unlock();
3171 return D3D_OK;
3174 return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3177 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3178 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3180 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3182 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3184 return IDirect3DDevice3_SetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3187 /*****************************************************************************
3188 * IDirect3DDevice7::GetTransform
3190 * Returns the matrix assigned to a transform state
3191 * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3192 * SetTransform
3194 * Params:
3195 * TransformStateType: State to read the matrix from
3196 * Matrix: Address to store the matrix at
3198 * Returns:
3199 * D3D_OK on success
3200 * DDERR_INVALIDPARAMS if Matrix == NULL
3202 *****************************************************************************/
3203 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3204 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3206 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3207 enum wined3d_transform_state wined3d_state;
3209 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3211 switch (state)
3213 case D3DTRANSFORMSTATE_WORLD:
3214 wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3215 break;
3216 case D3DTRANSFORMSTATE_WORLD1:
3217 wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3218 break;
3219 case D3DTRANSFORMSTATE_WORLD2:
3220 wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3221 break;
3222 case D3DTRANSFORMSTATE_WORLD3:
3223 wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3224 break;
3225 default:
3226 wined3d_state = state;
3229 if (!matrix)
3230 return DDERR_INVALIDPARAMS;
3232 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3233 wined3d_mutex_lock();
3234 memcpy(matrix, &wined3d_stateblock_get_state(device->state)->transforms[wined3d_state], sizeof(*matrix));
3235 wined3d_mutex_unlock();
3237 return D3D_OK;
3240 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3241 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3243 return d3d_device7_GetTransform(iface, state, matrix);
3246 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3247 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3249 HRESULT hr;
3250 WORD old_fpucw;
3252 old_fpucw = d3d_fpu_setup();
3253 hr = d3d_device7_GetTransform(iface, state, matrix);
3254 set_fpu_control_word(old_fpucw);
3256 return hr;
3259 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3260 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3262 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3264 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3266 if (!matrix)
3267 return DDERR_INVALIDPARAMS;
3269 if (state == D3DTRANSFORMSTATE_PROJECTION)
3271 wined3d_mutex_lock();
3272 memcpy(matrix, &device->legacy_projection, sizeof(*matrix));
3273 wined3d_mutex_unlock();
3274 return DD_OK;
3277 return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3280 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3281 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3283 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3285 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3287 return IDirect3DDevice3_GetTransform(&device->IDirect3DDevice3_iface, state, matrix);
3290 /*****************************************************************************
3291 * IDirect3DDevice7::MultiplyTransform
3293 * Multiplies the already-set transform matrix of a transform state
3294 * with another matrix. For the world matrix, see SetTransform
3296 * Version 2, 3 and 7
3298 * Params:
3299 * TransformStateType: Transform state to multiply
3300 * D3DMatrix Matrix to multiply with.
3302 * Returns
3303 * D3D_OK on success
3304 * DDERR_INVALIDPARAMS if D3DMatrix is NULL
3306 *****************************************************************************/
3307 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3308 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3310 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3311 enum wined3d_transform_state wined3d_state;
3313 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3315 switch (state)
3317 case D3DTRANSFORMSTATE_WORLD:
3318 wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3319 break;
3320 case D3DTRANSFORMSTATE_WORLD1:
3321 wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3322 break;
3323 case D3DTRANSFORMSTATE_WORLD2:
3324 wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3325 break;
3326 case D3DTRANSFORMSTATE_WORLD3:
3327 wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3328 break;
3329 default:
3330 wined3d_state = state;
3333 /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3334 wined3d_mutex_lock();
3335 wined3d_stateblock_multiply_transform(device->state,
3336 wined3d_state, (struct wined3d_matrix *)matrix);
3337 wined3d_mutex_unlock();
3339 return D3D_OK;
3342 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3343 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3345 return d3d_device7_MultiplyTransform(iface, state, matrix);
3348 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3349 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3351 HRESULT hr;
3352 WORD old_fpucw;
3354 old_fpucw = d3d_fpu_setup();
3355 hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3356 set_fpu_control_word(old_fpucw);
3358 return hr;
3361 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3362 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3364 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3366 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3368 if (state == D3DTRANSFORMSTATE_PROJECTION)
3370 struct wined3d_matrix projection, tmp;
3372 wined3d_mutex_lock();
3373 multiply_matrix(&tmp, &device->legacy_projection, (struct wined3d_matrix *)matrix);
3374 multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3375 wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
3376 device->legacy_projection = tmp;
3377 wined3d_mutex_unlock();
3379 return D3D_OK;
3382 return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3385 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3386 D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3388 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3390 TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3392 return IDirect3DDevice3_MultiplyTransform(&device->IDirect3DDevice3_iface, state, matrix);
3395 /*****************************************************************************
3396 * IDirect3DDevice7::DrawPrimitive
3398 * Draws primitives based on vertices in an application-provided pointer
3400 * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3401 * an FVF format for D3D7
3403 * Params:
3404 * PrimitiveType: The type of the primitives to draw
3405 * Vertex type: Flexible vertex format vertex description
3406 * Vertices: Pointer to the vertex array
3407 * VertexCount: The number of vertices to draw
3408 * Flags: As usual a few flags
3410 * Returns:
3411 * D3D_OK on success
3412 * DDERR_INVALIDPARAMS if Vertices is NULL
3414 *****************************************************************************/
3416 /* The caller is responsible for wined3d locking */
3417 static HRESULT d3d_device_prepare_vertex_buffer(struct d3d_device *device, UINT min_size)
3419 HRESULT hr;
3421 if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
3423 UINT size = max(device->vertex_buffer_size * 2, min_size);
3424 struct wined3d_buffer_desc desc;
3425 struct wined3d_buffer *buffer;
3427 TRACE("Growing vertex buffer to %u bytes\n", size);
3429 desc.byte_width = size;
3430 desc.usage = WINED3DUSAGE_DYNAMIC;
3431 desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
3432 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W;
3433 desc.misc_flags = 0;
3434 desc.structure_byte_stride = 0;
3436 if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
3437 NULL, NULL, &ddraw_null_wined3d_parent_ops, &buffer)))
3439 ERR("Failed to create vertex buffer, hr %#x.\n", hr);
3440 return hr;
3443 if (device->vertex_buffer)
3444 wined3d_buffer_decref(device->vertex_buffer);
3446 device->vertex_buffer = buffer;
3447 device->vertex_buffer_size = size;
3448 device->vertex_buffer_pos = 0;
3450 return D3D_OK;
3453 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3454 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3455 DWORD vertex_count, DWORD flags)
3457 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3458 struct wined3d_map_desc wined3d_map_desc;
3459 struct wined3d_box wined3d_box = {0};
3460 UINT stride, vb_pos, size, align;
3461 struct wined3d_resource *vb;
3462 HRESULT hr;
3464 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3465 iface, primitive_type, fvf, vertices, vertex_count, flags);
3467 if (!vertex_count)
3469 WARN("0 vertex count.\n");
3470 return D3D_OK;
3473 /* Get the stride */
3474 stride = get_flexible_vertex_size(fvf);
3475 size = vertex_count * stride;
3477 wined3d_mutex_lock();
3478 hr = d3d_device_prepare_vertex_buffer(device, size);
3479 if (FAILED(hr))
3480 goto done;
3482 vb_pos = device->vertex_buffer_pos;
3483 align = vb_pos % stride;
3484 if (align) align = stride - align;
3485 if (vb_pos + size + align > device->vertex_buffer_size)
3486 vb_pos = 0;
3487 else
3488 vb_pos += align;
3490 wined3d_box.left = vb_pos;
3491 wined3d_box.right = vb_pos + size;
3492 vb = wined3d_buffer_get_resource(device->vertex_buffer);
3493 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
3494 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3495 goto done;
3496 memcpy(wined3d_map_desc.data, vertices, size);
3497 wined3d_resource_unmap(vb, 0);
3498 device->vertex_buffer_pos = vb_pos + size;
3500 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, stride);
3501 if (FAILED(hr))
3502 goto done;
3504 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3505 wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
3506 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3507 hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vertex_count);
3509 done:
3510 wined3d_mutex_unlock();
3511 return hr;
3514 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3515 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3516 DWORD vertex_count, DWORD flags)
3518 return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3521 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3522 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3523 DWORD vertex_count, DWORD flags)
3525 HRESULT hr;
3526 WORD old_fpucw;
3528 old_fpucw = d3d_fpu_setup();
3529 hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3530 set_fpu_control_word(old_fpucw);
3532 return hr;
3535 static void setup_lighting(const struct d3d_device *device, DWORD fvf, DWORD flags)
3537 BOOL enable = TRUE;
3539 /* Ignore the D3DFVF_XYZRHW case here, wined3d takes care of that */
3540 if (!device->material || !(fvf & D3DFVF_NORMAL) || (flags & D3DDP_DONOTLIGHT))
3541 enable = FALSE;
3543 wined3d_stateblock_set_render_state(device->state, WINED3D_RS_LIGHTING, enable);
3547 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3548 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3549 DWORD flags)
3551 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3553 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3554 iface, primitive_type, fvf, vertices, vertex_count, flags);
3556 setup_lighting(device, fvf, flags);
3558 return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3559 primitive_type, fvf, vertices, vertex_count, flags);
3562 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3563 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3564 DWORD vertex_count, DWORD flags)
3566 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3567 DWORD fvf;
3569 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3570 iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3572 switch (vertex_type)
3574 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3575 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3576 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3577 default:
3578 FIXME("Unhandled vertex type %#x.\n", vertex_type);
3579 return DDERR_INVALIDPARAMS; /* Should never happen */
3582 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface,
3583 primitive_type, fvf, vertices, vertex_count, flags);
3586 /*****************************************************************************
3587 * IDirect3DDevice7::DrawIndexedPrimitive
3589 * Draws vertices from an application-provided pointer, based on the index
3590 * numbers in a WORD array.
3592 * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3593 * an FVF format for D3D7
3595 * Params:
3596 * PrimitiveType: The primitive type to draw
3597 * VertexType: The FVF vertex description
3598 * Vertices: Pointer to the vertex array
3599 * VertexCount: ?
3600 * Indices: Pointer to the index array
3601 * IndexCount: Number of indices = Number of vertices to draw
3602 * Flags: As usual, some flags
3604 * Returns:
3605 * D3D_OK on success
3606 * DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3608 *****************************************************************************/
3609 /* The caller is responsible for wined3d locking */
3610 static HRESULT d3d_device_prepare_index_buffer(struct d3d_device *device, UINT min_size)
3612 HRESULT hr;
3614 if (device->index_buffer_size < min_size || !device->index_buffer)
3616 UINT size = max(device->index_buffer_size * 2, min_size);
3617 struct wined3d_buffer_desc desc;
3618 struct wined3d_buffer *buffer;
3620 TRACE("Growing index buffer to %u bytes\n", size);
3622 desc.byte_width = size;
3623 desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_STATICDECL;
3624 desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
3625 desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W;
3626 desc.misc_flags = 0;
3627 desc.structure_byte_stride = 0;
3629 if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
3630 NULL, NULL, &ddraw_null_wined3d_parent_ops, &buffer)))
3632 ERR("Failed to create index buffer, hr %#x.\n", hr);
3633 return hr;
3636 if (device->index_buffer)
3637 wined3d_buffer_decref(device->index_buffer);
3638 device->index_buffer = buffer;
3639 device->index_buffer_size = size;
3640 device->index_buffer_pos = 0;
3642 return D3D_OK;
3645 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3646 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3647 WORD *indices, DWORD index_count, DWORD flags)
3649 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3650 HRESULT hr;
3651 UINT stride = get_flexible_vertex_size(fvf);
3652 UINT vtx_size = stride * vertex_count, idx_size = index_count * sizeof(*indices);
3653 struct wined3d_map_desc wined3d_map_desc;
3654 struct wined3d_box wined3d_box = {0};
3655 struct wined3d_resource *ib, *vb;
3656 UINT vb_pos, ib_pos, align;
3658 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3659 "indices %p, index_count %u, flags %#x.\n",
3660 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3662 if (!vertex_count || !index_count)
3664 WARN("0 vertex or index count.\n");
3665 return D3D_OK;
3668 /* Set the D3DDevice's FVF */
3669 wined3d_mutex_lock();
3671 hr = d3d_device_prepare_vertex_buffer(device, vtx_size);
3672 if (FAILED(hr))
3673 goto done;
3675 vb_pos = device->vertex_buffer_pos;
3676 align = vb_pos % stride;
3677 if (align) align = stride - align;
3678 if (vb_pos + vtx_size + align > device->vertex_buffer_size)
3679 vb_pos = 0;
3680 else
3681 vb_pos += align;
3683 wined3d_box.left = vb_pos;
3684 wined3d_box.right = vb_pos + vtx_size;
3685 vb = wined3d_buffer_get_resource(device->vertex_buffer);
3686 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
3687 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3688 goto done;
3689 memcpy(wined3d_map_desc.data, vertices, vtx_size);
3690 wined3d_resource_unmap(vb, 0);
3691 device->vertex_buffer_pos = vb_pos + vtx_size;
3693 hr = d3d_device_prepare_index_buffer(device, idx_size);
3694 if (FAILED(hr))
3695 goto done;
3696 ib_pos = device->index_buffer_pos;
3697 if (device->index_buffer_size - idx_size < ib_pos)
3698 ib_pos = 0;
3700 wined3d_box.left = ib_pos;
3701 wined3d_box.right = ib_pos + idx_size;
3702 ib = wined3d_buffer_get_resource(device->index_buffer);
3703 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
3704 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
3705 goto done;
3706 memcpy(wined3d_map_desc.data, indices, idx_size);
3707 wined3d_resource_unmap(ib, 0);
3708 device->index_buffer_pos = ib_pos + idx_size;
3710 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, stride);
3711 if (FAILED(hr))
3712 goto done;
3713 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
3715 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
3716 wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
3717 wined3d_stateblock_set_base_vertex_index(device->state, vb_pos / stride);
3718 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
3719 hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / sizeof(*indices), index_count);
3721 done:
3722 wined3d_mutex_unlock();
3723 return hr;
3726 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3727 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3728 WORD *indices, DWORD index_count, DWORD flags)
3730 return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3731 vertices, vertex_count, indices, index_count, flags);
3734 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3735 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3736 WORD *indices, DWORD index_count, DWORD flags)
3738 HRESULT hr;
3739 WORD old_fpucw;
3741 old_fpucw = d3d_fpu_setup();
3742 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3743 vertices, vertex_count, indices, index_count, flags);
3744 set_fpu_control_word(old_fpucw);
3746 return hr;
3749 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3750 D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3751 WORD *indices, DWORD index_count, DWORD flags)
3753 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3755 TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3756 "indices %p, index_count %u, flags %#x.\n",
3757 iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3759 setup_lighting(device, fvf, flags);
3761 return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3762 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3765 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3766 D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3767 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3769 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3770 DWORD fvf;
3772 TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3773 "indices %p, index_count %u, flags %#x.\n",
3774 iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3776 switch (vertex_type)
3778 case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3779 case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3780 case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3781 default:
3782 ERR("Unhandled vertex type %#x.\n", vertex_type);
3783 return DDERR_INVALIDPARAMS; /* Should never happen */
3786 return d3d_device3_DrawIndexedPrimitive(&device->IDirect3DDevice3_iface,
3787 primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3790 /*****************************************************************************
3791 * IDirect3DDevice3::End
3793 * Ends a draw begun with IDirect3DDevice3::Begin or
3794 * IDirect3DDevice::BeginIndexed. The vertices specified with
3795 * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
3796 * the IDirect3DDevice3::DrawPrimitive method. So far only
3797 * non-indexed mode is supported
3799 * Version 2 and 3
3801 * Params:
3802 * Flags: Some flags, as usual. Don't know which are defined
3804 * Returns:
3805 * The return value of IDirect3DDevice3::DrawPrimitive
3807 *****************************************************************************/
3808 static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
3810 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3812 TRACE("iface %p, flags %#x.\n", iface, flags);
3814 return d3d_device3_DrawPrimitive(&device->IDirect3DDevice3_iface, device->primitive_type,
3815 device->vertex_type, device->sysmem_vertex_buffer, device->nb_vertices, device->render_flags);
3818 static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
3820 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3822 TRACE("iface %p, flags %#x.\n", iface, flags);
3824 return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
3827 /*****************************************************************************
3828 * IDirect3DDevice7::SetClipStatus
3830 * Sets the clip status. This defines things as clipping conditions and
3831 * the extents of the clipping region.
3833 * Version 2, 3 and 7
3835 * Params:
3836 * ClipStatus:
3838 * Returns:
3839 * D3D_OK because it's a stub
3840 * (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3842 *****************************************************************************/
3843 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3845 FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3847 return D3D_OK;
3850 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3852 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3854 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3856 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3859 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3861 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3863 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3865 return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3868 /*****************************************************************************
3869 * IDirect3DDevice7::GetClipStatus
3871 * Returns the clip status
3873 * Params:
3874 * ClipStatus: Address to write the clip status to
3876 * Returns:
3877 * D3D_OK because it's a stub
3879 *****************************************************************************/
3880 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3882 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3883 struct wined3d_viewport vp;
3885 FIXME("iface %p, clip_status %p stub.\n", iface, clip_status);
3887 vp = wined3d_stateblock_get_state(device->state)->viewport;
3888 clip_status->minx = vp.x;
3889 clip_status->maxx = vp.x + vp.width;
3890 clip_status->miny = vp.y;
3891 clip_status->maxy = vp.y + vp.height;
3892 clip_status->minz = 0.0f;
3893 clip_status->maxz = 0.0f;
3894 clip_status->dwFlags = D3DCLIPSTATUS_EXTENTS2;
3895 clip_status->dwStatus = 0;
3897 return D3D_OK;
3900 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3902 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3904 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3906 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3909 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3911 struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3913 TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3915 return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3918 /*****************************************************************************
3919 * IDirect3DDevice::DrawPrimitiveStrided
3921 * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3923 * Version 3 and 7
3925 * Params:
3926 * PrimitiveType: The primitive type to draw
3927 * VertexType: The FVF description of the vertices to draw (for the stride??)
3928 * D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3929 * the vertex data locations
3930 * VertexCount: The number of vertices to draw
3931 * Flags: Some flags
3933 * Returns:
3934 * D3D_OK, because it's a stub
3935 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3937 *****************************************************************************/
3938 static void pack_strided_data(BYTE *dst, DWORD count, const D3DDRAWPRIMITIVESTRIDEDDATA *src, DWORD fvf)
3940 DWORD i, tex, offset;
3942 for (i = 0; i < count; i++)
3944 /* The contents of the strided data are determined by the fvf,
3945 * not by the members set in src. So it's valid
3946 * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3947 * not set in the fvf. */
3948 if (fvf & D3DFVF_POSITION_MASK)
3950 offset = i * src->position.dwStride;
3951 if (fvf & D3DFVF_XYZRHW)
3953 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 4 * sizeof(float));
3954 dst += 4 * sizeof(float);
3956 else
3958 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 3 * sizeof(float));
3959 dst += 3 * sizeof(float);
3963 if (fvf & D3DFVF_NORMAL)
3965 offset = i * src->normal.dwStride;
3966 memcpy(dst, ((BYTE *)src->normal.lpvData) + offset, 3 * sizeof(float));
3967 dst += 3 * sizeof(float);
3970 if (fvf & D3DFVF_DIFFUSE)
3972 offset = i * src->diffuse.dwStride;
3973 memcpy(dst, ((BYTE *)src->diffuse.lpvData) + offset, sizeof(DWORD));
3974 dst += sizeof(DWORD);
3977 if (fvf & D3DFVF_SPECULAR)
3979 offset = i * src->specular.dwStride;
3980 memcpy(dst, ((BYTE *)src->specular.lpvData) + offset, sizeof(DWORD));
3981 dst += sizeof(DWORD);
3984 for (tex = 0; tex < GET_TEXCOUNT_FROM_FVF(fvf); ++tex)
3986 DWORD attrib_count = GET_TEXCOORD_SIZE_FROM_FVF(fvf, tex);
3987 offset = i * src->textureCoords[tex].dwStride;
3988 memcpy(dst, ((BYTE *)src->textureCoords[tex].lpvData) + offset, attrib_count * sizeof(float));
3989 dst += attrib_count * sizeof(float);
3994 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
3995 DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data, DWORD vertex_count, DWORD flags)
3997 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3998 HRESULT hr;
3999 UINT dst_stride = get_flexible_vertex_size(fvf);
4000 UINT dst_size = dst_stride * vertex_count;
4001 struct wined3d_map_desc wined3d_map_desc;
4002 struct wined3d_box wined3d_box = {0};
4003 struct wined3d_resource *vb;
4004 UINT vb_pos, align;
4006 TRACE("iface %p, primitive_type %#x, fvf %#x, strided_data %p, vertex_count %u, flags %#x.\n",
4007 iface, primitive_type, fvf, strided_data, vertex_count, flags);
4009 if (!vertex_count)
4011 WARN("0 vertex count.\n");
4012 return D3D_OK;
4015 wined3d_mutex_lock();
4016 hr = d3d_device_prepare_vertex_buffer(device, dst_size);
4017 if (FAILED(hr))
4018 goto done;
4020 vb_pos = device->vertex_buffer_pos;
4021 align = vb_pos % dst_stride;
4022 if (align) align = dst_stride - align;
4023 if (vb_pos + dst_size + align > device->vertex_buffer_size)
4024 vb_pos = 0;
4025 else
4026 vb_pos += align;
4028 wined3d_box.left = vb_pos;
4029 wined3d_box.right = vb_pos + dst_size;
4030 vb = wined3d_buffer_get_resource(device->vertex_buffer);
4031 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
4032 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4033 goto done;
4034 pack_strided_data(wined3d_map_desc.data, vertex_count, strided_data, fvf);
4035 wined3d_resource_unmap(vb, 0);
4036 device->vertex_buffer_pos = vb_pos + dst_size;
4038 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, dst_stride);
4039 if (FAILED(hr))
4040 goto done;
4041 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4043 wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
4044 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4045 hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / dst_stride, vertex_count);
4047 done:
4048 wined3d_mutex_unlock();
4049 return hr;
4052 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4053 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4054 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4056 return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
4057 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4060 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4061 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4062 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4064 HRESULT hr;
4065 WORD old_fpucw;
4067 old_fpucw = d3d_fpu_setup();
4068 hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
4069 VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4070 set_fpu_control_word(old_fpucw);
4072 return hr;
4075 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
4076 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4077 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
4079 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4081 TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
4082 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4084 setup_lighting(device, VertexType, Flags);
4086 return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
4087 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
4090 /*****************************************************************************
4091 * IDirect3DDevice7::DrawIndexedPrimitiveStrided
4093 * Draws primitives specified by strided data locations based on indices
4095 * Version 3 and 7
4097 * Params:
4098 * PrimitiveType:
4100 * Returns:
4101 * D3D_OK, because it's a stub
4102 * (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
4103 * (DDERR_INVALIDPARAMS if Indices is NULL)
4105 *****************************************************************************/
4106 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
4107 D3DPRIMITIVETYPE primitive_type, DWORD fvf, D3DDRAWPRIMITIVESTRIDEDDATA *strided_data,
4108 DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4110 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4111 UINT vtx_dst_stride = get_flexible_vertex_size(fvf);
4112 UINT vtx_dst_size = vertex_count * vtx_dst_stride;
4113 UINT idx_size = index_count * sizeof(WORD);
4114 struct wined3d_map_desc wined3d_map_desc;
4115 struct wined3d_box wined3d_box = {0};
4116 struct wined3d_resource *ib, *vb;
4117 UINT vb_pos, align;
4118 UINT ib_pos;
4119 HRESULT hr;
4121 TRACE("iface %p, primitive_type %#x, fvf %#x, strided_data %p, "
4122 "vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4123 iface, primitive_type, fvf, strided_data, vertex_count, indices, index_count, flags);
4125 if (!vertex_count || !index_count)
4127 WARN("0 vertex or index count.\n");
4128 return D3D_OK;
4131 wined3d_mutex_lock();
4133 hr = d3d_device_prepare_vertex_buffer(device, vtx_dst_size);
4134 if (FAILED(hr))
4135 goto done;
4137 vb_pos = device->vertex_buffer_pos;
4138 align = vb_pos % vtx_dst_stride;
4139 if (align) align = vtx_dst_stride - align;
4140 if (vb_pos + vtx_dst_size + align > device->vertex_buffer_size)
4141 vb_pos = 0;
4142 else
4143 vb_pos += align;
4145 wined3d_box.left = vb_pos;
4146 wined3d_box.right = vb_pos + vtx_dst_size;
4147 vb = wined3d_buffer_get_resource(device->vertex_buffer);
4148 if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
4149 WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4150 goto done;
4151 pack_strided_data(wined3d_map_desc.data, vertex_count, strided_data, fvf);
4152 wined3d_resource_unmap(vb, 0);
4153 device->vertex_buffer_pos = vb_pos + vtx_dst_size;
4155 hr = d3d_device_prepare_index_buffer(device, idx_size);
4156 if (FAILED(hr))
4157 goto done;
4158 ib_pos = device->index_buffer_pos;
4159 if (device->index_buffer_size - idx_size < ib_pos)
4160 ib_pos = 0;
4162 wined3d_box.left = ib_pos;
4163 wined3d_box.right = ib_pos + idx_size;
4164 ib = wined3d_buffer_get_resource(device->index_buffer);
4165 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
4166 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4167 goto done;
4168 memcpy(wined3d_map_desc.data, indices, idx_size);
4169 wined3d_resource_unmap(ib, 0);
4170 device->index_buffer_pos = ib_pos + idx_size;
4172 hr = wined3d_stateblock_set_stream_source(device->state, 0, device->vertex_buffer, 0, vtx_dst_stride);
4173 if (FAILED(hr))
4174 goto done;
4175 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
4176 wined3d_stateblock_set_base_vertex_index(device->state, vb_pos / vtx_dst_stride);
4178 wined3d_stateblock_set_vertex_declaration(device->state, ddraw_find_decl(device->ddraw, fvf));
4179 wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
4180 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4181 hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / sizeof(WORD), index_count);
4183 done:
4184 wined3d_mutex_unlock();
4185 return hr;
4188 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4189 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4190 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4191 WORD *Indices, DWORD IndexCount, DWORD Flags)
4193 return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4194 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4197 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4198 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4199 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4200 WORD *Indices, DWORD IndexCount, DWORD Flags)
4202 HRESULT hr;
4203 WORD old_fpucw;
4205 old_fpucw = d3d_fpu_setup();
4206 hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4207 D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4208 set_fpu_control_word(old_fpucw);
4210 return hr;
4213 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4214 D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4215 D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4216 DWORD IndexCount, DWORD Flags)
4218 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4220 TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4221 iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4223 setup_lighting(device, VertexType, Flags);
4225 return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
4226 PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4229 /*****************************************************************************
4230 * IDirect3DDevice7::DrawPrimitiveVB
4232 * Draws primitives from a vertex buffer to the screen.
4234 * Version 3 and 7
4236 * Params:
4237 * PrimitiveType: Type of primitive to be rendered.
4238 * D3DVertexBuf: Source Vertex Buffer
4239 * StartVertex: Index of the first vertex from the buffer to be rendered
4240 * NumVertices: Number of vertices to be rendered
4241 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4243 * Return values
4244 * D3D_OK on success
4245 * DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4247 *****************************************************************************/
4248 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE primitive_type,
4249 IDirect3DVertexBuffer7 *vb, DWORD start_vertex, DWORD vertex_count, DWORD flags)
4251 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4252 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4253 struct wined3d_resource *wined3d_resource;
4254 struct wined3d_map_desc wined3d_map_desc;
4255 struct wined3d_box wined3d_box = {0};
4256 DWORD stride;
4257 HRESULT hr;
4259 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4260 iface, primitive_type, vb, start_vertex, vertex_count, flags);
4262 if (!vertex_count)
4264 WARN("0 vertex count.\n");
4265 return D3D_OK;
4268 stride = get_flexible_vertex_size(vb_impl->fvf);
4270 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4272 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawPrimitive().\n");
4273 wined3d_mutex_lock();
4274 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4275 wined3d_box.left = start_vertex * stride;
4276 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4277 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4278 &wined3d_box, WINED3D_MAP_READ)))
4280 wined3d_mutex_unlock();
4281 return D3DERR_VERTEXBUFFERLOCKED;
4283 hr = d3d_device7_DrawPrimitive(iface, primitive_type, vb_impl->fvf, wined3d_map_desc.data,
4284 vertex_count, flags);
4285 wined3d_resource_unmap(wined3d_resource, 0);
4286 wined3d_mutex_unlock();
4287 return hr;
4290 wined3d_mutex_lock();
4291 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4292 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4293 0, vb_impl->wined3d_buffer, 0, stride)))
4295 WARN("Failed to set stream source, hr %#x.\n", hr);
4296 wined3d_mutex_unlock();
4297 return hr;
4300 /* Now draw the primitives */
4301 wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
4302 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4303 hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex, vertex_count);
4305 wined3d_mutex_unlock();
4307 return hr;
4310 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4311 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4313 return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4316 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4317 IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4319 HRESULT hr;
4320 WORD old_fpucw;
4322 old_fpucw = d3d_fpu_setup();
4323 hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4324 set_fpu_control_word(old_fpucw);
4326 return hr;
4329 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4330 IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4332 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4333 struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)D3DVertexBuf);
4335 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4336 iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4338 setup_lighting(device, vb->fvf, Flags);
4340 return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4341 PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4344 /*****************************************************************************
4345 * IDirect3DDevice7::DrawIndexedPrimitiveVB
4347 * Draws primitives from a vertex buffer to the screen
4349 * Params:
4350 * PrimitiveType: Type of primitive to be rendered.
4351 * D3DVertexBuf: Source Vertex Buffer
4352 * StartVertex: Index of the first vertex from the buffer to be rendered
4353 * NumVertices: Number of vertices to be rendered
4354 * Indices: Array of DWORDs used to index into the Vertices
4355 * IndexCount: Number of indices in Indices
4356 * Flags: Can be D3DDP_WAIT to wait until rendering has finished
4358 * Return values
4360 *****************************************************************************/
4361 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4362 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer7 *vb,
4363 DWORD start_vertex, DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
4365 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4366 struct d3d_vertex_buffer *vb_impl = unsafe_impl_from_IDirect3DVertexBuffer7(vb);
4367 DWORD stride = get_flexible_vertex_size(vb_impl->fvf);
4368 struct wined3d_resource *wined3d_resource;
4369 struct wined3d_map_desc wined3d_map_desc;
4370 struct wined3d_box wined3d_box = {0};
4371 struct wined3d_resource *ib;
4372 HRESULT hr;
4373 UINT ib_pos;
4375 TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, "
4376 "vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4377 iface, primitive_type, vb, start_vertex, vertex_count, indices, index_count, flags);
4379 if (!vertex_count || !index_count)
4381 WARN("0 vertex or index count.\n");
4382 return D3D_OK;
4385 if (vb_impl->Caps & D3DVBCAPS_SYSTEMMEMORY)
4387 TRACE("Drawing from D3DVBCAPS_SYSTEMMEMORY vertex buffer, forwarding to DrawIndexedPrimitive().\n");
4388 wined3d_mutex_lock();
4389 wined3d_box.left = start_vertex * stride;
4390 wined3d_box.right = wined3d_box.left + vertex_count * stride;
4391 wined3d_resource = wined3d_buffer_get_resource(vb_impl->wined3d_buffer);
4392 if (FAILED(hr = wined3d_resource_map(wined3d_resource, 0, &wined3d_map_desc,
4393 &wined3d_box, WINED3D_MAP_READ)))
4395 wined3d_mutex_unlock();
4396 return D3DERR_VERTEXBUFFERLOCKED;
4398 hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, vb_impl->fvf,
4399 wined3d_map_desc.data, vertex_count, indices, index_count, flags);
4400 wined3d_resource_unmap(wined3d_resource, 0);
4401 wined3d_mutex_unlock();
4402 return hr;
4405 /* Steps:
4406 * 1) Upload the indices to the index buffer
4407 * 2) Set the index source
4408 * 3) Set the Vertex Buffer as the Stream source
4409 * 4) Call wined3d_device_draw_indexed_primitive()
4412 wined3d_mutex_lock();
4414 wined3d_stateblock_set_vertex_declaration(device->state, vb_impl->wined3d_declaration);
4416 hr = d3d_device_prepare_index_buffer(device, index_count * sizeof(WORD));
4417 if (FAILED(hr))
4419 wined3d_mutex_unlock();
4420 return hr;
4422 ib_pos = device->index_buffer_pos;
4424 if (device->index_buffer_size - index_count * sizeof(WORD) < ib_pos)
4425 ib_pos = 0;
4427 /* Copy the index stream into the index buffer. */
4428 wined3d_box.left = ib_pos;
4429 wined3d_box.right = ib_pos + index_count * sizeof(WORD);
4430 ib = wined3d_buffer_get_resource(device->index_buffer);
4431 if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
4432 WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
4434 ERR("Failed to map buffer, hr %#x.\n", hr);
4435 wined3d_mutex_unlock();
4436 return hr;
4438 memcpy(wined3d_map_desc.data, indices, index_count * sizeof(WORD));
4439 wined3d_resource_unmap(ib, 0);
4440 device->index_buffer_pos = ib_pos + index_count * sizeof(WORD);
4442 /* Set the index stream */
4443 wined3d_stateblock_set_base_vertex_index(device->state, start_vertex);
4444 wined3d_stateblock_set_index_buffer(device->state, device->index_buffer, WINED3DFMT_R16_UINT);
4446 /* Set the vertex stream source */
4447 if (FAILED(hr = wined3d_stateblock_set_stream_source(device->state,
4448 0, vb_impl->wined3d_buffer, 0, stride)))
4450 ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", device, hr);
4451 wined3d_mutex_unlock();
4452 return hr;
4455 wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
4456 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
4457 hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / sizeof(WORD), index_count);
4459 wined3d_mutex_unlock();
4461 return hr;
4464 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4465 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4466 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4468 return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4469 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4472 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4473 D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4474 DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4476 HRESULT hr;
4477 WORD old_fpucw;
4479 old_fpucw = d3d_fpu_setup();
4480 hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4481 D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4482 set_fpu_control_word(old_fpucw);
4484 return hr;
4487 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4488 D3DPRIMITIVETYPE primitive_type, IDirect3DVertexBuffer *vertex_buffer,
4489 WORD *indices, DWORD index_count, DWORD flags)
4491 struct d3d_vertex_buffer *vb =
4492 unsafe_impl_from_IDirect3DVertexBuffer7((IDirect3DVertexBuffer7 *)vertex_buffer);
4493 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4494 DWORD stride;
4496 TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4497 iface, primitive_type, vertex_buffer, indices, index_count, flags);
4499 setup_lighting(device, vb->fvf, flags);
4501 if (!(stride = get_flexible_vertex_size(vb->fvf)))
4502 return D3D_OK;
4504 return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, primitive_type,
4505 &vb->IDirect3DVertexBuffer7_iface, 0, vb->size / stride, indices, index_count, flags);
4508 /*****************************************************************************
4509 * IDirect3DDevice7::ComputeSphereVisibility
4511 * Calculates the visibility of spheres in the current viewport. The spheres
4512 * are passed in the Centers and Radii arrays, the results are passed back
4513 * in the ReturnValues array. Return values are either completely visible,
4514 * partially visible or completely invisible.
4515 * The return value consists of a combination of D3DCLIP_* flags, or is
4516 * 0 if the sphere is completely visible (according to the SDK, not checked)
4518 * Version 3 and 7
4520 * Params:
4521 * Centers: Array containing the sphere centers
4522 * Radii: Array containing the sphere radii
4523 * NumSpheres: The number of centers and radii in the arrays
4524 * Flags: Some flags
4525 * ReturnValues: Array to write the results to
4527 * Returns:
4528 * D3D_OK
4529 * (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4530 * (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4531 * is singular)
4533 *****************************************************************************/
4535 static DWORD in_plane(UINT idx, struct wined3d_vec4 p, D3DVECTOR center, D3DVALUE radius, BOOL equality)
4537 float distance, norm;
4539 norm = sqrtf(p.x * p.x + p.y * p.y + p.z * p.z);
4540 distance = (p.x * center.u1.x + p.y * center.u2.y + p.z * center.u3.z + p.w) / norm;
4542 if (equality)
4544 if (fabs(distance) <= radius)
4545 return D3DSTATUS_CLIPUNIONLEFT << idx;
4546 if (distance <= -radius)
4547 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4549 else
4551 if (fabs(distance) < radius)
4552 return D3DSTATUS_CLIPUNIONLEFT << idx;
4553 if (distance < -radius)
4554 return (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT) << idx;
4556 return 0;
4559 static void prepare_clip_space_planes(struct d3d_device *device, struct wined3d_vec4 *plane)
4561 const struct wined3d_stateblock_state *state;
4562 struct wined3d_matrix m;
4564 /* We want the wined3d matrices since those include the legacy viewport
4565 * transformation. */
4566 wined3d_mutex_lock();
4567 state = wined3d_stateblock_get_state(device->state);
4568 multiply_matrix(&m, &state->transforms[WINED3D_TS_VIEW], &state->transforms[WINED3D_TS_WORLD]);
4569 multiply_matrix(&m, &state->transforms[WINED3D_TS_PROJECTION], &m);
4570 wined3d_mutex_unlock();
4572 /* Left plane. */
4573 plane[0].x = m._14 + m._11;
4574 plane[0].y = m._24 + m._21;
4575 plane[0].z = m._34 + m._31;
4576 plane[0].w = m._44 + m._41;
4578 /* Right plane. */
4579 plane[1].x = m._14 - m._11;
4580 plane[1].y = m._24 - m._21;
4581 plane[1].z = m._34 - m._31;
4582 plane[1].w = m._44 - m._41;
4584 /* Top plane. */
4585 plane[2].x = m._14 - m._12;
4586 plane[2].y = m._24 - m._22;
4587 plane[2].z = m._34 - m._32;
4588 plane[2].w = m._44 - m._42;
4590 /* Bottom plane. */
4591 plane[3].x = m._14 + m._12;
4592 plane[3].y = m._24 + m._22;
4593 plane[3].z = m._34 + m._32;
4594 plane[3].w = m._44 + m._42;
4596 /* Front plane. */
4597 plane[4].x = m._13;
4598 plane[4].y = m._23;
4599 plane[4].z = m._33;
4600 plane[4].w = m._43;
4602 /* Back plane. */
4603 plane[5].x = m._14 - m._13;
4604 plane[5].y = m._24 - m._23;
4605 plane[5].z = m._34 - m._33;
4606 plane[5].w = m._44 - m._43;
4609 static void compute_sphere_visibility(struct wined3d_vec4 plane[12], DWORD enabled_planes, BOOL equality,
4610 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD *return_values)
4612 UINT i, j;
4614 for (i = 0; i < sphere_count; ++i)
4616 return_values[i] = 0;
4617 for (j = 0; j < 12; ++j)
4618 if (enabled_planes & 1u << j)
4619 return_values[i] |= in_plane(j, plane[j], centers[i], radii[i], equality);
4623 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4624 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4626 struct wined3d_vec4 plane[12];
4627 DWORD enabled_planes = 0x3f;
4628 DWORD user_clip_planes;
4629 UINT j;
4631 TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4632 iface, centers, radii, sphere_count, flags, return_values);
4634 prepare_clip_space_planes(impl_from_IDirect3DDevice7(iface), plane);
4636 IDirect3DDevice7_GetRenderState(iface, D3DRENDERSTATE_CLIPPLANEENABLE, &user_clip_planes);
4637 enabled_planes |= user_clip_planes << 6;
4638 for (j = 6; j < 12; ++j)
4639 IDirect3DDevice7_GetClipPlane(iface, j - 6, (D3DVALUE *)&plane[j]);
4641 compute_sphere_visibility(plane, enabled_planes, FALSE, centers, radii, sphere_count, return_values);
4642 return D3D_OK;
4645 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4646 D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4648 static const DWORD enabled_planes = 0x3f;
4649 struct wined3d_vec4 plane[6];
4650 unsigned int i, j;
4652 TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4653 iface, centers, radii, sphere_count, flags, return_values);
4655 prepare_clip_space_planes(impl_from_IDirect3DDevice3(iface), plane);
4657 compute_sphere_visibility(plane, enabled_planes, TRUE, centers, radii, sphere_count, return_values);
4658 for (i = 0; i < sphere_count; ++i)
4660 BOOL intersect_frustum = FALSE, outside_frustum = FALSE;
4661 DWORD d3d7_result = return_values[i];
4663 return_values[i] = 0;
4665 for (j = 0; j < 6; ++j)
4667 DWORD clip = (d3d7_result >> j) & (D3DSTATUS_CLIPUNIONLEFT | D3DSTATUS_CLIPINTERSECTIONLEFT);
4669 if (clip == D3DSTATUS_CLIPUNIONLEFT)
4671 return_values[i] |= D3DVIS_INTERSECT_LEFT << j * 2;
4672 intersect_frustum = TRUE;
4674 else if (clip)
4676 return_values[i] |= D3DVIS_OUTSIDE_LEFT << j * 2;
4677 outside_frustum = TRUE;
4680 if (outside_frustum)
4681 return_values[i] |= D3DVIS_OUTSIDE_FRUSTUM;
4682 else if (intersect_frustum)
4683 return_values[i] |= D3DVIS_INTERSECT_FRUSTUM;
4685 return D3D_OK;
4688 /*****************************************************************************
4689 * IDirect3DDevice7::GetTexture
4691 * Returns the texture interface handle assigned to a texture stage.
4692 * The returned texture is AddRefed. This is taken from old ddraw,
4693 * not checked in Windows.
4695 * Version 3 and 7
4697 * Params:
4698 * Stage: Texture stage to read the texture from
4699 * Texture: Address to store the interface pointer at
4701 * Returns:
4702 * D3D_OK on success
4703 * DDERR_INVALIDPARAMS if Texture is NULL
4705 *****************************************************************************/
4706 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4707 DWORD stage, IDirectDrawSurface7 **texture)
4709 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4710 struct wined3d_texture *wined3d_texture;
4711 struct ddraw_texture *ddraw_texture;
4713 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4715 if (!texture)
4716 return DDERR_INVALIDPARAMS;
4718 if (stage >= DDRAW_MAX_TEXTURES)
4720 WARN("Invalid stage %u.\n", stage);
4721 *texture = NULL;
4722 return D3D_OK;
4725 wined3d_mutex_lock();
4726 if (!(wined3d_texture = wined3d_stateblock_get_state(device->state)->textures[stage]))
4728 *texture = NULL;
4729 wined3d_mutex_unlock();
4730 return D3D_OK;
4733 ddraw_texture = wined3d_texture_get_parent(wined3d_texture);
4734 *texture = &ddraw_texture->root->IDirectDrawSurface7_iface;
4735 IDirectDrawSurface7_AddRef(*texture);
4736 wined3d_mutex_unlock();
4738 return D3D_OK;
4741 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4742 DWORD stage, IDirectDrawSurface7 **Texture)
4744 return d3d_device7_GetTexture(iface, stage, Texture);
4747 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4748 DWORD stage, IDirectDrawSurface7 **Texture)
4750 HRESULT hr;
4751 WORD old_fpucw;
4753 old_fpucw = d3d_fpu_setup();
4754 hr = d3d_device7_GetTexture(iface, stage, Texture);
4755 set_fpu_control_word(old_fpucw);
4757 return hr;
4760 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4762 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4763 struct ddraw_surface *ret_val_impl;
4764 HRESULT ret;
4765 IDirectDrawSurface7 *ret_val;
4767 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4769 ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4771 ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4772 *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4774 TRACE("Returning texture %p.\n", *Texture2);
4776 return ret;
4779 /*****************************************************************************
4780 * IDirect3DDevice7::SetTexture
4782 * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4784 * Version 3 and 7
4786 * Params:
4787 * Stage: The stage to assign the texture to
4788 * Texture: Interface pointer to the texture surface
4790 * Returns
4791 * D3D_OK on success
4793 *****************************************************************************/
4794 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4795 DWORD stage, IDirectDrawSurface7 *texture)
4797 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4798 struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4799 struct wined3d_texture *wined3d_texture = NULL;
4801 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4803 if (surf && (surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE))
4804 wined3d_texture = surf->wined3d_texture;
4806 wined3d_mutex_lock();
4807 wined3d_stateblock_set_texture(device->update_state, stage, wined3d_texture);
4808 wined3d_mutex_unlock();
4810 return D3D_OK;
4813 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4814 DWORD stage, IDirectDrawSurface7 *texture)
4816 return d3d_device7_SetTexture(iface, stage, texture);
4819 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4820 DWORD stage, IDirectDrawSurface7 *texture)
4822 HRESULT hr;
4823 WORD old_fpucw;
4825 old_fpucw = d3d_fpu_setup();
4826 hr = d3d_device7_SetTexture(iface, stage, texture);
4827 set_fpu_control_word(old_fpucw);
4829 return hr;
4832 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4833 DWORD stage, IDirect3DTexture2 *texture)
4835 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4836 struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4837 HRESULT hr;
4839 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4841 wined3d_mutex_lock();
4843 hr = IDirect3DDevice7_SetTexture(&device->IDirect3DDevice7_iface, stage, &tex->IDirectDrawSurface7_iface);
4845 fixup_texture_alpha_op(device);
4847 wined3d_mutex_unlock();
4849 return hr;
4852 static const struct tss_lookup
4854 BOOL sampler_state;
4855 union
4857 enum wined3d_texture_stage_state texture_state;
4858 enum wined3d_sampler_state sampler_state;
4859 } u;
4861 tss_lookup[] =
4863 {FALSE, {WINED3D_TSS_INVALID}}, /* 0, unused */
4864 {FALSE, {WINED3D_TSS_COLOR_OP}}, /* 1, D3DTSS_COLOROP */
4865 {FALSE, {WINED3D_TSS_COLOR_ARG1}}, /* 2, D3DTSS_COLORARG1 */
4866 {FALSE, {WINED3D_TSS_COLOR_ARG2}}, /* 3, D3DTSS_COLORARG2 */
4867 {FALSE, {WINED3D_TSS_ALPHA_OP}}, /* 4, D3DTSS_ALPHAOP */
4868 {FALSE, {WINED3D_TSS_ALPHA_ARG1}}, /* 5, D3DTSS_ALPHAARG1 */
4869 {FALSE, {WINED3D_TSS_ALPHA_ARG2}}, /* 6, D3DTSS_ALPHAARG2 */
4870 {FALSE, {WINED3D_TSS_BUMPENV_MAT00}}, /* 7, D3DTSS_BUMPENVMAT00 */
4871 {FALSE, {WINED3D_TSS_BUMPENV_MAT01}}, /* 8, D3DTSS_BUMPENVMAT01 */
4872 {FALSE, {WINED3D_TSS_BUMPENV_MAT10}}, /* 9, D3DTSS_BUMPENVMAT10 */
4873 {FALSE, {WINED3D_TSS_BUMPENV_MAT11}}, /* 10, D3DTSS_BUMPENVMAT11 */
4874 {FALSE, {WINED3D_TSS_TEXCOORD_INDEX}}, /* 11, D3DTSS_TEXCOORDINDEX */
4875 {TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 12, D3DTSS_ADDRESS */
4876 {TRUE, {WINED3D_SAMP_ADDRESS_U}}, /* 13, D3DTSS_ADDRESSU */
4877 {TRUE, {WINED3D_SAMP_ADDRESS_V}}, /* 14, D3DTSS_ADDRESSV */
4878 {TRUE, {WINED3D_SAMP_BORDER_COLOR}}, /* 15, D3DTSS_BORDERCOLOR */
4879 {TRUE, {WINED3D_SAMP_MAG_FILTER}}, /* 16, D3DTSS_MAGFILTER */
4880 {TRUE, {WINED3D_SAMP_MIN_FILTER}}, /* 17, D3DTSS_MINFILTER */
4881 {TRUE, {WINED3D_SAMP_MIP_FILTER}}, /* 18, D3DTSS_MIPFILTER */
4882 {TRUE, {WINED3D_SAMP_MIPMAP_LOD_BIAS}}, /* 19, D3DTSS_MIPMAPLODBIAS */
4883 {TRUE, {WINED3D_SAMP_MAX_MIP_LEVEL}}, /* 20, D3DTSS_MAXMIPLEVEL */
4884 {TRUE, {WINED3D_SAMP_MAX_ANISOTROPY}}, /* 21, D3DTSS_MAXANISOTROPY */
4885 {FALSE, {WINED3D_TSS_BUMPENV_LSCALE}}, /* 22, D3DTSS_BUMPENVLSCALE */
4886 {FALSE, {WINED3D_TSS_BUMPENV_LOFFSET}}, /* 23, D3DTSS_BUMPENVLOFFSET */
4887 {FALSE, {WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS}}, /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4890 /*****************************************************************************
4891 * IDirect3DDevice7::GetTextureStageState
4893 * Retrieves a state from a texture stage.
4895 * Version 3 and 7
4897 * Params:
4898 * Stage: The stage to retrieve the state from
4899 * TexStageStateType: The state type to retrieve
4900 * State: Address to store the state's value at
4902 * Returns:
4903 * D3D_OK on success
4904 * DDERR_INVALIDPARAMS if State is NULL
4906 *****************************************************************************/
4907 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4908 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4910 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4911 const struct wined3d_stateblock_state *device_state;
4912 const struct tss_lookup *l;
4914 TRACE("iface %p, stage %u, state %#x, value %p.\n",
4915 iface, stage, state, value);
4917 if (!value)
4918 return DDERR_INVALIDPARAMS;
4920 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4922 WARN("Invalid state %#x passed.\n", state);
4923 return DD_OK;
4926 if (stage >= DDRAW_MAX_TEXTURES)
4928 WARN("Invalid stage %u.\n", stage);
4929 *value = 0;
4930 return D3D_OK;
4933 l = &tss_lookup[state];
4935 wined3d_mutex_lock();
4937 device_state = wined3d_stateblock_get_state(device->state);
4939 if (l->sampler_state)
4941 *value = device_state->sampler_states[stage][l->u.sampler_state];
4943 switch (state)
4945 /* Mipfilter is a sampler state with different values */
4946 case D3DTSS_MIPFILTER:
4948 switch (*value)
4950 case WINED3D_TEXF_NONE:
4951 *value = D3DTFP_NONE;
4952 break;
4953 case WINED3D_TEXF_POINT:
4954 *value = D3DTFP_POINT;
4955 break;
4956 case WINED3D_TEXF_LINEAR:
4957 *value = D3DTFP_LINEAR;
4958 break;
4959 default:
4960 ERR("Unexpected mipfilter value %#x.\n", *value);
4961 *value = D3DTFP_NONE;
4962 break;
4964 break;
4967 /* Magfilter has slightly different values */
4968 case D3DTSS_MAGFILTER:
4970 switch (*value)
4972 case WINED3D_TEXF_POINT:
4973 *value = D3DTFG_POINT;
4974 break;
4975 case WINED3D_TEXF_LINEAR:
4976 *value = D3DTFG_LINEAR;
4977 break;
4978 case WINED3D_TEXF_ANISOTROPIC:
4979 *value = D3DTFG_ANISOTROPIC;
4980 break;
4981 case WINED3D_TEXF_FLAT_CUBIC:
4982 *value = D3DTFG_FLATCUBIC;
4983 break;
4984 case WINED3D_TEXF_GAUSSIAN_CUBIC:
4985 *value = D3DTFG_GAUSSIANCUBIC;
4986 break;
4987 default:
4988 ERR("Unexpected wined3d mag filter value %#x.\n", *value);
4989 *value = D3DTFG_POINT;
4990 break;
4992 break;
4995 default:
4996 break;
4999 else
5001 *value = device_state->texture_states[stage][l->u.texture_state];
5004 wined3d_mutex_unlock();
5006 return D3D_OK;
5009 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5010 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5012 return d3d_device7_GetTextureStageState(iface, stage, state, value);
5015 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5016 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5018 HRESULT hr;
5019 WORD old_fpucw;
5021 old_fpucw = d3d_fpu_setup();
5022 hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
5023 set_fpu_control_word(old_fpucw);
5025 return hr;
5028 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
5029 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
5031 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5033 TRACE("iface %p, stage %u, state %#x, value %p.\n",
5034 iface, stage, state, value);
5036 return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5039 /*****************************************************************************
5040 * IDirect3DDevice7::SetTextureStageState
5042 * Sets a texture stage state. Some stage types need to be handled specially,
5043 * because they do not exist in WineD3D and were moved to another place
5045 * Version 3 and 7
5047 * Params:
5048 * Stage: The stage to modify
5049 * TexStageStateType: The state to change
5050 * State: The new value for the state
5052 * Returns:
5053 * D3D_OK on success
5055 *****************************************************************************/
5056 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
5057 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5059 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5060 const struct tss_lookup *l;
5062 TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5063 iface, stage, state, value);
5065 if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
5067 WARN("Invalid state %#x passed.\n", state);
5068 return DD_OK;
5071 l = &tss_lookup[state];
5073 wined3d_mutex_lock();
5075 if (l->sampler_state)
5077 switch (state)
5079 /* Mipfilter is a sampler state with different values */
5080 case D3DTSS_MIPFILTER:
5082 switch (value)
5084 case D3DTFP_NONE:
5085 value = WINED3D_TEXF_NONE;
5086 break;
5087 case D3DTFP_POINT:
5088 value = WINED3D_TEXF_POINT;
5089 break;
5090 case 0: /* Unchecked */
5091 case D3DTFP_LINEAR:
5092 value = WINED3D_TEXF_LINEAR;
5093 break;
5094 default:
5095 ERR("Unexpected mipfilter value %#x.\n", value);
5096 value = WINED3D_TEXF_NONE;
5097 break;
5099 break;
5102 /* Magfilter has slightly different values */
5103 case D3DTSS_MAGFILTER:
5105 switch (value)
5107 case D3DTFG_POINT:
5108 value = WINED3D_TEXF_POINT;
5109 break;
5110 case D3DTFG_LINEAR:
5111 value = WINED3D_TEXF_LINEAR;
5112 break;
5113 case D3DTFG_FLATCUBIC:
5114 value = WINED3D_TEXF_FLAT_CUBIC;
5115 break;
5116 case D3DTFG_GAUSSIANCUBIC:
5117 value = WINED3D_TEXF_GAUSSIAN_CUBIC;
5118 break;
5119 case D3DTFG_ANISOTROPIC:
5120 value = WINED3D_TEXF_ANISOTROPIC;
5121 break;
5122 default:
5123 ERR("Unexpected d3d7 mag filter value %#x.\n", value);
5124 value = WINED3D_TEXF_POINT;
5125 break;
5127 break;
5130 case D3DTSS_ADDRESS:
5131 wined3d_stateblock_set_sampler_state(device->state, stage, WINED3D_SAMP_ADDRESS_V, value);
5132 break;
5134 default:
5135 break;
5138 wined3d_stateblock_set_sampler_state(device->state, stage, l->u.sampler_state, value);
5140 else
5141 wined3d_stateblock_set_texture_stage_state(device->update_state, stage, l->u.texture_state, value);
5143 wined3d_mutex_unlock();
5145 return D3D_OK;
5148 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
5149 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5151 return d3d_device7_SetTextureStageState(iface, stage, state, value);
5154 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
5155 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5157 HRESULT hr;
5158 WORD old_fpucw;
5160 old_fpucw = d3d_fpu_setup();
5161 hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
5162 set_fpu_control_word(old_fpucw);
5164 return hr;
5167 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
5168 DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
5170 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5171 DWORD old_value;
5172 HRESULT hr;
5174 TRACE("iface %p, stage %u, state %#x, value %#x.\n",
5175 iface, stage, state, value);
5177 /* Tests show that legacy texture blending is not reset if the texture stage state
5178 * value is unchanged. */
5179 if (FAILED(hr = IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface,
5180 stage, state, &old_value)))
5181 return hr;
5183 if (old_value == value)
5185 TRACE("Application is setting the same value over, nothing to do.\n");
5186 return D3D_OK;
5189 device->legacyTextureBlending = FALSE;
5191 return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
5194 /*****************************************************************************
5195 * IDirect3DDevice7::ValidateDevice
5197 * SDK: "Reports the device's ability to render the currently set
5198 * texture-blending operations in a single pass". Whatever that means
5199 * exactly...
5201 * Version 3 and 7
5203 * Params:
5204 * NumPasses: Address to write the number of necessary passes for the
5205 * desired effect to.
5207 * Returns:
5208 * D3D_OK on success
5210 *****************************************************************************/
5211 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
5213 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5214 HRESULT hr;
5216 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5218 wined3d_mutex_lock();
5219 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5220 hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
5221 wined3d_mutex_unlock();
5223 return hr;
5226 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
5228 return d3d_device7_ValidateDevice(iface, pass_count);
5231 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
5233 HRESULT hr;
5234 WORD old_fpucw;
5236 old_fpucw = d3d_fpu_setup();
5237 hr = d3d_device7_ValidateDevice(iface, pass_count);
5238 set_fpu_control_word(old_fpucw);
5240 return hr;
5243 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
5245 struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5247 TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5249 return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
5252 /*****************************************************************************
5253 * IDirect3DDevice7::Clear
5255 * Fills the render target, the z buffer and the stencil buffer with a
5256 * clear color / value
5258 * Version 7 only
5260 * Params:
5261 * Count: Number of rectangles in Rects must be 0 if Rects is NULL
5262 * Rects: Rectangles to clear. If NULL, the whole surface is cleared
5263 * Flags: Some flags, as usual
5264 * Color: Clear color for the render target
5265 * Z: Clear value for the Z buffer
5266 * Stencil: Clear value to store in each stencil buffer entry
5268 * Returns:
5269 * D3D_OK on success
5271 *****************************************************************************/
5272 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
5273 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5275 const struct wined3d_color c =
5277 ((color >> 16) & 0xff) / 255.0f,
5278 ((color >> 8) & 0xff) / 255.0f,
5279 (color & 0xff) / 255.0f,
5280 ((color >> 24) & 0xff) / 255.0f,
5282 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5283 HRESULT hr;
5285 TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5286 iface, count, rects, flags, color, z, stencil);
5288 if (count && !rects)
5290 WARN("count %u with NULL rects.\n", count);
5291 count = 0;
5294 wined3d_mutex_lock();
5295 wined3d_device_apply_stateblock(device->wined3d_device, device->state);
5296 hr = wined3d_device_clear(device->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5297 wined3d_mutex_unlock();
5299 return hr;
5302 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
5303 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5305 return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5308 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
5309 D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5311 HRESULT hr;
5312 WORD old_fpucw;
5314 old_fpucw = d3d_fpu_setup();
5315 hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5316 set_fpu_control_word(old_fpucw);
5318 return hr;
5321 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5323 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5324 struct wined3d_sub_resource_desc rt_desc;
5325 struct wined3d_rendertarget_view *rtv;
5326 struct ddraw_surface *surface;
5327 struct wined3d_viewport vp;
5329 TRACE("iface %p, viewport %p.\n", iface, viewport);
5331 if (!viewport)
5332 return DDERR_INVALIDPARAMS;
5334 wined3d_mutex_lock();
5335 if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
5337 wined3d_mutex_unlock();
5338 return DDERR_INVALIDCAPS;
5340 surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
5341 wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc);
5343 if (viewport->dwX > rt_desc.width || viewport->dwWidth > rt_desc.width - viewport->dwX
5344 || viewport->dwY > rt_desc.height || viewport->dwHeight > rt_desc.height - viewport->dwY)
5346 WARN("Invalid viewport, returning E_INVALIDARG.\n");
5347 wined3d_mutex_unlock();
5348 return E_INVALIDARG;
5351 vp.x = viewport->dwX;
5352 vp.y = viewport->dwY;
5353 vp.width = viewport->dwWidth;
5354 vp.height = viewport->dwHeight;
5355 vp.min_z = viewport->dvMinZ;
5356 vp.max_z = viewport->dvMaxZ;
5358 wined3d_stateblock_set_viewport(device->update_state, &vp);
5359 if (!device->recording)
5360 wined3d_device_set_viewports(device->wined3d_device, 1, &vp);
5361 wined3d_mutex_unlock();
5363 return D3D_OK;
5366 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5368 return d3d_device7_SetViewport(iface, viewport);
5371 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5373 HRESULT hr;
5374 WORD old_fpucw;
5376 old_fpucw = d3d_fpu_setup();
5377 hr = d3d_device7_SetViewport(iface, viewport);
5378 set_fpu_control_word(old_fpucw);
5380 return hr;
5383 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5385 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5386 struct wined3d_viewport wined3d_viewport;
5388 TRACE("iface %p, viewport %p.\n", iface, viewport);
5390 if (!viewport)
5391 return DDERR_INVALIDPARAMS;
5393 wined3d_mutex_lock();
5394 wined3d_viewport = wined3d_stateblock_get_state(device->state)->viewport;
5395 wined3d_mutex_unlock();
5397 viewport->dwX = wined3d_viewport.x;
5398 viewport->dwY = wined3d_viewport.y;
5399 viewport->dwWidth = wined3d_viewport.width;
5400 viewport->dwHeight = wined3d_viewport.height;
5401 viewport->dvMinZ = wined3d_viewport.min_z;
5402 viewport->dvMaxZ = wined3d_viewport.max_z;
5404 return D3D_OK;
5407 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5409 return d3d_device7_GetViewport(iface, viewport);
5412 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5414 HRESULT hr;
5415 WORD old_fpucw;
5417 old_fpucw = d3d_fpu_setup();
5418 hr = d3d_device7_GetViewport(iface, viewport);
5419 set_fpu_control_word(old_fpucw);
5421 return hr;
5424 /*****************************************************************************
5425 * IDirect3DDevice7::SetMaterial
5427 * Sets the Material
5429 * Version 7
5431 * Params:
5432 * Mat: The material to set
5434 * Returns:
5435 * D3D_OK on success
5436 * DDERR_INVALIDPARAMS if Mat is NULL.
5438 *****************************************************************************/
5439 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5441 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5443 TRACE("iface %p, material %p.\n", iface, material);
5445 if (!material)
5446 return DDERR_INVALIDPARAMS;
5448 wined3d_mutex_lock();
5449 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5450 wined3d_stateblock_set_material(device->update_state, (const struct wined3d_material *)material);
5451 wined3d_mutex_unlock();
5453 return D3D_OK;
5456 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5458 return d3d_device7_SetMaterial(iface, material);
5461 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5463 HRESULT hr;
5464 WORD old_fpucw;
5466 old_fpucw = d3d_fpu_setup();
5467 hr = d3d_device7_SetMaterial(iface, material);
5468 set_fpu_control_word(old_fpucw);
5470 return hr;
5473 /*****************************************************************************
5474 * IDirect3DDevice7::GetMaterial
5476 * Returns the current material
5478 * Version 7
5480 * Params:
5481 * Mat: D3DMATERIAL7 structure to write the material parameters to
5483 * Returns:
5484 * D3D_OK on success
5485 * DDERR_INVALIDPARAMS if Mat is NULL
5487 *****************************************************************************/
5488 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5490 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5492 TRACE("iface %p, material %p.\n", iface, material);
5494 wined3d_mutex_lock();
5495 /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5496 memcpy(material, &wined3d_stateblock_get_state(device->state)->material, sizeof(*material));
5497 wined3d_mutex_unlock();
5499 return D3D_OK;
5502 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5504 return d3d_device7_GetMaterial(iface, material);
5507 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5509 HRESULT hr;
5510 WORD old_fpucw;
5512 old_fpucw = d3d_fpu_setup();
5513 hr = d3d_device7_GetMaterial(iface, material);
5514 set_fpu_control_word(old_fpucw);
5516 return hr;
5519 /*****************************************************************************
5520 * IDirect3DDevice7::SetLight
5522 * Assigns a light to a light index, but doesn't activate it yet.
5524 * Version 7, IDirect3DLight uses this method for older versions
5526 * Params:
5527 * LightIndex: The index of the new light
5528 * Light: A D3DLIGHT7 structure describing the light
5530 * Returns:
5531 * D3D_OK on success
5533 *****************************************************************************/
5534 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5536 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5537 HRESULT hr;
5539 TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5541 wined3d_mutex_lock();
5542 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5543 hr = wined3d_stateblock_set_light(device->update_state, light_idx, (const struct wined3d_light *)light);
5544 if (SUCCEEDED(hr) && !device->recording)
5545 hr = wined3d_device_set_light(device->wined3d_device, light_idx, (const struct wined3d_light *)light);
5546 wined3d_mutex_unlock();
5548 return hr_ddraw_from_wined3d(hr);
5551 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5553 return d3d_device7_SetLight(iface, light_idx, light);
5556 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5558 HRESULT hr;
5559 WORD old_fpucw;
5561 old_fpucw = d3d_fpu_setup();
5562 hr = d3d_device7_SetLight(iface, light_idx, light);
5563 set_fpu_control_word(old_fpucw);
5565 return hr;
5568 /*****************************************************************************
5569 * IDirect3DDevice7::GetLight
5571 * Returns the light assigned to a light index
5573 * Params:
5574 * Light: Structure to write the light information to
5576 * Returns:
5577 * D3D_OK on success
5578 * DDERR_INVALIDPARAMS if Light is NULL
5580 *****************************************************************************/
5581 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5583 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5584 HRESULT rc;
5586 TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5588 wined3d_mutex_lock();
5589 /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5590 rc = wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5591 wined3d_mutex_unlock();
5593 /* Translate the result. WineD3D returns other values than D3D7 */
5594 return hr_ddraw_from_wined3d(rc);
5597 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5599 return d3d_device7_GetLight(iface, light_idx, light);
5602 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5604 HRESULT hr;
5605 WORD old_fpucw;
5607 old_fpucw = d3d_fpu_setup();
5608 hr = d3d_device7_GetLight(iface, light_idx, light);
5609 set_fpu_control_word(old_fpucw);
5611 return hr;
5614 /*****************************************************************************
5615 * IDirect3DDevice7::BeginStateBlock
5617 * Begins recording to a stateblock
5619 * Version 7
5621 * Returns:
5622 * D3D_OK on success
5624 *****************************************************************************/
5625 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5627 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5628 struct wined3d_stateblock *stateblock;
5629 HRESULT hr;
5631 TRACE("iface %p.\n", iface);
5633 wined3d_mutex_lock();
5634 if (device->recording)
5636 wined3d_mutex_unlock();
5637 WARN("Trying to begin a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5638 return D3DERR_INBEGINSTATEBLOCK;
5640 if (SUCCEEDED(hr = wined3d_stateblock_create(device->wined3d_device, NULL, WINED3D_SBT_RECORDED, &stateblock)))
5641 device->update_state = device->recording = stateblock;
5642 wined3d_mutex_unlock();
5644 return hr_ddraw_from_wined3d(hr);
5647 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5649 return d3d_device7_BeginStateBlock(iface);
5652 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5654 HRESULT hr;
5655 WORD old_fpucw;
5657 old_fpucw = d3d_fpu_setup();
5658 hr = d3d_device7_BeginStateBlock(iface);
5659 set_fpu_control_word(old_fpucw);
5661 return hr;
5664 /*****************************************************************************
5665 * IDirect3DDevice7::EndStateBlock
5667 * Stops recording to a state block and returns the created stateblock
5668 * handle.
5670 * Version 7
5672 * Params:
5673 * BlockHandle: Address to store the stateblock's handle to
5675 * Returns:
5676 * D3D_OK on success
5677 * DDERR_INVALIDPARAMS if BlockHandle is NULL
5679 *****************************************************************************/
5680 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5682 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5683 struct wined3d_stateblock *wined3d_sb;
5684 DWORD h;
5686 TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5688 if (!stateblock)
5689 return DDERR_INVALIDPARAMS;
5691 wined3d_mutex_lock();
5692 if (!device->recording)
5694 wined3d_mutex_unlock();
5695 WARN("Trying to end a stateblock, but no stateblock is being recorded.\n");
5696 return D3DERR_NOTINBEGINSTATEBLOCK;
5698 wined3d_sb = device->recording;
5699 wined3d_stateblock_init_contained_states(wined3d_sb);
5700 device->recording = NULL;
5701 device->update_state = device->state;
5703 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5704 if (h == DDRAW_INVALID_HANDLE)
5706 ERR("Failed to allocate a stateblock handle.\n");
5707 wined3d_stateblock_decref(wined3d_sb);
5708 wined3d_mutex_unlock();
5709 *stateblock = 0;
5710 return DDERR_OUTOFMEMORY;
5713 wined3d_mutex_unlock();
5714 *stateblock = h + 1;
5716 return D3D_OK;
5719 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5721 return d3d_device7_EndStateBlock(iface, stateblock);
5724 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5726 HRESULT hr;
5727 WORD old_fpucw;
5729 old_fpucw = d3d_fpu_setup();
5730 hr = d3d_device7_EndStateBlock(iface, stateblock);
5731 set_fpu_control_word(old_fpucw);
5733 return hr;
5736 /*****************************************************************************
5737 * IDirect3DDevice7::PreLoad
5739 * Allows the app to signal that a texture will be used soon, to allow
5740 * the Direct3DDevice to load it to the video card in the meantime.
5742 * Version 7
5744 * Params:
5745 * Texture: The texture to preload
5747 * Returns:
5748 * D3D_OK on success
5749 * DDERR_INVALIDPARAMS if Texture is NULL
5751 *****************************************************************************/
5752 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5754 struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5756 TRACE("iface %p, texture %p.\n", iface, texture);
5758 if (!texture)
5759 return DDERR_INVALIDPARAMS;
5761 wined3d_mutex_lock();
5762 wined3d_resource_preload(wined3d_texture_get_resource(surface->wined3d_texture));
5763 wined3d_mutex_unlock();
5765 return D3D_OK;
5768 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5770 return d3d_device7_PreLoad(iface, texture);
5773 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5775 HRESULT hr;
5776 WORD old_fpucw;
5778 old_fpucw = d3d_fpu_setup();
5779 hr = d3d_device7_PreLoad(iface, texture);
5780 set_fpu_control_word(old_fpucw);
5782 return hr;
5785 /*****************************************************************************
5786 * IDirect3DDevice7::ApplyStateBlock
5788 * Activates the state stored in a state block handle.
5790 * Params:
5791 * BlockHandle: The stateblock handle to activate
5793 * Returns:
5794 * D3D_OK on success
5795 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5797 *****************************************************************************/
5798 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5800 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5801 struct wined3d_stateblock *wined3d_sb;
5803 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5805 wined3d_mutex_lock();
5806 if (device->recording)
5808 wined3d_mutex_unlock();
5809 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5810 return D3DERR_INBEGINSTATEBLOCK;
5812 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5813 if (!wined3d_sb)
5815 WARN("Invalid stateblock handle.\n");
5816 wined3d_mutex_unlock();
5817 return D3DERR_INVALIDSTATEBLOCK;
5820 wined3d_stateblock_apply(wined3d_sb, device->state);
5821 wined3d_mutex_unlock();
5823 return D3D_OK;
5826 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5828 return d3d_device7_ApplyStateBlock(iface, stateblock);
5831 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5833 HRESULT hr;
5834 WORD old_fpucw;
5836 old_fpucw = d3d_fpu_setup();
5837 hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5838 set_fpu_control_word(old_fpucw);
5840 return hr;
5843 /*****************************************************************************
5844 * IDirect3DDevice7::CaptureStateBlock
5846 * Updates a stateblock's values to the values currently set for the device
5848 * Version 7
5850 * Params:
5851 * BlockHandle: Stateblock to update
5853 * Returns:
5854 * D3D_OK on success
5855 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5857 *****************************************************************************/
5858 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5860 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5861 struct wined3d_stateblock *wined3d_sb;
5863 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5865 wined3d_mutex_lock();
5866 if (device->recording)
5868 wined3d_mutex_unlock();
5869 WARN("Trying to capture a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
5870 return D3DERR_INBEGINSTATEBLOCK;
5872 wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5873 if (!wined3d_sb)
5875 WARN("Invalid stateblock handle.\n");
5876 wined3d_mutex_unlock();
5877 return D3DERR_INVALIDSTATEBLOCK;
5880 wined3d_stateblock_capture(wined3d_sb, device->state);
5881 wined3d_mutex_unlock();
5883 return D3D_OK;
5886 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5888 return d3d_device7_CaptureStateBlock(iface, stateblock);
5891 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5893 HRESULT hr;
5894 WORD old_fpucw;
5896 old_fpucw = d3d_fpu_setup();
5897 hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5898 set_fpu_control_word(old_fpucw);
5900 return hr;
5903 /*****************************************************************************
5904 * IDirect3DDevice7::DeleteStateBlock
5906 * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5908 * Version 7
5910 * Params:
5911 * BlockHandle: Stateblock handle to delete
5913 * Returns:
5914 * D3D_OK on success
5915 * D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5917 *****************************************************************************/
5918 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5920 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5921 struct wined3d_stateblock *wined3d_sb;
5922 ULONG ref;
5924 TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5926 wined3d_mutex_lock();
5928 wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5929 if (!wined3d_sb)
5931 WARN("Invalid stateblock handle.\n");
5932 wined3d_mutex_unlock();
5933 return D3DERR_INVALIDSTATEBLOCK;
5936 if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5938 ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5941 wined3d_mutex_unlock();
5943 return D3D_OK;
5946 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5948 return d3d_device7_DeleteStateBlock(iface, stateblock);
5951 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5953 HRESULT hr;
5954 WORD old_fpucw;
5956 old_fpucw = d3d_fpu_setup();
5957 hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5958 set_fpu_control_word(old_fpucw);
5960 return hr;
5963 /*****************************************************************************
5964 * IDirect3DDevice7::CreateStateBlock
5966 * Creates a new state block handle.
5968 * Version 7
5970 * Params:
5971 * Type: The state block type
5972 * BlockHandle: Address to write the created handle to
5974 * Returns:
5975 * D3D_OK on success
5976 * DDERR_INVALIDPARAMS if BlockHandle is NULL
5978 *****************************************************************************/
5979 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5980 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5982 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5983 struct wined3d_stateblock *wined3d_sb;
5984 HRESULT hr;
5985 DWORD h;
5987 TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5989 if (!stateblock)
5990 return DDERR_INVALIDPARAMS;
5992 if (type != D3DSBT_ALL
5993 && type != D3DSBT_PIXELSTATE
5994 && type != D3DSBT_VERTEXSTATE)
5996 WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5997 return DDERR_INVALIDPARAMS;
6000 wined3d_mutex_lock();
6002 if (device->recording)
6004 wined3d_mutex_unlock();
6005 WARN("Trying to apply a stateblock while recording, returning D3DERR_INBEGINSTATEBLOCK.\n");
6006 return D3DERR_INBEGINSTATEBLOCK;
6009 /* The D3DSTATEBLOCKTYPE enum is fine here. */
6010 hr = wined3d_stateblock_create(device->wined3d_device, device->state, type, &wined3d_sb);
6011 if (FAILED(hr))
6013 WARN("Failed to create stateblock, hr %#x.\n", hr);
6014 wined3d_mutex_unlock();
6015 return hr_ddraw_from_wined3d(hr);
6018 h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
6019 if (h == DDRAW_INVALID_HANDLE)
6021 ERR("Failed to allocate stateblock handle.\n");
6022 wined3d_stateblock_decref(wined3d_sb);
6023 wined3d_mutex_unlock();
6024 return DDERR_OUTOFMEMORY;
6027 *stateblock = h + 1;
6028 wined3d_mutex_unlock();
6030 return hr_ddraw_from_wined3d(hr);
6033 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
6034 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6036 return d3d_device7_CreateStateBlock(iface, type, stateblock);
6039 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
6040 D3DSTATEBLOCKTYPE type, DWORD *stateblock)
6042 HRESULT hr;
6043 WORD old_fpucw;
6045 old_fpucw = d3d_fpu_setup();
6046 hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
6047 set_fpu_control_word(old_fpucw);
6049 return hr;
6052 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
6054 struct ddraw_surface *src_level, *dest_level;
6055 IDirectDrawSurface7 *temp;
6056 DDSURFACEDESC2 ddsd;
6057 BOOL levelFound; /* at least one suitable sublevel in dest found */
6059 /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
6060 * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
6061 * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
6063 levelFound = FALSE;
6065 src_level = src;
6066 dest_level = dest;
6068 for (;src_level && dest_level;)
6070 if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6071 src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6073 levelFound = TRUE;
6075 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6076 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6077 IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6079 if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6081 dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6084 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6085 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6086 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6088 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6090 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6093 if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6094 if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6096 return !dest_level && levelFound;
6099 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dst,
6100 struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
6102 struct ddraw_surface *dst_level, *src_level;
6103 IDirectDrawSurface7 *temp;
6104 DDSURFACEDESC2 ddsd;
6105 POINT point;
6106 RECT src_rect;
6107 HRESULT hr;
6108 IDirectDrawPalette *pal = NULL, *pal_src = NULL;
6109 DWORD ckeyflag;
6110 DDCOLORKEY ddckey;
6112 /* Copy palette, if possible. */
6113 IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
6114 IDirectDrawSurface7_GetPalette(&dst->IDirectDrawSurface7_iface, &pal);
6116 if (pal_src != NULL && pal != NULL)
6118 PALETTEENTRY palent[256];
6120 IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
6121 IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
6124 if (pal) IDirectDrawPalette_Release(pal);
6125 if (pal_src) IDirectDrawPalette_Release(pal_src);
6127 /* Copy colorkeys, if present. */
6128 for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
6130 hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6132 if (SUCCEEDED(hr))
6134 IDirectDrawSurface7_SetColorKey(&dst->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6138 src_level = src;
6139 dst_level = dst;
6141 point = *DestPoint;
6142 src_rect = *SrcRect;
6144 for (;src_level && dst_level;)
6146 if (src_level->surface_desc.dwWidth == dst_level->surface_desc.dwWidth
6147 && src_level->surface_desc.dwHeight == dst_level->surface_desc.dwHeight)
6149 UINT src_w = src_rect.right - src_rect.left;
6150 UINT src_h = src_rect.bottom - src_rect.top;
6151 RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
6153 if (FAILED(hr = wined3d_texture_blt(dst_level->wined3d_texture, dst_level->sub_resource_idx, &dst_rect,
6154 src_level->wined3d_texture, src_level->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
6155 ERR("Blit failed, hr %#x.\n", hr);
6157 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6158 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6159 IDirectDrawSurface7_GetAttachedSurface(&dst_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6161 if (dst_level != dst)
6162 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6164 dst_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6167 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6168 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6169 IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6171 if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6173 src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6175 point.x /= 2;
6176 point.y /= 2;
6178 src_rect.top /= 2;
6179 src_rect.left /= 2;
6180 src_rect.right = (src_rect.right + 1) / 2;
6181 src_rect.bottom = (src_rect.bottom + 1) / 2;
6184 if (src_level && src_level != src)
6185 IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6186 if (dst_level && dst_level != dst)
6187 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6190 /*****************************************************************************
6191 * IDirect3DDevice7::Load
6193 * Loads a rectangular area from the source into the destination texture.
6194 * It can also copy the source to the faces of a cubic environment map
6196 * Version 7
6198 * Params:
6199 * DestTex: Destination texture
6200 * DestPoint: Point in the destination where the source image should be
6201 * written to
6202 * SrcTex: Source texture
6203 * SrcRect: Source rectangle
6204 * Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6205 * DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6206 * DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6208 * Returns:
6209 * D3D_OK on success
6210 * DDERR_INVALIDPARAMS if dst_texture or src_texture is NULL, broken coordinates or anything unexpected.
6213 *****************************************************************************/
6214 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
6215 IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6217 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6218 struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
6219 struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
6220 POINT destpoint;
6221 RECT srcrect;
6223 TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
6224 iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
6226 if( (!src) || (!dest) )
6227 return DDERR_INVALIDPARAMS;
6229 wined3d_mutex_lock();
6231 if (!src_rect)
6232 SetRect(&srcrect, 0, 0, src->surface_desc.dwWidth, src->surface_desc.dwHeight);
6233 else
6234 srcrect = *src_rect;
6236 if (!dst_pos)
6237 destpoint.x = destpoint.y = 0;
6238 else
6239 destpoint = *dst_pos;
6241 /* Check bad dimensions. dst_pos is validated against src, not dest, because
6242 * destination can be a subset of mip levels, in which case actual coordinates used
6243 * for it may be divided. If any dimension of dest is larger than source, it can't be
6244 * mip level subset, so an error can be returned early.
6246 if (IsRectEmpty(&srcrect) || srcrect.right > src->surface_desc.dwWidth ||
6247 srcrect.bottom > src->surface_desc.dwHeight ||
6248 destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6249 destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6250 dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6251 dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6253 wined3d_mutex_unlock();
6254 return DDERR_INVALIDPARAMS;
6257 /* Must be top level surfaces. */
6258 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6259 dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6261 wined3d_mutex_unlock();
6262 return DDERR_INVALIDPARAMS;
6265 if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6267 struct ddraw_surface *src_face, *dest_face;
6268 DWORD src_face_flag, dest_face_flag;
6269 IDirectDrawSurface7 *temp;
6270 DDSURFACEDESC2 ddsd;
6271 int i;
6273 if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6275 wined3d_mutex_unlock();
6276 return DDERR_INVALIDPARAMS;
6279 /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6280 * time it's actual surface loading. */
6281 for (i = 0; i < 2; i++)
6283 dest_face = dest;
6284 src_face = src;
6286 for (;dest_face && src_face;)
6288 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6289 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6291 if (src_face_flag == dest_face_flag)
6293 if (i == 0)
6295 /* Destination mip levels must be subset of source mip levels. */
6296 if (!is_mip_level_subset(dest_face, src_face))
6298 wined3d_mutex_unlock();
6299 return DDERR_INVALIDPARAMS;
6302 else if (flags & dest_face_flag)
6304 copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6307 if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6309 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6310 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6311 IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6313 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6315 src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6317 else
6319 if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6321 src_face = NULL;
6325 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6327 ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6328 ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6329 IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6331 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6333 dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6335 else
6337 if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6339 dest_face = NULL;
6343 if (i == 0)
6345 /* Native returns error if src faces are not subset of dest faces. */
6346 if (src_face)
6348 wined3d_mutex_unlock();
6349 return DDERR_INVALIDPARAMS;
6354 wined3d_mutex_unlock();
6355 return D3D_OK;
6357 else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6359 wined3d_mutex_unlock();
6360 return DDERR_INVALIDPARAMS;
6363 /* Handle non cube map textures. */
6365 /* Destination mip levels must be subset of source mip levels. */
6366 if (!is_mip_level_subset(dest, src))
6368 wined3d_mutex_unlock();
6369 return DDERR_INVALIDPARAMS;
6372 copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6374 wined3d_mutex_unlock();
6376 return D3D_OK;
6379 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6380 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6382 return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6385 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6386 POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6388 HRESULT hr;
6389 WORD old_fpucw;
6391 old_fpucw = d3d_fpu_setup();
6392 hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6393 set_fpu_control_word(old_fpucw);
6395 return hr;
6398 /*****************************************************************************
6399 * IDirect3DDevice7::LightEnable
6401 * Enables or disables a light
6403 * Version 7, IDirect3DLight uses this method too.
6405 * Params:
6406 * LightIndex: The index of the light to enable / disable
6407 * Enable: Enable or disable the light
6409 * Returns:
6410 * D3D_OK on success
6412 *****************************************************************************/
6413 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6415 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6416 HRESULT hr;
6418 TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6420 wined3d_mutex_lock();
6421 hr = wined3d_stateblock_set_light_enable(device->update_state, light_idx, enabled);
6422 if (SUCCEEDED(hr) && !device->recording)
6423 hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
6424 wined3d_mutex_unlock();
6426 return hr_ddraw_from_wined3d(hr);
6429 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6431 return d3d_device7_LightEnable(iface, light_idx, enabled);
6434 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6436 HRESULT hr;
6437 WORD old_fpucw;
6439 old_fpucw = d3d_fpu_setup();
6440 hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6441 set_fpu_control_word(old_fpucw);
6443 return hr;
6446 /*****************************************************************************
6447 * IDirect3DDevice7::GetLightEnable
6449 * Retrieves if the light with the given index is enabled or not
6451 * Version 7
6453 * Params:
6454 * LightIndex: Index of desired light
6455 * Enable: Pointer to a BOOL which contains the result
6457 * Returns:
6458 * D3D_OK on success
6459 * DDERR_INVALIDPARAMS if Enable is NULL
6461 *****************************************************************************/
6462 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6464 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6465 HRESULT hr;
6467 TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6469 if (!enabled)
6470 return DDERR_INVALIDPARAMS;
6472 wined3d_mutex_lock();
6473 hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6474 wined3d_mutex_unlock();
6476 return hr_ddraw_from_wined3d(hr);
6479 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6481 return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6484 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6486 HRESULT hr;
6487 WORD old_fpucw;
6489 old_fpucw = d3d_fpu_setup();
6490 hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6491 set_fpu_control_word(old_fpucw);
6493 return hr;
6496 /*****************************************************************************
6497 * IDirect3DDevice7::SetClipPlane
6499 * Sets custom clipping plane
6501 * Version 7
6503 * Params:
6504 * Index: The index of the clipping plane
6505 * PlaneEquation: An equation defining the clipping plane
6507 * Returns:
6508 * D3D_OK on success
6509 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6511 *****************************************************************************/
6512 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6514 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6515 const struct wined3d_vec4 *wined3d_plane;
6516 HRESULT hr;
6518 TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6520 if (!plane)
6521 return DDERR_INVALIDPARAMS;
6523 wined3d_plane = (struct wined3d_vec4 *)plane;
6525 wined3d_mutex_lock();
6526 hr = wined3d_stateblock_set_clip_plane(device->update_state, idx, wined3d_plane);
6527 if (idx < ARRAY_SIZE(device->user_clip_planes))
6529 device->user_clip_planes[idx] = *wined3d_plane;
6530 if (hr == WINED3DERR_INVALIDCALL)
6532 WARN("Clip plane %u is not supported.\n", idx);
6533 hr = D3D_OK;
6536 wined3d_mutex_unlock();
6538 return hr;
6541 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6543 return d3d_device7_SetClipPlane(iface, idx, plane);
6546 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6548 HRESULT hr;
6549 WORD old_fpucw;
6551 old_fpucw = d3d_fpu_setup();
6552 hr = d3d_device7_SetClipPlane(iface, idx, plane);
6553 set_fpu_control_word(old_fpucw);
6555 return hr;
6558 /*****************************************************************************
6559 * IDirect3DDevice7::GetClipPlane
6561 * Returns the clipping plane with a specific index
6563 * Params:
6564 * Index: The index of the desired plane
6565 * PlaneEquation: Address to store the plane equation to
6567 * Returns:
6568 * D3D_OK on success
6569 * DDERR_INVALIDPARAMS if PlaneEquation is NULL
6571 *****************************************************************************/
6572 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6574 struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6576 TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6578 if (!plane)
6579 return DDERR_INVALIDPARAMS;
6581 wined3d_mutex_lock();
6582 if (idx < WINED3D_MAX_CLIP_DISTANCES)
6583 memcpy(plane, &wined3d_stateblock_get_state(device->state)->clip_planes[idx], sizeof(struct wined3d_vec4));
6584 else
6586 WARN("Clip plane %u is not supported.\n", idx);
6587 if (idx < ARRAY_SIZE(device->user_clip_planes))
6588 memcpy(plane, &device->user_clip_planes[idx], sizeof(struct wined3d_vec4));
6590 wined3d_mutex_unlock();
6592 return D3D_OK;
6595 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6597 return d3d_device7_GetClipPlane(iface, idx, plane);
6600 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6602 HRESULT hr;
6603 WORD old_fpucw;
6605 old_fpucw = d3d_fpu_setup();
6606 hr = d3d_device7_GetClipPlane(iface, idx, plane);
6607 set_fpu_control_word(old_fpucw);
6609 return hr;
6612 /*****************************************************************************
6613 * IDirect3DDevice7::GetInfo
6615 * Retrieves some information about the device. The DirectX sdk says that
6616 * this version returns S_FALSE for all retail builds of DirectX, that's what
6617 * this implementation does.
6619 * Params:
6620 * DevInfoID: Information type requested
6621 * DevInfoStruct: Pointer to a structure to store the info to
6622 * Size: Size of the structure
6624 * Returns:
6625 * S_FALSE, because it's a non-debug driver
6627 *****************************************************************************/
6628 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6630 TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6631 iface, info_id, info, info_size);
6633 if (TRACE_ON(ddraw))
6635 TRACE(" info requested : ");
6636 switch (info_id)
6638 case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6639 case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6640 case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6641 default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6645 return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6648 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6649 * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6650 * are not duplicated.
6652 * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6653 * has already been setup for optimal d3d operation.
6655 * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6656 * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6657 * by Sacrifice (game). */
6658 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6660 /*** IUnknown Methods ***/
6661 d3d_device7_QueryInterface,
6662 d3d_device7_AddRef,
6663 d3d_device7_Release,
6664 /*** IDirect3DDevice7 ***/
6665 d3d_device7_GetCaps_FPUSetup,
6666 d3d_device7_EnumTextureFormats_FPUSetup,
6667 d3d_device7_BeginScene_FPUSetup,
6668 d3d_device7_EndScene_FPUSetup,
6669 d3d_device7_GetDirect3D,
6670 d3d_device7_SetRenderTarget_FPUSetup,
6671 d3d_device7_GetRenderTarget,
6672 d3d_device7_Clear_FPUSetup,
6673 d3d_device7_SetTransform_FPUSetup,
6674 d3d_device7_GetTransform_FPUSetup,
6675 d3d_device7_SetViewport_FPUSetup,
6676 d3d_device7_MultiplyTransform_FPUSetup,
6677 d3d_device7_GetViewport_FPUSetup,
6678 d3d_device7_SetMaterial_FPUSetup,
6679 d3d_device7_GetMaterial_FPUSetup,
6680 d3d_device7_SetLight_FPUSetup,
6681 d3d_device7_GetLight_FPUSetup,
6682 d3d_device7_SetRenderState_FPUSetup,
6683 d3d_device7_GetRenderState_FPUSetup,
6684 d3d_device7_BeginStateBlock_FPUSetup,
6685 d3d_device7_EndStateBlock_FPUSetup,
6686 d3d_device7_PreLoad_FPUSetup,
6687 d3d_device7_DrawPrimitive_FPUSetup,
6688 d3d_device7_DrawIndexedPrimitive_FPUSetup,
6689 d3d_device7_SetClipStatus,
6690 d3d_device7_GetClipStatus,
6691 d3d_device7_DrawPrimitiveStrided_FPUSetup,
6692 d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6693 d3d_device7_DrawPrimitiveVB_FPUSetup,
6694 d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6695 d3d_device7_ComputeSphereVisibility,
6696 d3d_device7_GetTexture_FPUSetup,
6697 d3d_device7_SetTexture_FPUSetup,
6698 d3d_device7_GetTextureStageState_FPUSetup,
6699 d3d_device7_SetTextureStageState_FPUSetup,
6700 d3d_device7_ValidateDevice_FPUSetup,
6701 d3d_device7_ApplyStateBlock_FPUSetup,
6702 d3d_device7_CaptureStateBlock_FPUSetup,
6703 d3d_device7_DeleteStateBlock_FPUSetup,
6704 d3d_device7_CreateStateBlock_FPUSetup,
6705 d3d_device7_Load_FPUSetup,
6706 d3d_device7_LightEnable_FPUSetup,
6707 d3d_device7_GetLightEnable_FPUSetup,
6708 d3d_device7_SetClipPlane_FPUSetup,
6709 d3d_device7_GetClipPlane_FPUSetup,
6710 d3d_device7_GetInfo
6713 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6715 /*** IUnknown Methods ***/
6716 d3d_device7_QueryInterface,
6717 d3d_device7_AddRef,
6718 d3d_device7_Release,
6719 /*** IDirect3DDevice7 ***/
6720 d3d_device7_GetCaps_FPUPreserve,
6721 d3d_device7_EnumTextureFormats_FPUPreserve,
6722 d3d_device7_BeginScene_FPUPreserve,
6723 d3d_device7_EndScene_FPUPreserve,
6724 d3d_device7_GetDirect3D,
6725 d3d_device7_SetRenderTarget_FPUPreserve,
6726 d3d_device7_GetRenderTarget,
6727 d3d_device7_Clear_FPUPreserve,
6728 d3d_device7_SetTransform_FPUPreserve,
6729 d3d_device7_GetTransform_FPUPreserve,
6730 d3d_device7_SetViewport_FPUPreserve,
6731 d3d_device7_MultiplyTransform_FPUPreserve,
6732 d3d_device7_GetViewport_FPUPreserve,
6733 d3d_device7_SetMaterial_FPUPreserve,
6734 d3d_device7_GetMaterial_FPUPreserve,
6735 d3d_device7_SetLight_FPUPreserve,
6736 d3d_device7_GetLight_FPUPreserve,
6737 d3d_device7_SetRenderState_FPUPreserve,
6738 d3d_device7_GetRenderState_FPUPreserve,
6739 d3d_device7_BeginStateBlock_FPUPreserve,
6740 d3d_device7_EndStateBlock_FPUPreserve,
6741 d3d_device7_PreLoad_FPUPreserve,
6742 d3d_device7_DrawPrimitive_FPUPreserve,
6743 d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6744 d3d_device7_SetClipStatus,
6745 d3d_device7_GetClipStatus,
6746 d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6747 d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6748 d3d_device7_DrawPrimitiveVB_FPUPreserve,
6749 d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6750 d3d_device7_ComputeSphereVisibility,
6751 d3d_device7_GetTexture_FPUPreserve,
6752 d3d_device7_SetTexture_FPUPreserve,
6753 d3d_device7_GetTextureStageState_FPUPreserve,
6754 d3d_device7_SetTextureStageState_FPUPreserve,
6755 d3d_device7_ValidateDevice_FPUPreserve,
6756 d3d_device7_ApplyStateBlock_FPUPreserve,
6757 d3d_device7_CaptureStateBlock_FPUPreserve,
6758 d3d_device7_DeleteStateBlock_FPUPreserve,
6759 d3d_device7_CreateStateBlock_FPUPreserve,
6760 d3d_device7_Load_FPUPreserve,
6761 d3d_device7_LightEnable_FPUPreserve,
6762 d3d_device7_GetLightEnable_FPUPreserve,
6763 d3d_device7_SetClipPlane_FPUPreserve,
6764 d3d_device7_GetClipPlane_FPUPreserve,
6765 d3d_device7_GetInfo
6768 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6770 /*** IUnknown Methods ***/
6771 d3d_device3_QueryInterface,
6772 d3d_device3_AddRef,
6773 d3d_device3_Release,
6774 /*** IDirect3DDevice3 ***/
6775 d3d_device3_GetCaps,
6776 d3d_device3_GetStats,
6777 d3d_device3_AddViewport,
6778 d3d_device3_DeleteViewport,
6779 d3d_device3_NextViewport,
6780 d3d_device3_EnumTextureFormats,
6781 d3d_device3_BeginScene,
6782 d3d_device3_EndScene,
6783 d3d_device3_GetDirect3D,
6784 d3d_device3_SetCurrentViewport,
6785 d3d_device3_GetCurrentViewport,
6786 d3d_device3_SetRenderTarget,
6787 d3d_device3_GetRenderTarget,
6788 d3d_device3_Begin,
6789 d3d_device3_BeginIndexed,
6790 d3d_device3_Vertex,
6791 d3d_device3_Index,
6792 d3d_device3_End,
6793 d3d_device3_GetRenderState,
6794 d3d_device3_SetRenderState,
6795 d3d_device3_GetLightState,
6796 d3d_device3_SetLightState,
6797 d3d_device3_SetTransform,
6798 d3d_device3_GetTransform,
6799 d3d_device3_MultiplyTransform,
6800 d3d_device3_DrawPrimitive,
6801 d3d_device3_DrawIndexedPrimitive,
6802 d3d_device3_SetClipStatus,
6803 d3d_device3_GetClipStatus,
6804 d3d_device3_DrawPrimitiveStrided,
6805 d3d_device3_DrawIndexedPrimitiveStrided,
6806 d3d_device3_DrawPrimitiveVB,
6807 d3d_device3_DrawIndexedPrimitiveVB,
6808 d3d_device3_ComputeSphereVisibility,
6809 d3d_device3_GetTexture,
6810 d3d_device3_SetTexture,
6811 d3d_device3_GetTextureStageState,
6812 d3d_device3_SetTextureStageState,
6813 d3d_device3_ValidateDevice
6816 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6818 /*** IUnknown Methods ***/
6819 d3d_device2_QueryInterface,
6820 d3d_device2_AddRef,
6821 d3d_device2_Release,
6822 /*** IDirect3DDevice2 ***/
6823 d3d_device2_GetCaps,
6824 d3d_device2_SwapTextureHandles,
6825 d3d_device2_GetStats,
6826 d3d_device2_AddViewport,
6827 d3d_device2_DeleteViewport,
6828 d3d_device2_NextViewport,
6829 d3d_device2_EnumTextureFormats,
6830 d3d_device2_BeginScene,
6831 d3d_device2_EndScene,
6832 d3d_device2_GetDirect3D,
6833 d3d_device2_SetCurrentViewport,
6834 d3d_device2_GetCurrentViewport,
6835 d3d_device2_SetRenderTarget,
6836 d3d_device2_GetRenderTarget,
6837 d3d_device2_Begin,
6838 d3d_device2_BeginIndexed,
6839 d3d_device2_Vertex,
6840 d3d_device2_Index,
6841 d3d_device2_End,
6842 d3d_device2_GetRenderState,
6843 d3d_device2_SetRenderState,
6844 d3d_device2_GetLightState,
6845 d3d_device2_SetLightState,
6846 d3d_device2_SetTransform,
6847 d3d_device2_GetTransform,
6848 d3d_device2_MultiplyTransform,
6849 d3d_device2_DrawPrimitive,
6850 d3d_device2_DrawIndexedPrimitive,
6851 d3d_device2_SetClipStatus,
6852 d3d_device2_GetClipStatus
6855 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6857 /*** IUnknown Methods ***/
6858 d3d_device1_QueryInterface,
6859 d3d_device1_AddRef,
6860 d3d_device1_Release,
6861 /*** IDirect3DDevice1 ***/
6862 d3d_device1_Initialize,
6863 d3d_device1_GetCaps,
6864 d3d_device1_SwapTextureHandles,
6865 d3d_device1_CreateExecuteBuffer,
6866 d3d_device1_GetStats,
6867 d3d_device1_Execute,
6868 d3d_device1_AddViewport,
6869 d3d_device1_DeleteViewport,
6870 d3d_device1_NextViewport,
6871 d3d_device1_Pick,
6872 d3d_device1_GetPickRecords,
6873 d3d_device1_EnumTextureFormats,
6874 d3d_device1_CreateMatrix,
6875 d3d_device1_SetMatrix,
6876 d3d_device1_GetMatrix,
6877 d3d_device1_DeleteMatrix,
6878 d3d_device1_BeginScene,
6879 d3d_device1_EndScene,
6880 d3d_device1_GetDirect3D
6883 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6885 d3d_device_inner_QueryInterface,
6886 d3d_device_inner_AddRef,
6887 d3d_device_inner_Release,
6890 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6892 if (!iface) return NULL;
6893 assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6894 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6897 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6899 if (!iface) return NULL;
6900 assert(iface->lpVtbl == &d3d_device3_vtbl);
6901 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6904 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6906 if (!iface) return NULL;
6907 assert(iface->lpVtbl == &d3d_device2_vtbl);
6908 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6911 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6913 if (!iface) return NULL;
6914 assert(iface->lpVtbl == &d3d_device1_vtbl);
6915 return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6918 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6920 IDirectDrawSurface7 *depthStencil = NULL;
6921 IDirectDrawSurface7 *render_target;
6922 static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, {0} };
6923 struct ddraw_surface *dsi;
6925 if (device->rt_iface && SUCCEEDED(IUnknown_QueryInterface(device->rt_iface,
6926 &IID_IDirectDrawSurface7, (void **)&render_target)))
6928 IDirectDrawSurface7_GetAttachedSurface(render_target, &depthcaps, &depthStencil);
6929 IDirectDrawSurface7_Release(render_target);
6931 if (!depthStencil)
6933 TRACE("Setting wined3d depth stencil to NULL\n");
6934 wined3d_device_set_depth_stencil_view(device->wined3d_device, NULL);
6935 return WINED3D_ZB_FALSE;
6938 dsi = impl_from_IDirectDrawSurface7(depthStencil);
6939 wined3d_device_set_depth_stencil_view(device->wined3d_device,
6940 ddraw_surface_get_rendertarget_view(dsi));
6942 IDirectDrawSurface7_Release(depthStencil);
6943 return WINED3D_ZB_TRUE;
6946 static void ddraw_reset_viewport_state(struct ddraw *ddraw)
6948 struct wined3d_viewport vp;
6949 RECT rect;
6951 wined3d_device_get_viewports(ddraw->wined3d_device, NULL, &vp);
6952 wined3d_stateblock_set_viewport(ddraw->state, &vp);
6953 wined3d_device_get_scissor_rects(ddraw->wined3d_device, NULL, &rect);
6954 wined3d_stateblock_set_scissor_rect(ddraw->state, &rect);
6957 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
6958 struct ddraw_surface *target, IUnknown *rt_iface, UINT version, IUnknown *outer_unknown)
6960 static const struct wined3d_matrix ident =
6962 1.0f, 0.0f, 0.0f, 0.0f,
6963 0.0f, 1.0f, 0.0f, 0.0f,
6964 0.0f, 0.0f, 1.0f, 0.0f,
6965 0.0f, 0.0f, 0.0f, 1.0f,
6967 HRESULT hr;
6969 if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6970 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6971 else
6972 device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6974 device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6975 device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6976 device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6977 device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6978 device->ref = 1;
6979 device->version = version;
6981 if (outer_unknown)
6982 device->outer_unknown = outer_unknown;
6983 else
6984 device->outer_unknown = &device->IUnknown_inner;
6986 device->ddraw = ddraw;
6987 list_init(&device->viewport_list);
6989 if (!ddraw_handle_table_init(&device->handle_table, 64))
6991 ERR("Failed to initialize handle table.\n");
6992 return DDERR_OUTOFMEMORY;
6995 device->legacyTextureBlending = FALSE;
6996 device->legacy_projection = ident;
6997 device->legacy_clipspace = ident;
6999 /* This is for convenience. */
7000 device->wined3d_device = ddraw->wined3d_device;
7001 wined3d_device_incref(ddraw->wined3d_device);
7002 device->update_state = device->state = ddraw->state;
7003 wined3d_stateblock_incref(ddraw->state);
7005 /* Render to the back buffer */
7006 if (FAILED(hr = wined3d_device_set_rendertarget_view(ddraw->wined3d_device,
7007 0, ddraw_surface_get_rendertarget_view(target), TRUE)))
7009 ERR("Failed to set render target, hr %#x.\n", hr);
7010 wined3d_stateblock_decref(device->state);
7011 ddraw_handle_table_destroy(&device->handle_table);
7012 return hr;
7015 device->rt_iface = rt_iface;
7016 if (version != 1)
7017 IUnknown_AddRef(device->rt_iface);
7019 ddraw->d3ddevice = device;
7021 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_ZENABLE,
7022 d3d_device_update_depth_stencil(device));
7023 if (version == 1) /* Color keying is initially enabled for version 1 devices. */
7024 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_COLORKEYENABLE, TRUE);
7025 else if (version == 2)
7026 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_SPECULARENABLE, TRUE);
7027 if (version < 7)
7029 wined3d_stateblock_set_render_state(ddraw->state, WINED3D_RS_NORMALIZENORMALS, TRUE);
7030 IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface,
7031 D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
7033 ddraw_reset_viewport_state(ddraw);
7034 return D3D_OK;
7037 HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target, IUnknown *rt_iface,
7038 UINT version, struct d3d_device **device, IUnknown *outer_unknown)
7040 struct d3d_device *object;
7041 HRESULT hr;
7043 TRACE("ddraw %p, target %p, version %u, device %p, outer_unknown %p.\n",
7044 ddraw, target, version, device, outer_unknown);
7046 if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
7047 || (target->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
7049 WARN("Surface %p is not a render target.\n", target);
7050 return DDERR_INVALIDCAPS;
7053 if (!validate_surface_palette(target))
7055 WARN("Surface %p has an indexed pixel format, but no palette.\n", target);
7056 return DDERR_NOPALETTEATTACHED;
7059 if (ddraw->flags & DDRAW_NO3D)
7061 ERR_(winediag)("The application wants to create a Direct3D device, "
7062 "but the current DirectDrawRenderer does not support this.\n");
7064 return DDERR_OUTOFMEMORY;
7067 if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
7069 WARN("Surface %p is not in video memory.\n", target);
7070 return D3DERR_SURFACENOTINVIDMEM;
7073 if (ddraw->d3ddevice)
7075 FIXME("Only one Direct3D device per DirectDraw object supported.\n");
7076 return DDERR_INVALIDPARAMS;
7079 if (!(object = heap_alloc_zero(sizeof(*object))))
7081 ERR("Failed to allocate device memory.\n");
7082 return DDERR_OUTOFMEMORY;
7085 if (FAILED(hr = d3d_device_init(object, ddraw, target, rt_iface, version, outer_unknown)))
7087 WARN("Failed to initialize device, hr %#x.\n", hr);
7088 heap_free(object);
7089 return hr;
7092 TRACE("Created device %p.\n", object);
7093 *device = object;
7095 return D3D_OK;