// BSE.h // #pragma once #include "../../engine/models/Model_local.h" #include "../../engine/renderer/tr_local.h" // BSE - Basic System for Effects // Notes: // All times are floats of seconds // All tints are floats of 0.0 to 1.0 // All effects are presumed to be in the "base/effects" folder and have the extension of BSE_EFFECT_EXTENSION // All angles are in fractions of a circle - 1 means 1 full circle // All effect files are case insensitive // Will not have different shaders to be randomly chosen - need to keep the tesses to a minimum (except possibly for decals) // Defined classes class rvSegment; class rvSegmentTemplate; class rvDeclEffect; class rvBSE; class rvBSEManagerLocal; // Referenced classes class rvRenderModelBSE; class idRenderModel; class rvParticle; class idPlayerView; class idRenderWorld; const float WORLD_SIZE = (128.0f * 1024.0f); const float BSE_LARGEST = (512.0f); const float BSE_TESS_COST = (20.0f); // The expense of a new tess const float BSE_PHYSICS_COST = (80.0f); // The expense of 1 particle having physics const float BSE_PARTICLE_TEXCOORDSCALE = (0.01f); const unsigned int MEMORY_BLOCK_SIZE = (0x100000); const unsigned int BSE_ELEC_MAX_BOLTS = (200); typedef enum eBSEPerfCounter { PERF_NUM_BSE, PERF_NUM_TRACES, PERF_NUM_PARTICLES, PERF_NUM_TEXELS, PERF_NUM_SEGMENTS, NUM_PERF_COUNTERS }; typedef enum eBSESegment { SEG_NONE = 0, SEG_EFFECT, // Spawns another effect inheriting data from owner SEG_EMITTER, // Spawns particles at a rate SEG_SPAWNER, // Spawns particles instantly SEG_TRAIL, // Leaves a trail of particles SEG_SOUND, // Plays a sound SEG_DECAL, // Leaves an idDecal SEG_LIGHT, // Displays a 3D light SEG_DELAY, // A control segment for looping SEG_SHAKE, // Triggers a screen shake SEG_TUNNEL, // Triggers the id tunnel vision effect SEG_DOUBLEVISION, // Triggers the id double-vision effect SEG_COUNT }; typedef enum eBSETrail { TRAIL_NONE = 0, TRAIL_BURN, TRAIL_MOTION, TRAIL_PARTICLE, TRAIL_COUNT }; enum { SFLAG_EXPIRED = BITT< 0 >::VALUE, SFLAG_SOUNDPLAYING = BITT< 1 >::VALUE, SFLAG_HASMOTIONTRAIL = BITT< 2 >::VALUE, }; // ============================================== // Effect class // ============================================== class rvSegment { public: friend class rvBSE; rvSegment(void) { mFlags = 0; mParticles = NULL; mUsedHead = NULL; mFreeHead = NULL; mParticleCount = 0; mLoopParticleCount = 0; } ~rvSegment(void); void SetFlag(bool on, int flag) { on ? mFlags |= flag : mFlags &= ~flag; } bool GetExpired(void) const { return((bool)(mFlags & SFLAG_EXPIRED)); } bool GetSoundPlaying(void) const { return(!!(mFlags & SFLAG_SOUNDPLAYING)); } bool GetHasMotionTrail(void) const { return(!!(mFlags & SFLAG_HASMOTIONTRAIL)); } void SetExpired(bool expired) { SetFlag(expired, SFLAG_EXPIRED); } void SetSoundPlaying(bool soundPlaying) { SetFlag(soundPlaying, SFLAG_SOUNDPLAYING); } void SetHasMotionTrail(bool hmt) { SetFlag(hmt, SFLAG_HASMOTIONTRAIL); } int GetMotionTrailCount(void) { return(mActiveCount); } rvSegmentTemplate* GetSegmentTemplate(void); const rvDeclEffect* GetEffectDecl(void) { return(mEffectDecl); } bool GetLocked(void); bool Active(void); void PlayEffect(rvBSE* effect, rvSegmentTemplate* st, float depthOffset); void InitTime(rvBSE* effect, rvSegmentTemplate* st, float time); void ResetTime(rvBSE* effect, float time); void Init(rvBSE* effect, const rvDeclEffect* decl, int segmentTemplateHandle, float time); void InitParticles(rvBSE* effect); void RefreshParticles(rvBSE* effect, rvSegmentTemplate* st); bool Check(rvBSE* effect, float time, float offset); void Handle(rvBSE* effect, float time); void UpdateGenericParticles(rvBSE* effect, rvSegmentTemplate* st, float time); void UpdateSimpleParticles(float time); bool UpdateParticles(rvBSE* effect, float time); float AttenuateDuration(rvBSE* effect, rvSegmentTemplate* st); float AttenuateInterval(rvBSE* effect, rvSegmentTemplate* st); float AttenuateCount(rvBSE* effect, rvSegmentTemplate* st, float min, float max); void ValidateSpawnRates(void); void AddToParticleCount(rvBSE* effect, int count, int loopCount, float duration); void GetSecondsPerParticle(rvBSE* effect, rvSegmentTemplate* st, rvParticleTemplate* pt); void CalcTrailCounts(rvBSE* effect, rvSegmentTemplate* st, rvParticleTemplate* pt, float duration); void CalcCounts(rvBSE* effect, float time); void EmitSmokeParticles(rvBSE* effect, rvSegmentTemplate* st, rvParticle* particle, float time); // soundChannel_t GetSoundChannel( void ) { return static_cast< soundChannel_t >( mSegmentTemplateHandle ) + SCHANNEL_ONE; } void CreateDecal(rvBSE* effect, float time); void InitLight(rvBSE* effect, rvSegmentTemplate* st, float time); bool HandleLight(rvBSE* effect, rvSegmentTemplate* st, float time); rvParticle* InitParticleArray(rvBSE* effect); rvParticle* GetFreeParticle(rvBSE* effect); rvParticle* SpawnParticle(rvBSE* effect, rvSegmentTemplate* st, float birthTime, const idVec3& initPos = vec3_origin, const idMat3& initAxis = mat3_identity); void SpawnParticles(rvBSE* effect, rvSegmentTemplate* st, float birthTime, int count); void AllocateSurface(rvBSE* effect, idRenderModel* model); void ClearSurface(rvBSE* effect, idRenderModel* model); void RenderMotion(rvBSE* effect, const struct renderEffect_s* owner, idRenderModel* model, rvParticleTemplate* pt, float time); void RenderTrail(rvBSE* effect, const struct renderEffect_s* owner, idRenderModel* model, float time); void Render(rvBSE* effect, const struct renderEffect_s* owner, idRenderModel* model, float time); protected: void Sort(const idVec3& eyePos); // Fixed at spawn time int mSegmentTemplateHandle; int mParticleType; int mSurfaceIndex; // Index of the model surface that this segment uses const rvDeclEffect* mEffectDecl; float mSegStartTime; // Start time of segment float mSegEndTime; idVec2 mSecondsPerParticle; // How quickly the particles are spawned in an emitter idVec2 mCount; // The count of particles from a spawner int mParticleCount; // For getting the amount of memory to alloc for tris data int mLoopParticleCount; float mSoundVolume; float mFreqShift; // Dynamically altered during effect int mFlags; float mLastTime; // Last time the segment was serviced int mActiveCount; // Number of active particles rvParticle* mFreeHead; // Linked list of particles rvParticle* mUsedHead; rvParticle* mParticles; }; enum { STFLAG_ENABLED = BITT< 0 >::VALUE, STFLAG_LOCKED = BITT< 1 >::VALUE, STFLAG_HASPARTICLES = BITT< 2 >::VALUE, STFLAG_HASPHYSICS = BITT< 3 >::VALUE, STFLAG_IGNORE_DURATION = BITT< 4 >::VALUE, STFLAG_INFINITE_DURATION = BITT< 5 >::VALUE, STFLAG_ATTENUATE_EMITTER = BITT< 6 >::VALUE, STFLAG_INVERSE_ATTENUATE = BITT< 7 >::VALUE, STFLAG_TEMPORARY = BITT< 8 >::VALUE, STFLAG_USEMATCOLOR = BITT< 9 >::VALUE, STFLAG_DEPTH_SORT = BITT< 10 >::VALUE, STFLAG_INVERSE_DRAWORDER = BITT< 11 >::VALUE, STFLAG_ORIENTATE_IDENTITY = BITT< 12 >::VALUE, STFLAG_COMPLEX = BITT< 13 >::VALUE, STFLAG_CALCULATE_DURATION = BITT< 14 >::VALUE, }; class rvSegmentTemplate { public: friend class rvSegment; friend class rvBSE; friend class rvSegmentTemplateWrapper; rvSegmentTemplate(void) { Init(NULL); SetEnabled(true); } ~rvSegmentTemplate(void) {} // Support copying of a template rvSegmentTemplate(const rvSegmentTemplate& copy) { *this = copy; } void operator = (const rvSegmentTemplate& copy); bool operator == (const rvSegmentTemplate& a) const { return Compare(a); } bool operator != (const rvSegmentTemplate& a) const { return !Compare(a); } void SetFlag(bool on, int flag) { on ? mFlags |= flag : mFlags &= ~flag; } bool GetEnabled(void) const { return(!!(mFlags & STFLAG_ENABLED)); } bool GetLocked(void) const { return(!!(mFlags & STFLAG_LOCKED)); } bool GetHasParticles(void) const { return(!!(mFlags & STFLAG_HASPARTICLES)); } bool GetHasPhysics(void) const { return(!!(mFlags & STFLAG_HASPHYSICS)); } bool GetIgnoreDuration(void) const { return(!!(mFlags & STFLAG_IGNORE_DURATION)); } bool GetInfiniteDuration(void) const { return(!!(mFlags & STFLAG_INFINITE_DURATION)); } bool GetAttenuateEmitter(void) const { return(!!(mFlags & STFLAG_ATTENUATE_EMITTER)); } bool GetInverseAttenuate(void) const { return(!!(mFlags & STFLAG_INVERSE_ATTENUATE)); } bool GetUseMaterialColor(void) const { return(!!(mFlags & STFLAG_USEMATCOLOR)); } bool GetTemporary(void) const { return(!!(mFlags & STFLAG_TEMPORARY)); } bool GetDepthSort(void) const { return(!!(mFlags & STFLAG_DEPTH_SORT)); } bool GetInverseDrawOrder(void) const { return(!!(mFlags & STFLAG_INVERSE_DRAWORDER)); } bool GetOrientateIdentity(void) const { return(!!(mFlags & STFLAG_ORIENTATE_IDENTITY)); } bool GetComplexParticle(void) const { return(!!(mFlags & STFLAG_COMPLEX)); } bool GetCalculateDuration(void) const { return(!!(mFlags & STFLAG_CALCULATE_DURATION)); } void SetEnabled(bool enabled) { SetFlag(enabled, STFLAG_ENABLED); } void SetLocked(bool locked) { SetFlag(locked, STFLAG_LOCKED); } void SetHasParticles(bool hasParticles) { SetFlag(hasParticles, STFLAG_HASPARTICLES); } void SetHasPhysics(bool hasPhysics) { SetFlag(hasPhysics, STFLAG_HASPHYSICS); } void SetIgnoreDuration(bool ignoreDuration) { SetFlag(ignoreDuration, STFLAG_IGNORE_DURATION); } void SetInfiniteDuration(bool infiniteDuration) { SetFlag(infiniteDuration, STFLAG_INFINITE_DURATION); } void SetAttenuateEmitter(bool attenuate) { SetFlag(attenuate, STFLAG_ATTENUATE_EMITTER); } void SetInverseAttenuate(bool attenuate) { SetFlag(attenuate, STFLAG_INVERSE_ATTENUATE); } void SetUseMaterialColor(bool attenuate) { SetFlag(attenuate, STFLAG_USEMATCOLOR); } void SetTemporary(bool persistent) { SetFlag(persistent, STFLAG_TEMPORARY); } void SetDepthSort(bool locked) { SetFlag(locked, STFLAG_DEPTH_SORT); } void SetInverseDrawOrder(bool inverseDrawOrder) { SetFlag(inverseDrawOrder, STFLAG_INVERSE_DRAWORDER); } void SetOrientateIdentity(bool orientateIdentity) { SetFlag(orientateIdentity, STFLAG_ORIENTATE_IDENTITY); } void SetComplexParticle(bool enabled) { SetFlag(enabled, STFLAG_COMPLEX); } void SetCalculateDuration(bool calculateDuration) { SetFlag(calculateDuration, STFLAG_CALCULATE_DURATION); } const idStr& GetSegmentName(void) const { return(mSegmentName); } const rvDeclEffect* GetEffectDecl(void) { return(mDeclEffect); } void EvaluateTrailSegment(rvDeclEffect* et); int GetTrailSegmentIndex(void) const { return(mTrailSegmentIndex); } int GetType(void) const { return(mSegType); } bool GetSmoker(void); bool Parse(rvDeclEffect* et, int segmentType, idParser* lexer); void Init(rvDeclEffect* decl); float GetStartTime(void) const { return(rvRandom::flrand(mLocalStartTime[0], mLocalStartTime[1])); } float GetDuration(void) const { return(rvRandom::flrand(mLocalDuration[0], mLocalDuration[1])); } void SetMinDuration(rvDeclEffect* effect); void SetMaxDuration(rvDeclEffect* effect); bool GetSoundLooping(void); float GetSoundVolume(void) const { return(rvRandom::flrand(mSoundVolume[0], mSoundVolume[1])); } float GetFreqShift(void) const { return(rvRandom::flrand(mFreqShift[0], mFreqShift[1])); } float GetDensity(void) const { return(rvRandom::flrand(mDensity[0], mDensity[1])); } float GetMaxDensity(void) const { return(mDensity[1]); } float GetParticleCap(void) const { return(mParticleCap); } float GetMaxCount(void) const { return(mCount[1]); } int GetTexelCount(void); bool Finish(rvDeclEffect* et); void CreateParticleTemplate(rvDeclEffect* et, idParser* lexer, int particleType); rvParticleTemplate* GetParticleTemplate(void) { return(&mParticleTemplate); } const rvParticleTemplate* GetParticleTemplate(void) const { return(&mParticleTemplate); } float CalculateBounds(void); bool DetailCull(void) const; float EvaluateCost(int activeParticles) const; void Duplicate(const rvSegmentTemplate& copy); private: bool Compare(const rvSegmentTemplate& a) const; rvDeclEffect* mDeclEffect; // Common parms idStr mSegmentName; int mFlags; int mSegType; // SEG_ enum idVec2 mLocalStartTime; // Start time of segment wrt effect idVec2 mLocalDuration; // Min and max duration idVec2 mAttenuation; // How effect fades off to the distance float mParticleCap; float mScale; float mDetail; // bse_scale value that culls out this segment // Emitter parms rvParticleTemplate mParticleTemplate; idVec2 mCount; // The count of particles from a spawner idVec2 mDensity; // Sets count or rate based on volume, area or length int mTrailSegmentIndex; // Segment containing the trail info int mNumEffects; const rvDeclEffect* mEffects[BSE_NUM_SPAWNABLE]; // Effect to play on certain conditions const idSoundShader* mSoundShader; idVec2 mSoundVolume; // Starting volume of sound in decibels idVec2 mFreqShift; // Frequency shift of sound int mDecalAxis; // Axis to project decals along static float mSegmentBaseCosts[SEG_COUNT]; }; // ============================================== // ============================================== enum { ETFLAG_HAS_SOUND = BITT< 0 >::VALUE, ETFLAG_USES_ENDORIGIN = BITT< 1 >::VALUE, ETFLAG_ATTENUATES = BITT< 2 >::VALUE, ETFLAG_EDITOR_MODIFIED = BITT< 3 >::VALUE, ETFLAG_USES_MATERIAL_COLOR = BITT< 4 >::VALUE, ETFLAG_ORIENTATE_IDENTITY = BITT< 5 >::VALUE, ETFLAG_USES_AMBIENT_CUBEMAP = BITT< 6 >::VALUE, ETFLAG_HAS_PHYSICS = BITT< 7 >::VALUE, }; class rvDeclEffect : public idDecl { public: friend class rvBSE; friend class rvEffectTemplateWrapper; friend class rvBSEManagerLocal; rvDeclEffect(void) { Init(); } rvDeclEffect(const rvDeclEffect& copy) { Init(); *this = copy; } virtual ~rvDeclEffect(void) { } bool operator== (const rvDeclEffect& comp) const { return Compare(comp); } bool operator!= (const rvDeclEffect& comp) const { return !Compare(comp); } rvDeclEffect& operator= (const rvDeclEffect& copy); virtual bool SetDefaultText(void); virtual const char* DefaultDefinition(void) const; virtual bool Parse(const char* text, const int textLength) override; virtual void FreeData(void); virtual size_t Size(void) const; static void CacheFromDict(const idDict& dict); void SetFlag(bool on, int flag) { on ? mFlags |= flag : mFlags &= ~flag; } bool GetEditorModified(void) const { return(!!(mFlags & ETFLAG_EDITOR_MODIFIED)); } bool GetHasSound(void) const { return(!!(mFlags & ETFLAG_HAS_SOUND)); } bool GetHasPhysics(void) const { return(!!(mFlags & ETFLAG_HAS_PHYSICS)); } bool GetUsesEndOrigin(void) const { return(!!(mFlags & ETFLAG_USES_ENDORIGIN)); } bool GetAttenuates(void) const { return(!!(mFlags & ETFLAG_ATTENUATES)); } bool GetOrientateIdentity(void) const { return(!!(mFlags & ETFLAG_ORIENTATE_IDENTITY)); } bool GetUsesAmbientCubeMap(void) const { return(!!(mFlags & ETFLAG_USES_AMBIENT_CUBEMAP)); } void SetEditorModified(bool modified) { base->EnsureNotPurged(); SetFlag(modified, ETFLAG_EDITOR_MODIFIED); } void SetHasSound(bool hasSound) { SetFlag(hasSound, ETFLAG_HAS_SOUND); } void SetHasPhysics(bool hasPhysics) { SetFlag(hasPhysics, ETFLAG_HAS_PHYSICS); } void SetUsesEndOrigin(bool usesEndOrigin) { SetFlag(usesEndOrigin, ETFLAG_USES_ENDORIGIN); } void SetAttenuates(bool attenuates) { SetFlag(attenuates, ETFLAG_ATTENUATES); } void SetOrientateIdentity(bool orientateIdentity) { SetFlag(orientateIdentity, ETFLAG_ORIENTATE_IDENTITY); } void SetUsesAmbientCubeMap(bool usesAmbientCubeMap) { SetFlag(usesAmbientCubeMap, ETFLAG_USES_AMBIENT_CUBEMAP); } rvSegmentTemplate* GetSegmentTemplate(int i) { return(&mSegmentTemplates[i]); } const rvSegmentTemplate* GetSegmentTemplate(int i) const { return(&mSegmentTemplates[i]); } rvSegmentTemplate* GetSegmentTemplate(const char* name); int GetTrailSegmentIndex(const idStr& name); void SetMinDuration(float duration); float GetMinDuration(void) const { return(mMinDuration); } void SetMaxDuration(float duration); float GetMaxDuration(void) const { return(mMaxDuration); } float GetSize(void) const { return(mSize); } void SetSize(float size) { mSize = size; } int GetNumSegmentTemplates(void) const { return(mSegmentTemplates.Num()); } rvSegmentTemplate* GetSegmentTemplate(const char* name) const; void Init(void); void Finish(void); bool ParseSegment(int segmentType, idLexer* lexer); float CalculateBounds(void); void IncPlayCount(void) const { mPlayCount++; } int GetPlayCount(void) const { return(mPlayCount); } void IncLoopCount(void) const { mLoopCount++; } int GetLoopCount(void) const { return(mLoopCount); } float EvaluateCost(int activeParticles, int segment = -1) const; float GetCutOffDistance(void) const { return mCutOffDistance; } void SetCutOffDistance(float dist) { mCutOffDistance = dist; } private: bool Compare(const rvDeclEffect& comp) const; int mFlags; float mMinDuration; // Minimum possible duration of the effect float mMaxDuration; // Maximum possible duration of the effect float mCutOffDistance; float mSize; idList mSegmentTemplates; mutable int mPlayCount; // For profiling mutable int mLoopCount; // For profiling }; enum { EFLAG_LOOPING = BITT< 0 >::VALUE, EFLAG_HASENDORIGIN = BITT< 1 >::VALUE, EFLAG_ENDORIGINCHANGED = BITT< 2 >::VALUE, EFLAG_STOPPED = BITT< 3 >::VALUE, EFLAG_ORIENTATE_IDENTITY = BITT< 4 >::VALUE, EFLAG_AMBIENT = BITT< 5 >::VALUE, }; const int LIGHTID_EFFECT_LIGHT = 300; class rvBSE { public: rvBSE(void) { mFlags = 0; mRenderWorld = NULL; } ~rvBSE(void) {} void Init(const rvDeclEffect* declEffect, struct renderEffect_s* parms, float time); void Destroy(void); void SetFlag(bool on, int flag) { on ? mFlags |= flag : mFlags &= ~flag; } bool GetLooping(void) const { return(!!(mFlags & EFLAG_LOOPING)); } bool GetHasEndOrigin(void) const { return(!!(mFlags & EFLAG_HASENDORIGIN)); } bool GetEndOriginChanged(void) const { return(!!(mFlags & EFLAG_ENDORIGINCHANGED)); } bool GetStopped(void) const { return(!!(mFlags & EFLAG_STOPPED)); } bool GetOrientateIdentity(void) const { return(!!(mFlags & EFLAG_ORIENTATE_IDENTITY)); } void SetLooping(bool looping) { SetFlag(looping, EFLAG_LOOPING); } void SetHasEndOrigin(bool hasEndOrigin) { SetFlag(hasEndOrigin, EFLAG_HASENDORIGIN); } void SetEndOriginChanged(bool endOriginChanged) { SetFlag(endOriginChanged, EFLAG_ENDORIGINCHANGED); } virtual void SetStopped(bool stopped) { SetFlag(stopped, EFLAG_STOPPED); } virtual void SetOrientateIdentity(bool orientateIdentity) { SetFlag(orientateIdentity, EFLAG_ORIENTATE_IDENTITY); } void SetDuration(float time); virtual float GetDuration(void) const { return(mDuration); } float GetStartTime(void) const { return mStartTime; } bool Expired(float time) const { return(time > mStartTime + mDuration); } void SetAttenuation(float atten) { mAttenuation = atten; } float GetAttenuation(rvSegmentTemplate* st) const; float GetOriginAttenuation(rvSegmentTemplate* st) const; void UpdateAttenuation(void); idSoundEmitter* GetReferenceSound(void) const { return(mReferenceSound); } float GetRed(void) const { return(mTint[0]); } float GetGreen(void) const { return(mTint[1]); } float GetBlue(void) const { return(mTint[2]); } float GetAlpha(void) const { return(mTint[3]); } int GetSuppressLightsInViewID(void) const { return mSuppressLightsInViewID; } float GetBrightness(void) const { return(mBrightness); } void SetBrightness(float bright) { mBrightness = bright; } const idVec2& GetSpriteSize(void) const { return mSpriteSize; } const float* GetShaderParms(void) const { return mShaderParms; } bool CanInterpolate(void) { return(mCurrentTime - mLastTime > BSE_TIME_EPSILON); } void UpdateFromOwner(renderEffect_t* parms, float time, bool init = false); void LoopInstant(float time); void LoopLooping(float time); virtual bool Service(renderEffect_t* parms, float time, bool spawn, bool& forcePush); void UpdateSoundEmitter(rvSegmentTemplate* st, rvSegment* seg); virtual void DisplayDebugInfo(const struct renderEffect_s* parms, const struct viewDef_s* view, idBounds& bounds); void InitModel(idRenderModel* model); idRenderModel* Render(idRenderModel* model, const struct renderEffect_s* owner, const struct viewDef_s* view); const char* GetDeclName(void); rvSegment* GetTrailSegment(int child) { return(&mSegments[child]); } rvSegment* GetTrailSegment(const idStr& name); const idVec3& GetViewOrg(void) const { return(mViewOrg); } const idMat3& GetViewAxis(void) const { return(mViewAxis); } const idVec3& GetGravity(void) const { return(mGravity); } const idVec3& GetGravityDir(void) const { return(mGravityDir); } const idVec3& GetOriginalOrigin(void) const { return(mOriginalOrigin); } const idVec3& GetOriginalEndOrigin(void) const { return(mOriginalEndOrigin); } const idMat3& GetOriginalAxis(void) const { return(mOriginalAxis); } const idMat3& GetLightningAxis(void) const { return(mLightningAxis); } const idVec3& GetCurrentOrigin(void) const { return(mCurrentOrigin); } const idVec3& GetCurrentVelocity(void) const { return(mCurrentVelocity); } const idVec3& GetCurrentEndOrigin(void) const { return(mCurrentEndOrigin); } const idVec3 GetInterpolatedOffset(float time) const; const idMat3& GetCurrentAxis(void) const { return(mCurrentAxis); } const idMat3& GetCurrentAxisTransposed(void) const { return(mCurrentAxisTransposed); } virtual const idBounds& GetCurrentLocalBounds(void) const { return(mCurrentLocalBounds); } const idBounds& GetLastRenderBounds(void) const { return(mLastRenderBounds); } const idVec3& GetCurrentWindVector(void) const { return(mCurrentWindVector); } void SetRenderWorld( idRenderWorld *renderWorld ) { mRenderWorld = renderWorld; } idRenderWorld* GetRenderWorld( void ) const { return mRenderWorld; } void UpdateSegments(float time); virtual int GetValidFrames(void) const { return mValidFrames; }; void SetMaterialColor(const idVec3& color) { mMaterialColor = color; } const idVec3& GetMaterialColor() const { return mMaterialColor; } float EvaluateCost(int segment = -1); private: // Fixed at spawn time const rvDeclEffect* mDeclEffect; idSoundEmitter* mReferenceSound; idRenderWorld* mRenderWorld; idVec3 mOriginalOrigin; // Origin in world space idVec3 mOriginalEndOrigin; idMat3 mOriginalAxis; // Original axis of orientation idMat3 mLightningAxis; float mStartTime; // World start time of effect float mLastTime; // Last time the effect was serviced float mDuration; // Duration of the effect - including any randomness idVec3 mMaterialColor; // Dynamically altered int mFlags; int mSuppressLightsInViewID; float mAttenuation; // Forced attenuation settable in code float mOriginDistanceToCamera; // Distance from effect origin to view origin float mShortestDistanceToCamera; // Closest point on effects bounds to view origin idVec4 mTint; // Overridable tint float mBrightness; // Overall brightness of effect idVec2 mSpriteSize; // Optional sprite size override from shader parms float mShaderParms[MAX_ENTITY_SHADER_PARMS]; // Owner shader parms for light/material control float mCost; // Best guess at how expensive the effect is idVec3 mViewOrg; idMat3 mViewAxis; idVec3 mGravity; idVec3 mGravityDir; idVec3 mLastOrigin; float mCurrentTime; idVec3 mCurrentOrigin; // Current origin in world space idVec3 mCurrentVelocity; // Current velocity in world space idVec3 mCurrentEndOrigin; // Current end origin in world space idMat3 mCurrentAxis; // Current axis of orientation idMat3 mCurrentAxisTransposed; // Current axis of orientation transposed idBounds mCurrentLocalBounds; // Current local bounds idBounds mCurrentWorldBounds; // Current world bounds idBounds mLastRenderBounds; // Last render bounds idBounds mGrownRenderBounds; // Last render bounds bool mForcePush; idVec3 mCurrentWindVector; idList mSegments; int mValidFrames; // The model doesn't need to be updated the next x frames (zero means reupdate every frame obviously) }; class rvRenderEffectLocal; class rvBSEManagerLocal : public rvBSEManager { public: virtual bool Init(void); virtual bool Shutdown(void); virtual bool PlayEffect(class rvRenderEffectLocal* def, float time); virtual bool ServiceEffect(class rvRenderEffectLocal* def, float time); virtual idRenderModel* RenderEffect(class rvRenderEffectLocal* def, const struct viewDef_s* view); virtual void StopEffect(rvRenderEffectLocal* def); virtual void FreeEffect(rvRenderEffectLocal* def); virtual float EffectDuration(const rvRenderEffectLocal* def); virtual bool CheckDefForSound(const renderEffect_t* def); virtual void BeginLevelLoad(void); virtual void EndLevelLoad(void); virtual void StartFrame(void); virtual void EndFrame(void); virtual bool Filtered(const char* name, effectCategory_t category); virtual void UpdateRateTimes(void) ; virtual bool CanPlayRateLimited(effectCategory_t category); virtual int AddTraceModel(idTraceModel* model); virtual idTraceModel* GetTraceModel(int index); virtual void FreeTraceModel(int index); private: static idBlockAlloc effects; static idVec3 mCubeNormals[6]; static idMat3 mModelToBSE; static idList mTraceModels; static const char* mSegmentNames[SEG_COUNT]; static int mPerfCounters[NUM_PERF_COUNTERS]; static float mEffectRates[EC_MAX]; float pauseTime; // -1 means pause at the next time update };