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