mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
enhanced-emitter -- numerous enhancements to ParticleEmitter class.
pooled-particles -- optional support for pooled particles which combines multiple emitters in a common sorting pool.
This commit is contained in:
parent
fc449307f9
commit
43d2399aea
|
|
@ -24,6 +24,7 @@
|
|||
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||
// Copyright (C) 2015 Faust Logic, Inc.
|
||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "T3D/fx/particleEmitter.h"
|
||||
|
||||
|
|
@ -42,6 +43,10 @@
|
|||
#include "lighting/lightInfo.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
#include "afx/util/afxParticlePool.h"
|
||||
#endif
|
||||
|
||||
Point3F ParticleEmitter::mWindVelocity( 0.0, 0.0, 0.0 );
|
||||
const F32 ParticleEmitter::AgedSpinToRadians = (1.0f/1000.0f) * (1.0f/360.0f) * M_PI_F * 2.0f;
|
||||
|
||||
|
|
@ -153,6 +158,21 @@ ParticleEmitterData::ParticleEmitterData()
|
|||
|
||||
alignParticles = false;
|
||||
alignDirection = Point3F(0.0f, 1.0f, 0.0f);
|
||||
|
||||
ejectionInvert = false;
|
||||
fade_color = false;
|
||||
fade_alpha = false;
|
||||
fade_size = false;
|
||||
parts_per_eject = 1;
|
||||
use_emitter_xfm = false;
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
pool_datablock = 0;
|
||||
pool_index = 0;
|
||||
pool_depth_fade = false;
|
||||
pool_radial_fade = false;
|
||||
do_pool_id_convert = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -297,6 +317,23 @@ void ParticleEmitterData::initPersistFields()
|
|||
|
||||
endGroup( "ParticleEmitterData" );
|
||||
|
||||
addGroup("AFX");
|
||||
addField("ejectionInvert", TypeBool, Offset(ejectionInvert, ParticleEmitterData));
|
||||
addField("fadeColor", TypeBool, Offset(fade_color, ParticleEmitterData));
|
||||
addField("fadeAlpha", TypeBool, Offset(fade_alpha, ParticleEmitterData));
|
||||
addField("fadeSize", TypeBool, Offset(fade_size, ParticleEmitterData));
|
||||
// useEmitterTransform currently does not work in TGEA or T3D
|
||||
addField("useEmitterTransform", TypeBool, Offset(use_emitter_xfm, ParticleEmitterData));
|
||||
endGroup("AFX");
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
addGroup("AFX Pooled Particles");
|
||||
addField("poolData", TYPEID<afxParticlePoolData>(), Offset(pool_datablock, ParticleEmitterData));
|
||||
addField("poolIndex", TypeS32, Offset(pool_index, ParticleEmitterData));
|
||||
addField("poolDepthFade", TypeBool, Offset(pool_depth_fade, ParticleEmitterData));
|
||||
addField("poolRadialFade", TypeBool, Offset(pool_radial_fade, ParticleEmitterData));
|
||||
endGroup("AFX Pooled Particles");
|
||||
#endif
|
||||
// disallow some field substitutions
|
||||
disableFieldSubstitutions("particles");
|
||||
onlyKeepClearSubstitutions("poolData"); // subs resolving to "~~", or "~0" are OK
|
||||
|
|
@ -365,6 +402,22 @@ void ParticleEmitterData::packData(BitStream* stream)
|
|||
stream->writeFlag(renderReflection);
|
||||
stream->writeFlag(glow);
|
||||
stream->writeInt( blendStyle, 4 );
|
||||
|
||||
stream->writeFlag(ejectionInvert);
|
||||
stream->writeFlag(fade_color);
|
||||
stream->writeFlag(fade_alpha);
|
||||
stream->writeFlag(fade_size);
|
||||
stream->writeFlag(use_emitter_xfm);
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (stream->writeFlag(pool_datablock))
|
||||
{
|
||||
stream->writeRangedU32(packed ? SimObjectId((uintptr_t)pool_datablock) : pool_datablock->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
stream->write(pool_index);
|
||||
stream->writeFlag(pool_depth_fade);
|
||||
stream->writeFlag(pool_radial_fade);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -428,6 +481,22 @@ void ParticleEmitterData::unpackData(BitStream* stream)
|
|||
renderReflection = stream->readFlag();
|
||||
glow = stream->readFlag();
|
||||
blendStyle = stream->readInt( 4 );
|
||||
ejectionInvert = stream->readFlag();
|
||||
fade_color = stream->readFlag();
|
||||
fade_alpha = stream->readFlag();
|
||||
fade_size = stream->readFlag();
|
||||
use_emitter_xfm = stream->readFlag();
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (stream->readFlag())
|
||||
{
|
||||
pool_datablock = (afxParticlePoolData*)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
||||
stream->read(&pool_index);
|
||||
pool_depth_fade = stream->readFlag();
|
||||
pool_radial_fade = stream->readFlag();
|
||||
do_pool_id_convert = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -607,6 +676,22 @@ bool ParticleEmitterData::preload(bool server, String &errorStr)
|
|||
|
||||
if (!server)
|
||||
{
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (do_pool_id_convert)
|
||||
{
|
||||
SimObjectId db_id = (SimObjectId)(uintptr_t)pool_datablock;
|
||||
if (db_id != 0)
|
||||
{
|
||||
// try to convert id to pointer
|
||||
if (!Sim::findObject(db_id, pool_datablock))
|
||||
{
|
||||
Con::errorf("ParticleEmitterData::reload() -- bad datablockId: 0x%x (poolData)", db_id);
|
||||
}
|
||||
}
|
||||
do_pool_id_convert = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// load emitter texture if specified
|
||||
if (textureName && textureName[0])
|
||||
{
|
||||
|
|
@ -676,6 +761,8 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize )
|
|||
|
||||
partListInitSize = maxPartLife / (ejectionPeriodMS - periodVarianceMS);
|
||||
partListInitSize += 8; // add 8 as "fudge factor" to make sure it doesn't realloc if it goes over by 1
|
||||
if (parts_per_eject > 1)
|
||||
partListInitSize *= parts_per_eject;
|
||||
|
||||
// if override size is specified, then the emitter overran its buffer and needs a larger allocation
|
||||
if( overrideSize != -1 )
|
||||
|
|
@ -871,7 +958,16 @@ ParticleEmitter::ParticleEmitter()
|
|||
|
||||
// ParticleEmitter should be allocated on the client only.
|
||||
mNetFlags.set( IsGhost );
|
||||
fade_amt = 1.0f;
|
||||
forced_bbox = false;
|
||||
db_temp_clone = false;
|
||||
pos_pe.set(0,0,0);
|
||||
sort_priority = 0;
|
||||
mDataBlock = 0;
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
pool = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -920,6 +1016,11 @@ bool ParticleEmitter::onAdd()
|
|||
mObjBox.maxExtents = Point3F(radius, radius, radius);
|
||||
resetWorldBox();
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (pool)
|
||||
pool->addParticleEmitter(this);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -929,6 +1030,14 @@ bool ParticleEmitter::onAdd()
|
|||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitter::onRemove()
|
||||
{
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (pool)
|
||||
{
|
||||
pool->removeParticleEmitter(this);
|
||||
pool = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
|
@ -1015,6 +1124,11 @@ LinearColorF ParticleEmitter::getCollectiveColor()
|
|||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
||||
{
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (pool)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if( state->isReflectPass() && !getDataBlock()->renderReflection )
|
||||
return;
|
||||
|
||||
|
|
@ -1043,6 +1157,7 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
|||
ri->translucentSort = true;
|
||||
ri->type = RenderPassManager::RIT_Particle;
|
||||
ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint( camPos );
|
||||
ri->defaultKey = (-sort_priority*100);
|
||||
|
||||
// Draw the system offscreen unless the highResOnly flag is set on the datablock
|
||||
ri->systemState = ( getDataBlock()->highResOnly ? PSS_AwaitingHighResDraw : PSS_AwaitingOffscreenDraw );
|
||||
|
|
@ -1146,6 +1261,7 @@ void ParticleEmitter::emitParticles(const Point3F& point,
|
|||
return;
|
||||
}
|
||||
|
||||
pos_pe = point;
|
||||
Point3F realStart;
|
||||
if( useLastPosition && mHasLastPosition )
|
||||
realStart = mLastPosition;
|
||||
|
|
@ -1213,7 +1329,8 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
|||
// Create particle at the correct position
|
||||
Point3F pos;
|
||||
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
||||
addParticle(pos, axis, velocity, axisx);
|
||||
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
|
||||
|
||||
particlesAdded = true;
|
||||
mNextParticleTime = 0;
|
||||
}
|
||||
|
|
@ -1243,7 +1360,7 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
|||
// Create particle at the correct position
|
||||
Point3F pos;
|
||||
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
||||
addParticle(pos, axis, velocity, axisx);
|
||||
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
|
||||
particlesAdded = true;
|
||||
|
||||
// This override-advance code is restored in order to correctly adjust
|
||||
|
|
@ -1268,17 +1385,27 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
|||
{
|
||||
if (advanceMS != 0)
|
||||
{
|
||||
F32 t = F32(advanceMS) / 1000.0;
|
||||
F32 t = F32(advanceMS) / 1000.0;
|
||||
|
||||
Point3F a = last_part->acc;
|
||||
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
|
||||
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
|
||||
a += Point3F(0.0f, 0.0f, -9.81f) * last_part->dataBlock->gravityCoefficient;
|
||||
Point3F a = last_part->acc;
|
||||
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
|
||||
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
|
||||
//a += Point3F(0.0f, 0.0f, -9.81f) * last_part->dataBlock->gravityCoefficient;
|
||||
a.z += -9.81f*last_part->dataBlock->gravityCoefficient; // as long as gravity is a constant, this is faster
|
||||
|
||||
last_part->vel += a * t;
|
||||
last_part->pos += last_part->vel * t;
|
||||
last_part->vel += a * t;
|
||||
//last_part->pos += last_part->vel * t;
|
||||
last_part->pos_local += last_part->vel * t;
|
||||
|
||||
updateKeyData( last_part );
|
||||
// AFX -- allow subclasses to adjust the particle params here
|
||||
sub_particleUpdate(last_part);
|
||||
|
||||
if (last_part->dataBlock->constrain_pos)
|
||||
last_part->pos = last_part->pos_local + this->pos_pe;
|
||||
else
|
||||
last_part->pos = last_part->pos_local;
|
||||
|
||||
updateKeyData( last_part );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1350,7 +1477,7 @@ void ParticleEmitter::emitParticles(const Point3F& rCenter,
|
|||
axis.normalize();
|
||||
pos += rCenter;
|
||||
|
||||
addParticle(pos, axis, velocity, axisz);
|
||||
addParticle(pos, axis, velocity, axisz, 0);
|
||||
}
|
||||
|
||||
// Set world bounding box
|
||||
|
|
@ -1373,6 +1500,8 @@ void ParticleEmitter::emitParticles(const Point3F& rCenter,
|
|||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitter::updateBBox()
|
||||
{
|
||||
if (forced_bbox)
|
||||
return;
|
||||
Point3F minPt(1e10, 1e10, 1e10);
|
||||
Point3F maxPt(-1e10, -1e10, -1e10);
|
||||
|
||||
|
|
@ -1393,15 +1522,18 @@ void ParticleEmitter::updateBBox()
|
|||
boxScale.y = getMax(boxScale.y, 1.0f);
|
||||
boxScale.z = getMax(boxScale.z, 1.0f);
|
||||
mBBObjToWorld.scale(boxScale);
|
||||
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (pool)
|
||||
pool->updatePoolBBox(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// addParticle
|
||||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitter::addParticle(const Point3F& pos,
|
||||
const Point3F& axis,
|
||||
const Point3F& vel,
|
||||
const Point3F& axisx)
|
||||
void ParticleEmitter::addParticle(const Point3F& pos, const Point3F& axis, const Point3F& vel,
|
||||
const Point3F& axisx, const U32 age_offset)
|
||||
{
|
||||
n_parts++;
|
||||
if (n_parts > n_part_capacity || n_parts > mDataBlock->partListInitSize)
|
||||
|
|
@ -1423,6 +1555,16 @@ void ParticleEmitter::addParticle(const Point3F& pos,
|
|||
pNew->next = part_list_head.next;
|
||||
part_list_head.next = pNew;
|
||||
|
||||
// for earlier access to constrain_pos, the ParticleData datablock is chosen here instead
|
||||
// of later in the method.
|
||||
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
|
||||
ParticleData* part_db = mDataBlock->particleDataBlocks[dBlockIndex];
|
||||
// set start position to world or local space
|
||||
Point3F pos_start;
|
||||
if (part_db->constrain_pos)
|
||||
pos_start.set(0,0,0);
|
||||
else
|
||||
pos_start = pos;
|
||||
Point3F ejectionAxis = axis;
|
||||
F32 theta = (mDataBlock->thetaMax - mDataBlock->thetaMin) * gRandGen.randF() +
|
||||
mDataBlock->thetaMin;
|
||||
|
|
@ -1444,14 +1586,17 @@ void ParticleEmitter::addParticle(const Point3F& pos,
|
|||
F32 initialVel = mDataBlock->ejectionVelocity;
|
||||
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
|
||||
|
||||
pNew->pos = pos + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
|
||||
pNew->vel = ejectionAxis * initialVel;
|
||||
pNew->orientDir = ejectionAxis;
|
||||
pNew->pos = pos_start + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
|
||||
pNew->pos_local = pNew->pos;
|
||||
pNew->vel = mDataBlock->ejectionInvert ? ejectionAxis * -initialVel : ejectionAxis * initialVel;
|
||||
if (mDataBlock->orientParticles)
|
||||
pNew->orientDir = ejectionAxis;
|
||||
else
|
||||
// note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
|
||||
pNew->orientDir.x = mDegToRad(part_db->start_angle + part_db->angle_variance*2.0f*gRandGen.randF() - part_db->angle_variance);
|
||||
pNew->acc.set(0, 0, 0);
|
||||
pNew->currentAge = 0;
|
||||
|
||||
// Choose a new particle datablack randomly from the list
|
||||
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
|
||||
pNew->currentAge = age_offset;
|
||||
pNew->t_last = 0.0f;
|
||||
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
|
||||
updateKeyData( pNew );
|
||||
|
||||
|
|
@ -1533,8 +1678,10 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
|||
if( part->totalLifetime < 1 )
|
||||
part->totalLifetime = 1;
|
||||
|
||||
F32 t = F32(part->currentAge) / F32(part->totalLifetime);
|
||||
AssertFatal(t <= 1.0f, "Out out bounds filter function for particle.");
|
||||
if (part->currentAge > part->totalLifetime)
|
||||
part->currentAge = part->totalLifetime;
|
||||
F32 t = (F32)part->currentAge / (F32)part->totalLifetime;
|
||||
|
||||
|
||||
for( U32 i = 1; i < ParticleData::PDC_NUM_KEYS; i++ )
|
||||
{
|
||||
|
|
@ -1566,7 +1713,25 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
|||
{
|
||||
part->size = (part->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
|
||||
(part->dataBlock->sizes[i] * firstPart);
|
||||
part->size *= part->dataBlock->sizeBias;
|
||||
}
|
||||
|
||||
if (mDataBlock->fade_color)
|
||||
{
|
||||
if (mDataBlock->fade_alpha)
|
||||
part->color *= fade_amt;
|
||||
else
|
||||
{
|
||||
part->color.red *= fade_amt;
|
||||
part->color.green *= fade_amt;
|
||||
part->color.blue *= fade_amt;
|
||||
}
|
||||
}
|
||||
else if (mDataBlock->fade_alpha)
|
||||
part->color.alpha *= fade_amt;
|
||||
|
||||
if (mDataBlock->fade_size)
|
||||
part->size *= fade_amt;
|
||||
break;
|
||||
|
||||
}
|
||||
|
|
@ -1578,19 +1743,25 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
|||
//-----------------------------------------------------------------------------
|
||||
void ParticleEmitter::update( U32 ms )
|
||||
{
|
||||
// TODO: Prefetch
|
||||
F32 t = F32(ms)/1000.0f; // AFX -- moved outside loop, no need to recalculate this for every particle
|
||||
|
||||
for (Particle* part = part_list_head.next; part != NULL; part = part->next)
|
||||
{
|
||||
F32 t = F32(ms) / 1000.0;
|
||||
|
||||
Point3F a = part->acc;
|
||||
a -= part->vel * part->dataBlock->dragCoefficient;
|
||||
a -= part->vel * part->dataBlock->dragCoefficient;
|
||||
a -= mWindVelocity * part->dataBlock->windCoefficient;
|
||||
a += Point3F(0.0f, 0.0f, -9.81f) * part->dataBlock->gravityCoefficient;
|
||||
a.z += -9.81f*part->dataBlock->gravityCoefficient; // AFX -- as long as gravity is a constant, this is faster
|
||||
|
||||
part->vel += a * t;
|
||||
part->pos += part->vel * t;
|
||||
part->pos_local += part->vel * t;
|
||||
|
||||
// AFX -- allow subclasses to adjust the particle params here
|
||||
sub_particleUpdate(part);
|
||||
|
||||
if (part->dataBlock->constrain_pos)
|
||||
part->pos = part->pos_local + this->pos_pe;
|
||||
else
|
||||
part->pos = part->pos_local;
|
||||
|
||||
updateKeyData( part );
|
||||
}
|
||||
|
|
@ -2153,3 +2324,43 @@ DefineEngineMethod(ParticleEmitterData, reload, void,(),,
|
|||
{
|
||||
object->reload();
|
||||
}
|
||||
void ParticleEmitter::emitParticlesExt(const MatrixF& xfm, const Point3F& point,
|
||||
const Point3F& velocity, const U32 numMilliseconds)
|
||||
{
|
||||
if (mDataBlock->use_emitter_xfm)
|
||||
{
|
||||
Point3F zero_point(0.0f, 0.0f, 0.0f);
|
||||
this->pos_pe = zero_point;
|
||||
this->setTransform(xfm);
|
||||
Point3F axis(0.0,0.0,1.0);
|
||||
xfm.mulV(axis);
|
||||
emitParticles(zero_point, true, axis, velocity, numMilliseconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->pos_pe = point;
|
||||
Point3F axis(0.0,0.0,1.0);
|
||||
xfm.mulV(axis);
|
||||
emitParticles(point, true, axis, velocity, numMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEmitter::setForcedObjBox(Box3F& box)
|
||||
{
|
||||
mObjBox = box;
|
||||
forced_bbox = true;
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (pool)
|
||||
pool->updatePoolBBox(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ParticleEmitter::setSortPriority(S8 priority)
|
||||
{
|
||||
sort_priority = (priority == 0) ? 1 : priority;
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
if (pool)
|
||||
pool->setSortPriority(sort_priority);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||
// Copyright (C) 2015 Faust Logic, Inc.
|
||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
#ifndef _H_PARTICLE_EMITTER
|
||||
#define _H_PARTICLE_EMITTER
|
||||
|
||||
|
|
@ -46,6 +47,12 @@
|
|||
class RenderPassManager;
|
||||
class ParticleData;
|
||||
|
||||
#define AFX_CAP_PARTICLE_POOLS
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
class afxParticlePoolData;
|
||||
class afxParticlePool;
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
// Particle Emitter Data
|
||||
//*****************************************************************************
|
||||
|
|
@ -117,6 +124,21 @@ class ParticleEmitterData : public GameBaseData
|
|||
bool glow; ///< Renders this emitter into the glow buffer.
|
||||
|
||||
bool reload();
|
||||
public:
|
||||
bool fade_color;
|
||||
bool fade_size;
|
||||
bool fade_alpha;
|
||||
bool ejectionInvert;
|
||||
U8 parts_per_eject;
|
||||
bool use_emitter_xfm;
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
public:
|
||||
afxParticlePoolData* pool_datablock;
|
||||
U32 pool_index;
|
||||
bool pool_depth_fade;
|
||||
bool pool_radial_fade;
|
||||
bool do_pool_id_convert;
|
||||
#endif
|
||||
public:
|
||||
/*C*/ ParticleEmitterData(const ParticleEmitterData&, bool = false);
|
||||
/*D*/ ~ParticleEmitterData();
|
||||
|
|
@ -130,6 +152,9 @@ public:
|
|||
class ParticleEmitter : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
friend class afxParticlePool;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -199,7 +224,7 @@ class ParticleEmitter : public GameBase
|
|||
/// @param axis
|
||||
/// @param vel Initial velocity
|
||||
/// @param axisx
|
||||
void addParticle(const Point3F &pos, const Point3F &axis, const Point3F &vel, const Point3F &axisx);
|
||||
void addParticle(const Point3F &pos, const Point3F &axis, const Point3F &vel, const Point3F &axisx, const U32 age_offset);
|
||||
|
||||
|
||||
inline void setupBillboard( Particle *part,
|
||||
|
|
@ -236,7 +261,12 @@ class ParticleEmitter : public GameBase
|
|||
// PEngine interface
|
||||
private:
|
||||
|
||||
// AFX subclasses to ParticleEmitter require access to some members and methods of
|
||||
// ParticleEmitter which are normally declared with private scope. In this section,
|
||||
// protected and private scope statements have been inserted inline with the original
|
||||
// code to expose the necessary members and methods.
|
||||
void update( U32 ms );
|
||||
protected:
|
||||
inline void updateKeyData( Particle *part );
|
||||
|
||||
|
||||
|
|
@ -248,25 +278,30 @@ class ParticleEmitter : public GameBase
|
|||
|
||||
ParticleEmitterData* mDataBlock;
|
||||
|
||||
protected:
|
||||
U32 mInternalClock;
|
||||
|
||||
U32 mNextParticleTime;
|
||||
|
||||
Point3F mLastPosition;
|
||||
bool mHasLastPosition;
|
||||
private:
|
||||
MatrixF mBBObjToWorld;
|
||||
|
||||
bool mDeleteWhenEmpty;
|
||||
bool mDeleteOnTick;
|
||||
|
||||
protected:
|
||||
S32 mLifetimeMS;
|
||||
S32 mElapsedTimeMS;
|
||||
|
||||
private:
|
||||
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
|
||||
LinearColorF colors[ ParticleData::PDC_NUM_KEYS ];
|
||||
|
||||
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
|
||||
|
||||
protected:
|
||||
// These members are for implementing a link-list of the active emitter
|
||||
// particles. Member part_store contains blocks of particles that can be
|
||||
// chained in a link-list. Usually the first part_store block is large
|
||||
|
|
@ -277,8 +312,28 @@ class ParticleEmitter : public GameBase
|
|||
Particle part_list_head;
|
||||
S32 n_part_capacity;
|
||||
S32 n_parts;
|
||||
private:
|
||||
S32 mCurBuffSize;
|
||||
|
||||
protected:
|
||||
F32 fade_amt;
|
||||
bool forced_bbox;
|
||||
bool db_temp_clone;
|
||||
Point3F pos_pe;
|
||||
S8 sort_priority;
|
||||
virtual void sub_particleUpdate(Particle*) { }
|
||||
public:
|
||||
virtual void emitParticlesExt(const MatrixF& xfm, const Point3F& point, const Point3F& velocity, const U32 numMilliseconds);
|
||||
void setFadeAmount(F32 amt) { fade_amt = amt; }
|
||||
void setForcedObjBox(Box3F& box);
|
||||
void setSortPriority(S8 priority);
|
||||
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||
protected:
|
||||
afxParticlePool* pool;
|
||||
public:
|
||||
void clearPool() { pool = 0; }
|
||||
void setPool(afxParticlePool* p) { pool = p; }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // _H_PARTICLE_EMITTER
|
||||
|
|
|
|||
Loading…
Reference in a new issue