viewport.c 36.4 KB
Newer Older
1
/* Direct3D Viewport
2
 * Copyright (c) 1998 Lionel ULMER
3
 * Copyright (c) 2006-2007 Stefan DÖSINGER
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This file contains the implementation of Direct3DViewport2.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 28
#include <string.h>
#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 38
#include "wine/exception.h"

39 40
#include "ddraw.h"
#include "d3d.h"
41 42

#include "ddraw_private.h"
43
#include "wine/debug.h"
44

45
WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
46

47 48 49
/*****************************************************************************
 * Helper functions
 *****************************************************************************/
50

51 52 53 54 55 56
/*****************************************************************************
 * viewport_activate
 *
 * activates the viewport using IDirect3DDevice7::SetViewport
 *
 *****************************************************************************/
57
void viewport_activate(IDirect3DViewportImpl* This, BOOL ignore_lights) {
58
    IDirect3DLightImpl* light;
59
    D3DVIEWPORT7 vp;
60

61 62 63 64 65 66 67 68
    if (!ignore_lights) {
        /* Activate all the lights associated with this context */
        light = This->lights;

        while (light != NULL) {
            light->activate(light);
            light = light->next;
        }
69
    }
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

    /* And copy the values in the structure used by the device */
    if (This->use_vp2) {
        vp.dwX = This->viewports.vp2.dwX;
	vp.dwY = This->viewports.vp2.dwY;
	vp.dwHeight = This->viewports.vp2.dwHeight;
	vp.dwWidth = This->viewports.vp2.dwWidth;
	vp.dvMinZ = This->viewports.vp2.dvMinZ;
	vp.dvMaxZ = This->viewports.vp2.dvMaxZ;
    } else {
        vp.dwX = This->viewports.vp1.dwX;
	vp.dwY = This->viewports.vp1.dwY;
	vp.dwHeight = This->viewports.vp1.dwHeight;
	vp.dwWidth = This->viewports.vp1.dwWidth;
	vp.dvMinZ = This->viewports.vp1.dvMinZ;
	vp.dvMaxZ = This->viewports.vp1.dvMaxZ;
    }
    
    /* And also set the viewport */
89
    IDirect3DDevice7_SetViewport((IDirect3DDevice7 *)This->active_device, &vp);
90
}
91

92 93 94 95 96 97
/*****************************************************************************
 * _dump_D3DVIEWPORT, _dump_D3DVIEWPORT2
 *
 * Writes viewport information to TRACE
 *
 *****************************************************************************/
98
static void _dump_D3DVIEWPORT(const D3DVIEWPORT *lpvp)
99
{
100
    TRACE("    - dwSize = %d   dwX = %d   dwY = %d\n",
101
	  lpvp->dwSize, lpvp->dwX, lpvp->dwY);
102
    TRACE("    - dwWidth = %d   dwHeight = %d\n",
103 104 105 106 107 108 109
	  lpvp->dwWidth, lpvp->dwHeight);
    TRACE("    - dvScaleX = %f   dvScaleY = %f\n",
	  lpvp->dvScaleX, lpvp->dvScaleY);
    TRACE("    - dvMaxX = %f   dvMaxY = %f\n",
	  lpvp->dvMaxX, lpvp->dvMaxY);
    TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
	  lpvp->dvMinZ, lpvp->dvMaxZ);
110 111
}

112
static void _dump_D3DVIEWPORT2(const D3DVIEWPORT2 *lpvp)
113
{
114
    TRACE("    - dwSize = %d   dwX = %d   dwY = %d\n",
115
	  lpvp->dwSize, lpvp->dwX, lpvp->dwY);
116
    TRACE("    - dwWidth = %d   dwHeight = %d\n",
117 118 119 120 121 122 123
	  lpvp->dwWidth, lpvp->dwHeight);
    TRACE("    - dvClipX = %f   dvClipY = %f\n",
	  lpvp->dvClipX, lpvp->dvClipY);
    TRACE("    - dvClipWidth = %f   dvClipHeight = %f\n",
	  lpvp->dvClipWidth, lpvp->dvClipHeight);
    TRACE("    - dvMinZ = %f   dvMaxZ = %f\n",
	  lpvp->dvMinZ, lpvp->dvMaxZ);
124 125
}

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/*****************************************************************************
 * IUnknown Methods.
 *****************************************************************************/

