viewport.c 35.6 KB
Newer Older
1
/* Direct3D Viewport
2
 * Copyright (c) 1998 Lionel ULMER
3
 * Copyright (c) 2006-2007 Stefan DSINGER
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 89

    /* 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 */
    IDirect3DDevice7_SetViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice7), &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
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
152
    TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), obp);
153 154 155 156 157 158 159 160 161 162 163 164 165

    *obp = NULL;

    if ( IsEqualGUID(&IID_IUnknown,  riid) ||
	 IsEqualGUID(&IID_IDirect3DViewport, riid) ||
	 IsEqualGUID(&IID_IDirect3DViewport2, riid) ||
	 IsEqualGUID(&IID_IDirect3DViewport3, riid) ) {
        IDirect3DViewport3_AddRef(ICOM_INTERFACE(This, IDirect3DViewport3));
        *obp = ICOM_INTERFACE(This, IDirect3DViewport3);
	TRACE("  Creating IDirect3DViewport1/2/3 interface %p\n", *obp);
	return S_OK;
    }
    FIXME("(%p): interface for IID %s NOT found!\n", This, debugstr_guid(riid));
166
    return E_NOINTERFACE;
167 168
}

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

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

    return ref;
187 188
}

189 190 191 192 193 194 195 196 197 198 199
/*****************************************************************************
 * 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)
200
{
201
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
202 203
    ULONG ref = InterlockedDecrement(&This->ref);

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

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

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

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
/*****************************************************************************
 * 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)
232
{
233 234
    TRACE("(%p)->(%p) no-op...\n", iface, Direct3D);
    return DDERR_ALREADYINITIALIZED;
235 236
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
/*****************************************************************************
 * 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)
253
{
254 255 256
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
    DWORD dwSize;
    TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
257 258

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

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

274
    return DD_OK;
275 276
}

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

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

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

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

    if (This->active_device) {
315 316 317 318 319 320
        IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), &current_viewport);
        if (current_viewport) {
            if (ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport) == This)
                This->activate(This, FALSE);
            IDirect3DViewport3_Release(current_viewport);
        }
321
    }
322
    LeaveCriticalSection(&ddraw_cs);
323

324 325
    return DD_OK;
}
326

327 328 329 330 331
/*****************************************************************************
 * IDirect3DViewport3::TransformVertices
 *
 * Transforms vertices by the transformation matrix.
 *
332 333
 * This function is pretty similar to IDirect3DVertexBuffer7::ProcessVertices,
 * so it's tempting to forward it to there. However, there are some
334
 * tiny differences. First, the lpOffscreen flag that is reported back,
335
 * then there is the homogeneous vertex that is generated. Also there's a lack
336
 * of FVFs, but still a custom stride. Last, the d3d1 - d3d3 viewport has some
337
 * settings (scale) that d3d7 and wined3d do not have. All in all wrapping to
338 339 340
 * ProcessVertices doesn't pay of in terms of wrapper code needed and code
 * reused.
 *
341 342 343 344
 * Params:
 *  dwVertexCount: The number of vertices to be transformed
 *  lpData: Pointer to the vertex data
 *  dwFlags: D3DTRANSFORM_CLIPPED or D3DTRANSFORM_UNCLIPPED
345 346
 *  lpOffScreen: Set to the clipping plane clipping the vertex, if only one
 *               vertex is transformed and clipping is on. 0 otherwise
347 348
 *
 * Returns:
349 350 351
 *  D3D_OK on success
 *  D3DERR_VIEWPORTHASNODEVICE if the viewport is not assigned to a device
 *  DDERR_INVALIDPARAMS if no clipping flag is specified
352 353 354 355 356 357 358 359
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_TransformVertices(IDirect3DViewport3 *iface,
                                        DWORD dwVertexCount,
                                        D3DTRANSFORMDATA *lpData,
                                        DWORD dwFlags,
                                        DWORD *lpOffScreen)
360 361
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
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 401 402 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 437
    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);

    in = (float *) lpData->lpIn;
    out = (float *) lpData->lpOut;
    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
438
                 * definitely writes something there.
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 479
                 */
                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");
480
    return DD_OK;
481 482
}

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
/*****************************************************************************
 * 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)
499
{
500
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
501
    TRACE("(%p)->(%08x,%p): Unimplemented!\n", This, dwElementCount, lpData);
502
    return DDERR_UNSUPPORTED;
503
}
504

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
/*****************************************************************************
 * 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)
520 521
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
522
    TRACE("(%p)->(%d)\n", This, hMat);
523

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

    if(hMat)
    {
        This->background = (IDirect3DMaterialImpl *) This->ddraw->d3ddevice->Handles[hMat - 1].ptr;
        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");
    }
552

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

557 558 559 560 561 562 563 564 565 566
/*****************************************************************************
 * 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:
567
 *  D3D_OK
568 569 570 571 572 573
 *
 *****************************************************************************/
