oleacc: Use int64 in the spec file for 64-bit integers.
[wine] / dlls / ddraw / viewport.c
1 /* Direct3D Viewport
2  * Copyright (c) 1998 Lionel ULMER
3  * Copyright (c) 2006-2007 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 "ddraw_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
28
29 /*****************************************************************************
30  * Helper functions
31  *****************************************************************************/
32
33 /*****************************************************************************
34  * viewport_activate
35  *
36  * activates the viewport using IDirect3DDevice7::SetViewport
37  *
38  *****************************************************************************/
39 void viewport_activate(IDirect3DViewportImpl* This, BOOL ignore_lights) {
40     IDirect3DLightImpl* light;
41     D3DVIEWPORT7 vp;
42
43     if (!ignore_lights) {
44         /* Activate all the lights associated with this context */
45         light = This->lights;
46
47         while (light)
48         {
49             light_activate(light);
50             light = light->next;
51         }
52     }
53
54     /* And copy the values in the structure used by the device */
55     if (This->use_vp2) {
56         vp.dwX = This->viewports.vp2.dwX;
57         vp.dwY = This->viewports.vp2.dwY;
58         vp.dwHeight = This->viewports.vp2.dwHeight;
59         vp.dwWidth = This->viewports.vp2.dwWidth;
60         vp.dvMinZ = This->viewports.vp2.dvMinZ;
61         vp.dvMaxZ = This->viewports.vp2.dvMaxZ;
62     } else {
63         vp.dwX = This->viewports.vp1.dwX;
64         vp.dwY = This->viewports.vp1.dwY;
65         vp.dwHeight = This->viewports.vp1.dwHeight;
66         vp.dwWidth = This->viewports.vp1.dwWidth;
67         vp.dvMinZ = This->viewports.vp1.dvMinZ;
68         vp.dvMaxZ = This->viewports.vp1.dvMaxZ;
69     }
70
71     /* And also set the viewport */
72     IDirect3DDevice7_SetViewport((IDirect3DDevice7 *)This->active_device, &vp);
73 }
74
75 /*****************************************************************************
76  * _dump_D3DVIEWPORT, _dump_D3DVIEWPORT2
77  *
78  * Writes viewport information to TRACE
79  *
80  *****************************************************************************/
81 static void _dump_D3DVIEWPORT(const D3DVIEWPORT *lpvp)
82 {
83     TRACE("    - dwSize = %d   dwX = %d   dwY = %d\n",
84           lpvp->dwSize, lpvp->dwX, lpvp->dwY);
85     TRACE("    - dwWidth = %d   dwHeight = %d\n",
86           lpvp->dwWidth, lpvp->dwHeight);
87     TRACE("    - dvScaleX = %f   dvScaleY = %f\n",
88           lpvp->dvScaleX, lpvp->dvScaleY);
89     TRACE("    - dvMaxX = %f   dvMaxY = %f\n",
90           lpvp->dvMaxX, lpvp->dvMaxY);
91     TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
92           lpvp->dvMinZ, lpvp->dvMaxZ);
93 }
94
95 static void _dump_D3DVIEWPORT2(const D3DVIEWPORT2 *lpvp)
96 {
97     TRACE("    - dwSize = %d   dwX = %d   dwY = %d\n",
98           lpvp->dwSize, lpvp->dwX, lpvp->dwY);
99     TRACE("    - dwWidth = %d   dwHeight = %d\n",
100           lpvp->dwWidth, lpvp->dwHeight);
101     TRACE("    - dvClipX = %f   dvClipY = %f\n",
102           lpvp->dvClipX, lpvp->dvClipY);
103     TRACE("    - dvClipWidth = %f   dvClipHeight = %f\n",
104           lpvp->dvClipWidth, lpvp->dvClipHeight);
105     TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
106           lpvp->dvMinZ, lpvp->dvMaxZ);
107 }
108
109 /*****************************************************************************
110  * IUnknown Methods.
111  *****************************************************************************/
112
113 /*****************************************************************************
114  * IDirect3DViewport3::QueryInterface
115  *
116  * A normal QueryInterface. Can query all interface versions and the
117  * IUnknown interface. The VTables of the different versions
118  * are equal
119  *
120  * Params:
121  *  refiid: Interface id queried for
122  *  obj: Address to write the interface pointer to
123  *
124  * Returns:
125  *  S_OK on success.
126  *  E_NOINTERFACE if the requested interface wasn't found
127  *
128  *****************************************************************************/
129 static HRESULT WINAPI
130 IDirect3DViewportImpl_QueryInterface(IDirect3DViewport3 *iface,
131                                      REFIID riid,
132                                      void **obp)
133 {
134     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obp);
135
136     *obp = NULL;
137
138     if ( IsEqualGUID(&IID_IUnknown,  riid) ||
139          IsEqualGUID(&IID_IDirect3DViewport, riid) ||
140          IsEqualGUID(&IID_IDirect3DViewport2, riid) ||
141          IsEqualGUID(&IID_IDirect3DViewport3, riid) ) {
142         IDirect3DViewport3_AddRef(iface);
143         *obp = iface;
144         TRACE("  Creating IDirect3DViewport1/2/3 interface %p\n", *obp);
145         return S_OK;
146     }
147     FIXME("(%p): interface for IID %s NOT found!\n", iface, debugstr_guid(riid));
148     return E_NOINTERFACE;
149 }
150
151 /*****************************************************************************
152  * IDirect3DViewport3::AddRef
153  *
154  * Increases the refcount.
155  *
156  * Returns:
157  *  The new refcount
158  *
159  *****************************************************************************/
160 static ULONG WINAPI
161 IDirect3DViewportImpl_AddRef(IDirect3DViewport3 *iface)
162 {
163     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
164     ULONG ref = InterlockedIncrement(&This->ref);
165
166     TRACE("%p increasing refcount to %u.\n", This, ref);
167
168     return ref;
169 }
170
171 /*****************************************************************************
172  * IDirect3DViewport3::Release
173  *
174  * Reduces the refcount. If it falls to 0, the interface is released
175  *
176  * Returns:
177  *  The new refcount
178  *
179  *****************************************************************************/
180 static ULONG WINAPI
181 IDirect3DViewportImpl_Release(IDirect3DViewport3 *iface)
182 {
183     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
184     ULONG ref = InterlockedDecrement(&This->ref);
185
186     TRACE("%p decreasing refcount to %u.\n", This, ref);
187
188     if (!ref) {
189         HeapFree(GetProcessHeap(), 0, This);
190         return 0;
191     }
192     return ref;
193 }
194
195 /*****************************************************************************
196  * IDirect3DViewport Methods.
197  *****************************************************************************/
198
199 /*****************************************************************************
200  * IDirect3DViewport3::Initialize
201  *
202  * No-op initialization.
203  *
204  * Params:
205  *  Direct3D: The direct3D device this viewport is assigned to
206  *
207  * Returns:
208  *  DDERR_ALREADYINITIALIZED
209  *
210  *****************************************************************************/
211 static HRESULT WINAPI
212 IDirect3DViewportImpl_Initialize(IDirect3DViewport3 *iface,
213                                  IDirect3D *Direct3D)
214 {
215     TRACE("iface %p, d3d %p.\n", iface, Direct3D);
216
217     return DDERR_ALREADYINITIALIZED;
218 }
219
220 /*****************************************************************************
221  * IDirect3DViewport3::GetViewport
222  *
223  * Returns the viewport data assigned to this viewport interface
224  *
225  * Params:
226  *  Data: Address to store the data
227  *
228  * Returns:
229  *  D3D_OK on success
230  *  DDERR_INVALIDPARAMS if Data is NULL
231  *
232  *****************************************************************************/
233 static HRESULT WINAPI
234 IDirect3DViewportImpl_GetViewport(IDirect3DViewport3 *iface,
235                                   D3DVIEWPORT *lpData)
236 {
237     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
238     DWORD dwSize;
239
240     TRACE("iface %p, data %p.\n", iface, lpData);
241
242     EnterCriticalSection(&ddraw_cs);
243     dwSize = lpData->dwSize;
244     memset(lpData, 0, dwSize);
245     if (!This->use_vp2)
246         memcpy(lpData, &(This->viewports.vp1), dwSize);
247     else {
248         D3DVIEWPORT vp1;
249         vp1.dwSize = sizeof(vp1);
250         vp1.dwX = This->viewports.vp2.dwX;
251         vp1.dwY = This->viewports.vp2.dwY;
252         vp1.dwWidth = This->viewports.vp2.dwWidth;
253         vp1.dwHeight = This->viewports.vp2.dwHeight;
254         vp1.dvMaxX = 0.0;
255         vp1.dvMaxY = 0.0;
256         vp1.dvScaleX = 0.0;
257         vp1.dvScaleY = 0.0;
258         vp1.dvMinZ = This->viewports.vp2.dvMinZ;
259         vp1.dvMaxZ = This->viewports.vp2.dvMaxZ;
260         memcpy(lpData, &vp1, dwSize);
261     }
262
263     if (TRACE_ON(ddraw))
264     {
265         TRACE("  returning D3DVIEWPORT :\n");
266         _dump_D3DVIEWPORT(lpData);
267     }
268     LeaveCriticalSection(&ddraw_cs);
269
270     return DD_OK;
271 }
272
273 /*****************************************************************************
274  * IDirect3DViewport3::SetViewport
275  *
276  * Sets the viewport information for this interface
277  *
278  * Params:
279  *  lpData: Viewport to set
280  *
281  * Returns:
282  *  D3D_OK on success
283  *  DDERR_INVALIDPARAMS if Data is NULL
284  *
285  *****************************************************************************/
286 static HRESULT WINAPI
287 IDirect3DViewportImpl_SetViewport(IDirect3DViewport3 *iface,
288                                   D3DVIEWPORT *lpData)
289 {
290     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
291     LPDIRECT3DVIEWPORT3 current_viewport;
292
293     TRACE("iface %p, data %p.\n", iface, lpData);
294
295     if (TRACE_ON(ddraw))
296     {
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 *d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
314         IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
315         if (current_viewport)
316         {
317             if ((IDirect3DViewportImpl *)current_viewport == This) viewport_activate(This, FALSE);
318             IDirect3DViewport3_Release(current_viewport);
319         }
320     }
321     LeaveCriticalSection(&ddraw_cs);
322
323     return DD_OK;
324 }
325
326 /*****************************************************************************
327  * IDirect3DViewport3::TransformVertices
328  *
329  * Transforms vertices by the transformation matrix.
330  *
331  * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices,
332  * so it's tempting to forward it to there. However, there are some
333  * tiny differences. First, the lpOffscreen flag that is reported back,
334  * then there is the homogeneous vertex that is generated. Also there's a lack
335  * of FVFs, but still a custom stride. Last, the d3d1 - d3d3 viewport has some
336  * settings (scale) that d3d7 and wined3d do not have. All in all wrapping to
337  * ProcessVertices doesn't pay of in terms of wrapper code needed and code
338  * reused.
339  *
340  * Params:
341  *  dwVertexCount: The number of vertices to be transformed
342  *  lpData: Pointer to the vertex data
343  *  dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED
344  *  lpOffScreen: Set to the clipping plane clipping the vertex, if only one
345  *               vertex is transformed and clipping is on. 0 otherwise
346  *
347  * Returns:
348  *  D3D_OK on success
349  *  D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device
350  *  DDERR_INVALIDPARAMS if no clipping flag is specified
351  *
352  *****************************************************************************/
353 static HRESULT WINAPI
354 IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
355                                         DWORD dwVertexCount,
356                                         D3DTRANSFORMDATA *lpData,
357                                         DWORD dwFlags,
358                                         DWORD *lpOffScreen)
359 {
360     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
361     D3DMATRIX view_mat, world_mat, proj_mat, mat;
362     float *in;
363     float *out;
364     float x, y, z, w;
365     unsigned int i;
366     D3DVIEWPORT vp = This->viewports.vp1;
367     D3DHVERTEX *outH;
368
369     TRACE("iface %p, vertex_count %u, vertex_data %p, flags %#x, clip_plane %p.\n",
370             iface, dwVertexCount, lpData, dwFlags, lpOffScreen);
371
372     /* Tests on windows show that Windows crashes when this occurs,
373      * so don't return the (intuitive) return value
374     if(!This->active_device)
375     {
376         WARN("No device active, returning D3DERR_VIEWPORTHASNODEVICE\n");
377         return D3DERR_VIEWPORTHASNODEVICE;
378     }
379      */
380
381     if(!(dwFlags & (D3DTRANSFORM_UNCLIPPED | D3DTRANSFORM_CLIPPED)))
382     {
383         WARN("No clipping flag passed, returning DDERR_INVALIDPARAMS\n");
384         return DDERR_INVALIDPARAMS;
385     }
386
387
388     EnterCriticalSection(&ddraw_cs);
389     IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice,
390                                 D3DTRANSFORMSTATE_VIEW,
391                                 (WINED3DMATRIX*) &view_mat);
392
393     IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice,
394                                 D3DTRANSFORMSTATE_PROJECTION,
395                                 (WINED3DMATRIX*) &proj_mat);
396
397     IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice,
398                                 WINED3DTS_WORLDMATRIX(0),
399                                 (WINED3DMATRIX*) &world_mat);
400     multiply_matrix(&mat,&view_mat,&world_mat);
401     multiply_matrix(&mat,&proj_mat,&mat);
402
403     in = lpData->lpIn;
404     out = lpData->lpOut;
405     outH = lpData->lpHOut;
406     for(i = 0; i < dwVertexCount; i++)
407     {
408         x = (in[0] * mat._11) + (in[1] * mat._21) + (in[2] * mat._31) + (1.0 * mat._41);
409         y = (in[0] * mat._12) + (in[1] * mat._22) + (in[2] * mat._32) + (1.0 * mat._42);
410         z = (in[0] * mat._13) + (in[1] * mat._23) + (in[2] * mat._33) + (1.0 * mat._43);
411         w = (in[0] * mat._14) + (in[1] * mat._24) + (in[2] * mat._34) + (1.0 * mat._44);
412
413         if(dwFlags & D3DTRANSFORM_CLIPPED)
414         {
415             /* If clipping is enabled, Windows assumes that outH is
416              * a valid pointer
417              */
418             outH[i].u1.hx = x; outH[i].u2.hy = y; outH[i].u3.hz = z;
419
420             outH[i].dwFlags = 0;
421             if(x * vp.dvScaleX > ((float) vp.dwWidth * 0.5))
422                 outH[i].dwFlags |= D3DCLIP_RIGHT;
423             if(x * vp.dvScaleX <= -((float) vp.dwWidth) * 0.5)
424                 outH[i].dwFlags |= D3DCLIP_LEFT;
425             if(y * vp.dvScaleY > ((float) vp.dwHeight * 0.5))
426                 outH[i].dwFlags |= D3DCLIP_TOP;
427             if(y * vp.dvScaleY <= -((float) vp.dwHeight) * 0.5)
428                 outH[i].dwFlags |= D3DCLIP_BOTTOM;
429             if(z < 0.0)
430                 outH[i].dwFlags |= D3DCLIP_FRONT;
431             if(z > 1.0)
432                 outH[i].dwFlags |= D3DCLIP_BACK;
433
434             if(outH[i].dwFlags)
435             {
436                 /* Looks like native just drops the vertex, leaves whatever data
437                  * it has in the output buffer and goes on with the next vertex.
438                  * The exact scheme hasn't been figured out yet, but windows
439                  * definitely writes something there.
440                  */
441                 out[0] = x;
442                 out[1] = y;
443                 out[2] = z;
444                 out[3] = w;
445                 in = (float *) ((char *) in + lpData->dwInSize);
446                 out = (float *) ((char *) out + lpData->dwOutSize);
447                 continue;
448             }
449         }
450
451         w = 1 / w;
452         x *= w; y *= w; z *= w;
453
454         out[0] = vp.dwWidth / 2 + vp.dwX + x * vp.dvScaleX;
455         out[1] = vp.dwHeight / 2 + vp.dwY - y * vp.dvScaleY;
456         out[2] = z;
457         out[3] = w;
458         in = (float *) ((char *) in + lpData->dwInSize);
459         out = (float *) ((char *) out + lpData->dwOutSize);
460     }
461
462     /* According to the d3d test, the offscreen flag is set only
463      * if exactly one vertex is transformed. Its not documented,
464      * but the test shows that the lpOffscreen flag is set to the
465      * flag combination of clipping planes that clips the vertex.
466      *
467      * If clipping is requested, Windows assumes that the offscreen
468      * param is a valid pointer.
469      */
470     if(dwVertexCount == 1 && dwFlags & D3DTRANSFORM_CLIPPED)
471     {
472         *lpOffScreen = outH[0].dwFlags;
473     }
474     else if(*lpOffScreen)
475     {
476         *lpOffScreen = 0;
477     }
478     LeaveCriticalSection(&ddraw_cs);
479
480     TRACE("All done\n");
481     return DD_OK;
482 }
483
484 /*****************************************************************************
485  * IDirect3DViewport3::LightElements
486  *
487  * The DirectX 5.0 sdk says that it's not implemented
488  *
489  * Params:
490  *  ?
491  *
492  * Returns:
493  *  DDERR_UNSUPPORTED
494  *
495  *****************************************************************************/
496 static HRESULT WINAPI
497 IDirect3DViewportImpl_LightElements(IDirect3DViewport3 *iface,
498                                     DWORD dwElementCount,
499                                     LPD3DLIGHTDATA lpData)
500 {
501     TRACE("iface %p, element_count %u, data %p.\n", iface, dwElementCount, lpData);
502
503     return DDERR_UNSUPPORTED;
504 }
505
506 /*****************************************************************************
507  * IDirect3DViewport3::SetBackground
508  *
509  * Sets tje background material
510  *
511  * Params:
512  *  hMat: Handle from a IDirect3DMaterial interface
513  *
514  * Returns:
515  *  D3D_OK on success
516  *
517  *****************************************************************************/
518 static HRESULT WINAPI
519 IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface,
520                                     D3DMATERIALHANDLE hMat)
521 {
522     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
523     IDirect3DMaterialImpl *m;
524
525     TRACE("iface %p, material %#x.\n", iface, hMat);
526
527     EnterCriticalSection(&ddraw_cs);
528
529     if (!hMat)
530     {
531         This->background = NULL;
532         TRACE("Setting background to NULL\n");
533         LeaveCriticalSection(&ddraw_cs);
534         return D3D_OK;
535     }
536
537     m = ddraw_get_object(&This->ddraw->d3ddevice->handle_table, hMat - 1, DDRAW_HANDLE_MATERIAL);
538     if (!m)
539     {
540         WARN("Invalid material handle.\n");
541         LeaveCriticalSection(&ddraw_cs);
542         return DDERR_INVALIDPARAMS;
543     }
544
545     TRACE("Setting background color : %.8e %.8e %.8e %.8e.\n",
546             m->mat.u.diffuse.u1.r, m->mat.u.diffuse.u2.g,
547             m->mat.u.diffuse.u3.b, m->mat.u.diffuse.u4.a);
548     This->background = m;
549
550     LeaveCriticalSection(&ddraw_cs);
551     return D3D_OK;
552 }
553
554 /*****************************************************************************
555  * IDirect3DViewport3::GetBackground
556  *
557  * Returns the material handle assigned to the background of the viewport
558  *
559  * Params:
560  *  lphMat: Address to store the handle
561  *  lpValid: is set to FALSE if no background is set, TRUE if one is set
562  *
563  * Returns:
564  *  D3D_OK
565  *
566  *****************************************************************************/
567 static HRESULT WINAPI
568 IDirect3DViewportImpl_GetBackground(IDirect3DViewport3 *iface,
569                                     D3DMATERIALHANDLE *lphMat,
570                                     BOOL *lpValid)
571 {
572     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
573
574     TRACE("iface %p, material %p, valid %p.\n", iface, lphMat, lpValid);
575
576     EnterCriticalSection(&ddraw_cs);
577     if(lpValid)
578     {
579         *lpValid = This->background != NULL;
580     }
581     if(lphMat)
582     {
583         if(This->background)
584         {
585             *lphMat = This->background->Handle;
586         }
587         else
588         {
589             *lphMat = 0;
590         }
591     }
592     LeaveCriticalSection(&ddraw_cs);
593
594     return D3D_OK;
595 }
596
597 /*****************************************************************************
598  * IDirect3DViewport3::SetBackgroundDepth
599  *
600  * Sets a surface that represents the background depth. It's contents are
601  * used to set the depth buffer in IDirect3DViewport3::Clear
602  *
603  * Params:
604  *  lpDDSurface: Surface to set
605  *
606  * Returns: D3D_OK, because it's a stub
607  *
608  *****************************************************************************/
609 static HRESULT WINAPI
610 IDirect3DViewportImpl_SetBackgroundDepth(IDirect3DViewport3 *iface,
611                                          IDirectDrawSurface *lpDDSurface)
612 {
613     FIXME("iface %p, surface %p stub!\n", iface, lpDDSurface);
614
615     return D3D_OK;
616 }
617
618 /*****************************************************************************
619  * IDirect3DViewport3::GetBackgroundDepth
620  *
621  * Returns the surface that represents the depth field
622  *
623  * Params:
624  *  lplpDDSurface: Address to store the interface pointer
625  *  lpValid: Set to TRUE if a depth is assigned, FALSE otherwise
626  *
627  * Returns:
628  *  D3D_OK, because it's a stub
629  *  (DDERR_INVALIDPARAMS if DDSurface of Valid is NULL)
630  *
631  *****************************************************************************/
632 static HRESULT WINAPI
633 IDirect3DViewportImpl_GetBackgroundDepth(IDirect3DViewport3 *iface,
634                                          IDirectDrawSurface **lplpDDSurface,
635                                          LPBOOL lpValid)
636 {
637     FIXME("iface %p, surface %p, valid %p stub!\n", iface, lplpDDSurface, lpValid);
638
639     return DD_OK;
640 }
641
642 /*****************************************************************************
643  * IDirect3DViewport3::Clear
644  *
645  * Clears the render target and / or the z buffer
646  *
647  * Params:
648  *  dwCount: The amount of rectangles to clear. If 0, the whole buffer is
649  *           cleared
650  *  lpRects: Pointer to the array of rectangles. If NULL, Count must be 0
651  *  dwFlags: D3DCLEAR_ZBUFFER and / or D3DCLEAR_TARGET
652  *
653  * Returns:
654  *  D3D_OK on success
655  *  D3DERR_VIEWPORTHASNODEVICE if there's no active device
656  *  The return value of IDirect3DDevice7::Clear
657  *
658  *****************************************************************************/
659 static HRESULT WINAPI IDirect3DViewportImpl_Clear(IDirect3DViewport3 *iface,
660         DWORD dwCount, D3DRECT *lpRects, DWORD dwFlags)
661 {
662     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
663     DWORD color = 0x00000000;
664     HRESULT hr;
665     LPDIRECT3DVIEWPORT3 current_viewport;
666     IDirect3DDevice3 *d3d_device3;
667
668     TRACE("iface %p, rect_count %u, rects %p, flags %#x.\n", iface, dwCount, lpRects, dwFlags);
669
670     if (This->active_device == NULL) {
671         ERR(" Trying to clear a viewport not attached to a device !\n");
672         return D3DERR_VIEWPORTHASNODEVICE;
673     }
674     d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
675
676     EnterCriticalSection(&ddraw_cs);
677     if (dwFlags & D3DCLEAR_TARGET) {
678         if (This->background == NULL) {
679             ERR(" Trying to clear the color buffer without background material !\n");
680         }
681         else
682         {
683             color = ((int)((This->background->mat.u.diffuse.u1.r) * 255) << 16)
684                     | ((int) ((This->background->mat.u.diffuse.u2.g) * 255) <<  8)
685                     | ((int) ((This->background->mat.u.diffuse.u3.b) * 255) <<  0)
686                     | ((int) ((This->background->mat.u.diffuse.u4.a) * 255) << 24);
687         }
688     }
689
690     /* Need to temporarily activate viewport to clear it. Previously active one will be restored
691         afterwards. */
692     viewport_activate(This, TRUE);
693
694     hr = IDirect3DDevice7_Clear((IDirect3DDevice7 *)This->active_device, dwCount, lpRects,
695             dwFlags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET), color, 1.0, 0x00000000);
696
697     IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
698     if(current_viewport) {
699         IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)current_viewport;
700         viewport_activate(vp, TRUE);
701         IDirect3DViewport3_Release(current_viewport);
702     }
703
704     LeaveCriticalSection(&ddraw_cs);
705     return hr;
706 }
707
708 /*****************************************************************************
709  * IDirect3DViewport3::AddLight
710  *
711  * Adds an light to the viewport
712  *
713  * Params:
714  *  lpDirect3DLight: Interface of the light to add
715  *
716  * Returns:
717  *  D3D_OK on success
718  *  DDERR_INVALIDPARAMS if Direct3DLight is NULL
719  *  DDERR_INVALIDPARAMS if there are 8 lights or more
720  *
721  *****************************************************************************/
722 static HRESULT WINAPI
723 IDirect3DViewportImpl_AddLight(IDirect3DViewport3 *iface,
724                                IDirect3DLight *lpDirect3DLight)
725 {
726     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
727     IDirect3DLightImpl *lpDirect3DLightImpl = (IDirect3DLightImpl *)lpDirect3DLight;
728     DWORD i = 0;
729     DWORD map = This->map_lights;
730
731     TRACE("iface %p, light %p.\n", iface, lpDirect3DLight);
732
733     EnterCriticalSection(&ddraw_cs);
734     if (This->num_lights >= 8)
735     {
736         LeaveCriticalSection(&ddraw_cs);
737         return DDERR_INVALIDPARAMS;
738     }
739
740     /* Find a light number and update both light and viewports objects accordingly */
741     while(map&1) {
742         map>>=1;
743         i++;
744     }
745     lpDirect3DLightImpl->dwLightIndex = i;
746     This->num_lights++;
747     This->map_lights |= 1<<i;
748
749     /* Add the light in the 'linked' chain */
750     lpDirect3DLightImpl->next = This->lights;
751     This->lights = lpDirect3DLightImpl;
752     IDirect3DLight_AddRef(lpDirect3DLight);
753
754     /* Attach the light to the viewport */
755     lpDirect3DLightImpl->active_viewport = This;
756
757     /* If active, activate the light */
758     if (This->active_device)
759         light_activate(lpDirect3DLightImpl);
760
761     LeaveCriticalSection(&ddraw_cs);
762     return D3D_OK;
763 }
764
765 /*****************************************************************************
766  * IDirect3DViewport3::DeleteLight
767  *
768  * Deletes a light from the viewports' light list
769  *
770  * Params:
771  *  lpDirect3DLight: Light to delete
772  *
773  * Returns:
774  *  D3D_OK on success
775  *  DDERR_INVALIDPARAMS if the light wasn't found
776  *
777  *****************************************************************************/
778 static HRESULT WINAPI
779 IDirect3DViewportImpl_DeleteLight(IDirect3DViewport3 *iface,
780                                   IDirect3DLight *lpDirect3DLight)
781 {
782     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
783     IDirect3DLightImpl *lpDirect3DLightImpl = (IDirect3DLightImpl *)lpDirect3DLight;
784     IDirect3DLightImpl *cur_light, *prev_light = NULL;
785
786     TRACE("iface %p, light %p.\n", iface, lpDirect3DLight);
787
788     EnterCriticalSection(&ddraw_cs);
789     cur_light = This->lights;
790     while (cur_light != NULL) {
791         if (cur_light == lpDirect3DLightImpl)
792         {
793             light_deactivate(lpDirect3DLightImpl);
794             if (prev_light == NULL) This->lights = cur_light->next;
795             else prev_light->next = cur_light->next;
796             /* Detach the light to the viewport */
797             cur_light->active_viewport = NULL;
798             IDirect3DLight_Release( (IDirect3DLight *)cur_light );
799             This->num_lights--;
800             This->map_lights &= ~(1<<lpDirect3DLightImpl->dwLightIndex);
801             LeaveCriticalSection(&ddraw_cs);
802             return D3D_OK;
803         }
804         prev_light = cur_light;
805         cur_light = cur_light->next;
806     }
807     LeaveCriticalSection(&ddraw_cs);
808
809     return DDERR_INVALIDPARAMS;
810 }
811
812 /*****************************************************************************
813  * IDirect3DViewport::NextLight
814  *
815  * Enumerates the lights associated with the viewport
816  *
817  * Params:
818  *  lpDirect3DLight: Light to start with
819  *  lplpDirect3DLight: Address to store the successor to
820  *
821  * Returns:
822  *  D3D_OK, because it's a stub
823  *
824  *****************************************************************************/
825 static HRESULT WINAPI
826 IDirect3DViewportImpl_NextLight(IDirect3DViewport3 *iface,
827                                 IDirect3DLight *lpDirect3DLight,
828                                 IDirect3DLight **lplpDirect3DLight,
829                                 DWORD dwFlags)
830 {
831     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
832     IDirect3DLightImpl *cur_light, *prev_light = NULL;
833
834     TRACE("iface %p, light %p, next_light %p, flags %#x.\n",
835             iface, lpDirect3DLight, lplpDirect3DLight, dwFlags);
836
837     if (!lplpDirect3DLight)
838         return DDERR_INVALIDPARAMS;
839
840     *lplpDirect3DLight = NULL;
841
842     EnterCriticalSection(&ddraw_cs);
843
844     cur_light = This->lights;
845
846     switch (dwFlags) {
847         case D3DNEXT_NEXT:
848             if (!lpDirect3DLight) {
849                 LeaveCriticalSection(&ddraw_cs);
850                 return DDERR_INVALIDPARAMS;
851             }
852             while (cur_light != NULL) {
853                 if (cur_light == (IDirect3DLightImpl *)lpDirect3DLight) {
854                     *lplpDirect3DLight = (IDirect3DLight*)cur_light->next;
855                     break;
856                 }
857                 cur_light = cur_light->next;
858             }
859             break;
860         case D3DNEXT_HEAD:
861             *lplpDirect3DLight = (IDirect3DLight*)This->lights;
862             break;
863         case D3DNEXT_TAIL:
864             while (cur_light != NULL) {
865                 prev_light = cur_light;
866                 cur_light = cur_light->next;
867             }
868             *lplpDirect3DLight = (IDirect3DLight*)prev_light;
869             break;
870         default:
871             ERR("Unknown flag %d\n", dwFlags);
872             break;
873     }
874
875     if (*lplpDirect3DLight)
876         IDirect3DLight_AddRef(*lplpDirect3DLight);
877
878     LeaveCriticalSection(&ddraw_cs);
879
880     return *lplpDirect3DLight ? D3D_OK : DDERR_INVALIDPARAMS;
881 }
882
883 /*****************************************************************************
884  * IDirect3DViewport2 Methods.
885  *****************************************************************************/
886
887 /*****************************************************************************
888  * IDirect3DViewport3::GetViewport2
889  *
890  * Returns the currently set viewport in a D3DVIEWPORT2 structure.
891  * Similar to IDirect3DViewport3::GetViewport
892  *
893  * Params:
894  *  lpData: Pointer to the structure to fill
895  *
896  * Returns:
897  *  D3D_OK on success
898  *  DDERR_INVALIDPARAMS if the viewport was set with
899  *                      IDirect3DViewport3::SetViewport
900  *  DDERR_INVALIDPARAMS if Data is NULL
901  *
902  *****************************************************************************/
903 static HRESULT WINAPI
904 IDirect3DViewportImpl_GetViewport2(IDirect3DViewport3 *iface,
905                                    D3DVIEWPORT2 *lpData)
906 {
907     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
908     DWORD dwSize;
909
910     TRACE("iface %p, data %p.\n", iface, lpData);
911
912     EnterCriticalSection(&ddraw_cs);
913     dwSize = lpData->dwSize;
914     memset(lpData, 0, dwSize);
915     if (This->use_vp2)
916         memcpy(lpData, &(This->viewports.vp2), dwSize);
917     else {
918         D3DVIEWPORT2 vp2;
919         vp2.dwSize = sizeof(vp2);
920         vp2.dwX = This->viewports.vp1.dwX;
921         vp2.dwY = This->viewports.vp1.dwY;
922         vp2.dwWidth = This->viewports.vp1.dwWidth;
923         vp2.dwHeight = This->viewports.vp1.dwHeight;
924         vp2.dvClipX = 0.0;
925         vp2.dvClipY = 0.0;
926         vp2.dvClipWidth = 0.0;
927         vp2.dvClipHeight = 0.0;
928         vp2.dvMinZ = This->viewports.vp1.dvMinZ;
929         vp2.dvMaxZ = This->viewports.vp1.dvMaxZ;
930         memcpy(lpData, &vp2, dwSize);
931     }
932
933     if (TRACE_ON(ddraw))
934     {
935         TRACE("  returning D3DVIEWPORT2 :\n");
936         _dump_D3DVIEWPORT2(lpData);
937     }
938
939     LeaveCriticalSection(&ddraw_cs);
940     return D3D_OK;
941 }
942
943 /*****************************************************************************
944  * IDirect3DViewport3::SetViewport2
945  *
946  * Sets the viewport from a D3DVIEWPORT2 structure
947  *
948  * Params:
949  *  lpData: Viewport to set
950  *
951  * Returns:
952  *  D3D_OK on success
953  *
954  *****************************************************************************/
955 static HRESULT WINAPI
956 IDirect3DViewportImpl_SetViewport2(IDirect3DViewport3 *iface,
957                                    D3DVIEWPORT2 *lpData)
958 {
959     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
960     LPDIRECT3DVIEWPORT3 current_viewport;
961
962     TRACE("iface %p, data %p.\n", iface, lpData);
963
964     if (TRACE_ON(ddraw))
965     {
966         TRACE("  getting D3DVIEWPORT2 :\n");
967         _dump_D3DVIEWPORT2(lpData);
968     }
969
970     EnterCriticalSection(&ddraw_cs);
971     This->use_vp2 = 1;
972     memset(&(This->viewports.vp2), 0, sizeof(This->viewports.vp2));
973     memcpy(&(This->viewports.vp2), lpData, lpData->dwSize);
974
975     if (This->active_device) {
976         IDirect3DDevice3 *d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
977         IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
978         if (current_viewport)
979         {
980             if ((IDirect3DViewportImpl *)current_viewport == This) viewport_activate(This, FALSE);
981             IDirect3DViewport3_Release(current_viewport);
982         }
983     }
984     LeaveCriticalSection(&ddraw_cs);
985
986     return D3D_OK;
987 }
988
989 /*****************************************************************************
990  * IDirect3DViewport3 Methods.
991  *****************************************************************************/
992
993 /*****************************************************************************
994  * IDirect3DViewport3::SetBackgroundDepth2
995  *
996  * Sets a IDirectDrawSurface4 surface as the background depth surface
997  *
998  * Params:
999  *  lpDDS: Surface to set
1000  *
1001  * Returns:
1002  *  D3D_OK, because it's stub
1003  *
1004  *****************************************************************************/
1005 static HRESULT WINAPI
1006 IDirect3DViewportImpl_SetBackgroundDepth2(IDirect3DViewport3 *iface,
1007                                           IDirectDrawSurface4 *lpDDS)
1008 {
1009     FIXME("iface %p, surface %p stub!\n", iface, lpDDS);
1010
1011     return D3D_OK;
1012 }
1013
1014 /*****************************************************************************
1015  * IDirect3DViewport3::GetBackgroundDepth2
1016  *
1017  * Returns the IDirect3DSurface4 interface to the background depth surface
1018  *
1019  * Params:
1020  *  lplpDDS: Address to store the interface pointer at
1021  *  lpValid: Set to true if a surface is assigned
1022  *
1023  * Returns:
1024  *  D3D_OK because it's a stub
1025  *
1026  *****************************************************************************/
1027 static HRESULT WINAPI
1028 IDirect3DViewportImpl_GetBackgroundDepth2(IDirect3DViewport3 *iface,
1029                                           IDirectDrawSurface4 **lplpDDS,
1030                                           BOOL *lpValid)
1031 {
1032     FIXME("iface %p, surface %p, valid %p stub!\n", iface, lplpDDS, lpValid);
1033
1034     return D3D_OK;
1035 }
1036
1037 /*****************************************************************************
1038  * IDirect3DViewport3::Clear2
1039  *
1040  * Another clearing method
1041  *
1042  * Params:
1043  *  Count: Number of rectangles to clear
1044  *  Rects: Rectangle array to clear
1045  *  Flags: Some flags :)
1046  *  Color: Color to fill the render target with
1047  *  Z: Value to fill the depth buffer with
1048  *  Stencil: Value to fill the stencil bits with
1049  *
1050  * Returns:
1051  *
1052  *****************************************************************************/
1053 static HRESULT WINAPI
1054 IDirect3DViewportImpl_Clear2(IDirect3DViewport3 *iface,
1055                              DWORD dwCount,
1056                              LPD3DRECT lpRects,
1057                              DWORD dwFlags,
1058                              DWORD dwColor,
1059                              D3DVALUE dvZ,
1060                              DWORD dwStencil)
1061 {
1062     IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
1063     HRESULT hr;
1064     LPDIRECT3DVIEWPORT3 current_viewport;
1065     IDirect3DDevice3 *d3d_device3;
1066
1067     TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
1068             iface, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
1069
1070     EnterCriticalSection(&ddraw_cs);
1071     if (This->active_device == NULL) {
1072         ERR(" Trying to clear a viewport not attached to a device !\n");
1073         LeaveCriticalSection(&ddraw_cs);
1074         return D3DERR_VIEWPORTHASNODEVICE;
1075     }
1076     d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
1077     /* Need to temporarily activate viewport to clear it. Previously active
1078      * one will be restored afterwards. */
1079     viewport_activate(This, TRUE);
1080
1081     hr = IDirect3DDevice7_Clear((IDirect3DDevice7 *)This->active_device,
1082             dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
1083     IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
1084     if(current_viewport) {
1085         IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)current_viewport;
1086         viewport_activate(vp, TRUE);
1087         IDirect3DViewport3_Release(current_viewport);
1088     }
1089     LeaveCriticalSection(&ddraw_cs);
1090     return hr;
1091 }
1092
1093 /*****************************************************************************
1094  * The VTable
1095  *****************************************************************************/
1096
1097 static const struct IDirect3DViewport3Vtbl d3d_viewport_vtbl =
1098 {
1099     /*** IUnknown Methods ***/
1100     IDirect3DViewportImpl_QueryInterface,
1101     IDirect3DViewportImpl_AddRef,
1102     IDirect3DViewportImpl_Release,
1103     /*** IDirect3DViewport Methods */
1104     IDirect3DViewportImpl_Initialize,
1105     IDirect3DViewportImpl_GetViewport,
1106     IDirect3DViewportImpl_SetViewport,
1107     IDirect3DViewportImpl_TransformVertices,
1108     IDirect3DViewportImpl_LightElements,
1109     IDirect3DViewportImpl_SetBackground,
1110     IDirect3DViewportImpl_GetBackground,
1111     IDirect3DViewportImpl_SetBackgroundDepth,
1112     IDirect3DViewportImpl_GetBackgroundDepth,
1113     IDirect3DViewportImpl_Clear,
1114     IDirect3DViewportImpl_AddLight,
1115     IDirect3DViewportImpl_DeleteLight,
1116     IDirect3DViewportImpl_NextLight,
1117     /*** IDirect3DViewport2 Methods ***/
1118     IDirect3DViewportImpl_GetViewport2,
1119     IDirect3DViewportImpl_SetViewport2,
1120     /*** IDirect3DViewport3 Methods ***/
1121     IDirect3DViewportImpl_SetBackgroundDepth2,
1122     IDirect3DViewportImpl_GetBackgroundDepth2,
1123     IDirect3DViewportImpl_Clear2,
1124 };
1125
1126 void d3d_viewport_init(IDirect3DViewportImpl *viewport, IDirectDrawImpl *ddraw)
1127 {
1128     viewport->lpVtbl = &d3d_viewport_vtbl;
1129     viewport->ref = 1;
1130     viewport->ddraw = ddraw;
1131     viewport->use_vp2 = 0xff;
1132 }