/*****************************************************************************
 * IDirect3DViewport3::QueryInterface
 *
 * A normal QueryInterface. Can query all interface versions and the
 * IUnknown interface. The VTables of the different versions
 * are equal
 *
 * Params:
 *  refiid: Interface id queried for
 *  obj: Address to write the interface pointer to
 *
 * Returns:
 *  S_OK on success.
 *  E_NOINTERFACE if the requested interface wasn't found
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_QueryInterface(IDirect3DViewport3 *iface,
                                     REFIID riid,
                                     void **obp)
150
{
151
    TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), obp);
152 153 154 155 156 157 158

    *obp = NULL;

    if ( IsEqualGUID(&IID_IUnknown,  riid) ||
	 IsEqualGUID(&IID_IDirect3DViewport, riid) ||
	 IsEqualGUID(&IID_IDirect3DViewport2, riid) ||
	 IsEqualGUID(&IID_IDirect3DViewport3, riid) ) {
159 160
        IDirect3DViewport3_AddRef(iface);
        *obp = iface;
161 162 163
	TRACE("  Creating IDirect3DViewport1/2/3 interface %p\n", *obp);
	return S_OK;
    }
164
    FIXME("(%p): interface for IID %s NOT found!\n", iface, debugstr_guid(riid));
165
    return E_NOINTERFACE;
166 167
}

168 169 170 171 172 173 174 175 176 177 178
/*****************************************************************************
 * IDirect3DViewport3::AddRef
 *
 * Increases the refcount.
 *
 * Returns:
 *  The new refcount
 *
 *****************************************************************************/
static ULONG WINAPI
IDirect3DViewportImpl_AddRef(IDirect3DViewport3 *iface)
179
{
180
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
181 182
    ULONG ref = InterlockedIncrement(&This->ref);

183
    TRACE("(%p)->() incrementing from %u.\n", This, ref - 1);
184 185

    return ref;
186 187
}

188 189 190 191 192 193 194 195 196 197 198
/*****************************************************************************
 * IDirect3DViewport3::Release
 *
 * Reduces the refcount. If it falls to 0, the interface is released
 *
 * Returns:
 *  The new refcount
 *
 *****************************************************************************/
static ULONG WINAPI
IDirect3DViewportImpl_Release(IDirect3DViewport3 *iface)
199
{
200
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
201 202
    ULONG ref = InterlockedDecrement(&This->ref);

203
    TRACE("(%p)->() decrementing from %u.\n", This, ref + 1);
204 205

    if (!ref) {
206 207 208
        HeapFree(GetProcessHeap(), 0, This);
	return 0;
    }
209
    return ref;
210 211
}

212 213 214
/*****************************************************************************
 * IDirect3DViewport Methods.
 *****************************************************************************/
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
/*****************************************************************************
 * IDirect3DViewport3::Initialize
 *
 * No-op initialization.
 *
 * Params:
 *  Direct3D: The direct3D device this viewport is assigned to
 *
 * Returns:
 *  DDERR_ALREADYINITIALIZED
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_Initialize(IDirect3DViewport3 *iface,
                                 IDirect3D *Direct3D)
231
{
232 233
    TRACE("(%p)->(%p) no-op...\n", iface, Direct3D);
    return DDERR_ALREADYINITIALIZED;
234 235
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
/*****************************************************************************
 * IDirect3DViewport3::GetViewport
 *
 * Returns the viewport data assigned to this viewport interface
 *
 * Params:
 *  Data: Address to store the data
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Data is NULL
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_GetViewport(IDirect3DViewport3 *iface,
                                  D3DVIEWPORT *lpData)
252
{
253
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
254 255
    DWORD dwSize;
    TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
256 257

    EnterCriticalSection(&ddraw_cs);
258 259
    if (This->use_vp2 != 0) {
        ERR("  Requesting to get a D3DVIEWPORT struct where a D3DVIEWPORT2 was set !\n");
260 261
        LeaveCriticalSection(&ddraw_cs);
        return DDERR_INVALIDPARAMS;
262 263 264 265
    }
    dwSize = lpData->dwSize;
    memset(lpData, 0, dwSize);
    memcpy(lpData, &(This->viewports.vp1), dwSize);
266

267
    if (TRACE_ON(d3d7)) {
268
        TRACE("  returning D3DVIEWPORT :\n");
269 270
	_dump_D3DVIEWPORT(lpData);
    }
271 272
    LeaveCriticalSection(&ddraw_cs);

273
    return DD_OK;
274 275
}

276 277 278 279 280 281 282 283 284
/*****************************************************************************
 * IDirect3DViewport3::SetViewport
 *
 * Sets the viewport information for this interface
 *
 * Params:
 *  lpData: Viewport to set
 *
 * Returns:
285
 *  D3D_OK on success
286 287 288
 *  DDERR_INVALIDPARAMS if Data is NULL
 *
 *****************************************************************************/
289
static HRESULT WINAPI
290 291
IDirect3DViewportImpl_SetViewport(IDirect3DViewport3 *iface,
                                  D3DVIEWPORT *lpData)