static HRESULT WINAPI
IDirect3DViewportImpl_GetBackground(IDirect3DViewport3 *iface,
                                    D3DMATERIALHANDLE *lphMat,
                                    BOOL *lpValid)
574 575
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
576 577
    TRACE("(%p)->(%p,%p)\n", This, lphMat, lpValid);

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

596
    return D3D_OK;
597
}
598

599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
/*****************************************************************************
 * 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)
614 615
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
616 617
    FIXME("(%p)->(%p): stub!\n", This, lpDDSurface);
    return D3D_OK;
618
}
619

620 621 622 623 624 625 626
/*****************************************************************************
 * 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
627
 *  lpValid: Set to TRUE if a depth is assigned, FALSE otherwise
628 629 630 631 632 633 634 635 636 637
 *
 * 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)
638 639
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
640
    FIXME("(%p)->(%p,%p): stub!\n", This, lplpDDSurface, lpValid);
641
    return DD_OK;
642 643
}

644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
/*****************************************************************************
 * 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)
666
{
667
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
668
    DWORD color = 0x00000000;
669
    HRESULT hr;
670
    LPDIRECT3DVIEWPORT3 current_viewport;
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 678

    EnterCriticalSection(&ddraw_cs);
679 680 681 682 683 684 685 686 687 688 689
    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);
	}
    }
690

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

695 696 697 698 699 700 701
    hr = IDirect3DDevice7_Clear(ICOM_INTERFACE(This->active_device, IDirect3DDevice7),
                                dwCount,
                                lpRects,
                                dwFlags & (D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET),
                                color,
                                1.0,
                                0x00000000);
702 703 704 705 706 707 708 709

    IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), &current_viewport);
    if(current_viewport) {
        IDirect3DViewportImpl *vp = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport);
        vp->activate(vp, TRUE);
        IDirect3DViewport3_Release(current_viewport);
    }

710 711
    LeaveCriticalSection(&ddraw_cs);
    return hr;
712
}
713

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
/*****************************************************************************
 * 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)
731 732 733
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
    IDirect3DLightImpl *lpDirect3DLightImpl = ICOM_OBJECT(IDirect3DLightImpl, IDirect3DLight, lpDirect3DLight);
734 735
    DWORD i = 0;
    DWORD map = This->map_lights;
736
    
737
    TRACE("(%p)->(%p)\n", This, lpDirect3DLight);
738 739

    EnterCriticalSection(&ddraw_cs);
740
    if (This->num_lights >= 8)
741 742
    {
        LeaveCriticalSection(&ddraw_cs);
743
        return DDERR_INVALIDPARAMS;
744
    }
745 746 747 748 749 750 751 752 753 754

    /* 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;

755 756 757 758
    /* Add the light in the 'linked' chain */
    lpDirect3DLightImpl->next = This->lights;
    This->lights = lpDirect3DLightImpl;

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

    LeaveCriticalSection(&ddraw_cs);
768
    return D3D_OK;
769 770
}

771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
/*****************************************************************************
 * 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)
787
{
788 789 790 791
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
    IDirect3DLightImpl *lpDirect3DLightImpl = ICOM_OBJECT(IDirect3DLightImpl, IDirect3DLight, lpDirect3DLight);
    IDirect3DLightImpl *cur_light, *prev_light = NULL;
    
792
    TRACE("(%p)->(%p)\n", This, lpDirect3DLight);
793 794

    EnterCriticalSection(&ddraw_cs);
795 796 797 798 799 800
    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;
801 802 803 804
	    /* Detach the light to the viewport */
	    cur_light->active_viewport = NULL;
	    This->num_lights--;
	    This->map_lights &= ~(1<<lpDirect3DLightImpl->dwLightIndex);
805 806
            LeaveCriticalSection(&ddraw_cs);
            return D3D_OK;
807 808 809 810
	}
	prev_light = cur_light;
	cur_light = cur_light->next;
    }
811 812
    LeaveCriticalSection(&ddraw_cs);

813 814
    return DDERR_INVALIDPARAMS;
}
815

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
/*****************************************************************************
 * 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)
834 835
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
836
    FIXME("(%p)->(%p,%p,%08x): stub!\n", This, lpDirect3DLight, lplpDirect3DLight, dwFlags);
837
    return D3D_OK;
838 839
}

840 841 842 843 844 845 846 847
/*****************************************************************************
 * IDirect3DViewport2 Methods.
 *****************************************************************************/

