/*==========================================================================; * * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved. * * File: vwport.c * Content: Direct3D viewport functions *@@BEGIN_MSINTERNAL * * $Id: vwport.c,v 1.25 1995/12/04 11:29:49 sjl Exp $ * * History: * Date By Reason * ==== == ====== * 05/11/95 stevela Initial rev with this header. *@@END_MSINTERNAL * ***************************************************************************/ #include "pch.cpp" #pragma hdrstop /* * Create an api for the Direct3DViewport object */ #include "d3dfei.h" #include "drawprim.hpp" extern void UpdateViewportCache(LPDIRECT3DDEVICEI device, D3DVIEWPORT2 *data); //--------------------------------------------------------------------- // // Compute inverse Mclip matrix // void updateInverseMclip(LPDIRECT3DDEVICEI lpDevI) { D3DFE_VIEWPORTCACHE& VPORT = lpDevI->vcache; VPORT.imclip11 = D3DVAL(1)/VPORT.mclip11; VPORT.imclip41 = - VPORT.imclip11 * VPORT.mclip41; VPORT.imclip22 = D3DVAL(1)/VPORT.mclip22; VPORT.imclip42 = - VPORT.imclip22 * VPORT.mclip42; VPORT.imclip33 = D3DVAL(1)/VPORT.mclip33; VPORT.imclip43 = VPORT.imclip33 * VPORT.mclip43; } //--------------------------------------------------------------------- HRESULT downloadView(LPDIRECT3DVIEWPORTI lpViewI) { HRESULT err; if (!lpViewI->v_data_is_set) { D3D_ERR("SetViewport not called for viewport yet"); return D3DERR_VIEWPORTDATANOTSET; } LPDIRECT3DDEVICEI lpDevI = lpViewI->lpDevI; // Update front-end data UpdateViewportCache(lpDevI, &lpViewI->v_data); // Download viewport data if ((err = lpDevI->UpdateDrvViewInfo(&lpViewI->v_data)) != DD_OK) { return err; } lpViewI->bLightsChanged = TRUE; // Force setLights call lpDevI->v_id = lpViewI->v_id; return (D3D_OK); } //--------------------------------------------------------------------- // Viewport ID could be different from Device->v_id, because during Execute call // Device->v_id is changed to whatever viewport is used as a parameter. // So we have to make sure that we use the right viewport. // inline HRESULT ValidateViewport(LPDIRECT3DDEVICEI lpDevI, LPDIRECT3DVIEWPORTI lpView) { #if DBG if (!VALID_DIRECT3DDEVICE3_PTR(lpDevI)) { D3D_ERR( "Viewport not attached to Device" ); return D3DERR_VIEWPORTHASNODEVICE; } #endif if (lpDevI->v_id != lpView->v_id) { return downloadView(lpView); } else return D3D_OK; } HRESULT hookViewportToD3D(LPDIRECT3DI lpDirect3DI, LPDIRECT3DVIEWPORTI lpD3DView) { LIST_INSERT_ROOT(&lpDirect3DI->viewports, lpD3DView, list); lpD3DView->lpDirect3DI = lpDirect3DI; lpDirect3DI->numViewports++; return (D3D_OK); } HRESULT D3DAPI DIRECT3DVIEWPORTI::Initialize(LPDIRECT3D lpD3D) { return DDERR_ALREADYINITIALIZED; } /* * Light Management */ HRESULT hookLightToViewport(LPDIRECT3DVIEWPORTI lpD3DViewI, LPDIRECT3DLIGHTI lpD3DLight) { CIRCLE_QUEUE_INSERT_END(&lpD3DViewI->lights, DIRECT3DLIGHTI, lpD3DLight, light_list); lpD3DLight->lpD3DViewportI = lpD3DViewI; lpD3DViewI->numLights++; return (D3D_OK); } HRESULT setLights(LPDIRECT3DVIEWPORTI lpView) { LPDIRECT3DDEVICEI lpDevI; LPDIRECT3DLIGHTI lpD3DLightI; int i; lpDevI = lpView->lpDevI; lpD3DLightI = (LPDIRECT3DLIGHTI)CIRCLE_QUEUE_FIRST(&lpView->lights); D3DFE_LIGHTING& LIGHTING = lpDevI->lighting; LIGHTING.activeLights = NULL; // Set lights in the device for (i = 0; i < lpView->numLights; i++) { if (lpD3DLightI->diLightData.valid && lpD3DLightI->diLightData.flags & D3DLIGHT_ACTIVE) { lpD3DLightI->diLightData.next = LIGHTING.activeLights; LIGHTING.activeLights = &lpD3DLightI->diLightData; } lpD3DLightI = CIRCLE_QUEUE_NEXT(&lpView->lights,lpD3DLightI,light_list); } lpDevI->dwFEFlags |= (D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_LIGHTS_DIRTY); return (D3D_OK); } /* * Create the Viewport */ #undef DPF_MODNAME #define DPF_MODNAME "Direct3D::CreateViewport" HRESULT D3DAPI DIRECT3DI::CreateViewport(LPDIRECT3DVIEWPORT* lplpD3DView, IUnknown *pUnkOuter) { return CreateViewport((LPDIRECT3DVIEWPORT3*)lplpD3DView, NULL); } HRESULT D3DAPI DIRECT3DI::CreateViewport(LPDIRECT3DVIEWPORT2* lplpD3DView2, IUnknown *pUnkOuter) { return CreateViewport((LPDIRECT3DVIEWPORT3*)lplpD3DView2, NULL); } HRESULT D3DAPI DIRECT3DI::CreateViewport(LPDIRECT3DVIEWPORT3* lplpD3DView, IUnknown *pUnkOuter) { LPDIRECT3DVIEWPORTI lpView; HRESULT ret = D3D_OK; if(pUnkOuter != NULL) { return CLASS_E_NOAGGREGATION; } CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ if (!VALID_DIRECT3D3_PTR(this)) { D3D_ERR( "Invalid Direct3D pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_OUTPTR(lplpD3DView)) { D3D_ERR( "Invalid pointer to pointer pointer" ); return DDERR_INVALIDPARAMS; } *lplpD3DView = NULL; lpView = new DIRECT3DVIEWPORTI(this); if (!lpView) { D3D_ERR("failed to allocate space for object"); return (DDERR_OUTOFMEMORY); } /* * Put this device in the list of those owned by the * Direct3D object */ ret = hookViewportToD3D(this, lpView); if (ret != D3D_OK) { D3D_ERR("failed to associate viewport to Direct3D"); delete lpView; return (ret); } *lplpD3DView = (LPDIRECT3DVIEWPORT3)lpView; return (D3D_OK); } DIRECT3DVIEWPORTI::DIRECT3DVIEWPORTI(LPDIRECT3DI lpD3DI) { /* * setup the object */ /*** Object Data ***/ memset(&v_data, 0, sizeof(D3DVIEWPORT2)); v_data_is_set = FALSE; bHaveBackgndMat=FALSE; hBackgndMat=NULL; lpDDSBackgndDepth=NULL; clrCount=0; clrRects=NULL; refCnt = 1; lpDevI=NULL; v_id = lpD3DI->v_next++; /* * Initialise lights */ numLights = 0; CIRCLE_QUEUE_INITIALIZE(&lights, DIRECT3DLIGHTI); /* * Make sure that lights are always downloaded the first time */ bLightsChanged = TRUE; } /* * IDirect3DViewport members */ /* * Transform */ #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::SetViewport" HRESULT D3DAPI DIRECT3DVIEWPORTI::SetViewport(LPD3DVIEWPORT lpData) { HRESULT ret; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3DVIEWPORT_PTR(lpData)) { D3D_ERR( "Invalid D3DVIEWPORT pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } D3DVIEWPORT2 v; if (lpData->dvScaleX == 0.0f || lpData->dvScaleY == 0.0f) { D3D_ERR( "Invalid viewport data" ); v.dvClipWidth = 0.0f; v.dvClipHeight = 0.0f; } else { v.dvClipWidth = lpData->dwWidth / lpData->dvScaleX; v.dvClipHeight = lpData->dwHeight / lpData->dvScaleY; } /* Convert D3DVIEWPORT to D3DVIEWPORT2 */ v.dwSize = sizeof(D3DVIEWPORT2); v.dwX = lpData->dwX; v.dwY = lpData->dwY; v.dwWidth = lpData->dwWidth; v.dwHeight = lpData->dwHeight; v.dvClipX = -v.dvClipWidth/2.0f; v.dvClipY = v.dvClipHeight/2.0f; v.dvMinZ = 0.0f; v.dvMaxZ = 1.0f; ret = SetViewport2(&v); return ret; } HRESULT D3DAPI DIRECT3DVIEWPORTI::SetViewport2(LPD3DVIEWPORT2 lpData) { HRESULT err; DWORD uSurfWidth,uSurfHeight; LPDIRECTDRAWSURFACE lpDDS; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport2 pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3DVIEWPORT2_PTR(lpData)) { D3D_ERR( "Invalid D3DVIEWPORT2 pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if (!VALID_DIRECT3DDEVICE3_PTR(this->lpDevI)) { D3D_ERR( "Viewport not attached to Device" ); return D3DERR_VIEWPORTHASNODEVICE; } if (IS_DX5_COMPATIBLE_DEVICE(this->lpDevI)) { /* we're called directly by dx5 app, so validate params */ if (lpData->dvClipWidth == 0.0f || lpData->dvClipHeight == 0.0f || lpData->dvMinZ == lpData->dvMaxZ) { D3D_ERR( "Invalid viewport data" ); return DDERR_INVALIDPARAMS; } lpDDS = this->lpDevI->lpDDSTarget; uSurfWidth= ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wWidth; uSurfHeight= ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wHeight; if (lpData->dwX > uSurfWidth || lpData->dwY > uSurfHeight || lpData->dwX + lpData->dwWidth > uSurfWidth || lpData->dwY + lpData->dwHeight > uSurfHeight) { D3D_ERR("Viewport outside the render target surface"); return DDERR_INVALIDPARAMS; } } this->v_data = *lpData; this->v_data_is_set = TRUE; // If this is the last rendered viewport, update its device if (this->v_id == this->lpDevI->v_id) { err = downloadView(this); if (err != D3D_OK) { return err; } } return (D3D_OK); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::GetViewport" HRESULT D3DAPI DIRECT3DVIEWPORTI::GetViewport(LPD3DVIEWPORT lpData) { HRESULT ret; D3DVIEWPORT2 v; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3DVIEWPORT_PTR(lpData)) { D3D_ERR( "Invalid D3DVIEWPORT pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } v.dwSize = sizeof(D3DVIEWPORT2); ret = GetViewport2(&v); /* Convert D3DVIEWPORT2 to D3DVIEWPORT */ lpData->dwSize = sizeof(D3DVIEWPORT); lpData->dwX = v.dwX; lpData->dwY = v.dwY; lpData->dwWidth = v.dwWidth; lpData->dwHeight = v.dwHeight; lpData->dvMinZ = 0.0f; lpData->dvMaxZ = 1.0f; lpData->dvScaleX = v.dwWidth / v.dvClipWidth; lpData->dvScaleY = v.dwHeight / v.dvClipHeight; lpData->dvMaxX = v.dvClipX + v.dvClipWidth; lpData->dvMaxY = v.dvClipY; return ret; } HRESULT D3DAPI DIRECT3DVIEWPORTI::GetViewport2(LPD3DVIEWPORT2 lpData) { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3DVIEWPORT2_PTR(lpData)) { D3D_ERR( "Invalid D3DVIEWPORT2 pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if (!this->v_data_is_set) { D3D_ERR("SetViewport not called for viewport yet"); return D3DERR_VIEWPORTDATANOTSET; } *lpData = this->v_data; return (D3D_OK); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::TransformVertices" HRESULT D3DAPI DIRECT3DVIEWPORTI::TransformVertices(DWORD dwVertexCount, LPD3DTRANSFORMDATA lpData, DWORD dwFlags, LPDWORD lpOffScreen) { HRESULT err; D3DTRANSFORMDATAI data; LPDIRECT3DVIEWPORTI lpViewOld; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. CD3DFPstate D3DFPstate; // Sets optimal FPU state for D3D. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3DTRANSFORMDATA_PTR(lpData)) { D3D_ERR( "Invalid D3DTRANSFORMDATA pointer" ); return DDERR_INVALIDPARAMS; } if (!VALID_DWORD_PTR(lpOffScreen)) { D3D_ERR( "Invalid DWORD pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } dwFlags &= (D3DTRANSFORM_CLIPPED | D3DTRANSFORM_UNCLIPPED); if (!dwFlags) { D3D_ERR("invalid flags"); return (DDERR_INVALIDPARAMS); } /* * Make sure the correct viewport is set up in the driver. */ err = ValidateViewport(this->lpDevI, this); if (err != D3D_OK) { D3D_ERR("failed to set viewport"); return err; } lpViewOld = this->lpDevI->lpCurrentViewport; lpDevI->lpCurrentViewport = this; data = *(LPD3DTRANSFORMDATAI)lpData; data.drExtent.x1 = D3DVAL(lpData->drExtent.x1); data.drExtent.y1 = D3DVAL(lpData->drExtent.y1); data.drExtent.x2 = D3DVAL(lpData->drExtent.x2); data.drExtent.y2 = D3DVAL(lpData->drExtent.y2); if (lpDevI->dwFEFlags & D3DFE_TRANSFORM_DIRTY) updateTransform(lpDevI); if (dwFlags == D3DTRANSFORM_CLIPPED) { if (lpDevI->dwFEFlags & D3DFE_INVERSEMCLIP_DIRTY) { updateInverseMclip(lpDevI); lpDevI->dwFEFlags &= ~D3DFE_INVERSEMCLIP_DIRTY; } lpDevI->dwFlags &= ~D3DDP_DONOTCLIP; } else lpDevI->dwFlags |= D3DDP_DONOTCLIP; *lpOffScreen = lpDevI->pGeometryFuncs->TransformVertices(lpDevI, dwVertexCount, &data); *lpData = *(D3DTRANSFORMDATA*)&data; D3DFE_ConvertExtent(this->lpDevI, &data.drExtent, &lpData->drExtent); this->lpDevI->lpCurrentViewport = lpViewOld; return (D3D_OK); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::LightElements" HRESULT D3DAPI DIRECT3DVIEWPORTI::LightElements(DWORD dwElementCount, LPD3DLIGHTDATA lpData) { return E_NOTIMPL; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::SetBackground" HRESULT D3DAPI DIRECT3DVIEWPORTI::SetBackground(D3DMATERIALHANDLE hMat) { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if (!hMat) { D3D_ERR("invalid material handle"); return (DDERR_INVALIDPARAMS); } this->bHaveBackgndMat = (hMat!=0); this->hBackgndMat = hMat; return (D3D_OK); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::GetBackground" HRESULT D3DAPI DIRECT3DVIEWPORTI::GetBackground(LPD3DMATERIALHANDLE lphMat, LPBOOL lpValid) { HRESULT err; err = D3D_OK; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3DMATERIALHANDLE_PTR(lphMat)) { D3D_ERR( "Invalid D3DMATERIALHANDLE pointer" ); return DDERR_INVALIDPARAMS; } if (!VALID_BOOL_PTR(lpValid)) { D3D_ERR( "Invalid BOOL pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if (this->bHaveBackgndMat) { *lpValid = TRUE; *lphMat = this->hBackgndMat; } else { *lphMat = 0; *lpValid = FALSE; } return (err); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::SetBackgroundDepth" HRESULT D3DAPI DIRECT3DVIEWPORTI::SetBackgroundDepth(LPDIRECTDRAWSURFACE lpDDS) { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT2_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } // passing NULL is OK if ((lpDDS!=NULL) && !VALID_D3D_DIRECTDRAWSURFACE_PTR((LPDDRAWI_DDRAWSURFACE_INT)lpDDS)) { D3D_ERR( "Invalid DirectDrawSurface pointer" ); return DDERR_INVALIDOBJECT; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if(this->lpDDSBackgndDepth!=NULL) { this->lpDDSBackgndDepth->Release(); } this->lpDDSBackgndDepth=lpDDS; return (D3D_OK); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::SetBackgroundDepth2" HRESULT D3DAPI DIRECT3DVIEWPORTI::SetBackgroundDepth2(LPDIRECTDRAWSURFACE4 lpDDS4) { LPDIRECTDRAWSURFACE lpDDS; HRESULT ret; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } // passing NULL is OK if ((lpDDS4!=NULL) && !VALID_D3D_DIRECTDRAWSURFACE4_PTR((LPDDRAWI_DDRAWSURFACE_INT)lpDDS4)) { D3D_ERR( "Invalid DirectDrawSurface4 pointer" ); return DDERR_INVALIDOBJECT; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } lpDDS=NULL; if(lpDDS4!=NULL) { // QI for DDS interface. This constitutes an AddRef, which is different from previous DX5 behavior ret = lpDDS4->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)&lpDDS); if(FAILED(ret)) return ret; } if(this->lpDDSBackgndDepth) this->lpDDSBackgndDepth->Release(); this->lpDDSBackgndDepth = lpDDS; return (D3D_OK); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::GetBackgroundDepth2" HRESULT D3DAPI DIRECT3DVIEWPORTI::GetBackgroundDepth2(LPDIRECTDRAWSURFACE4* lplpDDS, LPBOOL lpValid) { LPDIRECTDRAWSURFACE lpDDS; HRESULT ret = D3D_OK; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_OUTPTR(lplpDDS)) { D3D_ERR( "Invalid ptr to LPDIRECTDRAWSURFACE4" ); return DDERR_INVALIDPARAMS; } if (!VALID_BOOL_PTR(lpValid)) { D3D_ERR( "Invalid BOOL pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } *lplpDDS=NULL; if(this->lpDDSBackgndDepth!=NULL) { // QI for DDS interface. This constitutes an AddRef, which is different from previous DX5 behavior ret = this->lpDDSBackgndDepth->QueryInterface(IID_IDirectDrawSurface4, (LPVOID*)lplpDDS); } *lpValid = (*lplpDDS!=NULL); return ret; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::GetBackgroundDepth" HRESULT D3DAPI DIRECT3DVIEWPORTI::GetBackgroundDepth(LPDIRECTDRAWSURFACE* lplpDDS, LPBOOL lpValid) { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_OUTPTR(lplpDDS)) { D3D_ERR( "Invalid ptr to LPDIRECTDRAWSURFACE" ); return DDERR_INVALIDPARAMS; } if (!VALID_BOOL_PTR(lpValid)) { D3D_ERR( "Invalid BOOL pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } // no AddRef taken (this was a DX3 bug) *lplpDDS = this->lpDDSBackgndDepth; *lpValid = (this->lpDDSBackgndDepth!=NULL); return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::Clear (ProcessRects)" HRESULT ProcessRects(DIRECT3DVIEWPORTI *pViewport, DWORD dwCount, LPD3DRECT rects) { RECT vwport; DWORD i,j; /* * Rip through the rects and validate that they * are within the viewport. */ #if DBG if(dwCount == 0) { return D3D_OK; } if(rects == NULL) { D3D_ERR("invalid clear rectangle parameter rects == NULL"); return DDERR_INVALIDPARAMS; } #endif if (dwCount > pViewport->clrCount) { if (D3DRealloc((void**)&pViewport->clrRects, dwCount * sizeof(D3DRECT)) != DD_OK) { pViewport->clrCount = 0; pViewport->clrRects = NULL; D3D_ERR("failed to allocate space for rects"); return DDERR_OUTOFMEMORY; } } if (IS_DX5_COMPATIBLE_DEVICE(pViewport->lpDevI)) { vwport.left = pViewport->v_data.dwX; vwport.top = pViewport->v_data.dwY; vwport.right = pViewport->v_data.dwX + pViewport->v_data.dwWidth; vwport.bottom = pViewport->v_data.dwY + pViewport->v_data.dwHeight; } else { LPDIRECTDRAWSURFACE lpDDS; lpDDS = pViewport->lpDevI->lpDDSTarget; vwport.right = ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wWidth; vwport.bottom = ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpGbl->wHeight; vwport.left = 0; vwport.top = 0; } j=0; for (i = 0; i < dwCount; i++) { if (IntersectRect((LPRECT)(pViewport->clrRects + j), &vwport, (LPRECT)(rects + i))) j++; } pViewport->clrCount = j; return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::Clear2" HRESULT D3DAPI DIRECT3DVIEWPORTI::Clear2(DWORD dwCount, LPD3DRECT rects, DWORD dwFlags, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil) { LPDIRECT3DVIEWPORTI lpTempVwport; HRESULT err; BOOL bDoRGBClear,bDoZClear,bDoStencilClear; LPDDPIXELFORMAT pZPixFmt=NULL; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_DIRECT3DDEVICE3_PTR(this->lpDevI)) { D3D_ERR( "Viewport not attached to Device" ); return D3DERR_VIEWPORTHASNODEVICE; } #if DBG if (IsBadWritePtr(rects, dwCount * sizeof(D3DRECT))) { D3D_ERR( "Invalid rects pointer" ); return DDERR_INVALIDPARAMS; } #endif } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } bDoRGBClear=((dwFlags & D3DCLEAR_TARGET)!=0); bDoZClear=((dwFlags & D3DCLEAR_ZBUFFER)!=0); bDoStencilClear=((dwFlags & D3DCLEAR_STENCIL)!=0); if (lpDevI->lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR) { if (!(lpDevI->lpD3DHALCallbacks3->Clear2) && !(IS_DX7HAL_DEVICE(lpDevI))) { if (bDoStencilClear) { D3D_ERR("Invalid flag D3DCLEAR_STENCIL: this ZBUFFERLESSHSR device doesn't support Clear2()"); return D3DERR_ZBUFFER_NOTPRESENT; } if (bDoZClear) { if (!(lpDevI->lpD3DHALCallbacks2->Clear) || (dvZ!=1.0)) { D3D_WARN(3,"Ignoring D3DCLEAR_ZBUFFER since this ZBUFFERLESSHSR device doesn't even support Clear() or Z!=1"); dwFlags &= ~(D3DCLEAR_ZBUFFER); bDoZClear = FALSE; } } } } else { if((this->lpDevI->lpDDSZBuffer==NULL)&&(bDoStencilClear||bDoZClear)) { // unlike Clear(), specifying a Zbuffer-clearing flag without a zbuffer will // be considered an error if(bDoZClear) { D3D_ERR("Invalid flag D3DCLEAR_ZBUFFER: no zbuffer is associated with device"); } if(bDoStencilClear) { D3D_ERR("Invalid flag D3DCLEAR_STENCIL: no zbuffer is associated with device"); } return D3DERR_ZBUFFER_NOTPRESENT; } if(bDoStencilClear) { pZPixFmt=&((LPDDRAWI_DDRAWSURFACE_INT) lpDevI->lpDDSZBuffer)->lpLcl->lpGbl->ddpfSurface; if(!(pZPixFmt->dwFlags & DDPF_STENCILBUFFER)) { D3D_ERR("Invalid flag D3DCLEAR_STENCIL; current zbuffer's pixel format doesnt support stencil bits"); return D3DERR_STENCILBUFFER_NOTPRESENT; } } } if (!(dwFlags & (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL))) { D3D_ERR("no valid flags passed to Clear2"); err=DDERR_INVALIDPARAMS; goto early_out; } #if DBG // bad clear values just cause wacky results but no crashes, so OK to allow in retail bld if(bDoZClear && ((dvZ<0.0) || (dvZ>1.0))) { D3D_ERR("clear2 Z value outside legal range (0.0-1.0)"); err=DDERR_INVALIDPARAMS; goto early_out; } if(bDoStencilClear && pZPixFmt && (dwStencil > (DWORD)((1<dwStencilBitDepth)-1))) { D3D_ERR("clear2 stencil value larger than max allowed stencil value for zbuf pixelfmt"); err=DDERR_INVALIDPARAMS; goto early_out; } #endif // leave this check in retail build since DDFE_Clear keys off lpDDSBackgndDepth to do textured backg. clrs if(bDoZClear && (this->lpDDSBackgndDepth!=NULL)) { D3D_ERR("Background Depth Buffer not allowed to be used with Clear2"); err=DDERR_INVALIDPARAMS; goto early_out; } #if DBG // dont bother with this check for retail, since we can easily ignore existing background material if(this->bHaveBackgndMat && bDoRGBClear) { D3DMATERIAL dmMat; err = D3DHAL_MaterialGetData(this->lpDevI, this->hBackgndMat, &dmMat); if (err != D3D_OK) { D3D_ERR("Failed to find material from current viewport background material handle"); goto early_out; } if(dmMat.hTexture!=0) { D3D_ERR("Textured background materials not allowed to be used with Clear2"); err=DDERR_INVALIDPARAMS; goto early_out; } D3D_WARN(3,"Ignoring current Background Material Color, Clear2 dwColor arg overrides it"); } #endif // Make sure the correct viewport is set up in the driver. err = ValidateViewport(this->lpDevI, this); if (err != D3D_OK) { D3D_ERR("failed to set viewport"); goto early_out; } if((err=ProcessRects(this,dwCount,rects))!=D3D_OK) goto early_out; /* Make sure this viewport is the current viewport for the duration of this call */ lpTempVwport = this->lpDevI->lpCurrentViewport; this->lpDevI->lpCurrentViewport = this; if (IS_DX7HAL_DEVICE(lpDevI)) { static_cast(lpDevI)->ClearI(dwFlags, clrCount, clrRects, dwColor, dvZ, dwStencil); } else { err = D3DFE_Clear2(this->lpDevI, dwFlags, this->clrCount, this->clrRects, dwColor, dvZ, dwStencil); } /* Restore the original current viewport of the device */ this->lpDevI->lpCurrentViewport = lpTempVwport; early_out: return err; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::Clear" extern void TriFillRectsTex(LPDIRECT3DDEVICEI lpDevI, DWORD count, LPD3DRECT rect,D3DTEXTUREHANDLE hTex); HRESULT D3DAPI DIRECT3DVIEWPORTI::Clear(DWORD dwCount, LPD3DRECT rects, DWORD dwFlags) { LPDIRECT3DVIEWPORTI lpTempVwport; HRESULT err; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_DIRECT3DDEVICE3_PTR(this->lpDevI)) { D3D_ERR( "Viewport not attached to Device" ); return D3DERR_VIEWPORTHASNODEVICE; } #if DBG if (IsBadWritePtr(rects, dwCount * sizeof(D3DRECT))) { D3D_ERR( "Invalid rects pointer" ); return DDERR_INVALIDPARAMS; } #endif } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if((dwFlags & D3DCLEAR_ZBUFFER) && (this->lpDevI->lpDDSZBuffer==NULL)) { // this is not an error for legacy app compatibility--DX5 allowed this flag // to be set even if no ZBuffer exists if (!(this->lpDevI->lpD3DHALGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR) || !(this->lpDevI->lpD3DHALCallbacks2->Clear || this->lpDevI->lpD3DHALCallbacks3->Clear2 || (IS_DX7HAL_DEVICE(lpDevI))) ) { D3D_WARN(3,"Ignoring D3DCLEAR_ZBUFFER since no zbuffer associated with device"); dwFlags &= ~(D3DCLEAR_ZBUFFER); if (! dwFlags) { D3D_WARN(3, "Viewport::Clear: Nothing to do"); err = D3D_OK; goto early_out; } } } #if DBG if (dwFlags & D3DCLEAR_ZBUFFER) { LPDDPIXELFORMAT pZPixFmt = &((LPDDRAWI_DDRAWSURFACE_INT) lpDevI->lpDDSZBuffer)->lpLcl->lpGbl->ddpfSurface; if (pZPixFmt->dwFlags & DDPF_STENCILBUFFER) { D3D_ERR("Can't use Clear() on Z buffer with stencil planes. Use Clear2()"); // No change to execution path. } } #endif // leave this check until after checks that turn off flags if (!(dwFlags & (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER))) { D3D_ERR("no valid flags were passed to Clear"); err=DDERR_INVALIDPARAMS; goto early_out; } // Make sure the correct viewport is set up in the driver. err = ValidateViewport(this->lpDevI, this); if (err != D3D_OK) { D3D_ERR("failed to set viewport"); goto early_out; } if((err=ProcessRects(this,dwCount,rects))!=D3D_OK) goto early_out; D3DMATERIAL dmMat; if(this->bHaveBackgndMat) { err = D3DHAL_MaterialGetData(lpDevI, this->hBackgndMat, &dmMat); if(err != D3D_OK) { D3D_ERR("Failed to find material from current background material handle"); goto early_out; } } else { // DX5 legacy apps expect to Clear to Black if Background not initialized dmMat.diffuse.r=dmMat.diffuse.g=dmMat.diffuse.b=dmMat.diffuse.a=0; dmMat.hTexture=0; D3D_WARN(3,"Background Material is NULL!! Setting color to black, but please set a valid background"); } /* Make sure this viewport is the current viewport for the duration of this call */ lpTempVwport = this->lpDevI->lpCurrentViewport; this->lpDevI->lpCurrentViewport = this; if (IS_DX7HAL_DEVICE(lpDevI)) { if (0 != dmMat.hTexture && (D3DCLEAR_TARGET & dwFlags)) { err = lpDevI->FlushStates(); if (err != D3D_OK) { D3D_ERR("Error trying to render batched commands in Clear"); goto early_out; } TriFillRectsTex(lpDevI, clrCount, clrRects, dmMat.hTexture); dwFlags &= ~D3DCLEAR_TARGET; } if ((D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER) & dwFlags) { static_cast(lpDevI)->ClearI(dwFlags, clrCount, clrRects, CVAL_TO_RGBA(dmMat.diffuse), 1.0, 0); } } else { err = D3DFE_Clear(this->lpDevI, dwFlags, this->clrCount, this->clrRects, &dmMat.diffuse, dmMat.hTexture); } /* Restore the original current viewport of the device */ this->lpDevI->lpCurrentViewport = lpTempVwport; early_out: return err; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::AddLight" HRESULT D3DAPI DIRECT3DVIEWPORTI::AddLight(LPDIRECT3DLIGHT lpD3DLight) { LPDIRECT3DLIGHTI lpLightI; HRESULT err = D3D_OK; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { lpLightI = (LPDIRECT3DLIGHTI)lpD3DLight; if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_DIRECT3DLIGHT_PTR(lpLightI)) { D3D_ERR( "Invalid DIRECT3DLIGHT pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if (lpLightI->lpD3DViewportI) { D3D_ERR("light already associated with a viewport"); return (D3DERR_LIGHTHASVIEWPORT); } err = hookLightToViewport(this, lpLightI); if (err != D3D_OK) { D3D_ERR("failed to add light to viewport"); return (err); } this->bLightsChanged = TRUE; /* * AddRef the light */ lpD3DLight->AddRef(); return (err); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::DeleteLight" HRESULT D3DAPI DIRECT3DVIEWPORTI::DeleteLight(LPDIRECT3DLIGHT lpD3DLight) { LPDIRECT3DLIGHTI lpLightI; HRESULT err = D3D_OK; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { lpLightI = (LPDIRECT3DLIGHTI)lpD3DLight; if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_DIRECT3DLIGHT_PTR(lpLightI)) { D3D_ERR( "Invalid DIRECT3DLIGHT pointer" ); return DDERR_INVALIDPARAMS; } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } if (lpLightI->lpD3DViewportI != this) { D3D_ERR("Light is not associated with this viewport"); return (D3DERR_LIGHTNOTINTHISVIEWPORT); } /* * Remove this light from the viewport. */ CIRCLE_QUEUE_DELETE(&this->lights, lpLightI, light_list); this->numLights--; lpLightI->lpD3DViewportI = NULL; this->bLightsChanged = TRUE; /* * Release the light */ lpD3DLight->Release(); return (err); } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DViewport::NextLight" HRESULT D3DAPI DIRECT3DVIEWPORTI::NextLight(LPDIRECT3DLIGHT lpD3DLight, LPDIRECT3DLIGHT* lplpLight, DWORD dwFlags) { LPDIRECT3DLIGHTI lpLightI; CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. /* * validate parms */ TRY { if (!VALID_OUTPTR(lplpLight)) { D3D_ERR( "Invalid output pointer to LPDIRECT3DLIGHT" ); return DDERR_INVALIDPARAMS; } *lplpLight = NULL; lpLightI = (LPDIRECT3DLIGHTI)lpD3DLight; if (!VALID_DIRECT3DVIEWPORT3_PTR(this)) { D3D_ERR( "Invalid Direct3DViewport pointer" ); return DDERR_INVALIDOBJECT; } if (dwFlags & D3DNEXT_NEXT) { if (!VALID_DIRECT3DLIGHT_PTR(lpLightI)) { D3D_ERR( "Invalid Direct3DLight pointer" ); return DDERR_INVALIDPARAMS; } if (lpLightI && lpLightI->lpD3DViewportI != this) { D3D_ERR("light not associated with this viewport"); return (D3DERR_LIGHTNOTINTHISVIEWPORT); } } } EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { D3D_ERR( "Exception encountered validating parameters" ); return DDERR_INVALIDPARAMS; } switch (dwFlags) { case D3DNEXT_NEXT: *lplpLight = (LPDIRECT3DLIGHT)CIRCLE_QUEUE_NEXT(this,lpLightI,light_list); break; case D3DNEXT_HEAD: *lplpLight = (LPDIRECT3DLIGHT)CIRCLE_QUEUE_FIRST(&this->lights); break; case D3DNEXT_TAIL: *lplpLight = (LPDIRECT3DLIGHT)CIRCLE_QUEUE_LAST(&this->lights); break; default: D3D_ERR("invalid flags"); return (DDERR_INVALIDPARAMS); } if (*lplpLight == (LPDIRECT3DLIGHT)&this->lights) { *lplpLight = NULL; } /* * Must AddRef the returned object */ if (*lplpLight) (*lplpLight)->AddRef(); return (D3D_OK); }