From 9b2caeed6af0907467b856ee3d59ee10c24f7250 Mon Sep 17 00:00:00 2001 From: bank Date: Fri, 18 Jan 2013 15:07:27 +0400 Subject: [PATCH 1/2] Fix for issue #210 for ParticleData sends out-of-range data via BitStream 1. When addProtectedField used with custom setters, we need to return false, or it will set the value via regular routine after the method exists (change ParticleData::protectedSetTimes() to return false instead of true). 2. The ParticleData::sizes[] needs a custom setter, so the value is clamped in a range of 0.f and MaxParticleSize. 3. The spinRadnomMin and spinRandomMax ParticleData fields need a FRangeValidator, so it auto-clamped in a range of -1000 to 1000, as we are writing data trying to fit the values in 11 bits (as UInt upto 2048 max). * The description for those fields needs to be updated to use 1000 instead of 10000. * ParticleData::onAdd() should check for values to be in a correct range too. --- Engine/source/T3D/fx/particle.cpp | 35 +++++++++++++++++++++++-------- Engine/source/T3D/fx/particle.h | 1 + 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Engine/source/T3D/fx/particle.cpp b/Engine/source/T3D/fx/particle.cpp index 2e331fb7f..ca8ead21f 100644 --- a/Engine/source/T3D/fx/particle.cpp +++ b/Engine/source/T3D/fx/particle.cpp @@ -149,10 +149,10 @@ void ParticleData::initPersistFields() "Variance in lifetime of particle, from 0 - lifetimeMS." ); addField( "spinSpeed", TYPEID< F32 >(), Offset(spinSpeed, ParticleData), "Speed at which to spin the particle." ); - addField( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData), - "Minimum allowed spin speed of this particle, between -10000 and spinRandomMax." ); - addField( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData), - "Maximum allowed spin speed of this particle, between spinRandomMin and 10000." ); + addFieldV( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData), new FRangeValidator(-1000.f, 1000.f), + "Minimum allowed spin speed of this particle, between -1000 and spinRandomMax." ); + addFieldV( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData), new FRangeValidator(-1000.f, 1000.f), + "Maximum allowed spin speed of this particle, between spinRandomMin and 1000." ); addField( "useInvAlpha", TYPEID< bool >(), Offset(useInvAlpha, ParticleData), "@brief Controls how particles blend with the scene.\n\n" "If true, particles blend like ParticleBlendStyle NORMAL, if false, " @@ -200,7 +200,8 @@ void ParticleData::initPersistFields() "@brief Particle RGBA color keyframe values.\n\n" "The particle color will linearly interpolate between the color/time keys " "over the lifetime of the particle." ); - addField( "sizes", TYPEID< F32 >(), Offset(sizes, ParticleData), PDC_NUM_KEYS, + addProtectedField( "sizes", TYPEID< F32 >(), Offset(sizes, ParticleData), &protectedSetSizes, + &defaultProtectedGetFn, PDC_NUM_KEYS, "@brief Particle size keyframe values.\n\n" "The particle size will linearly interpolate between the size/time keys " "over the lifetime of the particle." ); @@ -343,6 +344,22 @@ void ParticleData::unpackData(BitStream* stream) } } +bool ParticleData::protectedSetSizes( void *object, const char *index, const char *data) +{ + ParticleData *pData = static_cast( object ); + F32 val = dAtof(data); + U32 i; + + if (!index) + i = 0; + else + i = dAtoui(index); + + pData->sizes[i] = mClampF( val, 0.f, MaxParticleSize ); + + return false; +} + bool ParticleData::protectedSetTimes( void *object, const char *index, const char *data) { ParticleData *pData = static_cast( object ); @@ -356,7 +373,7 @@ bool ParticleData::protectedSetTimes( void *object, const char *index, const cha pData->times[i] = mClampF( val, 0.f, 1.f ); - return true; + return false; } //----------------------------------------------------------------------------- @@ -379,11 +396,11 @@ bool ParticleData::onAdd() Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) lifetimeVariance >= lifetime", getName()); lifetimeVarianceMS = lifetimeMS - 1; } - if (spinSpeed > 10000.0 || spinSpeed < -10000.0) { + if (spinSpeed > 1000.f || spinSpeed < -1000.f) { Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinSpeed invalid", getName()); return false; } - if (spinRandomMin > 10000.0 || spinRandomMin < -10000.0) { + if (spinRandomMin > 1000.f || spinRandomMin < -1000.f) { Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMin invalid", getName()); spinRandomMin = -360.0; return false; @@ -393,7 +410,7 @@ bool ParticleData::onAdd() spinRandomMin = spinRandomMax - (spinRandomMin - spinRandomMax ); return false; } - if (spinRandomMax > 10000.0 || spinRandomMax < -10000.0) { + if (spinRandomMax > 1000.f || spinRandomMax < -1000.f) { Con::warnf(ConsoleLogEntry::General, "ParticleData(%s) spinRandomMax invalid", getName()); spinRandomMax = 360.0; return false; diff --git a/Engine/source/T3D/fx/particle.h b/Engine/source/T3D/fx/particle.h index 3f1b7ff26..14db8c096 100644 --- a/Engine/source/T3D/fx/particle.h +++ b/Engine/source/T3D/fx/particle.h @@ -79,6 +79,7 @@ class ParticleData : public SimDataBlock StringTableEntry textureName; GFXTexHandle textureHandle; + static bool protectedSetSizes( void *object, const char *index, const char *data ); static bool protectedSetTimes( void *object, const char *index, const char *data ); public: From 82de08b57ab57506d7ee1b9db9cd3cb514612aba Mon Sep 17 00:00:00 2001 From: bank Date: Fri, 1 Feb 2013 21:22:03 +0400 Subject: [PATCH 2/2] Fix memory leak (ParticleData and ParticleEmitterData) on using TypeValidator class. This fixes issue #154 --- Engine/source/T3D/fx/particle.cpp | 12 ++++++++---- Engine/source/T3D/fx/particleEmitter.cpp | 25 +++++++++++++++--------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Engine/source/T3D/fx/particle.cpp b/Engine/source/T3D/fx/particle.cpp index ca8ead21f..da53be6c6 100644 --- a/Engine/source/T3D/fx/particle.cpp +++ b/Engine/source/T3D/fx/particle.cpp @@ -128,16 +128,20 @@ ParticleData::~ParticleData() } } +FRangeValidator dragCoefFValidator(0.f, 5.f); +FRangeValidator gravCoefFValidator(-10.f, 10.f); +FRangeValidator spinRandFValidator(-1000.f, 1000.f); + //----------------------------------------------------------------------------- // initPersistFields //----------------------------------------------------------------------------- void ParticleData::initPersistFields() { - addFieldV( "dragCoefficient", TYPEID< F32 >(), Offset(dragCoefficient, ParticleData), new FRangeValidator(0, 5), + addFieldV( "dragCoefficient", TYPEID< F32 >(), Offset(dragCoefficient, ParticleData), &dragCoefFValidator, "Particle physics drag amount." ); addField( "windCoefficient", TYPEID< F32 >(), Offset(windCoefficient, ParticleData), "Strength of wind on the particles." ); - addFieldV( "gravityCoefficient", TYPEID< F32 >(), Offset(gravityCoefficient, ParticleData), new FRangeValidator(-10, 10), + addFieldV( "gravityCoefficient", TYPEID< F32 >(), Offset(gravityCoefficient, ParticleData), &gravCoefFValidator, "Strength of gravity on the particles." ); addFieldV( "inheritedVelFactor", TYPEID< F32 >(), Offset(inheritedVelFactor, ParticleData), &CommonValidators::NormalizedFloat, "Amount of emitter velocity to add to particle initial velocity." ); @@ -149,9 +153,9 @@ void ParticleData::initPersistFields() "Variance in lifetime of particle, from 0 - lifetimeMS." ); addField( "spinSpeed", TYPEID< F32 >(), Offset(spinSpeed, ParticleData), "Speed at which to spin the particle." ); - addFieldV( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData), new FRangeValidator(-1000.f, 1000.f), + addFieldV( "spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData), &spinRandFValidator, "Minimum allowed spin speed of this particle, between -1000 and spinRandomMax." ); - addFieldV( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData), new FRangeValidator(-1000.f, 1000.f), + addFieldV( "spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData), &spinRandFValidator, "Maximum allowed spin speed of this particle, between spinRandomMin and 1000." ); addField( "useInvAlpha", TYPEID< bool >(), Offset(useInvAlpha, ParticleData), "@brief Controls how particles blend with the scene.\n\n" diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index 100fbe185..bab62dba8 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -171,6 +171,13 @@ ImplementEnumType( ParticleBlendStyle, { ParticleRenderInst::BlendPremultAlpha, "PREMULTALPHA", "Color blends with the colors of the imagemap rather than the alpha.\n" }, EndImplementEnumType; +IRangeValidator ejectPeriodIValidator(1, 2047); +IRangeValidator periodVarianceIValidator(0, 2047); +FRangeValidator ejectionFValidator(0.f, 655.35f); +FRangeValidator velVarianceFValidator(0.f, 163.83f); +FRangeValidator thetaFValidator(0.f, 180.f); +FRangeValidator phiFValidator(0.f, 360.f); + //----------------------------------------------------------------------------- // initPersistFields //----------------------------------------------------------------------------- @@ -178,31 +185,31 @@ void ParticleEmitterData::initPersistFields() { addGroup( "ParticleEmitterData" ); - addFieldV("ejectionPeriodMS", TYPEID< S32 >(), Offset(ejectionPeriodMS, ParticleEmitterData), new IRangeValidator(1, 2047), + addFieldV("ejectionPeriodMS", TYPEID< S32 >(), Offset(ejectionPeriodMS, ParticleEmitterData), &ejectPeriodIValidator, "Time (in milliseconds) between each particle ejection." ); - addFieldV("periodVarianceMS", TYPEID< S32 >(), Offset(periodVarianceMS, ParticleEmitterData), new IRangeValidator(0, 2047), + addFieldV("periodVarianceMS", TYPEID< S32 >(), Offset(periodVarianceMS, ParticleEmitterData), &periodVarianceIValidator, "Variance in ejection period, from 1 - ejectionPeriodMS." ); - addFieldV( "ejectionVelocity", TYPEID< F32 >(), Offset(ejectionVelocity, ParticleEmitterData), new FRangeValidator(0, 655.35f), + addFieldV( "ejectionVelocity", TYPEID< F32 >(), Offset(ejectionVelocity, ParticleEmitterData), &ejectionFValidator, "Particle ejection velocity." ); - addFieldV( "velocityVariance", TYPEID< F32 >(), Offset(velocityVariance, ParticleEmitterData), new FRangeValidator(0, 163.83f), + addFieldV( "velocityVariance", TYPEID< F32 >(), Offset(velocityVariance, ParticleEmitterData), &velVarianceFValidator, "Variance for ejection velocity, from 0 - ejectionVelocity." ); - addFieldV( "ejectionOffset", TYPEID< F32 >(), Offset(ejectionOffset, ParticleEmitterData), new FRangeValidator(0, 655.35f), + addFieldV( "ejectionOffset", TYPEID< F32 >(), Offset(ejectionOffset, ParticleEmitterData), &ejectionFValidator, "Distance along ejection Z axis from which to eject particles." ); - addFieldV( "thetaMin", TYPEID< F32 >(), Offset(thetaMin, ParticleEmitterData), new FRangeValidator(0, 180.0f), + addFieldV( "thetaMin", TYPEID< F32 >(), Offset(thetaMin, ParticleEmitterData), &thetaFValidator, "Minimum angle, from the horizontal plane, to eject from." ); - addFieldV( "thetaMax", TYPEID< F32 >(), Offset(thetaMax, ParticleEmitterData), new FRangeValidator(0, 180.0f), + addFieldV( "thetaMax", TYPEID< F32 >(), Offset(thetaMax, ParticleEmitterData), &thetaFValidator, "Maximum angle, from the horizontal plane, to eject particles from." ); - addFieldV( "phiReferenceVel", TYPEID< F32 >(), Offset(phiReferenceVel, ParticleEmitterData), new FRangeValidator(0, 360.0f), + addFieldV( "phiReferenceVel", TYPEID< F32 >(), Offset(phiReferenceVel, ParticleEmitterData), &phiFValidator, "Reference angle, from the vertical plane, to eject particles from." ); - addFieldV( "phiVariance", TYPEID< F32 >(), Offset(phiVariance, ParticleEmitterData), new FRangeValidator(0, 360.0f), + addFieldV( "phiVariance", TYPEID< F32 >(), Offset(phiVariance, ParticleEmitterData), &phiFValidator, "Variance from the reference angle, from 0 - 360." ); addField( "softnessDistance", TYPEID< F32 >(), Offset(softnessDistance, ParticleEmitterData),