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/Gems/GameEffectSystem/Code/source/GameEffectsSystem.cpp

1013 lines
40 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.
*
*/
//==================================================================================================
// Name: CGameEffectsSystem
// Desc: System to handle game effects, render nodes and render elements
// Author: James Chilvers
//==================================================================================================
// Includes
#include "GameEffectSystem_precompiled.h"
#include "GameEffectsSystem.h"
#include "BitFiddling.h"
#include "RenderElements/GameRenderElement.h"
#include <GameEffectSystem/IGameRenderNode.h>
#include <GameEffectSystem/GameEffects/IGameEffect.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
//--------------------------------------------------------------------------------------------------
// Desc: Defines
//--------------------------------------------------------------------------------------------------
#define GAME_FX_DATA_FILE "scripts/effects/gameeffects.xml"
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Desc: Debug data
//--------------------------------------------------------------------------------------------------
#if DEBUG_GAME_FX_SYSTEM
int CGameEffectsSystem::s_currentDebugEffectId = 0;
const char* GAME_FX_DEBUG_VIEW_NAMES[eMAX_GAME_FX_DEBUG_VIEWS] = {
"None", "Profiling",
"Effect List", "Bounding Box",
"Bounding Sphere", "Particles"
};
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Desc: Static data
//--------------------------------------------------------------------------------------------------
int CGameEffectsSystem::s_postEffectCVarNameOffset = 0;
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//==================================================================================================
// Name: CGameRenderNodeSoftCodeListener
// Desc: Game Render Node Soft Code Listener
// Author: James Chilvers
//==================================================================================================
class CGameRenderNodeSoftCodeListener
: public ISoftCodeListener
{
public:
CGameRenderNodeSoftCodeListener()
{
if (gEnv->pSoftCodeMgr)
{
gEnv->pSoftCodeMgr->AddListener(GAME_RENDER_NODE_LIBRARY_NAME, this,
GAME_RENDER_NODE_LISTENER_NAME);
}
}
virtual ~CGameRenderNodeSoftCodeListener()
{
if (gEnv->pSoftCodeMgr)
{
gEnv->pSoftCodeMgr->RemoveListener(GAME_RENDER_NODE_LIBRARY_NAME, this);
}
}
virtual void InstanceReplaced(void* pOldInstance, void* pNewInstance)
{
GAME_FX_SYSTEM.GameRenderNodeInstanceReplaced(pOldInstance, pNewInstance);
}
}; //------------------------------------------------------------------------------------------------
//==================================================================================================
// Name: CGameRenderElementSoftCodeListener
// Desc: Game Render Element Soft Code Listener
// Author: James Chilvers
//==================================================================================================
class CGameRenderElementSoftCodeListener
: public ISoftCodeListener
{
public:
CGameRenderElementSoftCodeListener()
{
if (gEnv->pSoftCodeMgr)
{
gEnv->pSoftCodeMgr->AddListener(GAME_RENDER_ELEMENT_LIBRARY_NAME, this,
GAME_RENDER_ELEMENT_LISTENER_NAME);
}
}
virtual ~CGameRenderElementSoftCodeListener()
{
if (gEnv->pSoftCodeMgr)
{
gEnv->pSoftCodeMgr->RemoveListener(GAME_RENDER_ELEMENT_LIBRARY_NAME, this);
}
}
virtual void InstanceReplaced(void* pOldInstance, void* pNewInstance)
{
GAME_FX_SYSTEM.GameRenderElementInstanceReplaced(pOldInstance, pNewInstance);
}
}; //------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: CGameEffectsSystem
// Desc: Constructor
//--------------------------------------------------------------------------------------------------
CGameEffectsSystem::CGameEffectsSystem()
: AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDebug())
{
#if DEBUG_GAME_FX_SYSTEM
AzFramework::InputChannelEventListener::Connect();
#endif
#ifdef SOFTCODE_ENABLED
if (gEnv->pSoftCodeMgr)
{
gEnv->pSoftCodeMgr->AddListener(GAME_FX_LIBRARY_NAME, this, GAME_FX_LISTENER_NAME);
}
m_gameRenderNodes.clear();
m_gameRenderNodeSoftCodeListener = new CGameRenderNodeSoftCodeListener;
m_gameRenderElements.clear();
m_gameRenderElementSoftCodeListener = new CGameRenderElementSoftCodeListener;
RegisterSoftCodeLib(IGameEffect::TLibrary::Instance());
RegisterSoftCodeLib(IGameRenderNode::TLibrary::Instance());
RegisterSoftCodeLib(IGameRenderElement::TLibrary::Instance());
#endif
Reset();
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: ~CGameEffectsSystem
// Desc: Destructor
//--------------------------------------------------------------------------------------------------
CGameEffectsSystem::~CGameEffectsSystem()
{
#if DEBUG_GAME_FX_SYSTEM
AzFramework::InputChannelEventListener::Disconnect();
#endif
#ifdef SOFTCODE_ENABLED
if (gEnv->pSoftCodeMgr)
{
gEnv->pSoftCodeMgr->RemoveListener(GAME_FX_LIBRARY_NAME, this);
}
SAFE_DELETE(m_gameRenderNodeSoftCodeListener);
SAFE_DELETE(m_gameRenderElementSoftCodeListener);
m_softCodeTypeLibs.clear();
m_gameRenderNodes.clear();
m_gameRenderElements.clear();
#endif
AZ::TickBus::Handler::BusDisconnect();
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Destroy
// Desc: Destroys effects system
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::Destroy()
{
EBUS_EVENT(GameEffectSystemNotificationBus, OnReleaseGameEffects);
AutoReleaseAndDeleteFlaggedEffects(m_effectsToUpdate);
AutoReleaseAndDeleteFlaggedEffects(m_effectsNotToUpdate);
FX_ASSERT_MESSAGE(m_effectsToUpdate == nullptr && m_effectsNotToUpdate == nullptr,
"Game Effects System being destroyed even though game effects still exist!");
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Reset
// Desc: Resets effects systems data
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::Reset()
{
m_isInitialised = false;
m_effectsToUpdate = NULL;
m_effectsNotToUpdate = NULL;
m_nextEffectToUpdate = NULL;
s_postEffectCVarNameOffset = 0;
#if DEBUG_GAME_FX_SYSTEM
m_debugView = eGAME_FX_DEBUG_VIEW_None;
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Initialize
// Desc: Initializes effects system
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::Initialize()
{
if (m_isInitialised == false)
{
Reset();
SetPostEffectCVarCallbacks();
AZ::TickBus::Handler::BusConnect();
m_isInitialised = true;
}
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: GameRulesInitialise
// Desc: Game Rules initialise
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::GameRulesInitialise()
{
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: LoadData
// Desc: Loads data for game effects system and effects
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::LoadData()
{
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: ReleaseData
// Desc: Releases any loaded data for game effects system and any effects with registered callbacks
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::ReleaseData()
{
if (s_hasLoadedData)
{
#if DEBUG_GAME_FX_SYSTEM
// Unload all debug effects which rely on effect data
for (size_t i = 0; i < s_effectDebugList.Size(); i++)
{
if (s_effectDebugList[i].inputCallback)
{
s_effectDebugList[i].inputCallback(GAME_FX_INPUT_ReleaseDebugEffect);
}
}
#endif
for (IGameEffect* ge = m_effectsToUpdate; ge; ge = ge->Next())
{
ge->UnloadData();
}
for (IGameEffect* ge = m_effectsNotToUpdate; ge; ge = ge->Next())
{
ge->UnloadData();
}
s_hasLoadedData = false;
}
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: ReloadData
// Desc: Reloads any loaded data for game effects registered callbacks
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::ReloadData()
{
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: EnteredGame
// Desc: Called when entering a game
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::EnteredGame()
{
const int callbackCount = s_enteredGameCallbackList.size();
EnteredGameCallback enteredGameCallbackFunc = NULL;
for (int i = 0; i < callbackCount; i++)
{
enteredGameCallbackFunc = s_enteredGameCallbackList[i];
if (enteredGameCallbackFunc)
{
enteredGameCallbackFunc();
}
}
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: AutoReleaseAndDeleteFlaggedEffects
// Desc: Calls release and delete on any effects with the these flags set
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::AutoReleaseAndDeleteFlaggedEffects(IGameEffect* effectList)
{
if (effectList)
{
IGameEffect* effect = effectList;
while (effect)
{
m_nextEffectToUpdate = effect->Next();
bool autoRelease = effect->IsFlagSet(GAME_EFFECT_AUTO_RELEASE);
bool autoDelete = effect->IsFlagSet(GAME_EFFECT_AUTO_DELETE);
if (autoRelease || autoDelete)
{
SOFTCODE_RETRY(effect, effect->Release());
if (autoDelete)
{
SAFE_DELETE(effect);
}
}
effect = m_nextEffectToUpdate;
}
m_nextEffectToUpdate = NULL;
}
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: InstanceReplaced
// Desc: Replaces instance for soft coding
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::InstanceReplaced([[maybe_unused]] void* pOldInstance, [[maybe_unused]] void* pNewInstance)
{
#ifdef SOFTCODE_ENABLED
if (pNewInstance && pOldInstance)
{
IGameEffect* pNewGameEffectInstance = static_cast<IGameEffect*>(pNewInstance);
IGameEffect* pOldGameEffectInstance = static_cast<IGameEffect*>(pOldInstance);
// Copy over flags and remove registered flag so new effect instance can be registered
// We haven't used the SOFT macro on the m_flags member because the oldInstance's flags
// would then be Nulled out, and they are needed for the effect to be deregistered
uint32 oldGameEffectFlags = pOldGameEffectInstance->GetFlags();
SET_FLAG(oldGameEffectFlags, GAME_EFFECT_REGISTERED, false);
pNewGameEffectInstance->SetFlags(oldGameEffectFlags);
// Register new effect instance, old instance will get unregistered by destructor
GAME_FX_SYSTEM.RegisterEffect(pNewGameEffectInstance);
// Reload all data used by effects, then data can be added/removed for soft coding
ReloadData();
// Data used by effect will be copied to new effect, so mustn't release it but
// must set flag so destructor doesn't assert
pOldGameEffectInstance->SetFlag(GAME_EFFECT_RELEASED, true);
}
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: GameRenderNodeInstanceReplaced
// Desc: Replaces Game Render Node instance for soft coding
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::GameRenderNodeInstanceReplaced([[maybe_unused]] void* pOldInstance, [[maybe_unused]] void* pNewInstance)
{
#ifdef SOFTCODE_ENABLED
if (pOldInstance && pNewInstance)
{
IGameRenderNode* pOldGameRenderNodeInstance = (IGameRenderNode*)pOldInstance;
IGameRenderNode* pNewGameRenderNodeInstance = (IGameRenderNode*)pNewInstance;
// Unregister old node from engine
gEnv->p3DEngine->FreeRenderNodeState(pOldGameRenderNodeInstance);
// Register new node with engine
gEnv->p3DEngine->RegisterEntity(pNewGameRenderNodeInstance);
for (TGameRenderNodeVec::iterator iter(m_gameRenderNodes.begin());
iter != m_gameRenderNodes.end(); ++iter)
{
IGameRenderNodePtr* ppRenderNode = *iter;
if (ppRenderNode)
{
IGameRenderNodePtr& pRenderNode = *ppRenderNode;
if (pRenderNode == pOldGameRenderNodeInstance)
{
pRenderNode = pNewGameRenderNodeInstance;
}
}
}
}
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: GameRenderElementInstanceReplaced
// Desc: Replaces Game Render Element instance for soft coding
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::GameRenderElementInstanceReplaced([[maybe_unused]] void* pOldInstance, [[maybe_unused]] void* pNewInstance)
{
#ifdef SOFTCODE_ENABLED
if (pOldInstance && pNewInstance)
{
IGameRenderElement* pOldGameRenderElementInstance = (IGameRenderElement*)pOldInstance;
IGameRenderElement* pNewGameRenderElementInstance = (IGameRenderElement*)pNewInstance;
pNewGameRenderElementInstance->UpdatePrivateImplementation();
for (TGameRenderElementVec::iterator iter(m_gameRenderElements.begin());
iter != m_gameRenderElements.end(); ++iter)
{
IGameRenderElementPtr* ppRenderElement = *iter;
if (ppRenderElement)
{
IGameRenderElementPtr& pRenderElement = *ppRenderElement;
if (pRenderElement == pOldGameRenderElementInstance)
{
pRenderElement = pNewGameRenderElementInstance;
}
}
}
}
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: SetPostEffectCVarCallbacks
// Desc: Sets Post effect CVar callbacks for testing and tweaking post effect values
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::SetPostEffectCVarCallbacks()
{
#if DEBUG_GAME_FX_SYSTEM
ICVar* postEffectCvar = NULL;
const char postEffectNames[][64] =
{
"g_postEffect.FilterGrain_Amount", "g_postEffect.FilterRadialBlurring_Amount",
"g_postEffect.FilterRadialBlurring_ScreenPosX",
"g_postEffect.FilterRadialBlurring_ScreenPosY", "g_postEffect.FilterRadialBlurring_Radius",
"g_postEffect.Global_User_ColorC", "g_postEffect.Global_User_ColorM",
"g_postEffect.Global_User_ColorY", "g_postEffect.Global_User_ColorK",
"g_postEffect.Global_User_Brightness", "g_postEffect.Global_User_Contrast",
"g_postEffect.Global_User_Saturation", "g_postEffect.Global_User_ColorHue"
};
int postEffectNameCount = sizeof(postEffectNames) / sizeof(*postEffectNames);
if (postEffectNameCount > 0)
{
// Calc name offset
const char* postEffectName = postEffectNames[0];
s_postEffectCVarNameOffset = 0;
while ((*postEffectName) != 0)
{
s_postEffectCVarNameOffset++;
if ((*postEffectName) == '.')
{
break;
}
postEffectName++;
}
// Set callback functions
for (int i = 0; i < postEffectNameCount; i++)
{
postEffectCvar = gEnv->pConsole->GetCVar(postEffectNames[i]);
if (postEffectCvar)
{
postEffectCvar->SetOnChangeCallback(PostEffectCVarCallback);
}
}
}
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: PostEffectCVarCallback
// Desc: Callback function of post effect cvars to set their values
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::PostEffectCVarCallback(ICVar* cvar)
{
const char* effectName = cvar->GetName() + s_postEffectCVarNameOffset;
gEnv->p3DEngine->SetPostEffectParam(effectName, cvar->GetFVal());
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: RegisterEffect
// Desc: Registers effect with effect system
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::RegisterEffect(IGameEffect* effect)
{
FX_ASSERT_MESSAGE(m_isInitialised,
"Game Effects System trying to register an effect without being initialised");
FX_ASSERT_MESSAGE(effect, "Trying to Register a NULL effect");
if (effect)
{
// If effect is registered, then unregister first
if (effect->IsFlagSet(GAME_EFFECT_REGISTERED))
{
UnRegisterEffect(effect);
}
// Add effect to effect list
IGameEffect** effectList = NULL;
bool isActive = effect->IsFlagSet(GAME_EFFECT_ACTIVE);
bool autoUpdatesWhenActive = effect->IsFlagSet(GAME_EFFECT_AUTO_UPDATES_WHEN_ACTIVE);
bool autoUpdatesWhenNotActive = effect->IsFlagSet(GAME_EFFECT_AUTO_UPDATES_WHEN_NOT_ACTIVE);
if ((isActive && autoUpdatesWhenActive) || ((!isActive) && autoUpdatesWhenNotActive))
{
effectList = &m_effectsToUpdate;
}
else
{
effectList = &m_effectsNotToUpdate;
}
if (*effectList)
{
(*effectList)->SetPrev(effect);
effect->SetNext(*effectList);
}
(*effectList) = effect;
effect->SetFlag(GAME_EFFECT_REGISTERED, true);
}
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: UnRegisterEffect
// Desc: UnRegisters effect from effect system
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::UnRegisterEffect(IGameEffect* effect)
{
FX_ASSERT_MESSAGE(
m_isInitialised,
"Game Effects System trying to unregister an effect without being initialised");
FX_ASSERT_MESSAGE(effect, "Trying to UnRegister a NULL effect");
if (effect && effect->IsFlagSet(GAME_EFFECT_REGISTERED))
{
// If the effect is the next one to be updated, then point m_nextEffectToUpdate to the next
// effect after it
if (effect == m_nextEffectToUpdate)
{
m_nextEffectToUpdate = m_nextEffectToUpdate->Next();
}
if (effect->Prev())
{
effect->Prev()->SetNext(effect->Next());
}
else
{
if (m_effectsToUpdate == effect)
{
m_effectsToUpdate = effect->Next();
}
else
{
FX_ASSERT_MESSAGE((m_effectsNotToUpdate == effect),
"Effect isn't either updating list");
m_effectsNotToUpdate = effect->Next();
}
}
if (effect->Next())
{
effect->Next()->SetPrev(effect->Prev());
}
effect->SetNext(NULL);
effect->SetPrev(NULL);
effect->SetFlag(GAME_EFFECT_REGISTERED, false);
}
} //-------------------------------------------------------------------------------------------------
void CGameEffectsSystem::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
Update(deltaTime);
}
//--------------------------------------------------------------------------------------------------
// Name: Update
// Desc: Updates effects system and any effects registered in it's update list
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::Update(float frameTime)
{
FX_ASSERT_MESSAGE(m_isInitialised,
"Game Effects System trying to update without being initialised");
// Update effects
if (m_effectsToUpdate)
{
IGameEffect* effect = m_effectsToUpdate;
while (effect)
{
m_nextEffectToUpdate = effect->Next();
if (effect->IsFlagSet(GAME_EFFECT_UPDATE_WHEN_PAUSED))
{
SOFTCODE_RETRY(effect, effect->Update(frameTime));
}
effect = m_nextEffectToUpdate;
}
}
m_nextEffectToUpdate = NULL;
#if DEBUG_GAME_FX_SYSTEM
DrawDebugDisplay();
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: CreateSoftCodeInstance
// Desc: Creates soft code instance
//--------------------------------------------------------------------------------------------------
#ifdef SOFTCODE_ENABLED
void* CGameEffectsSystem::CreateSoftCodeInstance(const char* pTypeName)
{
void* pNewInstance = NULL;
if (pTypeName)
{
for (std::vector<ITypeLibrary*>::iterator iter(m_softCodeTypeLibs.begin());
iter != m_softCodeTypeLibs.end(); ++iter)
{
ITypeLibrary* pLib = *iter;
if (pLib)
{
if (pNewInstance = pLib->CreateInstanceVoid(pTypeName))
{
break;
}
}
}
}
return pNewInstance;
}
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: RegisterSoftCodeLib
// Desc: Register soft code lib for creation of instances
//--------------------------------------------------------------------------------------------------
#ifdef SOFTCODE_ENABLED
void CGameEffectsSystem::RegisterSoftCodeLib(ITypeLibrary* pLib)
{
m_softCodeTypeLibs.push_back(pLib);
};
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: RegisterGameRenderNode
// Desc: Registers game render node
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::RegisterGameRenderNode([[maybe_unused]] IGameRenderNodePtr& pGameRenderNode)
{
#ifdef SOFTCODE_ENABLED
for (TGameRenderNodeVec::iterator iter(m_gameRenderNodes.begin());
iter != m_gameRenderNodes.end(); ++iter)
{
IGameRenderNodePtr* ppIterRenderNode = *iter;
if (ppIterRenderNode == NULL)
{
*iter = &pGameRenderNode;
return;
}
}
m_gameRenderNodes.push_back(&pGameRenderNode);
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: UnregisterGameRenderNode
// Desc: Unregisters game render node
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::UnregisterGameRenderNode([[maybe_unused]] IGameRenderNodePtr& pGameRenderNode)
{
#ifdef SOFTCODE_ENABLED
TGameRenderNodeVec::iterator iter(
std::find(m_gameRenderNodes.begin(), m_gameRenderNodes.end(), &pGameRenderNode));
if (iter != m_gameRenderNodes.end())
{
*iter = NULL;
}
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: RegisterGameRenderElement
// Desc: Registers game render element
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::RegisterGameRenderElement([[maybe_unused]] IGameRenderElementPtr& pGameRenderElement)
{
#ifdef SOFTCODE_ENABLED
for (TGameRenderElementVec::iterator iter(m_gameRenderElements.begin());
iter != m_gameRenderElements.end(); ++iter)
{
IGameRenderElementPtr* ppIterRenderElement = *iter;
if (ppIterRenderElement == NULL)
{
*iter = &pGameRenderElement;
return;
}
}
m_gameRenderElements.push_back(&pGameRenderElement);
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: UnregisterGameRenderElement
// Desc: Unregisters game render element
//--------------------------------------------------------------------------------------------------
void CGameEffectsSystem::UnregisterGameRenderElement([[maybe_unused]] IGameRenderElementPtr& pGameRenderElement)
{
#ifdef SOFTCODE_ENABLED
TGameRenderElementVec::iterator iter(
std::find(m_gameRenderElements.begin(), m_gameRenderElements.end(), &pGameRenderElement));
if (iter != m_gameRenderElements.end())
{
*iter = NULL;
}
#endif
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: DrawDebugDisplay
// Desc: Draws debug display
//--------------------------------------------------------------------------------------------------
#if DEBUG_GAME_FX_SYSTEM
void CGameEffectsSystem::DrawDebugDisplay()
{
static ColorF textCol(1.0f, 1.0f, 1.0f, 1.0f);
static ColorF controlCol(0.6f, 0.6f, 0.6f, 1.0f);
static Vec2 textPos(10.0f, 10.0f);
static float textSize = 1.4f;
static float textYSpacing = 18.0f;
static float effectNameXOffset = 100.0f;
static ColorF effectNameCol(0.0f, 1.0f, 0.0f, 1.0f);
Vec2 currentTextPos = textPos;
int debugEffectCount = s_effectDebugList.Size();
if (GetISystem()->GetIConsole()->GetCVar("g_gameFXSystemDebug")->GetIVal() && debugEffectCount > 0)
{
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &textCol.r,
false, "Debug view:");
gEnv->pRenderer->Draw2dLabel(currentTextPos.x + effectNameXOffset, currentTextPos.y,
textSize, &effectNameCol.r, false,
GAME_FX_DEBUG_VIEW_NAMES[m_debugView]);
currentTextPos.y += textYSpacing;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &controlCol.r,
false, "(Change debug view: Left/Right arrows)");
currentTextPos.y += textYSpacing;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &textCol.r,
false, "Debug effect:");
gEnv->pRenderer->Draw2dLabel(currentTextPos.x + effectNameXOffset, currentTextPos.y,
textSize, &effectNameCol.r, false,
s_effectDebugList[s_currentDebugEffectId].effectName);
currentTextPos.y += textYSpacing;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &controlCol.r,
false, "(Change effect: NumPad +/-)");
currentTextPos.y += textYSpacing;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &controlCol.r,
false, "(Reload effect data: NumPad .)");
currentTextPos.y += textYSpacing;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &controlCol.r,
false, "(Reset Particle System: Delete)");
currentTextPos.y += textYSpacing;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize, &controlCol.r,
false, "(Pause Particle System: End)");
currentTextPos.y += textYSpacing;
if (s_effectDebugList[s_currentDebugEffectId].displayCallback)
{
s_effectDebugList[s_currentDebugEffectId].displayCallback(currentTextPos, textSize,
textYSpacing);
}
if (m_debugView == eGAME_FX_DEBUG_VIEW_EffectList)
{
static Vec2 listPos(350.0f, 50.0f);
static float nameSize = 150.0f;
static float tabSize = 60.0f;
currentTextPos = listPos;
const int EFFECT_LIST_COUNT = 2;
IGameEffect* pEffectListArray[EFFECT_LIST_COUNT] = {
m_effectsToUpdate,
m_effectsNotToUpdate
};
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize,
&effectNameCol.r, false, "Name");
currentTextPos.x += nameSize;
const int FLAG_COUNT = 9;
const char* flagName[FLAG_COUNT] = {
"Init", "Rel", "ARels", "ADels", "AUWA",
"AUWnA", "Reg", "Actv", "DBG"
};
const int flag[FLAG_COUNT] = {
GAME_EFFECT_INITIALISED, GAME_EFFECT_RELEASED,
GAME_EFFECT_AUTO_RELEASE, GAME_EFFECT_AUTO_DELETE,
GAME_EFFECT_AUTO_UPDATES_WHEN_ACTIVE,
GAME_EFFECT_AUTO_UPDATES_WHEN_NOT_ACTIVE,
GAME_EFFECT_REGISTERED, GAME_EFFECT_ACTIVE,
GAME_EFFECT_DEBUG_EFFECT
};
for (int i = 0; i < FLAG_COUNT; i++)
{
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize,
&effectNameCol.r, false, flagName[i]);
currentTextPos.x += tabSize;
}
currentTextPos.y += textYSpacing;
for (int l = 0; l < EFFECT_LIST_COUNT; l++)
{
IGameEffect* pCurrentEffect = pEffectListArray[l];
while (pCurrentEffect)
{
currentTextPos.x = listPos.x;
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize,
&textCol.r, false, pCurrentEffect->GetName());
currentTextPos.x += nameSize;
for (int i = 0; i < FLAG_COUNT; i++)
{
gEnv->pRenderer->Draw2dLabel(currentTextPos.x, currentTextPos.y, textSize,
&textCol.r, false,
pCurrentEffect->IsFlagSet(flag[i]) ? "1"
: "0");
currentTextPos.x += tabSize;
}
currentTextPos.y += textYSpacing;
pCurrentEffect = pCurrentEffect->Next();
}
}
}
}
}
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: OnInputChannelEventFiltered
// Desc: Handles any debug input for the game effects system to test effects
//--------------------------------------------------------------------------------------------------
bool CGameEffectsSystem::OnInputChannelEventFiltered([[maybe_unused]] const AzFramework::InputChannel& inputChannel)
{
#if DEBUG_GAME_FX_SYSTEM
int debugEffectCount = s_effectDebugList.Size();
if ((GetISystem()->GetIConsole()->GetCVar("g_gameFXSystemDebug")->GetIVal()) && (debugEffectCount > 0))
{
if (AzFramework::InputDeviceKeyboard::IsKeyboardDevice(inputChannel.GetInputDevice().GetInputDeviceId()) &&
inputChannel.IsStateBegan())
{
const AZ::Crc32& inputChannelNameCrc32 = inputChannel.GetInputChannelId().GetNameCrc32();
if (inputChannelNameCrc32 == GAME_FX_INPUT_IncrementDebugEffectId)
{
if (s_currentDebugEffectId < (debugEffectCount - 1))
{
s_currentDebugEffectId++;
}
}
else if (inputChannelNameCrc32 == GAME_FX_INPUT_DecrementDebugEffectId)
{
if (s_currentDebugEffectId > 0)
{
s_currentDebugEffectId--;
}
}
else if (inputChannelNameCrc32 == GAME_FX_INPUT_DecrementDebugView)
{
if (m_debugView > 0)
{
OnDeActivateDebugView(m_debugView);
m_debugView--;
OnActivateDebugView(m_debugView);
}
}
else if (inputChannelNameCrc32 == GAME_FX_INPUT_IncrementDebugView)
{
if (m_debugView < (eMAX_GAME_FX_DEBUG_VIEWS - 1))
{
OnDeActivateDebugView(m_debugView);
m_debugView++;
OnActivateDebugView(m_debugView);
}
}
else if (inputChannelNameCrc32 == GAME_FX_INPUT_ReloadEffectData)
{
ReloadData();
}
// Send input to current debug effect
if (s_effectDebugList[s_currentDebugEffectId].inputCallback)
{
s_effectDebugList[s_currentDebugEffectId].inputCallback(inputChannelNameCrc32);
}
}
}
#endif
return false; // Return false so that other listeners will get this event
} //-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: GetDebugEffect
// Desc: Gets debug instance of effect
//--------------------------------------------------------------------------------------------------
#if DEBUG_GAME_FX_SYSTEM
IGameEffect* CGameEffectsSystem::GetDebugEffect(const char* pEffectName) const
{
const int EFFECT_LIST_COUNT = 2;
IGameEffect* pEffectListArray[EFFECT_LIST_COUNT] = {m_effectsToUpdate, m_effectsNotToUpdate};
for (int l = 0; l < EFFECT_LIST_COUNT; l++)
{
IGameEffect* pCurrentEffect = pEffectListArray[l];
while (pCurrentEffect)
{
if (pCurrentEffect->IsFlagSet(GAME_EFFECT_DEBUG_EFFECT) &&
(strcmp(pCurrentEffect->GetName(), pEffectName) == 0))
{
return pCurrentEffect;
}
pCurrentEffect = pCurrentEffect->Next();
}
}
return NULL;
}
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: OnActivateDebugView
// Desc: Called on debug view activation
//--------------------------------------------------------------------------------------------------
#if DEBUG_GAME_FX_SYSTEM
void CGameEffectsSystem::OnActivateDebugView(int debugView)
{
switch (debugView)
{
case eGAME_FX_DEBUG_VIEW_Profiling:
{
ICVar* r_displayInfoCVar = gEnv->pConsole->GetCVar("r_DisplayInfo");
if (r_displayInfoCVar)
{
r_displayInfoCVar->Set(1);
}
break;
}
}
}
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: OnDeActivateDebugView
// Desc: Called on debug view de-activation
//--------------------------------------------------------------------------------------------------
#if DEBUG_GAME_FX_SYSTEM
void CGameEffectsSystem::OnDeActivateDebugView(int debugView)
{
switch (debugView)
{
case eGAME_FX_DEBUG_VIEW_Profiling:
{
ICVar* r_displayInfoCVar = gEnv->pConsole->GetCVar("r_DisplayInfo");
if (r_displayInfoCVar)
{
r_displayInfoCVar->Set(0);
}
break;
}
}
}
#endif
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: RegisterEffectDebugData
// Desc: Registers effect's debug data with the game effects system, which will then call the
// relevant debug callback functions for the for the effect when its selected
//using the
// s_currentDebugEffectId
//--------------------------------------------------------------------------------------------------
#if DEBUG_GAME_FX_SYSTEM
void IGameEffectSystem::RegisterEffectDebugData(DebugOnInputEventCallback inputEventCallback,
DebugDisplayCallback displayCallback,
const char* effectName)
{
s_effectDebugList.push_back(SEffectDebugData(inputEventCallback, displayCallback, effectName));
}
#endif
//--------------------------------------------------------------------------------------------------