292
{
293
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
294
    LPDIRECT3DVIEWPORT3 current_viewport;
295
    TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
296

297
    if (TRACE_ON(d3d7)) {
298 299 300
        TRACE("  getting D3DVIEWPORT :\n");
	_dump_D3DVIEWPORT(lpData);
    }
301

302
    EnterCriticalSection(&ddraw_cs);
303 304 305
    This->use_vp2 = 0;
    memset(&(This->viewports.vp1), 0, sizeof(This->viewports.vp1));
    memcpy(&(This->viewports.vp1), lpData, lpData->dwSize);
306

307
    /* Tests on two games show that these values are never used properly so override
308 309 310 311
       them with proper ones :-)
    */
    This->viewports.vp1.dvMinZ = 0.0;
    This->viewports.vp1.dvMaxZ = 1.0;
312 313

    if (This->active_device) {
314 315
        IDirect3DDevice3 *d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
        IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
316
        if (current_viewport) {
317
            if ((IDirect3DViewportImpl *)current_viewport == This) This->activate(This, FALSE);
318 319
            IDirect3DViewport3_Release(current_viewport);
        }
320
    }
321
    LeaveCriticalSection(&ddraw_cs);
322

323 324
    return DD_OK;
}
325

326 327 328 329 330
/*****************************************************************************
 * IDirect3DViewport3::TransformVertices
 *
 * Transforms vertices by the transformation matrix.
 *
331 332
 * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices,
 * 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 338 339
 * ProcessVertices doesn't pay of in terms of wrapper code needed and code
 * reused.
 *
340 341 342 343
 * Params:
 *  dwVertexCount: The number of vertices to be transformed
 *  lpData: Pointer to the vertex data
 *  dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED
344 345
 *  lpOffScreen: Set to the clipping plane clipping the vertex, if only one
 *               vertex is transformed and clipping is on. 0 otherwise
346 347
 *
 * Returns:
348 349 350
 *  D3D_OK on success
 *  D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device
 *  DDERR_INVALIDPARAMS if no clipping flag is specified
351 352 353 354 355 356 357 358
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
                                        DWORD dwVertexCount,
                                        D3DTRANSFORMDATA *lpData,
                                        DWORD dwFlags,
                                        DWORD *lpOffScreen)
359
{
360
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    D3DMATRIX view_mat, world_mat, proj_mat, mat;
    float *in;
    float *out;
    float x, y, z, w;
    unsigned int i;
    D3DVIEWPORT vp = This->viewports.vp1;
    D3DHVERTEX *outH;
    TRACE("(%p)->(%08x,%p,%08x,%p)\n", This, dwVertexCount, lpData, dwFlags, lpOffScreen);

    /* Tests on windows show that Windows crashes when this occurs,
     * so don't return the (intuitive) return value
    if(!This->active_device)
    {
        WARN("No device active, returning D3DERR_VIEWPORTHASNODEVICE\n");
        return D3DERR_VIEWPORTHASNODEVICE;
    }
     */

    if(!(dwFlags & (D3DTRANSFORM_UNCLIPPED | D3DTRANSFORM_CLIPPED)))
    {
        WARN("No clipping flag passed, returning DDERR_INVALIDPARAMS\n");
        return DDERR_INVALIDPARAMS;
    }


    EnterCriticalSection(&ddraw_cs);
    IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice,
                                D3DTRANSFORMSTATE_VIEW,
                                (WINED3DMATRIX*) &view_mat);

    IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice,
                                D3DTRANSFORMSTATE_PROJECTION,
                                (WINED3DMATRIX*) &proj_mat);

    IWineD3DDevice_GetTransform(This->active_device->wineD3DDevice,
                                WINED3DTS_WORLDMATRIX(0),
                                (WINED3DMATRIX*) &world_mat);
    multiply_matrix(&mat,&view_mat,&world_mat);
    multiply_matrix(&mat,&proj_mat,&mat);

