You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/Common/PostProcess/PostEffects.cpp

870 lines
26 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "I3DEngine.h"
#include "PostEffects.h"
#include "PostProcessUtils.h"
#include "IPostEffectGroup.h"
#include <AzCore/std/sort.h>
#include "../../../Cry3DEngine/Environment/OceanEnvironmentBus.h"
AZStd::vector< CWaterRipples::SWaterHit, AZ::StdLegacyAllocator > CWaterRipples::s_pWaterHits[RT_COMMAND_BUF_COUNT];
AZStd::vector< CWaterRipples::SWaterHit, AZ::StdLegacyAllocator > CWaterRipples::s_pWaterHitsMGPU;
AZStd::vector< CWaterRipples::SWaterHitRecord, AZ::StdLegacyAllocator > CWaterRipples::m_DebugWaterHits;
Vec3 CWaterRipples::s_CameraPos = Vec3(ZERO);
Vec2 CWaterRipples::s_SimOrigin = Vec2(ZERO);
int CWaterRipples::s_nUpdateMask;
Vec4 CWaterRipples::s_vParams = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
Vec4 CWaterRipples::s_vLookupParams = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
bool CWaterRipples::s_bInitializeSim;
int CSunShafts::Initialize()
{
Release();
m_pOcclQuery = new COcclusionQuery;
m_pOcclQuery->Create();
return true;
}
void CSunShafts::Release()
{
SAFE_DELETE(m_pOcclQuery);
}
void CSunShafts::Reset([[maybe_unused]] bool bOnSpecChange)
{
}
void CSunShafts::OnLostDevice()
{
Release();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CFilterSharpening::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessFilters)
{
return false;
}
if (fabs(m_pAmount->GetParam() - 1.0f) + CRenderer::CV_r_Sharpening + CRenderer::CV_r_ChromaticAberration > 0.09f)
{
return true;
}
return false;
}
void CFilterSharpening::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(1.0f);
m_pType->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CFilterBlurring::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessFilters)
{
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
return false;
}
void CFilterBlurring::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pType->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CUberGamePostProcess::Preprocess()
{
const float fParamThreshold = 1.0f / 255.0f;
const Vec4 vWhite = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
bool bEnable = false;
bEnable |= m_pColorTint->GetParamVec4() != vWhite;
bEnable |= m_pNoise->GetParam() > fParamThreshold;
bEnable |= m_pSyncWaveAmplitude->GetParam() > fParamThreshold;
bEnable |= m_pGrainAmount->GetParam() > fParamThreshold;
bEnable |= m_pPixelationScale->GetParam() > fParamThreshold;
if (m_pInterlationAmount->GetParam() > fParamThreshold || m_pVSyncAmount->GetParam() > fParamThreshold)
{
m_nCurrPostEffectsMask |= ePE_SyncArtifacts;
bEnable = true;
}
// todo: looks like some game code/flowgraph doing silly stuff - investigate
const float fParamThresholdBackCompatibility = 0.09f;
if (m_pChromaShiftAmount->GetParam() > fParamThresholdBackCompatibility || m_pFilterChromaShiftAmount->GetParam() > fParamThresholdBackCompatibility)
{
m_nCurrPostEffectsMask |= ePE_ChromaShift;
bEnable = true;
}
return bEnable;
}
void CUberGamePostProcess::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_nCurrPostEffectsMask = 0;
m_pVSyncAmount->ResetParam(0.0f);
m_pVSyncFreq->ResetParam(1.0f);
const Vec4 vWhite = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
m_pColorTint->ResetParamVec4(vWhite);
m_pInterlationAmount->ResetParam(0.0f);
m_pInterlationTiling->ResetParam(1.0f);
m_pInterlationRotation->ResetParam(0.0f);
m_pPixelationScale->ResetParam(0.0f);
m_pNoise->ResetParam(0.0f);
m_pSyncWaveFreq->ResetParam(0.0f);
m_pSyncWavePhase->ResetParam(0.0f);
m_pSyncWaveAmplitude->ResetParam(0.0f);
m_pFilterChromaShiftAmount->ResetParam(0.0f);
m_pChromaShiftAmount->ResetParam(0.0f);
m_pGrainAmount->ResetParam(0.0f);
m_pGrainTile->ResetParam(1.0f);
m_pMask->Release();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CColorGrading::Preprocess()
{
// Depreceated: to be removed / replaced by UberPostProcess shader
return false;
}
void CColorGrading::Reset([[maybe_unused]] bool bOnSpecChange)
{
// reset user params
m_pSaturationOffset->ResetParam(0.0f);
m_pPhotoFilterColorOffset->ResetParamVec4(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
m_pPhotoFilterColorDensityOffset->ResetParam(0.0f);
m_pGrainAmountOffset->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CUnderwaterGodRays::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
static ICVar* pVar = iConsole->GetCVar("e_WaterOcean");
//bool bOceanVolumeVisible = (gEnv->p3DEngine->GetOceanRenderFlags() & OCR_OCEANVOLUME_VISIBLE) != 0;
bool godRaysEnabled = OceanToggle::IsActive() ? OceanRequest::GetGodRaysEnabled() : (CRenderer::CV_r_water_godrays == 1);
if (godRaysEnabled && m_pAmount->GetParam() > 0.005f) // && bOceanEnabled && bOceanVolumeVisible)
{
float fWatLevel = SPostEffectsUtils::m_fWaterLevel;
if (fWatLevel - 0.1f > gRenDev->GetViewParameters().vOrigin.z)
{
// check water level
return true;
}
}
return false;
}
void CUnderwaterGodRays::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(1.0f);
m_pQuality->ResetParam(1.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CVolumetricScattering::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_High, eSQ_High);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
return false;
}
void CVolumetricScattering::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pType->ResetParam(0.0f);
m_pQuality->ResetParam(1.0f);
m_pTiling->ResetParam(1.0f);
m_pSpeed->ResetParam(1.0f);
m_pColor->ResetParamVec4(Vec4(0.5f, 0.75f, 1.0f, 1.0f));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Game/Hud specific post-effects
////////////////////////////////////////////////////////////////////////////////////////////////////
void CAlienInterference::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pTintColor->ResetParamVec4(Vec4(Vec3(0.85f, 0.95f, 1.25f) * 0.5f, 1.0f));
}
bool CAlienInterference::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CGhostVision::CreateResources()
{
Release();
m_pUserTex1 = CTexture::ForName("EngineAssets/Textures/user_tex1.tif", FT_DONT_STREAM, eTF_Unknown);
m_pUserTex2 = CTexture::ForName("EngineAssets/Textures/user_tex2.tif", FT_DONT_STREAM, eTF_Unknown);
return true;
}
void CGhostVision::Release()
{
SAFE_RELEASE(m_pUserTex1);
SAFE_RELEASE(m_pUserTex2);
}
void CGhostVision::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pUserValue1->ResetParam(0.0f);
m_pUserValue2->ResetParam(0.0f);
m_pUserValue3->ResetParam(0.0f);
m_pTintColor->ResetParamVec4(Vec4(Vec3(0.85f, 0.95f, 1.25f) * 0.5f, 1.0f));
}
bool CGhostVision::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Low, eSQ_Low);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pUserValue1->GetParam() > 0.09f || m_pUserValue2->GetParam() > 0.09f || m_pUserValue3->GetParam() > 0.09f)
{
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWaterDroplets::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
const bool bUserActive = m_pAmount->GetParam() > 0.005f;
bool godRaysEnabled = OceanToggle::IsActive() ? OceanRequest::GetGodRaysEnabled() : (CRenderer::CV_r_water_godrays == 1);
if (godRaysEnabled)
{
return bUserActive; // user enabled override
}
return false;
}
void CWaterDroplets::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWaterFlow::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
return false;
}
void CWaterFlow::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWaterVolume::Preprocess()
{
if (!gRenDev->m_RP.m_eQuality)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
return false;
}
void CWaterVolume::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CScreenFrost::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
return false;
}
void CScreenFrost::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pCenterAmount->ResetParam(1.0f);
m_fRandOffset = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CRainDrops::CreateResources()
{
Release();
//create texture for HitEffect accumulation
m_bFirstFrame = true;
// Already generated ? No need to proceed
if (!m_pDropsLst.empty())
{
return 1;
}
m_pDropsLst.reserve(m_nMaxDropsCount);
for (int p = 0; p < m_nMaxDropsCount; p++)
{
SRainDrop* pDrop = new SRainDrop;
m_pDropsLst.push_back(pDrop);
}
return 1;
}
void CRainDrops::Release()
{
if (m_pDropsLst.empty())
{
return;
}
SRainDropsItor pItor, pItorEnd = m_pDropsLst.end();
for (pItor = m_pDropsLst.begin(); pItor != pItorEnd; ++pItor)
{
SAFE_DELETE((*pItor));
}
m_pDropsLst.clear();
}
void CRainDrops::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_bFirstFrame = true;
m_uCurrentDytex = 0;
m_pAmount->ResetParam(0.0f);
m_pSpawnTimeDistance->ResetParam(0.35f);
m_pSize->ResetParam(5.0f);
m_pSizeVar->ResetParam(2.5f);
m_nAliveDrops = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CHudSilhouettes::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pActive->ResetParam(0.0f);
m_pAmount->ResetParam(1.0f);
m_pType->ResetParam(1);
FindIfSilhouettesOptimisedTechAvailable();
}
bool CHudSilhouettes::Preprocess()
{
if ((CRenderer::CV_r_customvisions != 3) || (m_bSilhouettesOptimisedTechAvailable))
{
if (!CRenderer::CV_r_PostProcessGameFx ||
!CRenderer::CV_r_customvisions ||
gRenDev->IsPost3DRendererEnabled())
{
return false;
}
// no need to proceed
float fType = m_pType->GetParam();
uint32 nBatchMask = SRendItem::BatchFlags(EFSLIST_GENERAL, gRenDev->m_RP.m_pRLD) | SRendItem::BatchFlags(EFSLIST_TRANSP, gRenDev->m_RP.m_pRLD);
if ((!(nBatchMask & FB_CUSTOM_RENDER)) && fType == 1.0f)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CFlashBang::Release()
{
SAFE_DELETE(m_pGhostImage);
}
void CFlashBang::Reset([[maybe_unused]] bool bOnSpecChange)
{
SAFE_DELETE(m_pGhostImage);
m_pActive->ResetParam(0.0f);
m_pTime->ResetParam(2.0f);
m_pDifractionAmount->ResetParam(1.0f);
m_pBlindAmount->ResetParam(0.5f);
m_fBlindAmount = 1.0f;
m_fSpawnTime = 0.0f;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CSoftAlphaTest::Reset([[maybe_unused]] bool bOnSpecChange)
{
}
bool CSoftAlphaTest::Preprocess()
{
uint32 nBatchMask = SRendItem::BatchFlags(EFSLIST_GENERAL, gRenDev->m_RP.m_pRLD);
return CRenderer::CV_r_SoftAlphaTest != 0 && (nBatchMask & FB_SOFTALPHATEST);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CImageGhosting::Preprocess()
{
CTexture* pPrevFrame = CTexture::s_ptexPrevFrameScaled;
if (!pPrevFrame)
{
m_bInit = true;
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
m_bInit = true;
return false;
}
void CImageGhosting::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_bInit = true;
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CFilterKillCamera::Initialize()
{
m_techName = "KillCameraFilter";
m_paramName = "psParams";
return 1;
}
bool CFilterKillCamera::Preprocess()
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessFilters)
{
return false;
}
if (m_pActive->GetParam() > 0.0f)
{
const int mode = int_round(m_pMode->GetParam());
if (mode != m_lastMode)
{
m_blindTimer = 0.0f;
m_lastMode = mode;
}
return true;
}
m_blindTimer = 0.0f;
return false;
}
void CFilterKillCamera::Reset([[maybe_unused]] bool bOnSpecChange)
{
// Game controls parameters + reset (removed from here due to a race condition).
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CScreenBlood::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pBorder->ResetParamVec4(Vec4(0.0f, 0.0f, 2.0f, 1.0f)); // Border: x=xOffset y=yOffset z=range w=alpha
}
bool CScreenBlood::Preprocess()
{
return (CRenderer::CV_r_PostProcessGameFx && m_pAmount->GetParam() > 0.005f);
}
//////////////////////////////////////////////////////////////////////////
bool CPost3DRenderer::Preprocess()
{
if (IsActive())
{
// Defer turning off post effect for 5 frames - sometimes the flash is left rendering on the screen
// for a frame, if we don't render the post effect for this frame then junk will be rendered into
// the flash. Currently the post effect is disabled at the latest point in menu code, thus this is the
// simplest/safest fix.
m_deferDisableFrameCountDown = 5;
}
else if (m_deferDisableFrameCountDown > 0)
{
m_deferDisableFrameCountDown--;
}
const bool bRender = (m_deferDisableFrameCountDown > 0) ? true : false;
return bRender;
}
void CPost3DRenderer::Reset([[maybe_unused]] bool bOnSpecChange)
{
// Let game code fully control its active status, otherwise in some situations
// the post effect system will get reset between menus and game and thus this
// will get turned off when undesired
}
//////////////////////////////////////////////////////////////////////////
// AZStd visitor class to resolve the effect parameter into the appropriate type
class FetchVisitor
{
public:
void SetEffectParam( CEffectParam* effectParameter )
{
m_effectParam = effectParameter;
}
void operator()(float param)
{
m_effectParam->SetParam(param);
}
void operator()(const Vec4& param)
{
m_effectParam->SetParamVec4(param);
}
void operator()(const AZStd::string& param)
{
m_effectParam->SetParamString(param.c_str());
}
private:
CEffectParam* m_effectParam = nullptr;
};
// Helper function to set a CEffectParam from a group, visitor and parameter name
void SetEffectParamFromVisitor( IPostEffectGroup* group, FetchVisitor& fetchVisitor, const char* paramName, CEffectParam* effectParam /* in/out */ )
{
PostEffectGroupParam* groupParam = group->GetParam(paramName);
fetchVisitor.SetEffectParam( effectParam );
AZStd::visit(fetchVisitor, *groupParam);
}
bool ScreenFader::Preprocess()
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
IPostEffectGroupManager* groupManager = gEnv->p3DEngine->GetPostEffectGroups();
const PostEffectGroupList& toggledGroupList = groupManager->GetGroupsToggledThisFrame();
bool newScreenPassAdded = false;
// Iterate over all of the groups that had their enabled/disabled flag toggled this frame
// If the group already exists in the screenpass list, then that should mean it either needs change its
// state to fade-in (if it was actively fading-out), or it needs to change to fade-out (if it was actively fading in or rendering at full opacity)
// Once a group has faded out completely, then it will be removed from the screenpass list.
for ( auto groupIter = toggledGroupList.begin(); groupIter != toggledGroupList.end(); ++groupIter )
{
IPostEffectGroup* group = (*groupIter);
bool foundGroupInList = false;
for ( ScreenPassList::iterator passIter = m_screenPasses.begin(); passIter != m_screenPasses.end(); ++passIter )
{
ScreenFaderPass* pass = (*passIter);
if ( pass->m_group == group )
{
foundGroupInList = true;
if ( group->GetEnable() )
{
// If the group has changed to enabled, then that means the group was actively fading out before
// Change its state to fade-in, and fade from its existing alpha value.
pass->m_fadingIn = true;
pass->m_fadingOut = false;
pass->m_fadeDirection = 1.0f;
pass->m_fadeDuration = pass->m_fadeInTime;
}
else
{
// If the group has changed to disabled, then that means we were either actively fading in or rendering at full opacity.
// Change its state to fade out and fade from its existing alpha value
pass->m_fadingIn = false;
pass->m_fadingOut = true;
pass->m_fadeDirection = -1.0f;
pass->m_fadeDuration = pass->m_fadeOutTime;
}
break;
}
}
// If the group was not found, then add it to the list
if ( !foundGroupInList )
{
FetchVisitor groupParamVisitor;
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_Enable", m_enable );
bool fadeIn = m_enable->GetParam() ? true : false;
if ( fadeIn )
{
// The screen fader is different from the other PostEffects in the PostEffectsGroups.
// We do not want the interpolated parameters when enabling another group since we want to render
// multiple stacked screenfaders. Fetch the parameters from the original PostEffectGroup for this
// screen fader pass
ScreenFaderPass* pass = new ScreenFaderPass();
pass->m_group = group;
pass->m_fadingIn = true;
pass->m_fadeDirection = 1.0f;
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_FadeColor", m_fadeColor );
pass->m_currentColor = m_fadeColor->GetParamVec4();
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_ScreenCoordinates", m_screenCoordinates );
pass->m_screenCoordinates = m_screenCoordinates->GetParamVec4();
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_TextureName", m_fadeTextureParam );
pass->m_fadeTexture = static_cast<CParamTexture*>(m_fadeTextureParam)->GetParamTexture();
if (pass->m_fadeTexture)
{
// Since we are manually holding onto a CTexture pointer, make sure we increment the ref count
pass->m_fadeTexture->AddRef();
}
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_FadeOutTime", m_fadeOutTime );
pass->m_fadeOutTime = m_fadeOutTime->GetParam();
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_FadeInTime", m_fadeInTime );
pass->m_fadeInTime = m_fadeInTime->GetParam();
pass->m_fadeDuration = pass->m_fadeInTime;
m_screenPasses.push_back( pass );
newScreenPassAdded = true;
}
}
}
// If we added a new ScreenPass, then re-sort our ScreenPasses based on the PostEffectGroup's priorities
if ( newScreenPassAdded )
{
m_screenPasses.sort(SortFaderPasses);
}
// Update all of the screen passes, removing any that have recently faded out from the list.
auto passIter = m_screenPasses.begin();
while ( passIter != m_screenPasses.end() )
{
ScreenFaderPass* pass = (*passIter);
if ( pass->m_fadingOut && pass->m_currentFadeTime <= 0.0f )
{
// We have finished fading out. Now clean up the list and remove the pass.
delete pass;
passIter = m_screenPasses.erase(passIter);
}
else if ( pass->m_fadingIn && (pass->m_currentFadeTime >= pass->m_fadeDuration) )
{
// We have finished fading in. Stay at 100% fade time until fade out is triggered.
pass->m_currentFadeTime = pass->m_fadeDuration;
pass->m_fadingIn = false;
}
++passIter;
}
return m_screenPasses.size() > 0;
}
void ScreenFader::Reset([[maybe_unused]] bool bOnSpecChange)
{
// Do not clear m_screenPasses here, otherwise global and default PostEffectGroups will be removed
}
bool ScreenFader::SortFaderPasses(ScreenFaderPass* pass1, ScreenFaderPass* pass2)
{
return pass1->m_group->GetPriority() < pass2->m_group->GetPriority();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////