wined3d: SetDepthStencilSurface is always called when AutoDepthStencil is enabled.
[wine] / dlls / ddraw / light.c
1 /* Direct3D Light
2  * Copyright (c) 1998 / 2002 Lionel ULMER
3  * Copyright (c) 2006        Stefan DÖSINGER
4  *
5  * This file contains the implementation of Direct3DLight.
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 #include "wine/debug.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #define COBJMACROS
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
44 WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
45
46 /*****************************************************************************
47  * IUnknown Methods.
48  *****************************************************************************/
49
50 /*****************************************************************************
51  * IDirect3DLight::QueryInterface
52  *
53  * Queries the object for different interfaces. Unimplemented for this
54  * object at the moment
55  *
56  * Params:
57  *  riid: Interface id asked for
58  *  obj: Address to return the resulting pointer at.
59  *
60  * Returns:
61  *  E_NOINTERFACE, because it's a stub
62  *****************************************************************************/
63 static HRESULT WINAPI
64 IDirect3DLightImpl_QueryInterface(IDirect3DLight *iface,
65                                   REFIID riid,
66                                   void **obp)
67 {
68     IDirect3DLightImpl *This = (IDirect3DLightImpl *)iface;
69     FIXME("(%p)->(%s,%p): stub!\n", This, debugstr_guid(riid), obp);
70     *obp = NULL;
71     return E_NOINTERFACE;
72 }
73
74 /*****************************************************************************
75  * IDirect3DLight::AddRef
76  *
77  * Increases the refcount by 1
78  *
79  * Returns:
80  *  The new refcount
81  *
82  *****************************************************************************/
83 static ULONG WINAPI
84 IDirect3DLightImpl_AddRef(IDirect3DLight *iface)
85 {
86     IDirect3DLightImpl *This = (IDirect3DLightImpl *)iface;
87     ULONG ref = InterlockedIncrement(&This->ref);
88
89     TRACE("(%p)->() incrementing from %u.\n", This, ref - 1);
90
91     return ref;
92 }
93
94 /*****************************************************************************
95  * IDirect3DLight::Release
96  *
97  * Reduces the refcount by one. If the refcount falls to 0, the object
98  * is destroyed
99  *
100  * Returns:
101  *  The new refcount
102  *
103  *****************************************************************************/
104 static ULONG WINAPI
105 IDirect3DLightImpl_Release(IDirect3DLight *iface)
106 {
107     IDirect3DLightImpl *This = (IDirect3DLightImpl *)iface;
108     ULONG ref = InterlockedDecrement(&This->ref);
109
110     TRACE("(%p)->() decrementing from %u.\n", This, ref + 1);
111
112     if (!ref) {
113         HeapFree(GetProcessHeap(), 0, This);
114         return 0;
115     }
116     return ref;
117 }
118
119 /*****************************************************************************
120  * IDirect3DLight Methods.
121  *****************************************************************************/
122
123 /*****************************************************************************
124  * IDirect3DLight::Initialize
125  *
126  * Initializes the interface. This implementation is a no-op, because
127  * initialization takes place at creation time
128  *
129  * Params:
130  *  Direct3D: Pointer to an IDirect3D interface.
131  *
132  * Returns:
133  *  D3D_OK
134  *
135  *****************************************************************************/
136 static HRESULT WINAPI
137 IDirect3DLightImpl_Initialize(IDirect3DLight *iface,
138                               IDirect3D *lpDirect3D)
139 {
140     IDirect3DLightImpl *This = (IDirect3DLightImpl *)iface;
141     IDirectDrawImpl *d3d = lpDirect3D ? ddraw_from_d3d1(lpDirect3D) : NULL;
142     TRACE("(%p)->(%p) no-op...\n", This, d3d);
143     return D3D_OK;
144 }
145
146 /*****************************************************************************
147  * IDirect3DLight::SetLight
148  *
149  * Assigns a lighting value to this object
150  *
151  * Params:
152  *  Light: Lighting parameter to set
153  *
154  * Returns:
155  *  D3D_OK on success
156  *  DDERR_INVALIDPARAMS if Light is NULL
157  *
158  *****************************************************************************/
159 static void dump_light(const D3DLIGHT2 *light)
160 {
161     TRACE("    - dwSize : %d\n", light->dwSize);
162 }
163
164 static const float zero_value[] = {
165     0.0, 0.0, 0.0, 0.0
166 };
167
168 static HRESULT WINAPI
169 IDirect3DLightImpl_SetLight(IDirect3DLight *iface,
170                             D3DLIGHT *lpLight)
171 {
172     IDirect3DLightImpl *This = (IDirect3DLightImpl *)iface;
173     LPD3DLIGHT7 light7 = &(This->light7);
174     TRACE("(%p)->(%p)\n", This, lpLight);
175     if (TRACE_ON(d3d7)) {
176         TRACE("  Light definition :\n");
177         dump_light((LPD3DLIGHT2) lpLight);
178     }
179
180     if ( (lpLight->dltType == 0) || (lpLight->dltType > D3DLIGHT_PARALLELPOINT) )
181          return DDERR_INVALIDPARAMS;
182     
183     if ( lpLight->dltType == D3DLIGHT_PARALLELPOINT )
184          FIXME("D3DLIGHT_PARALLELPOINT no supported\n");
185     
186     /* Translate D3DLIGH2 structure to D3DLIGHT7 */
187     light7->dltType        = lpLight->dltType;
188     light7->dcvDiffuse     = lpLight->dcvColor;
189     if ((((LPD3DLIGHT2)lpLight)->dwFlags & D3DLIGHT_NO_SPECULAR) != 0)      
190       light7->dcvSpecular    = lpLight->dcvColor;
191     else
192       light7->dcvSpecular    = *(const D3DCOLORVALUE*)zero_value;           
193     light7->dcvAmbient     = lpLight->dcvColor;
194     light7->dvPosition     = lpLight->dvPosition;
195     light7->dvDirection    = lpLight->dvDirection;
196     light7->dvRange        = lpLight->dvRange;
197     light7->dvFalloff      = lpLight->dvFalloff;
198     light7->dvAttenuation0 = lpLight->dvAttenuation0;
199     light7->dvAttenuation1 = lpLight->dvAttenuation1;
200     light7->dvAttenuation2 = lpLight->dvAttenuation2;
201     light7->dvTheta        = lpLight->dvTheta;
202     light7->dvPhi          = lpLight->dvPhi;
203
204     EnterCriticalSection(&ddraw_cs);
205     memcpy(&This->light, lpLight, lpLight->dwSize);
206     if ((This->light.dwFlags & D3DLIGHT_ACTIVE) != 0) {
207         This->update(This);        
208     }
209     LeaveCriticalSection(&ddraw_cs);
210     return D3D_OK;
211 }
212
213 /*****************************************************************************
214  * IDirect3DLight::GetLight
215  *
216  * Returns the parameters currently assigned to the IDirect3DLight object
217  *
218  * Params:
219  *  Light: Pointer to an D3DLIGHT structure to store the parameters
220  *
221  * Returns:
222  *  D3D_OK on success
223  *  DDERR_INVALIDPARAMS if Light is NULL
224  *****************************************************************************/
225 static HRESULT WINAPI
226 IDirect3DLightImpl_GetLight(IDirect3DLight *iface,
227                             D3DLIGHT *lpLight)
228 {
229     IDirect3DLightImpl *This = (IDirect3DLightImpl *)iface;
230     TRACE("(%p/%p)->(%p)\n", This, iface, lpLight);
231     if (TRACE_ON(d3d7)) {
232         TRACE("  Returning light definition :\n");
233         dump_light(&This->light);
234     }
235
236     EnterCriticalSection(&ddraw_cs);
237     memcpy(lpLight, &This->light, lpLight->dwSize);
238     LeaveCriticalSection(&ddraw_cs);
239
240     return DD_OK;
241 }
242
243 /*****************************************************************************
244  * light_update
245  *
246  * Updates the Direct3DDevice7 lighting parameters
247  *
248  *****************************************************************************/
249 void light_update(IDirect3DLightImpl* This)
250 {
251     IDirect3DDeviceImpl* device;
252
253     TRACE("(%p)\n", This);
254
255     if (!This->active_viewport || !This->active_viewport->active_device)
256         return;
257     device =  This->active_viewport->active_device;
258
259     IDirect3DDevice7_SetLight((IDirect3DDevice7 *)device, This->dwLightIndex, &(This->light7));
260 }
261
262 /*****************************************************************************
263  * light_activate
264  *
265  * Uses the Direct3DDevice7::LightEnable method to active the light
266  *
267  *****************************************************************************/
268 void light_activate(IDirect3DLightImpl* This)
269 {
270     IDirect3DDeviceImpl* device;
271
272     TRACE("(%p)\n", This);
273
274     if (!This->active_viewport || !This->active_viewport->active_device)
275         return;
276     device =  This->active_viewport->active_device;
277     
278     light_update(This);
279     /* If was not active, activate it */
280     if ((This->light.dwFlags & D3DLIGHT_ACTIVE) == 0) {
281         IDirect3DDevice7_LightEnable((IDirect3DDevice7 *)device, This->dwLightIndex, TRUE);
282         This->light.dwFlags |= D3DLIGHT_ACTIVE;
283     }
284 }
285
286 /*****************************************************************************
287  *
288  * light_desactivate
289  *
290  * Uses the Direct3DDevice7::LightEnable method to deactivate the light
291  *
292  *****************************************************************************/
293 void light_desactivate(IDirect3DLightImpl* This)
294 {
295     IDirect3DDeviceImpl* device;
296
297     TRACE("(%p)\n", This);
298
299     if (!This->active_viewport || !This->active_viewport->active_device)
300         return;
301     device =  This->active_viewport->active_device;
302     
303     /* If was not active, activate it */
304     if ((This->light.dwFlags & D3DLIGHT_ACTIVE) != 0) {
305         IDirect3DDevice7_LightEnable((IDirect3DDevice7 *)device, This->dwLightIndex, FALSE);
306         This->light.dwFlags &= ~D3DLIGHT_ACTIVE;
307     }
308 }
309
310 const IDirect3DLightVtbl IDirect3DLight_Vtbl =
311 {
312     /*** IUnknown Methods ***/
313     IDirect3DLightImpl_QueryInterface,
314     IDirect3DLightImpl_AddRef,
315     IDirect3DLightImpl_Release,
316     /*** IDirect3DLight Methods ***/
317     IDirect3DLightImpl_Initialize,
318     IDirect3DLightImpl_SetLight,
319     IDirect3DLightImpl_GetLight
320 };