401 402
    in = lpData->lpIn;
    out = lpData->lpOut;
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
    outH = lpData->lpHOut;
    for(i = 0; i < dwVertexCount; i++)
    {
        x = (in[0] * mat._11) + (in[1] * mat._21) + (in[2] * mat._31) + (1.0 * mat._41);
        y = (in[0] * mat._12) + (in[1] * mat._22) + (in[2] * mat._32) + (1.0 * mat._42);
        z = (in[0] * mat._13) + (in[1] * mat._23) + (in[2] * mat._33) + (1.0 * mat._43);
        w = (in[0] * mat._14) + (in[1] * mat._24) + (in[2] * mat._34) + (1.0 * mat._44);

        if(dwFlags & D3DTRANSFORM_CLIPPED)
        {
            /* If clipping is enabled, Windows assumes that outH is
             * a valid pointer
             */
            outH[i].u1.hx = x; outH[i].u2.hy = y; outH[i].u3.hz = z;

            outH[i].dwFlags = 0;
            if(x * vp.dvScaleX > ((float) vp.dwWidth * 0.5))
                outH[i].dwFlags |= D3DCLIP_RIGHT;
            if(x * vp.dvScaleX <= -((float) vp.dwWidth) * 0.5)
                outH[i].dwFlags |= D3DCLIP_LEFT;
            if(y * vp.dvScaleY > ((float) vp.dwHeight * 0.5))
                outH[i].dwFlags |= D3DCLIP_TOP;
            if(y * vp.dvScaleY <= -((float) vp.dwHeight) * 0.5)
                outH[i].dwFlags |= D3DCLIP_BOTTOM;
            if(z < 0.0)
                outH[i].dwFlags |= D3DCLIP_FRONT;
            if(z > 1.0)
                outH[i].dwFlags |= D3DCLIP_BACK;

            if(outH[i].dwFlags)
            {
                /* Looks like native just drops the vertex, leaves whatever data
                 * it has in the output buffer and goes on with the next vertex.
                 * The exact scheme hasn't been figured out yet, but windows
437
                 * definitely writes something there.
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
                 */
                out[0] = x;
                out[1] = y;
                out[2] = z;
                out[3] = w;
                in = (float *) ((char *) in + lpData->dwInSize);
                out = (float *) ((char *) out + lpData->dwOutSize);
                continue;
            }
        }

        w = 1 / w;
        x *= w; y *= w; z *= w;

        out[0] = vp.dwWidth / 2 + vp.dwX + x * vp.dvScaleX;
        out[1] = vp.dwHeight / 2 + vp.dwY - y * vp.dvScaleY;
        out[2] = z;
        out[3] = w;
        in = (float *) ((char *) in + lpData->dwInSize);
        out = (float *) ((char *) out + lpData->dwOutSize);
    }

    /* According to the d3d test, the offscreen flag is set only
     * if exactly one vertex is transformed. Its not documented,
     * but the test shows that the lpOffscreen flag is set to the
     * flag combination of clipping planes that clips the vertex.
     *
     * If clipping is requested, Windows assumes that the offscreen
     * param is a valid pointer.
     */
    if(dwVertexCount == 1 && dwFlags & D3DTRANSFORM_CLIPPED)
    {
        *lpOffScreen = outH[0].dwFlags;
    }
    else if(*lpOffScreen)
    {
        *lpOffScreen = 0;
    }
    LeaveCriticalSection(&ddraw_cs);

    TRACE("All done\n");
479
    return DD_OK;
