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