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