mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 15:44:36 +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
2 changed files with 297 additions and 31 deletions
|
|
@ -24,6 +24,7 @@
|
||||||
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
// Copyright (C) 2015 Faust Logic, Inc.
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "T3D/fx/particleEmitter.h"
|
#include "T3D/fx/particleEmitter.h"
|
||||||
|
|
||||||
|
|
@ -42,6 +43,10 @@
|
||||||
#include "lighting/lightInfo.h"
|
#include "lighting/lightInfo.h"
|
||||||
#include "console/engineAPI.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 );
|
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;
|
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;
|
alignParticles = false;
|
||||||
alignDirection = Point3F(0.0f, 1.0f, 0.0f);
|
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" );
|
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
|
// disallow some field substitutions
|
||||||
disableFieldSubstitutions("particles");
|
disableFieldSubstitutions("particles");
|
||||||
onlyKeepClearSubstitutions("poolData"); // subs resolving to "~~", or "~0" are OK
|
onlyKeepClearSubstitutions("poolData"); // subs resolving to "~~", or "~0" are OK
|
||||||
|
|
@ -365,6 +402,22 @@ void ParticleEmitterData::packData(BitStream* stream)
|
||||||
stream->writeFlag(renderReflection);
|
stream->writeFlag(renderReflection);
|
||||||
stream->writeFlag(glow);
|
stream->writeFlag(glow);
|
||||||
stream->writeInt( blendStyle, 4 );
|
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();
|
renderReflection = stream->readFlag();
|
||||||
glow = stream->readFlag();
|
glow = stream->readFlag();
|
||||||
blendStyle = stream->readInt( 4 );
|
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 (!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
|
// load emitter texture if specified
|
||||||
if (textureName && textureName[0])
|
if (textureName && textureName[0])
|
||||||
{
|
{
|
||||||
|
|
@ -676,6 +761,8 @@ void ParticleEmitterData::allocPrimBuffer( S32 overrideSize )
|
||||||
|
|
||||||
partListInitSize = maxPartLife / (ejectionPeriodMS - periodVarianceMS);
|
partListInitSize = maxPartLife / (ejectionPeriodMS - periodVarianceMS);
|
||||||
partListInitSize += 8; // add 8 as "fudge factor" to make sure it doesn't realloc if it goes over by 1
|
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 override size is specified, then the emitter overran its buffer and needs a larger allocation
|
||||||
if( overrideSize != -1 )
|
if( overrideSize != -1 )
|
||||||
|
|
@ -871,7 +958,16 @@ ParticleEmitter::ParticleEmitter()
|
||||||
|
|
||||||
// ParticleEmitter should be allocated on the client only.
|
// ParticleEmitter should be allocated on the client only.
|
||||||
mNetFlags.set( IsGhost );
|
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;
|
mDataBlock = 0;
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
pool = 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -920,6 +1016,11 @@ bool ParticleEmitter::onAdd()
|
||||||
mObjBox.maxExtents = Point3F(radius, radius, radius);
|
mObjBox.maxExtents = Point3F(radius, radius, radius);
|
||||||
resetWorldBox();
|
resetWorldBox();
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
pool->addParticleEmitter(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -929,6 +1030,14 @@ bool ParticleEmitter::onAdd()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::onRemove()
|
void ParticleEmitter::onRemove()
|
||||||
{
|
{
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
{
|
||||||
|
pool->removeParticleEmitter(this);
|
||||||
|
pool = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
removeFromScene();
|
removeFromScene();
|
||||||
Parent::onRemove();
|
Parent::onRemove();
|
||||||
}
|
}
|
||||||
|
|
@ -1015,6 +1124,11 @@ LinearColorF ParticleEmitter::getCollectiveColor()
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
||||||
{
|
{
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( state->isReflectPass() && !getDataBlock()->renderReflection )
|
if( state->isReflectPass() && !getDataBlock()->renderReflection )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1043,6 +1157,7 @@ void ParticleEmitter::prepRenderImage(SceneRenderState* state)
|
||||||
ri->translucentSort = true;
|
ri->translucentSort = true;
|
||||||
ri->type = RenderPassManager::RIT_Particle;
|
ri->type = RenderPassManager::RIT_Particle;
|
||||||
ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint( camPos );
|
ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint( camPos );
|
||||||
|
ri->defaultKey = (-sort_priority*100);
|
||||||
|
|
||||||
// Draw the system offscreen unless the highResOnly flag is set on the datablock
|
// Draw the system offscreen unless the highResOnly flag is set on the datablock
|
||||||
ri->systemState = ( getDataBlock()->highResOnly ? PSS_AwaitingHighResDraw : PSS_AwaitingOffscreenDraw );
|
ri->systemState = ( getDataBlock()->highResOnly ? PSS_AwaitingHighResDraw : PSS_AwaitingOffscreenDraw );
|
||||||
|
|
@ -1146,6 +1261,7 @@ void ParticleEmitter::emitParticles(const Point3F& point,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos_pe = point;
|
||||||
Point3F realStart;
|
Point3F realStart;
|
||||||
if( useLastPosition && mHasLastPosition )
|
if( useLastPosition && mHasLastPosition )
|
||||||
realStart = mLastPosition;
|
realStart = mLastPosition;
|
||||||
|
|
@ -1213,7 +1329,8 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
||||||
// Create particle at the correct position
|
// Create particle at the correct position
|
||||||
Point3F pos;
|
Point3F pos;
|
||||||
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
||||||
addParticle(pos, axis, velocity, axisx);
|
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
|
||||||
|
|
||||||
particlesAdded = true;
|
particlesAdded = true;
|
||||||
mNextParticleTime = 0;
|
mNextParticleTime = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1243,7 +1360,7 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
||||||
// Create particle at the correct position
|
// Create particle at the correct position
|
||||||
Point3F pos;
|
Point3F pos;
|
||||||
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
pos.interpolate(start, end, F32(currTime) / F32(numMilliseconds));
|
||||||
addParticle(pos, axis, velocity, axisx);
|
addParticle(pos, axis, velocity, axisx, numMilliseconds-currTime);
|
||||||
particlesAdded = true;
|
particlesAdded = true;
|
||||||
|
|
||||||
// This override-advance code is restored in order to correctly adjust
|
// This override-advance code is restored in order to correctly adjust
|
||||||
|
|
@ -1268,17 +1385,27 @@ void ParticleEmitter::emitParticles(const Point3F& start,
|
||||||
{
|
{
|
||||||
if (advanceMS != 0)
|
if (advanceMS != 0)
|
||||||
{
|
{
|
||||||
F32 t = F32(advanceMS) / 1000.0;
|
F32 t = F32(advanceMS) / 1000.0;
|
||||||
|
|
||||||
Point3F a = last_part->acc;
|
Point3F a = last_part->acc;
|
||||||
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
|
a -= last_part->vel * last_part->dataBlock->dragCoefficient;
|
||||||
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
|
a -= mWindVelocity * last_part->dataBlock->windCoefficient;
|
||||||
a += Point3F(0.0f, 0.0f, -9.81f) * last_part->dataBlock->gravityCoefficient;
|
//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->vel += a * t;
|
||||||
last_part->pos += last_part->vel * 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();
|
axis.normalize();
|
||||||
pos += rCenter;
|
pos += rCenter;
|
||||||
|
|
||||||
addParticle(pos, axis, velocity, axisz);
|
addParticle(pos, axis, velocity, axisz, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set world bounding box
|
// Set world bounding box
|
||||||
|
|
@ -1373,6 +1500,8 @@ void ParticleEmitter::emitParticles(const Point3F& rCenter,
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::updateBBox()
|
void ParticleEmitter::updateBBox()
|
||||||
{
|
{
|
||||||
|
if (forced_bbox)
|
||||||
|
return;
|
||||||
Point3F minPt(1e10, 1e10, 1e10);
|
Point3F minPt(1e10, 1e10, 1e10);
|
||||||
Point3F maxPt(-1e10, -1e10, -1e10);
|
Point3F maxPt(-1e10, -1e10, -1e10);
|
||||||
|
|
||||||
|
|
@ -1393,15 +1522,18 @@ void ParticleEmitter::updateBBox()
|
||||||
boxScale.y = getMax(boxScale.y, 1.0f);
|
boxScale.y = getMax(boxScale.y, 1.0f);
|
||||||
boxScale.z = getMax(boxScale.z, 1.0f);
|
boxScale.z = getMax(boxScale.z, 1.0f);
|
||||||
mBBObjToWorld.scale(boxScale);
|
mBBObjToWorld.scale(boxScale);
|
||||||
|
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
if (pool)
|
||||||
|
pool->updatePoolBBox(this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// addParticle
|
// addParticle
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::addParticle(const Point3F& pos,
|
void ParticleEmitter::addParticle(const Point3F& pos, const Point3F& axis, const Point3F& vel,
|
||||||
const Point3F& axis,
|
const Point3F& axisx, const U32 age_offset)
|
||||||
const Point3F& vel,
|
|
||||||
const Point3F& axisx)
|
|
||||||
{
|
{
|
||||||
n_parts++;
|
n_parts++;
|
||||||
if (n_parts > n_part_capacity || n_parts > mDataBlock->partListInitSize)
|
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;
|
pNew->next = part_list_head.next;
|
||||||
part_list_head.next = pNew;
|
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;
|
Point3F ejectionAxis = axis;
|
||||||
F32 theta = (mDataBlock->thetaMax - mDataBlock->thetaMin) * gRandGen.randF() +
|
F32 theta = (mDataBlock->thetaMax - mDataBlock->thetaMin) * gRandGen.randF() +
|
||||||
mDataBlock->thetaMin;
|
mDataBlock->thetaMin;
|
||||||
|
|
@ -1444,14 +1586,17 @@ void ParticleEmitter::addParticle(const Point3F& pos,
|
||||||
F32 initialVel = mDataBlock->ejectionVelocity;
|
F32 initialVel = mDataBlock->ejectionVelocity;
|
||||||
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
|
initialVel += (mDataBlock->velocityVariance * 2.0f * gRandGen.randF()) - mDataBlock->velocityVariance;
|
||||||
|
|
||||||
pNew->pos = pos + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
|
pNew->pos = pos_start + (ejectionAxis * (mDataBlock->ejectionOffset + mDataBlock->ejectionOffsetVariance* gRandGen.randF()) );
|
||||||
pNew->vel = ejectionAxis * initialVel;
|
pNew->pos_local = pNew->pos;
|
||||||
pNew->orientDir = ejectionAxis;
|
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->acc.set(0, 0, 0);
|
||||||
pNew->currentAge = 0;
|
pNew->currentAge = age_offset;
|
||||||
|
pNew->t_last = 0.0f;
|
||||||
// Choose a new particle datablack randomly from the list
|
|
||||||
U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size();
|
|
||||||
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
|
mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel);
|
||||||
updateKeyData( pNew );
|
updateKeyData( pNew );
|
||||||
|
|
||||||
|
|
@ -1533,8 +1678,10 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
||||||
if( part->totalLifetime < 1 )
|
if( part->totalLifetime < 1 )
|
||||||
part->totalLifetime = 1;
|
part->totalLifetime = 1;
|
||||||
|
|
||||||
F32 t = F32(part->currentAge) / F32(part->totalLifetime);
|
if (part->currentAge > part->totalLifetime)
|
||||||
AssertFatal(t <= 1.0f, "Out out bounds filter function for particle.");
|
part->currentAge = part->totalLifetime;
|
||||||
|
F32 t = (F32)part->currentAge / (F32)part->totalLifetime;
|
||||||
|
|
||||||
|
|
||||||
for( U32 i = 1; i < ParticleData::PDC_NUM_KEYS; i++ )
|
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->size = (part->dataBlock->sizes[i-1] * (1.0 - firstPart)) +
|
||||||
(part->dataBlock->sizes[i] * 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;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1578,19 +1743,25 @@ void ParticleEmitter::updateKeyData( Particle *part )
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void ParticleEmitter::update( U32 ms )
|
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)
|
for (Particle* part = part_list_head.next; part != NULL; part = part->next)
|
||||||
{
|
{
|
||||||
F32 t = F32(ms) / 1000.0;
|
|
||||||
|
|
||||||
Point3F a = part->acc;
|
Point3F a = part->acc;
|
||||||
a -= part->vel * part->dataBlock->dragCoefficient;
|
a -= part->vel * part->dataBlock->dragCoefficient;
|
||||||
a -= mWindVelocity * part->dataBlock->windCoefficient;
|
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->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 );
|
updateKeyData( part );
|
||||||
}
|
}
|
||||||
|
|
@ -2153,3 +2324,43 @@ DefineEngineMethod(ParticleEmitterData, reload, void,(),,
|
||||||
{
|
{
|
||||||
object->reload();
|
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
|
// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
|
||||||
// Copyright (C) 2015 Faust Logic, Inc.
|
// Copyright (C) 2015 Faust Logic, Inc.
|
||||||
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|
||||||
|
|
||||||
#ifndef _H_PARTICLE_EMITTER
|
#ifndef _H_PARTICLE_EMITTER
|
||||||
#define _H_PARTICLE_EMITTER
|
#define _H_PARTICLE_EMITTER
|
||||||
|
|
||||||
|
|
@ -46,6 +47,12 @@
|
||||||
class RenderPassManager;
|
class RenderPassManager;
|
||||||
class ParticleData;
|
class ParticleData;
|
||||||
|
|
||||||
|
#define AFX_CAP_PARTICLE_POOLS
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
class afxParticlePoolData;
|
||||||
|
class afxParticlePool;
|
||||||
|
#endif
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Particle Emitter Data
|
// Particle Emitter Data
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
@ -117,6 +124,21 @@ class ParticleEmitterData : public GameBaseData
|
||||||
bool glow; ///< Renders this emitter into the glow buffer.
|
bool glow; ///< Renders this emitter into the glow buffer.
|
||||||
|
|
||||||
bool reload();
|
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:
|
public:
|
||||||
/*C*/ ParticleEmitterData(const ParticleEmitterData&, bool = false);
|
/*C*/ ParticleEmitterData(const ParticleEmitterData&, bool = false);
|
||||||
/*D*/ ~ParticleEmitterData();
|
/*D*/ ~ParticleEmitterData();
|
||||||
|
|
@ -130,6 +152,9 @@ public:
|
||||||
class ParticleEmitter : public GameBase
|
class ParticleEmitter : public GameBase
|
||||||
{
|
{
|
||||||
typedef GameBase Parent;
|
typedef GameBase Parent;
|
||||||
|
#if defined(AFX_CAP_PARTICLE_POOLS)
|
||||||
|
friend class afxParticlePool;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -199,7 +224,7 @@ class ParticleEmitter : public GameBase
|
||||||
/// @param axis
|
/// @param axis
|
||||||
/// @param vel Initial velocity
|
/// @param vel Initial velocity
|
||||||
/// @param axisx
|
/// @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,
|
inline void setupBillboard( Particle *part,
|
||||||
|
|
@ -236,7 +261,12 @@ class ParticleEmitter : public GameBase
|
||||||
// PEngine interface
|
// PEngine interface
|
||||||
private:
|
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 );
|
void update( U32 ms );
|
||||||
|
protected:
|
||||||
inline void updateKeyData( Particle *part );
|
inline void updateKeyData( Particle *part );
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -248,25 +278,30 @@ class ParticleEmitter : public GameBase
|
||||||
|
|
||||||
ParticleEmitterData* mDataBlock;
|
ParticleEmitterData* mDataBlock;
|
||||||
|
|
||||||
|
protected:
|
||||||
U32 mInternalClock;
|
U32 mInternalClock;
|
||||||
|
|
||||||
U32 mNextParticleTime;
|
U32 mNextParticleTime;
|
||||||
|
|
||||||
Point3F mLastPosition;
|
Point3F mLastPosition;
|
||||||
bool mHasLastPosition;
|
bool mHasLastPosition;
|
||||||
|
private:
|
||||||
MatrixF mBBObjToWorld;
|
MatrixF mBBObjToWorld;
|
||||||
|
|
||||||
bool mDeleteWhenEmpty;
|
bool mDeleteWhenEmpty;
|
||||||
bool mDeleteOnTick;
|
bool mDeleteOnTick;
|
||||||
|
|
||||||
|
protected:
|
||||||
S32 mLifetimeMS;
|
S32 mLifetimeMS;
|
||||||
S32 mElapsedTimeMS;
|
S32 mElapsedTimeMS;
|
||||||
|
|
||||||
|
private:
|
||||||
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
|
F32 sizes[ ParticleData::PDC_NUM_KEYS ];
|
||||||
LinearColorF colors[ ParticleData::PDC_NUM_KEYS ];
|
LinearColorF colors[ ParticleData::PDC_NUM_KEYS ];
|
||||||
|
|
||||||
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
|
GFXVertexBufferHandle<ParticleVertexType> mVertBuff;
|
||||||
|
|
||||||
|
protected:
|
||||||
// These members are for implementing a link-list of the active emitter
|
// These members are for implementing a link-list of the active emitter
|
||||||
// particles. Member part_store contains blocks of particles that can be
|
// particles. Member part_store contains blocks of particles that can be
|
||||||
// chained in a link-list. Usually the first part_store block is large
|
// 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;
|
Particle part_list_head;
|
||||||
S32 n_part_capacity;
|
S32 n_part_capacity;
|
||||||
S32 n_parts;
|
S32 n_parts;
|
||||||
|
private:
|
||||||
S32 mCurBuffSize;
|
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
|
#endif // _H_PARTICLE_EMITTER
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue