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