480 481
}

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
/*****************************************************************************
 * IDirect3DViewport3::LightElements
 *
 * The DirectX 5.0 sdk says that it's not implemented
 *
 * Params:
 *  ?
 *
 * Returns:
 *  DDERR_UNSUPPORTED
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_LightElements(IDirect3DViewport3 *iface,
                                    DWORD dwElementCount,
                                    LPD3DLIGHTDATA lpData)
498
{
499
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
500
    TRACE("(%p)->(%08x,%p): Unimplemented!\n", This, dwElementCount, lpData);
501
    return DDERR_UNSUPPORTED;
502
}
503

504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
/*****************************************************************************
 * IDirect3DViewport3::SetBackground
 *
 * Sets tje background material
 *
 * Params:
 *  hMat: Handle from a IDirect3DMaterial interface
 *
 * Returns:
 *  D3D_OK on success
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_SetBackground(IDirect3DViewport3 *iface,
                                    D3DMATERIALHANDLE hMat)
519
{
520
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
521
    TRACE("(%p)->(%d)\n", This, hMat);
522

523
    EnterCriticalSection(&ddraw_cs);
524 525
    if(hMat && hMat > This->ddraw->d3ddevice->numHandles)
    {
526
        WARN("Specified Handle %d out of range\n", hMat);
527
        LeaveCriticalSection(&ddraw_cs);
528 529 530 531
        return DDERR_INVALIDPARAMS;
    }
    else if(hMat && This->ddraw->d3ddevice->Handles[hMat - 1].type != DDrawHandle_Material)
    {
532
        WARN("Handle %d is not a material handle\n", hMat);
533
        LeaveCriticalSection(&ddraw_cs);
534 535 536 537 538
        return DDERR_INVALIDPARAMS;
    }

    if(hMat)
    {
539
        This->background = This->ddraw->d3ddevice->Handles[hMat - 1].ptr;
540 541 542 543 544 545 546 547 548 549 550
        TRACE(" setting background color : %f %f %f %f\n",
              This->background->mat.u.diffuse.u1.r,
              This->background->mat.u.diffuse.u2.g,
              This->background->mat.u.diffuse.u3.b,
              This->background->mat.u.diffuse.u4.a);
    }
    else
    {
        This->background = NULL;
        TRACE("Setting background to NULL\n");
    }
551

552
    LeaveCriticalSection(&ddraw_cs);
553
    return D3D_OK;
554
}
555

556 557 558 559 560 561 562 563 564 565
/*****************************************************************************
 * IDirect3DViewport3::GetBackground
 *
 * Returns the material handle assigned to the background of the viewport
 *
 * Params:
 *  lphMat: Address to store the handle
 *  lpValid: is set to FALSE if no background is set, TRUE if one is set
 *
 * Returns:
566
 *  D3D_OK
567 568 569 570 571 572
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_GetBackground(IDirect3DViewport3 *iface,
                                    D3DMATERIALHANDLE *lphMat,
                                    BOOL *lpValid)
573
{
574
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
575 576
    TRACE("(%p)->(%p,%p)\n", This, lphMat, lpValid);

577
    EnterCriticalSection(&ddraw_cs);
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    if(lpValid)
    {
        *lpValid = This->background != NULL;
    }
    if(lphMat)
    {
        if(This->background)
        {
            *lphMat = This->background->Handle;
        }
        else
        {
            *lphMat = 0;
        }
    }
593
    LeaveCriticalSection(&ddraw_cs);
594

595
    return D3D_OK;
596
}
597

598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
/*****************************************************************************
 * IDirect3DViewport3::SetBackgroundDepth
 *
 * Sets a surface that represents the background depth. It's contents are
 * used to set the depth buffer in IDirect3DViewport3::Clear
 *
 * Params:
 *  lpDDSurface: Surface to set
 *
 * Returns: D3D_OK, because it's a stub
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_SetBackgroundDepth(IDirect3DViewport3 *iface,
                                         IDirectDrawSurface *lpDDSurface)
613
{
614
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
615 616
    FIXME("(%p)->(%p): stub!\n", This, lpDDSurface);
    return D3D_OK;
617
}
618

619 620 621 622 623 624 625
/*****************************************************************************
 * IDirect3DViewport3::GetBackgroundDepth
 *
 * Returns the surface that represents the depth field
 *
 * Params:
 *  lplpDDSurface: Address to store the interface pointer
Austin English's avatar
Austin English committed
626
 *  lpValid: Set to TRUE if a depth is assigned, FALSE otherwise
627 628 629 630 631 632 633 634 635 636
 *
 * Returns:
 *  D3D_OK, because it's a stub
 *  (DDERR_INVALIDPARAMS if DDSurface of Valid is NULL)
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_GetBackgroundDepth(IDirect3DViewport3 *iface,
                                         IDirectDrawSurface **lplpDDSurface,
                                         LPBOOL lpValid)
637
{
638
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
639
    FIXME("(%p)->(%p,%p): stub!\n", This, lplpDDSurface, lpValid);
640
    return DD_OK;
641 642
}

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
/*****************************************************************************
 * IDirect3DViewport3::Clear
 *
 * Clears the render target and / or the z buffer
 *
 * Params:
 *  dwCount: The amount of rectangles to clear. If 0, the whole buffer is
 *           cleared
 *  lpRects: Pointer to the array of rectangles. If NULL, Count must be 0
 *  dwFlags: D3DCLEAR_ZBUFFER and / or D3DCLEAR_TARGET
 *
 * Returns:
 *  D3D_OK on success
 *  D3DERR_VIEWPORTHASNODEVICE if there's no active device
 *  The return value of IDirect3DDevice7::Clear
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_Clear(IDirect3DViewport3 *iface,
                            DWORD dwCount, 
                            D3DRECT *lpRects,
                            DWORD dwFlags)
665
{
666
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
667
    DWORD color = 0x00000000;
668
    HRESULT hr;
669
    LPDIRECT3DVIEWPORT3 current_viewport;
670
    IDirect3DDevice3 *d3d_device3;
671

672
    TRACE("(%p/%p)->(%08x,%p,%08x)\n", This, iface, dwCount, lpRects, dwFlags);
673 674 675 676
    if (This->active_device == NULL) {
        ERR(" Trying to clear a viewport not attached to a device !\n");
	return D3DERR_VIEWPORTHASNODEVICE;
    }
677
    d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
678 679

    EnterCriticalSection(&ddraw_cs);
680 681 682 683 684 685 686 687 688 689 690
    if (dwFlags & D3DCLEAR_TARGET) {
        if (This->background == NULL) {
	    ERR(" Trying to clear the color buffer without background material !\n");
	} else {
	    color = 
	      ((int) ((This->background->mat.u.diffuse.u1.r) * 255) << 16) |
	      ((int) ((This->background->mat.u.diffuse.u2.g) * 255) <<  8) |
	      ((int) ((This->background->mat.u.diffuse.u3.b) * 255) <<  0) |
	      ((int) ((This->background->mat.u.diffuse.u4.a) * 255) << 24);
	}
    }
691

692 693 694 695
    /* Need to temporarily activate viewport to clear it. Previously active one will be restored
        afterwards. */
    This->activate(This, TRUE);

696 697
    hr = IDirect3DDevice7_Clear((IDirect3DDevice7 *)This->active_device, dwCount, lpRects,
            dwFlags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET), color, 1.0, 0x00000000);
698

699
    IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
700
    if(current_viewport) {
701
        IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)current_viewport;
