d3d9: Partially implement IDirect3D9Ex::CreateDeviceEx().
[wine] / dlls / ddraw / material.c
1 /* Direct3D Material
2  * Copyright (c) 2002 Lionel ULMER
3  * Copyright (c) 2006 Stefan DÖSINGER
4  *
5  * This file contains the implementation of Direct3DMaterial.
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
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include "ddraw_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
28
29 static void dump_material(const D3DMATERIAL *mat)
30 {
31     TRACE("  dwSize : %d\n", mat->dwSize);
32 }
33
34 static inline IDirect3DMaterialImpl *material_from_material1(IDirect3DMaterial *iface)
35 {
36     return (IDirect3DMaterialImpl *)((char*)iface - FIELD_OFFSET(IDirect3DMaterialImpl, IDirect3DMaterial_vtbl));
37 }
38
39 static inline IDirect3DMaterialImpl *material_from_material2(IDirect3DMaterial2 *iface)
40 {
41     return (IDirect3DMaterialImpl *)((char*)iface - FIELD_OFFSET(IDirect3DMaterialImpl, IDirect3DMaterial2_vtbl));
42 }
43
44 /*****************************************************************************
45  * IUnknown Methods.
46  *****************************************************************************/
47
48 /*****************************************************************************
49  * IDirect3DMaterial3::QueryInterface
50  *
51  * QueryInterface for IDirect3DMaterial. Can query all IDirect3DMaterial
52  * versions.
53  *
54  * Params:
55  *  riid: Interface id queried for
56  *  obj: Address to pass the interface pointer back
57  *
58  * Returns:
59  *  S_OK on success
60  *  E_NOINTERFACE if the requested interface wasn't found
61  *
62  *****************************************************************************/
63 static HRESULT WINAPI
64 IDirect3DMaterialImpl_QueryInterface(IDirect3DMaterial3 *iface,
65                                      REFIID riid,
66                                      LPVOID* obp)
67 {
68     IDirect3DMaterialImpl *This = (IDirect3DMaterialImpl *)iface;
69
70     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
71
72     *obp = NULL;
73
74     if ( IsEqualGUID( &IID_IUnknown,  riid ) ) {
75         IUnknown_AddRef(iface);
76         *obp = iface;
77         TRACE("  Creating IUnknown interface at %p.\n", *obp);
78         return S_OK;
79     }
80     if ( IsEqualGUID( &IID_IDirect3DMaterial, riid ) ) {
81         IDirect3DMaterial_AddRef((IDirect3DMaterial *)&This->IDirect3DMaterial_vtbl);
82         *obp = &This->IDirect3DMaterial_vtbl;
83         TRACE("  Creating IDirect3DMaterial interface %p\n", *obp);
84         return S_OK;
85     }
86     if ( IsEqualGUID( &IID_IDirect3DMaterial2, riid ) ) {
87         IDirect3DMaterial_AddRef((IDirect3DMaterial2 *)&This->IDirect3DMaterial2_vtbl);
88         *obp = &This->IDirect3DMaterial2_vtbl;
89         TRACE("  Creating IDirect3DMaterial2 interface %p\n", *obp);
90         return S_OK;
91     }
92     if ( IsEqualGUID( &IID_IDirect3DMaterial3, riid ) ) {
93         IDirect3DMaterial3_AddRef((IDirect3DMaterial3 *)This);
94         *obp = This;
95         TRACE("  Creating IDirect3DMaterial3 interface %p\n", *obp);
96         return S_OK;
97     }
98     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
99     return E_NOINTERFACE;
100 }
101
102 /*****************************************************************************
103  * IDirect3DMaterial3::AddRef
104  *
105  * Increases the refcount.
106  *
107  * Returns:
108  *  The new refcount
109  *
110  *****************************************************************************/
111 static ULONG WINAPI
112 IDirect3DMaterialImpl_AddRef(IDirect3DMaterial3 *iface)
113 {
114     IDirect3DMaterialImpl *This = (IDirect3DMaterialImpl *)iface;
115     ULONG ref = InterlockedIncrement(&This->ref);
116
117     TRACE("%p increasing refcount to %u.\n", This, ref);
118
119     return ref;
120 }
121
122 /*****************************************************************************
123  * IDirect3DMaterial3::Release
124  *
125  * Reduces the refcount by one. If the refcount falls to 0, the object
126  * is destroyed
127  *
128  * Returns:
129  *  The new refcount
130  *
131  *****************************************************************************/
132 static ULONG WINAPI
133 IDirect3DMaterialImpl_Release(IDirect3DMaterial3 *iface)
134 {
135     IDirect3DMaterialImpl *This = (IDirect3DMaterialImpl *)iface;
136     ULONG ref = InterlockedDecrement(&This->ref);
137
138     TRACE("%p decreasing refcount to %u.\n", This, ref);
139
140     if (!ref)
141     {
142         if(This->Handle)
143         {
144             EnterCriticalSection(&ddraw_cs);
145             ddraw_free_handle(&This->ddraw->d3ddevice->handle_table, This->Handle - 1, DDRAW_HANDLE_MATERIAL);
146             LeaveCriticalSection(&ddraw_cs);
147         }
148
149         HeapFree(GetProcessHeap(), 0, This);
150         return 0;
151     }
152     return ref;
153 }
154
155 /*****************************************************************************
156  * IDirect3DMaterial Methods
157  *****************************************************************************/
158
159 /*****************************************************************************
160  * IDirect3DMaterial::Initialize
161  *
162  * A no-op initialization
163  *
164  * Params:
165  *  Direct3D: Pointer to a Direct3D interface
166  *
167  * Returns:
168  *  D3D_OK
169  *
170  *****************************************************************************/
171 static HRESULT WINAPI
172 IDirect3DMaterialImpl_Initialize(IDirect3DMaterial *iface,
173                                   IDirect3D *Direct3D)
174 {
175     TRACE("iface %p, d3d %p.\n", iface, Direct3D);
176
177     return D3D_OK;
178 }
179
180 /*****************************************************************************
181  * IDirect3DMaterial::Reserve
182  *
183  * DirectX 5 sdk: "The IDirect3DMaterial2::Reserve method is not implemented"
184  * Odd. They seem to have mixed their interfaces.
185  *
186  * Returns:
187  *  DDERR_UNSUPPORTED
188  *
189  *****************************************************************************/
190 static HRESULT WINAPI
191 IDirect3DMaterialImpl_Reserve(IDirect3DMaterial *iface)
192 {
193     TRACE("iface %p.\n", iface);
194
195     return DDERR_UNSUPPORTED;
196 }
197
198 /*****************************************************************************
199  * IDirect3DMaterial::Unreserve
200  *
201  * Not supported too
202  *
203  * Returns:
204  *  DDERR_UNSUPPORTED
205  *
206  *****************************************************************************/
207 static HRESULT WINAPI
208 IDirect3DMaterialImpl_Unreserve(IDirect3DMaterial *iface)
209 {
210     TRACE("iface %p.\n", iface);
211
212     return DDERR_UNSUPPORTED;
213 }
214
215 /*****************************************************************************
216  * IDirect3DMaterial3::SetMaterial
217  *
218  * Sets the material description
219  *
220  * Params:
221  *  Mat: Material to set
222  *
223  * Returns:
224  *  D3D_OK on success
225  *  DDERR_INVALIDPARAMS if Mat is NULL
226  *
227  *****************************************************************************/
228 static HRESULT WINAPI
229 IDirect3DMaterialImpl_SetMaterial(IDirect3DMaterial3 *iface,
230                                   D3DMATERIAL *lpMat)
231 {
232     IDirect3DMaterialImpl *This = (IDirect3DMaterialImpl *)iface;
233
234     TRACE("iface %p, material %p.\n", iface, lpMat);
235     if (TRACE_ON(ddraw))
236         dump_material(lpMat);
237
238     /* Stores the material */
239     EnterCriticalSection(&ddraw_cs);
240     memset(&This->mat, 0, sizeof(This->mat));
241     memcpy(&This->mat, lpMat, lpMat->dwSize);
242     LeaveCriticalSection(&ddraw_cs);
243
244     return DD_OK;
245 }
246
247 /*****************************************************************************
248  * IDirect3DMaterial3::GetMaterial
249  *
250  * Returns the material assigned to this interface
251  *
252  * Params:
253  *  Mat: Pointer to a D3DMATERIAL structure to store the material description
254  *
255  * Returns:
256  *  D3D_OK on success
257  *  DDERR_INVALIDPARAMS if Mat is NULL
258  *
259  *****************************************************************************/
260 static HRESULT WINAPI
261 IDirect3DMaterialImpl_GetMaterial(IDirect3DMaterial3 *iface,
262                                   D3DMATERIAL *lpMat)
263 {
264     IDirect3DMaterialImpl *This = (IDirect3DMaterialImpl *)iface;
265     DWORD dwSize;
266
267     TRACE("iface %p, material %p.\n", iface, lpMat);
268     if (TRACE_ON(ddraw))
269     {
270         TRACE("  Returning material : ");
271         dump_material(&This->mat);
272     }
273
274     /* Copies the material structure */
275     EnterCriticalSection(&ddraw_cs);
276     dwSize = lpMat->dwSize;
277     memcpy(lpMat, &This->mat, dwSize);
278     LeaveCriticalSection(&ddraw_cs);
279
280     return DD_OK;
281 }
282
283 /*****************************************************************************
284  * IDirect3DMaterial3::GetHandle
285  *
286  * Returns a handle for the material interface. The handle is simply a
287  * pointer to the material implementation
288  *
289  * Params:
290  *  Direct3DDevice3: The device this handle is assigned to
291  *  Handle: Address to write the handle to
292  *
293  * Returns:
294  *  D3D_OK on success
295  *  DDERR_INVALIDPARAMS if Handle is NULL
296  *
297  *****************************************************************************/
298 static HRESULT WINAPI
299 IDirect3DMaterialImpl_GetHandle(IDirect3DMaterial3 *iface,
300                                 IDirect3DDevice3 *lpDirect3DDevice3,
301                                 D3DMATERIALHANDLE *lpHandle)
302 {
303     IDirect3DMaterialImpl *This = (IDirect3DMaterialImpl *)iface;
304     IDirect3DDeviceImpl *device = device_from_device3(lpDirect3DDevice3);
305
306     TRACE("iface %p, device %p, handle %p.\n", iface, lpDirect3DDevice3, lpHandle);
307
308     EnterCriticalSection(&ddraw_cs);
309     This->active_device = device;
310     if(!This->Handle)
311     {
312         DWORD h = ddraw_allocate_handle(&device->handle_table, This, DDRAW_HANDLE_MATERIAL);
313         if (h == DDRAW_INVALID_HANDLE)
314         {
315             ERR("Failed to allocate a material handle.\n");
316             LeaveCriticalSection(&ddraw_cs);
317             return DDERR_INVALIDPARAMS;   /* Unchecked */
318         }
319
320         This->Handle = h + 1;
321     }
322     *lpHandle = This->Handle;
323     TRACE(" returning handle %08x.\n", *lpHandle);
324     LeaveCriticalSection(&ddraw_cs);
325
326     return D3D_OK;
327 }
328
329 static HRESULT WINAPI Thunk_IDirect3DMaterialImpl_2_GetHandle(IDirect3DMaterial2 *iface,
330         IDirect3DDevice2 *lpDirect3DDevice2, D3DMATERIALHANDLE *lpHandle)
331 {
332     TRACE("iface %p, device %p, handle %p.\n", iface, lpDirect3DDevice2, lpHandle);
333
334     return IDirect3DMaterial3_GetHandle((IDirect3DMaterial3 *)material_from_material2(iface), lpDirect3DDevice2 ?
335             (IDirect3DDevice3 *)&device_from_device2(lpDirect3DDevice2)->IDirect3DDevice3_vtbl : NULL, lpHandle);
336 }
337
338 static HRESULT WINAPI Thunk_IDirect3DMaterialImpl_1_GetHandle(IDirect3DMaterial *iface,
339         IDirect3DDevice *lpDirect3DDevice, D3DMATERIALHANDLE *lpHandle)
340 {
341     TRACE("iface %p, device %p, handle %p.\n", iface, lpDirect3DDevice, lpHandle);
342
343     return IDirect3DMaterial3_GetHandle((IDirect3DMaterial3 *)material_from_material1(iface), lpDirect3DDevice ?
344             (IDirect3DDevice3 *)&device_from_device1(lpDirect3DDevice)->IDirect3DDevice3_vtbl : NULL, lpHandle);
345 }
346
347 static HRESULT WINAPI
348 Thunk_IDirect3DMaterialImpl_2_QueryInterface(LPDIRECT3DMATERIAL2 iface,
349                                              REFIID riid,
350                                              LPVOID* obp)
351 {
352     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
353
354     return IDirect3DMaterial3_QueryInterface((IDirect3DMaterial3 *)material_from_material2(iface), riid, obp);
355 }
356
357 static HRESULT WINAPI
358 Thunk_IDirect3DMaterialImpl_1_QueryInterface(LPDIRECT3DMATERIAL iface,
359                                              REFIID riid,
360                                              LPVOID* obp)
361 {
362     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
363
364     return IDirect3DMaterial3_QueryInterface((IDirect3DMaterial3 *)material_from_material1(iface), riid, obp);
365 }
366
367 static ULONG WINAPI
368 Thunk_IDirect3DMaterialImpl_2_AddRef(LPDIRECT3DMATERIAL2 iface)
369 {
370     TRACE("iface %p.\n", iface);
371
372     return IDirect3DMaterial3_AddRef((IDirect3DMaterial3 *)material_from_material2(iface));
373 }
374
375 static ULONG WINAPI
376 Thunk_IDirect3DMaterialImpl_1_AddRef(LPDIRECT3DMATERIAL iface)
377 {
378     TRACE("iface %p.\n", iface);
379
380     return IDirect3DMaterial3_AddRef((IDirect3DMaterial3 *)material_from_material1(iface));
381 }
382
383 static ULONG WINAPI
384 Thunk_IDirect3DMaterialImpl_2_Release(LPDIRECT3DMATERIAL2 iface)
385 {
386     TRACE("iface %p.\n", iface);
387
388     return IDirect3DMaterial3_Release((IDirect3DMaterial3 *)material_from_material2(iface));
389 }
390
391 static ULONG WINAPI
392 Thunk_IDirect3DMaterialImpl_1_Release(LPDIRECT3DMATERIAL iface)
393 {
394     TRACE("iface %p.\n", iface);
395
396     return IDirect3DMaterial3_Release((IDirect3DMaterial3 *)material_from_material1(iface));
397 }
398
399 static HRESULT WINAPI
400 Thunk_IDirect3DMaterialImpl_2_SetMaterial(LPDIRECT3DMATERIAL2 iface,
401                                           LPD3DMATERIAL lpMat)
402 {
403     TRACE("iface %p, material %p.\n", iface, lpMat);
404
405     return IDirect3DMaterial3_SetMaterial((IDirect3DMaterial3 *)material_from_material2(iface), lpMat);
406 }
407
408 static HRESULT WINAPI
409 Thunk_IDirect3DMaterialImpl_1_SetMaterial(LPDIRECT3DMATERIAL iface,
410                                           LPD3DMATERIAL lpMat)
411 {
412     TRACE("iface %p, material %p.\n", iface, lpMat);
413
414     return IDirect3DMaterial3_SetMaterial((IDirect3DMaterial3 *)material_from_material1(iface), lpMat);
415 }
416
417 static HRESULT WINAPI
418 Thunk_IDirect3DMaterialImpl_2_GetMaterial(LPDIRECT3DMATERIAL2 iface,
419                                           LPD3DMATERIAL lpMat)
420 {
421     TRACE("iface %p, material %p.\n", iface, lpMat);
422
423     return IDirect3DMaterial3_GetMaterial((IDirect3DMaterial3 *)material_from_material2(iface), lpMat);
424 }
425
426 static HRESULT WINAPI
427 Thunk_IDirect3DMaterialImpl_1_GetMaterial(LPDIRECT3DMATERIAL iface,
428                                           LPD3DMATERIAL lpMat)
429 {
430     TRACE("iface %p, material %p.\n", iface, lpMat);
431
432     return IDirect3DMaterial3_GetMaterial((IDirect3DMaterial3 *)material_from_material1(iface), lpMat);
433 }
434
435
436 /*****************************************************************************
437  * material_activate
438  *
439  * Uses IDirect3DDevice7::SetMaterial to activate the material
440  *
441  * Params:
442  *  This: Pointer to the material implementation to activate
443  *
444  *****************************************************************************/
445 void material_activate(IDirect3DMaterialImpl* This)
446 {
447     D3DMATERIAL7 d3d7mat;
448
449     TRACE("Activating material %p\n", This);
450     d3d7mat.u.diffuse = This->mat.u.diffuse;
451     d3d7mat.u1.ambient = This->mat.u1.ambient;
452     d3d7mat.u2.specular = This->mat.u2.specular;
453     d3d7mat.u3.emissive = This->mat.u3.emissive;
454     d3d7mat.u4.power = This->mat.u4.power;
455
456     IDirect3DDevice7_SetMaterial((IDirect3DDevice7 *)This->active_device, &d3d7mat);
457 }
458
459 static const struct IDirect3DMaterial3Vtbl d3d_material3_vtbl =
460 {
461     /*** IUnknown Methods ***/
462     IDirect3DMaterialImpl_QueryInterface,
463     IDirect3DMaterialImpl_AddRef,
464     IDirect3DMaterialImpl_Release,
465     /*** IDirect3DMaterial3 Methods ***/
466     IDirect3DMaterialImpl_SetMaterial,
467     IDirect3DMaterialImpl_GetMaterial,
468     IDirect3DMaterialImpl_GetHandle,
469 };
470
471 static const struct IDirect3DMaterial2Vtbl d3d_material2_vtbl =
472 {
473     /*** IUnknown Methods ***/
474     Thunk_IDirect3DMaterialImpl_2_QueryInterface,
475     Thunk_IDirect3DMaterialImpl_2_AddRef,
476     Thunk_IDirect3DMaterialImpl_2_Release,
477     /*** IDirect3DMaterial2 Methods ***/
478     Thunk_IDirect3DMaterialImpl_2_SetMaterial,
479     Thunk_IDirect3DMaterialImpl_2_GetMaterial,
480     Thunk_IDirect3DMaterialImpl_2_GetHandle,
481 };
482
483 static const struct IDirect3DMaterialVtbl d3d_material1_vtbl =
484 {
485     /*** IUnknown Methods ***/
486     Thunk_IDirect3DMaterialImpl_1_QueryInterface,
487     Thunk_IDirect3DMaterialImpl_1_AddRef,
488     Thunk_IDirect3DMaterialImpl_1_Release,
489     /*** IDirect3DMaterial1 Methods ***/
490     IDirect3DMaterialImpl_Initialize,
491     Thunk_IDirect3DMaterialImpl_1_SetMaterial,
492     Thunk_IDirect3DMaterialImpl_1_GetMaterial,
493     Thunk_IDirect3DMaterialImpl_1_GetHandle,
494     IDirect3DMaterialImpl_Reserve,
495     IDirect3DMaterialImpl_Unreserve
496 };
497
498 void d3d_material_init(IDirect3DMaterialImpl *material, IDirectDrawImpl *ddraw)
499 {
500     material->lpVtbl = &d3d_material3_vtbl;
501     material->IDirect3DMaterial2_vtbl = &d3d_material2_vtbl;
502     material->IDirect3DMaterial_vtbl = &d3d_material1_vtbl;
503     material->ref = 1;
504     material->ddraw = ddraw;
505 }