Files
GTASource/game/renderer/PostProcessFXHelper.h
T
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1120 lines
30 KiB
C++

//
// Filename: PostProcessFXHelper.h
// Description: This file contains miscellaneous, PostFX related classes
#ifndef __POSTPROCESSFX_HELPER_H__
#define __POSTPROCESSFX_HELPER_H__
#include "atl/hashstring.h"
#include "atl/array.h"
#include "atl/functor.h"
#include "bank/bank.h"
#include "bank/combo.h"
#include "data/callback.h"
#include "grcore/texture.h"
#include "grcore/viewport.h"
#include "fwtl/LinkList.h"
#include "parser/macros.h"
#include "scene/RegdRefTypes.h"
#include "timecycle/tckeyframe.h"
#include "renderer/color.h"
#include "grcore/effect.h"
#include "grcore/stateblock.h"
#include "vector/color32.h"
#include "control/replay/ReplaySettings.h"
#include "timecycle/TimeCycle.h"
namespace rage
{
class grcTexture;
class grcRenderTarget;
};
class CTextLayout;
//////////////////////////////////////////////////////////////////////////
// Helper class to simplify handling effects setup as timecycle modifiers that animate over time
enum eAnimatedPostFXMode
{
POSTFX_IN_HOLD_OUT = 0,
POSTFX_EASE_IN_HOLD_EASE_OUT,
POSTFX_EASE_IN,
POSTFX_EASE_OUT,
};
enum eAnimatedPostFXLoopMode
{
POSTFX_LOOP_ALL = 0,
POSTFX_LOOP_HOLD_ONLY,
POSTFX_LOOP_NONE,
};
class AnimatedPostFX
{
public:
enum eState
{
POSTFX_IDLE = 0,
POSTFX_DELAY_IN,
POSTFX_GOING_IN,
POSTFX_ON_HOLD,
POSTFX_GOING_OUT,
};
AnimatedPostFX() { Init(); }
void Set(atHashString modifierName, eAnimatedPostFXMode animMode, u32 inDelayDuration, u32 inDuration, u32 holdDuration, u32 outDuration);
void Start();
void Start(u32 duration);
void Update();
void Init();
void Reset();
void Disable() { m_Disabled = true; }
void Enable() { m_Disabled = false; }
void SetLoopEnabled(bool bEnabled) { m_Loop = bEnabled; }
void SetCanBePaused(bool bCanBePaused) { m_CanBePaused = bCanBePaused; }
bool IsDisabled() const { return m_Disabled; }
bool IsIdle() const { return (m_StartTime == 0U); }
float GetFadeLevel() const { return m_FadeLevel; }
atHashString GetModifierName() const { return m_ModifierName; }
void ApplyModifiers(tcKeyframeUncompressed& keyframe, float globalFadeLevel) const;
eState GetState() const { return m_State; }
u32 GetDuration() const { return (m_StartDelayDuration+m_InDuration+m_HoldDuration+m_OutDuration); }
u32 GetCurrentTime() const { return m_CurrentTime; }
private:
bool NeedsEaseIn() const { return m_AnimMode > POSTFX_IN_HOLD_OUT && m_AnimMode < POSTFX_EASE_OUT; }
bool NeedsEaseOut() const { return (m_AnimMode == POSTFX_EASE_IN_HOLD_EASE_OUT || m_AnimMode == POSTFX_EASE_OUT); }
void Update_InHoldOut();
void Update_EaseInOrOut();
atHashString m_ModifierName;
u32 m_StartDelayDuration;
u32 m_InDuration;
u32 m_HoldDuration;
u32 m_OutDuration;
u32 m_CurrentTime;
float m_FadeLevel;
float m_Scale;
u32 m_StartTime;
eAnimatedPostFXMode m_AnimMode;
eState m_State;
eAnimatedPostFXLoopMode m_LoopMode;
bool m_Disabled;
bool m_Loop;
bool m_CanBePaused;
PAR_SIMPLE_PARSABLE;
friend class AnimatedPostFXStack;
};
class LayerBlendModifier
{
public:
LayerBlendModifier() { Init(); }
void Init();
void Reset();
void Disable() { m_Disabled = true; }
void Enable() { m_Disabled = false; }
bool IsEnabled() const { return m_Disabled == false; }
void ApplyModifiers(tcKeyframeUncompressed& keyframe, float globalFadeLevel) const;
void Set(const AnimatedPostFX* pLayerA, const AnimatedPostFX* pLayerB);
void Update();
private:
const AnimatedPostFX* m_pLayerA;
const AnimatedPostFX* m_pLayerB;
float m_FrequencyNoise;
float m_AmplitudeNoise;
float m_Frequency;
float m_Bias;
float m_Level;
atHashString m_LayerA;
atHashString m_LayerB;
bool m_Disabled;
PAR_SIMPLE_PARSABLE;
friend class AnimatedPostFXStack;
};
//////////////////////////////////////////////////////////////////////////
// Animpostfx events
enum AnimPostFXEventType
{
ANIMPOSTFX_EVENT_INVALID = -1,
ANIMPOSTFX_EVENT_ON_START = 0,
ANIMPOSTFX_EVENT_ON_STOP,
ANIMPOSTFX_EVENT_ON_FRAME,
ANIMPOSTFX_EVENT_ON_START_ON_STOP,
ANIMPOSTFX_EVENT_ON_START_ON_STOP_ON_FRAME,
ANIMPOSTFX_EVENT_ON_START_ON_FRAME,
ANIMPOSTFX_EVENT_ON_STOP_ON_FRAME,
};
//////////////////////////////////////////////////////////////////////////
// Helper class to simplify handling effects setup as timecycle modifiers that animate over time
class AnimatedPostFXStack
{
public:
enum { kNumEffectLayers = 6 };
AnimatedPostFXStack() { m_UserFadeOverrideEnabled = false; m_UserFadeOverrideLevel = 1.0f; m_Layers.Reset(); m_GroupId = -1; m_EventTimeMS = 0U; m_EventType = ANIMPOSTFX_EVENT_INVALID; m_EventUserTag = 0U; }
void Add(atHashString modifierName, eAnimatedPostFXMode animMode, u32 inDelayDuration, u32 inDuration, u32 holdDuration, u32 outDuration);
void Set(u32 layer, atHashString modifierName, eAnimatedPostFXMode animMode, u32 inDelayDuration, u32 inDuration, u32 holdDuration, u32 outDuration);
void SetLoopEnabled(bool bEnable);
void SetUserFadeOverride(bool bEnable);
void SetUserFadeLevel(float level);
float GetUserFadeLevel() const { return m_UserFadeOverrideLevel; }
void Start();
void Start(u32 duration);
void Stop() { m_UserFadeOverrideEnabled = false; m_UserFadeOverrideLevel = 1.0f; Reset(); };
void Update();
void Reset();
s32 GetGroupId() const { return m_GroupId; }
u32 GetDuration() const;
u32 GetEventTimeMS() const { return m_EventTimeMS; }
AnimPostFXEventType GetEventType() const { return m_EventType; }
u32 GetEventUserTag() const { return m_EventUserTag; }
bool IsIdle() const;
float GetCurrentTime() const;
u32 GetCurrentTimeMS() const;
const AnimatedPostFX& GetLayer(u32 idx) const { return m_Layers[idx]; }
u32 GetCount() const { return (u32)m_Layers.GetCount(); }
void ApplyModifiers(tcKeyframeUncompressed& keyframe) const;
void PostLoadCallback();
#if __BANK
void AddWidgets(rage::bkBank& bank);
#endif
private:
LayerBlendModifier m_LayerBlend;
atFixedArray<AnimatedPostFX, kNumEffectLayers> m_Layers;
bool m_UserFadeOverrideEnabled;
float m_UserFadeOverrideLevel;
AnimPostFXEventType m_EventType;
u32 m_EventUserTag;
u32 m_EventTimeMS;
s32 m_GroupId;
friend class RegisteredAnimPostFXStack;
PAR_SIMPLE_PARSABLE;
};
//////////////////////////////////////////////////////////////////////////
//
class RegisteredAnimPostFXStack
{
public:
RegisteredAnimPostFXStack() { Init(); }
void Init();
bool operator >(const RegisteredAnimPostFXStack& stackB) const { return m_Priority > stackB.m_Priority; }
bool operator >=(const RegisteredAnimPostFXStack& stackB) const { return m_Priority >= stackB.m_Priority; }
void Start();
void Start(u32 duration);
void Stop() { m_StopRequested = true; };
void CancelStartRequest();
void Reset();
void Update();
void FrameDelayUpdate();
float GetCurrentTime() const;
void SetLoopEnabled(bool bEnable) { m_FXStack.SetLoopEnabled(bEnable); };
void SetUserFadeOverride(bool bEnable) { m_FXStack.SetUserFadeOverride(bEnable); };
void SetUserFadeLevel(float level) { m_FXStack.SetUserFadeLevel(level); };
void SetFrameDelay(unsigned int frameDelay) { m_FrameDelay = frameDelay; }
u32 GetDuration() const { return m_FXStack.GetDuration(); }
u32 GetFrameDelay() const { return m_FrameDelay; }
s32 GetGroupId() const { return m_FXStack.GetGroupId(); }
u32 GetEventTimeMS() const { return m_FXStack.GetEventTimeMS(); }
u32 GetCurrentTimeMS() const { return m_FXStack.GetCurrentTimeMS(); }
AnimPostFXEventType GetEventType() const { return m_FXStack.GetEventType(); }
u32 GetEventUserTag() const { return m_FXStack.GetEventUserTag(); }
bool DoesEventTypeMatch(AnimPostFXEventType eventType) const;
bool HasFrameEventTriggered() const { return m_FrameEventTriggered; }
void MarkFrameEventTriggered(bool bTriggered) { m_FrameEventTriggered = bTriggered; }
#if __BANK
void ClearForEdit();
bool Validate();
#endif
atHashString GetName() const { return m_Name; }
u32 GetCount() const { return (u32)m_FXStack.GetCount(); }
bool IsIdle() const { return m_FXStack.IsIdle(); }
bool IsStartPending() const { return m_StartRequested; }
bool IsStopPending() const { return m_StopRequested; }
float GetUserFadeLevel() const { return m_FXStack.GetUserFadeLevel(); }
const AnimatedPostFX& GetLayer(u32 idx) const { return m_FXStack.GetLayer(idx); }
AnimatedPostFXStack* GetStack() { return &m_FXStack; }
const AnimatedPostFXStack* GetStack() const { return &m_FXStack; }
void ApplyModifiers(tcKeyframeUncompressed& keyframe);
private:
atHashString m_Name;
AnimatedPostFXStack m_FXStack;
u32 m_OverriddenDuration;
u32 m_FrameDelay;
u8 m_Priority;
bool m_StartRequested;
bool m_StopRequested;
bool m_FrameEventTriggered;
PAR_SIMPLE_PARSABLE;
friend class AnimPostFXManager;
};
#if GTA_REPLAY
//////////////////////////////////////////////////////////////////////////
//
class AnimPostFXManager;
class AnimPostFXManagerReplayEffectLookup
{
public:
static void Init(AnimPostFXManager *pFxManager);
static void Shutdown();
static bool AreAllGameCamStacksIdle(bool forThumbnail, int* activeIndex = nullptr);
static bool IsStackDisabledForGameCam(const RegisteredAnimPostFXStack* pStack);
static bool IsStackDisabledForFreeCam(const RegisteredAnimPostFXStack* pStack);
#if !__FINAL
static const char* GetFilterName(int index);
#endif // !__FINAL
private:
// Clear out all pointers
static void Reset();
// Name + Cached pointer to stack for each table entry
struct AnimPostFXReplayEffectTableEntry
{
atHashString m_Name;
RegisteredAnimPostFXStack *m_pStack;
bool m_AllowForThumbnail;
};
// Storage for the table
static AnimPostFXReplayEffectTableEntry m_PostEffectReplayGameCamRemovalLookupTable[];
static AnimPostFXReplayEffectTableEntry m_PostEffectReplayFreeCamRemovalLookupTable[];
};
#endif //GTA_REPLAY
struct AnimPostFXEvent
{
AnimPostFXEvent() { Reset(); }
~AnimPostFXEvent() { Reset(); }
void Reset()
{
fxName = 0U;
groupId = -1;
eventType = ANIMPOSTFX_EVENT_INVALID;
currentTime = 0U;
userTag = 0U;
}
bool IsValid() const { return (fxName != 0U && groupId != -1); }
atHashString fxName; // name of the effect stack that triggered the event
s32 groupId; // group id (set up in the stack itself)
AnimPostFXEventType eventType; // event type
u32 currentTime; // current running time of the effect
u32 userTag; // user tag for random flags
};
typedef Functor1<AnimPostFXEvent*> AnimPostFXEventCB;
struct AnimPostFXListener
{
AnimPostFXListener() { Reset(); }
~AnimPostFXListener() { Reset(); }
bool IsValid () const { return (groupId != -1 && eventCallback != 0); }
bool Matches(AnimPostFXEventCB pCBFunc, s32 _groupId) const { return (eventCallback == pCBFunc && _groupId == groupId); }
void Reset()
{
groupId = -1;
eventCallback = NULL;
}
s32 groupId;
AnimPostFXEventCB eventCallback;
};
//////////////////////////////////////////////////////////////////////////
// Helper struct to store triggered events for polling
struct AnimPostFXPolledEvent
{
AnimPostFXPolledEvent() { Reset(); }
~AnimPostFXPolledEvent() { Reset(); }
bool Matches(atHashString fxName) { return (fxName.IsNotNull() && fxName == srcEvent.fxName); }
void Reset()
{
srcEvent.Reset();
timeStamp = 0U;
bConsumed = false;
}
AnimPostFXEvent srcEvent;
u32 timeStamp;
bool bConsumed;
};
//////////////////////////////////////////////////////////////////////////
// Helper class to turn the event-based AnimPostFXEventManager system into
// a polling-based one that's script-friendly
class AnimPostFXEventPollingManager
{
public:
AnimPostFXEventPollingManager() {};
~AnimPostFXEventPollingManager() {};
void Init();
void Shutdown();
bool AddListener(const atHashString fxName);
void RemoveListener(const atHashString fxName);
bool HasEventTriggered(atHashString fxName, AnimPostFXEventType eventType, bool bPeekOnly, bool& bIsRegistered);
void OnEventTriggered(AnimPostFXEvent* pEvent);
void Update();
#if __BANK
void AddWidgets(rage::bkBank& bank);
void OnRegisterEvent();
void OnUnregisterEvent();
#endif
private:
bool AddListener(s32 groupId);
void RemoveListener(s32 groupId);
fwLinkList<AnimPostFXPolledEvent> m_events; // list of events received so they can be polled
typedef fwLink<AnimPostFXPolledEvent> PolledEventNode;
atMap<s32, s32> m_managedEventGroups; // table with registered event groups, so that script doesn't have to know about groups
// and can instead focus on individual effects when registering a listener.
static const s32 MAX_EVENTS;
static u32 EVENT_POLLING_TIMEOUT;
#if __BANK
static char ms_registeredFxName[128];
#endif
};
//////////////////////////////////////////////////////////////////////////
//
class AnimPostFXEventManager
{
public:
AnimPostFXEventManager() {};
~AnimPostFXEventManager() {};
void Init();
void Shutdown();
bool RegisterListener(AnimPostFXEventCB pCBFunc, s32 groupId);
void RemoveListener(AnimPostFXEventCB pCBFunc, s32 groupId);
void OnEventTriggered(const RegisteredAnimPostFXStack* pStack, AnimPostFXEventType eventType);
static s32 GetMaxListeners() { return MAX_LISTENERS; }
private:
bool Exists(AnimPostFXEventCB pCBFunc, s32 groupId) const;
fwLinkList<AnimPostFXListener> m_listenerList;
typedef fwLink<AnimPostFXListener> ListenerNode;
static const s32 MAX_LISTENERS;
};
//////////////////////////////////////////////////////////////////////////
//
class AnimPostFXManager
{
public:
enum eAnimPostFXUser
{
kDefault = 0,
kPedKill,
kCameraFlash,
kSelectionWheel,
kLongPlayerSwitch,
kShortPlayerSwitch,
kKERSBoost,
kFirstPersonProp,
kScript,
kSpecialAbility,
kCount
};
AnimPostFXManager() {}
~AnimPostFXManager() {}
void Start(atHashString effectName, u32 duration, bool bLoop, bool bUserControlsFade, bool bStartOnce, int frameDelay, eAnimPostFXUser user);
void CancelStartRequest(atHashString effectName, eAnimPostFXUser user);
void StartCrossfade(atHashString effectNameIn, atHashString effectNameOut, u32 duration, eAnimPostFXUser user);
void StopCrossfade(eAnimPostFXUser user);
void SetUserFadeLevel(atHashString effectName, float level);
void StopAll(eAnimPostFXUser user);
void Stop(atHashString effectName, eAnimPostFXUser user);
bool IsRunning(atHashString effectName) const;
bool IsStartPending(atHashString effectName) const;
float GetCurrentTime(atHashString effectName) const;
bool IsIdle() const { return (m_ActiveStacks.GetNumUsed() == 0) && (m_FrameDelayStacks.GetNumUsed() == 0); }
void Init();
void Shutdown();
void Update();
void ApplyModifiers(tcKeyframeUncompressed& keyframe REPLAY_ONLY(, eTimeCyclePhase currentPhase));
void Reset();
void Add(RegisteredAnimPostFXStack& stack);
void Remove(atHashString name);
const RegisteredAnimPostFXStack* Get(atHashString name) const;
RegisteredAnimPostFXStack* Get(atHashString name);
// Event-based system for tagged FX stacks
bool RegisterListener(AnimPostFXEventCB pCBFunc, s32 groupId) { return m_eventManager.RegisterListener(pCBFunc, groupId); };
void RemoveListener(AnimPostFXEventCB pCBFunc, s32 groupId) { m_eventManager.RemoveListener(pCBFunc, groupId); };
void OnEventTriggered(const RegisteredAnimPostFXStack* pStack, AnimPostFXEventType eventType) { m_eventManager.OnEventTriggered(pStack, eventType); }
// Polling-based system for tagged FX stacks (script)
bool AddListener(const atHashString fxName) { return m_polledEventManager.AddListener(fxName); };
void RemoveListener(const atHashString fxName) { m_polledEventManager.RemoveListener(fxName); };
bool HasEventTriggered(atHashString fxName, AnimPostFXEventType eventType, bool bPeekOnly, bool& bIsRegistered) { return m_polledEventManager.HasEventTriggered(fxName, eventType, bPeekOnly, bIsRegistered); }
static void ClassInit();
static void ClassShutdown();
static AnimPostFXManager& GetInstance() { return *smp_Instance; }
#if __BANK
void AddWidgets(rage::bkBank& bank );
bool DebugOutput() const { return m_bDebugOutput; };
bool DebugDisplay() const { return m_bDebugDisplay; };
bool AllowPausing() const { return m_bDebugAllowPausing; }
#endif
#if GTA_REPLAY
bool AreReplayRecordingRestrictedStacksAtIdle(bool forThumbnail, int* activeIndex)
{
return AnimPostFXManagerReplayEffectLookup::AreAllGameCamStacksIdle(forThumbnail, activeIndex);
}
#endif //GTA_REPLAY
private:
bool AddToActiveList(RegisteredAnimPostFXStack* pStack);
bool AddToFrameDelayList(RegisteredAnimPostFXStack* pStack);
bool LoadMetaData();
#if __BANK && !__FINAL
bool SaveMetaData();
#endif
atArray<RegisteredAnimPostFXStack> m_RegisteredStacks;
fwLinkList<RegisteredAnimPostFXStack*> m_ActiveStacks;
fwLinkList<RegisteredAnimPostFXStack*> m_FrameDelayStacks;
typedef fwLink<RegisteredAnimPostFXStack*> ActiveStackNode;
struct CrossfadeHelper
{
CrossfadeHelper() { Reset(); }
void Reset()
{
m_InStackName.Null();
m_OutStackName.Null();
m_pInStack = NULL;
m_pOutStack = NULL;
m_StartRequested = false;
m_StopRequested = false;
m_Duration = 0U;
m_StartTime = 0U;
m_FadeLevel = 0.0f;
m_Active = false;
m_State = AnimatedPostFX::POSTFX_IDLE;
}
void Start(atHashString effectNameIn, atHashString effectNameOut, u32 duration);
void Stop();
bool IsActive() const { return m_Active; }
void Update();
void UpdateTiming();
atHashString m_InStackName;
atHashString m_OutStackName;
u32 m_Duration;
u32 m_StartTime;
float m_FadeLevel;
RegisteredAnimPostFXStack* m_pInStack;
RegisteredAnimPostFXStack* m_pOutStack;
AnimatedPostFX::eState m_State;
bool m_StartRequested;
bool m_StopRequested;
bool m_Active;
};
CrossfadeHelper m_Crossfade;
bool m_bStopAllRequested;
#if __BANK
bool m_bBlockRequestFromUser;
eAnimPostFXUser m_blockedUserType;
#endif // __BANK
AnimPostFXEventManager m_eventManager;
AnimPostFXEventPollingManager m_polledEventManager;
static AnimPostFXManager* smp_Instance;
#if __BANK
class EditTool
{
public:
EditTool() {}
void Init();
void Shutdown();
void AddWidgets(rage::bkBank& bank );
void OnSaveCurrentFXStack();
void OnDeleteCurrentFXStack();
void OnSaveData();
void OnLoadData();
void OnFXStackNameSelected();
void OnStopTestStackFX0() { OnStopTestStackFX(0); }
void OnStartTestStackFX0() { OnStartTestStackFX(0); }
void OnStopTestStackFX1() { OnStopTestStackFX(1); }
void OnStartTestStackFX1() { OnStartTestStackFX(1); }
void OnStopTestStackFX2() { OnStopTestStackFX(2); }
void OnStartTestStackFX2() { OnStartTestStackFX(2); }
void OnStopTestStackFX3() { OnStopTestStackFX(3); }
void OnStartTestStackFX3() { OnStartTestStackFX(3); }
void OnStopTestStackFX4() { OnStopTestStackFX(4); }
void OnStartTestStackFX4() { OnStartTestStackFX(4); }
void OnStopTestStackFX5() { OnStopTestStackFX(5); }
void OnStartTestStackFX5() { OnStartTestStackFX(5); }
void OnStopTestStackFXAll() { OnStopTestStackFX(0);OnStopTestStackFX(1);OnStopTestStackFX(2);OnStopTestStackFX(3);OnStopTestStackFX(4);OnStopTestStackFX(5); }
void OnStartTestStackFXAll() { OnStartTestStackFX(0);OnStartTestStackFX(1);OnStartTestStackFX(2);OnStartTestStackFX(3);OnStartTestStackFX(4);OnStartTestStackFX(5); }
void OnStartCrossfade();
void OnStopCrossfade();
void OnStopTestStackFX(int fxTestIndex);
void OnStartTestStackFX(int fxTestIndex);
char* GetSavePath() { return &ms_savePath[0]; }
private:
bool ValidateCurrentFXStack() const;
void UpdateRegStackNamesList(const atArray<RegisteredAnimPostFXStack>& stacks);
atArray<const char*> m_RegStackNames;
int m_RegStackNamesComboIdx;
bkCombo* m_pRegStackNamesCombo;
RegisteredAnimPostFXStack m_editableStack;
u32 m_testStackDuration[6];
bool m_bTestLoopEnabled[6];
static atHashString ms_newStackName;
static char ms_testStackName[6][32];
static char ms_testCrossfadeName[2][32];
u32 m_testCrossfadeDuration;
static char ms_savePath[256];
};
EditTool m_EditTool;
bool m_bDebugOutput;
bool m_bDebugDisplay;
bool m_bDebugAllowPausing;
int m_userTypeComboIdx;
bkCombo* m_pUserTypeCombo;
static const char* ms_debugUserTypeStr[];
void OnUserTypeToBlockSelected();
#endif // __BANK
PAR_SIMPLE_PARSABLE;
};
#define ANIMPOSTFXMGR AnimPostFXManager::GetInstance()
//////////////////////////////////////////////////////////////////////////
//
class PauseMenuPostFXManager
{
public:
enum eState
{
PMPOSTFX_IDLE = 0,
PMPOSTFX_FADING_IN,
PMPOSTFX_FADING_OUT,
};
PauseMenuPostFXManager() {}
~PauseMenuPostFXManager() {}
void Init();
void Shutdown();
void StartFadeIn();
void StartFadeOut();
void Update();
void ApplyModifiers(tcKeyframeUncompressed& keyframe);
void Reset();
bool IsIdle() const { return (m_State == PMPOSTFX_IDLE); }
// Returns true if the pause menu effects are fading, *having into account* the bias values m_FadeInCheckTreshold and m_FadeOutCheckTreshold.
// This allows markers, etc., to resume rendering slightly earlier, before the effects are fully faded out.
bool IsFading() const;
eState GetState() const { return m_State; }
static void ClassInit();
static void ClassShutdown();
static PauseMenuPostFXManager& GetInstance() { return *smp_Instance; }
#if __BANK
void AddWidgets(rage::bkBank& bank );
#endif
#if GTA_REPLAY
bool AreAllPostFXAtIdle();
#endif //GTA_REPLAY
private:
bool LoadMetaData();
#if __BANK && !__FINAL
bool SaveMetaData();
#endif
void UpdateCurrentEffect();
enum eEffectType
{
PAUSEFX_FRANKLIN = 0,
PAUSEFX_MICHAEL,
PAUSEFX_TREVOR,
PAUSEFX_NEUTRAL,
//PAUSEFX_CNC_COP,
//PAUSEFX_CNC_CROOK,
PAUSEFX_COUNT
};
RegisteredAnimPostFXStack* m_pFadeInEffects[PAUSEFX_COUNT];
RegisteredAnimPostFXStack* m_pFadeOutEffects[PAUSEFX_COUNT];
RegisteredAnimPostFXStack m_FallbackEffect;
AnimatedPostFXStack* m_pCurFadeInFX;
AnimatedPostFXStack* m_pCurFadeOutFX;
eState m_State;
float m_FadeInCheckTreshold;
float m_FadeOutCheckTreshold;
bool m_FadeInRequested;
bool m_FadeOutRequested;
static PauseMenuPostFXManager* smp_Instance;
#if __BANK
class EditTool
{
public:
EditTool() {}
void Init();
void Shutdown();
void AddWidgets(rage::bkBank& bank );
void OnTestFadeInEffects();
void OnTestFadeOutEffects();
void OnSaveData();
void OnLoadData();
};
EditTool m_EditTool;
#endif // __BANK
PAR_SIMPLE_PARSABLE;
};
#define PAUSEMENUPOSTFXMGR PauseMenuPostFXManager::GetInstance()
//////////////////////////////////////////////////////////////////////////
//
class OverlayTextRenderer
{
public: // methods
static void InitializeTextBlendState();
static void RenderText( char const * const text, Vector2 const& position, Vector2 const& scale,
CRGBA const& color, s32 const style, Vector2 const& wrap, Vector2 const& c_maskTL = Vector2(0,0), Vector2 const& c_maskBR = Vector2(0,0));
static void RenderText( char const * const text, Vector2 const& position, CTextLayout& textLayout );
protected:
inline static grcBlendStateHandle GetTextBlendState() { return sm_textBlendState; }
private: // declarations and variables
static grcBlendStateHandle sm_textBlendState;
};
//////////////////////////////////////////////////////////////////////////
//
class PhonePhotoEditor : public OverlayTextRenderer
{
public:
static const int PHOTO_TEXT_MAX_LENGTH = 32;
typedef Functor3<u8*, u32, bool> OnPhotoEditorSaveCallback;
PhonePhotoEditor() { Reset(); }
~PhonePhotoEditor() {}
// API for text editing //////////////////////////////////////////////////
// Use to check whether editing is available.
bool IsEditingAvailable() const;
// Will fail in either of these cases:
// 1. Nested call within a Start/Finish bracket
// 2. Rendering is not frozen
// 3. there's no memory for JPEG buffer
// 4. the TXD is not available
bool StartEditing(s32 txdId);
inline bool IsEditing() const { return m_galleryEdit.m_bEditing; }
inline bool IsWaitingUserInput() const { return m_galleryEdit.m_bWaitingForUser; }
inline bool IsRequestingSave() const { return m_galleryEdit.m_requestFlags.bSave; }
// Only call to finish an edit previously initiated with StartEditing. Not synchronous: release of resources is deferred.
bool FinishEditing();
// Not synchronous: user will get a callback with the JPEG buffer, its size and whether the save operation succeeded.
bool RequestSave(OnPhotoEditorSaveCallback pCallback); //
//////////////////////////////////////////////////////////////////////////
void UpdateSafe();
void Init();
void Shutdown();
void Reset();
void Update();
void Render();
void Enable() { m_bActive = true; }
void Disable();
bool IsActive() const { return m_bActive; }
inline void SetDestTarget(grcRenderTarget* pRT) { m_pDestRt = pRT; }
void SetBorderTexture(const char* txdName, bool bDisableCurrentFrame);
void SetText(const char* pTopText, const char* pBottomText, const Vector4& textPos, float topTextSize, float bottomTextSize, s32 topTextStyle, s32 bottomTextStyle, Color32 topTextCol, Color32 bottomTextCol);
inline void SetText(const char* pTopText, const char* pBottomText )
{
SetText( pTopText, pBottomText, m_textPos, m_topTextSize, m_bottomTextSize, m_topTextStyle, m_bottomTextStyle, m_topTextCol, m_bottomTextCol );
}
inline const char * GetTopText() const { return m_topText; }
inline s32 GetTopTextStyle() const { return m_topTextStyle; }
inline float GetTopTextSize() const { return m_topTextSize; }
inline Color32 const & GetTopColour() const { return m_topTextCol; }
inline const char * GetBottomText() const { return m_bottomText; }
inline s32 GetBottomTextStyle() const { return m_bottomTextStyle; }
inline float GetBottomTextSize() const { return m_bottomTextSize; }
inline Color32 const & GetBottomColour() const { return m_bottomTextCol; }
inline Vector4 const & GetTextPosition() const { return m_textPos; }
void ResetTextParameters();
inline grcTexture * GetTargetTexture() { return m_galleryEdit.m_pRt; }
#if __BANK
void AddWidgets(rage::bkBank& bank );
void RenderDebug();
#endif
static void ClassInit();
static void ClassShutdown();
#if RSG_PC
static void DeviceLost();
static void DeviceReset();
#endif // RSG_PC
static PhonePhotoEditor& GetInstance() { return *smp_Instance; }
void RenderBorder(bool bAdjustFor43 = false);
void RenderGalleryEdit();
private:
void InitGalleryEdit(bool bReInit);
void ShutdownGalleryEdit();
void UpdateGalleryEdit();
void ReleaseCurrentBorderTextures();
void RenderText( int const destWidth, int const destHeight );
void RenderTextOverlay();
void ResetGalleryEditState();
bool AllocateGalleryEditJPEGBuffer();
void ReleaseGalleryEditJPEGBuffer();
bool ProcessGalleryEditSourceImage(s32 txdId);
void ReleaseGalleryEditSourceImage();
bool SaveToJPEGBuffer();
grcRenderTarget* m_pDestRt;
grcTextureHandle m_pBorderTexture[5];
char m_topText[PHOTO_TEXT_MAX_LENGTH];
char m_bottomText[PHOTO_TEXT_MAX_LENGTH];
atFinalHashString m_borderTxdName;
s32 m_borderTextureTxd;
Color32 m_topTextCol;
Color32 m_bottomTextCol;
Vector4 m_textPos;
s32 m_topTextStyle;
s32 m_bottomTextStyle;
float m_topTextSize;
float m_bottomTextSize;
bool m_bBorderTextureRefAdded;
bool m_bActive;
bool m_bUpdateBorderTexture;
bool m_bReleaseCurrentBorderTexture;
bool m_bUseText;
struct GalleryEditData
{
GalleryEditData() { Reset(); }
~GalleryEditData() {}
void Reset();
OnPhotoEditorSaveCallback m_pOnSaveFnc;
grcViewport m_viewport;
grcRenderTarget* m_pRt;
grcTextureHandle m_pSrcImg;
u8* m_pJPEGBuffer;
u32 m_JPEGBufferSize;
u32 m_JPEGActualSize;
s32 m_SrcImgTxd;
s32 m_PendingSrcImgTxd;
bool m_bSrcImgRefAdded;
union
{
struct
{
u8 bSave : 1;
u8 bRelease: 1;
} m_requestFlags;
bool m_bRequestsPending;
};
bool m_bEditing : 1;
bool m_bWaitingForUser : 1;
bool m_bNeedToIssueCallback : 1;
bool m_bWasSaveOk : 1;
};
GalleryEditData m_galleryEdit;
static PhonePhotoEditor* smp_Instance;
#if __BANK
void AddWidgetsForGalleryEdit(rage::bkBank& bank );
void OnToggleActive();
void OnTextChange();
static char sm_borderTxdName[PHOTO_TEXT_MAX_LENGTH*2];
static char sm_topText[PHOTO_TEXT_MAX_LENGTH];
static char sm_bottomText[PHOTO_TEXT_MAX_LENGTH];
static Color32 sm_topTextCol;
static Color32 sm_bottomTextCol;
static Vector4 sm_textPos;
static float sm_topTextSize;
static float sm_bottomTextSize;
static bool sm_bToggleActive;
static s32 sm_topTextStyle;
static s32 sm_bottomTextStyle;
static const char* sm_fontTypesStr[];
void OnToggleGalleryEdit();
void OnGalleryEditSave();
void OnGalleryEditTextChange();
void OnGalleryEditTextureNameChange();
static Vector2 sm_debugRenderPos;
static Vector2 sm_debugRenderSize;
static s32 sm_galleryEditTxdId;
static bool sm_bToggleGalleryEdit;
static bool sm_bDebugRender;
static bool sm_bTestSave;
static char sm_photoToEditName[64];
#endif
};
#define PHONEPHOTOEDITOR PhonePhotoEditor::GetInstance()
//////////////////////////////////////////////////////////////////////////
//
struct DofTODOverrideEntry
{
DofTODOverrideEntry() : hourFrom(0.0f), hourTo(0.0f), overrideValue(0.0f) {};
void Reset() { hourFrom = 0.0f; hourTo = 0.0f; overrideValue = 0.0f; };
float hourFrom;
float hourTo;
float overrideValue;
};
//////////////////////////////////////////////////////////////////////////
//
class DofTODOverrideHelper
{
public:
DofTODOverrideHelper() { Reset(); };
bool IsActive() const { return m_bActive; }
bool Begin();
bool End();
void Reset();
void AddSample(float hourFrom, float hourTo, float overrideValue);
void SetDefaultOutOfRangeOverride(float defValue) { m_outOfRangeOverrideValue = defValue; }
void Update();
float GetCurrentValue();
#if __BANK
void AddWidgets(rage::bkBank& bank);
void OnToggle();
#endif
private:
static const int MAX_TIME_SAMPLES = 4;
atFixedArray<DofTODOverrideEntry, MAX_TIME_SAMPLES> m_samples;
float m_outOfRangeOverrideValue;
float m_currentValue;
bool m_bActive;
#if __BANK
static Vector3 sm_debugSamples[MAX_TIME_SAMPLES];
static float sm_debugOutOfRangeOverride;
static bool sm_bToggle;
#endif
};
#endif // __POSTPROCESSFX_HELPER_H__