702 703 704 705
        vp->activate(vp, TRUE);
        IDirect3DViewport3_Release(current_viewport);
    }

706 707
    LeaveCriticalSection(&ddraw_cs);
    return hr;
708
}
709

710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
/*****************************************************************************
 * IDirect3DViewport3::AddLight
 *
 * Adds an light to the viewport
 *
 * Params:
 *  lpDirect3DLight: Interface of the light to add
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if Direct3DLight is NULL
 *  DDERR_INVALIDPARAMS if there are 8 lights or more
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_AddLight(IDirect3DViewport3 *iface,
                               IDirect3DLight *lpDirect3DLight)
727
{
728
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
729
    IDirect3DLightImpl *lpDirect3DLightImpl = (IDirect3DLightImpl *)lpDirect3DLight;
730 731
    DWORD i = 0;
    DWORD map = This->map_lights;
732
    
733
    TRACE("(%p)->(%p)\n", This, lpDirect3DLight);
734 735

    EnterCriticalSection(&ddraw_cs);
736
    if (This->num_lights >= 8)
737 738
    {
        LeaveCriticalSection(&ddraw_cs);
739
        return DDERR_INVALIDPARAMS;
740
    }
741 742 743 744 745 746 747 748 749 750

    /* Find a light number and update both light and viewports objects accordingly */
    while(map&1) {
        map>>=1;
	i++;
    }
    lpDirect3DLightImpl->dwLightIndex = i;
    This->num_lights++;
    This->map_lights |= 1<<i;

751 752 753
    /* Add the light in the 'linked' chain */
    lpDirect3DLightImpl->next = This->lights;
    This->lights = lpDirect3DLightImpl;
754
    IDirect3DLight_AddRef(lpDirect3DLight);
755

756 757 758
    /* Attach the light to the viewport */
    lpDirect3DLightImpl->active_viewport = This;
    
759 760 761 762
    /* If active, activate the light */
    if (This->active_device != NULL) {
        lpDirect3DLightImpl->activate(lpDirect3DLightImpl);
    }
763 764

    LeaveCriticalSection(&ddraw_cs);
765
    return D3D_OK;
766 767
}

768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
/*****************************************************************************
 * IDirect3DViewport3::DeleteLight
 *
 * Deletes a light from the viewports' light list
 *
 * Params:
 *  lpDirect3DLight: Light to delete
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if the light wasn't found
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_DeleteLight(IDirect3DViewport3 *iface,
                                  IDirect3DLight *lpDirect3DLight)
784
{
785
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
786
    IDirect3DLightImpl *lpDirect3DLightImpl = (IDirect3DLightImpl *)lpDirect3DLight;
787 788
    IDirect3DLightImpl *cur_light, *prev_light = NULL;
    
789
    TRACE("(%p)->(%p)\n", This, lpDirect3DLight);
790 791

    EnterCriticalSection(&ddraw_cs);
792 793 794 795 796 797
    cur_light = This->lights;
    while (cur_light != NULL) {
        if (cur_light == lpDirect3DLightImpl) {
	    lpDirect3DLightImpl->desactivate(lpDirect3DLightImpl);
	    if (prev_light == NULL) This->lights = cur_light->next;
	    else prev_light->next = cur_light->next;
798 799
	    /* Detach the light to the viewport */
	    cur_light->active_viewport = NULL;
800
	    IDirect3DLight_Release( (IDirect3DLight *)cur_light );
801 802
	    This->num_lights--;
	    This->map_lights &= ~(1<<lpDirect3DLightImpl->dwLightIndex);
803 804
            LeaveCriticalSection(&ddraw_cs);
            return D3D_OK;
805 806 807 808
	}
	prev_light = cur_light;
	cur_light = cur_light->next;
    }
809 810
    LeaveCriticalSection(&ddraw_cs);

811 812
    return DDERR_INVALIDPARAMS;
}
813

