500 lines
17 KiB
C++
500 lines
17 KiB
C++
![]() |
/**********************************************************************
|
||
|
|
||
|
Filename : GFxDisplayContext.cpp
|
||
|
Content : Implements GFxDisplayContext class, used to pass state
|
||
|
and binding information during rendering.
|
||
|
Created :
|
||
|
Authors : Michael Antonov
|
||
|
|
||
|
Copyright : (c) 2001-2007 Scaleform Corp. All Rights Reserved.
|
||
|
|
||
|
Notes : More implementation-specific classes are
|
||
|
defined in the GFxPlayerImpl.h
|
||
|
|
||
|
Licensees may use this file in accordance with the valid Scaleform
|
||
|
Commercial License Agreement provided with the software.
|
||
|
|
||
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
||
|
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
|
||
|
|
||
|
**********************************************************************/
|
||
|
|
||
|
#include "GFxDisplayContext.h"
|
||
|
|
||
|
#include "GFxCharacter.h"
|
||
|
#include "GFxPlayerImpl.h"
|
||
|
|
||
|
// Necessary to avoid template related issued wiuth GASEnvironment.
|
||
|
#include "GFxAction.h"
|
||
|
|
||
|
|
||
|
// ***** GFxDisplayContext
|
||
|
|
||
|
GFxDisplayContext::GFxDisplayContext()
|
||
|
{
|
||
|
pRenderStats = 0;
|
||
|
pChar = 0;
|
||
|
#ifndef GFC_NO_3D
|
||
|
pRealParentMatrix3D = 0;
|
||
|
#endif
|
||
|
pResourceBinding = 0;
|
||
|
MaskRenderCount = 0;
|
||
|
MaskStackIndex = 0;
|
||
|
MaskStackIndexMax = 0;
|
||
|
PixelScale = 1;
|
||
|
pStats = 0;
|
||
|
pRealParentCxform = 0;
|
||
|
}
|
||
|
|
||
|
GFxDisplayContext::GFxDisplayContext(const GFxStateBag *pstate,
|
||
|
GFxResourceWeakLib *plib,
|
||
|
GFxResourceBinding *pbinding,
|
||
|
Float pixelScale,
|
||
|
const Matrix& viewportMatrix,
|
||
|
GFxAmpViewStats* pstats,
|
||
|
bool prepass)
|
||
|
: GFxDisplayContextFilters(prepass), pStats(pstats)
|
||
|
{
|
||
|
Init(pstate, plib, pbinding, pixelScale, viewportMatrix);
|
||
|
}
|
||
|
|
||
|
GFxDisplayContext::~GFxDisplayContext()
|
||
|
{
|
||
|
GASSERT(MaskStackIndex == 0);
|
||
|
GASSERT(MaskStackIndexMax == 0);
|
||
|
GASSERT(MaskRenderCount == 0);
|
||
|
}
|
||
|
|
||
|
void GFxDisplayContext::Init(const GFxStateBag *pstate,
|
||
|
GFxResourceWeakLib *plib,
|
||
|
GFxResourceBinding *pbinding,
|
||
|
Float pixelScale,
|
||
|
const Matrix& viewportMatrix)
|
||
|
{
|
||
|
// Capture the state for efficient access
|
||
|
// (Usually called in the beginning for Advance)
|
||
|
|
||
|
const static GFxState::StateType stateQuery[6] =
|
||
|
{
|
||
|
GFxState::State_RenderConfig, GFxState::State_GradientParams,
|
||
|
GFxState::State_ImageCreator, GFxState::State_FontCacheManager,
|
||
|
GFxState::State_Log, GFxState::State_MeshCacheManager
|
||
|
};
|
||
|
|
||
|
GFxState* pstates[6] = {0,0,0,0,0,0};
|
||
|
|
||
|
// Get multiple states at once to avoid extra locking.
|
||
|
pstate->GetStatesAddRef(pstates, stateQuery, 6);
|
||
|
pRenderConfig = *(GFxRenderConfig*) pstates[0];
|
||
|
pGradientParams = *(GFxGradientParams*) pstates[1];
|
||
|
pImageCreator = *(GFxImageCreator*) pstates[2];
|
||
|
pFontCacheManager = *(GFxFontCacheManager*) pstates[3];
|
||
|
pLog = *(GFxLog*) pstates[4];
|
||
|
pMeshCacheManager = *(GFxMeshCacheManager*) pstates[5];
|
||
|
|
||
|
pWeakLib = plib;
|
||
|
pResourceBinding = pbinding;
|
||
|
|
||
|
pRenderStats = 0;
|
||
|
|
||
|
MaskRenderCount = 0;
|
||
|
MaskStackIndex = 0;
|
||
|
MaskStackIndexMax = 0;
|
||
|
pRealParentCxform = 0;
|
||
|
#ifndef GFC_NO_3D
|
||
|
pRealParentMatrix3D = 0;
|
||
|
#endif
|
||
|
PixelScale = pixelScale;
|
||
|
ViewportMatrix = viewportMatrix;
|
||
|
pChar = 0;
|
||
|
|
||
|
GFxDisplayContextTransforms::ResetTransforms();
|
||
|
}
|
||
|
|
||
|
// Mask Stack management
|
||
|
void GFxDisplayContext::PushAndDrawMask(GFxCharacter* pmask)
|
||
|
{
|
||
|
GRenderer* prenderer = GetRenderer();
|
||
|
// Only clear stencil if no masks were applied before us; otherwise
|
||
|
// no clear is necessary because we are building a cumulative mask.
|
||
|
prenderer->BeginSubmitMask((MaskStackIndex == 0) ?
|
||
|
GRenderer::Mask_Clear : GRenderer::Mask_Increment);
|
||
|
|
||
|
// Stack bounds check. We increment anyway, but access only lower stack.
|
||
|
if (MaskStackIndex < GFxDisplayContext::Mask_MaxStackSize)
|
||
|
MaskStack[MaskStackIndex] = pmask;
|
||
|
MaskStackIndex++;
|
||
|
MaskStackIndexMax++;
|
||
|
MaskRenderCount++;
|
||
|
|
||
|
// Draw mask.
|
||
|
prenderer->PushBlendMode(pmask->GetBlendMode());
|
||
|
pmask->Display(*this);
|
||
|
prenderer->PopBlendMode();
|
||
|
|
||
|
// Done rendering mask.
|
||
|
MaskRenderCount--;
|
||
|
prenderer->EndSubmitMask();
|
||
|
}
|
||
|
|
||
|
void GFxDisplayContext::PopMask()
|
||
|
{
|
||
|
GASSERT(MaskStackIndex > 0);
|
||
|
MaskStackIndex--;
|
||
|
// If we reached the bottom of stack, disable mask checks.
|
||
|
if (MaskStackIndex == 0)
|
||
|
{
|
||
|
GetRenderer()->DisableMask();
|
||
|
MaskStackIndexMax = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GFxDisplayContext::PreDrawMask(GFxCharacter* pmask, GMatrix2D *pmatrix, GMatrix3D *pmatrix3D)
|
||
|
{
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (pmask->Is3D(true))
|
||
|
{
|
||
|
pmask->GetParent()->GetWorldMatrix3D(pmatrix3D);
|
||
|
pParentMatrix3D = pmatrix3D;
|
||
|
pParentMatrix = &GMatrix2D::Identity;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// 2d case
|
||
|
pmask->GetParent()->GetWorldMatrix(pmatrix);
|
||
|
pParentMatrix = pmatrix;
|
||
|
pParentMatrix3D = NULL;
|
||
|
}
|
||
|
#else
|
||
|
// 2d case
|
||
|
pmask->GetParent()->GetWorldMatrix(pmatrix);
|
||
|
pParentMatrix = pmatrix;
|
||
|
GUNUSED(pmatrix3D);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void GFxDisplayContext::PreDisplay(GFxDisplayContextTransforms &oldXform, const GFxCharacter *pchar,
|
||
|
GMatrix2D *pmatrix, GMatrix3D *pmatrix3D, GRenderer::Cxform *pcxform)
|
||
|
{
|
||
|
*pmatrix = *oldXform.pParentMatrix;
|
||
|
pChar = pchar;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (Is3D == false)
|
||
|
#endif
|
||
|
{
|
||
|
pmatrix->Prepend(pchar->GetMatrix());
|
||
|
pParentMatrix = pmatrix;
|
||
|
}
|
||
|
|
||
|
*pcxform = *pParentCxform;
|
||
|
pcxform->Concatenate(pchar->GetCxform());
|
||
|
pParentCxform = pcxform;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (Is3D || pchar->Is3D())
|
||
|
{
|
||
|
*pmatrix3D = oldXform.pParentMatrix3D ? *oldXform.pParentMatrix3D : GMatrix3D::Identity;
|
||
|
GMatrix3D local3DMat = (pchar->GetMatrix3D() ? *pchar->GetMatrix3D() : GMatrix3D::Identity);
|
||
|
if (pchar->Is3D() && Is3D == false)
|
||
|
{
|
||
|
local3DMat.Append(GMatrix3D(*pParentMatrix)); // add 2d world mat
|
||
|
Is3D = true; // enter 3d mode
|
||
|
}
|
||
|
else if (Is3D == true)
|
||
|
{
|
||
|
local3DMat.Append(GMatrix3D(pchar->GetMatrix())); // add 2d local mat
|
||
|
}
|
||
|
|
||
|
if (Is3D)
|
||
|
{
|
||
|
|
||
|
pmatrix3D->Prepend(local3DMat);
|
||
|
pParentMatrix3D = pmatrix3D;
|
||
|
GetRenderer()->SetWorld3D(pmatrix3D);
|
||
|
pParentMatrix = &GMatrix2D::Identity; // reset 2d matrix
|
||
|
#if RSG_PC
|
||
|
const float fStereoFlag = pParentMatrix3D->GetZ();
|
||
|
GetRenderer()->SetStereoFlag(fStereoFlag);
|
||
|
#endif
|
||
|
|
||
|
pViewMatrix3D = pchar->GetView3D() ? pchar->GetView3D() : oldXform.pViewMatrix3D;
|
||
|
pPerspectiveMatrix3D = pchar->GetPerspective3D() ? pchar->GetPerspective3D() : oldXform.pPerspectiveMatrix3D;
|
||
|
if (!pRealParentMatrix3D) // don't change view/persp if rendering to a filter texture
|
||
|
{
|
||
|
if (pViewMatrix3D)
|
||
|
GetRenderer()->SetView3D(*pViewMatrix3D);
|
||
|
if (pPerspectiveMatrix3D)
|
||
|
GetRenderer()->SetPerspective3D(*pPerspectiveMatrix3D);
|
||
|
}
|
||
|
}
|
||
|
#if RSG_PC
|
||
|
else
|
||
|
{
|
||
|
// if non 3D stereo, reset stereo params
|
||
|
GetRenderer()->SetStereoFlag(0.0f);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
#if RSG_PC
|
||
|
else
|
||
|
{
|
||
|
// if non 3D stereo, reset stereo params
|
||
|
GetRenderer()->SetStereoFlag(0.0f);
|
||
|
}
|
||
|
#endif
|
||
|
#else
|
||
|
GUNUSED(pmatrix3D);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// restore old transforms
|
||
|
void GFxDisplayContext::PostDisplay(GFxDisplayContextTransforms &oldXform)
|
||
|
{
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (Is3D)
|
||
|
GetRenderer()->SetWorld3D(oldXform.pParentMatrix3D);
|
||
|
if (!pRealParentMatrix3D) // don't change view/persp if rendering to a filter texture
|
||
|
{
|
||
|
if (oldXform.pViewMatrix3D)
|
||
|
GetRenderer()->SetView3D(*oldXform.pViewMatrix3D);
|
||
|
if (oldXform.pPerspectiveMatrix3D)
|
||
|
GetRenderer()->SetPerspective3D(*oldXform.pPerspectiveMatrix3D);
|
||
|
}
|
||
|
#endif
|
||
|
CopyTransformsFrom(oldXform); // restore context transform info
|
||
|
}
|
||
|
|
||
|
bool GFxDisplayContext::BeginFilters(GFxDisplayContextFilters& oldFilters, GFxCharacter* ch, const GArray<GFxFilterDesc>& Filters)
|
||
|
{
|
||
|
if (Filters.GetSize())
|
||
|
{
|
||
|
bool HasFilter = 0;
|
||
|
Float FilterSizeX = 0;
|
||
|
Float FilterSizeY = 0;
|
||
|
|
||
|
for (UInt i = 0; i < Filters.GetSize(); i++)
|
||
|
{
|
||
|
const GFxFilterDesc &filter = Filters[i];
|
||
|
bool bBlurFilter = ((filter.Blur.BlurX > 1 || filter.Blur.BlurY > 1) && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_Blur));
|
||
|
bool bShadowFilter = (filter.Blur.Color.GetAlpha() > 0 && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_DropShadow));
|
||
|
bool bGlowFilter = (filter.Blur.Color.GetAlpha() > 0 && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_Glow));
|
||
|
bool bBevelFilter = (filter.Blur.Color.GetAlpha() > 0 && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_Bevel));
|
||
|
if (bBlurFilter)
|
||
|
{
|
||
|
HasFilter = 1;
|
||
|
FilterSizeX += 20 * ceilf(filter.Blur.BlurX * filter.Blur.Passes);
|
||
|
FilterSizeY += 20 * ceilf(filter.Blur.BlurY * filter.Blur.Passes);
|
||
|
}
|
||
|
else if (bShadowFilter || bGlowFilter || bBevelFilter)
|
||
|
{
|
||
|
HasFilter = 1;
|
||
|
|
||
|
// the filter area must be extended even for inner shadows as the blurred area outside is still read
|
||
|
Float count = bBevelFilter ? 2.f : 1.f;
|
||
|
FilterSizeX += count * 20 * ceilf(filter.Blur.BlurX * filter.Blur.Passes);
|
||
|
FilterSizeY += count * 20 * ceilf(filter.Blur.BlurY * filter.Blur.Passes);
|
||
|
|
||
|
if (bShadowFilter)
|
||
|
{
|
||
|
GPointF offset = filter.GetShadowOffset();
|
||
|
FilterSizeX += ceilf(count * 20 * fabsf(offset.x));
|
||
|
FilterSizeY += ceilf(count * 20 * fabsf(offset.y));
|
||
|
}
|
||
|
}
|
||
|
else if ((filter.Flags & 0xf) == GFxFilterDesc::Filter_AdjustColor)
|
||
|
HasFilter = 1;
|
||
|
}
|
||
|
|
||
|
if (!HasFilter)
|
||
|
return 0;
|
||
|
|
||
|
oldFilters.CopyFilterStateFrom(*this);
|
||
|
|
||
|
scrXScale = (Float)ViewportMatrix.GetXScale();
|
||
|
scrYScale = (Float)ViewportMatrix.GetYScale();
|
||
|
|
||
|
mcRect = ch->GetBounds(*pParentMatrix);
|
||
|
mcRect.Expand(FilterSizeX, FilterSizeY);
|
||
|
mcWidth = (UInt)ceilf(mcRect.Width() * scrXScale);
|
||
|
mcHeight = (UInt)ceilf(mcRect.Height() * scrYScale);
|
||
|
|
||
|
// Before setting the new render target, give the app a chance to save off the previous contents
|
||
|
GetRenderer()->SaveCurrentRenderTargetContents();
|
||
|
|
||
|
pFilterRTT = GetRenderer()->PushTempRenderTarget(mcRect, mcWidth, mcHeight, true);
|
||
|
if (pFilterRTT)
|
||
|
{
|
||
|
pRealParentCxform = pParentCxform;
|
||
|
pParentCxform = &GRenderer::Cxform::Identity;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
// Draw object without 3D
|
||
|
if (Is3D)
|
||
|
{
|
||
|
pRealParentMatrix3D = pParentMatrix3D;
|
||
|
pParentMatrix3D = &GMatrix3D::Identity;
|
||
|
GetRenderer()->SetWorld3D(NULL);
|
||
|
Is3D = false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Use normal blending for the filtered clip, and all the filters except the last one.
|
||
|
// Overlay is used because it is not actually supported (treated as Normal), but isn't ignored if there are "real"
|
||
|
// blend modes below it on stack.
|
||
|
GetRenderer()->PushBlendMode(GRenderer::Blend_Overlay);
|
||
|
|
||
|
FilterStack++;
|
||
|
return 1;
|
||
|
}
|
||
|
else
|
||
|
CopyFilterStateFrom(oldFilters);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void GFxDisplayContext::EndFilters(const GFxDisplayContextFilters& oldFilters, GFxCharacter* ch,
|
||
|
const GArray<GFxFilterDesc>& Filters, bool finishPrePass)
|
||
|
{
|
||
|
GUNUSED(ch);
|
||
|
GASSERT(pFilterRTT);
|
||
|
GRenderer* prenderer = GetRenderer();
|
||
|
|
||
|
UInt filtercount = (UInt)Filters.GetSize();
|
||
|
UInt lastfilter = filtercount - 1;
|
||
|
|
||
|
#ifndef GFC_NO_3D
|
||
|
// restore correct 3d matrix when drawing RT
|
||
|
if (pRealParentMatrix3D)
|
||
|
{
|
||
|
GetRenderer()->SetWorld3D(pRealParentMatrix3D);
|
||
|
// pRealParentMatrix3D = 0;
|
||
|
}
|
||
|
#endif
|
||
|
#ifndef GFC_NO_FILTERS_PREPASS
|
||
|
if (!finishPrePass)
|
||
|
prenderer->PopRenderTarget();
|
||
|
|
||
|
if (IsInPrePass)
|
||
|
{
|
||
|
// Leave the temp last render target, don't draw anything to the primary framebuffer
|
||
|
lastfilter++;
|
||
|
// The last filter is drawn in the main pass
|
||
|
filtercount--;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
for (UInt i = 0; i < filtercount; i++)
|
||
|
{
|
||
|
const GFxFilterDesc &filter = Filters[i];
|
||
|
bool bBlurFilter = ((filter.Blur.BlurX > 1 || filter.Blur.BlurY > 1) && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_Blur));
|
||
|
bool bShadowFilter = (filter.Blur.Color.GetAlpha() > 0 && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_DropShadow));
|
||
|
bool bBevelFilter = (filter.Blur.Color.GetAlpha() > 0 && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_Bevel));
|
||
|
bool bGlowFilter = (filter.Blur.Color.GetAlpha() > 0 && ((filter.Flags & 0xF) == GFxFilterDesc::Filter_Glow));
|
||
|
bool bColorFilter = ((filter.Flags & 0xF) == GFxFilterDesc::Filter_AdjustColor);
|
||
|
|
||
|
if (bBlurFilter || bShadowFilter || bGlowFilter || bColorFilter || bBevelFilter)
|
||
|
{
|
||
|
prenderer->SetMatrix(GMatrix2D::Identity);
|
||
|
|
||
|
GPtr<GTexture> pNext;
|
||
|
if (i != lastfilter)
|
||
|
{
|
||
|
pNext = prenderer->PushTempRenderTarget(mcRect, mcWidth, mcHeight);
|
||
|
if (!pNext)
|
||
|
{
|
||
|
// out of resources, this will be the last filter processed in this stack
|
||
|
lastfilter = i;
|
||
|
filtercount = i+1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i == lastfilter && !finishPrePass)
|
||
|
prenderer->PopBlendMode();
|
||
|
|
||
|
if (bColorFilter)
|
||
|
{
|
||
|
if (i == lastfilter)
|
||
|
{
|
||
|
Float cxmatrix[20];
|
||
|
for (UInt i = 0; i < 5; i++)
|
||
|
{
|
||
|
cxmatrix[i*4+0] = filter.ColorMatrix[i*4+0] * pRealParentCxform->M_[0][0] * pRealParentCxform->M_[3][0];
|
||
|
cxmatrix[i*4+1] = filter.ColorMatrix[i*4+1] * pRealParentCxform->M_[1][0] * pRealParentCxform->M_[3][0];
|
||
|
cxmatrix[i*4+2] = filter.ColorMatrix[i*4+2] * pRealParentCxform->M_[2][0] * pRealParentCxform->M_[3][0];
|
||
|
cxmatrix[i*4+3] = filter.ColorMatrix[i*4+3] * pRealParentCxform->M_[3][0];
|
||
|
}
|
||
|
cxmatrix[16] = (filter.ColorMatrix[16] + pRealParentCxform->M_[0][1] * 1.f/255.f) * pRealParentCxform->M_[3][0];
|
||
|
cxmatrix[17] = (filter.ColorMatrix[17] + pRealParentCxform->M_[1][1] * 1.f/255.f) * pRealParentCxform->M_[3][0];
|
||
|
cxmatrix[18] = (filter.ColorMatrix[18] + pRealParentCxform->M_[2][1] * 1.f/255.f) * pRealParentCxform->M_[3][0];
|
||
|
cxmatrix[19] = (filter.ColorMatrix[19] + pRealParentCxform->M_[3][1] * 1.f/255.f) * pRealParentCxform->M_[3][0];
|
||
|
|
||
|
// This is the last filter. Ensure we restore the previous contents of the render target
|
||
|
prenderer->DrawColorMatrixRect(pFilterRTT, GRectF(0,0,Float(mcWidth),Float(mcHeight)), mcRect, cxmatrix, true);
|
||
|
}
|
||
|
else {
|
||
|
// Not the last filter. No need to restore the previous contents of the render target
|
||
|
prenderer->DrawColorMatrixRect(pFilterRTT, GRectF(0,0,Float(mcWidth),Float(mcHeight)), mcRect, filter.ColorMatrix, false);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GRenderer::BlurFilterParams params (filter.Blur);
|
||
|
if (i == lastfilter)
|
||
|
params.cxform = *pRealParentCxform;
|
||
|
|
||
|
prenderer->DrawBlurRect(pFilterRTT, GRectF(0,0,Float(mcWidth),Float(mcHeight)), mcRect,
|
||
|
GRenderer::BlurFilterParams(params).Scale(scrXScale*20.f,scrYScale*20.f), i == lastfilter);
|
||
|
}
|
||
|
|
||
|
if (i != lastfilter)
|
||
|
{
|
||
|
prenderer->PopRenderTarget();
|
||
|
pFilterRTT = pNext;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pParentCxform = pRealParentCxform;
|
||
|
#ifndef GFC_NO_3D
|
||
|
if (pRealParentMatrix3D)
|
||
|
{
|
||
|
pParentMatrix3D = pRealParentMatrix3D;
|
||
|
pRealParentMatrix3D = 0;
|
||
|
}
|
||
|
#endif
|
||
|
FilterStack--;
|
||
|
if (!IsInPrePass)
|
||
|
{
|
||
|
pFilterRTT = 0;
|
||
|
CopyFilterStateFrom(oldFilters);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
prenderer->PopBlendMode();
|
||
|
if (FilterStack > 0)
|
||
|
CopyFilterStateFrom(oldFilters);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GFxDisplayContext::DisplayFilterPrePass(GFxCharacter* ch, const GArray<GFxFilterDesc>& Filters,
|
||
|
GTexture* pFilterResult, GRectF mcr, UInt mcw, UInt mch)
|
||
|
{
|
||
|
GFxDisplayContextFilters oldFilters;
|
||
|
oldFilters.CopyFilterStateFrom(*this);
|
||
|
|
||
|
// Even if in a prepass, display nested filters normally
|
||
|
IsInPrePass = 0;
|
||
|
pRealParentCxform = pParentCxform;
|
||
|
pFilterRTT = pFilterResult;
|
||
|
mcRect = mcr;
|
||
|
mcWidth = mcw;
|
||
|
mcHeight = mch;
|
||
|
scrXScale = (Float)ViewportMatrix.GetXScale();
|
||
|
scrYScale = (Float)ViewportMatrix.GetYScale();
|
||
|
|
||
|
EndFilters(oldFilters, ch, Filters, true);
|
||
|
CopyFilterStateFrom(oldFilters);
|
||
|
}
|