enhanced-particle -- Accounts for larger number of particle size keys.

This commit is contained in:
Marc Chapman 2017-07-26 23:24:08 +01:00
parent 6910ee584d
commit 169e539e47
3 changed files with 123 additions and 23 deletions

View file

@ -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/debris.h" #include "T3D/debris.h"
@ -633,7 +634,8 @@ bool Debris::onAdd()
{ {
sizeList[0] = mSize * 0.5; sizeList[0] = mSize * 0.5;
sizeList[1] = mSize; sizeList[1] = mSize;
sizeList[2] = mSize * 1.5; for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
sizeList[i] = mSize * 1.5;
mEmitterList[0]->setSizes( sizeList ); mEmitterList[0]->setSizes( sizeList );
} }
@ -642,7 +644,8 @@ bool Debris::onAdd()
{ {
sizeList[0] = 0.0; sizeList[0] = 0.0;
sizeList[1] = mSize * 0.5; sizeList[1] = mSize * 0.5;
sizeList[2] = mSize; for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
sizeList[i] = mSize;
mEmitterList[1]->setSizes( sizeList ); mEmitterList[1]->setSizes( sizeList );
} }

View file

@ -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 "particle.h" #include "particle.h"
#include "console/consoleTypes.h" #include "console/consoleTypes.h"
#include "console/typeValidators.h" #include "console/typeValidators.h"
@ -77,6 +78,8 @@ static const F32 sgDefaultSpinSpeed = 1.f;
static const F32 sgDefaultSpinRandomMin = 0.f; static const F32 sgDefaultSpinRandomMin = 0.f;
static const F32 sgDefaultSpinRandomMax = 0.f; static const F32 sgDefaultSpinRandomMax = 0.f;
static const F32 sgDefaultSpinBias = 1.0f;
static const F32 sgDefaultSizeBias = 1.0f;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Constructor // Constructor
@ -107,9 +110,9 @@ ParticleData::ParticleData()
} }
times[0] = 0.0f; times[0] = 0.0f;
times[1] = 0.33f; times[1] = 1.0f;
times[2] = 0.66f; for (i = 2; i < PDC_NUM_KEYS; i++)
times[3] = 1.0f; times[i] = -1.0f;
texCoords[0].set(0.0,0.0); // texture coords at 4 corners texCoords[0].set(0.0,0.0); // texture coords at 4 corners
texCoords[1].set(0.0,1.0); // of particle quad texCoords[1].set(0.0,1.0); // of particle quad
@ -120,18 +123,20 @@ ParticleData::ParticleData()
animTexUVs = NULL; // array of tile vertex UVs animTexUVs = NULL; // array of tile vertex UVs
textureName = NULL; // texture filename textureName = NULL; // texture filename
textureHandle = NULL; // loaded texture handle textureHandle = NULL; // loaded texture handle
textureExtName = NULL;
textureExtHandle = NULL;
constrain_pos = false;
start_angle = 0.0f;
angle_variance = 0.0f;
sizeBias = sgDefaultSizeBias;
spinBias = sgDefaultSpinBias;
randomizeSpinDir = false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Destructor // Destructor
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ParticleData::~ParticleData()
{
if (animTexUVs)
{
delete [] animTexUVs;
}
}
FRangeValidator dragCoefFValidator(0.f, 5.f); FRangeValidator dragCoefFValidator(0.f, 5.f);
FRangeValidator gravCoefFValidator(-10.f, 10.f); FRangeValidator gravCoefFValidator(-10.f, 10.f);
@ -219,6 +224,15 @@ void ParticleData::initPersistFields()
"@brief Time keys used with the colors and sizes keyframes.\n\n" "@brief Time keys used with the colors and sizes keyframes.\n\n"
"Values are from 0.0 (particle creation) to 1.0 (end of lifespace)." ); "Values are from 0.0 (particle creation) to 1.0 (end of lifespace)." );
addGroup("AFX");
addField("textureExtName", TypeFilename, Offset(textureExtName, ParticleData));
addField("constrainPos", TypeBool, Offset(constrain_pos, ParticleData));
addField("angle", TypeF32, Offset(start_angle, ParticleData));
addField("angleVariance", TypeF32, Offset(angle_variance, ParticleData));
addField("sizeBias", TypeF32, Offset(sizeBias, ParticleData));
addField("spinBias", TypeF32, Offset(spinBias, ParticleData));
addField("randomizeSpinDir", TypeBool, Offset(randomizeSpinDir, ParticleData));
endGroup("AFX");
Parent::initPersistFields(); Parent::initPersistFields();
} }
@ -248,18 +262,22 @@ void ParticleData::packData(BitStream* stream)
stream->writeInt((S32)(spinRandomMin + 1000), 11); stream->writeInt((S32)(spinRandomMin + 1000), 11);
stream->writeInt((S32)(spinRandomMax + 1000), 11); stream->writeInt((S32)(spinRandomMax + 1000), 11);
} }
if(stream->writeFlag(spinBias != sgDefaultSpinBias))
stream->write(spinBias);
stream->writeFlag(randomizeSpinDir);
stream->writeFlag(useInvAlpha); stream->writeFlag(useInvAlpha);
S32 i, count; S32 i, count;
// see how many frames there are: // see how many frames there are:
for(count = 0; count < 3; count++) for(count = 0; count < ParticleData::PDC_NUM_KEYS-1; count++)
if(times[count] >= 1) if(times[count] >= 1)
break; break;
count++; count++;
stream->writeInt(count-1, 2); // An extra bit is needed for 8 keys.
stream->writeInt(count-1, 3);
for( i=0; i<count; i++ ) for( i=0; i<count; i++ )
{ {
@ -267,7 +285,8 @@ void ParticleData::packData(BitStream* stream)
stream->writeFloat( colors[i].green, 7); stream->writeFloat( colors[i].green, 7);
stream->writeFloat( colors[i].blue, 7); stream->writeFloat( colors[i].blue, 7);
stream->writeFloat( colors[i].alpha, 7); stream->writeFloat( colors[i].alpha, 7);
stream->writeFloat( sizes[i]/MaxParticleSize, 14); // AFX bits raised from 14 to 16 to allow larger sizes
stream->writeFloat( sizes[i]/MaxParticleSize, 16);
stream->writeFloat( times[i], 8); stream->writeFloat( times[i], 8);
} }
@ -284,6 +303,13 @@ void ParticleData::packData(BitStream* stream)
mathWrite(*stream, animTexTiling); mathWrite(*stream, animTexTiling);
stream->writeInt(framesPerSec, 8); stream->writeInt(framesPerSec, 8);
} }
if (stream->writeFlag(textureExtName && textureExtName[0]))
stream->writeString(textureExtName);
stream->writeFlag(constrain_pos);
stream->writeFloat(start_angle/360.0f, 11);
stream->writeFloat(angle_variance/180.0f, 10);
if(stream->writeFlag(sizeBias != sgDefaultSizeBias))
stream->write(sizeBias);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -327,17 +353,24 @@ void ParticleData::unpackData(BitStream* stream)
spinRandomMax = sgDefaultSpinRandomMax; spinRandomMax = sgDefaultSpinRandomMax;
} }
if(stream->readFlag())
stream->read(&spinBias);
else
spinBias = sgDefaultSpinBias;
randomizeSpinDir = stream->readFlag();
useInvAlpha = stream->readFlag(); useInvAlpha = stream->readFlag();
S32 i; S32 i;
S32 count = stream->readInt(2) + 1; // An extra bit is needed for 8 keys.
S32 count = stream->readInt(3) + 1;
for(i = 0;i < count; i++) for(i = 0;i < count; i++)
{ {
colors[i].red = stream->readFloat(7); colors[i].red = stream->readFloat(7);
colors[i].green = stream->readFloat(7); colors[i].green = stream->readFloat(7);
colors[i].blue = stream->readFloat(7); colors[i].blue = stream->readFloat(7);
colors[i].alpha = stream->readFloat(7); colors[i].alpha = stream->readFloat(7);
sizes[i] = stream->readFloat(14) * MaxParticleSize; // AFX bits raised from 14 to 16 to allow larger sizes
sizes[i] = stream->readFloat(16) * MaxParticleSize;
times[i] = stream->readFloat(8); times[i] = stream->readFloat(8);
} }
textureName = (stream->readFlag()) ? stream->readSTString() : 0; textureName = (stream->readFlag()) ? stream->readSTString() : 0;
@ -351,6 +384,14 @@ void ParticleData::unpackData(BitStream* stream)
mathRead(*stream, &animTexTiling); mathRead(*stream, &animTexTiling);
framesPerSec = stream->readInt(8); framesPerSec = stream->readInt(8);
} }
textureExtName = (stream->readFlag()) ? stream->readSTString() : 0;
constrain_pos = stream->readFlag();
start_angle = 360.0f*stream->readFloat(11);
angle_variance = 180.0f*stream->readFloat(10);
if(stream->readFlag())
stream->read(&sizeBias);
else
sizeBias = sgDefaultSizeBias;
} }
bool ParticleData::protectedSetSizes( void *object, const char *index, const char *data) bool ParticleData::protectedSetSizes( void *object, const char *index, const char *data)
@ -432,11 +473,33 @@ bool ParticleData::onAdd()
} }
times[0] = 0.0f; times[0] = 0.0f;
for (U32 i = 1; i < 4; i++) { for (U32 i = 1; i < PDC_NUM_KEYS; i++)
if (times[i] < times[i-1]) { {
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) times[%d] < times[%d]", getName(), i, i-1); if (times[i] < 0.0f)
times[i] = times[i-1]; break;
} if (times[i] < times[i-1])
{
Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) times[%d] < times[%d]", getName(), i, i-1);
times[i] = times[i-1];
}
}
times[0] = 0.0f;
U32 last_idx = 0;
for (U32 i = 1; i < PDC_NUM_KEYS; i++)
{
if (times[i] < 0.0f)
break;
else
last_idx = i;
}
for (U32 i = last_idx+1; i < PDC_NUM_KEYS; i++)
{
times[i] = times[last_idx];
colors[i] = colors[last_idx];
sizes[i] = sizes[last_idx];
} }
// Here we validate parameters // Here we validate parameters
@ -475,6 +538,10 @@ bool ParticleData::onAdd()
} }
} }
start_angle = mFmod(start_angle, 360.0f);
if (start_angle < 0.0f)
start_angle += 360.0f;
angle_variance = mClampF(angle_variance, -180.0f, 180.0f);
return true; return true;
} }
@ -500,6 +567,15 @@ bool ParticleData::preload(bool server, String &errorStr)
error = true; error = true;
} }
} }
if (textureExtName && textureExtName[0])
{
textureExtHandle = GFXTexHandle(textureExtName, &GFXStaticTextureSRGBProfile, avar("%s() - textureExtHandle (line %d)", __FUNCTION__, __LINE__));
if (!textureExtHandle)
{
errorStr = String::ToString("Missing particle texture: %s", textureName);
error = true;
}
}
if (animateTexture) if (animateTexture)
{ {
@ -611,6 +687,11 @@ void ParticleData::initializeParticle(Particle* init, const Point3F& inheritVelo
// assign spin amount // assign spin amount
init->spinSpeed = spinSpeed * gRandGen.randF( spinRandomMin, spinRandomMax ); init->spinSpeed = spinSpeed * gRandGen.randF( spinRandomMin, spinRandomMax );
// apply spin bias
init->spinSpeed *= spinBias;
// randomize spin direction
if (randomizeSpinDir && (gRandGen.randI( 0, 1 ) == 1))
init->spinSpeed = -init->spinSpeed;
} }
bool ParticleData::reload(char errorBuffer[256]) bool ParticleData::reload(char errorBuffer[256])

View file

@ -49,7 +49,9 @@ class ParticleData : public SimDataBlock
public: public:
enum PDConst enum PDConst
{ {
PDC_NUM_KEYS = 4, // This increase the keyframes from 4 to 8. Especially useful for premult-alpha blended particles
// for which 4 keyframes is often not enough.
PDC_NUM_KEYS = 8,
}; };
F32 dragCoefficient; F32 dragCoefficient;
@ -106,6 +108,16 @@ class ParticleData : public SimDataBlock
/*C*/ ParticleData(const ParticleData&, bool = false); /*C*/ ParticleData(const ParticleData&, bool = false);
virtual void onPerformSubstitutions(); virtual void onPerformSubstitutions();
virtual bool allowSubstitutions() const { return true; } virtual bool allowSubstitutions() const { return true; }
protected:
F32 spinBias;
bool randomizeSpinDir;
StringTableEntry textureExtName;
public:
GFXTexHandle textureExtHandle;
bool constrain_pos;
F32 start_angle;
F32 angle_variance;
F32 sizeBias;
public: public:
bool loadParameters(); bool loadParameters();
bool reload(String &errorStr); bool reload(String &errorStr);
@ -135,6 +147,10 @@ struct Particle
F32 spinSpeed; F32 spinSpeed;
Particle * next; Particle * next;
Point3F pos_local;
F32 t_last;
Point3F radial_v; // radial vector for concentric effects
// note -- for non-oriented particles, we use orientDir.x to store the billboard start angle.
}; };