814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
/*****************************************************************************
 * IDirect3DViewport::NextLight
 *
 * Enumerates the lights associated with the viewport
 *
 * Params:
 *  lpDirect3DLight: Light to start with
 *  lplpDirect3DLight: Address to store the successor to
 *
 * Returns:
 *  D3D_OK, because it's a stub
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_NextLight(IDirect3DViewport3 *iface,
                                IDirect3DLight *lpDirect3DLight,
                                IDirect3DLight **lplpDirect3DLight,
                                DWORD dwFlags)
832
{
833
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
    IDirect3DLightImpl *cur_light, *prev_light = NULL;

    TRACE("(%p)->(%p,%p,%08x)\n", This, lpDirect3DLight, lplpDirect3DLight, dwFlags);

    if (!lplpDirect3DLight)
        return DDERR_INVALIDPARAMS;

    *lplpDirect3DLight = NULL;

    EnterCriticalSection(&ddraw_cs);

    cur_light = This->lights;

    switch (dwFlags) {
        case D3DNEXT_NEXT:
            if (!lpDirect3DLight) {
                LeaveCriticalSection(&ddraw_cs);
                return DDERR_INVALIDPARAMS;
            }
            while (cur_light != NULL) {
                if (cur_light == (IDirect3DLightImpl *)lpDirect3DLight) {
                    *lplpDirect3DLight = (IDirect3DLight*)cur_light->next;
                    break;
                }
                cur_light = cur_light->next;
            }
            break;
        case D3DNEXT_HEAD:
            *lplpDirect3DLight = (IDirect3DLight*)This->lights;
            break;
        case D3DNEXT_TAIL:
            while (cur_light != NULL) {
                prev_light = cur_light;
                cur_light = cur_light->next;
            }
            *lplpDirect3DLight = (IDirect3DLight*)prev_light;
            break;
        default:
            ERR("Unknown flag %d\n", dwFlags);
            break;
    }

876 877 878
    if (*lplpDirect3DLight)
        IDirect3DLight_AddRef(*lplpDirect3DLight);

879 880 881
    LeaveCriticalSection(&ddraw_cs);

    return *lplpDirect3DLight ? D3D_OK : DDERR_INVALIDPARAMS;
882 883
}

884 885 886 887 888 889 890 891
/*****************************************************************************
 * IDirect3DViewport2 Methods.
 *****************************************************************************/

/*****************************************************************************
 * IDirect3DViewport3::GetViewport2
 *
 * Returns the currently set viewport in a D3DVIEWPORT2 structure.
892
 * Similar to IDirect3DViewport3::GetViewport
893 894 895 896 897 898 899 900 901 902 903 904 905 906
 *
 * Params:
 *  lpData: Pointer to the structure to fill
 *
 * Returns:
 *  D3D_OK on success
 *  DDERR_INVALIDPARAMS if the viewport was set with
 *                      IDirect3DViewport3::SetViewport
 *  DDERR_INVALIDPARAMS if Data is NULL
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_GetViewport2(IDirect3DViewport3 *iface,
                                   D3DVIEWPORT2 *lpData)
907
{
908
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
909
    DWORD dwSize;
910
    TRACE("(%p)->(%p)\n", This, lpData);
911 912

    EnterCriticalSection(&ddraw_cs);
913 914
    if (This->use_vp2 != 1) {
        ERR("  Requesting to get a D3DVIEWPORT2 struct where a D3DVIEWPORT was set !\n");
915 916
        LeaveCriticalSection(&ddraw_cs);
        return DDERR_INVALIDPARAMS;
917 918 919 920
    }
    dwSize = lpData->dwSize;
    memset(lpData, 0, dwSize);
    memcpy(lpData, &(This->viewports.vp2), dwSize);
921

922
    if (TRACE_ON(d3d7)) {
923
        TRACE("  returning D3DVIEWPORT2 :\n");
924 925
	_dump_D3DVIEWPORT2(lpData);
    }
926 927

    LeaveCriticalSection(&ddraw_cs);
928
    return D3D_OK;
929 930
}

931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
/*****************************************************************************
 * IDirect3DViewport3::SetViewport2
 *
 * Sets the viewport from a D3DVIEWPORT2 structure
 *
 * Params:
 *  lpData: Viewport to set
 *
 * Returns:
 *  D3D_OK on success
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_SetViewport2(IDirect3DViewport3 *iface,
                                   D3DVIEWPORT2 *lpData)
946
{
947
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
948
    LPDIRECT3DVIEWPORT3 current_viewport;
949
    TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
950

951
    if (TRACE_ON(d3d7)) {
952 953 954 955
        TRACE("  getting D3DVIEWPORT2 :\n");
	_dump_D3DVIEWPORT2(lpData);
    }

956
    EnterCriticalSection(&ddraw_cs);
957 958 959
    This->use_vp2 = 1;
    memset(&(This->viewports.vp2), 0, sizeof(This->viewports.vp2));
    memcpy(&(This->viewports.vp2), lpData, lpData->dwSize);
960 961

    if (This->active_device) {
962 963
        IDirect3DDevice3 *d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
        IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
964
        if (current_viewport) {
965
            if ((IDirect3DViewportImpl *)current_viewport == This) This->activate(This, FALSE);
966 967
            IDirect3DViewport3_Release(current_viewport);
        }
968
    }
969
    LeaveCriticalSection(&ddraw_cs);
970

971
    return D3D_OK;
972 973
}

974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
/*****************************************************************************
 * IDirect3DViewport3 Methods.
 *****************************************************************************/

