wined3d: Call IWineD3DDeviceImpl_FindTexUnitMap() when activating the context.
[wine] / dlls / ddraw / viewport.c
1 /* Direct3D Viewport
2  * Copyright (c) 1998 Lionel ULMER
3  * Copyright (c) 2006 Stefan DÖSINGER
4  *
5  * This file contains the implementation of Direct3DViewport2.
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
47 /*****************************************************************************
48  * Helper functions
49  *****************************************************************************/
50
51 /*****************************************************************************
52  * viewport_activate
53  *
54  * activates the viewport using IDirect3DDevice7::SetViewport
55  *
56  *****************************************************************************/
57 void viewport_activate(IDirect3DViewportImpl* This) {
58     IDirect3DLightImpl* light;
59     D3DVIEWPORT7 vp;
60     
61     /* Activate all the lights associated with this context */
62     light = This->lights;
63
64     while (light != NULL) {
65         light->activate(light);
66         light = light->next;
67     }
68
69     /* And copy the values in the structure used by the device */
70     if (This->use_vp2) {
71         vp.dwX = This->viewports.vp2.dwX;
72         vp.dwY = This->viewports.vp2.dwY;
73         vp.dwHeight = This->viewports.vp2.dwHeight;
74         vp.dwWidth = This->viewports.vp2.dwWidth;
75         vp.dvMinZ = This->viewports.vp2.dvMinZ;
76         vp.dvMaxZ = This->viewports.vp2.dvMaxZ;
77     } else {
78         vp.dwX = This->viewports.vp1.dwX;
79         vp.dwY = This->viewports.vp1.dwY;
80         vp.dwHeight = This->viewports.vp1.dwHeight;
81         vp.dwWidth = This->viewports.vp1.dwWidth;
82         vp.dvMinZ = This->viewports.vp1.dvMinZ;
83         vp.dvMaxZ = This->viewports.vp1.dvMaxZ;
84     }
85     
86     /* And also set the viewport */
87     IDirect3DDevice7_SetViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice7), &vp);
88 }
89
90 /*****************************************************************************
91  * _dump_D3DVIEWPORT, _dump_D3DVIEWPORT2
92  *
93  * Writes viewport information to TRACE
94  *
95  *****************************************************************************/
96 static void _dump_D3DVIEWPORT(const D3DVIEWPORT *lpvp)
97 {
98     TRACE("    - dwSize = %d   dwX = %d   dwY = %d\n",
99           lpvp->dwSize, lpvp->dwX, lpvp->dwY);
100     TRACE("    - dwWidth = %d   dwHeight = %d\n",
101           lpvp->dwWidth, lpvp->dwHeight);
102     TRACE("    - dvScaleX = %f   dvScaleY = %f\n",
103           lpvp->dvScaleX, lpvp->dvScaleY);
104     TRACE("    - dvMaxX = %f   dvMaxY = %f\n",
105           lpvp->dvMaxX, lpvp->dvMaxY);
106     TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
107           lpvp->dvMinZ, lpvp->dvMaxZ);
108 }
109
110 static void _dump_D3DVIEWPORT2(const D3DVIEWPORT2 *lpvp)
111 {
112     TRACE("    - dwSize = %d   dwX = %d   dwY = %d\n",
113           lpvp->dwSize, lpvp->dwX, lpvp->dwY);
114     TRACE("    - dwWidth = %d   dwHeight = %d\n",
115           lpvp->dwWidth, lpvp->dwHeight);
116     TRACE("    - dvClipX = %f   dvClipY = %f\n",
117           lpvp->dvClipX, lpvp->dvClipY);
118     TRACE("    - dvClipWidth = %f   dvClipHeight = %f\n",
119           lpvp->dvClipWidth, lpvp->dvClipHeight);
120     TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
121           lpvp->dvMinZ, lpvp->dvMaxZ);
122 }
123
124 /*****************************************************************************
125  * IUnknown Methods.
126  *****************************************************************************/
127
128 /*****************************************************************************
129  * IDirect3DViewport3::QueryInterface
130  *
131  * A normal QueryInterface. Can query all interface versions and the
132  * IUnknown interface. The VTables of the different versions
133  * are equal
134  *
135  * Params:
136  *  refiid: Interface id queried for
137  *  obj: Address to write the interface pointer to
138  *
139  * Returns:
140  *  S_OK on success.
141  *  E_NOINTERFACE if the requested interface wasn't found
142  *
143  *****************************************************************************/
144 static HRESULT WINAPI
145 IDirect3DViewportImpl_QueryInterface(IDirect3DViewport3 *iface,
146                                      REFIID riid,
147                                      void **obp)
148 {
149     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
150     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), obp);
151
152     *obp = NULL;
153
154     if ( IsEqualGUID(&IID_IUnknown,  riid) ||
155          IsEqualGUID(&IID_IDirect3DViewport, riid) ||
156          IsEqualGUID(&IID_IDirect3DViewport2, riid) ||
157          IsEqualGUID(&IID_IDirect3DViewport3, riid) ) {
158         IDirect3DViewport3_AddRef(ICOM_INTERFACE(This, IDirect3DViewport3));
159         *obp = ICOM_INTERFACE(This, IDirect3DViewport3);
160         TRACE("  Creating IDirect3DViewport1/2/3 interface %p\n", *obp);
161         return S_OK;
162     }
163     FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
164     return E_NOINTERFACE;
165 }
166
167 /*****************************************************************************
168  * IDirect3DViewport3::AddRef
169  *
170  * Increases the refcount.
171  *
172  * Returns:
173  *  The new refcount
174  *
175  *****************************************************************************/
176 static ULONG WINAPI
177 IDirect3DViewportImpl_AddRef(IDirect3DViewport3 *iface)
178 {
179     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
180     ULONG ref = InterlockedIncrement(&This->ref);
181
182     TRACE("(%p)->() incrementing from %u.\n", This, ref - 1);
183
184     return ref;
185 }
186
187 /*****************************************************************************
188  * IDirect3DViewport3::Release
189  *
190  * Reduces the refcount. If it falls to 0, the interface is released
191  *
192  * Returns:
193  *  The new refcount
194  *
195  *****************************************************************************/
196 static ULONG WINAPI
197 IDirect3DViewportImpl_Release(IDirect3DViewport3 *iface)
198 {
199     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
200     ULONG ref = InterlockedDecrement(&This->ref);
201
202     TRACE("(%p)->() decrementing from %u.\n", This, ref + 1);
203
204     if (!ref) {
205         HeapFree(GetProcessHeap(), 0, This);
206         return 0;
207     }
208     return ref;
209 }
210
211 /*****************************************************************************
212  * IDirect3DViewport Methods.
213  *****************************************************************************/
214
215 /*****************************************************************************
216  * IDirect3DViewport3::Initialize
217  *
218  * No-op initialization.
219  *
220  * Params:
221  *  Direct3D: The direct3D device this viewport is assigned to
222  *
223  * Returns:
224  *  DDERR_ALREADYINITIALIZED
225  *
226  *****************************************************************************/
227 static HRESULT WINAPI
228 IDirect3DViewportImpl_Initialize(IDirect3DViewport3 *iface,
229                                  IDirect3D *Direct3D)
230 {
231     TRACE("(%p)->(%p) no-op...\n", iface, Direct3D);
232     return DDERR_ALREADYINITIALIZED;
233 }
234
235 /*****************************************************************************
236  * IDirect3DViewport3::GetViewport
237  *
238  * Returns the viewport data assigned to this viewport interface
239  *
240  * Params:
241  *  Data: Address to store the data
242  *
243  * Returns:
244  *  D3D_OK on success
245  *  DDERR_INVALIDPARAMS if Data is NULL
246  *
247  *****************************************************************************/
248 static HRESULT WINAPI
249 IDirect3DViewportImpl_GetViewport(IDirect3DViewport3 *iface,
250                                   D3DVIEWPORT *lpData)
251 {
252     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
253     DWORD dwSize;
254     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
255
256     EnterCriticalSection(&ddraw_cs);
257     if (This->use_vp2 != 0) {
258         ERR("  Requesting to get a D3DVIEWPORT struct where a D3DVIEWPORT2 was set !\n");
259         LeaveCriticalSection(&ddraw_cs);
260         return DDERR_INVALIDPARAMS;
261     }
262     dwSize = lpData->dwSize;
263     memset(lpData, 0, dwSize);
264     memcpy(lpData, &(This->viewports.vp1), dwSize);
265
266     if (TRACE_ON(d3d7)) {
267         TRACE("  returning D3DVIEWPORT :\n");
268         _dump_D3DVIEWPORT(lpData);
269     }
270     LeaveCriticalSection(&ddraw_cs);
271
272     return DD_OK;
273 }
274
275 /*****************************************************************************
276  * IDirect3DViewport3::SetViewport
277  *
278  * Sets the viewport information for this interface
279  *
280  * Params:
281  *  lpData: Viewport to set
282  *
283  * Returns:
284  *  D3D_OK on success
285  *  DDERR_INVALIDPARAMS if Data is NULL
286  *
287  *****************************************************************************/
288 static HRESULT WINAPI
289 IDirect3DViewportImpl_SetViewport(IDirect3DViewport3 *iface,
290                                   D3DVIEWPORT *lpData)
291 {
292     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
293     LPDIRECT3DVIEWPORT3 current_viewport;
294     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
295
296     if (TRACE_ON(d3d7)) {
297         TRACE("  getting D3DVIEWPORT :\n");
298         _dump_D3DVIEWPORT(lpData);
299     }
300
301     EnterCriticalSection(&ddraw_cs);
302     This->use_vp2 = 0;
303     memset(&(This->viewports.vp1), 0, sizeof(This->viewports.vp1));
304     memcpy(&(This->viewports.vp1), lpData, lpData->dwSize);
305
306     /* Tests on two games show that these values are never used properly so override
307        them with proper ones :-)
308     */
309     This->viewports.vp1.dvMinZ = 0.0;
310     This->viewports.vp1.dvMaxZ = 1.0;
311
312     if (This->active_device) {
313       IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), &current_viewport);
314       if (ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport) == This)
315           This->activate(This);
316       if(current_viewport) IDirect3DViewport3_Release(current_viewport);
317     }
318     LeaveCriticalSection(&ddraw_cs);
319
320     return DD_OK;
321 }
322
323 /*****************************************************************************
324  * IDirect3DViewport3::TransformVertices
325  *
326  * Transforms vertices by the transformation matrix.
327  *
328  * Params:
329  *  dwVertexCount: The number of vertices to be transformed
330  *  lpData: Pointer to the vertex data
331  *  dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED
332  *  lpOffScreen: Is set to nonzero if all vertices are off-screen
333  *
334  * Returns:
335  *  D3D_OK because it's a stub
336  *
337  *****************************************************************************/
338 static HRESULT WINAPI
339 IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
340                                         DWORD dwVertexCount,
341                                         D3DTRANSFORMDATA *lpData,
342                                         DWORD dwFlags,
343                                         DWORD *lpOffScreen)
344 {
345     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
346     FIXME("(%p)->(%08x,%p,%08x,%p): stub!\n", This, dwVertexCount, lpData, dwFlags, lpOffScreen);
347     if (lpOffScreen)
348         *lpOffScreen = 0;
349     return DD_OK;
350 }
351
352 /*****************************************************************************
353  * IDirect3DViewport3::LightElements
354  *
355  * The DirectX 5.0 sdk says that it's not implemented
356  *
357  * Params:
358  *  ?
359  *
360  * Returns:
361  *  DDERR_UNSUPPORTED
362  *
363  *****************************************************************************/
364 static HRESULT WINAPI
365 IDirect3DViewportImpl_LightElements(IDirect3DViewport3 *iface,
366                                     DWORD dwElementCount,
367                                     LPD3DLIGHTDATA lpData)
368 {
369     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
370     TRACE("(%p)->(%08x,%p): Unimplemented!\n", This, dwElementCount, lpData);
371     return DDERR_UNSUPPORTED;
372 }
373
374 /*****************************************************************************
375  * IDirect3DViewport3::SetBackground
376  *
377  * Sets tje background material
378  *
379  * Params:
380  *  hMat: Handle from a IDirect3DMaterial interface
381  *
382  * Returns:
383  *  D3D_OK on success
384  *
385  *****************************************************************************/
386 static HRESULT WINAPI
387 IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface,
388                                     D3DMATERIALHANDLE hMat)
389 {
390     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
391     TRACE("(%p)->(%d)\n", This, (DWORD) hMat);
392
393     EnterCriticalSection(&ddraw_cs);
394     if(hMat && hMat > This->ddraw->d3ddevice->numHandles)
395     {
396         WARN("Specified Handle %d out of range\n", hMat);
397         LeaveCriticalSection(&ddraw_cs);
398         return DDERR_INVALIDPARAMS;
399     }
400     else if(hMat && This->ddraw->d3ddevice->Handles[hMat - 1].type != DDrawHandle_Material)
401     {
402         WARN("Handle %d is not a material handle\n", hMat);
403         LeaveCriticalSection(&ddraw_cs);
404         return DDERR_INVALIDPARAMS;
405     }
406
407     if(hMat)
408     {
409         This->background = (IDirect3DMaterialImpl *) This->ddraw->d3ddevice->Handles[hMat - 1].ptr;
410         TRACE(" setting background color : %f %f %f %f\n",
411               This->background->mat.u.diffuse.u1.r,
412               This->background->mat.u.diffuse.u2.g,
413               This->background->mat.u.diffuse.u3.b,
414               This->background->mat.u.diffuse.u4.a);
415     }
416     else
417     {
418         This->background = NULL;
419         TRACE("Setting background to NULL\n");
420     }
421
422     LeaveCriticalSection(&ddraw_cs);
423     return D3D_OK;
424 }
425
426 /*****************************************************************************
427  * IDirect3DViewport3::GetBackground
428  *
429  * Returns the material handle assigned to the background of the viewport
430  *
431  * Params:
432  *  lphMat: Address to store the handle
433  *  lpValid: is set to FALSE if no background is set, TRUE if one is set
434  *
435  * Returns:
436  *  D3D_OK
437  *
438  *****************************************************************************/
439 static HRESULT WINAPI
440 IDirect3DViewportImpl_GetBackground(IDirect3DViewport3 *iface,
441                                     D3DMATERIALHANDLE *lphMat,
442                                     BOOL *lpValid)
443 {
444     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
445     TRACE("(%p)->(%p,%p)\n", This, lphMat, lpValid);
446
447     EnterCriticalSection(&ddraw_cs);
448     if(lpValid)
449     {
450         *lpValid = This->background != NULL;
451     }
452     if(lphMat)
453     {
454         if(This->background)
455         {
456             *lphMat = This->background->Handle;
457         }
458         else
459         {
460             *lphMat = 0;
461         }
462     }
463     LeaveCriticalSection(&ddraw_cs);
464
465     return D3D_OK;
466 }
467
468 /*****************************************************************************
469  * IDirect3DViewport3::SetBackgroundDepth
470  *
471  * Sets a surface that represents the background depth. It's contents are
472  * used to set the depth buffer in IDirect3DViewport3::Clear
473  *
474  * Params:
475  *  lpDDSurface: Surface to set
476  *
477  * Returns: D3D_OK, because it's a stub
478  *
479  *****************************************************************************/
480 static HRESULT WINAPI
481 IDirect3DViewportImpl_SetBackgroundDepth(IDirect3DViewport3 *iface,
482                                          IDirectDrawSurface *lpDDSurface)
483 {
484     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
485     FIXME("(%p)->(%p): stub!\n", This, lpDDSurface);
486     return D3D_OK;
487 }
488
489 /*****************************************************************************
490  * IDirect3DViewport3::GetBackgroundDepth
491  *
492  * Returns the surface that represents the depth field
493  *
494  * Params:
495  *  lplpDDSurface: Address to store the interface pointer
496  *  lpValid: Set to TRUE if a depth is asigned, FALSE otherwise
497  *
498  * Returns:
499  *  D3D_OK, because it's a stub
500  *  (DDERR_INVALIDPARAMS if DDSurface of Valid is NULL)
501  *
502  *****************************************************************************/
503 static HRESULT WINAPI
504 IDirect3DViewportImpl_GetBackgroundDepth(IDirect3DViewport3 *iface,
505                                          IDirectDrawSurface **lplpDDSurface,
506                                          LPBOOL lpValid)
507 {
508     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
509     FIXME("(%p)->(%p,%p): stub!\n", This, lplpDDSurface, lpValid);
510     return DD_OK;
511 }
512
513 /*****************************************************************************
514  * IDirect3DViewport3::Clear
515  *
516  * Clears the render target and / or the z buffer
517  *
518  * Params:
519  *  dwCount: The amount of rectangles to clear. If 0, the whole buffer is
520  *           cleared
521  *  lpRects: Pointer to the array of rectangles. If NULL, Count must be 0
522  *  dwFlags: D3DCLEAR_ZBUFFER and / or D3DCLEAR_TARGET
523  *
524  * Returns:
525  *  D3D_OK on success
526  *  D3DERR_VIEWPORTHASNODEVICE if there's no active device
527  *  The return value of IDirect3DDevice7::Clear
528  *
529  *****************************************************************************/
530 static HRESULT WINAPI
531 IDirect3DViewportImpl_Clear(IDirect3DViewport3 *iface,
532                             DWORD dwCount, 
533                             D3DRECT *lpRects,
534                             DWORD dwFlags)
535 {
536     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
537     DWORD color = 0x00000000;
538     HRESULT hr;
539
540     TRACE("(%p/%p)->(%08x,%p,%08x)\n", This, iface, dwCount, lpRects, dwFlags);
541     if (This->active_device == NULL) {
542         ERR(" Trying to clear a viewport not attached to a device !\n");
543         return D3DERR_VIEWPORTHASNODEVICE;
544     }
545
546     EnterCriticalSection(&ddraw_cs);
547     if (dwFlags & D3DCLEAR_TARGET) {
548         if (This->background == NULL) {
549             ERR(" Trying to clear the color buffer without background material !\n");
550         } else {
551             color = 
552               ((int) ((This->background->mat.u.diffuse.u1.r) * 255) << 16) |
553               ((int) ((This->background->mat.u.diffuse.u2.g) * 255) <<  8) |
554               ((int) ((This->background->mat.u.diffuse.u3.b) * 255) <<  0) |
555               ((int) ((This->background->mat.u.diffuse.u4.a) * 255) << 24);
556         }
557     }
558
559     hr = IDirect3DDevice7_Clear(ICOM_INTERFACE(This->active_device, IDirect3DDevice7),
560                                 dwCount,
561                                 lpRects,
562                                 dwFlags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET),
563                                 color,
564                                 1.0,
565                                 0x00000000);
566     LeaveCriticalSection(&ddraw_cs);
567     return hr;
568 }
569
570 /*****************************************************************************
571  * IDirect3DViewport3::AddLight
572  *
573  * Adds an light to the viewport
574  *
575  * Params:
576  *  lpDirect3DLight: Interface of the light to add
577  *
578  * Returns:
579  *  D3D_OK on success
580  *  DDERR_INVALIDPARAMS if Direct3DLight is NULL
581  *  DDERR_INVALIDPARAMS if there are 8 lights or more
582  *
583  *****************************************************************************/
584 static HRESULT WINAPI
585 IDirect3DViewportImpl_AddLight(IDirect3DViewport3 *iface,
586                                IDirect3DLight *lpDirect3DLight)
587 {
588     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
589     IDirect3DLightImpl *lpDirect3DLightImpl = ICOM_OBJECT(IDirect3DLightImpl, IDirect3DLight, lpDirect3DLight);
590     DWORD i = 0;
591     DWORD map = This->map_lights;
592     
593     TRACE("(%p)->(%p)\n", This, lpDirect3DLight);
594
595     EnterCriticalSection(&ddraw_cs);
596     if (This->num_lights >= 8)
597     {
598         LeaveCriticalSection(&ddraw_cs);
599         return DDERR_INVALIDPARAMS;
600     }
601
602     /* Find a light number and update both light and viewports objects accordingly */
603     while(map&1) {
604         map>>=1;
605         i++;
606     }
607     lpDirect3DLightImpl->dwLightIndex = i;
608     This->num_lights++;
609     This->map_lights |= 1<<i;
610
611     /* Add the light in the 'linked' chain */
612     lpDirect3DLightImpl->next = This->lights;
613     This->lights = lpDirect3DLightImpl;
614
615     /* Attach the light to the viewport */
616     lpDirect3DLightImpl->active_viewport = This;
617     
618     /* If active, activate the light */
619     if (This->active_device != NULL) {
620         lpDirect3DLightImpl->activate(lpDirect3DLightImpl);
621     }
622
623     LeaveCriticalSection(&ddraw_cs);
624     return D3D_OK;
625 }
626
627 /*****************************************************************************
628  * IDirect3DViewport3::DeleteLight
629  *
630  * Deletes a light from the viewports' light list
631  *
632  * Params:
633  *  lpDirect3DLight: Light to delete
634  *
635  * Returns:
636  *  D3D_OK on success
637  *  DDERR_INVALIDPARAMS if the light wasn't found
638  *
639  *****************************************************************************/
640 static HRESULT WINAPI
641 IDirect3DViewportImpl_DeleteLight(IDirect3DViewport3 *iface,
642                                   IDirect3DLight *lpDirect3DLight)
643 {
644     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
645     IDirect3DLightImpl *lpDirect3DLightImpl = ICOM_OBJECT(IDirect3DLightImpl, IDirect3DLight, lpDirect3DLight);
646     IDirect3DLightImpl *cur_light, *prev_light = NULL;
647     
648     TRACE("(%p)->(%p)\n", This, lpDirect3DLight);
649
650     EnterCriticalSection(&ddraw_cs);
651     cur_light = This->lights;
652     while (cur_light != NULL) {
653         if (cur_light == lpDirect3DLightImpl) {
654             lpDirect3DLightImpl->desactivate(lpDirect3DLightImpl);
655             if (prev_light == NULL) This->lights = cur_light->next;
656             else prev_light->next = cur_light->next;
657             /* Detach the light to the viewport */
658             cur_light->active_viewport = NULL;
659             This->num_lights--;
660             This->map_lights &= ~(1<<lpDirect3DLightImpl->dwLightIndex);
661             LeaveCriticalSection(&ddraw_cs);
662             return D3D_OK;
663         }
664         prev_light = cur_light;
665         cur_light = cur_light->next;
666     }
667     LeaveCriticalSection(&ddraw_cs);
668
669     return DDERR_INVALIDPARAMS;
670 }
671
672 /*****************************************************************************
673  * IDirect3DViewport::NextLight
674  *
675  * Enumerates the lights associated with the viewport
676  *
677  * Params:
678  *  lpDirect3DLight: Light to start with
679  *  lplpDirect3DLight: Address to store the successor to
680  *
681  * Returns:
682  *  D3D_OK, because it's a stub
683  *
684  *****************************************************************************/
685 static HRESULT WINAPI
686 IDirect3DViewportImpl_NextLight(IDirect3DViewport3 *iface,
687                                 IDirect3DLight *lpDirect3DLight,
688                                 IDirect3DLight **lplpDirect3DLight,
689                                 DWORD dwFlags)
690 {
691     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
692     FIXME("(%p)->(%p,%p,%08x): stub!\n", This, lpDirect3DLight, lplpDirect3DLight, dwFlags);
693     return D3D_OK;
694 }
695
696 /*****************************************************************************
697  * IDirect3DViewport2 Methods.
698  *****************************************************************************/
699
700 /*****************************************************************************
701  * IDirect3DViewport3::GetViewport2
702  *
703  * Returns the currently set viewport in a D3DVIEWPORT2 structure.
704  * Similar to IDirect3DViewport3::GetViewport
705  *
706  * Params:
707  *  lpData: Pointer to the structure to fill
708  *
709  * Returns:
710  *  D3D_OK on success
711  *  DDERR_INVALIDPARAMS if the viewport was set with
712  *                      IDirect3DViewport3::SetViewport
713  *  DDERR_INVALIDPARAMS if Data is NULL
714  *
715  *****************************************************************************/
716 static HRESULT WINAPI
717 IDirect3DViewportImpl_GetViewport2(IDirect3DViewport3 *iface,
718                                    D3DVIEWPORT2 *lpData)
719 {
720     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
721     DWORD dwSize;
722     TRACE("(%p)->(%p)\n", This, lpData);
723
724     EnterCriticalSection(&ddraw_cs);
725     if (This->use_vp2 != 1) {
726         ERR("  Requesting to get a D3DVIEWPORT2 struct where a D3DVIEWPORT was set !\n");
727         LeaveCriticalSection(&ddraw_cs);
728         return DDERR_INVALIDPARAMS;
729     }
730     dwSize = lpData->dwSize;
731     memset(lpData, 0, dwSize);
732     memcpy(lpData, &(This->viewports.vp2), dwSize);
733
734     if (TRACE_ON(d3d7)) {
735         TRACE("  returning D3DVIEWPORT2 :\n");
736         _dump_D3DVIEWPORT2(lpData);
737     }
738
739     LeaveCriticalSection(&ddraw_cs);
740     return D3D_OK;
741 }
742
743 /*****************************************************************************
744  * IDirect3DViewport3::SetViewport2
745  *
746  * Sets the viewport from a D3DVIEWPORT2 structure
747  *
748  * Params:
749  *  lpData: Viewport to set
750  *
751  * Returns:
752  *  D3D_OK on success
753  *
754  *****************************************************************************/
755 static HRESULT WINAPI
756 IDirect3DViewportImpl_SetViewport2(IDirect3DViewport3 *iface,
757                                    D3DVIEWPORT2 *lpData)
758 {
759     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
760     LPDIRECT3DVIEWPORT3 current_viewport;
761     TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
762
763     if (TRACE_ON(d3d7)) {
764         TRACE("  getting D3DVIEWPORT2 :\n");
765         _dump_D3DVIEWPORT2(lpData);
766     }
767
768     EnterCriticalSection(&ddraw_cs);
769     This->use_vp2 = 1;
770     memset(&(This->viewports.vp2), 0, sizeof(This->viewports.vp2));
771     memcpy(&(This->viewports.vp2), lpData, lpData->dwSize);
772
773     if (This->active_device) {
774       IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), &current_viewport);
775       if (ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport) == This)
776         This->activate(This);
777       IDirect3DViewport3_Release(current_viewport);
778     }
779     LeaveCriticalSection(&ddraw_cs);
780
781     return D3D_OK;
782 }
783
784 /*****************************************************************************
785  * IDirect3DViewport3 Methods.
786  *****************************************************************************/
787
788 /*****************************************************************************
789  * IDirect3DViewport3::SetBackgroundDepth2
790  *
791  * Sets a IDirectDrawSurface4 surface as the background depth surface
792  *
793  * Params:
794  *  lpDDS: Surface to set
795  *
796  * Returns:
797  *  D3D_OK, because it's stub
798  *
799  *****************************************************************************/
800 static HRESULT WINAPI
801 IDirect3DViewportImpl_SetBackgroundDepth2(IDirect3DViewport3 *iface,
802                                           IDirectDrawSurface4 *lpDDS)
803 {
804     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
805     FIXME("(%p)->(%p): stub!\n", This, lpDDS);
806     return D3D_OK;
807 }
808
809 /*****************************************************************************
810  * IDirect3DViewport3::GetBackgroundDepth2
811  *
812  * Returns the IDirect3DSurface4 interface to the background depth surface
813  *
814  * Params:
815  *  lplpDDS: Address to store the interface pointer at
816  *  lpValid: Set to true if a surface is assigned
817  *
818  * Returns:
819  *  D3D_OK because it's a stub
820  *
821  *****************************************************************************/
822 static HRESULT WINAPI
823 IDirect3DViewportImpl_GetBackgroundDepth2(IDirect3DViewport3 *iface,
824                                           IDirectDrawSurface4 **lplpDDS,
825                                           BOOL *lpValid)
826 {
827     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
828     FIXME("(%p/%p)->(%p,%p): stub!\n", This, iface, lplpDDS, lpValid);
829     return D3D_OK;
830 }
831
832 /*****************************************************************************
833  * IDirect3DViewport3::Clear2
834  *
835  * Another clearing method
836  *
837  * Params:
838  *  Count: Number of rectangles to clear
839  *  Rects: Rectangle array to clear
840  *  Flags: Some flags :)
841  *  Color: Color to fill the render target with
842  *  Z: Value to fill the depth buffer with
843  *  Stencil: Value to fill the stencil bits with
844  *
845  * Returns:
846  *
847  *****************************************************************************/
848 static HRESULT WINAPI
849 IDirect3DViewportImpl_Clear2(IDirect3DViewport3 *iface,
850                              DWORD dwCount,
851                              LPD3DRECT lpRects,
852                              DWORD dwFlags,
853                              DWORD dwColor,
854                              D3DVALUE dvZ,
855                              DWORD dwStencil)
856 {
857     ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
858     HRESULT hr;
859     TRACE("(%p)->(%08x,%p,%08x,%08x,%f,%08x)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
860
861     EnterCriticalSection(&ddraw_cs);
862     if (This->active_device == NULL) {
863         ERR(" Trying to clear a viewport not attached to a device !\n");
864         LeaveCriticalSection(&ddraw_cs);
865         return D3DERR_VIEWPORTHASNODEVICE;
866     }
867     hr = IDirect3DDevice7_Clear(ICOM_INTERFACE(This->active_device, IDirect3DDevice7),
868                                 dwCount,
869                                 lpRects,
870                                 dwFlags,
871                                 dwColor,
872                                 dvZ,
873                                 dwStencil);
874     LeaveCriticalSection(&ddraw_cs);
875     return hr;
876 }
877
878 /*****************************************************************************
879  * The VTable
880  *****************************************************************************/
881
882 const IDirect3DViewport3Vtbl IDirect3DViewport3_Vtbl =
883 {
884     /*** IUnknown Methods ***/
885     IDirect3DViewportImpl_QueryInterface,
886     IDirect3DViewportImpl_AddRef,
887     IDirect3DViewportImpl_Release,
888     /*** IDirect3DViewport Methods */
889     IDirect3DViewportImpl_Initialize,
890     IDirect3DViewportImpl_GetViewport,
891     IDirect3DViewportImpl_SetViewport,
892     IDirect3DViewportImpl_TransformVertices,
893     IDirect3DViewportImpl_LightElements,
894     IDirect3DViewportImpl_SetBackground,
895     IDirect3DViewportImpl_GetBackground,
896     IDirect3DViewportImpl_SetBackgroundDepth,
897     IDirect3DViewportImpl_GetBackgroundDepth,
898     IDirect3DViewportImpl_Clear,
899     IDirect3DViewportImpl_AddLight,
900     IDirect3DViewportImpl_DeleteLight,
901     IDirect3DViewportImpl_NextLight,
902     /*** IDirect3DViewport2 Methods ***/
903     IDirect3DViewportImpl_GetViewport2,
904     IDirect3DViewportImpl_SetViewport2,
905     /*** IDirect3DViewport3 Methods ***/
906     IDirect3DViewportImpl_SetBackgroundDepth2,
907     IDirect3DViewportImpl_GetBackgroundDepth2,
908     IDirect3DViewportImpl_Clear2,
909 };