1 /*
2 * Copyright (c) 2006 Stefan Dösinger
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "config.h"
20 #include "wine/port.h"
21 #include "wine/debug.h"
22
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <stdlib.h>
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "wingdi.h"
34 #include "wine/exception.h"
35
36 #include "ddraw.h"
37 #include "d3d.h"
38
39 #include "ddraw_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
42
43 /*****************************************************************************
44 * IDirect3D7::QueryInterface
45 *
46 * QueryInterface implementation with thunks to IDirectDraw7
47 *
48 *****************************************************************************/
49 static HRESULT WINAPI
50 Thunk_IDirect3DImpl_7_QueryInterface(IDirect3D7 *iface,
51 REFIID refiid,
52 void **obj)
53 {
54 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
55 TRACE("(%p)->(%s,%p): Thunking to IDirectDraw7\n", This, debugstr_guid(refiid), obj);
56
57 return IDirectDraw7_QueryInterface(ICOM_INTERFACE(This, IDirectDraw7),
58 refiid,
59 obj);
60 }
61
62 static HRESULT WINAPI
63 Thunk_IDirect3DImpl_3_QueryInterface(IDirect3D3 *iface,
64 REFIID refiid,
65 void **obj)
66 {
67 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
68 TRACE("(%p)->(%s,%p): Thunking to IDirectDraw7\n", This, debugstr_guid(refiid), obj);
69
70 return IDirectDraw7_QueryInterface(ICOM_INTERFACE(This, IDirectDraw7),
71 refiid,
72 obj);
73 }
74
75 static HRESULT WINAPI
76 Thunk_IDirect3DImpl_2_QueryInterface(IDirect3D2 *iface,
77 REFIID refiid,
78 void **obj)
79 {
80 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
81 TRACE("(%p)->(%s,%p): Thunking to IDirectDraw7\n", This, debugstr_guid(refiid), obj);
82
83 return IDirectDraw7_QueryInterface(ICOM_INTERFACE(This, IDirectDraw7),
84 refiid,
85 obj);
86 }
87
88 static HRESULT WINAPI
89 Thunk_IDirect3DImpl_1_QueryInterface(IDirect3D *iface,
90 REFIID refiid,
91 void **obj)
92 {
93 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
94 TRACE("(%p)->(%s,%p): Thunking to IDirectDraw7\n", This, debugstr_guid(refiid), obj);
95
96 return IDirectDraw7_QueryInterface(ICOM_INTERFACE(This, IDirectDraw7),
97 refiid,
98 obj);
99 }
100
101 /*****************************************************************************
102 * IDirect3D7::AddRef
103 *
104 * DirectDraw refcounting is a bit odd. Every version of the ddraw interface
105 * has its own refcount, but IDirect3D 1/2/3 refcounts are linked to
106 * IDirectDraw, and IDirect3D7 is linked to IDirectDraw7
107 *
108 * IDirect3D7 -> IDirectDraw7
109 * IDirect3D3 -> IDirectDraw
110 * IDirect3D2 -> IDirectDraw
111 * IDirect3D -> IDirectDraw
112 *
113 * So every AddRef implementation thunks to a different interface, and the
114 * IDirectDrawX::AddRef implementations have different counters...
115 *
116 * Returns
117 * The new refcount
118 *
119 *****************************************************************************/
120 static ULONG WINAPI
121 Thunk_IDirect3DImpl_7_AddRef(IDirect3D7 *iface)
122 {
123 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
124 TRACE("(%p) : Thunking to IDirectDraw7.\n", This);
125
126 return IDirectDraw7_AddRef(ICOM_INTERFACE(This, IDirectDraw7));
127 }
128
129 static ULONG WINAPI
130 Thunk_IDirect3DImpl_3_AddRef(IDirect3D3 *iface)
131 {
132 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
133 TRACE("(%p) : Thunking to IDirectDraw.\n", This);
134
135 return IDirectDraw_AddRef(ICOM_INTERFACE(This, IDirectDraw));
136 }
137
138 static ULONG WINAPI
139 Thunk_IDirect3DImpl_2_AddRef(IDirect3D2 *iface)
140 {
141 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
142 TRACE("(%p) : Thunking to IDirectDraw.\n", This);
143
144 return IDirectDraw_AddRef(ICOM_INTERFACE(This, IDirectDraw));
145 }
146
147 static ULONG WINAPI
148 Thunk_IDirect3DImpl_1_AddRef(IDirect3D *iface)
149 {
150 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
151 TRACE("(%p) : Thunking to IDirectDraw.\n", This);
152
153 return IDirectDraw_AddRef(ICOM_INTERFACE(This, IDirectDraw));
154 }
155
156 /*****************************************************************************
157 * IDirect3D7::Release
158 *
159 * Same story as IDirect3D7::AddRef
160 *
161 * Returns: The new refcount
162 *
163 *****************************************************************************/
164 static ULONG WINAPI
165 Thunk_IDirect3DImpl_7_Release(IDirect3D7 *iface)
166 {
167 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
168 TRACE("(%p) : Thunking to IDirectDraw7.\n", This);
169
170 return IDirectDraw7_Release(ICOM_INTERFACE(This, IDirectDraw7));
171 }
172
173 static ULONG WINAPI
174 Thunk_IDirect3DImpl_3_Release(IDirect3D3 *iface)
175 {
176 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
177 TRACE("(%p) : Thunking to IDirectDraw.\n", This);
178
179 return IDirectDraw_Release(ICOM_INTERFACE(This, IDirectDraw));
180 }
181
182 static ULONG WINAPI
183 Thunk_IDirect3DImpl_2_Release(IDirect3D2 *iface)
184 {
185 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
186 TRACE("(%p) : Thunking to IDirectDraw.\n", This);
187
188 return IDirectDraw_Release(ICOM_INTERFACE(This, IDirectDraw));
189 }
190
191 static ULONG WINAPI
192 Thunk_IDirect3DImpl_1_Release(IDirect3D *iface)
193 {
194 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
195 TRACE("(%p) : Thunking to IDirectDraw.\n", This);
196
197 return IDirectDraw_Release(ICOM_INTERFACE(This, IDirectDraw));
198 }
199
200 /*****************************************************************************
201 * IDirect3D Methods
202 *****************************************************************************/
203
204 /*****************************************************************************
205 * IDirect3D::Initialize
206 *
207 * Initializes the IDirect3D interface. This is a no-op implementation,
208 * as all initialization is done at create time.
209 *
210 * Version 1
211 *
212 * Params:
213 * refiid: ?
214 *
215 * Returns:
216 * D3D_OK, because it's a no-op
217 *
218 *****************************************************************************/
219 static HRESULT WINAPI
220 IDirect3DImpl_1_Initialize(IDirect3D *iface,
221 REFIID refiid)
222 {
223 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
224
225 TRACE("(%p)->(%s) no-op...\n", This, debugstr_guid(refiid));
226 return D3D_OK;
227 }
228
229 /*****************************************************************************
230 * IDirect3D7::EnumDevices
231 *
232 * The EnumDevices method for IDirect3D7. It enumerates all supported
233 * D3D7 devices. Currently the T&L, HAL and RGB devices are enumerated.
234 *
235 * Params:
236 * Callback: Function to call for each enumerated device
237 * Context: Pointer to pass back to the app
238 *
239 * Returns:
240 * D3D_OK, or the return value of the GetCaps call
241 *
242 *****************************************************************************/
243 static HRESULT WINAPI
244 IDirect3DImpl_7_EnumDevices(IDirect3D7 *iface,
245 LPD3DENUMDEVICESCALLBACK7 Callback,
246 void *Context)
247 {
248 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
249 char interface_name_tnl[] = "WINE Direct3D7 Hardware Transform and Lighting acceleration using WineD3D";
250 char device_name_tnl[] = "Wine D3D7 T&L HAL";
251 char interface_name_hal[] = "WINE Direct3D7 Hardware acceleration using WineD3D";
252 char device_name_hal[] = "Wine D3D7 HAL";
253 char interface_name_rgb[] = "WINE Direct3D7 RGB Software Emulation using WineD3D";
254 char device_name_rgb[] = "Wine D3D7 RGB";
255 D3DDEVICEDESC7 ddesc;
256 D3DDEVICEDESC oldDesc;
257 HRESULT hr;
258
259 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
260 EnterCriticalSection(&ddraw_cs);
261
262 TRACE("(%p) Enumerating WineD3D D3Device7 interface\n", This);
263 hr = IDirect3DImpl_GetCaps(This->wineD3D, &oldDesc, &ddesc);
264 if(hr != D3D_OK)
265 {
266 LeaveCriticalSection(&ddraw_cs);
267 return hr;
268 }
269 Callback(interface_name_tnl, device_name_tnl, &ddesc, Context);
270
271 ddesc.deviceGUID = IID_IDirect3DHALDevice;
272 Callback(interface_name_hal, device_name_hal, &ddesc, Context);
273
274 ddesc.deviceGUID = IID_IDirect3DRGBDevice;
275 Callback(interface_name_rgb, device_name_rgb, &ddesc, Context);
276
277 TRACE("(%p) End of enumeration\n", This);
278 LeaveCriticalSection(&ddraw_cs);
279 return D3D_OK;
280 }
281
282 /*****************************************************************************
283 * IDirect3D3::EnumDevices
284 *
285 * Enumerates all supported Direct3DDevice interfaces. This is the
286 * implementation for Direct3D 1 to Direc3D 3, Version 7 has its own.
287 *
288 * Version 1, 2 and 3
289 *
290 * Params:
291 * Callback: Application-provided routine to call for each enumerated device
292 * Context: Pointer to pass to the callback
293 *
294 * Returns:
295 * D3D_OK on success,
296 * The result of IDirect3DImpl_GetCaps if it failed
297 *
298 *****************************************************************************/
299 static HRESULT WINAPI
300 IDirect3DImpl_3_EnumDevices(IDirect3D3 *iface,
301 LPD3DENUMDEVICESCALLBACK Callback,
302 void *Context)
303 {
304 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
305 D3DDEVICEDESC dref, d1, d2;
306 D3DDEVICEDESC7 newDesc;
307 static CHAR wined3d_description[] = "Wine D3DDevice using WineD3D and OpenGL";
308 HRESULT hr;
309
310 /* Some games (Motoracer 2 demo) have the bad idea to modify the device name string.
311 Let's put the string in a sufficiently sized array in writable memory. */
312 char device_name[50];
313 strcpy(device_name,"Direct3D HEL");
314
315 TRACE("(%p)->(%p,%p)\n", This, Callback, Context);
316 EnterCriticalSection(&ddraw_cs);
317
318 hr = IDirect3DImpl_GetCaps(This->wineD3D, &dref, &newDesc);
319 if(hr != D3D_OK)
320 {
321 LeaveCriticalSection(&ddraw_cs);
322 return hr;
323 }
324
325 /* Do I have to enumerate the reference id? Note from old d3d7:
326 * "It seems that enumerating the reference IID on Direct3D 1 games
327 * (AvP / Motoracer2) breaks them". So do not enumerate this iid in V1
328 *
329 * There's a registry key HKLM\Software\Microsoft\Direct3D\Drivers, EnumReference
330 * which enables / disables enumerating the reference rasterizer. It's a DWORD,
331 * 0 means disabled, 2 means enabled. The enablerefrast.reg and disablerefrast.reg
332 * files in the DirectX 7.0 sdk demo directory suggest this.
333 *
334 * Some games(GTA 2) seem to use the second enumerated device, so I have to enumerate
335 * at least 2 devices. So enumerate the reference device to have 2 devices.
336 *
337 * Other games(Rollcage) tell emulation and hal device apart by certain flags.
338 * Rollcage expects D3DPTEXTURECAPS_POW2 to be set(yeah, it is a limitation flag),
339 * and it refuses all devices that have the perspective flag set. This way it refuses
340 * the emulation device, and HAL devices never have POW2 unset in d3d7 on windows.
341 */
342
343 if(This->d3dversion != 1)
344 {
345 static CHAR reference_description[] = "RGB Direct3D emulation";
346
347 TRACE("(%p) Enumerating WineD3D D3DDevice interface\n", This);
348 d1 = dref;
349 d2 = dref;
350 /* The rgb device has the pow2 flag set in the hel caps, but not in the hal caps */
351 d1.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
352 d1.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
353 hr = Callback( (LPIID) &IID_IDirect3DRGBDevice, reference_description, device_name, &d1, &d2, Context);
354 if(hr != D3DENUMRET_OK)
355 {
356 TRACE("Application cancelled the enumeration\n");
357 LeaveCriticalSection(&ddraw_cs);
358 return D3D_OK;
359 }
360 }
361
362 strcpy(device_name,"Direct3D HAL");
363
364 TRACE("(%p) Enumerating HAL Direct3D device\n", This);
365 d1 = dref;
366 d2 = dref;
367 /* The hal device does not have the pow2 flag set in hel, but in hal */
368 d2.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
369 d2.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
370 hr = Callback( (LPIID) &IID_IDirect3DHALDevice, wined3d_description, device_name, &d1, &d2, Context);
371 if(hr != D3DENUMRET_OK)
372 {
373 TRACE("Application cancelled the enumeration\n");
374 LeaveCriticalSection(&ddraw_cs);
375 return D3D_OK;
376 }
377 TRACE("(%p) End of enumeration\n", This);
378
379 LeaveCriticalSection(&ddraw_cs);
380 return D3D_OK;
381 }
382
383 static HRESULT WINAPI
384 Thunk_IDirect3DImpl_2_EnumDevices(IDirect3D2 *iface,
385 LPD3DENUMDEVICESCALLBACK Callback,
386 void *Context)
387 {
388 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
389 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, Callback, Context);
390 return IDirect3D3_EnumDevices(ICOM_INTERFACE(This, IDirect3D3),
391 Callback,
392 Context);
393 }
394
395 static HRESULT WINAPI
396 Thunk_IDirect3DImpl_1_EnumDevices(IDirect3D *iface,
397 LPD3DENUMDEVICESCALLBACK Callback,
398 void *Context)
399 {
400 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
401 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, Callback, Context);
402 return IDirect3D3_EnumDevices(ICOM_INTERFACE(This, IDirect3D3),
403 Callback,
404 Context);
405 }
406
407 /*****************************************************************************
408 * IDirect3D3::CreateLight
409 *
410 * Creates an IDirect3DLight interface. This interface is used in
411 * Direct3D3 or earlier for lighting. In Direct3D7 it has been replaced
412 * by the DIRECT3DLIGHT7 structure. Wine's Direct3DLight implementation
413 * uses the IDirect3DDevice7 interface with D3D7 lights.
414 *
415 * Version 1, 2 and 3
416 *
417 * Params:
418 * Light: Address to store the new interface pointer
419 * UnkOuter: Basically for aggregation, but ddraw doesn't support it.
420 * Must be NULL
421 *
422 * Returns:
423 * D3D_OK on success
424 * DDERR_OUTOFMEMORY if memory allocation failed
425 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
426 *
427 *****************************************************************************/
428 static HRESULT WINAPI
429 IDirect3DImpl_3_CreateLight(IDirect3D3 *iface,
430 IDirect3DLight **Light,
431 IUnknown *UnkOuter )
432 {
433 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
434 IDirect3DLightImpl *object;
435
436 TRACE("(%p)->(%p,%p)\n", This, Light, UnkOuter);
437
438 if(UnkOuter)
439 return CLASS_E_NOAGGREGATION;
440
441 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DLightImpl));
442 if (object == NULL)
443 return DDERR_OUTOFMEMORY;
444
445 ICOM_INIT_INTERFACE(object, IDirect3DLight, IDirect3DLight_Vtbl);
446 object->ref = 1;
447 object->ddraw = This;
448 object->next = NULL;
449 object->active_viewport = NULL;
450
451 /* Update functions */
452 object->activate = light_update;
453 object->desactivate = light_activate;
454 object->update = light_desactivate;
455 object->active_viewport = NULL;
456
457 *Light = ICOM_INTERFACE(object, IDirect3DLight);
458
459 TRACE("(%p) creating implementation at %p.\n", This, object);
460
461 return D3D_OK;
462 }
463
464 static HRESULT WINAPI
465 Thunk_IDirect3DImpl_2_CreateLight(IDirect3D2 *iface,
466 IDirect3DLight **Direct3DLight,
467 IUnknown *UnkOuter)
468 {
469 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
470 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, Direct3DLight, UnkOuter);
471 return IDirect3D3_CreateLight(ICOM_INTERFACE(This, IDirect3D3),
472 Direct3DLight,
473 UnkOuter);
474 }
475
476 static HRESULT WINAPI
477 Thunk_IDirect3DImpl_1_CreateLight(IDirect3D *iface,
478 IDirect3DLight **Direct3DLight,
479 IUnknown *UnkOuter)
480 {
481 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
482 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, Direct3DLight, UnkOuter);
483 return IDirect3D3_CreateLight(ICOM_INTERFACE(This, IDirect3D3),
484 Direct3DLight,
485 UnkOuter);
486 }
487
488 /*****************************************************************************
489 * IDirect3D3::CreateMaterial
490 *
491 * Creates an IDirect3DMaterial interface. This interface is used by Direct3D3
492 * and older versions. The IDirect3DMaterial implementation wraps its
493 * functionality to IDirect3DDevice7::SetMaterial and friends.
494 *
495 * Version 1, 2 and 3
496 *
497 * Params:
498 * Material: Address to store the new interface's pointer to
499 * UnkOuter: Basically for aggregation, but ddraw doesn't support it.
500 * Must be NULL
501 *
502 * Returns:
503 * D3D_OK on success
504 * DDERR_OUTOFMEMORY if memory allocation failed
505 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
506 *
507 *****************************************************************************/
508 static HRESULT WINAPI
509 IDirect3DImpl_3_CreateMaterial(IDirect3D3 *iface,
510 IDirect3DMaterial3 **Material,
511 IUnknown *UnkOuter )
512 {
513 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
514 IDirect3DMaterialImpl *object;
515
516 TRACE("(%p)->(%p,%p)\n", This, Material, UnkOuter);
517
518 if(UnkOuter)
519 return CLASS_E_NOAGGREGATION;
520
521 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DMaterialImpl));
522 if (object == NULL)
523 return DDERR_OUTOFMEMORY;
524
525 ICOM_INIT_INTERFACE(object, IDirect3DMaterial3, IDirect3DMaterial3_Vtbl);
526 ICOM_INIT_INTERFACE(object, IDirect3DMaterial2, IDirect3DMaterial2_Vtbl);
527 ICOM_INIT_INTERFACE(object, IDirect3DMaterial, IDirect3DMaterial_Vtbl);
528 object->ref = 1;
529 object->ddraw = This;
530 object->activate = material_activate;
531
532 *Material = ICOM_INTERFACE(object, IDirect3DMaterial3);
533
534 TRACE("(%p) creating implementation at %p.\n", This, object);
535
536 return D3D_OK;
537 }
538
539 static HRESULT WINAPI
540 Thunk_IDirect3DImpl_2_CreateMaterial(IDirect3D2 *iface,
541 IDirect3DMaterial2 **Direct3DMaterial,
542 IUnknown* UnkOuter)
543 {
544 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
545 HRESULT ret;
546 IDirect3DMaterial3 *ret_val;
547
548 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, Direct3DMaterial, UnkOuter);
549 ret = IDirect3D3_CreateMaterial(ICOM_INTERFACE(This, IDirect3D3),
550 &ret_val,
551 UnkOuter);
552
553 *Direct3DMaterial = COM_INTERFACE_CAST(IDirect3DMaterialImpl, IDirect3DMaterial3, IDirect3DMaterial2, ret_val);
554
555 TRACE(" returning interface %p.\n", *Direct3DMaterial);
556
557 return ret;
558 }
559
560 static HRESULT WINAPI
561 Thunk_IDirect3DImpl_1_CreateMaterial(IDirect3D *iface,
562 IDirect3DMaterial **Direct3DMaterial,
563 IUnknown* UnkOuter)
564 {
565 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
566 HRESULT ret;
567 LPDIRECT3DMATERIAL3 ret_val;
568
569 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, Direct3DMaterial, UnkOuter);
570 ret = IDirect3D3_CreateMaterial(ICOM_INTERFACE(This, IDirect3D3),
571 &ret_val,
572 UnkOuter);
573
574 *Direct3DMaterial = COM_INTERFACE_CAST(IDirect3DMaterialImpl, IDirect3DMaterial3, IDirect3DMaterial, ret_val);
575
576 TRACE(" returning interface %p.\n", *Direct3DMaterial);
577
578 return ret;
579 }
580
581 /*****************************************************************************
582 * IDirect3D3::CreateViewport
583 *
584 * Creates an IDirect3DViewport interface. This interface is used
585 * by Direct3D and earlier versions for Viewport management. In Direct3D7
586 * it has been replaced by a viewport structure and
587 * IDirect3DDevice7::*Viewport. Wine's IDirect3DViewport implementation
588 * uses the IDirect3DDevice7 methods for its functionality
589 *
590 * Params:
591 * Viewport: Address to store the new interface pointer
592 * UnkOuter: Basically for aggregation, but ddraw doesn't support it.
593 * Must be NULL
594 *
595 * Returns:
596 * D3D_OK on success
597 * DDERR_OUTOFMEMORY if memory allocation failed
598 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
599 *
600 *****************************************************************************/
601 static HRESULT WINAPI
602 IDirect3DImpl_3_CreateViewport(IDirect3D3 *iface,
603 IDirect3DViewport3 **Viewport,
604 IUnknown *UnkOuter )
605 {
606 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
607 IDirect3DViewportImpl *object;
608
609 if(UnkOuter)
610 return CLASS_E_NOAGGREGATION;
611
612 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DViewportImpl));
613 if (object == NULL)
614 return DDERR_OUTOFMEMORY;
615
616 ICOM_INIT_INTERFACE(object, IDirect3DViewport3, IDirect3DViewport3_Vtbl);
617 object->ref = 1;
618 object->ddraw = This;
619 object->activate = viewport_activate;
620 object->use_vp2 = 0xFF;
621 object->next = NULL;
622 object->lights = NULL;
623 object->num_lights = 0;
624 object->map_lights = 0;
625
626 *Viewport = ICOM_INTERFACE(object, IDirect3DViewport3);
627
628 TRACE("(%p) creating implementation at %p.\n",This, object);
629
630 return D3D_OK;
631 }
632
633 static HRESULT WINAPI
634 Thunk_IDirect3DImpl_2_CreateViewport(IDirect3D2 *iface,
635 IDirect3DViewport2 **D3DViewport2,
636 IUnknown *UnkOuter)
637 {
638 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
639 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, D3DViewport2, UnkOuter);
640
641 return IDirect3D3_CreateViewport(ICOM_INTERFACE(This, IDirect3D3),
642 (IDirect3DViewport3 **) D3DViewport2 /* No need to cast here */,
643 UnkOuter);
644 }
645
646 static HRESULT WINAPI
647 Thunk_IDirect3DImpl_1_CreateViewport(IDirect3D *iface,
648 IDirect3DViewport **D3DViewport,
649 IUnknown* UnkOuter)
650 {
651 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
652 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, D3DViewport, UnkOuter);
653
654 return IDirect3D3_CreateViewport(ICOM_INTERFACE(This, IDirect3D3),
655 (IDirect3DViewport3 **) D3DViewport /* No need to cast here */,
656 UnkOuter);
657 }
658
659 /*****************************************************************************
660 * IDirect3D3::FindDevice
661 *
662 * This method finds a device with the requested properties and returns a
663 * device description
664 *
665 * Verion 1, 2 and 3
666 * Params:
667 * D3DDFS: Describes the requested device characteristics
668 * D3DFDR: Returns the device description
669 *
670 * Returns:
671 * D3D_OK on success
672 * DDERR_INVALIDPARAMS if no device was found
673 *
674 *****************************************************************************/
675 static HRESULT WINAPI
676 IDirect3DImpl_3_FindDevice(IDirect3D3 *iface,
677 D3DFINDDEVICESEARCH *D3DDFS,
678 D3DFINDDEVICERESULT *D3DFDR)
679 {
680 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D3, iface);
681 D3DDEVICEDESC desc;
682 D3DDEVICEDESC7 newDesc;
683 HRESULT hr;
684
685 TRACE("(%p)->(%p,%p)\n", This, D3DDFS, D3DFDR);
686
687 if ((D3DDFS->dwFlags & D3DFDS_COLORMODEL) &&
688 (D3DDFS->dcmColorModel != D3DCOLOR_RGB))
689 {
690 TRACE(" trying to request a non-RGB D3D color model. Not supported.\n");
691 return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
692 }
693 if (D3DDFS->dwFlags & D3DFDS_GUID)
694 {
695 TRACE(" trying to match guid %s.\n", debugstr_guid(&(D3DDFS->guid)));
696 if ((IsEqualGUID(&IID_D3DDEVICE_WineD3D, &(D3DDFS->guid)) == 0) &&
697 (IsEqualGUID(&IID_IDirect3DHALDevice, &(D3DDFS->guid)) == 0) &&
698 (IsEqualGUID(&IID_IDirect3DRefDevice, &(D3DDFS->guid)) == 0))
699 {
700 TRACE(" no match for this GUID.\n");
701 return DDERR_INVALIDPARAMS;
702 }
703 }
704
705 /* Get the caps */
706 hr = IDirect3DImpl_GetCaps(This->wineD3D, &desc, &newDesc);
707 if(hr != D3D_OK) return hr;
708
709 /* Now return our own GUID */
710 D3DFDR->guid = IID_D3DDEVICE_WineD3D;
711 D3DFDR->ddHwDesc = desc;
712 D3DFDR->ddSwDesc = desc;
713
714 TRACE(" returning Wine's WineD3D device with (undumped) capabilities\n");
715
716 return D3D_OK;
717 }
718
719 static HRESULT WINAPI
720 Thunk_IDirect3DImpl_2_FindDevice(IDirect3D2 *iface,
721 D3DFINDDEVICESEARCH *D3DDFS,
722 D3DFINDDEVICERESULT *D3DFDR)
723 {
724 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D2, iface);
725 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", iface, D3DDFS, D3DFDR);
726 return IDirect3D3_FindDevice(ICOM_INTERFACE(This, IDirect3D3),
727 D3DDFS,
728 D3DFDR);
729 }
730
731 static HRESULT WINAPI
732 Thunk_IDirect3DImpl_1_FindDevice(IDirect3D *iface,
733 D3DFINDDEVICESEARCH *D3DDFS,
734 D3DFINDDEVICERESULT *D3DDevice)
735 {
736 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D, iface);
737 TRACE("(%p)->(%p,%p) thunking to IDirect3D3 interface.\n", This, D3DDFS, D3DDevice);
738 return IDirect3D3_FindDevice(ICOM_INTERFACE(This, IDirect3D3),
739 D3DDFS,
740 D3DDevice);
741 }
742
743 /*****************************************************************************
744 * IDirect3D7::CreateDevice
745 *
746 * Creates an IDirect3DDevice7 interface.
747 *
748 * Version 2, 3 and 7. IDirect3DDevice 1 interfaces are interfaces to
749 * DirectDraw surfaces and are created with
750 * IDirectDrawSurface::QueryInterface. This method uses CreateDevice to
751 * create the device object and QueryInterfaces for IDirect3DDevice
752 *
753 * Params:
754 * refiid: IID of the device to create
755 * Surface: Initial rendertarget
756 * Device: Address to return the interface pointer
757 *
758 * Returns:
759 * D3D_OK on success
760 * DDERR_OUTOFMEMORY if memory allocation failed
761 * DDERR_INVALIDPARAMS if a device exists already
762 *
763 *****************************************************************************/
764 static HRESULT WINAPI
765 IDirect3DImpl_7_CreateDevice(IDirect3D7 *iface,
766 REFCLSID refiid,
767 IDirectDrawSurface7 *Surface,
768 IDirect3DDevice7 **Device)
769 {
770 ICOM_THIS_FROM(IDirectDrawImpl, IDirect3D7, iface);
771 IDirect3DDeviceImpl *object;
772 IParentImpl *IndexBufferParent;
773 HRESULT hr;
774 IDirectDrawSurfaceImpl *target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Surface);
775 TRACE("(%p)->(%s,%p,%p)\n", iface, debugstr_guid(refiid), Surface, Device);
776
777 EnterCriticalSection(&ddraw_cs);
778 *Device = NULL;
779
780 /* Fail device creation if non-opengl surfaces are used */
781 if(This->ImplType != SURFACE_OPENGL)
782 {
783 ERR("The application wants to create a Direct3D device, but non-opengl surfaces are set in the registry. Please set the surface implementation to opengl or autodetection to allow 3D rendering\n");
784
785 /* We only hit this path if a default surface is set in the registry. Incorrect autodetection
786 * is caught in CreateSurface or QueryInterface
787 */
788 LeaveCriticalSection(&ddraw_cs);
789 return DDERR_NO3D;
790 }
791
792 /* So far we can only create one device per ddraw object */
793 if(This->d3ddevice)
794 {
795 FIXME("(%p): Only one Direct3D device per DirectDraw object supported\n", This);
796 LeaveCriticalSection(&ddraw_cs);
797 return DDERR_INVALIDPARAMS;
798 }
799
800 object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirect3DDeviceImpl));
801 if(!object)
802 {
803 ERR("Out of memory when allocating a IDirect3DDevice implementation\n");
804 LeaveCriticalSection(&ddraw_cs);
805 return DDERR_OUTOFMEMORY;
806 }
807
808 ICOM_INIT_INTERFACE(object, IDirect3DDevice7, IDirect3DDevice7_Vtbl);
809 ICOM_INIT_INTERFACE(object, IDirect3DDevice3, IDirect3DDevice3_Vtbl);
810 ICOM_INIT_INTERFACE(object, IDirect3DDevice2, IDirect3DDevice2_Vtbl);
811 ICOM_INIT_INTERFACE(object, IDirect3DDevice, IDirect3DDevice1_Vtbl);
812
813 object->ref = 1;
814 object->ddraw = This;
815 object->viewport_list = NULL;
816 object->current_viewport = NULL;
817 object->material = 0;
818 object->target = target;
819
820 object->Handles = NULL;
821 object->numHandles = 0;
822
823 /* This is for convenience */
824 object->wineD3DDevice = This->wineD3DDevice;
825
826 /* Create an index buffer, it's needed for indexed drawing */
827 IndexBufferParent = HeapAlloc(GetProcessHeap(), 0, sizeof(IParentImpl *));
828 if(!IndexBufferParent)
829 {
830 ERR("Allocating memory for an index buffer parent failed\n");
831 HeapFree(GetProcessHeap(), 0, object);
832 LeaveCriticalSection(&ddraw_cs);
833 return DDERR_OUTOFMEMORY;
834 }
835 ICOM_INIT_INTERFACE(IndexBufferParent, IParent, IParent_Vtbl);
836 IndexBufferParent->ref = 1;
837
838 /* Create an Index Buffer. WineD3D needs one for Drawing indexed primitives
839 * Create a (hopefully) long enough buffer, and copy the indices into it
840 * Ideally, a IWineD3DIndexBuffer::SetData method could be created, which
841 * takes the pointer and avoids the memcpy
842 */
843 hr = IWineD3DDevice_CreateIndexBuffer(This->wineD3DDevice,
844 0x40000, /* Length. Don't know how long it should be */
845 WINED3DUSAGE_DYNAMIC, /* Usage */
846 WINED3DFMT_INDEX16, /* Format. D3D7 uses WORDS */
847 WINED3DPOOL_DEFAULT,
848 &object->indexbuffer,
849 0 /* Handle */,
850 (IUnknown *) ICOM_INTERFACE(IndexBufferParent, IParent));
851
852 if(FAILED(hr))
853 {
854 ERR("Failed to create an index buffer\n");
855 HeapFree(GetProcessHeap(), 0, object);
856 LeaveCriticalSection(&ddraw_cs);
857 return hr;
858 }
859 IndexBufferParent->child = (IUnknown *) object->indexbuffer;
860
861 /* No need to set the indices, it's done when necessary */
862
863 /* AddRef the WineD3D Device */
864 IWineD3DDevice_AddRef(This->wineD3DDevice);
865
866 /* Don't forget to return the interface ;) */
867 *Device = ICOM_INTERFACE(object, IDirect3DDevice7);
868
869 TRACE(" (%p) Created an IDirect3DDeviceImpl object at %p\n", This, object);
870
871 /* This is for apps which create a non-flip, non-d3d primary surface
872 * and an offscreen D3DDEVICE surface, then render to the offscreen surface
873 * and do a Blt from the offscreen to the primary surface.
874 *
875 * Set the offscreen D3DDDEVICE surface(=target) as the back buffer,
876 * and the primary surface(=This->d3d_target) as the front buffer.
877 *
878 * This way the app will render to the D3DDEVICE surface and WineD3D
879 * will catch the Blt was Back Buffer -> Front buffer blt and perform
880 * a flip instead. This way we don't have to deal with a mixed GL / GDI
881 * environment.
882 *
883 * This should be checked against windowed apps. The only app tested with
884 * this is moto racer 2 during the loading screen.
885 */
886 TRACE("Isrendertarget: %s, d3d_target=%p\n", target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE ? "true" : "false", This->d3d_target);
887 if(!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) &&
888 (This->d3d_target != target))
889 {
890 WINED3DVIEWPORT vp;
891 TRACE("(%p) Using %p as front buffer, %p as back buffer\n", This, This->d3d_target, target);
892 hr = IWineD3DDevice_SetFrontBackBuffers(This->wineD3DDevice,
893 This->d3d_target->WineD3DSurface,
894 target->WineD3DSurface);
895 if(hr != D3D_OK)
896 ERR("(%p) Error %08x setting the front and back buffer\n", This, hr);
897
898 /* Render to the back buffer */