ddraw: Use real flips.
[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 *lpDirect3DDevice3, D3DMATERIALHANDLE *lpHandle)
299 {
300     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial3(iface);
301     IDirect3DDeviceImpl *device = device_from_device3(lpDirect3DDevice3);
302
303     TRACE("iface %p, device %p, handle %p.\n", iface, lpDirect3DDevice3, lpHandle);
304
305     EnterCriticalSection(&ddraw_cs);
306     This->active_device = device;
307     if(!This->Handle)
308     {
309         DWORD h = ddraw_allocate_handle(&device->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     *lpHandle = This->Handle;
320     TRACE(" returning handle %08x.\n", *lpHandle);
321     LeaveCriticalSection(&ddraw_cs);
322
323     return D3D_OK;
324 }
325
326 static HRESULT WINAPI IDirect3DMaterialImpl_2_GetHandle(IDirect3DMaterial2 *iface,
327         IDirect3DDevice2 *lpDirect3DDevice2, D3DMATERIALHANDLE *lpHandle)
328 {
329     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial2(iface);
330
331     TRACE("iface %p, device %p, handle %p.\n", iface, lpDirect3DDevice2, lpHandle);
332
333     return IDirect3DMaterial3_GetHandle(&This->IDirect3DMaterial3_iface, lpDirect3DDevice2 ?
334             (IDirect3DDevice3 *)&device_from_device2(lpDirect3DDevice2)->IDirect3DDevice3_vtbl : NULL, lpHandle);
335 }
336
337 static HRESULT WINAPI IDirect3DMaterialImpl_1_GetHandle(IDirect3DMaterial *iface,
338         IDirect3DDevice *lpDirect3DDevice, D3DMATERIALHANDLE *lpHandle)
339 {
340     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial(iface);
341
342     TRACE("iface %p, device %p, handle %p.\n", iface, lpDirect3DDevice, lpHandle);
343
344     return IDirect3DMaterial3_GetHandle(&This->IDirect3DMaterial3_iface, lpDirect3DDevice ?
345             (IDirect3DDevice3 *)&device_from_device1(lpDirect3DDevice)->IDirect3DDevice3_vtbl : NULL, lpHandle);
346 }
347
348 static HRESULT WINAPI IDirect3DMaterialImpl_2_QueryInterface(IDirect3DMaterial2 *iface, REFIID riid,
349         void **obp)
350 {
351     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial2(iface);
352
353     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
354
355     return IDirect3DMaterial3_QueryInterface(&This->IDirect3DMaterial3_iface, riid, obp);
356 }
357
358 static HRESULT WINAPI IDirect3DMaterialImpl_1_QueryInterface(IDirect3DMaterial *iface, REFIID riid,
359         void **obp)
360 {
361     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial(iface);
362
363     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
364
365     return IDirect3DMaterial3_QueryInterface(&This->IDirect3DMaterial3_iface, riid, obp);
366 }
367
368 static ULONG WINAPI IDirect3DMaterialImpl_2_AddRef(IDirect3DMaterial2 *iface)
369 {
370     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial2(iface);
371
372     TRACE("iface %p.\n", iface);
373
374     return IDirect3DMaterial3_AddRef(&This->IDirect3DMaterial3_iface);
375 }
376
377 static ULONG WINAPI IDirect3DMaterialImpl_1_AddRef(IDirect3DMaterial *iface)
378 {
379     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial(iface);
380
381     TRACE("iface %p.\n", iface);
382
383     return IDirect3DMaterial3_AddRef(&This->IDirect3DMaterial3_iface);
384 }
385
386 static ULONG WINAPI IDirect3DMaterialImpl_2_Release(IDirect3DMaterial2 *iface)
387 {
388     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial2(iface);
389
390     TRACE("iface %p.\n", iface);
391
392     return IDirect3DMaterial3_Release(&This->IDirect3DMaterial3_iface);
393 }
394
395 static ULONG WINAPI IDirect3DMaterialImpl_1_Release(IDirect3DMaterial *iface)
396 {
397     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial(iface);
398
399     TRACE("iface %p.\n", iface);
400
401     return IDirect3DMaterial3_Release(&This->IDirect3DMaterial3_iface);
402 }
403
404 static HRESULT WINAPI IDirect3DMaterialImpl_2_SetMaterial(IDirect3DMaterial2 *iface,
405         LPD3DMATERIAL lpMat)
406 {
407     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial2(iface);
408
409     TRACE("iface %p, material %p.\n", iface, lpMat);
410
411     return IDirect3DMaterial3_SetMaterial(&This->IDirect3DMaterial3_iface, lpMat);
412 }
413
414 static HRESULT WINAPI IDirect3DMaterialImpl_1_SetMaterial(IDirect3DMaterial *iface,
415         LPD3DMATERIAL lpMat)
416 {
417     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial(iface);
418
419     TRACE("iface %p, material %p.\n", iface, lpMat);
420
421     return IDirect3DMaterial3_SetMaterial(&This->IDirect3DMaterial3_iface, lpMat);
422 }
423
424 static HRESULT WINAPI IDirect3DMaterialImpl_2_GetMaterial(IDirect3DMaterial2 *iface,
425         LPD3DMATERIAL lpMat)
426 {
427     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial2(iface);
428
429     TRACE("iface %p, material %p.\n", iface, lpMat);
430
431     return IDirect3DMaterial3_GetMaterial(&This->IDirect3DMaterial3_iface, lpMat);
432 }
433
434 static HRESULT WINAPI IDirect3DMaterialImpl_1_GetMaterial(IDirect3DMaterial *iface,
435         LPD3DMATERIAL lpMat)
436 {
437     IDirect3DMaterialImpl *This = impl_from_IDirect3DMaterial(iface);
438
439     TRACE("iface %p, material %p.\n", iface, lpMat);
440
441     return IDirect3DMaterial3_GetMaterial(&This->IDirect3DMaterial3_iface, lpMat);
442 }
443
444
445 /*****************************************************************************
446  * material_activate
447  *
448  * Uses IDirect3DDevice7::SetMaterial to activate the material
449  *
450  * Params:
451  *  This: Pointer to the material implementation to activate
452  *
453  *****************************************************************************/
454 void material_activate(IDirect3DMaterialImpl* This)
455 {
456     D3DMATERIAL7 d3d7mat;
457
458     TRACE("Activating material %p\n", This);
459     d3d7mat.u.diffuse = This->mat.u.diffuse;
460     d3d7mat.u1.ambient = This->mat.u1.ambient;
461     d3d7mat.u2.specular = This->mat.u2.specular;
462     d3d7mat.u3.emissive = This->mat.u3.emissive;
463     d3d7mat.u4.power = This->mat.u4.power;
464
465     IDirect3DDevice7_SetMaterial((IDirect3DDevice7 *)This->active_device, &d3d7mat);
466 }
467
468 static const struct IDirect3DMaterial3Vtbl d3d_material3_vtbl =
469 {
470     /*** IUnknown Methods ***/
471     IDirect3DMaterialImpl_QueryInterface,
472     IDirect3DMaterialImpl_AddRef,
473     IDirect3DMaterialImpl_Release,
474     /*** IDirect3DMaterial3 Methods ***/
475     IDirect3DMaterialImpl_SetMaterial,
476     IDirect3DMaterialImpl_GetMaterial,
477     IDirect3DMaterialImpl_GetHandle,
478 };
479
480 static const struct IDirect3DMaterial2Vtbl d3d_material2_vtbl =
481 {
482     /*** IUnknown Methods ***/
483     IDirect3DMaterialImpl_2_QueryInterface,
484     IDirect3DMaterialImpl_2_AddRef,
485     IDirect3DMaterialImpl_2_Release,
486     /*** IDirect3DMaterial2 Methods ***/
487     IDirect3DMaterialImpl_2_SetMaterial,
488     IDirect3DMaterialImpl_2_GetMaterial,
489     IDirect3DMaterialImpl_2_GetHandle,
490 };
491
492 static const struct IDirect3DMaterialVtbl d3d_material1_vtbl =
493 {
494     /*** IUnknown Methods ***/
495     IDirect3DMaterialImpl_1_QueryInterface,
496     IDirect3DMaterialImpl_1_AddRef,
497     IDirect3DMaterialImpl_1_Release,
498     /*** IDirect3DMaterial1 Methods ***/
499     IDirect3DMaterialImpl_Initialize,
500     IDirect3DMaterialImpl_1_SetMaterial,
501     IDirect3DMaterialImpl_1_GetMaterial,
502     IDirect3DMaterialImpl_1_GetHandle,
503     IDirect3DMaterialImpl_Reserve,
504     IDirect3DMaterialImpl_Unreserve
505 };
506
507 IDirect3DMaterialImpl *d3d_material_create(IDirectDrawImpl *ddraw)
508 {
509     IDirect3DMaterialImpl *material;
510
511     material = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*material));
512     if (!material)
513         return NULL;
514
515     material->IDirect3DMaterial3_iface.lpVtbl = &d3d_material3_vtbl;
516     material->IDirect3DMaterial2_iface.lpVtbl = &d3d_material2_vtbl;
517     material->IDirect3DMaterial_iface.lpVtbl = &d3d_material1_vtbl;
518     material->ref = 1;
519     material->ddraw = ddraw;
520
521     return material;
522 }