/*****************************************************************************
 * IDirect3DViewport3::SetBackgroundDepth2
 *
 * Sets a IDirectDrawSurface4 surface as the background depth surface
 *
 * Params:
 *  lpDDS: Surface to set
 *
 * Returns:
 *  D3D_OK, because it's stub
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_SetBackgroundDepth2(IDirect3DViewport3 *iface,
                                          IDirectDrawSurface4 *lpDDS)
993
{
994
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
995 996
    FIXME("(%p)->(%p): stub!\n", This, lpDDS);
    return D3D_OK;
997 998
}

999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
/*****************************************************************************
 * IDirect3DViewport3::GetBackgroundDepth2
 *
 * Returns the IDirect3DSurface4 interface to the background depth surface
 *
 * Params:
 *  lplpDDS: Address to store the interface pointer at
 *  lpValid: Set to true if a surface is assigned
 *
 * Returns:
 *  D3D_OK because it's a stub
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_GetBackgroundDepth2(IDirect3DViewport3 *iface,
                                          IDirectDrawSurface4 **lplpDDS,
                                          BOOL *lpValid)
1016
{
1017
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
1018
    FIXME("(%p/%p)->(%p,%p): stub!\n", This, iface, lplpDDS, lpValid);
1019
    return D3D_OK;
1020
}
1021

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
/*****************************************************************************
 * IDirect3DViewport3::Clear2
 *
 * Another clearing method
 *
 * Params:
 *  Count: Number of rectangles to clear
 *  Rects: Rectangle array to clear
 *  Flags: Some flags :)
 *  Color: Color to fill the render target with
 *  Z: Value to fill the depth buffer with
 *  Stencil: Value to fill the stencil bits with
 *
 * Returns:
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_Clear2(IDirect3DViewport3 *iface,
                             DWORD dwCount,
                             LPD3DRECT lpRects,
                             DWORD dwFlags,
                             DWORD dwColor,
                             D3DVALUE dvZ,
                             DWORD dwStencil)
1046
{
1047
    IDirect3DViewportImpl *This = (IDirect3DViewportImpl *)iface;
1048
    HRESULT hr;
1049
    LPDIRECT3DVIEWPORT3 current_viewport;
1050
    IDirect3DDevice3 *d3d_device3;
1051
    TRACE("(%p)->(%08x,%p,%08x,%08x,%f,%08x)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
1052 1053

    EnterCriticalSection(&ddraw_cs);
1054 1055
    if (This->active_device == NULL) {
        ERR(" Trying to clear a viewport not attached to a device !\n");
1056 1057
        LeaveCriticalSection(&ddraw_cs);
        return D3DERR_VIEWPORTHASNODEVICE;
1058
    }
1059
    d3d_device3 = (IDirect3DDevice3 *)&This->active_device->IDirect3DDevice3_vtbl;
1060 1061 1062 1063
    /* Need to temporarily activate viewport to clear it. Previously active one will be restored
        afterwards. */
    This->activate(This, TRUE);

1064 1065 1066
    hr = IDirect3DDevice7_Clear((IDirect3DDevice7 *)This->active_device,
            dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
    IDirect3DDevice3_GetCurrentViewport(d3d_device3, &current_viewport);
1067
    if(current_viewport) {
1068
        IDirect3DViewportImpl *vp = (IDirect3DViewportImpl *)current_viewport;
1069 1070 1071
        vp->activate(vp, TRUE);
        IDirect3DViewport3_Release(current_viewport);
    }
1072 1073
    LeaveCriticalSection(&ddraw_cs);
    return hr;
1074 1075
}

1076 1077 1078
/*****************************************************************************
 * The VTable
 *****************************************************************************/
1079

1080
const IDirect3DViewport3Vtbl IDirect3DViewport3_Vtbl =
1081
{
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
    /*** IUnknown Methods ***/
    IDirect3DViewportImpl_QueryInterface,
    IDirect3DViewportImpl_AddRef,
    IDirect3DViewportImpl_Release,
    /*** IDirect3DViewport Methods */
    IDirect3DViewportImpl_Initialize,
    IDirect3DViewportImpl_GetViewport,
    IDirect3DViewportImpl_SetViewport,
    IDirect3DViewportImpl_TransformVertices,
    IDirect3DViewportImpl_LightElements,
    IDirect3DViewportImpl_SetBackground,
    IDirect3DViewportImpl_GetBackground,
    IDirect3DViewportImpl_SetBackgroundDepth,
    IDirect3DViewportImpl_GetBackgroundDepth,
    IDirect3DViewportImpl_Clear,
    IDirect3DViewportImpl_AddLight,
    IDirect3DViewportImpl_DeleteLight,
    IDirect3DViewportImpl_NextLight,
    /*** IDirect3DViewport2 Methods ***/
    IDirect3DViewportImpl_GetViewport2,
    IDirect3DViewportImpl_SetViewport2,
    /*** IDirect3DViewport3 Methods ***/
    IDirect3DViewportImpl_SetBackgroundDepth2,
    IDirect3DViewportImpl_GetBackgroundDepth2,
    IDirect3DViewportImpl_Clear2,
1107
};