631 lines
29 KiB
C
631 lines
29 KiB
C
|
// Copyright (C) 2007 Id Software, Inc.
|
||
|
//
|
||
|
|
||
|
|
||
|
#ifndef _BSE_H_INC_
|
||
|
#define _BSE_H_INC_
|
||
|
|
||
|
#include "../sound/SoundEmitter.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;
|
||
|
|
||
|
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_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 © );
|
||
|
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 © );
|
||
|
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 © );
|
||
|
|
||
|
virtual bool SetDefaultText( void );
|
||
|
virtual const char *DefaultDefinition( void ) const;
|
||
|
virtual bool Parse( const char *text, const int textLength );
|
||
|
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 <rvSegmentTemplate> 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; }
|
||
|
~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; }
|
||
|
|
||
|
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 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;
|
||
|
|
||
|
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
|
||
|
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 <rvSegment> mSegments;
|
||
|
int mValidFrames; // The model doesn't need to be updated the next x frames (zero means reupdate every frame obviously)
|
||
|
};
|
||
|
|
||
|
// ==============================================
|
||
|
// ==============================================
|
||
|
|
||
|
class rvBSEManagerLocal : public rvBSEManager
|
||
|
{
|
||
|
public:
|
||
|
rvBSEManagerLocal( void ) {}
|
||
|
~rvBSEManagerLocal( void ) {}
|
||
|
|
||
|
virtual bool Init( void );
|
||
|
virtual bool Shutdown( void );
|
||
|
|
||
|
virtual bool PlayEffect( rvRenderEffectLocal *def, float time );
|
||
|
virtual bool ServiceEffect( rvRenderEffectLocal *def, float time, bool &forcePush );
|
||
|
virtual void StopEffect( rvRenderEffectLocal *def );
|
||
|
virtual void RestartEffect( rvRenderEffectLocal *def );
|
||
|
virtual void FreeEffect( rvRenderEffectLocal *def );
|
||
|
virtual float EffectDuration( const rvRenderEffectLocal *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 void SetShakeParms( float time, float scale );
|
||
|
virtual void SetTunnelParms( float time, float scale );
|
||
|
|
||
|
void LoadAll( const idCmdArgs &args );
|
||
|
void Stats( const idCmdArgs &args );
|
||
|
void Pause( const idCmdArgs &args );
|
||
|
rvBSE *GetPlayingEffect( int handle, struct renderEntity_s *ent );
|
||
|
|
||
|
virtual int AddTraceModel( idTraceModel* model );
|
||
|
virtual idTraceModel* GetTraceModel( int index );
|
||
|
virtual void FreeTraceModel( int index );
|
||
|
|
||
|
virtual const idVec3& GetCubeNormals( int index );
|
||
|
virtual const idMat3& GetModelToBSE() { return mModelToBSE; }
|
||
|
|
||
|
virtual bool IsTimeLocked() const { return pauseTime > 0.0f; }
|
||
|
virtual float GetLockedTime() const { return pauseTime; }
|
||
|
|
||
|
virtual void MakeEditable( class rvParticleTemplate *particle );
|
||
|
|
||
|
virtual void CopySegment( class rvSegmentTemplate *dest, class rvSegmentTemplate *src );
|
||
|
|
||
|
private:
|
||
|
friend class rvFXApp;
|
||
|
|
||
|
public:
|
||
|
static idBlockAlloc<rvBSE, 256> effects;
|
||
|
static idVec3 mCubeNormals[6];
|
||
|
static idMat3 mModelToBSE;
|
||
|
static idList<idTraceModel *> 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
|
||
|
};
|
||
|
|
||
|
#endif // _BSE_H_INC_
|
||
|
|