/*****************************************************************************
 * IDirect3DViewport3::GetViewport2
 *
 * Returns the currently set viewport in a D3DVIEWPORT2 structure.
848
 * Similar to IDirect3DViewport3::GetViewport
849 850 851 852 853 854 855 856 857 858 859 860 861 862
 *
 * 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)
863
{
864 865
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
    DWORD dwSize;
866
    TRACE("(%p)->(%p)\n", This, lpData);
867 868

    EnterCriticalSection(&ddraw_cs);
869 870
    if (This->use_vp2 != 1) {
        ERR("  Requesting to get a D3DVIEWPORT2 struct where a D3DVIEWPORT was set !\n");
871 872
        LeaveCriticalSection(&ddraw_cs);
        return DDERR_INVALIDPARAMS;
873 874 875 876
    }
    dwSize = lpData->dwSize;
    memset(lpData, 0, dwSize);
    memcpy(lpData, &(This->viewports.vp2), dwSize);
877

878
    if (TRACE_ON(d3d7)) {
879
        TRACE("  returning D3DVIEWPORT2 :\n");
880 881
	_dump_D3DVIEWPORT2(lpData);
    }
882 883

    LeaveCriticalSection(&ddraw_cs);
884
    return D3D_OK;
885 886
}

887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
/*****************************************************************************
 * 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)
902
{
903
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
904
    LPDIRECT3DVIEWPORT3 current_viewport;
905
    TRACE("(%p/%p)->(%p)\n", This, iface, lpData);
906

907
    if (TRACE_ON(d3d7)) {
908 909 910 911
        TRACE("  getting D3DVIEWPORT2 :\n");
	_dump_D3DVIEWPORT2(lpData);
    }

912
    EnterCriticalSection(&ddraw_cs);
913 914 915
    This->use_vp2 = 1;
    memset(&(This->viewports.vp2), 0, sizeof(This->viewports.vp2));
    memcpy(&(This->viewports.vp2), lpData, lpData->dwSize);
916 917

    if (This->active_device) {
918 919 920 921 922 923
        IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), &current_viewport);
        if (current_viewport) {
            if (ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport) == This)
                This->activate(This, FALSE);
            IDirect3DViewport3_Release(current_viewport);
        }
924
    }
925
    LeaveCriticalSection(&ddraw_cs);
926

927
    return D3D_OK;
928 929
}

930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
/*****************************************************************************
 * 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)
949
{
950
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
951 952
    FIXME("(%p)->(%p): stub!\n", This, lpDDS);
    return D3D_OK;
953 954
}

955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
/*****************************************************************************
 * 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)
972
{
973 974
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
    FIXME("(%p/%p)->(%p,%p): stub!\n", This, iface, lplpDDS, lpValid);
975
    return D3D_OK;
976
}
977

978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
/*****************************************************************************
 * 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)
1002 1003
{
    ICOM_THIS_FROM(IDirect3DViewportImpl, IDirect3DViewport3, iface);
1004
    HRESULT hr;
1005
    LPDIRECT3DVIEWPORT3 current_viewport;
1006
    TRACE("(%p)->(%08x,%p,%08x,%08x,%f,%08x)\n", This, dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
1007 1008

    EnterCriticalSection(&ddraw_cs);
1009 1010
    if (This->active_device == NULL) {
        ERR(" Trying to clear a viewport not attached to a device !\n");
1011 1012
        LeaveCriticalSection(&ddraw_cs);
        return D3DERR_VIEWPORTHASNODEVICE;
1013
    }
1014 1015 1016 1017
    /* Need to temporarily activate viewport to clear it. Previously active one will be restored
        afterwards. */
    This->activate(This, TRUE);

1018 1019 1020 1021 1022 1023 1024
    hr = IDirect3DDevice7_Clear(ICOM_INTERFACE(This->active_device, IDirect3DDevice7),
                                dwCount,
                                lpRects,
                                dwFlags,
                                dwColor,
                                dvZ,
                                dwStencil);
1025 1026 1027 1028 1029 1030
    IDirect3DDevice3_GetCurrentViewport(ICOM_INTERFACE(This->active_device, IDirect3DDevice3), &current_viewport);
    if(current_viewport) {
        IDirect3DViewportImpl *vp = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, current_viewport);
        vp->activate(vp, TRUE);
        IDirect3DViewport3_Release(current_viewport);
    }
1031 1032
    LeaveCriticalSection(&ddraw_cs);
    return hr;
1033 1034
}

1035 1036 1037
/*****************************************************************************
 * The VTable
 *****************************************************************************/
1038

1039
const IDirect3DViewport3Vtbl IDirect3DViewport3_Vtbl =
1040
{
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
    /*** 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,
1066
};