mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-20 20:50:58 +02:00
Quake 4 integrated with DoomRTX
This commit is contained in:
@@ -0,0 +1,615 @@
|
||||
// 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 <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; 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 <rvSegment> 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<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
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
#ifndef _BSE_INTERFACE_H_INC_
|
||||
#define _BSE_INTERFACE_H_INC_
|
||||
|
||||
#define BSE_EFFECT_EXTENSION "fx"
|
||||
|
||||
enum
|
||||
{
|
||||
VIEWEFFECT_DOUBLEVISION = 0,
|
||||
VIEWEFFECT_SHAKE,
|
||||
VIEWEFFECT_TUNNEL
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
EC_IGNORE = 0,
|
||||
EC_IMPACT,
|
||||
EC_IMPACT_PARTICLES,
|
||||
|
||||
EC_MAX,
|
||||
} effectCategory_t;
|
||||
|
||||
extern idCVar bse_enabled;
|
||||
extern idCVar bse_render;
|
||||
extern idCVar bse_debug;
|
||||
extern idCVar bse_showBounds;
|
||||
extern idCVar bse_physics;
|
||||
extern idCVar bse_debris;
|
||||
extern idCVar bse_scale;
|
||||
extern idCVar bse_singleEffect;
|
||||
extern idCVar bse_maxParticles;
|
||||
|
||||
// Temporary BSE frame counters (spawned/serviced/rendered), reset each StartFrame.
|
||||
extern int bse_frameSpawned;
|
||||
extern int bse_frameServiced;
|
||||
extern int bse_frameRendered;
|
||||
|
||||
void BSE_ResetFrameCounters( void );
|
||||
void BSE_AddSpawned( int count );
|
||||
void BSE_AddServiced( int count );
|
||||
void BSE_AddRendered( int count );
|
||||
|
||||
class idRenderModel;
|
||||
struct viewDef_s;
|
||||
|
||||
// Interface to the effects system
|
||||
|
||||
class rvBSEManager
|
||||
{
|
||||
public:
|
||||
virtual ~rvBSEManager( void ) {}
|
||||
|
||||
virtual bool Init( void ) = 0;
|
||||
virtual bool Shutdown( void ) = 0;
|
||||
|
||||
virtual bool PlayEffect( class rvRenderEffectLocal *def, float time ) = 0;
|
||||
virtual bool ServiceEffect( class rvRenderEffectLocal *def, float time ) = 0;
|
||||
virtual idRenderModel* RenderEffect( class rvRenderEffectLocal *def, const struct viewDef_s *view ) = 0;
|
||||
virtual void StopEffect( rvRenderEffectLocal *def ) = 0;
|
||||
virtual void FreeEffect( rvRenderEffectLocal *def ) = 0;
|
||||
virtual float EffectDuration( const rvRenderEffectLocal *def ) = 0;
|
||||
|
||||
virtual bool CheckDefForSound( const renderEffect_t *def ) = 0;
|
||||
|
||||
virtual void BeginLevelLoad( void ) = 0;
|
||||
virtual void EndLevelLoad( void ) = 0;
|
||||
|
||||
virtual void StartFrame( void ) = 0;
|
||||
virtual void EndFrame( void ) = 0;
|
||||
virtual bool Filtered( const char *name, effectCategory_t category ) = 0;
|
||||
|
||||
virtual void UpdateRateTimes( void ) = 0;
|
||||
virtual bool CanPlayRateLimited( effectCategory_t category ) = 0;
|
||||
|
||||
virtual int AddTraceModel(idTraceModel* model) = 0;
|
||||
virtual idTraceModel* GetTraceModel(int index) = 0;
|
||||
virtual void FreeTraceModel(int index) = 0;
|
||||
};
|
||||
|
||||
extern rvBSEManager *bse;
|
||||
|
||||
class rvDeclEffectEdit
|
||||
{
|
||||
public:
|
||||
virtual ~rvDeclEffectEdit() {}
|
||||
virtual void Finish( class rvDeclEffect *edit ) = 0;
|
||||
virtual class rvSegmentTemplate *GetSegmentTemplate( class rvDeclEffect *edit, const char *name ) = 0;
|
||||
virtual class rvSegmentTemplate *GetSegmentTemplate( class rvDeclEffect *edit, int i ) = 0;
|
||||
virtual void CopyData( class rvDeclEffect *edit, class rvDeclEffect *copy ) = 0;
|
||||
virtual int AddSegment( class rvDeclEffect *edit, class rvSegmentTemplate *add ) = 0;
|
||||
virtual void DeleteSegment( class rvDeclEffect *edit, int index ) = 0;
|
||||
virtual void SwapSegments( class rvSegmentTemplate *seg1, class rvSegmentTemplate *seg2 ) = 0;
|
||||
|
||||
virtual void CreateEditorOriginal( class rvDeclEffect *edit ) = 0;
|
||||
virtual void DeleteEditorOriginal( class rvDeclEffect *edit ) = 0;
|
||||
virtual bool CompareToEditorOriginal( class rvDeclEffect *edit ) = 0;
|
||||
virtual void RevertToEditorOriginal( class rvDeclEffect *edit ) = 0;
|
||||
|
||||
virtual void Init( class rvSegmentTemplate *edit, class rvDeclEffect *effect ) = 0;
|
||||
virtual bool Parse( class rvSegmentTemplate *edit, class rvDeclEffect *effect, int type, class idLexer *lexer ) = 0;
|
||||
virtual void Finish( class rvSegmentTemplate *edit, class rvDeclEffect *effect ) = 0;
|
||||
virtual bool Compare( class rvSegmentTemplate *edit, const class rvSegmentTemplate *other ) const = 0;
|
||||
virtual void SetName( class rvSegmentTemplate *edit, const char *name ) = 0;
|
||||
|
||||
virtual void Finish( class rvParticleTemplate *edit ) = 0;
|
||||
virtual bool Compare( class rvParticleTemplate *edit, const class rvParticleTemplate *other ) const = 0;
|
||||
virtual void Init( class rvParticleTemplate *edit ) = 0;
|
||||
virtual void FixupParms( class rvParticleTemplate *edit, class rvParticleParms *parms ) = 0;
|
||||
virtual void SetMaterialName( class rvParticleTemplate *edit, const char *name ) = 0;
|
||||
virtual void SetModelName( class rvParticleTemplate *edit, const char *name ) = 0;
|
||||
virtual void SetEntityDefName( class rvParticleTemplate *edit, const char *name ) = 0;
|
||||
virtual void SetTrailTypeName( class rvParticleTemplate *edit, const char *name ) = 0;
|
||||
virtual void SetTrailMaterialName( class rvParticleTemplate *edit, const char *name ) = 0;
|
||||
|
||||
virtual bool Compare( class rvParticleParms *edit, const class rvParticleParms *other ) const = 0;
|
||||
|
||||
virtual void CalcRate( class rvEnvParms *edit, float *rate, float duration, int count ) = 0;
|
||||
virtual void Evaluate3( class rvEnvParms *edit, float time, const float *start, const float *rate, const float *end, float *dest ) = 0;
|
||||
};
|
||||
|
||||
extern rvDeclEffectEdit *declEffectEdit;
|
||||
|
||||
#endif // _BSE_INTERFACE_H_INC_
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _BSE_API_H_INC_
|
||||
#define _BSE_API_H_INC_
|
||||
|
||||
#include "BSEInterface.h"
|
||||
|
||||
class idDecl;
|
||||
|
||||
typedef idDecl* (*BSE_AllocDeclEffect_t)(void);
|
||||
|
||||
rvBSEManager* OpenQ4_GetIntegratedBSEManager( void );
|
||||
idDecl* OpenQ4_AllocIntegratedBSEDeclEffect( void );
|
||||
|
||||
extern BSE_AllocDeclEffect_t bseAllocDeclEffect;
|
||||
|
||||
#endif // _BSE_API_H_INC_
|
||||
@@ -0,0 +1,780 @@
|
||||
// BSE_Effect.cpp
|
||||
//
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE.h"
|
||||
#include "BSE_SpawnDomains.h"
|
||||
|
||||
//#include "../renderer/RenderCommon.h"
|
||||
|
||||
static ID_INLINE void BSE_BoundTriSurf(srfTriangles_t* tri) {
|
||||
if (!tri) {
|
||||
return;
|
||||
}
|
||||
if (tri->numVerts <= 0 || !tri->verts) {
|
||||
tri->bounds.Clear();
|
||||
return;
|
||||
}
|
||||
tri->bounds.Clear();
|
||||
for (int i = 0; i < tri->numVerts; ++i) {
|
||||
tri->bounds.AddPoint(tri->verts[i].xyz);
|
||||
}
|
||||
}
|
||||
|
||||
void rvBSE::Init(const rvDeclEffect* declEffect, renderEffect_s* parms, float time)
|
||||
{
|
||||
int v6; // esi
|
||||
float* v7; // ecx
|
||||
float* v8; // eax
|
||||
double v9; // st3
|
||||
double v10; // st5
|
||||
float* v11; // esi
|
||||
float* v12; // eax
|
||||
int v13; // ecx
|
||||
double v14; // st5
|
||||
//float v15; // [esp+18h] [ebp-30h]
|
||||
//float v16; // [esp+1Ch] [ebp-2Ch]
|
||||
//float v17; // [esp+20h] [ebp-28h]
|
||||
//float v18; // [esp+24h] [ebp-24h]
|
||||
//float v19; // [esp+28h] [ebp-20h]
|
||||
//float v20; // [esp+2Ch] [ebp-1Ch]
|
||||
//float v21; // [esp+30h] [ebp-18h] BYREF
|
||||
//float v22[5]; // [esp+34h] [ebp-14h] BYREF
|
||||
float parmsa; // [esp+50h] [ebp+8h]
|
||||
|
||||
this->mStartTime = parms->startTime;
|
||||
this->mDeclEffect = declEffect;
|
||||
this->mLastTime = time;
|
||||
this->mFlags = 0;
|
||||
this->mDuration = 0.0;
|
||||
this->mAttenuation = 1.0;
|
||||
v6 = 2;
|
||||
this->mCost = 0.0;
|
||||
this->mFlags = parms->loop;
|
||||
this->mCurrentLocalBounds[1].z = 0.0;
|
||||
this->mCurrentLocalBounds[1].y = 0.0;
|
||||
v7 = &this->mLastRenderBounds[0].z;
|
||||
this->mCurrentLocalBounds[1].x = 0.0;
|
||||
this->mCurrentLocalBounds[0].z = 0.0;
|
||||
this->mCurrentLocalBounds[0].y = 0.0;
|
||||
this->mCurrentLocalBounds[0].x = 0.0;
|
||||
v8 = &this->mCurrentLocalBounds[0].z;
|
||||
v9 = declEffect->mSize;
|
||||
this->mCurrentLocalBounds[0].x = this->mCurrentLocalBounds[0].x - v9;
|
||||
this->mCurrentLocalBounds[0].y = this->mCurrentLocalBounds[0].y - v9;
|
||||
this->mCurrentLocalBounds[0].z = this->mCurrentLocalBounds[0].z - v9;
|
||||
this->mCurrentLocalBounds[1].x = this->mCurrentLocalBounds[1].x + v9;
|
||||
this->mCurrentLocalBounds[1].y = v9 + this->mCurrentLocalBounds[1].y;
|
||||
this->mCurrentLocalBounds[1].z = v9 + this->mCurrentLocalBounds[1].z;
|
||||
do
|
||||
{
|
||||
v10 = *(v8 - 2);
|
||||
v8 += 3;
|
||||
*(v7 - 2) = v10;
|
||||
v7 += 3;
|
||||
--v6;
|
||||
*(v7 - 4) = *(v8 - 4);
|
||||
*(v7 - 3) = *(v8 - 3);
|
||||
} while (v6);
|
||||
this->mGrownRenderBounds[0].z = 1.0e30;
|
||||
this->mGrownRenderBounds[0].y = 1.0e30;
|
||||
this->mGrownRenderBounds[0].x = 1.0e30;
|
||||
parmsa = -1.0e30;
|
||||
this->mGrownRenderBounds[1].z = parmsa;
|
||||
this->mGrownRenderBounds[1].y = parmsa;
|
||||
this->mGrownRenderBounds[1].x = parmsa;
|
||||
this->mForcePush = 0;
|
||||
this->mOriginalOrigin.x = parms->origin.x;
|
||||
this->mOriginalOrigin.y = parms->origin.y;
|
||||
this->mOriginalOrigin.z = parms->origin.z;
|
||||
this->mOriginalEndOrigin.z = 0.0;
|
||||
this->mOriginalEndOrigin.y = 0.0;
|
||||
this->mOriginalEndOrigin.x = 0.0;
|
||||
memcpy(&this->mOriginalAxis, &parms->axis, sizeof(this->mOriginalAxis));
|
||||
//v18 = this->mOriginalOrigin.x + this->mCurrentLocalBounds.b[1].x;
|
||||
//v19 = this->mCurrentLocalBounds[1].y + this->mOriginalOrigin.y;
|
||||
//v11 = &v21;
|
||||
//v20 = this->mCurrentLocalBounds[1].z + this->mOriginalOrigin.z;
|
||||
//v12 = &this->mCurrentWorldBounds[0].y;
|
||||
//v13 = 2;
|
||||
//v15 = this->mOriginalOrigin.x + this->mCurrentLocalBounds.b[0].x;
|
||||
//v16 = this->mCurrentLocalBounds[0].y + this->mOriginalOrigin.y;
|
||||
//v17 = this->mCurrentLocalBounds[0].z + this->mOriginalOrigin.z;
|
||||
//v21 = v15;
|
||||
//v22[0] = v16;
|
||||
//v22[1] = v17;
|
||||
//v22[2] = v18;
|
||||
//v22[3] = v19;
|
||||
//v22[4] = v20;
|
||||
//do
|
||||
//{
|
||||
// v14 = *v11;
|
||||
// v11 += 3;
|
||||
// *(v12 - 1) = v14;
|
||||
// v12 += 3;
|
||||
// --v13;
|
||||
// *(v12 - 3) = *(float*)((char*)v12 + (char*)&v21 - (char*)&this->mCurrentWorldBounds - 12);
|
||||
// *(v12 - 2) = *(float*)((char*)v12 + (char*)v22 - (char*)&this->mCurrentWorldBounds - 12);
|
||||
//} while (v13);
|
||||
if (parms->hasEndOrigin)
|
||||
{
|
||||
this->mFlags |= 2u;
|
||||
this->mOriginalEndOrigin.x = parms->endOrigin.x;
|
||||
this->mOriginalEndOrigin.y = parms->endOrigin.y;
|
||||
this->mOriginalEndOrigin.z = parms->endOrigin.z;
|
||||
this->mCurrentEndOrigin.x = parms->endOrigin.x;
|
||||
this->mCurrentEndOrigin.y = parms->endOrigin.y;
|
||||
this->mCurrentEndOrigin.z = parms->endOrigin.z;
|
||||
}
|
||||
this->mCurrentTime = time;
|
||||
this->mCurrentOrigin.x = this->mOriginalOrigin.x;
|
||||
this->mCurrentOrigin.y = this->mOriginalOrigin.y;
|
||||
this->mCurrentOrigin.z = this->mOriginalOrigin.z;
|
||||
this->mCurrentVelocity.z = 0.0;
|
||||
this->mCurrentVelocity.y = 0.0;
|
||||
this->mCurrentVelocity.x = 0.0;
|
||||
this->mCurrentWorldBounds.Clear();
|
||||
this->mCurrentWorldBounds.AddPoint(this->mCurrentOrigin + this->mCurrentLocalBounds[0]);
|
||||
this->mCurrentWorldBounds.AddPoint(this->mCurrentOrigin + this->mCurrentLocalBounds[1]);
|
||||
this->mSpriteSize.Zero();
|
||||
UpdateFromOwner(parms, time, 1);
|
||||
this->mReferenceSound = 0;
|
||||
if (parms->referenceSoundHandle > 0) {
|
||||
this->mReferenceSound = soundSystem->EmitterForIndex(SOUNDWORLD_GAME, parms->referenceSoundHandle);
|
||||
}
|
||||
UpdateSegments(time);
|
||||
this->mOriginDistanceToCamera = 0.0;
|
||||
this->mShortestDistanceToCamera = 0.0;
|
||||
}
|
||||
|
||||
float rvBSE::GetAttenuation(rvSegmentTemplate* st) const
|
||||
{
|
||||
double result; // st7
|
||||
float sta; // [esp+4h] [ebp+4h]
|
||||
float stb; // [esp+4h] [ebp+4h]
|
||||
float stc; // [esp+4h] [ebp+4h]
|
||||
float std; // [esp+4h] [ebp+4h]
|
||||
|
||||
result = 0.0;
|
||||
if (st->mAttenuation.x <= 0.0 && st->mAttenuation.y <= 0.0)
|
||||
return this->mAttenuation;
|
||||
sta = st->mAttenuation.x + 1.0;
|
||||
if (sta > (double)this->mShortestDistanceToCamera)
|
||||
return this->mAttenuation;
|
||||
stb = st->mAttenuation.y - 1.0;
|
||||
if (stb >= (double)this->mShortestDistanceToCamera)
|
||||
{
|
||||
stc = (this->mShortestDistanceToCamera - st->mAttenuation.x) / (st->mAttenuation.y - st->mAttenuation.x);
|
||||
std = (1.0 - stc) * this->mAttenuation;
|
||||
result = std;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float rvBSE::GetOriginAttenuation(rvSegmentTemplate* st) const
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
if (st->mAttenuation.x <= 0.0f && st->mAttenuation.y <= 0.0f) {
|
||||
return st->mScale * mAttenuation;
|
||||
}
|
||||
|
||||
if (st->mAttenuation.x + 1.0f > mOriginDistanceToCamera) {
|
||||
return st->mScale * mAttenuation;
|
||||
}
|
||||
|
||||
if (st->mAttenuation.y - 1.0f >= mOriginDistanceToCamera) {
|
||||
const float lerp = (mOriginDistanceToCamera - st->mAttenuation.x) / (st->mAttenuation.y - st->mAttenuation.x);
|
||||
result = (1.0f - lerp) * st->mScale * mAttenuation;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rvBSE::UpdateSoundEmitter(rvSegmentTemplate* st, rvSegment* seg)
|
||||
{
|
||||
if (!st || !seg || !mReferenceSound) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetStopped()) {
|
||||
// Stop looping sounds when the owning effect is stopped.
|
||||
if (st->GetSoundLooping() && (seg->mFlags & 2) != 0) {
|
||||
mReferenceSound->StopSound(static_cast<s_channelType>(seg->mSegmentTemplateHandle + SCHANNEL_ONE));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
soundShaderParms_t parms = {};
|
||||
parms.volume = seg->mSoundVolume;
|
||||
parms.frequencyShift = seg->mFreqShift;
|
||||
|
||||
// Keep the emitter spatialized at the current effect origin so sound
|
||||
// tracks moving/attached effects correctly.
|
||||
mReferenceSound->UpdateEmitter(mCurrentOrigin, mCurrentVelocity, 0, &parms);
|
||||
}
|
||||
const idVec3 rvBSE::GetInterpolatedOffset(float time) const
|
||||
{
|
||||
idVec3 result; // eax
|
||||
float v5; // [esp+0h] [ebp-18h]
|
||||
float v6; // [esp+4h] [ebp-14h]
|
||||
float v7; // [esp+8h] [ebp-10h]
|
||||
float v8; // [esp+Ch] [ebp-Ch]
|
||||
float v9; // [esp+10h] [ebp-8h]
|
||||
float v10; // [esp+14h] [ebp-4h]
|
||||
float deltaTime; // [esp+1Ch] [ebp+4h]
|
||||
float deltaTimea; // [esp+1Ch] [ebp+4h]
|
||||
|
||||
result.z = 0.0;
|
||||
result.y = 0.0;
|
||||
result.x = 0.0;
|
||||
deltaTime = this->mCurrentTime - this->mLastTime;
|
||||
if (deltaTime >= 0.0020000001)
|
||||
{
|
||||
deltaTimea = 1.0 - (time - this->mLastTime) / deltaTime;
|
||||
v5 = this->mCurrentOrigin.x - this->mLastOrigin.x;
|
||||
v6 = this->mCurrentOrigin.y - this->mLastOrigin.y;
|
||||
v7 = this->mCurrentOrigin.z - this->mLastOrigin.z;
|
||||
v8 = v5 * deltaTimea;
|
||||
v9 = v6 * deltaTimea;
|
||||
v10 = deltaTimea * v7;
|
||||
result.x = v8;
|
||||
result.y = v9;
|
||||
result.z = v10;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void rvBSE::SetDuration(float time)
|
||||
{
|
||||
double v2; // st7
|
||||
|
||||
v2 = time;
|
||||
if (time < 0.0)
|
||||
{
|
||||
v2 = this->mDeclEffect->mMinDuration;
|
||||
LABEL_3:
|
||||
this->mDuration = v2;
|
||||
return;
|
||||
}
|
||||
if (this->mDuration < v2)
|
||||
goto LABEL_3;
|
||||
}
|
||||
|
||||
const char* rvBSE::GetDeclName()
|
||||
{
|
||||
return mDeclEffect->base->GetName();
|
||||
}
|
||||
|
||||
void rvBSE::UpdateAttenuation()
|
||||
{
|
||||
if ((this->mDeclEffect->mFlags & ETFLAG_ATTENUATES) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
idVec3 viewOrigin;
|
||||
idMat3 viewAxis;
|
||||
game->GetPlayerView(viewOrigin, viewAxis);
|
||||
|
||||
const float originDistance = (mCurrentOrigin - viewOrigin).LengthFast();
|
||||
mOriginDistanceToCamera = idMath::ClampFloat(1.0f, 131072.0f, originDistance);
|
||||
|
||||
// Match vanilla BSE attenuation space conversion (uses current axis here).
|
||||
const idVec3 localView = mCurrentAxis * (viewOrigin - mCurrentOrigin);
|
||||
const float shortest = mCurrentLocalBounds.ShortestDistance(localView);
|
||||
mShortestDistanceToCamera = idMath::ClampFloat(1.0f, 131072.0f, shortest);
|
||||
}
|
||||
|
||||
void rvBSE::LoopInstant(float time)
|
||||
{
|
||||
rvBSE* v2; // esi
|
||||
int v3; // edi
|
||||
bool v4; // zf
|
||||
bool v5; // sf
|
||||
int v6; // ebx
|
||||
double v7; // st7
|
||||
|
||||
v2 = this;
|
||||
if (0.0 == this->mDuration)
|
||||
{
|
||||
v3 = 0;
|
||||
v4 = this->mSegments.Num() == 0;
|
||||
v5 = this->mSegments.Num() < 0;
|
||||
this->mStartTime = this->mDeclEffect->mMaxDuration + 0.5 + this->mStartTime;
|
||||
if (!v5 && !v4)
|
||||
{
|
||||
v6 = 0;
|
||||
do
|
||||
{
|
||||
v2->mSegments[v6].ResetTime(v2, v2->mStartTime);
|
||||
++v3;
|
||||
++v6;
|
||||
} while (v3 < v2->mSegments.Num());
|
||||
}
|
||||
if (bse_debug.GetInteger() == 2)
|
||||
{
|
||||
v7 = v2->mDeclEffect->mMaxDuration + 0.5;
|
||||
common->Printf("BSE: Looping duration %g\n", v7);
|
||||
}
|
||||
++v2->mDeclEffect->mLoopCount;
|
||||
}
|
||||
}
|
||||
|
||||
void rvBSE::LoopLooping(float time)
|
||||
{
|
||||
int v3; // edi
|
||||
bool v4; // cc
|
||||
int v5; // ebx
|
||||
|
||||
if (0.0 != this->mDuration)
|
||||
{
|
||||
v3 = 0;
|
||||
v4 = this->mSegments.Num() <= 0;
|
||||
this->mStartTime = this->mStartTime + this->mDuration;
|
||||
this->mDuration = 0.0;
|
||||
if (!v4)
|
||||
{
|
||||
v5 = 0;
|
||||
do
|
||||
{
|
||||
mSegments[v5].ResetTime(this, this->mStartTime);
|
||||
++v3;
|
||||
++v5;
|
||||
} while (v3 < this->mSegments.Num());
|
||||
}
|
||||
if (bse_debug.GetInteger() == 2) {
|
||||
common->Printf("BSE: Looping duration: %g", this->mDuration);
|
||||
}
|
||||
|
||||
++this->mDeclEffect->mLoopCount;
|
||||
}
|
||||
}
|
||||
bool rvBSE::Service(renderEffect_t* parms, float time, bool spawn, bool& forcePush)
|
||||
{
|
||||
renderEffect_s* v5; // ebp
|
||||
int v7; // edi
|
||||
int v8; // ebx
|
||||
int v9; // edi
|
||||
char v10; // bl
|
||||
int v11; // ebp
|
||||
bool v12; // zf
|
||||
float spawna; // [esp+24h] [ebp+Ch]
|
||||
float spawnb; // [esp+24h] [ebp+Ch]
|
||||
float spawnc; // [esp+24h] [ebp+Ch]
|
||||
float spawnd; // [esp+24h] [ebp+Ch]
|
||||
|
||||
v5 = parms;
|
||||
UpdateFromOwner(parms, time, 0);
|
||||
UpdateAttenuation();
|
||||
if (spawn)
|
||||
{
|
||||
v7 = 0;
|
||||
if (this->mSegments.Num() > 0)
|
||||
{
|
||||
v8 = 0;
|
||||
do
|
||||
{
|
||||
spawna = 0.0f;
|
||||
mSegments[v8].Check(this, time, spawna);
|
||||
++v7;
|
||||
++v8;
|
||||
} while (v7 < this->mSegments.Num());
|
||||
}
|
||||
}
|
||||
if ((this->mFlags & 8) == 0 && parms->loop)
|
||||
{
|
||||
spawnb = this->mDuration + this->mStartTime;
|
||||
if (spawnb < (double)time)
|
||||
LoopLooping(time);
|
||||
}
|
||||
v9 = 0;
|
||||
v10 = 0;
|
||||
if (this->mSegments.Num() > 0)
|
||||
{
|
||||
v11 = 0;
|
||||
do
|
||||
{
|
||||
if (mSegments[v11].UpdateParticles(this, time))
|
||||
v10 = 1;
|
||||
++v9;
|
||||
++v11;
|
||||
} while (v9 < this->mSegments.Num());
|
||||
v5 = parms;
|
||||
}
|
||||
this->mFlags &= 0xFFFFFFFB;
|
||||
forcePush = this->mForcePush;
|
||||
v12 = (this->mFlags & 8) == 0;
|
||||
this->mForcePush = 0;
|
||||
if (!v12)
|
||||
return v10 == 0;
|
||||
if (v5->loop)
|
||||
{
|
||||
spawnc = this->mDuration + this->mStartTime;
|
||||
if (spawnc < (double)time)
|
||||
LoopInstant(time);
|
||||
if (v5->loop)
|
||||
return 0;
|
||||
}
|
||||
spawnd = this->mDuration + this->mStartTime;
|
||||
return spawnd < (double)time;
|
||||
}
|
||||
|
||||
float rvBSE::EvaluateCost(int segment)
|
||||
{
|
||||
double result; // st7
|
||||
int v4; // edi
|
||||
int v5; // ebx
|
||||
double v6; // st7
|
||||
|
||||
if (segment < 0)
|
||||
{
|
||||
v4 = 0;
|
||||
this->mCost = 0.0;
|
||||
if (this->mSegments.Num() > 0)
|
||||
{
|
||||
v5 = 0;
|
||||
do
|
||||
{
|
||||
v6 = mDeclEffect->EvaluateCost(
|
||||
this->mSegments[v5].mActiveCount,
|
||||
segment);
|
||||
++v4;
|
||||
++v5;
|
||||
this->mCost = v6 + this->mCost;
|
||||
} while (v4 < this->mSegments.Num());
|
||||
}
|
||||
result = this->mCost;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->mCost = mDeclEffect->EvaluateCost(
|
||||
this->mSegments[segment].mActiveCount,
|
||||
segment);
|
||||
result = this->mCost;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void rvBSE::InitModel(idRenderModel* model)
|
||||
{
|
||||
int v3; // edi
|
||||
int v4; // ebx
|
||||
|
||||
v3 = 0;
|
||||
if (this->mSegments.Num() > 0)
|
||||
{
|
||||
v4 = 0;
|
||||
do
|
||||
{
|
||||
mSegments[v4].AllocateSurface(this, model);
|
||||
++v3;
|
||||
++v4;
|
||||
} while (v3 < this->mSegments.Num());
|
||||
}
|
||||
}
|
||||
|
||||
idRenderModel* rvBSE::Render(idRenderModel* model, const struct renderEffect_s* owner, const struct viewDef_s* view)
|
||||
{
|
||||
if (!bse_render.GetInteger() || !owner || !view) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idRenderModelStatic* renderModel = dynamic_cast<idRenderModelStatic*>(model);
|
||||
if (model && !renderModel) {
|
||||
renderModelManager->FreeModel(model);
|
||||
model = NULL;
|
||||
}
|
||||
|
||||
if (!renderModel) {
|
||||
model = renderModelManager->AllocModel();
|
||||
renderModel = dynamic_cast<idRenderModelStatic*>(model);
|
||||
if (!renderModel) {
|
||||
if (model) {
|
||||
renderModelManager->FreeModel(model);
|
||||
}
|
||||
common->Warning("^4BSE:^1 Unable to allocate runtime model for effect '%s'", mDeclEffect ? mDeclEffect->GetName() : "<unknown>");
|
||||
return NULL;
|
||||
}
|
||||
renderModel->InitEmpty("_bse_runtime");
|
||||
InitModel(renderModel);
|
||||
}
|
||||
else {
|
||||
// Runtime particles mutate vertex/index data every frame.
|
||||
// Invalidate vertex/index caches so new data is uploaded.
|
||||
renderModel->FreeVertexCache();
|
||||
for (int i = 0; i < renderModel->NumSurfaces(); ++i) {
|
||||
const modelSurface_t* surf = renderModel->Surface(i);
|
||||
if (!surf || !surf->geometry) {
|
||||
continue;
|
||||
}
|
||||
srfTriangles_t* tri = surf->geometry;
|
||||
if (tri->indexCache) {
|
||||
tri->indexCache = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mViewAxis = view->renderView.viewaxis;
|
||||
mViewOrg = view->renderView.vieworg;
|
||||
|
||||
float time = view->floatTime;
|
||||
for (int i = 0; i < mSegments.Num(); ++i) {
|
||||
const bool active = mSegments[i].Active();
|
||||
|
||||
mSegments[i].ClearSurface(this, renderModel);
|
||||
if (active) {
|
||||
mSegments[i].Render(this, owner, renderModel, time);
|
||||
mSegments[i].RenderTrail(this, owner, renderModel, time);
|
||||
}
|
||||
}
|
||||
|
||||
// BSE runtime geometry is rebuilt every frame and includes strip-like particle
|
||||
// topology that can intentionally share points. Avoid full static-surface cleanup
|
||||
// here and only update per-surface/model bounds for culling.
|
||||
idBounds modelBounds;
|
||||
modelBounds.Clear();
|
||||
bool hasBounds = false;
|
||||
for (int i = 0; i < renderModel->NumSurfaces(); ++i) {
|
||||
const modelSurface_t* surf = renderModel->Surface(i);
|
||||
if (!surf || !surf->geometry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
srfTriangles_t* tri = surf->geometry;
|
||||
if (tri->numVerts <= 0 || tri->numIndexes <= 0) {
|
||||
tri->bounds.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
BSE_BoundTriSurf(tri);
|
||||
if (!hasBounds) {
|
||||
modelBounds = tri->bounds;
|
||||
hasBounds = true;
|
||||
}
|
||||
else {
|
||||
modelBounds.AddBounds(tri->bounds);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasBounds) {
|
||||
modelBounds.Zero();
|
||||
}
|
||||
renderModel->bounds = modelBounds;
|
||||
DisplayDebugInfo(owner, view, renderModel->bounds);
|
||||
mLastRenderBounds = modelBounds;
|
||||
mGrownRenderBounds = mLastRenderBounds;
|
||||
mGrownRenderBounds.ExpandSelf(20.0f);
|
||||
mForcePush = true;
|
||||
return renderModel;
|
||||
}
|
||||
|
||||
void rvBSE::Destroy()
|
||||
{
|
||||
mSegments.Clear();
|
||||
mReferenceSound = NULL;
|
||||
}
|
||||
|
||||
|
||||
void rvBSE::UpdateSegments(float time)
|
||||
{
|
||||
int v3; // ebx
|
||||
rvSegment* v4; // eax
|
||||
rvParticle** v5; // esi
|
||||
bool v6; // cc
|
||||
int v7; // ecx
|
||||
int* v8; // eax
|
||||
rvSegment* v9; // esi
|
||||
rvSegment* v10; // ecx
|
||||
int v11; // edx
|
||||
int v12; // eax
|
||||
rvParticle** v13; // esi
|
||||
int v14; // esi
|
||||
int v15; // edi
|
||||
int v16; // esi
|
||||
int v17; // edi
|
||||
int v18; // esi
|
||||
int v19; // edi
|
||||
rvSegment* ptr; // [esp+14h] [ebp-14h]
|
||||
|
||||
v3 = this->mDeclEffect->mSegmentTemplates.Num();
|
||||
if (v3 > 0)
|
||||
{
|
||||
if (v3 != this->mSegments.Size())
|
||||
{
|
||||
mSegments.SetNum(v3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mSegments.Clear();
|
||||
}
|
||||
v14 = 0;
|
||||
//this->mSegments.num = v3; // Not sure why this gets set twice? compiler optimization gone wrong?
|
||||
if (v3 > 0)
|
||||
{
|
||||
v15 = 0;
|
||||
do
|
||||
mSegments[v15++].Init(this, this->mDeclEffect, v14++, time);
|
||||
while (v14 < this->mSegments.Num());
|
||||
}
|
||||
v16 = 0;
|
||||
if (this->mSegments.Num() > 0)
|
||||
{
|
||||
v17 = 0;
|
||||
do
|
||||
{
|
||||
mSegments[v17].CalcCounts(this, time);
|
||||
++v16;
|
||||
++v17;
|
||||
} while (v16 < this->mSegments.Num());
|
||||
}
|
||||
v18 = 0;
|
||||
if (this->mSegments.Num() > 0)
|
||||
{
|
||||
v19 = 0;
|
||||
do
|
||||
{
|
||||
|
||||
mSegments[v19].InitParticles(this);
|
||||
++v18;
|
||||
++v19;
|
||||
} while (v18 < this->mSegments.Num());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rvBSE::DisplayDebugInfo(const struct renderEffect_s* parms, const struct viewDef_s* view, idBounds& bounds) {
|
||||
if (!parms || !view || !view->renderWorld) {
|
||||
return;
|
||||
}
|
||||
const int debugLevel = bse_debug.GetInteger();
|
||||
if (!debugLevel && !bse_showBounds.GetBool()) {
|
||||
return;
|
||||
}
|
||||
|
||||
idRenderWorld* rw = view->renderWorld;
|
||||
|
||||
// Keep level-1 debug useful for logging without polluting gameplay visuals.
|
||||
// Level 2 enables heavy on-screen BSE overlays.
|
||||
if (debugLevel >= 2) {
|
||||
const char* effectName = "<unknown>";
|
||||
if (mDeclEffect && mDeclEffect->base) {
|
||||
effectName = mDeclEffect->base->GetName();
|
||||
}
|
||||
|
||||
idStr txt = va(
|
||||
"(%g) (size %g) (bri %g)\n%s",
|
||||
mCost,
|
||||
mDeclEffect ? mDeclEffect->mSize : 0.0f,
|
||||
parms->shaderParms[6],
|
||||
effectName);
|
||||
|
||||
rw->DebugAxis(parms->origin, parms->axis);
|
||||
rw->DrawText(txt.c_str(), parms->origin, 14.0f, colorCyan, view->renderView.viewaxis, 1, 0);
|
||||
}
|
||||
|
||||
if (!bse_showBounds.GetBool()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rw->DebugBounds(colorGreen, bounds, vec3_origin);
|
||||
|
||||
const idBox worldBox(mCurrentWorldBounds, parms->origin, parms->axis);
|
||||
rw->DebugBox(colorBlue, worldBox);
|
||||
|
||||
if (!mCurrentWorldBounds.Contains(bounds)) {
|
||||
rw->DebugBounds(colorRed, bounds, vec3_origin);
|
||||
}
|
||||
}
|
||||
|
||||
void rvBSE::UpdateFromOwner(renderEffect_s* parms, float time, bool init)
|
||||
{
|
||||
mLastTime = mCurrentTime;
|
||||
mLastOrigin = mCurrentOrigin;
|
||||
|
||||
mCurrentTime = time;
|
||||
mCurrentOrigin = parms->origin;
|
||||
mCurrentAxis = parms->axis;
|
||||
mCurrentAxisTransposed = mCurrentAxis.Transpose();
|
||||
|
||||
const float dt = mCurrentTime - mLastTime;
|
||||
if (dt > 0.002f) {
|
||||
mCurrentVelocity = (mCurrentOrigin - mLastOrigin) * (1.0f / dt);
|
||||
}
|
||||
// Vanilla keeps the last valid owner velocity when multiple updates land
|
||||
// on the same timestamp; avoid zeroing in that case.
|
||||
|
||||
mGravity = parms->gravity;
|
||||
mGravityDir = mGravity;
|
||||
const float gravityLengthSqr = mGravityDir.LengthSqr();
|
||||
if (gravityLengthSqr > 0.0f) {
|
||||
mGravityDir *= idMath::InvSqrt(gravityLengthSqr);
|
||||
}
|
||||
|
||||
SetLooping(parms->loop);
|
||||
SetHasEndOrigin(parms->hasEndOrigin);
|
||||
SetOrientateIdentity((mDeclEffect->mFlags & ETFLAG_ORIENTATE_IDENTITY) != 0);
|
||||
SetFlag(parms->ambient, EFLAG_AMBIENT);
|
||||
|
||||
const idVec3 halfSize(mDeclEffect->mSize, mDeclEffect->mSize, mDeclEffect->mSize);
|
||||
|
||||
mCurrentWorldBounds.AddPoint(mCurrentOrigin + halfSize);
|
||||
mCurrentWorldBounds.AddPoint(mCurrentOrigin - halfSize);
|
||||
|
||||
if (parms->hasEndOrigin && (mDeclEffect->mFlags & ETFLAG_USES_ENDORIGIN) != 0) {
|
||||
const bool endOriginChanged = init || parms->endOrigin != mCurrentEndOrigin || mCurrentOrigin != mLastOrigin;
|
||||
mCurrentEndOrigin = parms->endOrigin;
|
||||
mCurrentWorldBounds.AddPoint(mCurrentEndOrigin + halfSize);
|
||||
mCurrentWorldBounds.AddPoint(mCurrentEndOrigin - halfSize);
|
||||
SetEndOriginChanged(endOriginChanged);
|
||||
}
|
||||
else {
|
||||
mCurrentEndOrigin = parms->endOrigin;
|
||||
SetEndOriginChanged(false);
|
||||
}
|
||||
|
||||
mCurrentLocalBounds.Clear();
|
||||
for (int ix = 0; ix < 2; ++ix) {
|
||||
for (int iy = 0; iy < 2; ++iy) {
|
||||
for (int iz = 0; iz < 2; ++iz) {
|
||||
const idVec3 corner(
|
||||
mCurrentWorldBounds[ix].x,
|
||||
mCurrentWorldBounds[iy].y,
|
||||
mCurrentWorldBounds[iz].z);
|
||||
const idVec3 local = mCurrentAxisTransposed * (corner - mCurrentOrigin);
|
||||
mCurrentLocalBounds.AddPoint(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLightningAxis = mCurrentAxis;
|
||||
if (GetHasEndOrigin()) {
|
||||
idVec3 forward = mCurrentEndOrigin - mCurrentOrigin;
|
||||
if (forward.Normalize() > BSE_TIME_EPSILON) {
|
||||
idVec3 up = mCurrentAxis[2];
|
||||
if (idMath::Fabs(forward * up) > 0.98f) {
|
||||
up = mCurrentAxis[1];
|
||||
}
|
||||
|
||||
idVec3 right = up.Cross(forward);
|
||||
if (right.Normalize() > BSE_TIME_EPSILON) {
|
||||
up = forward.Cross(right);
|
||||
up.Normalize();
|
||||
mLightningAxis[0] = forward;
|
||||
mLightningAxis[1] = right;
|
||||
mLightningAxis[2] = up;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentWindVector.Zero();
|
||||
memcpy( mShaderParms, parms->shaderParms, sizeof( mShaderParms ) );
|
||||
mTint.Set(parms->shaderParms[0], parms->shaderParms[1], parms->shaderParms[2], parms->shaderParms[3]);
|
||||
mBrightness = parms->shaderParms[6];
|
||||
mSpriteSize.x = parms->shaderParms[8];
|
||||
mSpriteSize.y = parms->shaderParms[9];
|
||||
mAttenuation = parms->attenuation;
|
||||
mSuppressLightsInViewID = parms->suppressSurfaceInViewID;
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
// BSE_EffectTemplate.cpp
|
||||
//
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE.h"
|
||||
#include "BSE_SpawnDomains.h"
|
||||
|
||||
namespace {
|
||||
int BSE_ParseSegmentType(const idToken& token) {
|
||||
if (token == "effect") {
|
||||
return SEG_EFFECT;
|
||||
}
|
||||
if (token == "emitter") {
|
||||
return SEG_EMITTER;
|
||||
}
|
||||
if (token == "spawner") {
|
||||
return SEG_SPAWNER;
|
||||
}
|
||||
if (token == "trail") {
|
||||
return SEG_TRAIL;
|
||||
}
|
||||
if (token == "sound") {
|
||||
return SEG_SOUND;
|
||||
}
|
||||
if (token == "decal") {
|
||||
return SEG_DECAL;
|
||||
}
|
||||
if (token == "light") {
|
||||
return SEG_LIGHT;
|
||||
}
|
||||
if (token == "delay") {
|
||||
return SEG_DELAY;
|
||||
}
|
||||
if (token == "shake") {
|
||||
return SEG_SHAKE;
|
||||
}
|
||||
if (token == "tunnel") {
|
||||
return SEG_TUNNEL;
|
||||
}
|
||||
if (token == "doubleVision" || token == "doublevision") {
|
||||
return SEG_DOUBLEVISION;
|
||||
}
|
||||
return SEG_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void rvDeclEffect::Init()
|
||||
{
|
||||
mMinDuration = 0.0;
|
||||
mMaxDuration = 0.0;
|
||||
mSize = 512.0;
|
||||
mFlags = 0;
|
||||
mPlayCount = 0;
|
||||
mLoopCount = 0;
|
||||
mCutOffDistance = 0.0;
|
||||
mSegmentTemplates.Clear();
|
||||
}
|
||||
|
||||
bool rvDeclEffect::SetDefaultText()
|
||||
{
|
||||
char generated[1024]; // [esp+4h] [ebp-404h]
|
||||
|
||||
idStr::snPrintf(generated, sizeof(generated), "effect %s // IMPLICITLY GENERATED\n%s", GetName(), DefaultDefinition());
|
||||
SetText(generated);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t rvDeclEffect::Size(void) const {
|
||||
return sizeof(rvDeclEffect);
|
||||
}
|
||||
|
||||
int rvDeclEffect::GetTrailSegmentIndex(const idStr& name)
|
||||
{
|
||||
rvDeclEffect* v2; // esi
|
||||
int v3; // edi
|
||||
int v4; // ebx
|
||||
rvSegmentTemplate* v5; // eax
|
||||
int result; // eax
|
||||
|
||||
v2 = this;
|
||||
v3 = 0;
|
||||
if (mSegmentTemplates.Num() <= 0)
|
||||
{
|
||||
LABEL_6:
|
||||
common->Warning("^4BSE:^1 Unable to find segment '%s'\n", name.c_str());
|
||||
result = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
v4 = 0;
|
||||
while (1)
|
||||
{
|
||||
v5 = &this->mSegmentTemplates[v4];
|
||||
if (v5)
|
||||
{
|
||||
if (name == v5->GetSegmentName())
|
||||
break;
|
||||
}
|
||||
++v3;
|
||||
++v4;
|
||||
if (v3 >= this->mSegmentTemplates.Num())
|
||||
goto LABEL_6;
|
||||
}
|
||||
result = v3;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rvDeclEffect::Compare(const rvDeclEffect& comp) const
|
||||
{
|
||||
if (mSegmentTemplates.Num() != comp.mSegmentTemplates.Num()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mSegmentTemplates.Num(); ++i) {
|
||||
if (!(mSegmentTemplates[i] == comp.mSegmentTemplates[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float rvDeclEffect::CalculateBounds(void)
|
||||
{
|
||||
float size = 0.0f;
|
||||
for (int i = 0; i < mSegmentTemplates.Num(); ++i) {
|
||||
const float segmentSize = mSegmentTemplates[i].CalculateBounds();
|
||||
if (segmentSize > size) {
|
||||
size = segmentSize;
|
||||
}
|
||||
}
|
||||
return idMath::Ceil(size);
|
||||
}
|
||||
|
||||
float rvDeclEffect::EvaluateCost(int activeParticles, int segment) const
|
||||
{
|
||||
int v5; // edi
|
||||
int v6; // ebx
|
||||
double v7; // st7
|
||||
float cost; // [esp+Ch] [ebp+8h]
|
||||
|
||||
if (segment != -1)
|
||||
return mSegmentTemplates[segment].EvaluateCost(activeParticles);
|
||||
v5 = 0;
|
||||
cost = 0.0;
|
||||
if (this->mSegmentTemplates.Num() > 0)
|
||||
{
|
||||
v6 = 0;
|
||||
do
|
||||
{
|
||||
v7 = mSegmentTemplates[v6].EvaluateCost(activeParticles);
|
||||
++v5;
|
||||
++v6;
|
||||
cost = v7 + cost;
|
||||
} while (v5 < this->mSegmentTemplates.Num());
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
void rvDeclEffect::FreeData()
|
||||
{
|
||||
int v2; // ebx
|
||||
int v3; // edi
|
||||
rvSegmentTemplate* v4; // eax
|
||||
int* v5; // edi
|
||||
|
||||
v2 = 0;
|
||||
if (this->mSegmentTemplates.Num() > 0)
|
||||
{
|
||||
v3 = 0;
|
||||
do
|
||||
{
|
||||
mSegmentTemplates[v3].GetParticleTemplate()->Purge();
|
||||
mSegmentTemplates[v3].GetParticleTemplate()->PurgeTraceModel();
|
||||
++v2;
|
||||
++v3;
|
||||
} while (v2 < this->mSegmentTemplates.Num());
|
||||
}
|
||||
mSegmentTemplates.Clear();
|
||||
}
|
||||
|
||||
const char* rvDeclEffect::DefaultDefinition() const
|
||||
{
|
||||
return "{\n}\n";
|
||||
}
|
||||
|
||||
void rvDeclEffect::SetMinDuration(float duration)
|
||||
{
|
||||
if (this->mMinDuration < duration)
|
||||
this->mMinDuration = duration;
|
||||
}
|
||||
|
||||
void rvDeclEffect::SetMaxDuration(float duration)
|
||||
{
|
||||
if (this->mMaxDuration < duration)
|
||||
this->mMaxDuration = duration;
|
||||
}
|
||||
|
||||
void rvDeclEffect::Finish() {
|
||||
rvSegmentTemplate* segment;
|
||||
const int preservedFlags = mFlags & ETFLAG_EDITOR_MODIFIED;
|
||||
mFlags = preservedFlags;
|
||||
|
||||
for (int j = 0; j < mSegmentTemplates.Num(); j++)
|
||||
{
|
||||
segment = &mSegmentTemplates[j];
|
||||
if (segment)
|
||||
{
|
||||
segment->Finish(this);
|
||||
|
||||
if (segment->GetType() == SEG_SOUND)
|
||||
mFlags |= ETFLAG_HAS_SOUND;
|
||||
|
||||
if (segment->GetParticleTemplate()->UsesEndOrigin())
|
||||
mFlags |= ETFLAG_USES_ENDORIGIN;
|
||||
|
||||
if (segment->GetParticleTemplate()->GetHasPhysics() || segment->GetHasPhysics())
|
||||
mFlags |= ETFLAG_HAS_PHYSICS;
|
||||
if (segment->GetAttenuateEmitter())
|
||||
mFlags |= ETFLAG_ATTENUATES;
|
||||
if (segment->GetUseMaterialColor())
|
||||
mFlags |= ETFLAG_USES_MATERIAL_COLOR;
|
||||
if (segment->GetOrientateIdentity())
|
||||
mFlags |= ETFLAG_ORIENTATE_IDENTITY;
|
||||
|
||||
segment->EvaluateTrailSegment(this);
|
||||
segment->SetMinDuration(this);
|
||||
segment->SetMaxDuration(this);
|
||||
}
|
||||
}
|
||||
|
||||
mSize = CalculateBounds();
|
||||
}
|
||||
|
||||
bool rvDeclEffect::Parse(const char* text, const int textLength) {
|
||||
idParser src;
|
||||
idToken token;
|
||||
|
||||
FreeData();
|
||||
mFlags = 0;
|
||||
mMinDuration = 0.0f;
|
||||
mMaxDuration = 0.0f;
|
||||
mCutOffDistance = 0.0f;
|
||||
mSize = 512.0f;
|
||||
|
||||
src.LoadMemory(text, textLength, GetFileName());
|
||||
src.SetFlags(DECL_LEXER_FLAGS);
|
||||
if (!src.SkipUntilString("{")) {
|
||||
src.Warning("^4BSE:^1 Expected '{' in effect '%s'", GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (src.ReadToken(&token))
|
||||
{
|
||||
while (token != "}")
|
||||
{
|
||||
const int segmentType = BSE_ParseSegmentType(token);
|
||||
if (segmentType != SEG_NONE) {
|
||||
rvSegmentTemplate segment;
|
||||
segment.Init(this);
|
||||
segment.Parse(this, segmentType, &src);
|
||||
if (segment.Finish(this)) {
|
||||
mSegmentTemplates.Append(segment);
|
||||
}
|
||||
}
|
||||
else if (token == "cutOffDistance") {
|
||||
mCutOffDistance = src.ParseFloat();
|
||||
}
|
||||
else if (token == "size")
|
||||
{
|
||||
mSize = src.ParseFloat();
|
||||
}
|
||||
else
|
||||
{
|
||||
src.Warning("^4BSE:^1 Invalid segment type '%s' (file: %s, line: %d)\n", token.c_str(), GetFileName(), src.GetLineNum());
|
||||
if (src.CheckTokenString("{")) {
|
||||
src.SkipBracedSection(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!src.ReadToken(&token)) {
|
||||
src.Warning("^4BSE:^1 Unexpected end of effect '%s'", GetName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Finish();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
// Copyright (C) 2007 Id Software, Inc.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _BSE_ENVELOPE_H_INC_
|
||||
#define _BSE_ENVELOPE_H_INC_
|
||||
|
||||
extern const char sdPoolAllocator_rvEnvParms[];
|
||||
class rvEnvParms //: public sdPoolAllocator< rvEnvParms, sdPoolAllocator_rvEnvParms, 128 >
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms1;
|
||||
friend class rvEnvParms2;
|
||||
friend class rvEnvParms3;
|
||||
|
||||
rvEnvParms( void ) : mStatic(0), mFastLookUp(0) {}
|
||||
rvEnvParms( const rvEnvParms © ) { *this = copy; }
|
||||
~rvEnvParms( void ) {}
|
||||
|
||||
void SetDefaultType( void );
|
||||
// void SetType( const char *type ) { mTable = declHolder.declTableType.LocalFind( type ); }
|
||||
void SetType( const idDeclTable *tabl ) { mTable = tabl; }
|
||||
|
||||
idVec3 &GetOffsetRef( void ) { return( mEnvOffset ); }
|
||||
const idVec3 &GetOffsetRef( void ) const { return( mEnvOffset ); }
|
||||
idVec3 &GetRateRef( void ) { return( mRate ); }
|
||||
const idVec3 &GetRateRef( void ) const { return( mRate ); }
|
||||
const idDeclTable *GetType( void ) const { return mTable; }
|
||||
void SetIsCount( bool isCount ) { mIsCount = isCount; }
|
||||
|
||||
bool GetIsCount( void ) const { return( mIsCount != 0 ); }
|
||||
void CalcRate( float *rate, float duration, int count );
|
||||
|
||||
void Init( void );
|
||||
bool GetMinMax( float &min, float &max );
|
||||
|
||||
void Evaluate3( const float time, const float *start, const float *rate, const float *end, float *dest );
|
||||
void Evaluate( class rvEnvParms1Particle &env, float time, float oneOverDuration, float *v );
|
||||
void Evaluate( class rvEnvParms2Particle &env, float time, float oneOverDuration, float *v );
|
||||
void Evaluate( class rvEnvParms3Particle &env, float time, float oneOverDuration, float *v );
|
||||
|
||||
void operator= ( const rvEnvParms © );
|
||||
bool operator== ( const rvEnvParms &comp ) const { return( Compare( comp ) ); }
|
||||
bool operator!= ( const rvEnvParms &comp ) const { return( !Compare( comp ) ); }
|
||||
|
||||
void Finalize( void );
|
||||
void ClearFast( void ) { mFastLookUp = false; }
|
||||
|
||||
public:
|
||||
bool Compare( const rvEnvParms &comp ) const;
|
||||
|
||||
const idDeclTable *mTable;
|
||||
short mIsCount;
|
||||
public:
|
||||
byte mStatic;
|
||||
byte mFastLookUp;
|
||||
//private:
|
||||
idVec3 mEnvOffset;
|
||||
idVec3 mRate;
|
||||
};
|
||||
|
||||
class rvEnvParms1
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms;
|
||||
|
||||
rvEnvParms1( void ) {}
|
||||
~rvEnvParms1( void ) {}
|
||||
|
||||
void Init( const rvEnvParms & copy, float duration );
|
||||
void Evaluate( const float time, float *dest );
|
||||
|
||||
float *GetStart( void ) { return( &mStart ); }
|
||||
float *GetEnd( void ) { return( &mEnd ); }
|
||||
|
||||
void Scale( const float constant ) { mStart *= constant; mEnd *= constant; }
|
||||
void Transform( const idVec3 normal ) {}
|
||||
void Rotate( const rvAngles &angles );
|
||||
private:
|
||||
const idDeclTable *mTable;
|
||||
float mEnvOffset;
|
||||
|
||||
float mStart;
|
||||
float mRate;
|
||||
float mEnd;
|
||||
};
|
||||
|
||||
class rvEnvParms2
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms;
|
||||
|
||||
rvEnvParms2( void ) {}
|
||||
~rvEnvParms2( void ) {}
|
||||
|
||||
void Init( const rvEnvParms & copy, float duration );
|
||||
void Evaluate( const float time, float *dest );
|
||||
|
||||
float *GetStart( void ) { return( mStart.ToFloatPtr() ); }
|
||||
float *GetEnd( void ) { return( mEnd.ToFloatPtr() ); }
|
||||
|
||||
void Scale( const float constant ) { mStart *= constant; mEnd *= constant; }
|
||||
void Transform( const idVec3 normal ) {}
|
||||
void Rotate( const rvAngles &angles );
|
||||
private:
|
||||
const idDeclTable *mTable;
|
||||
idVec2 mEnvOffset;
|
||||
|
||||
bool mFastLookup;
|
||||
idVec2 mStart;
|
||||
idVec2 mRate;
|
||||
idVec2 mEnd;
|
||||
};
|
||||
|
||||
class rvEnvParms3
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms;
|
||||
|
||||
rvEnvParms3( void ) {}
|
||||
~rvEnvParms3( void ) {}
|
||||
|
||||
void Init( const rvEnvParms & copy, float duration );
|
||||
void Evaluate( const float time, float *dest );
|
||||
|
||||
float *GetStart( void ) { return( mStart.ToFloatPtr() ); }
|
||||
float *GetEnd( void ) { return( mEnd.ToFloatPtr() ); }
|
||||
|
||||
void Scale( const float constant ) { mStart *= constant; mEnd *= constant; }
|
||||
void Transform( const idVec3 normal ) { mStart *= normal.ToMat3(); mEnd *= normal.ToMat3(); }
|
||||
void Rotate( const rvAngles &angles );
|
||||
private:
|
||||
const idDeclTable *mTable;
|
||||
idVec3 mEnvOffset;
|
||||
|
||||
bool mFastLookup;
|
||||
idVec3 mStart;
|
||||
idVec3 mRate;
|
||||
idVec3 mEnd;
|
||||
};
|
||||
|
||||
class rvEnvParms1Particle
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms;
|
||||
friend class rvParticle;
|
||||
|
||||
rvEnvParms1Particle( void ) {}
|
||||
~rvEnvParms1Particle( void ) {}
|
||||
|
||||
void Init( const rvEnvParms & copy, float duration );
|
||||
void Evaluate( const rvEnvParms & params, const float time, float oneOverDuration, float *dest );
|
||||
|
||||
float *GetStart( void ) { return( &mStart ); }
|
||||
float *GetEnd( void ) { return( &mEnd ); }
|
||||
|
||||
void Scale( const float constant ) { mStart *= constant; mEnd *= constant; }
|
||||
void Transform( const idVec3 normal ) {}
|
||||
void Rotate( const rvAngles &angles );
|
||||
private:
|
||||
float mStart;
|
||||
float mEnd;
|
||||
};
|
||||
|
||||
class rvEnvParms2Particle
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms;
|
||||
friend class rvParticle;
|
||||
|
||||
rvEnvParms2Particle( void ) {}
|
||||
~rvEnvParms2Particle( void ) {}
|
||||
|
||||
void Init( const rvEnvParms & copy, float duration );
|
||||
void Evaluate( const rvEnvParms & params, const float time, float oneOverDuration, float *dest );
|
||||
|
||||
float *GetStart( void ) { return( mStart.ToFloatPtr() ); }
|
||||
float *GetEnd( void ) { return( mEnd.ToFloatPtr() ); }
|
||||
|
||||
void Scale( const float constant ) { mStart *= constant; mEnd *= constant; }
|
||||
void Transform( const idVec3 normal ) {}
|
||||
void Rotate( const rvAngles &angles );
|
||||
private:
|
||||
idVec2 mStart;
|
||||
idVec2 mEnd;
|
||||
};
|
||||
|
||||
class rvEnvParms3Particle
|
||||
{
|
||||
public:
|
||||
friend class rvEnvParms;
|
||||
friend class rvParticle;
|
||||
friend class rvDebrisParticle;
|
||||
friend class rvLineParticle;
|
||||
friend class rvElectricityParticle;
|
||||
|
||||
rvEnvParms3Particle( void ) {}
|
||||
~rvEnvParms3Particle( void ) {}
|
||||
|
||||
void Init( const rvEnvParms & copy, float duration );
|
||||
void Evaluate( const rvEnvParms & params, const float time, float oneOverDuration, float *dest );
|
||||
|
||||
float *GetStart( void ) { return( mStart.ToFloatPtr() ); }
|
||||
float *GetEnd( void ) { return( mEnd.ToFloatPtr() ); }
|
||||
|
||||
void Scale( const float constant ) { mStart *= constant; mEnd *= constant; }
|
||||
void Transform( const idMat3 &m ) { mStart *= m; mEnd *= m; }
|
||||
void Transform( const idVec3 normal ) { idMat3 const m = normal.ToMat3(); mStart *= m; mEnd *= m; }
|
||||
void Rotate( const rvAngles &angles );
|
||||
private:
|
||||
idVec3 mStart;
|
||||
idVec3 mEnd;
|
||||
};
|
||||
|
||||
#endif // _BSE_ENVELOPE_H_INC_
|
||||
@@ -0,0 +1,404 @@
|
||||
// BSP_Envelopes.cpp
|
||||
//
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
|
||||
/*
|
||||
==========================
|
||||
rvEnvParms::GetMinMax
|
||||
==========================
|
||||
*/
|
||||
bool rvEnvParms::GetMinMax(float& min, float& max)
|
||||
{
|
||||
bool result = false; // al
|
||||
|
||||
if (mTable)
|
||||
{
|
||||
min = mTable->GetMinValue();
|
||||
result = true;
|
||||
max = mTable->GetMaxValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
min = 0.0;
|
||||
max = 0.0;
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
==========================
|
||||
rvEnvParms::Init
|
||||
==========================
|
||||
*/
|
||||
void rvEnvParms::Init(void)
|
||||
{
|
||||
mTable = 0;
|
||||
mIsCount = 1;
|
||||
mFastLookUp = 0;
|
||||
mEnvOffset.z = 0.0;
|
||||
mEnvOffset.y = 0.0;
|
||||
mEnvOffset.x = 0.0;
|
||||
mRate.x = 1.0;
|
||||
mRate.y = 1.0;
|
||||
mRate.z = 1.0;
|
||||
}
|
||||
|
||||
/*
|
||||
==========================
|
||||
rvEnvParms::Compare
|
||||
==========================
|
||||
*/
|
||||
bool rvEnvParms::Compare(const rvEnvParms& comp) const
|
||||
{
|
||||
return this->mTable == comp.mTable
|
||||
&& this->mIsCount == comp.mIsCount
|
||||
&& this->mRate.x == comp.mRate.x
|
||||
&& this->mRate.y == comp.mRate.y
|
||||
&& this->mRate.z == comp.mRate.z
|
||||
&& this->mEnvOffset.x == comp.mEnvOffset.x
|
||||
&& this->mEnvOffset.y == comp.mEnvOffset.y
|
||||
&& this->mEnvOffset.z == comp.mEnvOffset.z;
|
||||
}
|
||||
|
||||
/*
|
||||
==========================
|
||||
rvEnvParms::operator=
|
||||
==========================
|
||||
*/
|
||||
void rvEnvParms::operator=(const rvEnvParms& copy)
|
||||
{
|
||||
if (this == ©) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTable = copy.mTable;
|
||||
mIsCount = copy.mIsCount;
|
||||
mStatic = copy.mStatic;
|
||||
mFastLookUp = copy.mFastLookUp;
|
||||
mEnvOffset = copy.mEnvOffset;
|
||||
mRate = copy.mRate;
|
||||
}
|
||||
|
||||
void rvEnvParms::CalcRate(float* rate, float duration, int count)
|
||||
{
|
||||
if (!rate || count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float safeDuration = Max(0.002f, duration);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rate[i] = mIsCount ? (rate[i] / safeDuration) : rate[i];
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms::Evaluate3(const float time, const float* start, const float* rate, const float* end, float* dest)
|
||||
{
|
||||
if (!start || !rate || !end || !dest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTable) {
|
||||
const float tx = rate[0] * time + mEnvOffset.x;
|
||||
const float ty = rate[1] * time + mEnvOffset.y;
|
||||
const float tz = rate[2] * time + mEnvOffset.z;
|
||||
|
||||
const float vx = mTable->TableLookup(tx);
|
||||
const float vy = mTable->TableLookup(ty);
|
||||
const float vz = mTable->TableLookup(tz);
|
||||
|
||||
dest[0] = (end[0] - start[0]) * vx + start[0];
|
||||
dest[1] = (end[1] - start[1]) * vy + start[1];
|
||||
dest[2] = (end[2] - start[2]) * vz + start[2];
|
||||
}
|
||||
else {
|
||||
dest[0] = start[0];
|
||||
dest[1] = start[1];
|
||||
dest[2] = start[2];
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms::Evaluate(class rvEnvParms1Particle& env, float time, float oneOverDuration, float* dest)
|
||||
{
|
||||
if (!dest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTable) {
|
||||
float rate = mRate.x;
|
||||
if (mIsCount) {
|
||||
rate *= oneOverDuration;
|
||||
}
|
||||
const float lookup = rate * time + mEnvOffset.x;
|
||||
const float value = mTable->TableLookup(lookup);
|
||||
*dest = (env.mEnd - env.mStart) * value + env.mStart;
|
||||
}
|
||||
else {
|
||||
*dest = env.mStart;
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms::Evaluate(class rvEnvParms2Particle& env, float time, float oneOverDuration, float* dest)
|
||||
{
|
||||
const idDeclTable* v6; // ecx
|
||||
float rate_4; // [esp+14h] [ebp-8h]
|
||||
float rate_4a; // [esp+14h] [ebp-8h]
|
||||
float v9; // [esp+18h] [ebp-4h]
|
||||
float timea; // [esp+24h] [ebp+8h]
|
||||
float timeb; // [esp+24h] [ebp+8h]
|
||||
float result; // [esp+28h] [ebp+Ch]
|
||||
float resulta; // [esp+28h] [ebp+Ch]
|
||||
float resultb; // [esp+28h] [ebp+Ch]
|
||||
float resultc; // [esp+28h] [ebp+Ch]
|
||||
|
||||
if (this->mFastLookUp)
|
||||
{
|
||||
rate_4 = this->mRate.x;
|
||||
if (this->mIsCount)
|
||||
rate_4 = rate_4 * oneOverDuration;
|
||||
timea = rate_4 * time + this->mEnvOffset.x;
|
||||
result = mTable->TableLookup(timea);
|
||||
*dest = env.mStart.x + (env.mEnd.x - env.mStart.x) * result;
|
||||
dest[1] = result * (env.mEnd.y - env.mStart.y) + env.mStart.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
v6 = this->mTable;
|
||||
if (this->mTable)
|
||||
{
|
||||
rate_4a = this->mRate.x;
|
||||
v9 = this->mRate.y;
|
||||
if (this->mIsCount)
|
||||
{
|
||||
rate_4a = rate_4a * oneOverDuration;
|
||||
v9 = oneOverDuration * v9;
|
||||
}
|
||||
resulta = rate_4a * time + this->mEnvOffset.x;
|
||||
resultb = v6->TableLookup(resulta);// ((double(__stdcall*)(_DWORD))v6->TableLookup)(LODWORD(resulta));
|
||||
*dest = (env.mEnd.x - env.mStart.x) * resultb + env.mStart.x;
|
||||
timeb = v9 * time + this->mEnvOffset.y;
|
||||
resultc = mTable->TableLookup(timeb); //((double(__stdcall*)(_DWORD))this->mTable->TableLookup)(LODWORD(timeb));
|
||||
dest[1] = (env.mEnd.y - env.mStart.y) * resultc + env.mStart.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest = env.mStart.x;
|
||||
dest[1] = env.mStart.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rvEnvParms::Evaluate(class rvEnvParms3Particle& env, float time, float oneOverDuration, float* dest)
|
||||
{
|
||||
const idDeclTable* v6; // ecx
|
||||
float v8; // [esp+18h] [ebp-10h]
|
||||
float v9; // [esp+1Ch] [ebp-Ch]
|
||||
float v10; // [esp+20h] [ebp-8h]
|
||||
float v11; // [esp+24h] [ebp-4h]
|
||||
float enva; // [esp+2Ch] [ebp+4h]
|
||||
float timea; // [esp+30h] [ebp+8h]
|
||||
float timeb; // [esp+30h] [ebp+8h]
|
||||
float result; // [esp+34h] [ebp+Ch]
|
||||
float resulta; // [esp+34h] [ebp+Ch]
|
||||
float resultb; // [esp+34h] [ebp+Ch]
|
||||
float resultc; // [esp+34h] [ebp+Ch]
|
||||
float resultd; // [esp+34h] [ebp+Ch]
|
||||
|
||||
if (this->mFastLookUp)
|
||||
{
|
||||
v8 = this->mRate.x;
|
||||
if (this->mIsCount)
|
||||
v8 = v8 * oneOverDuration;
|
||||
timea = v8 * time + this->mEnvOffset.x;
|
||||
result = this->mTable->TableLookup(timea);
|
||||
*dest = env.mStart.x + (env.mEnd.x - env.mStart.x) * result;
|
||||
dest[1] = (env.mEnd.y - env.mStart.y) * result + env.mStart.y;
|
||||
dest[2] = result * (env.mEnd.z - env.mStart.z) + env.mStart.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
v6 = this->mTable;
|
||||
if (this->mTable)
|
||||
{
|
||||
v9 = this->mRate.x;
|
||||
v10 = this->mRate.y;
|
||||
v11 = this->mRate.z;
|
||||
if (this->mIsCount)
|
||||
{
|
||||
v9 = v9 * oneOverDuration;
|
||||
v10 = v10 * oneOverDuration;
|
||||
v11 = oneOverDuration * v11;
|
||||
}
|
||||
resulta = v9 * time + this->mEnvOffset.x;
|
||||
resultb = v6->TableLookup(resulta);
|
||||
*dest = (env.mEnd.x - env.mStart.x) * resultb + env.mStart.x;
|
||||
enva = v10 * time + this->mEnvOffset.y;
|
||||
resultc = this->mTable->TableLookup(enva);
|
||||
dest[1] = (env.mEnd.y - env.mStart.y) * resultc + env.mStart.y;
|
||||
timeb = v11 * time + this->mEnvOffset.z;
|
||||
resultd = this->mTable->TableLookup(timeb);
|
||||
dest[2] = (env.mEnd.z - env.mStart.z) * resultd + env.mStart.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest = env.mStart.x;
|
||||
dest[1] = env.mStart.y;
|
||||
dest[2] = env.mStart.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms::Finalize(void)
|
||||
{
|
||||
bool v1; // zf
|
||||
|
||||
v1 = this->mTable == 0;
|
||||
this->mFastLookUp = 0;
|
||||
if (!v1)
|
||||
this->mFastLookUp = this->mRate.y == this->mRate.x
|
||||
&& this->mRate.z == this->mRate.x
|
||||
&& this->mEnvOffset.y == this->mEnvOffset.x
|
||||
&& this->mEnvOffset.z == this->mEnvOffset.x;
|
||||
}
|
||||
|
||||
void rvEnvParms1::Init(const rvEnvParms& copy, float duration) {
|
||||
mTable = copy.mTable;
|
||||
mEnvOffset = copy.mEnvOffset.x;
|
||||
mStart = 0.0f;
|
||||
mEnd = 0.0f;
|
||||
mRate = copy.mRate.x;
|
||||
}
|
||||
|
||||
void rvEnvParms1::Evaluate(const float time, float* dest) {
|
||||
if (!dest) {
|
||||
return;
|
||||
}
|
||||
if (mTable) {
|
||||
const float value = mTable->TableLookup(mRate * time + mEnvOffset);
|
||||
*dest = mStart + (mEnd - mStart) * value;
|
||||
}
|
||||
else {
|
||||
*dest = mStart;
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms2::Init(const rvEnvParms& copy, float duration) {
|
||||
mTable = copy.mTable;
|
||||
mEnvOffset.Set(copy.mEnvOffset.x, copy.mEnvOffset.y);
|
||||
mFastLookup = (copy.mRate.x == copy.mRate.y) && (copy.mEnvOffset.x == copy.mEnvOffset.y);
|
||||
mStart.Zero();
|
||||
mEnd.Zero();
|
||||
mRate.Set(copy.mRate.x, copy.mRate.y);
|
||||
}
|
||||
|
||||
void rvEnvParms2::Evaluate(const float time, float* dest) {
|
||||
if (!dest) {
|
||||
return;
|
||||
}
|
||||
if (mTable) {
|
||||
if (mFastLookup) {
|
||||
const float value = mTable->TableLookup(mRate.x * time + mEnvOffset.x);
|
||||
dest[0] = mStart.x + (mEnd.x - mStart.x) * value;
|
||||
dest[1] = mStart.y + (mEnd.y - mStart.y) * value;
|
||||
}
|
||||
else {
|
||||
const float valueX = mTable->TableLookup(mRate.x * time + mEnvOffset.x);
|
||||
const float valueY = mTable->TableLookup(mRate.y * time + mEnvOffset.y);
|
||||
dest[0] = mStart.x + (mEnd.x - mStart.x) * valueX;
|
||||
dest[1] = mStart.y + (mEnd.y - mStart.y) * valueY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dest[0] = mStart.x;
|
||||
dest[1] = mStart.y;
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms3::Init(const rvEnvParms& copy, float duration) {
|
||||
mTable = copy.mTable;
|
||||
mEnvOffset = copy.mEnvOffset;
|
||||
mFastLookup = (copy.mRate.x == copy.mRate.y) && (copy.mRate.x == copy.mRate.z) && (copy.mEnvOffset.x == copy.mEnvOffset.y) && (copy.mEnvOffset.x == copy.mEnvOffset.z);
|
||||
mStart.Zero();
|
||||
mEnd.Zero();
|
||||
mRate = copy.mRate;
|
||||
}
|
||||
|
||||
void rvEnvParms3::Evaluate(const float time, float* dest) {
|
||||
if (!dest) {
|
||||
return;
|
||||
}
|
||||
if (mTable) {
|
||||
if (mFastLookup) {
|
||||
const float value = mTable->TableLookup(mRate.x * time + mEnvOffset.x);
|
||||
dest[0] = mStart.x + (mEnd.x - mStart.x) * value;
|
||||
dest[1] = mStart.y + (mEnd.y - mStart.y) * value;
|
||||
dest[2] = mStart.z + (mEnd.z - mStart.z) * value;
|
||||
}
|
||||
else {
|
||||
const float valueX = mTable->TableLookup(mRate.x * time + mEnvOffset.x);
|
||||
const float valueY = mTable->TableLookup(mRate.y * time + mEnvOffset.y);
|
||||
const float valueZ = mTable->TableLookup(mRate.z * time + mEnvOffset.z);
|
||||
dest[0] = mStart.x + (mEnd.x - mStart.x) * valueX;
|
||||
dest[1] = mStart.y + (mEnd.y - mStart.y) * valueY;
|
||||
dest[2] = mStart.z + (mEnd.z - mStart.z) * valueZ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dest[0] = mStart.x;
|
||||
dest[1] = mStart.y;
|
||||
dest[2] = mStart.z;
|
||||
}
|
||||
}
|
||||
|
||||
void rvEnvParms1Particle::Init(const rvEnvParms& copy, float duration) {
|
||||
mStart = 0.0f;
|
||||
mEnd = 0.0f;
|
||||
}
|
||||
|
||||
void rvEnvParms1Particle::Evaluate(const rvEnvParms& params, const float time, float oneOverDuration, float* dest) {
|
||||
const_cast<rvEnvParms&>(params).Evaluate(*this, time, oneOverDuration, dest);
|
||||
}
|
||||
|
||||
void rvEnvParms2Particle::Init(const rvEnvParms& copy, float duration) {
|
||||
mStart.Zero();
|
||||
mEnd.Zero();
|
||||
}
|
||||
|
||||
void rvEnvParms2Particle::Evaluate(const rvEnvParms& params, const float time, float oneOverDuration, float* dest) {
|
||||
const_cast<rvEnvParms&>(params).Evaluate(*this, time, oneOverDuration, dest);
|
||||
}
|
||||
|
||||
void rvEnvParms3Particle::Init(const rvEnvParms& copy, float duration) {
|
||||
mStart.Zero();
|
||||
mEnd.Zero();
|
||||
}
|
||||
|
||||
void rvEnvParms3Particle::Evaluate(const rvEnvParms& params, const float time, float oneOverDuration, float* dest) {
|
||||
const_cast<rvEnvParms&>(params).Evaluate(*this, time, oneOverDuration, dest);
|
||||
}
|
||||
|
||||
void rvEnvParms3Particle::Rotate(const rvAngles& angles)
|
||||
{
|
||||
this->mStart.x = angles.pitch + this->mStart.x;
|
||||
this->mStart.y = angles.yaw + this->mStart.y;
|
||||
this->mStart.z = angles.roll + this->mStart.z;
|
||||
this->mEnd.x = angles.pitch + this->mEnd.x;
|
||||
this->mEnd.y = this->mEnd.y + angles.yaw;
|
||||
this->mEnd.z = angles.roll + this->mEnd.z;
|
||||
}
|
||||
|
||||
void rvEnvParms::SetDefaultType()
|
||||
{
|
||||
if (!this->mTable)
|
||||
{
|
||||
this->mTable = (const idDeclTable*)declManager->FindType(
|
||||
DECL_TABLE,
|
||||
"linear",
|
||||
1);
|
||||
this->mIsCount = 1;
|
||||
this->mFastLookUp = 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
// BSE_Manager.cpp
|
||||
//
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE.h"
|
||||
#include "BSE_SpawnDomains.h"
|
||||
|
||||
namespace {
|
||||
ID_INLINE int BSE_GetFrameCounterMode(void) {
|
||||
return cvarSystem ? cvarSystem->GetCVarInteger("bse_frameCounters") : 0;
|
||||
}
|
||||
}
|
||||
|
||||
rvBSEManagerLocal bseManagerLocal;
|
||||
rvBSEManager* bse = &bseManagerLocal;
|
||||
|
||||
idCVar bse_speeds("bse_speeds", "0", CVAR_INTEGER, "print bse frame statistics");
|
||||
idCVar bse_enabled("bse_enabled", "1", CVAR_BOOL, "set to false to disable all effects");
|
||||
idCVar bse_render("bse_render", "1", CVAR_BOOL, "disable effect rendering");
|
||||
idCVar bse_debug("bse_debug", "0", CVAR_INTEGER, "BSE debug level (0=off, 1=log, 2=log+onscreen)");
|
||||
idCVar bse_showBounds("bse_showbounds", "0", CVAR_BOOL, "display debug bounding boxes effect");
|
||||
idCVar bse_physics("bse_physics", "1", CVAR_BOOL, "disable effect physics");
|
||||
idCVar bse_debris("bse_debris", "1", CVAR_BOOL, "disable effect debris");
|
||||
idCVar bse_singleEffect("bse_singleEffect", "", 0, "set to the name of the effect that is only played");
|
||||
idCVar bse_rateLimit("bse_rateLimit", "1", CVAR_FLOAT, "rate limit for spawned effects");
|
||||
idCVar bse_rateCost("bse_rateCost", "1", CVAR_FLOAT, "rate cost multiplier for spawned effects");
|
||||
idCVar bse_scale("bse_scale", "1", CVAR_FLOAT, "global BSE scaling for spawn/detail");
|
||||
idCVar bse_maxParticles("bse_maxParticles", "2048", CVAR_INTEGER, "maximum per-segment particle allocation");
|
||||
|
||||
int bse_frameSpawned = 0;
|
||||
int bse_frameServiced = 0;
|
||||
int bse_frameRendered = 0;
|
||||
|
||||
void BSE_ResetFrameCounters(void) {
|
||||
bse_frameSpawned = 0;
|
||||
bse_frameServiced = 0;
|
||||
bse_frameRendered = 0;
|
||||
}
|
||||
|
||||
void BSE_AddSpawned(int count) {
|
||||
if (count > 0) {
|
||||
bse_frameSpawned += count;
|
||||
}
|
||||
}
|
||||
|
||||
void BSE_AddServiced(int count) {
|
||||
if (count > 0) {
|
||||
bse_frameServiced += count;
|
||||
}
|
||||
}
|
||||
|
||||
void BSE_AddRendered(int count) {
|
||||
if (count > 0) {
|
||||
bse_frameRendered += count;
|
||||
}
|
||||
}
|
||||
|
||||
float effectCosts[EC_MAX] = { 0.0f, 0.1f, 0.1f };
|
||||
|
||||
idBlockAlloc<rvBSE, 256> rvBSEManagerLocal::effects;
|
||||
idVec3 rvBSEManagerLocal::mCubeNormals[6];
|
||||
idMat3 rvBSEManagerLocal::mModelToBSE;
|
||||
idList<idTraceModel*> rvBSEManagerLocal::mTraceModels;
|
||||
const char* rvBSEManagerLocal::mSegmentNames[SEG_COUNT];
|
||||
int rvBSEManagerLocal::mPerfCounters[NUM_PERF_COUNTERS];
|
||||
float rvBSEManagerLocal::mEffectRates[EC_MAX];
|
||||
/*
|
||||
====================
|
||||
rvBSEManagerLocal::Init
|
||||
====================
|
||||
*/
|
||||
bool rvBSEManagerLocal::Init(void) {
|
||||
common->Printf("----------------- BSE Init ------------------\n");
|
||||
|
||||
declManager->FindEffect("_default");
|
||||
declManager->FindMaterial("_default");
|
||||
declManager->FindMaterial("gfx/effects/particles_shapes/motionblur");
|
||||
declManager->FindType(DECL_TABLE, "halfsintable", true);
|
||||
renderModelManager->FindModel("_default");
|
||||
pauseTime = -1.0f;
|
||||
|
||||
common->Printf("--------- BSE Created Successfully ----------\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
rvBSEManagerLocal::Shutdown
|
||||
====================
|
||||
*/
|
||||
bool rvBSEManagerLocal::Shutdown(void) {
|
||||
common->Printf("--------------- BSE Shutdown ----------------\n");
|
||||
|
||||
for (int i = 0; i < mTraceModels.Num(); ++i) {
|
||||
delete mTraceModels[i];
|
||||
}
|
||||
mTraceModels.Clear();
|
||||
mEffectRates[0] = 0.0f;
|
||||
mEffectRates[1] = 0.0f;
|
||||
mEffectRates[2] = 0.0f;
|
||||
pauseTime = -1.0f;
|
||||
|
||||
common->Printf("---------------------------------------------\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
rvBSEManagerLocal::AddTraceModel
|
||||
=======================
|
||||
*/
|
||||
int rvBSEManagerLocal::AddTraceModel(idTraceModel* model)
|
||||
{
|
||||
mTraceModels.Append(model);
|
||||
return mTraceModels.Num() - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
rvBSEManagerLocal::GetTraceModel
|
||||
=======================
|
||||
*/
|
||||
idTraceModel* rvBSEManagerLocal::GetTraceModel(int index)
|
||||
{
|
||||
idTraceModel* result; // eax
|
||||
|
||||
if (index < 0 || index >= mTraceModels.Num())
|
||||
result = 0;
|
||||
else
|
||||
result = mTraceModels[index];
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
rvBSEManagerLocal::FreeTraceModel
|
||||
=======================
|
||||
*/
|
||||
void rvBSEManagerLocal::FreeTraceModel(int index)
|
||||
{
|
||||
if (index >= 0 && index < mTraceModels.Num())
|
||||
{
|
||||
delete mTraceModels[index];
|
||||
mTraceModels[index] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool rvBSEManagerLocal::PlayEffect(class rvRenderEffectLocal* def, float time) {
|
||||
if (!bse_enabled.GetBool() || !def || !def->parms.declEffect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rvDeclEffect* v3 = (const rvDeclEffect*)def->parms.declEffect;
|
||||
const idStr effectName = def->parms.declEffect->GetName();
|
||||
|
||||
if (Filtered(effectName, EC_IGNORE)) {
|
||||
def->effect = NULL;
|
||||
def->expired = true;
|
||||
return false;
|
||||
}
|
||||
if (bse_debug.GetInteger())
|
||||
{
|
||||
common->Printf("Playing effect: %s at %g\n", effectName.c_str(), time);
|
||||
}
|
||||
++v3->mPlayCount;
|
||||
rvBSE* effectState = effects.Alloc();
|
||||
if (!effectState) {
|
||||
def->effect = NULL;
|
||||
def->expired = true;
|
||||
return false;
|
||||
}
|
||||
def->effect = effectState;
|
||||
def->expired = false;
|
||||
def->newEffect = true;
|
||||
effectState->SetRenderWorld( reinterpret_cast<idRenderWorld*>(def->world) );
|
||||
effectState->Init(v3, &def->parms, time);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rvBSEManagerLocal::ServiceEffect(class rvRenderEffectLocal* def, float time) {
|
||||
BSE_AddServiced(1);
|
||||
|
||||
if (!def || !def->effect) {
|
||||
if (def) {
|
||||
def->expired = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!bse_enabled.GetBool()) {
|
||||
def->expired = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool forcePush = false;
|
||||
|
||||
if (pauseTime >= 0.0f) {
|
||||
time = pauseTime;
|
||||
}
|
||||
|
||||
const idStr effectName = def->parms.declEffect ? def->parms.declEffect->GetName() : "";
|
||||
if (Filtered(effectName.c_str(), EC_IGNORE)) {
|
||||
def->expired = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
def->effect->SetRenderWorld( reinterpret_cast<idRenderWorld*>(def->world) );
|
||||
|
||||
if (def->effect->Service(&def->parms, time, def->gameTime > def->serviceTime, forcePush)) {
|
||||
def->expired = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
def->expired = false;
|
||||
def->newEffect = false;
|
||||
def->serviceTime = def->gameTime;
|
||||
const idBounds currentLocalBounds = def->effect->GetCurrentLocalBounds();
|
||||
def->referenceBounds = currentLocalBounds;
|
||||
if (bse_speeds.GetBool())
|
||||
++rvBSEManagerLocal::mPerfCounters[0];
|
||||
if (bse_debug.GetInteger())
|
||||
def->effect->EvaluateCost();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
idRenderModel* rvBSEManagerLocal::RenderEffect(class rvRenderEffectLocal* def, const struct viewDef_s* view) {
|
||||
if (!def || !def->effect) {
|
||||
if (def && def->dynamicModel) {
|
||||
delete def->dynamicModel;
|
||||
def->dynamicModel = NULL;
|
||||
def->dynamicModelFrameCount = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
def->dynamicModel = def->effect->Render(def->dynamicModel, &def->parms, view);
|
||||
if (!def->dynamicModel) {
|
||||
def->dynamicModelFrameCount = 0;
|
||||
}
|
||||
return def->dynamicModel;
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::StopEffect(rvRenderEffectLocal* def) {
|
||||
if (def && def->index >= 0 && def->effect)
|
||||
{
|
||||
if (bse_debug.GetInteger())
|
||||
{
|
||||
idStr effectName = def->parms.declEffect->GetName();
|
||||
common->Printf("Stopping effect %s\n", effectName.c_str());
|
||||
}
|
||||
def->effect->SetStopped(true);
|
||||
def->newEffect = false;
|
||||
}
|
||||
else if (def)
|
||||
{
|
||||
def->newEffect = false;
|
||||
def->expired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::FreeEffect(rvRenderEffectLocal* def) {
|
||||
if (def && def->index >= 0 && def->effect)
|
||||
{
|
||||
if (bse_debug.GetInteger())
|
||||
{
|
||||
idStr effectName = def->parms.declEffect->GetName();
|
||||
common->Printf("Freeing effect %s\n", effectName.c_str());
|
||||
}
|
||||
def->effect->Destroy();
|
||||
effects.Free(def->effect);
|
||||
def->effect = NULL;
|
||||
}
|
||||
if (def) {
|
||||
def->newEffect = false;
|
||||
def->expired = true;
|
||||
}
|
||||
}
|
||||
|
||||
float rvBSEManagerLocal::EffectDuration(const rvRenderEffectLocal* def) {
|
||||
if (!def) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (def->effect) {
|
||||
return def->effect->GetDuration();
|
||||
}
|
||||
if (def->parms.declEffect) {
|
||||
const rvDeclEffect* decl = (const rvDeclEffect*)def->parms.declEffect;
|
||||
return decl->GetMaxDuration();
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool rvBSEManagerLocal::CheckDefForSound(const renderEffect_t* def) {
|
||||
if (!def || !def->declEffect) {
|
||||
return false;
|
||||
}
|
||||
const rvDeclEffect* decl = (const rvDeclEffect*)def->declEffect;
|
||||
return decl->GetHasSound();
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::BeginLevelLoad(void) {
|
||||
mEffectRates[0] = 0.0f;
|
||||
mEffectRates[1] = 0.0f;
|
||||
mEffectRates[2] = 0.0f;
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::EndLevelLoad(void) {
|
||||
mEffectRates[0] = 0.0f;
|
||||
mEffectRates[1] = 0.0f;
|
||||
mEffectRates[2] = 0.0f;
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::StartFrame(void) {
|
||||
BSE_ResetFrameCounters();
|
||||
UpdateRateTimes();
|
||||
|
||||
if (bse_speeds.GetInteger())
|
||||
{
|
||||
rvBSEManagerLocal::mPerfCounters[0] = 0;
|
||||
rvBSEManagerLocal::mPerfCounters[1] = 0;
|
||||
rvBSEManagerLocal::mPerfCounters[2] = 0;
|
||||
rvBSEManagerLocal::mPerfCounters[3] = 0;
|
||||
rvBSEManagerLocal::mPerfCounters[4] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::EndFrame(void) {
|
||||
if (BSE_GetFrameCounterMode() > 0) {
|
||||
common->Printf(
|
||||
"BSE manager frame counters: spawned=%d serviced=%d rendered=%d\n",
|
||||
bse_frameSpawned,
|
||||
bse_frameServiced,
|
||||
bse_frameRendered);
|
||||
}
|
||||
|
||||
if (bse_speeds.GetInteger()) {
|
||||
common->Printf("bse_active: %i particles: %i traces: %i texels: %i\n",
|
||||
rvBSEManagerLocal::mPerfCounters[0],
|
||||
rvBSEManagerLocal::mPerfCounters[2],
|
||||
rvBSEManagerLocal::mPerfCounters[1],
|
||||
(double)rvBSEManagerLocal::mPerfCounters[3] * 0.00000095367431640625);
|
||||
}
|
||||
}
|
||||
|
||||
bool rvBSEManagerLocal::Filtered(const char* name, effectCategory_t category) {
|
||||
if (!name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* singleFilter = bse_singleEffect.GetString();
|
||||
if (singleFilter && singleFilter[0] != '\0') {
|
||||
if (idStr::FindText(name, singleFilter, false) < 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return !CanPlayRateLimited(category);
|
||||
}
|
||||
|
||||
void rvBSEManagerLocal::UpdateRateTimes(void) {
|
||||
const float decay = Max(0.0f, bse_rateCost.GetFloat()) * 0.1f;
|
||||
for (int i = 0; i < EC_MAX; ++i) {
|
||||
mEffectRates[i] = Max(0.0f, mEffectRates[i] - decay);
|
||||
}
|
||||
}
|
||||
|
||||
bool rvBSEManagerLocal::CanPlayRateLimited(effectCategory_t category) {
|
||||
if (category <= EC_IGNORE || category >= EC_MAX) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const float limit = Max(0.0f, bse_rateLimit.GetFloat());
|
||||
if (limit <= 0.0f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const float cost = effectCosts[category] * Max(0.0f, bse_rateCost.GetFloat());
|
||||
if (mEffectRates[category] + cost > limit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mEffectRates[category] += cost;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE.h"
|
||||
#include "BSE_SpawnDomains.h"
|
||||
#include "BSE_API.h"
|
||||
|
||||
namespace {
|
||||
rvBSEManagerLocal bseLocal;
|
||||
}
|
||||
|
||||
idDecl* OpenQ4_AllocIntegratedBSEDeclEffect( void ) {
|
||||
return new rvDeclEffect();
|
||||
}
|
||||
|
||||
rvBSEManager* OpenQ4_GetIntegratedBSEManager( void ) {
|
||||
return &bseLocal;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,833 @@
|
||||
// Copyright (C) 2007 Id Software, Inc.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _BSE_PARTICLE_H_INC_
|
||||
#define _BSE_PARTICLE_H_INC_
|
||||
|
||||
|
||||
#define BSE_FUTURE ( 0.016f ) // How far into the future to check for particle spawning
|
||||
#define BSE_TIME_EPSILON ( 0.002f ) // Edge condition checks
|
||||
#define BSE_PHYSICS_TIME_SAMPLE ( 0.1f ) // Number of seconds to check the position delta for physics
|
||||
#define BSE_MINIMUM_TRACE_DIST ( 16.0f ) // The square of the distance below which physics will not check
|
||||
#define BSE_SURFACE_OFFSET ( 2.0f ) // Amount a collision is pushed back along the normal
|
||||
#define BSE_BOUNCE_LIMIT ( 2500.0f ) // Square of velocity below which a particle stops bouncing
|
||||
#define BSE_TRACE_OFFSET ( 0.02f ) // How much the bounce should move back from the endpos
|
||||
#define MAX_PARTICLES ( 2048 ) // Max number of particles attached to an effect (arbitrary sanity check)
|
||||
#define BSE_DENSITY_FACTOR ( 50.0f )
|
||||
|
||||
#define BSE_MAX_FORKS ( 16 )
|
||||
|
||||
#define BSE_MAX_DURATION ( 60.0f * 5.0f ) // 5 Minutes
|
||||
|
||||
#define BSE_NUM_SPAWNABLE ( 4 ) // Number of random effects to choose from
|
||||
|
||||
enum
|
||||
{
|
||||
PTYPE_NONE = 0, // A non sprite - for sound and vision segments
|
||||
PTYPE_SPRITE, // Simple 2D alpha blended quad
|
||||
PTYPE_LINE, // 2D alpha blended line
|
||||
PTYPE_ORIENTED, // 2D particle oriented in 3D - alpha blended
|
||||
PTYPE_DECAL, // Hook into id's decal system
|
||||
PTYPE_MODEL, // Model - must only have 1 surface
|
||||
PTYPE_LIGHT, // Dynamic light - very expensive
|
||||
PTYPE_ELECTRICITY, // A bolt of electricity
|
||||
PTYPE_LINKED, // A series of linked lines
|
||||
PTYPE_ORIENTEDLINKED,
|
||||
PTYPE_DEBRIS, // A client side moveable entity spawned in the game
|
||||
PTYPE_COUNT
|
||||
};
|
||||
|
||||
// Defined classes
|
||||
class rvParticle;
|
||||
class rvSpriteParticle;
|
||||
class rvLineParticle;
|
||||
class rvOrientedParticle;
|
||||
class rvElectricityParticle;
|
||||
class rvDecalParticle;
|
||||
class rvModelParticle;
|
||||
class rvLightParticle;
|
||||
class rvLinkedParticle;
|
||||
class sdOrientedLinkedParticle;
|
||||
class rvDebrisParticle;
|
||||
|
||||
class rvParticleTemplate;
|
||||
class rvParticleParms;
|
||||
|
||||
// Referenced classes
|
||||
class rvBSE;
|
||||
class rvDeclEffect;
|
||||
class rvSegment;
|
||||
class rvSegmentTemplate;
|
||||
|
||||
#define PTFLAG_STATIONARY BIT( 0 )
|
||||
#define PTFLAG_LOCKED BIT( 1 )
|
||||
#define PTFLAG_HAS_OFFSET BIT( 2 )
|
||||
|
||||
#define PTFLAG_PARSED BIT( 8 )
|
||||
#define PTFLAG_HAS_PHYSICS BIT( 9 )
|
||||
#define PTFLAG_DELETE_ON_IMPACT BIT( 10 )
|
||||
#define PTFLAG_GENERATED_NORMAL BIT( 11 )
|
||||
#define PTFLAG_GENERATED_ORG_NORMAL BIT( 12 )
|
||||
#define PTFLAG_FLIPPED_NORMAL BIT( 13 )
|
||||
#define PTFLAG_CALCED_NORMAL BIT( 14 )
|
||||
#define PTFLAG_ADDITIVE BIT( 15 )
|
||||
#define PTFLAG_GENERATED_LINE BIT( 16 )
|
||||
#define PTFLAG_SHADOWS BIT( 17 )
|
||||
#define PTFLAG_SPECULAR BIT( 18 )
|
||||
#define PTFLAG_LINKED BIT( 19 )
|
||||
#define PTFLAG_TILED BIT( 20 )
|
||||
#define PTFLAG_PERSIST BIT( 21 )
|
||||
#define PTFLAG_USELIGHTNING_AXIS BIT( 22 )
|
||||
#define PTFLAG_FADE_IN BIT( 23 )
|
||||
#define PTFLAG_USE_MATERIAL_COLOR BIT( 24 )
|
||||
#define PTFLAG_PARENTVEL BIT( 25 )
|
||||
#define PTFLAG_HAS_LINEHIT BIT( 26 )
|
||||
#define PTFLAG_INITED BIT( 27 )
|
||||
|
||||
// ==============================================
|
||||
// Particle types (from multiple elements)
|
||||
// ==============================================
|
||||
class rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
rvParticle( void ) {}
|
||||
virtual ~rvParticle( void ) {}
|
||||
|
||||
void SetFlag( bool on, int flag ) { on ? mFlags |= flag : mFlags &= ~flag; }
|
||||
bool GetFlag( int flag ) const { return ( mFlags & flag ) != 0 ; }
|
||||
|
||||
int GetStationary( void ) const { return( ( mFlags & PTFLAG_STATIONARY ) ); }
|
||||
int GetLocked( void ) const { return( ( mFlags & PTFLAG_LOCKED ) ); }
|
||||
int GetHasOffset( void ) const { return( ( mFlags & PTFLAG_HAS_OFFSET ) ); }
|
||||
|
||||
int GetGeneratedLine( void ) const { return( ( mFlags & PTFLAG_GENERATED_LINE ) ); }
|
||||
int GetAdditive( void ) const { return( ( mFlags & PTFLAG_ADDITIVE ) ); }
|
||||
int GetTiled( void ) const { return( ( mFlags & PTFLAG_TILED ) ); }
|
||||
int GetPersist( void ) const { return( ( mFlags & PTFLAG_PERSIST ) ); }
|
||||
|
||||
int GetFlags(void) {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
void SetStationary( bool stopped ) { SetFlag( stopped, PTFLAG_STATIONARY ); }
|
||||
void SetLocked( bool locked ) { SetFlag( locked, PTFLAG_LOCKED ); }
|
||||
void SetHasOffset( bool hasOffset ) { SetFlag( hasOffset, PTFLAG_HAS_OFFSET ); }
|
||||
|
||||
void SetNext( rvParticle *next ) { mNext = next; }
|
||||
rvParticle *GetNext( void ) const { return( mNext ); }
|
||||
|
||||
ID_INLINE float GetDuration( void ) const { return( mEndTime - mStartTime ); }
|
||||
void ExtendLife( float time ) { mEndTime = time; }
|
||||
bool Expired( float time ) const { return( time >= mEndTime - BSE_TIME_EPSILON ); }
|
||||
|
||||
void CalcImpactPoint( idVec3 &endPos, const idVec3 &origin, const idVec3 &motion, const idBounds &bounds, const idVec3 &normal );
|
||||
void SetOriginUsingEndOrigin( rvBSE *effect, rvParticleTemplate *pt, idVec3 *normal, idVec3 *centre );
|
||||
void HandleEndOrigin( rvBSE *effect, rvParticleTemplate *pt, idVec3 *normal = NULL, idVec3 *centre = NULL );
|
||||
void SetLengthUsingEndOrigin( rvBSE *effect, rvParticleParms &parms, float *length );
|
||||
void HandleEndLength( rvBSE *effect, rvParticleTemplate *pt, rvParticleParms &parms, float *length );
|
||||
void Bounce( rvBSE *effect, rvParticleTemplate *pt, idVec3 endPos, idVec3 normal, float time );
|
||||
bool RunPhysics( rvBSE *effect, rvSegmentTemplate *pt, float time );
|
||||
void CheckTimeoutEffect( rvBSE *effect, rvSegmentTemplate *st, float time );
|
||||
dword HandleTint( const rvBSE *effect, idVec4 &colour, float alpha );
|
||||
void RenderQuadTrail( const rvBSE *effect, srfTriangles_t *tri, idVec3 offset, float fraction, idVec4 &colour, idVec3 &pos, bool first );
|
||||
void EmitSmokeParticles( rvBSE *effect, rvSegment *child, rvParticleTemplate *pt, float time );
|
||||
void ScaleAngle( float constant ) { mAngleEnv.Scale( constant ); }
|
||||
float GetEndTime( void ) const { return( mEndTime ); }
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const { assert( 0 ); return( NULL ); }
|
||||
virtual int GetArrayIndex( rvParticle *p ) const { assert( 0 ); return( 0 ); }
|
||||
|
||||
bool GetEvaluationTime( float time, float &evalTime, bool infinite = false );
|
||||
void EvaluatePosition( const rvBSE *effect, rvParticleTemplate *pt, idVec3 &pos, float time );
|
||||
void EvaluateVelocity( const rvBSE *effect, idVec3 &velocity, float time );
|
||||
|
||||
ID_INLINE void EvaluateTint( rvEnvParms *tint, rvEnvParms *fade, const float time, float oneOverDuration, idVec4 &dest ) {
|
||||
tint->Evaluate( mTintEnv, time, oneOverDuration, dest.ToFloatPtr() );
|
||||
fade->Evaluate( mFadeEnv, time, oneOverDuration, &dest[3] );
|
||||
}
|
||||
|
||||
ID_INLINE void EvaluateAngle( rvEnvParms *angle, const float time, float oneOverDuration, rvAngles &dest ) {
|
||||
angle->Evaluate( mAngleEnv, time, oneOverDuration, dest.ToFloatPtr() );
|
||||
}
|
||||
|
||||
ID_INLINE void EvaluateOffset( rvEnvParms *offset, const float time, float oneOverDuration, idVec3 &dest ) {
|
||||
offset->Evaluate( mOffsetEnv, time, oneOverDuration, dest.ToFloatPtr() );
|
||||
}
|
||||
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) { assert( 0 ); }
|
||||
virtual void EvaluateRotation( rvEnvParms *rotation, const float time, float oneOverDuration, float *dest ) { assert( 0 ); }
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) { dest.Zero(); }
|
||||
|
||||
|
||||
void InitTintEnv( rvEnvParms &env, float duration ) { mTintEnv.Init( env, duration ); }
|
||||
void InitFadeEnv( rvEnvParms &env, float duration ) { mFadeEnv.Init( env, duration ); }
|
||||
void InitAngleEnv( rvEnvParms &env, float duration ) { mAngleEnv.Init( env, duration ); }
|
||||
void InitOffsetEnv( rvEnvParms &env, float duration ) { mOffsetEnv.Init( env, duration ); }
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { assert( 0 ); }
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) { assert( 0 ); }
|
||||
virtual void InitLengthEnv( rvEnvParms &env, float duration ) {}
|
||||
|
||||
virtual float *GetInitSize( void ) { assert( 0 ); return( NULL ); }
|
||||
virtual float *GetDestSize( void ) { assert( 0 ); return( NULL ); }
|
||||
|
||||
virtual float *GetInitRotation( void ) { assert( 0 ); return( NULL ); }
|
||||
virtual float *GetDestRotation( void ) { assert( 0 ); return( NULL ); }
|
||||
virtual void ScaleRotation( float constant ) {}
|
||||
|
||||
virtual float *GetInitLength( void ) { return( NULL ); }
|
||||
virtual float *GetDestLength( void ) { return( NULL ); }
|
||||
|
||||
void Attenuate( float atten, rvParticleParms &parms, rvEnvParms1 &result );
|
||||
void Attenuate( float atten, rvParticleParms &parms, rvEnvParms2 &result );
|
||||
void Attenuate( float atten, rvParticleParms &parms, rvEnvParms3 &result );
|
||||
void Attenuate( float atten, rvParticleParms &parms, rvEnvParms1Particle &result );
|
||||
void Attenuate( float atten, rvParticleParms &parms, rvEnvParms2Particle &result );
|
||||
void Attenuate( float atten, rvParticleParms &parms, rvEnvParms3Particle &result );
|
||||
|
||||
void AttenuateFade( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mFadeEnv ); }
|
||||
virtual void AttenuateSize( float atten, rvParticleParms &parms ) {}
|
||||
virtual void AttenuateLength( float atten, rvParticleParms &parms ) {}
|
||||
|
||||
virtual void TransformLength( idVec3 normal ) {}
|
||||
virtual void ScaleLength( float constant ) {}
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate ) { assert( 0 ); }
|
||||
virtual void HandleTiling( rvParticleTemplate *pt ) {}
|
||||
|
||||
virtual void HandleOrientation( rvAngles &angles ) {}
|
||||
virtual void FinishSpawn( rvBSE *effect, rvSegment *segment, float birthTime, float fraction = 0.0f, const idVec3 &initOffset = vec3_origin, const idMat3 &initAxis = mat3_identity );
|
||||
virtual int Update( rvParticleTemplate *pt, float time ) { return( 1 ); }
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t *tri, float time, float override = 1.0f ) { return( false ); }
|
||||
void DoRenderBurnTrail( rvBSE *effect, rvParticleTemplate *st, const idMat3 &view, srfTriangles_t *tri, float time );
|
||||
virtual void RenderBurnTrail( rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t *tri, float time ) {}
|
||||
virtual void RenderMotion( rvBSE *effect, rvParticleTemplate *pt, srfTriangles_t *tri, const struct renderEffect_s *owner, float time );
|
||||
virtual bool InitLight( rvBSE *effect, rvSegmentTemplate *st, float time ) { return( false ); }
|
||||
virtual bool PresentLight( rvBSE *effect, rvParticleTemplate *pt, float time, bool infinite ) { return( false ); }
|
||||
virtual bool Destroy( void ) { return( false ); }
|
||||
virtual void SetModel( const idRenderModel *model ) {}
|
||||
virtual void SetupElectricity( rvParticleTemplate *pt ) {}
|
||||
virtual void Refresh( rvBSE *effect, rvSegmentTemplate *st, rvParticleTemplate *pt ) {}
|
||||
|
||||
float UpdateViewDist( const idVec3 &eyePos ) { return (mPosition - eyePos).LengthSqr(); }
|
||||
//REMOVE unsigned int GetSortKey( void ) { return *((int *)(&mSqrViewDist)); }
|
||||
//REMOVE const idVec3& GetPosition() const { return mPosition; }
|
||||
protected:
|
||||
// Can be altered in UpdateParticles
|
||||
class rvParticle *mNext;
|
||||
float mMotionStartTime; // World start time for motion calcs - reset on a bounce
|
||||
|
||||
// could be stored as a delta from start
|
||||
float mLastTrailTime; // Last time a smoke particle was emitted
|
||||
|
||||
// need to restructure flags
|
||||
int mFlags;
|
||||
|
||||
// Fixed at spawn time
|
||||
float mStartTime; // World start time of particle in seconds
|
||||
float mEndTime; // End of particle's life
|
||||
|
||||
float mTrailTime; // Length of trail
|
||||
int mTrailCount; // Number of particles in trail
|
||||
|
||||
// always between 0 and 1 inc
|
||||
float mFraction; // Fraction along the line
|
||||
|
||||
float mTextureScale; // Multiplier for the texture coord
|
||||
float mTextureOffset;
|
||||
|
||||
idVec3 mInitEffectPos; // Initial effect position when the particle is spawned
|
||||
idMat3 mInitAxis; // Initial effect axis when the particle is spawned
|
||||
|
||||
idVec3 mInitPos; // Position at time = 0
|
||||
idVec3 mVelocity; // Initial velocity
|
||||
idVec3 mAcceleration; // Initial acceleration
|
||||
float mFriction; // Friction works by slowing down over time, this float is basically ( 1 / [Time in seconds from spawning at which velocity should be zero] )
|
||||
|
||||
rvEnvParms3Particle mTintEnv;
|
||||
rvEnvParms1Particle mFadeEnv;
|
||||
rvEnvParms3Particle mAngleEnv;
|
||||
rvEnvParms3Particle mOffsetEnv;
|
||||
int mTrailRepeat;
|
||||
|
||||
idVec3 mPosition; // Updated every time EvaluatePosition is called
|
||||
//REMOVE float mSqrViewDist; // Fixme: Allocate on stack during sorting? // For sorting
|
||||
};
|
||||
|
||||
class rvSpriteParticle : public rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {
|
||||
size->Evaluate( mSizeEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateRotation( rvEnvParms *rotation, const float time, float oneOverDuration, float *dest ) {
|
||||
rotation->Evaluate( mRotationEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
//virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) { mRotationEnv.Init( env, duration ); }
|
||||
virtual float *GetInitRotation( void ) { return( mRotationEnv.GetStart() ); }
|
||||
virtual float *GetDestRotation( void ) { return( mRotationEnv.GetEnd() ); }
|
||||
|
||||
virtual void ScaleRotation( float constant ) { mRotationEnv.Scale( constant ); }
|
||||
|
||||
virtual void AttenuateSize( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mSizeEnv ); }
|
||||
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate );
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time, float override = 1.0f );
|
||||
virtual void RenderBurnTrail( rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time ) { DoRenderBurnTrail( effect, pt, view, tri, time ); }
|
||||
|
||||
protected:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms2Particle mSizeEnv;
|
||||
rvEnvParms1Particle mRotationEnv;
|
||||
};
|
||||
|
||||
class rvLineParticle : public rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {// { mSizeEnv.Evaluate( time, dest ); }
|
||||
size->Evaluate( mSizeEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {// { mLengthEnv.Evaluate( time, dest.ToFloatPtr() ); }
|
||||
length->Evaluate( mLengthEnv, time, oneOverDuration, dest.ToFloatPtr() );
|
||||
}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) {}
|
||||
virtual float *GetInitRotation( void ) { return( NULL ); }
|
||||
virtual float *GetDestRotation( void ) { return( NULL ); }
|
||||
virtual void SetRotation( void ) {}
|
||||
|
||||
virtual void InitLengthEnv( rvEnvParms &env, float duration ) { mLengthEnv.Init( env, duration ); }
|
||||
virtual float *GetInitLength( void ) { return( mLengthEnv.GetStart() ); }
|
||||
virtual float *GetDestLength( void ) { return( mLengthEnv.GetEnd() ); }
|
||||
virtual void TransformLength( idVec3 normal ) { mLengthEnv.Transform( normal ); }
|
||||
virtual void ScaleLength( float constant ) { mLengthEnv.Scale( constant ); }
|
||||
|
||||
virtual void AttenuateSize( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mSizeEnv ); }
|
||||
virtual void AttenuateLength( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mLengthEnv ); }
|
||||
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate );
|
||||
virtual void HandleTiling( rvParticleTemplate *pt );
|
||||
virtual void FinishSpawn( rvBSE *effect, rvSegment *segment, float birthTime, float fraction = 0.0f, const idVec3 &initOffset = vec3_origin, const idMat3 &initAxis = mat3_identity );
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time, float override = 1.0f );
|
||||
virtual void RenderBurnTrail( rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time ) { DoRenderBurnTrail( effect, pt, view, tri, time ); }
|
||||
virtual void Refresh( rvBSE *effect, rvSegmentTemplate *st, rvParticleTemplate *pt );
|
||||
|
||||
protected:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms1Particle mSizeEnv;
|
||||
rvEnvParms3Particle mLengthEnv;
|
||||
};
|
||||
|
||||
class rvOrientedParticle : public rvSpriteParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {// { mSizeEnv.Evaluate( time, dest ); }
|
||||
size->Evaluate( mSizeEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateRotation( rvEnvParms *rotation, const float time, float oneOverDuration, float *dest ) {
|
||||
rotation->Evaluate( mRotationEnv, time, oneOverDuration, dest );
|
||||
}// { mRotationEnv.Evaluate( time, dest ); }
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) { mRotationEnv.Init( env, duration ); }
|
||||
virtual float *GetInitRotation( void ) { return( mRotationEnv.GetStart() ); }
|
||||
virtual float *GetDestRotation( void ) { return( mRotationEnv.GetEnd() ); }
|
||||
|
||||
virtual void ScaleRotation( float constant ) { mRotationEnv.Scale( constant ); }
|
||||
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate );
|
||||
virtual void HandleOrientation( rvAngles &angles ) { mRotationEnv.Rotate( angles ); }
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time, float override = 1.0f );
|
||||
|
||||
private:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms2Particle mSizeEnv;
|
||||
rvEnvParms3Particle mRotationEnv;
|
||||
};
|
||||
|
||||
class rvElectricityParticle : public rvLineParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
int GetBoltCount( float length );
|
||||
void RenderBranch( const rvBSE *effect, struct SElecWork *work, idVec3 start, idVec3 end, const idDeclTable *jitterTable );
|
||||
bool RenderLineSegment( const rvBSE *effect, struct SElecWork *work, idVec3 start, float startFraction );
|
||||
void ApplyShape( const rvBSE *effect, struct SElecWork *work, idVec3 start, idVec3 end, int count, float startFraction, float endFraction );
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual int Update( rvParticleTemplate *pt, float time );
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t *tri, float time, float override = 1.0f );
|
||||
|
||||
virtual void SetupElectricity( rvParticleTemplate *pt );
|
||||
|
||||
private:
|
||||
// Alterable
|
||||
int mNumBolts;
|
||||
|
||||
// Fixed at spawn time
|
||||
int mNumForks;
|
||||
int mSeed;
|
||||
idVec3 mForkSizeMins;
|
||||
idVec3 mForkSizeMaxs;
|
||||
idVec3 mJitterSize;
|
||||
float mLastJitter;
|
||||
float mJitterRate;
|
||||
const idDeclTable *mJitterTable;
|
||||
};
|
||||
|
||||
class rvDecalParticle : public rvParticle //rvSpriteParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {}
|
||||
virtual void EvaluateRotation( rvEnvParms *rotation, const float time, float oneOverDuration, float *dest ) {
|
||||
rotation->Evaluate( mRotationEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) {}
|
||||
virtual float *GetInitRotation( void ) { return( mRotationEnv.GetStart() ); }
|
||||
virtual float *GetDestRotation( void ) { return( mRotationEnv.GetEnd() ); }
|
||||
|
||||
virtual void ScaleRotation( float constant ) { mRotationEnv.Scale( constant ); }
|
||||
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate );
|
||||
private:
|
||||
rvEnvParms2Particle mSizeEnv;
|
||||
rvEnvParms1Particle mRotationEnv;
|
||||
|
||||
};
|
||||
|
||||
class rvModelParticle : public rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {// { mSizeEnv.Evaluate( time, dest ); }
|
||||
size->Evaluate( mSizeEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateRotation( rvEnvParms *rotation, const float time, float oneOverDuration, float *dest ) {// { mRotationEnv.Evaluate( time, dest ); }
|
||||
rotation->Evaluate( mRotationEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) { mRotationEnv.Init( env, duration ); }
|
||||
virtual float *GetInitRotation( void ) { return( mRotationEnv.GetStart() ); }
|
||||
virtual float *GetDestRotation( void ) { return( mRotationEnv.GetEnd() ); }
|
||||
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate );
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time, float override = 1.0f );
|
||||
virtual void SetModel( const idRenderModel *model ) { mModel = model; }
|
||||
|
||||
virtual void AttenuateSize( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mSizeEnv ); }
|
||||
|
||||
private:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms3Particle mSizeEnv;
|
||||
rvEnvParms3Particle mRotationEnv;
|
||||
|
||||
const idRenderModel *mModel;
|
||||
};
|
||||
|
||||
class rvLightParticle : public rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
rvLightParticle( void ) { mLightDefHandle = -1; mLightRenderWorld = NULL; }
|
||||
~rvLightParticle( void ) { Destroy(); }
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {// { mSizeEnv.Evaluate( time, dest ); }
|
||||
size->Evaluate( mSizeEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) {}
|
||||
virtual float *GetInitRotation( void ) { return( NULL ); }
|
||||
virtual float *GetDestRotation( void ) { return( NULL ); }
|
||||
|
||||
virtual void AttenuateSize( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mSizeEnv ); }
|
||||
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate );
|
||||
virtual bool InitLight( rvBSE *effect, rvSegmentTemplate *st, float time );
|
||||
virtual bool PresentLight( rvBSE *effect, rvParticleTemplate *pt, float time, bool infinite );
|
||||
virtual bool Destroy( void );
|
||||
|
||||
private:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms3Particle mSizeEnv;
|
||||
|
||||
// Alterable
|
||||
qhandle_t mLightDefHandle;
|
||||
renderLight_t mLight;
|
||||
idRenderWorld* mLightRenderWorld;
|
||||
};
|
||||
|
||||
class rvLinkedParticle : public rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateSize( rvEnvParms *size, const float time, float oneOverDuration, float *dest ) {// { mSizeEnv.Evaluate( time, dest ); }
|
||||
size->Evaluate( mSizeEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
virtual void EvaluateLength( rvEnvParms *length, const float time, float oneOverDuration, idVec3 &dest ) {}
|
||||
|
||||
virtual void InitSizeEnv( rvEnvParms &env, float duration ) { mSizeEnv.Init( env, duration ); }
|
||||
virtual float *GetInitSize( void ) { return( mSizeEnv.GetStart() ); }
|
||||
virtual float *GetDestSize( void ) { return( mSizeEnv.GetEnd() ); }
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) {}
|
||||
virtual float *GetInitRotation( void ) { return( NULL ); }
|
||||
virtual float *GetDestRotation( void ) { return( NULL ); }
|
||||
|
||||
virtual void AttenuateSize( float atten, rvParticleParms &parms ) { Attenuate( atten, parms, mSizeEnv ); }
|
||||
|
||||
virtual void FinishSpawn( rvBSE *effect, rvSegment *segment, float birthTime, float fraction = 0.0f, const idVec3 &initOffset = vec3_origin, const idMat3 &initAxis = mat3_identity );
|
||||
virtual void GetSpawnInfo( idVec4 &tint, idVec3 &size, idVec3 &rotate ) {}
|
||||
virtual void HandleTiling( rvParticleTemplate *pt );
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time, float override = 1.0f );
|
||||
|
||||
private:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms1Particle mSizeEnv;
|
||||
};
|
||||
|
||||
class sdOrientedLinkedParticle : public rvLinkedParticle
|
||||
{
|
||||
public:
|
||||
virtual bool Render( const rvBSE *effect, rvParticleTemplate *pt, const idMat3 &view, srfTriangles_t* tri, float time, float override = 1.0f );
|
||||
};
|
||||
|
||||
class rvDebrisParticle : public rvParticle
|
||||
{
|
||||
public:
|
||||
friend class rvParticleTemplate;
|
||||
|
||||
virtual rvParticle *GetArrayEntry( int i ) const;
|
||||
virtual int GetArrayIndex( rvParticle *p ) const;
|
||||
|
||||
virtual void EvaluateRotation( rvEnvParms *rotation, const float time, float oneOverDuration, float *dest ) {// { mRotationEnv.Evaluate( time, dest ); }
|
||||
rotation->Evaluate( mRotationEnv, time, oneOverDuration, dest );
|
||||
}
|
||||
|
||||
virtual void InitRotationEnv( rvEnvParms &env, float duration ) { mRotationEnv.Init( env, duration ); }
|
||||
virtual float *GetInitRotation( void ) { return( mRotationEnv.GetStart() ); }
|
||||
virtual float *GetDestRotation( void ) { return( mRotationEnv.GetEnd() ); }
|
||||
|
||||
virtual void ScaleRotation( float constant ) { mRotationEnv.Scale( constant ); }
|
||||
virtual void FinishSpawn( rvBSE *effect, rvSegment *segment, float birthTime, float fraction = 0.0f, const idVec3 &initOffset = vec3_origin, const idMat3 &initAxis = mat3_identity );
|
||||
|
||||
private:
|
||||
// Fixed at spawn time
|
||||
rvEnvParms3Particle mRotationEnv;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
|
||||
struct rvTrailInfo {
|
||||
short mTrailType;
|
||||
byte mStatic;
|
||||
byte mPad;
|
||||
idStr mTrailTypeName;
|
||||
const idMaterial *mTrailMaterial;
|
||||
idVec2 mTrailTime; // Length of trial in seconds
|
||||
idVec2 mTrailCount; // Number of particles in trail
|
||||
float mTrailScale; // Width of the motion trails will be particleSize scaled by this
|
||||
|
||||
rvTrailInfo() : mStatic(0) {
|
||||
}
|
||||
};
|
||||
|
||||
struct rvElectricityInfo {
|
||||
int mNumForks; // Number of forks for
|
||||
byte mStatic;
|
||||
byte mPad;
|
||||
idVec3 mForkSizeMins;
|
||||
idVec3 mForkSizeMaxs;
|
||||
idVec3 mJitterSize; // Amount of jitter for the electricity
|
||||
float mJitterRate;
|
||||
idStr mJitterTableName; // Stable table name used to resolve jitter table pointers
|
||||
const idDeclTable *mJitterTable; // The envelope for the jitter in the lightning bolt
|
||||
|
||||
rvElectricityInfo() : mStatic(0) {
|
||||
}
|
||||
};
|
||||
|
||||
class rvParticleTemplate
|
||||
{
|
||||
public:
|
||||
friend class rvParticle;
|
||||
friend class rvSpriteParticle;
|
||||
friend class rvLineParticle;
|
||||
friend class rvOrientedParticle;
|
||||
friend class rvElectricityParticle;
|
||||
friend class rvModelParticle;
|
||||
friend class rvLightParticle;
|
||||
friend class rvDebrisParticle;
|
||||
friend class rvParticleTemplateWrapper;
|
||||
friend class rvLinkedParticle;
|
||||
friend class sdOrientedLinkedParticle;
|
||||
friend class rvSegmentTemplate;
|
||||
friend class rvSegment;
|
||||
|
||||
rvParticleTemplate( void ) : mFlags(0) { }
|
||||
~rvParticleTemplate( void ) {}
|
||||
|
||||
bool operator== ( const rvParticleTemplate& a ) const { return( Compare( a ) ); }
|
||||
bool operator!= ( const rvParticleTemplate& a ) const { return( !Compare( a ) ); }
|
||||
rvParticleTemplate& operator=(const rvParticleTemplate& __that);
|
||||
|
||||
int GetFlags(void) { return mFlags; }
|
||||
void SetFlag( bool on, int flag ) { on ? mFlags |= flag : mFlags &= ~flag; }
|
||||
bool GetFlag( int flag ) const { return ( mFlags & flag ) != 0; }
|
||||
bool GetParsed( void ) const { return( !!( mFlags & PTFLAG_PARSED ) ); }
|
||||
bool GetHasPhysics( void ) const { return( !!( mFlags & PTFLAG_HAS_PHYSICS ) ); }
|
||||
bool GetHasLineHit( void ) const { return( !!( mFlags & PTFLAG_HAS_LINEHIT ) ); }
|
||||
bool GetDeleteOnImpact( void ) const { return( !!( mFlags & PTFLAG_DELETE_ON_IMPACT ) ); }
|
||||
bool GetGeneratedNormal( void ) const { return( !!( mFlags & PTFLAG_GENERATED_NORMAL ) ); }
|
||||
bool GetGeneratedOriginNormal( void ) const { return( !!( mFlags & PTFLAG_GENERATED_ORG_NORMAL ) ); }
|
||||
bool GetFlippedNormal( void ) const { return( !!( mFlags & PTFLAG_FLIPPED_NORMAL ) ); }
|
||||
bool GetCalculatedNormal( void ) const { return( !!( mFlags & PTFLAG_CALCED_NORMAL ) ); }
|
||||
bool GetAdditive( void ) const { return( !!( mFlags & PTFLAG_ADDITIVE ) ); }
|
||||
bool GetGeneratedLine( void ) const { return( !!( mFlags & PTFLAG_GENERATED_LINE ) ); }
|
||||
bool GetShadows( void ) const { return( !!( mFlags & PTFLAG_SHADOWS ) ); }
|
||||
bool GetSpecular( void ) const { return( !!( mFlags & PTFLAG_SPECULAR ) ); }
|
||||
bool GetLinked( void ) const { return( !!( mFlags & PTFLAG_LINKED ) ); }
|
||||
bool GetTiled( void ) const { return( !!( mFlags & PTFLAG_TILED ) ); }
|
||||
bool GetPersist( void ) const { return( !!( mFlags & PTFLAG_PERSIST ) ); }
|
||||
bool GetParentVelocity( void ) const { return( !!( mFlags & PTFLAG_PARENTVEL ) ); }
|
||||
|
||||
void SetParsed( bool parsed ) { SetFlag( parsed, PTFLAG_PARSED ); }
|
||||
void SetHasPhysics( bool hasPhysics ) { SetFlag( hasPhysics, PTFLAG_HAS_PHYSICS ); }
|
||||
void SetHasLineHit( bool hasLH ) { SetFlag( hasLH, PTFLAG_HAS_LINEHIT ); }
|
||||
void SetDeleteOnImpact( bool deleteOnImpact ) { SetFlag( deleteOnImpact, PTFLAG_DELETE_ON_IMPACT ); }
|
||||
void SetGeneratedNormal( bool generatedNormal ) { SetFlag( generatedNormal, PTFLAG_GENERATED_NORMAL ); }
|
||||
void SetGeneratedOriginNormal( bool generatedNormal ) { SetFlag( generatedNormal, PTFLAG_GENERATED_ORG_NORMAL ); }
|
||||
void SetFlippedNormal( bool flippedNormal ) { SetFlag( flippedNormal, PTFLAG_FLIPPED_NORMAL ); }
|
||||
void SetCalculatedNormal( bool calcedNormal ) { SetFlag( calcedNormal, PTFLAG_CALCED_NORMAL ); }
|
||||
void SetAdditive( bool additive ) { SetFlag( additive, PTFLAG_ADDITIVE ); }
|
||||
void SetGeneratedLine( bool generatedLine ) { SetFlag( generatedLine, PTFLAG_GENERATED_LINE ); }
|
||||
void SetShadows( bool shadows ) { SetFlag( shadows, PTFLAG_SHADOWS ); }
|
||||
void SetSpecular( bool specular ) { SetFlag( specular, PTFLAG_SPECULAR ); }
|
||||
void SetLinked( bool linked ) { SetFlag( linked, PTFLAG_LINKED ); }
|
||||
void SetTiled( bool tiled ) { SetFlag( tiled, PTFLAG_TILED ); }
|
||||
void SetPersist( bool tiled ) { SetFlag( tiled, PTFLAG_PERSIST ); }
|
||||
void SetParentVelocity( bool pv ) { SetFlag( pv, PTFLAG_PARENTVEL ); }
|
||||
|
||||
void SetType( int type ) { mType = type; }
|
||||
int GetType( void ) const { return( mType ); }
|
||||
|
||||
const idMaterial *GetMaterial( void ) const { return( mMaterial ); }
|
||||
void SetMaterial( idMaterial *material ) { mMaterial = material; }
|
||||
|
||||
idRenderModel *GetModel( void ) const { return mModel; }
|
||||
idTraceModel *GetTraceModel( void ) const;
|
||||
|
||||
float GetPhysicsDistance() const { return mPhysicsDistance; }
|
||||
|
||||
const char *GetEntityDefName( void ) const { return( mEntityDefName ); }
|
||||
|
||||
float GetGravity( void ) const { return( rvRandom::flrand( mGravity[0], mGravity[1] ) ); }
|
||||
float GetTiling( void ) const { return( mTiling ); }
|
||||
int GetTrailType( void ) const { return( mTrailInfo->mTrailType ); }
|
||||
const idMaterial *GetTrailMaterial( void ) const { return( mTrailInfo->mTrailMaterial ); }
|
||||
float GetTrailTime( void ) const { return( rvRandom::flrand( mTrailInfo->mTrailTime[0], mTrailInfo->mTrailTime[1] ) ); }
|
||||
float GetMaxTrailTime( void ) const { return( mTrailInfo->mTrailTime[1] ); }
|
||||
int GetTrailCount( void ) const;
|
||||
int GetMaxTrailCount( void ) const { return( ( int )ceilf( mTrailInfo->mTrailCount[1] ) + 1 ); }
|
||||
float GetDuration( void ) const { return( rvRandom::flrand( mDuration[0], mDuration[1] ) ); }
|
||||
float GetMaxDuration( void ) const { return( mDuration[1] ); }
|
||||
int GetNumTimeoutEffects( void ) const { return( mNumTimeoutEffects ); }
|
||||
bool HasTrail( void ) const { return( mTrailInfo->mTrailType && !mTrailInfo->mTrailTypeName.IsEmpty() ); }
|
||||
int GetTrailRepeat( void ) { return mTrailRepeat; }
|
||||
float GetWindDeviationAngle( void ) { return mWindDeviationAngle; }
|
||||
int GetNumFrames( void ) { return mNumFrames; }
|
||||
|
||||
int GetVertexCount( void ) const { return( mVertexCount ); }
|
||||
int GetIndexCount( void ) const { return( mIndexCount ); }
|
||||
|
||||
float GetMaxParmValue( rvParticleParms &spawn, rvParticleParms &death, rvEnvParms &envelope );
|
||||
float GetMaxSize( void );
|
||||
float GetMaxOffset( void );
|
||||
float GetMaxLength( void );
|
||||
void EvaluateSimplePosition( idVec3 &pos, float time, float lifeTime, idVec3 &initPos, idVec3 &velocity, idVec3 &acceleration, idVec3 &friction );
|
||||
float GetFurthestDistance( void );
|
||||
float CostTrail( float cost ) const;
|
||||
const idStr &GetTrailTypeName( void ) const { return( mTrailInfo->mTrailTypeName ); }
|
||||
float GetTrailScale( void ) const { return mTrailInfo->mTrailScale; }
|
||||
float GetSpawnVolume( rvBSE *effect );
|
||||
bool UsesEndOrigin( void );
|
||||
bool GetVector( idParser *src, int count, idVec3 &result );
|
||||
void SetParameterCounts( void );
|
||||
rvEnvParms* ParseMotionParms( idParser *src, int count, rvEnvParms *def );
|
||||
rvParticleParms* ParseSpawnParms( rvDeclEffect *effect, idParser *src, int count, rvParticleParms *def );
|
||||
bool ParseMotionDomains( rvDeclEffect *effect, idParser *src );
|
||||
bool CheckCommonParms( idParser *src, rvParticleParms &parms );
|
||||
bool ParseSpawnDomains( rvDeclEffect *effect, idParser *src );
|
||||
bool ParseDeathDomains( rvDeclEffect *effect, idParser *src );
|
||||
bool ParseImpact( rvDeclEffect *effect, idParser *src );
|
||||
bool ParseTimeout( rvDeclEffect *effect, idParser *src );
|
||||
bool ParseBlendParms( rvDeclEffect *effect, idParser *src );
|
||||
bool Parse( rvDeclEffect *effect, idParser *src );
|
||||
void Init( void );
|
||||
void Finish( void );
|
||||
void Purge( void );
|
||||
void PurgeTraceModel( void );
|
||||
|
||||
void MakeEditable( void );
|
||||
static void ShutdownStatic( void );
|
||||
void Duplicate( rvParticleTemplate const © );
|
||||
private:
|
||||
bool Compare( const rvParticleTemplate& a ) const;
|
||||
void FixupParms( rvParticleParms *parms );
|
||||
void AllocTrail( void );
|
||||
void AllocElectricityInfo( void );
|
||||
|
||||
int mFlags;
|
||||
int mTraceModelIndex;
|
||||
int mType; // Type of particle
|
||||
|
||||
const idMaterial *mMaterial;
|
||||
idRenderModel *mModel;
|
||||
|
||||
//idStr mModelName;
|
||||
idStr mEntityDefName;
|
||||
|
||||
idVec2 mGravity;
|
||||
idVec2 mDuration;
|
||||
idVec3 mCentre; // Centre of bounds for normal generation
|
||||
|
||||
float mTiling; // Multiplier for texcoords
|
||||
float mBounce;
|
||||
float mPhysicsDistance;
|
||||
float mWindDeviationAngle;
|
||||
|
||||
short mVertexCount;
|
||||
short mIndexCount;
|
||||
|
||||
byte mTrailRepeat;
|
||||
byte mNumSizeParms;
|
||||
byte mNumRotateParms;
|
||||
byte mNumFrames;
|
||||
|
||||
rvTrailInfo *mTrailInfo;
|
||||
|
||||
rvElectricityInfo *mElecInfo;
|
||||
// Spawn info
|
||||
rvParticleParms *mpSpawnPosition;
|
||||
rvParticleParms *mpSpawnDirection;
|
||||
rvParticleParms *mpSpawnVelocity;
|
||||
rvParticleParms *mpSpawnAcceleration;
|
||||
rvParticleParms *mpSpawnFriction;
|
||||
rvParticleParms *mpSpawnTint;
|
||||
rvParticleParms *mpSpawnFade;
|
||||
rvParticleParms *mpSpawnSize;
|
||||
rvParticleParms *mpSpawnRotate;
|
||||
rvParticleParms *mpSpawnAngle;
|
||||
rvParticleParms *mpSpawnOffset;
|
||||
rvParticleParms *mpSpawnLength;
|
||||
rvParticleParms *mpSpawnWindStrength;
|
||||
|
||||
// Motion info
|
||||
rvEnvParms *mpTintEnvelope;
|
||||
rvEnvParms *mpFadeEnvelope;
|
||||
rvEnvParms *mpSizeEnvelope;
|
||||
rvEnvParms *mpRotateEnvelope;
|
||||
rvEnvParms *mpAngleEnvelope;
|
||||
rvEnvParms *mpOffsetEnvelope;
|
||||
rvEnvParms *mpLengthEnvelope;
|
||||
|
||||
// Death (end condition) info
|
||||
rvParticleParms *mpDeathTint;
|
||||
rvParticleParms *mpDeathFade;
|
||||
rvParticleParms *mpDeathSize;
|
||||
rvParticleParms *mpDeathRotate;
|
||||
rvParticleParms *mpDeathAngle;
|
||||
rvParticleParms *mpDeathOffset;
|
||||
rvParticleParms *mpDeathLength;
|
||||
|
||||
// Misc info
|
||||
int mNumImpactEffects;
|
||||
const rvDeclEffect *mImpactEffects[BSE_NUM_SPAWNABLE];
|
||||
int mNumTimeoutEffects;
|
||||
const rvDeclEffect *mTimeoutEffects[BSE_NUM_SPAWNABLE];
|
||||
|
||||
static rvTrailInfo sTrailInfo;
|
||||
static rvElectricityInfo sElectricityInfo;
|
||||
|
||||
// Motion info
|
||||
static rvEnvParms sDefaultEnvelope;
|
||||
static rvEnvParms sEmptyEnvelope;
|
||||
|
||||
static rvParticleParms sSPF_ONE_1;
|
||||
static rvParticleParms sSPF_ONE_2;
|
||||
static rvParticleParms sSPF_ONE_3;
|
||||
static rvParticleParms sSPF_NONE_0;
|
||||
static rvParticleParms sSPF_NONE_1;
|
||||
static rvParticleParms sSPF_NONE_3;
|
||||
|
||||
static bool sInited;
|
||||
static void InitStatic( void );
|
||||
};
|
||||
|
||||
#endif //_BSE_PARTICLE_H_INC_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,528 @@
|
||||
// Copyright (C) 2007 Id Software, Inc.
|
||||
//
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE.h"
|
||||
|
||||
|
||||
namespace {
|
||||
rvParticle* AllocateParticleArray(int particleType, int count) {
|
||||
if (count <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (particleType) {
|
||||
case PTYPE_LINE:
|
||||
return static_cast<rvParticle*>(new rvLineParticle[count]);
|
||||
case PTYPE_ORIENTED:
|
||||
return static_cast<rvParticle*>(new rvOrientedParticle[count]);
|
||||
case PTYPE_DECAL:
|
||||
return static_cast<rvParticle*>(new rvDecalParticle[count]);
|
||||
case PTYPE_MODEL:
|
||||
return static_cast<rvParticle*>(new rvModelParticle[count]);
|
||||
case PTYPE_LIGHT:
|
||||
return static_cast<rvParticle*>(new rvLightParticle[count]);
|
||||
case PTYPE_ELECTRICITY:
|
||||
return static_cast<rvParticle*>(new rvElectricityParticle[count]);
|
||||
case PTYPE_LINKED:
|
||||
return static_cast<rvParticle*>(new rvLinkedParticle[count]);
|
||||
case PTYPE_ORIENTEDLINKED:
|
||||
return static_cast<rvParticle*>(new sdOrientedLinkedParticle[count]);
|
||||
case PTYPE_DEBRIS:
|
||||
return static_cast<rvParticle*>(new rvDebrisParticle[count]);
|
||||
default:
|
||||
return static_cast<rvParticle*>(new rvSpriteParticle[count]);
|
||||
}
|
||||
}
|
||||
|
||||
ID_INLINE void InsertByEndTime(rvParticle*& head, rvParticle* particle) {
|
||||
rvParticle* prev = NULL;
|
||||
rvParticle* cur = head;
|
||||
while (cur && particle->GetEndTime() > cur->GetEndTime()) {
|
||||
prev = cur;
|
||||
cur = cur->GetNext();
|
||||
}
|
||||
particle->SetNext(cur);
|
||||
if (prev) {
|
||||
prev->SetNext(particle);
|
||||
}
|
||||
else {
|
||||
head = particle;
|
||||
}
|
||||
}
|
||||
|
||||
ID_INLINE int GetSegmentParticleCap() {
|
||||
return idMath::ClampInt(0, MAX_PARTICLES, bse_maxParticles.GetInteger());
|
||||
}
|
||||
|
||||
ID_INLINE bool BSESpawnTraceEnabled() {
|
||||
return cvarSystem && cvarSystem->GetCVarInteger("bse_frameCounters") >= 2;
|
||||
}
|
||||
|
||||
ID_INLINE void BSE_BoundTriSurf(srfTriangles_t* tri) {
|
||||
if (!tri) {
|
||||
return;
|
||||
}
|
||||
if (tri->numVerts <= 0 || !tri->verts) {
|
||||
tri->bounds.Clear();
|
||||
return;
|
||||
}
|
||||
tri->bounds.Clear();
|
||||
for (int i = 0; i < tri->numVerts; ++i) {
|
||||
tri->bounds.AddPoint(tri->verts[i].xyz);
|
||||
}
|
||||
}
|
||||
|
||||
void BSESpawnTrace(const char* fmt, ...) {
|
||||
static int spawnTraceCount = 0;
|
||||
if (spawnTraceCount >= 256) {
|
||||
return;
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
common->VPrintf(fmt, ap);
|
||||
va_end(ap);
|
||||
++spawnTraceCount;
|
||||
}
|
||||
}
|
||||
|
||||
void rvSegment::PlayEffect(rvBSE* effect, rvSegmentTemplate* st, float depthOffset) {
|
||||
if (!effect || !st || st->mNumEffects <= 0 || !game) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int index = rvRandom::irand(0, st->mNumEffects - 1);
|
||||
const rvDeclEffect* nested = st->mEffects[index];
|
||||
if (!nested) {
|
||||
return;
|
||||
}
|
||||
|
||||
game->PlayEffect(
|
||||
nested,
|
||||
effect->GetCurrentOrigin(),
|
||||
effect->GetCurrentAxis(),
|
||||
false,
|
||||
effect->GetHasEndOrigin() ? effect->GetCurrentEndOrigin() : vec3_origin,
|
||||
false,
|
||||
false,
|
||||
EC_IGNORE,
|
||||
vec4_one);
|
||||
}
|
||||
|
||||
rvParticle* rvSegment::InitParticleArray(rvBSE* effect) {
|
||||
if (!effect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mParticles) {
|
||||
switch (mParticleType) {
|
||||
case PTYPE_LINE:
|
||||
delete[] static_cast<rvLineParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_ORIENTED:
|
||||
delete[] static_cast<rvOrientedParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_DECAL:
|
||||
delete[] static_cast<rvDecalParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_MODEL:
|
||||
delete[] static_cast<rvModelParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_LIGHT:
|
||||
delete[] static_cast<rvLightParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_ELECTRICITY:
|
||||
delete[] static_cast<rvElectricityParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_LINKED:
|
||||
delete[] static_cast<rvLinkedParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_ORIENTEDLINKED:
|
||||
delete[] static_cast<sdOrientedLinkedParticle*>(mParticles);
|
||||
break;
|
||||
case PTYPE_DEBRIS:
|
||||
delete[] static_cast<rvDebrisParticle*>(mParticles);
|
||||
break;
|
||||
default:
|
||||
delete[] static_cast<rvSpriteParticle*>(mParticles);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mParticles = NULL;
|
||||
mFreeHead = NULL;
|
||||
mUsedHead = NULL;
|
||||
|
||||
const rvSegmentTemplate* st = GetSegmentTemplate();
|
||||
const int requestedCount = effect->GetLooping() ? mLoopParticleCount : mParticleCount;
|
||||
int particleCount = requestedCount;
|
||||
const int particleCap = GetSegmentParticleCap();
|
||||
if (particleCount > particleCap) {
|
||||
common->Warning("^4BSE:^1 '%s' exceeded particle cap (%d > %d), clamping", effect->GetDeclName(), particleCount, particleCap);
|
||||
}
|
||||
particleCount = idMath::ClampInt(0, particleCap, particleCount);
|
||||
if (particleCount <= 0) {
|
||||
if (BSESpawnTraceEnabled()) {
|
||||
BSESpawnTrace(
|
||||
"BSE spawn init: decl=%s segType=%d pType=%d handle=%d particleCount=%d loopCount=%d (clamped<=0)\n",
|
||||
effect ? effect->GetDeclName() : "<null>",
|
||||
st ? st->GetType() : -1,
|
||||
st ? st->GetParticleTemplate()->GetType() : -1,
|
||||
mSegmentTemplateHandle,
|
||||
mParticleCount,
|
||||
mLoopParticleCount);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mParticles = AllocateParticleArray(mParticleType, particleCount);
|
||||
if (!mParticles) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < particleCount - 1; ++i) {
|
||||
rvParticle* cur = mParticles->GetArrayEntry(i);
|
||||
rvParticle* next = mParticles->GetArrayEntry(i + 1);
|
||||
cur->SetNext(next);
|
||||
}
|
||||
mParticles->GetArrayEntry(particleCount - 1)->SetNext(NULL);
|
||||
|
||||
mFreeHead = mParticles;
|
||||
mUsedHead = NULL;
|
||||
return mParticles;
|
||||
}
|
||||
|
||||
rvParticle* rvSegment::GetFreeParticle(rvBSE* effect) {
|
||||
rvSegmentTemplate* st = GetSegmentTemplate();
|
||||
if (!st) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Decal/effect paths can request a spawn before explicit segment particle
|
||||
// initialization runs. Lazily allocate from precomputed counts so authored
|
||||
// spawn data (size/rotation/tint) is available instead of default fallbacks.
|
||||
if (mParticles == NULL) {
|
||||
InitParticleArray(effect);
|
||||
}
|
||||
if (mParticles == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rvParticle* particle = NULL;
|
||||
if (st->GetTemporary()) {
|
||||
particle = mParticles;
|
||||
if (particle) {
|
||||
particle->SetNext(NULL);
|
||||
}
|
||||
}
|
||||
else {
|
||||
particle = mFreeHead;
|
||||
if (!particle) {
|
||||
return NULL;
|
||||
}
|
||||
mFreeHead = particle->GetNext();
|
||||
particle->SetNext(NULL);
|
||||
}
|
||||
|
||||
return particle;
|
||||
}
|
||||
|
||||
rvParticle* rvSegment::SpawnParticle(rvBSE* effect, rvSegmentTemplate* st, float birthTime, const idVec3& initOffset, const idMat3& initAxis) {
|
||||
if (!effect || !st) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rvParticle* particle = GetFreeParticle(effect);
|
||||
if (!particle) {
|
||||
if (BSESpawnTraceEnabled()) {
|
||||
BSESpawnTrace(
|
||||
"BSE spawn miss: decl=%s segType=%d handle=%d birth=%.4f freeHead=null particleCount=%d loopCount=%d\n",
|
||||
effect ? effect->GetDeclName() : "<null>",
|
||||
st ? st->GetType() : -1,
|
||||
mSegmentTemplateHandle,
|
||||
birthTime,
|
||||
mParticleCount,
|
||||
mLoopParticleCount);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const float fraction = birthTime - effect->GetStartTime();
|
||||
particle->FinishSpawn(effect, this, birthTime, fraction, initOffset, initAxis);
|
||||
BSE_AddSpawned(1);
|
||||
if (BSESpawnTraceEnabled()) {
|
||||
BSESpawnTrace(
|
||||
"BSE spawn ok: decl=%s segType=%d pType=%d handle=%d birth=%.4f end=%.4f dur=%.4f fraction=%.4f\n",
|
||||
effect ? effect->GetDeclName() : "<null>",
|
||||
st ? st->GetType() : -1,
|
||||
st ? st->GetParticleTemplate()->GetType() : -1,
|
||||
mSegmentTemplateHandle,
|
||||
birthTime,
|
||||
particle->GetEndTime(),
|
||||
particle->GetDuration(),
|
||||
fraction);
|
||||
}
|
||||
|
||||
const int type = st->mParticleTemplate.GetType();
|
||||
const bool linked = (type == PTYPE_LINKED || type == PTYPE_ORIENTEDLINKED);
|
||||
if (st->GetTemporary()) {
|
||||
mUsedHead = particle;
|
||||
particle->SetNext(NULL);
|
||||
}
|
||||
else if (linked || !st->GetComplexParticle()) {
|
||||
InsertByEndTime(mUsedHead, particle);
|
||||
}
|
||||
else {
|
||||
particle->SetNext(mUsedHead);
|
||||
mUsedHead = particle;
|
||||
}
|
||||
|
||||
return particle;
|
||||
}
|
||||
|
||||
void rvSegment::SpawnParticles(rvBSE* effect, rvSegmentTemplate* st, float birthTime, int count) {
|
||||
if (!effect || !st || count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rvParticle* particle = GetFreeParticle(effect);
|
||||
if (!particle) {
|
||||
if (BSESpawnTraceEnabled()) {
|
||||
BSESpawnTrace(
|
||||
"BSE spawn batch miss: decl=%s segType=%d handle=%d birth=%.4f idx=%d count=%d freeHead=null particleCount=%d loopCount=%d\n",
|
||||
effect ? effect->GetDeclName() : "<null>",
|
||||
st ? st->GetType() : -1,
|
||||
mSegmentTemplateHandle,
|
||||
birthTime,
|
||||
i,
|
||||
count,
|
||||
mParticleCount,
|
||||
mLoopParticleCount);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
float fraction = 0.0f;
|
||||
if (count > 0) {
|
||||
fraction = static_cast<float>(i) / static_cast<float>(count);
|
||||
}
|
||||
particle->FinishSpawn(effect, this, birthTime, fraction, vec3_origin, mat3_identity);
|
||||
BSE_AddSpawned(1);
|
||||
if (BSESpawnTraceEnabled()) {
|
||||
BSESpawnTrace(
|
||||
"BSE spawn batch ok: decl=%s segType=%d pType=%d handle=%d birth=%.4f idx=%d count=%d end=%.4f dur=%.4f fraction=%.4f\n",
|
||||
effect ? effect->GetDeclName() : "<null>",
|
||||
st ? st->GetType() : -1,
|
||||
st ? st->GetParticleTemplate()->GetType() : -1,
|
||||
mSegmentTemplateHandle,
|
||||
birthTime,
|
||||
i,
|
||||
count,
|
||||
particle->GetEndTime(),
|
||||
particle->GetDuration(),
|
||||
fraction);
|
||||
}
|
||||
|
||||
const int type = st->mParticleTemplate.GetType();
|
||||
const bool linked = (type == PTYPE_LINKED || type == PTYPE_ORIENTEDLINKED);
|
||||
if (st->GetTemporary()) {
|
||||
mUsedHead = particle;
|
||||
particle->SetNext(NULL);
|
||||
}
|
||||
else if (linked || !st->GetComplexParticle()) {
|
||||
InsertByEndTime(mUsedHead, particle);
|
||||
}
|
||||
else {
|
||||
particle->SetNext(mUsedHead);
|
||||
mUsedHead = particle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rvSegment::UpdateSimpleParticles(float time) {
|
||||
rvSegmentTemplate* st = GetSegmentTemplate();
|
||||
if (!st) {
|
||||
mActiveCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
rvParticle* prev = NULL;
|
||||
rvParticle* p = mUsedHead;
|
||||
mActiveCount = 0;
|
||||
|
||||
while (p) {
|
||||
rvParticle* next = p->GetNext();
|
||||
if (p->GetEndTime() - BSE_TIME_EPSILON > time) {
|
||||
mActiveCount += p->Update(&st->mParticleTemplate, time);
|
||||
prev = p;
|
||||
}
|
||||
else {
|
||||
if (prev) {
|
||||
prev->SetNext(next);
|
||||
}
|
||||
else {
|
||||
mUsedHead = next;
|
||||
}
|
||||
p->SetNext(mFreeHead);
|
||||
p->Destroy();
|
||||
mFreeHead = p;
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
|
||||
void rvSegment::UpdateGenericParticles(rvBSE* effect, rvSegmentTemplate* st, float time) {
|
||||
if (!effect || !st) {
|
||||
mActiveCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool infinite = st->GetInfiniteDuration();
|
||||
const bool smoker = st->GetSmoker();
|
||||
|
||||
rvParticle* prev = NULL;
|
||||
rvParticle* p = mUsedHead;
|
||||
mActiveCount = 0;
|
||||
|
||||
while (p) {
|
||||
rvParticle* next = p->GetNext();
|
||||
bool remove = false;
|
||||
|
||||
if (infinite) {
|
||||
p->RunPhysics(effect, st, time);
|
||||
remove = effect->GetStopped();
|
||||
}
|
||||
else {
|
||||
if (p->GetEndTime() - BSE_TIME_EPSILON <= time) {
|
||||
p->CheckTimeoutEffect(effect, st, time);
|
||||
remove = true;
|
||||
}
|
||||
else {
|
||||
remove = p->RunPhysics(effect, st, time);
|
||||
}
|
||||
}
|
||||
|
||||
if (effect->GetStopped() && (p->GetFlags() & PTFLAG_PERSIST) == 0) {
|
||||
remove = true;
|
||||
}
|
||||
|
||||
if (smoker && st->mTrailSegmentIndex >= 0) {
|
||||
rvSegment* trail = effect->GetTrailSegment(st->mTrailSegmentIndex);
|
||||
if (trail) {
|
||||
p->EmitSmokeParticles(effect, trail, &st->mParticleTemplate, time);
|
||||
}
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
if (prev) {
|
||||
prev->SetNext(next);
|
||||
}
|
||||
else {
|
||||
mUsedHead = next;
|
||||
}
|
||||
p->SetNext(mFreeHead);
|
||||
p->Destroy();
|
||||
mFreeHead = p;
|
||||
}
|
||||
else {
|
||||
mActiveCount += p->Update(st->GetParticleTemplate(), time);
|
||||
prev = p;
|
||||
}
|
||||
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
|
||||
void rvSegment::AddToParticleCount(rvBSE* effect, int count, int loopCount, float duration) {
|
||||
rvSegmentTemplate* st = GetSegmentTemplate();
|
||||
if (!st) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (duration < st->mParticleTemplate.GetMaxDuration()) {
|
||||
duration = st->mParticleTemplate.GetMaxDuration();
|
||||
}
|
||||
|
||||
const float countDuration = duration + 0.016f;
|
||||
if (mSecondsPerParticle.y > BSE_TIME_EPSILON) {
|
||||
const int mult = static_cast<int>(ceilf(countDuration / mSecondsPerParticle.y)) + 1;
|
||||
mLoopParticleCount += loopCount * mult;
|
||||
mParticleCount += count * mult;
|
||||
}
|
||||
else {
|
||||
mLoopParticleCount += loopCount;
|
||||
mParticleCount += count;
|
||||
}
|
||||
|
||||
const int particleCap = GetSegmentParticleCap();
|
||||
mParticleCount = idMath::ClampInt(0, particleCap, mParticleCount);
|
||||
mLoopParticleCount = idMath::ClampInt(0, particleCap, mLoopParticleCount);
|
||||
}
|
||||
|
||||
void rvSegment::CalcTrailCounts(rvBSE* effect, rvSegmentTemplate* st, rvParticleTemplate* pt, float duration) {
|
||||
if (!effect || !st || !pt) {
|
||||
return;
|
||||
}
|
||||
if (st->mTrailSegmentIndex >= 0) {
|
||||
rvSegment* trail = effect->GetTrailSegment(st->mTrailSegmentIndex);
|
||||
if (trail) {
|
||||
trail->AddToParticleCount(effect, mParticleCount, mLoopParticleCount, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rvSegment::RenderMotion(rvBSE* effect, const renderEffect_s* owner, idRenderModel* model, rvParticleTemplate* pt, float time) {
|
||||
if (!effect || !owner || !model || !pt || mSurfaceIndex < 0) {
|
||||
return;
|
||||
}
|
||||
if (mSurfaceIndex + 1 >= model->NumSurfaces()) {
|
||||
return;
|
||||
}
|
||||
|
||||
srfTriangles_t* tri = model->Surface(mSurfaceIndex + 1)->geometry;
|
||||
if (!tri) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (rvParticle* p = mUsedHead; p; p = p->GetNext()) {
|
||||
p->RenderMotion(effect, pt, tri, owner, time);
|
||||
}
|
||||
|
||||
BSE_BoundTriSurf(tri);
|
||||
}
|
||||
|
||||
void rvSegment::Sort(const idVec3& eyePos) {
|
||||
if (!mUsedHead || !mUsedHead->GetNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
rvParticle* sorted = NULL;
|
||||
rvParticle* particle = mUsedHead;
|
||||
while (particle) {
|
||||
rvParticle* next = particle->GetNext();
|
||||
const float dist = particle->UpdateViewDist(eyePos);
|
||||
|
||||
if (!sorted || dist > sorted->UpdateViewDist(eyePos)) {
|
||||
particle->SetNext(sorted);
|
||||
sorted = particle;
|
||||
}
|
||||
else {
|
||||
rvParticle* insertAfter = sorted;
|
||||
while (insertAfter->GetNext()) {
|
||||
rvParticle* compare = insertAfter->GetNext();
|
||||
if (dist > compare->UpdateViewDist(eyePos)) {
|
||||
break;
|
||||
}
|
||||
insertAfter = compare;
|
||||
}
|
||||
particle->SetNext(insertAfter->GetNext());
|
||||
insertAfter->SetNext(particle);
|
||||
}
|
||||
|
||||
particle = next;
|
||||
}
|
||||
|
||||
mUsedHead = sorted;
|
||||
}
|
||||
@@ -0,0 +1,645 @@
|
||||
// BSE_SegmentTemplate.cpp
|
||||
//
|
||||
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE.h"
|
||||
|
||||
void rvSegmentTemplate::CreateParticleTemplate(rvDeclEffect* effect, idParser* src, int particleType)
|
||||
{
|
||||
mParticleTemplate.Init();
|
||||
mParticleTemplate.mType = particleType;
|
||||
mParticleTemplate.SetParameterCounts();
|
||||
mParticleTemplate.Parse(effect, src);
|
||||
}
|
||||
|
||||
bool rvSegmentTemplate::GetSoundLooping()
|
||||
{
|
||||
if (mSoundShader != NULL) {
|
||||
return ((unsigned int)mSoundShader->GetParms()->soundShaderFlags >> 5) & 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void rvSegmentTemplate::EvaluateTrailSegment(rvDeclEffect* et) {
|
||||
if (mParticleTemplate.mTrailInfo->mTrailType && !mParticleTemplate.mTrailInfo->mTrailTypeName.IsEmpty())
|
||||
{
|
||||
// jmarshall - WindowName isn't defined and doesn't make sense here
|
||||
// if (idStr::Cmp(v3->mTrailTypeName.data, (const char*)&WindowName))
|
||||
// jmarshall end
|
||||
{
|
||||
mTrailSegmentIndex = et->GetTrailSegmentIndex(mParticleTemplate.mTrailInfo->mTrailTypeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rvSegmentTemplate::GetSmoker()
|
||||
{
|
||||
return mParticleTemplate.mTrailInfo->mTrailType == 3;
|
||||
}
|
||||
|
||||
bool rvSegmentTemplate::DetailCull() const
|
||||
{
|
||||
return (mDetail > 0.0f) && (cvarSystem->GetCVarFloat("bse_scale") < mDetail);
|
||||
}
|
||||
|
||||
float rvSegmentTemplate::CalculateBounds(void)
|
||||
{
|
||||
switch (mSegType)
|
||||
{
|
||||
case SEG_EMITTER:
|
||||
case SEG_SPAWNER:
|
||||
case SEG_TRAIL: {
|
||||
const float maxSize = mParticleTemplate.GetMaxSize();
|
||||
const float maxDist = mParticleTemplate.GetFurthestDistance();
|
||||
float maxLength = 0.0f;
|
||||
const int particleType = mParticleTemplate.GetType();
|
||||
if (particleType == PTYPE_LINE || particleType == PTYPE_ELECTRICITY) {
|
||||
maxLength = mParticleTemplate.GetMaxLength();
|
||||
}
|
||||
return maxSize + maxDist + maxLength + mParticleTemplate.GetMaxOffset();
|
||||
}
|
||||
case SEG_LIGHT:
|
||||
return mParticleTemplate.GetMaxSize();
|
||||
default:
|
||||
return 8.0f;
|
||||
}
|
||||
}
|
||||
|
||||
bool rvSegmentTemplate::Compare(const rvSegmentTemplate& a) const
|
||||
{
|
||||
if (mSegmentName.Icmp(a.mSegmentName) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((mFlags ^ a.mFlags) & ~STFLAG_LOCKED) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSegType != a.mSegType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sound segments intentionally ignore local time ranges.
|
||||
if (mSegType != SEG_SOUND) {
|
||||
if (mLocalStartTime != a.mLocalStartTime || mLocalDuration != a.mLocalDuration) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mScale != a.mScale || mDetail != a.mDetail || mAttenuation != a.mAttenuation) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDensity.y == 0.0f) {
|
||||
if (mCount != a.mCount) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mDensity != a.mDensity || mParticleCap != a.mParticleCap) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mTrailSegmentIndex != a.mTrailSegmentIndex || mNumEffects != a.mNumEffects) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mNumEffects; ++i) {
|
||||
if (mEffects[i] != a.mEffects[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mSoundShader != a.mSoundShader || mSoundVolume != a.mSoundVolume || mFreqShift != a.mFreqShift) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mParticleTemplate == a.mParticleTemplate;
|
||||
}
|
||||
|
||||
float rvSegmentTemplate::EvaluateCost(int activeParticles) const
|
||||
{
|
||||
float v4; // [esp+8h] [ebp-4h]
|
||||
float activeParticlesa; // [esp+10h] [ebp+4h]
|
||||
|
||||
if ((mFlags & 1) == 0)
|
||||
return 0.0;
|
||||
v4 = rvSegmentTemplate::mSegmentBaseCosts[mSegType];
|
||||
if (mParticleTemplate.mType)
|
||||
{
|
||||
activeParticlesa = (float)activeParticles;
|
||||
v4 = mParticleTemplate.CostTrail(activeParticlesa) + v4;
|
||||
if ((mParticleTemplate.mFlags & 0x200) != 0)
|
||||
v4 = activeParticlesa * 80.0 + v4;
|
||||
}
|
||||
return v4;
|
||||
}
|
||||
|
||||
rvParticleTemplate& rvParticleTemplate::operator=(const rvParticleTemplate& __that)
|
||||
{
|
||||
mFlags = __that.mFlags;
|
||||
mTraceModelIndex = __that.mTraceModelIndex;
|
||||
mType = __that.mType;
|
||||
mMaterial = __that.mMaterial;
|
||||
mModel = __that.mModel;
|
||||
mEntityDefName = __that.mEntityDefName;
|
||||
mGravity = __that.mGravity;
|
||||
mDuration = __that.mDuration;
|
||||
mCentre = __that.mCentre;
|
||||
mTiling = __that.mTiling;
|
||||
mBounce = __that.mBounce;
|
||||
mPhysicsDistance = __that.mPhysicsDistance;
|
||||
mWindDeviationAngle = __that.mWindDeviationAngle;
|
||||
mVertexCount = __that.mVertexCount;
|
||||
mIndexCount = __that.mIndexCount;
|
||||
mTrailRepeat = __that.mTrailRepeat;
|
||||
mNumSizeParms = __that.mNumSizeParms;
|
||||
mNumRotateParms = __that.mNumRotateParms;
|
||||
mNumFrames = __that.mNumFrames;
|
||||
mTrailInfo = __that.mTrailInfo;
|
||||
mElecInfo = __that.mElecInfo;
|
||||
mpSpawnPosition = __that.mpSpawnPosition;
|
||||
mpSpawnDirection = __that.mpSpawnDirection;
|
||||
mpSpawnVelocity = __that.mpSpawnVelocity;
|
||||
mpSpawnAcceleration = __that.mpSpawnAcceleration;
|
||||
mpSpawnFriction = __that.mpSpawnFriction;
|
||||
mpSpawnTint = __that.mpSpawnTint;
|
||||
mpSpawnFade = __that.mpSpawnFade;
|
||||
mpSpawnSize = __that.mpSpawnSize;
|
||||
mpSpawnRotate = __that.mpSpawnRotate;
|
||||
mpSpawnAngle = __that.mpSpawnAngle;
|
||||
mpSpawnOffset = __that.mpSpawnOffset;
|
||||
mpSpawnLength = __that.mpSpawnLength;
|
||||
mpSpawnWindStrength = __that.mpSpawnWindStrength;
|
||||
mpTintEnvelope = __that.mpTintEnvelope;
|
||||
mpFadeEnvelope = __that.mpFadeEnvelope;
|
||||
mpSizeEnvelope = __that.mpSizeEnvelope;
|
||||
mpRotateEnvelope = __that.mpRotateEnvelope;
|
||||
mpAngleEnvelope = __that.mpAngleEnvelope;
|
||||
mpOffsetEnvelope = __that.mpOffsetEnvelope;
|
||||
mpLengthEnvelope = __that.mpLengthEnvelope;
|
||||
mpDeathTint = __that.mpDeathTint;
|
||||
mpDeathFade = __that.mpDeathFade;
|
||||
mpDeathSize = __that.mpDeathSize;
|
||||
mpDeathRotate = __that.mpDeathRotate;
|
||||
mpDeathAngle = __that.mpDeathAngle;
|
||||
mpDeathOffset = __that.mpDeathOffset;
|
||||
mpDeathLength = __that.mpDeathLength;
|
||||
mNumImpactEffects = __that.mNumImpactEffects;
|
||||
mImpactEffects[0] = __that.mImpactEffects[0];
|
||||
mImpactEffects[1] = __that.mImpactEffects[1];
|
||||
mImpactEffects[2] = __that.mImpactEffects[2];
|
||||
mImpactEffects[3] = __that.mImpactEffects[3];
|
||||
mNumTimeoutEffects = __that.mNumTimeoutEffects;
|
||||
mTimeoutEffects[0] = __that.mTimeoutEffects[0];
|
||||
mTimeoutEffects[1] = __that.mTimeoutEffects[1];
|
||||
mTimeoutEffects[2] = __that.mTimeoutEffects[2];
|
||||
mTimeoutEffects[3] = __that.mTimeoutEffects[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
void rvSegmentTemplate::Duplicate(const rvSegmentTemplate& copy)
|
||||
{
|
||||
mDeclEffect = copy.mDeclEffect;
|
||||
mSegmentName = copy.mSegmentName;
|
||||
mFlags = copy.mFlags;
|
||||
mSegType = copy.mSegType;
|
||||
mLocalStartTime = copy.mLocalStartTime;
|
||||
mLocalDuration = copy.mLocalDuration;
|
||||
mScale = copy.mScale;
|
||||
mAttenuation = copy.mAttenuation;
|
||||
mParticleCap = copy.mParticleCap;
|
||||
mScale = copy.mScale;
|
||||
mDetail = copy.mDetail;
|
||||
mCount = copy.mCount;
|
||||
mDensity = copy.mDensity;
|
||||
mTrailSegmentIndex = copy.mTrailSegmentIndex;
|
||||
mNumEffects = copy.mNumEffects;
|
||||
mEffects[0] = copy.mEffects[0];
|
||||
mEffects[1] = copy.mEffects[1];
|
||||
mEffects[2] = copy.mEffects[2];
|
||||
mEffects[3] = copy.mEffects[3];
|
||||
mSoundShader = copy.mSoundShader;
|
||||
mSoundVolume = copy.mSoundVolume;
|
||||
mFreqShift = copy.mFreqShift;
|
||||
mParticleTemplate.Duplicate(copy.mParticleTemplate);
|
||||
mDecalAxis = copy.mDecalAxis;
|
||||
}
|
||||
|
||||
void rvSegmentTemplate::Init(rvDeclEffect* decl)
|
||||
{
|
||||
mDeclEffect = decl;
|
||||
mSegmentName = "";
|
||||
mFlags = STFLAG_ENABLED;
|
||||
mSegType = SEG_NONE;
|
||||
mLocalStartTime.Zero();
|
||||
mLocalDuration.Zero();
|
||||
mAttenuation.Zero();
|
||||
mParticleCap = 0.0f;
|
||||
mScale = 1.0f;
|
||||
mDetail = 0.0f;
|
||||
mCount.Set(1.0f, 1.0f);
|
||||
mDensity.Zero();
|
||||
mTrailSegmentIndex = -1;
|
||||
mNumEffects = 0;
|
||||
for (int i = 0; i < BSE_NUM_SPAWNABLE; ++i) {
|
||||
mEffects[i] = NULL;
|
||||
}
|
||||
mSoundShader = NULL;
|
||||
mSoundVolume.Zero();
|
||||
mFreqShift.Set(1.0f, 1.0f);
|
||||
mDecalAxis = 0;
|
||||
mParticleTemplate.Init();
|
||||
}
|
||||
|
||||
|
||||
void rvSegmentTemplate::SetMinDuration(rvDeclEffect* effect)
|
||||
{
|
||||
const idSoundShader* v2; // eax
|
||||
float duration; // [esp+4h] [ebp-4h]
|
||||
|
||||
if ((mFlags & 0x10) == 0)
|
||||
{
|
||||
v2 = mSoundShader;
|
||||
if (!v2 || (v2->GetParms()->soundShaderFlags & 0x20) == 0)
|
||||
{
|
||||
duration = mLocalDuration.x + mLocalStartTime.x;
|
||||
effect->SetMinDuration(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rvSegmentTemplate::Finish(rvDeclEffect* effect)
|
||||
{
|
||||
rvParticleTemplate* v3; // edi
|
||||
int v5; // ecx
|
||||
float v6; // [esp+4h] [ebp-4h]
|
||||
float v7; // [esp+4h] [ebp-4h]
|
||||
float v8; // [esp+4h] [ebp-4h]
|
||||
float v9; // [esp+4h] [ebp-4h]
|
||||
float v10; // [esp+4h] [ebp-4h]
|
||||
|
||||
if (mLocalStartTime.y <= mLocalStartTime.x)
|
||||
{
|
||||
v6 = mLocalStartTime.x;
|
||||
mLocalStartTime.x = mLocalStartTime.y;
|
||||
mLocalStartTime.y = v6;
|
||||
}
|
||||
if (mLocalDuration.y <= mLocalDuration.x)
|
||||
{
|
||||
v7 = mLocalDuration.x;
|
||||
mLocalDuration.x = mLocalDuration.y;
|
||||
mLocalDuration.y = v7;
|
||||
}
|
||||
if (mCount.y <= mCount.x)
|
||||
{
|
||||
v8 = mCount.x;
|
||||
mCount.x = mCount.y;
|
||||
mCount.y = v8;
|
||||
}
|
||||
if (mDensity.y <= mDensity.x)
|
||||
{
|
||||
v9 = mDensity.x;
|
||||
mDensity.x = mDensity.y;
|
||||
mDensity.y = v9;
|
||||
}
|
||||
if (mAttenuation.y <= mAttenuation.x)
|
||||
{
|
||||
v10 = mAttenuation.x;
|
||||
mAttenuation.x = mAttenuation.y;
|
||||
mAttenuation.y = v10;
|
||||
}
|
||||
if (mParticleTemplate.mType)
|
||||
{
|
||||
v3 = &mParticleTemplate;
|
||||
mParticleTemplate.Finish();
|
||||
v3->mFlags &= 0xFFF7FFFF;
|
||||
}
|
||||
switch (mSegType)
|
||||
{
|
||||
case 2:
|
||||
mFlags |= 4u;
|
||||
if (mParticleTemplate.mType && (mFlags & 0x20) == 0)
|
||||
goto LABEL_25;
|
||||
return 0;
|
||||
case 3:
|
||||
mFlags |= 4u;
|
||||
if (mParticleTemplate.mType)
|
||||
goto LABEL_25;
|
||||
return 0;
|
||||
case 4:
|
||||
mFlags |= 4u;
|
||||
mLocalStartTime.y = 0.0;
|
||||
mLocalStartTime.x = 0.0;
|
||||
mLocalDuration.y = 0.0;
|
||||
mLocalDuration.x = 0.0;
|
||||
if (!mParticleTemplate.mType)
|
||||
return 0;
|
||||
mParticleTemplate.mFlags |= 0x80000u;
|
||||
LABEL_25:
|
||||
v5 = mParticleTemplate.mType;
|
||||
if (v5 != PTYPE_NONE) {
|
||||
mFlags |= STFLAG_HASPARTICLES;
|
||||
}
|
||||
if (v5 == 10)
|
||||
mFlags = mFlags & 0xFFFFFFFB | 0x100;
|
||||
if ((mFlags & 0x20) != 0
|
||||
|| mParticleTemplate.mTrailInfo->mTrailType == 3
|
||||
|| (mParticleTemplate.mFlags & 0x200) != 0
|
||||
|| mParticleTemplate.mNumTimeoutEffects)
|
||||
{
|
||||
mFlags |= 0x2000u;
|
||||
}
|
||||
if (v5 == 7 || v5 == 6)
|
||||
mFlags |= 0x2000u;
|
||||
return 1;
|
||||
case 5:
|
||||
mFlags |= 0x10u;
|
||||
goto LABEL_25;
|
||||
case 6:
|
||||
mFlags = mFlags & 0xFFFFFFFB | 0x100;
|
||||
goto LABEL_25;
|
||||
case SEG_SHAKE:
|
||||
case SEG_TUNNEL:
|
||||
case SEG_DOUBLEVISION:
|
||||
if (mAttenuation.y > 0.0)
|
||||
mFlags |= 0x40u;
|
||||
goto LABEL_24;
|
||||
default:
|
||||
LABEL_24:
|
||||
mFlags &= 0xFFFFFFFB;
|
||||
goto LABEL_25;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rvSegmentTemplate::operator=(const rvSegmentTemplate& copy)
|
||||
{
|
||||
this->mDeclEffect = copy.mDeclEffect;
|
||||
this->mSegmentName = copy.mSegmentName;
|
||||
this->mFlags = copy.mFlags;
|
||||
this->mSegType = copy.mSegType;
|
||||
this->mLocalStartTime = copy.mLocalStartTime;
|
||||
this->mLocalDuration = copy.mLocalDuration;
|
||||
this->mScale = copy.mScale;
|
||||
this->mAttenuation = copy.mAttenuation;
|
||||
this->mParticleCap = copy.mParticleCap;
|
||||
this->mScale = copy.mScale;
|
||||
this->mDetail = copy.mDetail;
|
||||
this->mCount = copy.mCount;
|
||||
this->mDensity = copy.mDensity;
|
||||
this->mTrailSegmentIndex = copy.mTrailSegmentIndex;
|
||||
this->mNumEffects = copy.mNumEffects;
|
||||
this->mEffects[0] = copy.mEffects[0];
|
||||
this->mEffects[1] = copy.mEffects[1];
|
||||
this->mEffects[2] = copy.mEffects[2];
|
||||
this->mEffects[3] = copy.mEffects[3];
|
||||
this->mSoundShader = copy.mSoundShader;
|
||||
this->mSoundVolume = copy.mSoundVolume;
|
||||
this->mFreqShift = copy.mFreqShift;
|
||||
this->mParticleTemplate = copy.mParticleTemplate;
|
||||
this->mDecalAxis = copy.mDecalAxis;
|
||||
}
|
||||
|
||||
void rvSegmentTemplate::SetMaxDuration(rvDeclEffect* effect)
|
||||
{
|
||||
rvSegmentTemplate* v2; // esi
|
||||
rvDeclEffect* v3; // edi
|
||||
float duration; // ST0C_4
|
||||
float effecta; // [esp+14h] [ebp+4h]
|
||||
|
||||
v2 = this;
|
||||
if (!(((unsigned int)this->mFlags >> 4) & 1))
|
||||
{
|
||||
v3 = effect;
|
||||
duration = this->mLocalDuration.x + this->mLocalStartTime.x;
|
||||
effect->SetMaxDuration(duration);
|
||||
if (v2->mParticleTemplate.mType)
|
||||
{
|
||||
effecta = v2->mLocalDuration.x + v2->mLocalStartTime.x + v2->mParticleTemplate.mDuration.y;
|
||||
v3->SetMaxDuration(effecta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rvSegmentTemplate::Parse(rvDeclEffect* effect, int segmentType, idParser* lexer) {
|
||||
idToken token;
|
||||
|
||||
if (!lexer->ReadToken(&token))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token != "{") {
|
||||
mSegmentName = token;
|
||||
}
|
||||
else {
|
||||
mSegmentName = va("unnamed%d", effect->GetNumSegmentTemplates());
|
||||
lexer->UnreadToken(&token);
|
||||
}
|
||||
|
||||
mSegType = segmentType;
|
||||
|
||||
if (!(lexer->ExpectTokenString("{") && lexer->ReadToken(&token))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (token != "}")
|
||||
{
|
||||
if (token == "decalAxis")
|
||||
{
|
||||
mDecalAxis = lexer->ParseInt();
|
||||
}
|
||||
else if (token == "orientateIdentity")
|
||||
{
|
||||
mFlags |= STFLAG_ORIENTATE_IDENTITY;
|
||||
}
|
||||
else if (token == "useMaterialColor")
|
||||
{
|
||||
mFlags |= STFLAG_USEMATCOLOR;
|
||||
}
|
||||
else if (token == "depthsort")
|
||||
{
|
||||
mFlags |= STFLAG_DEPTH_SORT;
|
||||
}
|
||||
else if (!idStr::Icmp(token.c_str(), "inverseDrawOrder"))
|
||||
{
|
||||
mFlags |= STFLAG_INVERSE_DRAWORDER;
|
||||
}
|
||||
else if (token == "calcDuration")
|
||||
{
|
||||
mFlags |= STFLAG_CALCULATE_DURATION;
|
||||
}
|
||||
else if (token == "constant")
|
||||
{
|
||||
mFlags |= STFLAG_INFINITE_DURATION;
|
||||
}
|
||||
else if (token == "looping")
|
||||
{
|
||||
// Keep legacy token behavior aligned with constant duration segments.
|
||||
mFlags |= STFLAG_INFINITE_DURATION;
|
||||
}
|
||||
else if (token == "locked")
|
||||
{
|
||||
mFlags |= STFLAG_LOCKED;
|
||||
}
|
||||
else if (!idStr::Icmp(token.c_str(), "temporary"))
|
||||
{
|
||||
mFlags |= STFLAG_TEMPORARY;
|
||||
}
|
||||
else if (token == "inverseAttenuateEmitter")
|
||||
{
|
||||
// Stock parser behavior enables attenuation when inverse attenuation is requested.
|
||||
mFlags |= STFLAG_ATTENUATE_EMITTER | STFLAG_INVERSE_ATTENUATE;
|
||||
}
|
||||
else if (token == "attenuateEmitter")
|
||||
{
|
||||
mFlags |= STFLAG_ATTENUATE_EMITTER;
|
||||
}
|
||||
else if (token == "scale")
|
||||
{
|
||||
mScale = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "channel")
|
||||
{
|
||||
if (!lexer->ReadToken(&token)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (token == "effect")
|
||||
{
|
||||
if (!lexer->ReadToken(&token)) {
|
||||
return false;
|
||||
}
|
||||
if (mNumEffects >= 4)
|
||||
{
|
||||
common->FatalError("Unable to add effect '%s' - too many effects\n", token.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
mEffects[this->mNumEffects++] = declManager->FindEffect(token);
|
||||
}
|
||||
}
|
||||
else if (idStr::Icmp(token.c_str(), "freqShift") == 0)
|
||||
{
|
||||
mFreqShift.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mFreqShift.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "attenuation")
|
||||
{
|
||||
mAttenuation.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mAttenuation.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "volume")
|
||||
{
|
||||
mSoundVolume.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mSoundVolume.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "soundShader")
|
||||
{
|
||||
if (!lexer->ReadToken(&token)) {
|
||||
return false;
|
||||
}
|
||||
mSoundShader = (idSoundShader*)declManager->FindSound(token);
|
||||
float effecta = 0.0f;
|
||||
if (mSoundShader) {
|
||||
effecta = 0.0f; // mSoundShader->GetTimeLength();
|
||||
}
|
||||
// Preserve a sane non-zero fallback for missing/streamed metadata.
|
||||
if (effecta <= BSE_TIME_EPSILON) {
|
||||
effecta = 1.0f;
|
||||
}
|
||||
mLocalDuration.x = effecta;
|
||||
mLocalDuration.y = effecta;
|
||||
}
|
||||
else if (token == "detail")
|
||||
{
|
||||
mDetail = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "duration")
|
||||
{
|
||||
mLocalDuration.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mLocalDuration.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "start")
|
||||
{
|
||||
mLocalStartTime.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mLocalStartTime.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "density")
|
||||
{
|
||||
mDensity.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mDensity.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "count" || token == "rate")
|
||||
{
|
||||
mCount.x = lexer->ParseFloat();
|
||||
lexer->ExpectTokenString(",");
|
||||
mCount.y = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "particleCap")
|
||||
{
|
||||
mParticleCap = lexer->ParseFloat();
|
||||
}
|
||||
else if (token == "debris")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_DEBRIS);
|
||||
}
|
||||
else if (token == "orientedlinked")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_ORIENTEDLINKED);
|
||||
}
|
||||
else if (token == "linked")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_LINKED);
|
||||
}
|
||||
else if (token == "electricity")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_ELECTRICITY);
|
||||
}
|
||||
else if (token == "light")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_LIGHT);
|
||||
}
|
||||
else if (token == "model")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_MODEL);
|
||||
}
|
||||
else if (token == "decal")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_DECAL);
|
||||
}
|
||||
else if (token == "oriented")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_ORIENTED);
|
||||
}
|
||||
else if (token == "line")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_LINE);
|
||||
}
|
||||
else if (token == "sprite")
|
||||
{
|
||||
CreateParticleTemplate(effect, lexer, PTYPE_SPRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
common->Warning("^4BSE:^1 Invalid segment parameter '%s' (file: %s, line: %d)", token.c_str(), lexer->GetFileName(), lexer->GetLineNum());
|
||||
}
|
||||
|
||||
if (!lexer->ReadToken(&token)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
// Copyright (C) 2007 Id Software, Inc.
|
||||
//
|
||||
|
||||
#include "precompiled.h"
|
||||
#include "BSE_Envelope.h"
|
||||
#include "BSE_Particle.h"
|
||||
#include "BSE_SpawnDomains.h"
|
||||
#include "BSE.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace {
|
||||
ID_INLINE float SpawnRandom01() {
|
||||
return rvRandom::flrand(0.0f, 1.0f);
|
||||
}
|
||||
|
||||
ID_INLINE float SpawnLerp(float a, float b, float t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
ID_INLINE void SpawnGetNormalInternal(idVec3* normal, const idVec3& point, const idVec3* centre) {
|
||||
if (!normal) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (centre) {
|
||||
*normal = point - *centre;
|
||||
}
|
||||
else {
|
||||
*normal = point;
|
||||
}
|
||||
|
||||
const float lenSqr = normal->LengthSqr();
|
||||
if (lenSqr > 1e-6f) {
|
||||
normal->NormalizeFast();
|
||||
}
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 SpawnBoxPoint(const rvParticleParms& parms) {
|
||||
return idVec3(
|
||||
rvRandom::flrand(parms.mMins.x, parms.mMaxs.x),
|
||||
rvRandom::flrand(parms.mMins.y, parms.mMaxs.y),
|
||||
rvRandom::flrand(parms.mMins.z, parms.mMaxs.z));
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 SpawnSurfaceBoxPoint(const rvParticleParms& parms) {
|
||||
idVec3 result = SpawnBoxPoint(parms);
|
||||
|
||||
switch (rvRandom::irand(0, 5)) {
|
||||
case 0:
|
||||
result.x = parms.mMins.x;
|
||||
break;
|
||||
case 1:
|
||||
result.x = parms.mMaxs.x;
|
||||
break;
|
||||
case 2:
|
||||
result.y = parms.mMins.y;
|
||||
break;
|
||||
case 3:
|
||||
result.y = parms.mMaxs.y;
|
||||
break;
|
||||
case 4:
|
||||
result.z = parms.mMins.z;
|
||||
break;
|
||||
default:
|
||||
result.z = parms.mMaxs.z;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 SpawnSpherePoint(const rvParticleParms& parms, bool surfaceOnly) {
|
||||
const idVec3 centre = (parms.mMins + parms.mMaxs) * 0.5f;
|
||||
const idVec3 radius = (parms.mMaxs - parms.mMins) * 0.5f;
|
||||
|
||||
const float z = rvRandom::flrand(-1.0f, 1.0f);
|
||||
const float phi = rvRandom::flrand(0.0f, idMath::TWO_PI);
|
||||
const float radial = surfaceOnly ? 1.0f : SpawnRandom01();
|
||||
const float ring = idMath::Sqrt(Max(0.0f, 1.0f - z * z));
|
||||
|
||||
idVec3 dir(ring * idMath::Cos(phi), ring * idMath::Sin(phi), z);
|
||||
return idVec3(
|
||||
centre.x + dir.x * radius.x * radial,
|
||||
centre.y + dir.y * radius.y * radial,
|
||||
centre.z + dir.z * radius.z * radial);
|
||||
}
|
||||
|
||||
ID_INLINE idVec3 SpawnCylinderPoint(const rvParticleParms& parms, bool surfaceOnly) {
|
||||
const float t = SpawnRandom01();
|
||||
const float phi = rvRandom::flrand(0.0f, idMath::TWO_PI);
|
||||
const float radial = surfaceOnly ? 1.0f : SpawnRandom01();
|
||||
|
||||
const float x = SpawnLerp(parms.mMins.x, parms.mMaxs.x, t);
|
||||
const float cy = 0.5f * (parms.mMins.y + parms.mMaxs.y);
|
||||
const float cz = 0.5f * (parms.mMins.z + parms.mMaxs.z);
|
||||
const float ry = 0.5f * (parms.mMaxs.y - parms.mMins.y);
|
||||
const float rz = 0.5f * (parms.mMaxs.z - parms.mMins.z);
|
||||
|
||||
return idVec3(x, cy + idMath::Cos(phi) * ry * radial, cz + idMath::Sin(phi) * rz * radial);
|
||||
}
|
||||
}
|
||||
|
||||
TSpawnFunc rvParticleParms::spawnFunctions[SPF_COUNT] = {
|
||||
/*00*/ &SpawnStub,
|
||||
/*01*/ &SpawnNone1,
|
||||
/*02*/ &SpawnNone2,
|
||||
/*03*/ &SpawnNone3,
|
||||
/*04*/ &SpawnStub,
|
||||
/*05*/ &SpawnOne1,
|
||||
/*06*/ &SpawnOne2,
|
||||
/*07*/ &SpawnOne3,
|
||||
/*08*/ &SpawnStub,
|
||||
/*09*/ &SpawnPoint1,
|
||||
/*10*/ &SpawnPoint2,
|
||||
/*11*/ &SpawnPoint3,
|
||||
/*12*/ &SpawnStub,
|
||||
/*13*/ &SpawnLinear1,
|
||||
/*14*/ &SpawnLinear2,
|
||||
/*15*/ &SpawnLinear3,
|
||||
/*16*/ &SpawnStub,
|
||||
/*17*/ &SpawnBox1,
|
||||
/*18*/ &SpawnBox2,
|
||||
/*19*/ &SpawnBox3,
|
||||
/*20*/ &SpawnStub,
|
||||
/*21*/ &SpawnSurfaceBox1,
|
||||
/*22*/ &SpawnSurfaceBox2,
|
||||
/*23*/ &SpawnSurfaceBox3,
|
||||
/*24*/ &SpawnStub,
|
||||
/*25*/ &SpawnBox1,
|
||||
/*26*/ &SpawnSphere2,
|
||||
/*27*/ &SpawnSphere3,
|
||||
/*28*/ &SpawnStub,
|
||||
/*29*/ &SpawnSurfaceBox1,
|
||||
/*30*/ &SpawnSurfaceSphere2,
|
||||
/*31*/ &SpawnSurfaceSphere3,
|
||||
/*32*/ &SpawnStub,
|
||||
/*33*/ &SpawnBox1,
|
||||
/*34*/ &SpawnSphere2,
|
||||
/*35*/ &SpawnCylinder3,
|
||||
/*36*/ &SpawnStub,
|
||||
/*37*/ &SpawnSurfaceBox1,
|
||||
/*38*/ &SpawnSurfaceSphere2,
|
||||
/*39*/ &SpawnSurfaceCylinder3,
|
||||
/*40*/ &SpawnStub,
|
||||
/*41*/ &SpawnStub,
|
||||
/*42*/ &SpawnSpiral2,
|
||||
/*43*/ &SpawnSpiral3,
|
||||
/*44*/ &SpawnStub,
|
||||
/*45*/ &SpawnStub,
|
||||
/*46*/ &SpawnStub,
|
||||
/*47*/ &SpawnModel3,
|
||||
};
|
||||
|
||||
void sdModelInfo::CalculateSurfRemap(void) {
|
||||
for (int i = 0; i < NUM_SURF_REMAP; ++i) {
|
||||
surfRemap[i] = 0;
|
||||
}
|
||||
|
||||
if (!model || model->NumSurfaces() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int totalTris = 0;
|
||||
for (int i = 0; i < model->NumSurfaces(); ++i) {
|
||||
const modelSurface_t* surf = model->Surface(i);
|
||||
if (!surf || !surf->geometry) {
|
||||
continue;
|
||||
}
|
||||
totalTris += surf->geometry->numIndexes / 3;
|
||||
}
|
||||
|
||||
if (totalTris <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int slot = 0;
|
||||
for (int i = 0; i < model->NumSurfaces() && slot < NUM_SURF_REMAP; ++i) {
|
||||
const modelSurface_t* surf = model->Surface(i);
|
||||
if (!surf || !surf->geometry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int tris = surf->geometry->numIndexes / 3;
|
||||
const int count = Max(1, idMath::FtoiFast((float)NUM_SURF_REMAP * ((float)tris / (float)totalTris) + 0.5f));
|
||||
for (int j = 0; j < count && slot < NUM_SURF_REMAP; ++j) {
|
||||
surfRemap[slot++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
while (slot < NUM_SURF_REMAP) {
|
||||
surfRemap[slot] = surfRemap[slot > 0 ? slot - 1 : 0];
|
||||
++slot;
|
||||
}
|
||||
}
|
||||
|
||||
bool rvParticleParms::Compare(const rvParticleParms& comp) const {
|
||||
if (mSpawnType != comp.mSpawnType || mFlags != comp.mFlags) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((mModelInfo == NULL) != (comp.mModelInfo == NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (mModelInfo && comp.mModelInfo && mModelInfo->model != comp.mModelInfo->model) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const float eps = 0.001f;
|
||||
if (!mMins.Compare(comp.mMins, eps) || !mMaxs.Compare(comp.mMaxs, eps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return idMath::Fabs(mRange - comp.mRange) <= eps;
|
||||
}
|
||||
|
||||
void rvParticleParms::HandleRelativeParms(float* death, float* init, int count) {
|
||||
if ((mFlags & PPFLAG_RELATIVE) == 0 || death == NULL || init == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
death[i] += init[i];
|
||||
}
|
||||
}
|
||||
|
||||
void rvParticleParms::GetMinsMaxs(idVec3& mins, idVec3& maxs) {
|
||||
mins.Zero();
|
||||
maxs.Zero();
|
||||
|
||||
switch (mSpawnType & ~0x3) {
|
||||
case SPF_ONE_0:
|
||||
mins.Set(1.0f, 1.0f, 1.0f);
|
||||
maxs = mins;
|
||||
break;
|
||||
case SPF_POINT_0:
|
||||
mins = mMins;
|
||||
maxs = mMins;
|
||||
break;
|
||||
case SPF_LINEAR_0:
|
||||
case SPF_BOX_0:
|
||||
case SPF_SURFACE_BOX_0:
|
||||
case SPF_SPHERE_0:
|
||||
case SPF_SURFACE_SPHERE_0:
|
||||
case SPF_CYLINDER_0:
|
||||
case SPF_SURFACE_CYLINDER_0:
|
||||
case SPF_SPIRAL_0:
|
||||
case SPF_MODEL_0:
|
||||
mins = mMins;
|
||||
maxs = mMaxs;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnStub(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
if (result) {
|
||||
result[0] = 0.0f;
|
||||
result[1] = 0.0f;
|
||||
result[2] = 0.0f;
|
||||
}
|
||||
if (normal) {
|
||||
normal->Set(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnNone1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = 0.0f;
|
||||
}
|
||||
|
||||
void SpawnNone2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = 0.0f;
|
||||
result[1] = 0.0f;
|
||||
}
|
||||
|
||||
void SpawnNone3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out.Zero();
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnOne1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = 1.0f;
|
||||
}
|
||||
|
||||
void SpawnOne2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = 1.0f;
|
||||
result[1] = 1.0f;
|
||||
}
|
||||
|
||||
void SpawnOne3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out.Set(1.0f, 1.0f, 1.0f);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnPoint1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = parms.mMins.x;
|
||||
}
|
||||
|
||||
void SpawnPoint2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = parms.mMins.x;
|
||||
result[1] = parms.mMins.y;
|
||||
}
|
||||
|
||||
void SpawnPoint3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = parms.mMins;
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnLinear1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = SpawnLerp(parms.mMins.x, parms.mMaxs.x, SpawnRandom01());
|
||||
}
|
||||
|
||||
void SpawnLinear2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
const float t = (parms.mFlags & PPFLAG_LINEARSPACING) ? result[0] : SpawnRandom01();
|
||||
result[0] = SpawnLerp(parms.mMins.x, parms.mMaxs.x, t);
|
||||
result[1] = SpawnLerp(parms.mMins.y, parms.mMaxs.y, t);
|
||||
}
|
||||
|
||||
void SpawnLinear3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
const float t = (parms.mFlags & PPFLAG_LINEARSPACING) ? out.x : SpawnRandom01();
|
||||
out.x = SpawnLerp(parms.mMins.x, parms.mMaxs.x, t);
|
||||
out.y = SpawnLerp(parms.mMins.y, parms.mMaxs.y, t);
|
||||
out.z = SpawnLerp(parms.mMins.z, parms.mMaxs.z, t);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnBox1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = rvRandom::flrand(parms.mMins.x, parms.mMaxs.x);
|
||||
}
|
||||
|
||||
void SpawnBox2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = rvRandom::flrand(parms.mMins.x, parms.mMaxs.x);
|
||||
result[1] = rvRandom::flrand(parms.mMins.y, parms.mMaxs.y);
|
||||
}
|
||||
|
||||
void SpawnBox3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = SpawnBoxPoint(parms);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnSurfaceBox1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = rvRandom::irand(0, 1) ? parms.mMins.x : parms.mMaxs.x;
|
||||
}
|
||||
|
||||
void SpawnSurfaceBox2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3 sample = SpawnSurfaceBoxPoint(parms);
|
||||
result[0] = sample.x;
|
||||
result[1] = sample.y;
|
||||
}
|
||||
|
||||
void SpawnSurfaceBox3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = SpawnSurfaceBoxPoint(parms);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnSphere1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = SpawnSpherePoint(parms, false).x;
|
||||
}
|
||||
|
||||
void SpawnSphere2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3 p = SpawnSpherePoint(parms, false);
|
||||
result[0] = p.x;
|
||||
result[1] = p.y;
|
||||
}
|
||||
|
||||
void SpawnSphere3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = SpawnSpherePoint(parms, false);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnSurfaceSphere1(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
result[0] = SpawnSpherePoint(parms, true).x;
|
||||
}
|
||||
|
||||
void SpawnSurfaceSphere2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3 p = SpawnSpherePoint(parms, true);
|
||||
result[0] = p.x;
|
||||
result[1] = p.y;
|
||||
}
|
||||
|
||||
void SpawnSurfaceSphere3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = SpawnSpherePoint(parms, true);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnCylinder3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = SpawnCylinderPoint(parms, false);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnSurfaceCylinder3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
out = SpawnCylinderPoint(parms, true);
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
|
||||
void SpawnSpiral2(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
if (parms.mFlags & PPFLAG_LINEARSPACING) {
|
||||
result[0] = SpawnLerp(parms.mMins.x, parms.mMaxs.x, result[0]);
|
||||
}
|
||||
else {
|
||||
result[0] = rvRandom::flrand(parms.mMins.x, parms.mMaxs.x);
|
||||
}
|
||||
|
||||
const float range = (idMath::Fabs(parms.mRange) > BSE_TIME_EPSILON) ? parms.mRange : 1.0f;
|
||||
const float theta = idMath::TWO_PI * (result[0] / range);
|
||||
result[1] = idMath::Cos(theta) * rvRandom::flrand(parms.mMins.y, parms.mMaxs.y);
|
||||
}
|
||||
|
||||
void SpawnSpiral3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
if (parms.mFlags & PPFLAG_LINEARSPACING) {
|
||||
out.x = SpawnLerp(parms.mMins.x, parms.mMaxs.x, out.x);
|
||||
}
|
||||
else {
|
||||
out.x = rvRandom::flrand(parms.mMins.x, parms.mMaxs.x);
|
||||
}
|
||||
|
||||
const float range = (idMath::Fabs(parms.mRange) > BSE_TIME_EPSILON) ? parms.mRange : 1.0f;
|
||||
const float theta = idMath::TWO_PI * (out.x / range);
|
||||
const float c = idMath::Cos(theta);
|
||||
const float s = idMath::Sin(theta);
|
||||
const float ry = rvRandom::flrand(parms.mMins.y, parms.mMaxs.y);
|
||||
const float rz = rvRandom::flrand(parms.mMins.z, parms.mMaxs.z);
|
||||
|
||||
out.y = c * ry - s * rz;
|
||||
out.z = c * rz + s * ry;
|
||||
|
||||
if (normal) {
|
||||
normal->x = centre ? 0.0f : out.x;
|
||||
normal->y = out.y;
|
||||
normal->z = out.z;
|
||||
|
||||
const float lenSqr = normal->LengthSqr();
|
||||
if (lenSqr > 1e-6f) {
|
||||
normal->NormalizeFast();
|
||||
}
|
||||
else {
|
||||
normal->Set(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnModel3(float* result, const rvParticleParms& parms, idVec3* normal, const idVec3* centre) {
|
||||
idVec3& out = *reinterpret_cast<idVec3*>(result);
|
||||
|
||||
if (parms.mModelInfo && parms.mModelInfo->model) {
|
||||
idBounds bounds = parms.mModelInfo->model->Bounds(NULL);
|
||||
out.x = rvRandom::flrand(bounds[0].x, bounds[1].x);
|
||||
out.y = rvRandom::flrand(bounds[0].y, bounds[1].y);
|
||||
out.z = rvRandom::flrand(bounds[0].z, bounds[1].z);
|
||||
}
|
||||
else {
|
||||
out = SpawnBoxPoint(parms);
|
||||
}
|
||||
|
||||
SpawnGetNormalInternal(normal, out, centre);
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
// Copyright (C) 2007 Id Software, Inc.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef _BSE_SPAWN_DOMAINS_H_INC_
|
||||
#define _BSE_SPAWN_DOMAINS_H_INC_
|
||||
|
||||
enum
|
||||
{
|
||||
SPF_NONE_0 = 0,
|
||||
SPF_NONE_1,
|
||||
SPF_NONE_2,
|
||||
SPF_NONE_3,
|
||||
|
||||
SPF_ONE_0,
|
||||
SPF_ONE_1,
|
||||
SPF_ONE_2,
|
||||
SPF_ONE_3,
|
||||
|
||||
SPF_POINT_0,
|
||||
SPF_POINT_1,
|
||||
SPF_POINT_2,
|
||||
SPF_POINT_3,
|
||||
|
||||
SPF_LINEAR_0,
|
||||
SPF_LINEAR_1,
|
||||
SPF_LINEAR_2,
|
||||
SPF_LINEAR_3,
|
||||
|
||||
SPF_BOX_0,
|
||||
SPF_BOX_1,
|
||||
SPF_BOX_2,
|
||||
SPF_BOX_3,
|
||||
|
||||
SPF_SURFACE_BOX_0,
|
||||
SPF_SURFACE_BOX_1,
|
||||
SPF_SURFACE_BOX_2,
|
||||
SPF_SURFACE_BOX_3,
|
||||
|
||||
SPF_SPHERE_0,
|
||||
SPF_SPHERE_1,
|
||||
SPF_SPHERE_2,
|
||||
SPF_SPHERE_3,
|
||||
|
||||
SPF_SURFACE_SPHERE_0,
|
||||
SPF_SURFACE_SPHERE_1,
|
||||
SPF_SURFACE_SPHERE_2,
|
||||
SPF_SURFACE_SPHERE_3,
|
||||
|
||||
SPF_CYLINDER_0,
|
||||
SPF_CYLINDER_1,
|
||||
SPF_CYLINDER_2,
|
||||
SPF_CYLINDER_3,
|
||||
|
||||
SPF_SURFACE_CYLINDER_0,
|
||||
SPF_SURFACE_CYLINDER_1,
|
||||
SPF_SURFACE_CYLINDER_2,
|
||||
SPF_SURFACE_CYLINDER_3,
|
||||
|
||||
SPF_SPIRAL_0,
|
||||
SPF_SPIRAL_1,
|
||||
SPF_SPIRAL_2,
|
||||
SPF_SPIRAL_3,
|
||||
|
||||
SPF_MODEL_0,
|
||||
SPF_MODEL_1,
|
||||
SPF_MODEL_2,
|
||||
SPF_MODEL_3,
|
||||
|
||||
SPF_COUNT
|
||||
};
|
||||
|
||||
typedef void ( *TSpawnFunc )( float *, const class rvParticleParms &, idVec3 *, const idVec3 * );
|
||||
|
||||
#define PPFLAG_SURFACE ( 1 << 0 )
|
||||
#define PPFLAG_USEENDORIGIN ( 1 << 1 )
|
||||
#define PPFLAG_CONE ( 1 << 2 )
|
||||
#define PPFLAG_RELATIVE ( 1 << 3 )
|
||||
#define PPFLAG_LINEARSPACING ( 1 << 4 )
|
||||
#define PPFLAG_ATTENUATE ( 1 << 5 )
|
||||
#define PPFLAG_INV_ATTENUATE ( 1 << 6 )
|
||||
|
||||
class idRenderModel;
|
||||
|
||||
// Parameters that define how a particle spawns. These are generic to all fields
|
||||
struct sdModelInfo {
|
||||
static const int NUM_SURF_REMAP = 10;
|
||||
idRenderModel *model;
|
||||
int surfRemap[NUM_SURF_REMAP]; //Will have a nuber of elements set to a certain surface's index based on the number of triangles in that surface
|
||||
// so surfaces with only like a few triangles don't have very dense particles generated for them.
|
||||
|
||||
void CalculateSurfRemap( void );
|
||||
};
|
||||
|
||||
extern const char sdPoolAllocator_rvParticleParms[];
|
||||
class rvParticleParms //: public sdPoolAllocator< rvParticleParms, sdPoolAllocator_rvParticleParms, 128 >
|
||||
{
|
||||
friend class rvParticle;
|
||||
friend class rvLineParticle;
|
||||
friend void SpawnStub( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnNone1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnNone2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnNone3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnOne1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnOne2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnOne3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnPoint1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnPoint2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnPoint3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnLinear1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnLinear2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnLinear3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnBox1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnBox2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnBox3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnSurfaceBox1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSurfaceBox2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSurfaceBox3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnSphere1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSphere2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSphere3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnSurfaceSphere1( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSurfaceSphere2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSurfaceSphere3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnCylinder3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSurfaceCylinder3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnSpiral2( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
friend void SpawnSpiral3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
friend void SpawnModel3( float *result, const rvParticleParms &parms, idVec3 *normal, const idVec3 * );
|
||||
|
||||
public:
|
||||
rvParticleParms( void ) { mModelInfo = NULL; mStatic = 0;}
|
||||
~rvParticleParms( void ) { delete mModelInfo; }
|
||||
|
||||
void operator= ( const rvParticleParms &other ) {
|
||||
memcpy( this, &other, sizeof( rvParticleParms ) );
|
||||
if ( other.mModelInfo ) {
|
||||
mModelInfo = new sdModelInfo;
|
||||
*mModelInfo = *other.mModelInfo;
|
||||
}
|
||||
mStatic = 0;
|
||||
}
|
||||
|
||||
bool operator== ( const rvParticleParms &comp ) const { return( Compare( comp ) ); }
|
||||
bool operator!= ( const rvParticleParms &comp ) const { return( !Compare( comp ) ); }
|
||||
|
||||
void Init( int spawnType = SPF_NONE_0 ) { mSpawnType = spawnType; mFlags = 0; mRange = 0.0f; mModelInfo = NULL; mMins.Zero(); mMaxs.Zero(); }
|
||||
ID_INLINE void Spawn( float *dest, const rvParticleParms &parms, idVec3 *normal, const idVec3 *centre ) { ( *spawnFunctions[mSpawnType] )( dest, parms, normal, centre ); }
|
||||
ID_INLINE void Spawn( float *dest, const rvParticleParms &parms ) { ( *spawnFunctions[mSpawnType] )( dest, parms, NULL, NULL ); }
|
||||
void HandleRelativeParms( float *death, float *init, int count );
|
||||
void GetMinsMaxs( idVec3 &mins, idVec3 &maxs );
|
||||
|
||||
ID_INLINE int GetFlags( void ) const { return mFlags; }
|
||||
ID_INLINE const idVec3 & GetMins( void ) const { return mMins; }
|
||||
ID_INLINE const idVec3 & GetMaxs( void ) const { return mMaxs; }
|
||||
|
||||
//private:
|
||||
byte mSpawnType; // Type of spawn domain (eg. box, spiral)
|
||||
byte mFlags; // PPFLAG_
|
||||
byte mStatic;
|
||||
byte mPad;
|
||||
float mRange; // Repeat length of spiral
|
||||
sdModelInfo *mModelInfo; // idRenderModel *
|
||||
idVec3 mMins; // Box mins, line start etc
|
||||
idVec3 mMaxs; // Box maxs, line end etc
|
||||
|
||||
private:
|
||||
bool Compare( const rvParticleParms &comp ) const;
|
||||
|
||||
static TSpawnFunc spawnFunctions[SPF_COUNT];
|
||||
};
|
||||
|
||||
void SpawnStub( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnNone1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnNone2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnNone3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnOne1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnOne2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnOne3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnPoint1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnPoint2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnPoint3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnLinear1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnLinear2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnLinear3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnBox1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnBox2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnBox3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnSurfaceBox1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSurfaceBox2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSurfaceBox3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnSphere1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSphere2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSphere3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnSurfaceSphere1( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSurfaceSphere2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSurfaceSphere3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnCylinder3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSurfaceCylinder3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnSpiral2( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
void SpawnSpiral3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
void SpawnModel3( float *result, const rvParticleParms &parms, idVec3 *normal = NULL, const idVec3 * = NULL );
|
||||
|
||||
#endif // _BSE_SPAWN_DOMAINS_H_INC_
|
||||
Reference in New Issue
Block a user