1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // 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/debris.h"
- #include "core/stream/bitStream.h"
- #include "math/mathUtils.h"
- #include "console/consoleTypes.h"
- #include "console/consoleObject.h"
- #include "sim/netConnection.h"
- #include "scene/sceneRenderState.h"
- #include "scene/sceneManager.h"
- #include "ts/tsShapeInstance.h"
- #include "ts/tsPartInstance.h"
- #include "T3D/fx/particleEmitter.h"
- #include "T3D/fx/explosion.h"
- #include "T3D/gameBase/gameProcess.h"
- #include "core/resourceManager.h"
- #include "gfx/gfxTransformSaver.h"
- #include "console/engineAPI.h"
- #include "lighting/lightQuery.h"
- const U32 csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
- IMPLEMENT_CO_DATABLOCK_V1(DebrisData);
- ConsoleDocClass( DebrisData,
- "@brief Stores properties for an individual debris type.\n\n"
- "DebrisData defines the base properties for a Debris object. Typically you'll want a Debris object to consist of "
- "a shape and possibly up to two particle emitters. The DebrisData datablock provides the definition for these items, "
- "along with physical properties and how a Debris object will react to other game objects, such as water and terrain.\n"
- "@tsexample\n"
- "datablock DebrisData(GrenadeDebris)\n"
- "{\n"
- " shapeFile = \"art/shapes/weapons/ramrifle/debris.dts\";\n"
- " emitters[0] = GrenadeDebrisFireEmitter;\n"
- " elasticity = 0.4;\n"
- " friction = 0.25;\n"
- " numBounces = 3;\n"
- " bounceVariance = 1;\n"
- " explodeOnMaxBounce = false;\n"
- " staticOnMaxBounce = false;\n"
- " snapOnMaxBounce = false;\n"
- " minSpinSpeed = 200;\n"
- " maxSpinSpeed = 600;\n"
- " lifetime = 4;\n"
- " lifetimeVariance = 1.5;\n"
- " velocity = 15;\n"
- " velocityVariance = 5;\n"
- " fade = true;\n"
- " useRadiusMass = true;\n"
- " baseRadius = 0.3;\n"
- " gravModifier = 1.0;\n"
- " terminalVelocity = 20;\n"
- " ignoreWater = false;\n"
- "};\n"
- "@endtsexample\n\n"
- "@see Debris\n\n"
- "@ingroup FX\n"
- );
- DebrisData::DebrisData()
- {
- dMemset( emitterList, 0, sizeof( emitterList ) );
- dMemset( emitterIDList, 0, sizeof( emitterIDList ) );
- explosion = NULL;
- explosionId = 0;
- velocity = 0.0f;
- velocityVariance = 0.0;
- elasticity = 0.3f;
- friction = 0.2f;
- numBounces = 0;
- bounceVariance = 0;
- staticOnMaxBounce = false;
- explodeOnMaxBounce = false;
- snapOnMaxBounce = false;
- lifetime = 3.0f;
- lifetimeVariance = 0.0f;
- minSpinSpeed = 0.0f;
- maxSpinSpeed = 0.0f;
- textureName = NULL;
- shapeName = NULL;
- fade = true;
- useRadiusMass = false;
- baseRadius = 1.0f;
- gravModifier = 1.0f;
- terminalVelocity = 0.0f;
- ignoreWater = true;
- }
- //#define TRACK_DEBRIS_DATA_CLONES
- #ifdef TRACK_DEBRIS_DATA_CLONES
- static int debris_data_clones = 0;
- #endif
- DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData(other, temp_clone)
- {
- #ifdef TRACK_DEBRIS_DATA_CLONES
- debris_data_clones++;
- if (debris_data_clones == 1)
- Con::errorf("DebrisData -- Clones are on the loose!");
- #endif
- velocity = other.velocity;
- velocityVariance = other.velocityVariance;
- friction = other.friction;
- elasticity = other.elasticity;
- lifetime = other.lifetime;
- lifetimeVariance = other.lifetimeVariance;
- numBounces = other.numBounces;
- bounceVariance = other.bounceVariance;
- minSpinSpeed = other.minSpinSpeed;
- maxSpinSpeed = other.maxSpinSpeed;
- explodeOnMaxBounce = other.explodeOnMaxBounce;
- staticOnMaxBounce = other.staticOnMaxBounce;
- snapOnMaxBounce = other.snapOnMaxBounce;
- fade = other.fade;
- useRadiusMass = other.useRadiusMass;
- baseRadius = other.baseRadius;
- gravModifier = other.gravModifier;
- terminalVelocity = other.terminalVelocity;
- ignoreWater = other.ignoreWater;
- shapeName = other.shapeName;
- shape = other.shape; // -- TSShape loaded using shapeName
- textureName = other.textureName;
- explosionId = other.explosionId; // -- for pack/unpack of explosion ptr
- explosion = other.explosion;
- dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) );
- dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs
- }
- DebrisData::~DebrisData()
- {
- if (!isTempClone())
- return;
- #ifdef TRACK_DEBRIS_DATA_CLONES
- if (debris_data_clones > 0)
- {
- debris_data_clones--;
- if (debris_data_clones == 0)
- Con::errorf("DebrisData -- Clones eliminated!");
- }
- else
- Con::errorf("DebrisData -- Too many clones deleted!");
- #endif
- }
- DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
- {
- if (!owner || getSubstitutionCount() == 0)
- return this;
- DebrisData* sub_debris_db = new DebrisData(*this, true);
- performSubstitutions(sub_debris_db, owner, index);
- return sub_debris_db;
- }
- void DebrisData::onPerformSubstitutions()
- {
- if( shapeName && shapeName[0] != '\0')
- {
- shape = ResourceManager::get().load(shapeName);
- if( bool(shape) == false )
- Con::errorf("DebrisData::onPerformSubstitutions(): failed to load shape \"%s\"", shapeName);
- }
- }
- bool DebrisData::onAdd()
- {
- if(!Parent::onAdd())
- return false;
- for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
- {
- if( !emitterList[i] && emitterIDList[i] != 0 )
- {
- if( Sim::findObject( emitterIDList[i], emitterList[i] ) == false)
- {
- Con::errorf( ConsoleLogEntry::General, "DebrisData::onAdd: Invalid packet, bad datablockId(emitter): 0x%x", emitterIDList[i]);
- }
- }
- }
- if (!explosion && explosionId != 0)
- {
- if (!Sim::findObject( SimObjectId( explosionId ), explosion ))
- Con::errorf( ConsoleLogEntry::General, "DebrisData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", explosionId);
- }
- // validate data
- if( velocityVariance > velocity )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: velocityVariance invalid", getName());
- velocityVariance = velocity;
- }
- if( friction < -10.0f || friction > 10.0f )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: friction invalid", getName());
- friction = 0.2f;
- }
- if( elasticity < -10.0f || elasticity > 10.0f )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: elasticity invalid", getName());
- elasticity = 0.2f;
- }
- if( lifetime < 0.0f || lifetime > 1000.0f )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: lifetime invalid", getName());
- lifetime = 3.0f;
- }
- if( lifetimeVariance < 0.0f || lifetimeVariance > lifetime )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: lifetimeVariance invalid", getName());
- lifetimeVariance = 0.0f;
- }
- if( numBounces < 0 || numBounces > 10000 )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: numBounces invalid", getName());
- numBounces = 3;
- }
- if( bounceVariance < 0 || bounceVariance > numBounces )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: bounceVariance invalid", getName());
- bounceVariance = 0;
- }
- if( minSpinSpeed < -10000.0f || minSpinSpeed > 10000.0f || minSpinSpeed > maxSpinSpeed )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: minSpinSpeed invalid", getName());
- minSpinSpeed = maxSpinSpeed - 1.0f;
- }
- if( maxSpinSpeed < -10000.0f || maxSpinSpeed > 10000.0f )
- {
- Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: maxSpinSpeed invalid", getName());
- maxSpinSpeed = 0.0f;
- }
- return true;
- }
- bool DebrisData::preload(bool server, String &errorStr)
- {
- if (Parent::preload(server, errorStr) == false)
- return false;
- if( server ) return true;
- if( shapeName && shapeName[0] != '\0' && !bool(shape) )
- {
- shape = ResourceManager::get().load(shapeName);
- if( bool(shape) == false )
- {
- errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", shapeName);
- return false;
- }
- else
- {
- TSShapeInstance* pDummy = new TSShapeInstance(shape, !server);
- delete pDummy;
- }
- }
- return true;
- }
- void DebrisData::initPersistFields()
- {
- addGroup("Display");
- addField("texture", TypeString, Offset(textureName, DebrisData),
- "@brief Texture imagemap to use for this debris object.\n\nNot used any more.\n");
- addField("shapeFile", TypeShapeFilename, Offset(shapeName, DebrisData),
- "@brief Object model to use for this debris object.\n\nThis shape is optional. You could have Debris made up of only particles.\n");
- endGroup("Display");
- addGroup("Datablocks");
- addField("emitters", TYPEID< ParticleEmitterData >(), Offset(emitterList, DebrisData), DDC_NUM_EMITTERS,
- "@brief List of particle emitters to spawn along with this debris object.\n\nThese are optional. You could have Debris made up of only a shape.\n");
- addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, DebrisData),
- "@brief ExplosionData to spawn along with this debris object.\n\nThis is optional as not all Debris explode.\n");
- endGroup("Datablocks");
- addGroup("Physical Properties");
- addField("elasticity", TypeF32, Offset(elasticity, DebrisData),
- "@brief A floating-point value specifying how 'bouncy' this object is.\n\nMust be in the range of -10 to 10.\n");
- addField("friction", TypeF32, Offset(friction, DebrisData),
- "@brief A floating-point value specifying how much velocity is lost to impact and sliding friction.\n\nMust be in the range of -10 to 10.\n");
- addField("numBounces", TypeS32, Offset(numBounces, DebrisData),
- "@brief How many times to allow this debris object to bounce until it either explodes, becomes static or snaps (defined in explodeOnMaxBounce, staticOnMaxBounce, snapOnMaxBounce).\n\n"
- "Must be within the range of 0 to 10000.\n"
- "@see bounceVariance\n");
- addField("bounceVariance", TypeS32, Offset(bounceVariance, DebrisData),
- "@brief Allowed variance in the value of numBounces.\n\nMust be less than numBounces.\n@see numBounces\n");
- addField("minSpinSpeed", TypeF32, Offset(minSpinSpeed, DebrisData),
- "@brief Minimum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 1000, and must be less than maxSpinSpeed.\n@see maxSpinSpeed\n");
- addField("maxSpinSpeed", TypeF32, Offset(maxSpinSpeed, DebrisData),
- "@brief Maximum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 10000.\n@see minSpinSpeed\n");
- addField("gravModifier", TypeF32, Offset(gravModifier, DebrisData), "How much gravity affects debris.");
- addField("terminalVelocity", TypeF32, Offset(terminalVelocity, DebrisData), "Max velocity magnitude.");
- addField("velocity", TypeF32, Offset(velocity, DebrisData),
- "@brief Speed at which this debris object will move.\n\n@see velocityVariance\n");
- addField("velocityVariance", TypeF32, Offset(velocityVariance, DebrisData),
- "@brief Allowed variance in the value of velocity\n\nMust be less than velocity.\n@see velocity\n");
- addField("lifetime", TypeF32, Offset(lifetime, DebrisData),
- "@brief Amount of time until this debris object is destroyed.\n\nMust be in the range of 0 to 1000.\n@see lifetimeVariance");
- addField("lifetimeVariance", TypeF32, Offset(lifetimeVariance, DebrisData),
- "@brief Allowed variance in the value of lifetime.\n\nMust be less than lifetime.\n@see lifetime\n");
- addField("useRadiusMass", TypeBool, Offset(useRadiusMass, DebrisData),
- "@brief Use mass calculations based on radius.\n\nAllows for the adjustment of elasticity and friction based on the Debris size.\n@see baseRadius\n");
- addField("baseRadius", TypeF32, Offset(baseRadius, DebrisData),
- "@brief Radius at which the standard elasticity and friction apply.\n\nOnly used when useRaduisMass is true.\n@see useRadiusMass.\n");
- endGroup("Physical Properties");
- addGroup("Behavior");
- addField("explodeOnMaxBounce", TypeBool, Offset(explodeOnMaxBounce, DebrisData),
- "@brief If true, this debris object will explode after it has bounced max times.\n\nBe sure to provide an ExplosionData datablock for this to take effect.\n@see explosion\n");
- addField("staticOnMaxBounce", TypeBool, Offset(staticOnMaxBounce, DebrisData), "If true, this debris object becomes static after it has bounced max times.");
- addField("snapOnMaxBounce", TypeBool, Offset(snapOnMaxBounce, DebrisData), "If true, this debris object will snap into a resting position on the last bounce.");
- addField("fade", TypeBool, Offset(fade, DebrisData),
- "@brief If true, this debris object will fade out when destroyed.\n\nThis fade occurs over the last second of the Debris' lifetime.\n");
- addField("ignoreWater", TypeBool, Offset(ignoreWater, DebrisData), "If true, this debris object will not collide with water, acting as if the water is not there.");
- endGroup("Behavior");
- // disallow some field substitutions
- onlyKeepClearSubstitutions("emitters"); // subs resolving to "~~", or "~0" are OK
- onlyKeepClearSubstitutions("explosion");
- Parent::initPersistFields();
- }
- void DebrisData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- stream->write(elasticity);
- stream->write(friction);
- stream->write(numBounces);
- stream->write(bounceVariance);
- stream->write(minSpinSpeed);
- stream->write(maxSpinSpeed);
- stream->write(explodeOnMaxBounce);
- stream->write(staticOnMaxBounce);
- stream->write(snapOnMaxBounce);
- stream->write(lifetime);
- stream->write(lifetimeVariance);
- stream->write(velocity);
- stream->write(velocityVariance);
- stream->write(fade);
- stream->write(useRadiusMass);
- stream->write(baseRadius);
- stream->write(gravModifier);
- stream->write(terminalVelocity);
- stream->write(ignoreWater);
- stream->writeString( textureName );
- stream->writeString( shapeName );
- for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
- {
- if( stream->writeFlag( emitterList[i] != NULL ) )
- {
- stream->writeRangedU32( emitterList[i]->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast );
- }
- }
- if( stream->writeFlag( explosion ) )
- {
- stream->writeRangedU32(packed? SimObjectId((uintptr_t)explosion):
- explosion->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
- }
- }
- void DebrisData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- stream->read(&elasticity);
- stream->read(&friction);
- stream->read(&numBounces);
- stream->read(&bounceVariance);
- stream->read(&minSpinSpeed);
- stream->read(&maxSpinSpeed);
- stream->read(&explodeOnMaxBounce);
- stream->read(&staticOnMaxBounce);
- stream->read(&snapOnMaxBounce);
- stream->read(&lifetime);
- stream->read(&lifetimeVariance);
- stream->read(&velocity);
- stream->read(&velocityVariance);
- stream->read(&fade);
- stream->read(&useRadiusMass);
- stream->read(&baseRadius);
- stream->read(&gravModifier);
- stream->read(&terminalVelocity);
- stream->read(&ignoreWater);
- textureName = stream->readSTString();
- shapeName = stream->readSTString();
- for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
- {
- if( stream->readFlag() )
- {
- emitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
- }
- }
- if(stream->readFlag())
- {
- explosionId = (S32)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
- }
- else
- {
- explosionId = 0;
- }
- }
- IMPLEMENT_CO_NETOBJECT_V1(Debris);
- ConsoleDocClass( Debris,
- "@brief Base debris class. Uses the DebrisData datablock for properties of individual debris objects.\n\n"
- "Debris is typically made up of a shape and up to two particle emitters. In most cases Debris objects are "
- "not created directly. They are usually produced automatically by other means, such as through the Explosion "
- "class. When an explosion goes off, its ExplosionData datablock determines what Debris to emit.\n"
-
- "@tsexample\n"
- "datablock ExplosionData(GrenadeLauncherExplosion)\n"
- "{\n"
- " // Assiging debris data\n"
- " debris = GrenadeDebris;\n\n"
- " // Adjust how debris is ejected\n"
- " debrisThetaMin = 10;\n"
- " debrisThetaMax = 60;\n"
- " debrisNum = 4;\n"
- " debrisNumVariance = 2;\n"
- " debrisVelocity = 25;\n"
- " debrisVelocityVariance = 5;\n\n"
- " // Note: other ExplosionData properties are not listed for this example\n"
- "};\n"
- "@endtsexample\n\n"
- "@note Debris are client side only objects.\n"
- "@see DebrisData\n"
- "@see ExplosionData\n"
- "@see Explosion\n"
- "@ingroup FX\n"
- );
- DefineEngineMethod(Debris, init, bool, (const char* inputPosition, const char* inputVelocity),
- ("1.0 1.0 1.0", "1.0 0.0 0.0"),
- "@brief Manually set this piece of debris at the given position with the given velocity.\n\n"
- "Usually you do not manually create Debris objects as they are generated through other means, "
- "such as an Explosion. This method exists when you do manually create a Debris object and "
- "want to have it start moving.\n"
- "@param inputPosition Position to place the debris.\n"
- "@param inputVelocity Velocity to move the debris after it has been placed.\n"
- "@return Always returns true.\n"
- "@tsexample\n"
- "// Define the position\n"
- "%position = \"1.0 1.0 1.0\";\n\n"
- "// Define the velocity\n"
- "%velocity = \"1.0 0.0 0.0\";\n\n"
- "// Inform the debris object of its new position and velocity\n"
- "%debris.init(%position,%velocity);\n"
- "@endtsexample\n")
- {
- Point3F pos;
- dSscanf( inputPosition, "%f %f %f", &pos.x, &pos.y, &pos.z );
- Point3F vel;
- dSscanf( inputVelocity, "%f %f %f", &vel.x, &vel.y, &vel.z );
- object->init( pos, vel );
- return true;
- }
- Debris::Debris()
- {
- mTypeMask |= DebrisObjectType | DynamicShapeObjectType;
- mVelocity = Point3F( 0.0f, 0.0f, 4.0f );
- mLifetime = gRandGen.randF( 1.0f, 10.0f );
- mLastPos = getPosition();
- mNumBounces = gRandGen.randI( 0, 1 );
- mSize = 2.0f;
- mElapsedTime = 0.0f;
- mShape = NULL;
- mPart = NULL;
- mDataBlock = NULL;
- mXRotSpeed = 0.0f;
- mZRotSpeed = 0.0f;
- mInitialTrans.identity();
- mRadius = 0.2f;
- mStatic = false;
- dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
- // Only allocated client side.
- mNetFlags.set( IsGhost );
- ss_object = 0;
- ss_index = 0;
- }
- Debris::~Debris()
- {
- if( mShape )
- {
- delete mShape;
- mShape = NULL;
- }
- if( mPart )
- {
- delete mPart;
- mPart = NULL;
- }
-
- if (mDataBlock && mDataBlock->isTempClone())
- {
- delete mDataBlock;
- mDataBlock = 0;
- }
- }
- void Debris::initPersistFields()
- {
- addGroup( "Debris" );
-
- addField( "lifetime", TypeF32, Offset(mLifetime, Debris),
- "@brief Length of time for this debris object to exist. When expired, the object will be deleted.\n\n"
- "The initial lifetime value comes from the DebrisData datablock.\n"
- "@see DebrisData::lifetime\n"
- "@see DebrisData::lifetimeVariance\n");
-
- endGroup( "Debris" );
-
- Parent::initPersistFields();
- }
- void Debris::init( const Point3F &position, const Point3F &velocity )
- {
- setPosition( position );
- setVelocity( velocity );
- }
- bool Debris::onNewDataBlock( GameBaseData *dptr, bool reload )
- {
- mDataBlock = dynamic_cast< DebrisData* >( dptr );
- if( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
- return false;
- if (mDataBlock->isTempClone())
- return true;
- scriptOnNewDataBlock();
- return true;
- }
- bool Debris::onAdd()
- {
- if( !Parent::onAdd() )
- {
- return false;
- }
- if( !mDataBlock )
- {
- Con::errorf("Debris::onAdd - Fail - No datablock");
- return false;
- }
- // create emitters
- for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
- {
- if( mDataBlock->emitterList[i] != NULL )
- {
- ParticleEmitter * pEmitter = new ParticleEmitter;
- pEmitter->onNewDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index), false);
- if( !pEmitter->registerObject() )
- {
- Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
- delete pEmitter;
- pEmitter = NULL;
- }
- mEmitterList[i] = pEmitter;
- }
- }
- // set particle sizes based on debris size
- F32 sizeList[ParticleData::PDC_NUM_KEYS];
- if( mEmitterList[0] )
- {
- sizeList[0] = mSize * 0.5;
- sizeList[1] = mSize;
- for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
- sizeList[i] = mSize * 1.5;
- mEmitterList[0]->setSizes( sizeList );
- }
- if( mEmitterList[1] )
- {
- sizeList[0] = 0.0;
- sizeList[1] = mSize * 0.5;
- for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
- sizeList[i] = mSize;
- mEmitterList[1]->setSizes( sizeList );
- }
- S32 bounceVar = (S32)mDataBlock->bounceVariance;
- bounceVar = gRandGen.randI( -bounceVar, bounceVar );
- mNumBounces = mDataBlock->numBounces + bounceVar;
- F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance;
- mLifetime = mDataBlock->lifetime + lifeVar;
- F32 xRotSpeed = gRandGen.randF( mDataBlock->minSpinSpeed, mDataBlock->maxSpinSpeed );
- F32 zRotSpeed = gRandGen.randF( mDataBlock->minSpinSpeed, mDataBlock->maxSpinSpeed );
- zRotSpeed *= gRandGen.randF( 0.1f, 0.5f );
- mRotAngles.set( xRotSpeed, 0.0f, zRotSpeed );
- mElasticity = mDataBlock->elasticity;
- mFriction = mDataBlock->friction;
- // Setup our bounding box
- if( mDataBlock->shape )
- {
- mObjBox = mDataBlock->shape->bounds;
- }
- else
- {
- mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
- }
- if( mDataBlock->shape )
- {
- mShape = new TSShapeInstance( mDataBlock->shape, true);
- }
- if( mPart )
- {
- // use half radius becuase we want debris to stick in ground
- mRadius = mPart->getRadius() * 0.5;
- mObjBox = mPart->getBounds();
- }
- resetWorldBox();
- mInitialTrans = getTransform();
- if( mDataBlock->velocity != 0.0 )
- {
- F32 velocity = mDataBlock->velocity + gRandGen.randF( -mDataBlock->velocityVariance, mDataBlock->velocityVariance );
- mVelocity.normalizeSafe();
- mVelocity *= velocity;
- }
- // mass calculations
- if( mDataBlock->useRadiusMass )
- {
- if( mRadius < mDataBlock->baseRadius )
- {
- mRadius = mDataBlock->baseRadius;
- }
- // linear falloff
- F32 multFactor = mDataBlock->baseRadius / mRadius;
- mElasticity *= multFactor;
- mFriction *= multFactor;
- mRotAngles *= multFactor;
- }
- // tell engine the debris exists
- gClientSceneGraph->addObjectToScene(this);
- removeFromProcessList();
- ClientProcessList::get()->addObject(this);
- NetConnection* pNC = NetConnection::getConnectionToServer();
- AssertFatal(pNC != NULL, "Error, must have a connection to the server!");
- pNC->addObject(this);
- return true;
- }
- void Debris::onRemove()
- {
- for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
- {
- if( mEmitterList[i] )
- {
- mEmitterList[i]->deleteWhenEmpty();
- mEmitterList[i] = NULL;
- }
- }
- if( mPart )
- {
- TSShapeInstance *ss = mPart->getSourceShapeInstance();
- if( ss )
- {
- ss->decDebrisRefCount();
- if( ss->getDebrisRefCount() == 0 )
- {
- delete ss;
- }
- }
- }
- removeFromScene();
- Parent::onRemove();
- }
- void Debris::processTick(const Move*)
- {
- if (mLifetime <= 0.0)
- deleteObject();
- }
- void Debris::advanceTime( F32 dt )
- {
- mElapsedTime += dt;
- mLifetime -= dt;
- if( mLifetime <= 0.0 )
- {
- mLifetime = 0.0;
- return;
- }
- mLastPos = getPosition();
- if( !mStatic )
- {
- rotate( dt );
- Point3F nextPos = getPosition();
- computeNewState( nextPos, mVelocity, dt );
- if( bounce( nextPos, dt ) )
- {
- --mNumBounces;
- if( mNumBounces <= 0 )
- {
- if( mDataBlock->explodeOnMaxBounce )
- {
- explode();
- mLifetime = 0.0;
- }
- if( mDataBlock->snapOnMaxBounce )
- {
- // orient debris so it's flat
- MatrixF stat = getTransform();
- Point3F dir;
- stat.getColumn( 1, &dir );
- dir.z = 0.0;
- MatrixF newTrans = MathUtils::createOrientFromDir( dir );
- // hack for shell casings to get them above ground. Need something better - bramage
- newTrans.setPosition( getPosition() + Point3F( 0.0f, 0.0f, 0.10f ) );
- setTransform( newTrans );
- }
- if( mDataBlock->staticOnMaxBounce )
- {
- mStatic = true;
- }
- }
- }
- else
- {
- setPosition( nextPos );
- }
- }
- Point3F pos( getPosition( ) );
- updateEmitters( pos, mVelocity, (U32)(dt * 1000.0));
- }
- void Debris::rotate( F32 dt )
- {
- MatrixF curTrans = getTransform();
- curTrans.setPosition( Point3F(0.0f, 0.0f, 0.0f) );
- Point3F curAngles = mRotAngles * dt * M_PI_F/180.0f;
- MatrixF rotMatrix( EulerF( curAngles.x, curAngles.y, curAngles.z ) );
- curTrans.mul( rotMatrix );
- curTrans.setPosition( getPosition() );
- setTransform( curTrans );
- }
- bool Debris::bounce( const Point3F &nextPos, F32 dt )
- {
- Point3F curPos = getPosition();
- Point3F dir = nextPos - curPos;
- if( dir.magnitudeSafe() == 0.0f ) return false;
- dir.normalizeSafe();
- Point3F extent = nextPos + dir * mRadius;
- F32 totalDist = Point3F( extent - curPos ).magnitudeSafe();
- F32 moveDist = Point3F( nextPos - curPos ).magnitudeSafe();
- F32 movePercent = (moveDist / totalDist);
- RayInfo rayInfo;
- U32 collisionMask = csmStaticCollisionMask;
- if( !mDataBlock->ignoreWater )
- {
- collisionMask |= WaterObjectType;
- }
- if( getContainer()->castRay( curPos, extent, collisionMask, &rayInfo ) )
- {
- Point3F reflection = mVelocity - rayInfo.normal * (mDot( mVelocity, rayInfo.normal ) * 2.0f);
- mVelocity = reflection;
- Point3F tangent = reflection - rayInfo.normal * mDot( reflection, rayInfo.normal );
- mVelocity -= tangent * mFriction;
- Point3F velDir = mVelocity;
- velDir.normalizeSafe();
- mVelocity *= mElasticity;
- Point3F bouncePos = curPos + dir * rayInfo.t * movePercent;
- bouncePos += mVelocity * dt;
- setPosition( bouncePos );
- mRotAngles *= mElasticity;
- return true;
- }
- return false;
- }
- void Debris::explode()
- {
- if( !mDataBlock->explosion ) return;
- Point3F explosionPos = getPosition();
- Explosion* pExplosion = new Explosion;
- pExplosion->setSubstitutionData(ss_object, ss_index);
- pExplosion->onNewDataBlock(mDataBlock->explosion->cloneAndPerformSubstitutions(ss_object, ss_index), false);
- MatrixF trans( true );
- trans.setPosition( getPosition() );
- pExplosion->setTransform( trans );
- pExplosion->setInitialState( explosionPos, VectorF(0,0,1), 1);
- if (!pExplosion->registerObject())
- delete pExplosion;
- }
- void Debris::computeNewState( Point3F &newPos, Point3F &newVel, F32 dt )
- {
- // apply gravity
- Point3F force = Point3F(0, 0, -9.81 * mDataBlock->gravModifier );
- if( mDataBlock->terminalVelocity > 0.0001 )
- {
- if( newVel.magnitudeSafe() > mDataBlock->terminalVelocity )
- {
- newVel.normalizeSafe();
- newVel *= mDataBlock->terminalVelocity;
- }
- else
- {
- newVel += force * dt;
- }
- }
- else
- {
- newVel += force * dt;
- }
- newPos += newVel * dt;
- }
- void Debris::updateEmitters( Point3F &pos, Point3F &vel, U32 ms )
- {
- Point3F axis = -vel;
- if( axis.magnitudeSafe() == 0.0 )
- {
- axis = Point3F( 0.0, 0.0, 1.0 );
- }
- axis.normalizeSafe();
- Point3F lastPos = mLastPos;
- for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
- {
- if( mEmitterList[i] )
- {
- mEmitterList[i]->emitParticles( lastPos, pos, axis, vel, ms );
- }
- }
- }
- void Debris::prepRenderImage( SceneRenderState *state )
- {
- if( !mPart && !mShape )
- return;
- Point3F cameraOffset;
- mObjToWorld.getColumn(3,&cameraOffset);
- cameraOffset -= state->getDiffuseCameraPosition();
- F32 dist = cameraOffset.len();
- F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
- if( mShape )
- {
- mShape->setDetailFromDistance( state, dist * invScale );
- if( mShape->getCurrentDetail() < 0 )
- return;
- }
- if( mPart )
- {
- // get the shapeInstance that we are using for the debris parts
- TSShapeInstance *si = mPart->getSourceShapeInstance();
- if ( si )
- si->setDetailFromDistance( state, dist * invScale );
- }
- prepBatchRender( state );
- }
- void Debris::prepBatchRender( SceneRenderState *state )
- {
- if ( !mShape && !mPart )
- return;
- GFXTransformSaver saver;
- F32 alpha = 1.0;
- if( mDataBlock->fade )
- {
- if( mLifetime < 1.0 ) alpha = mLifetime;
- }
- Point3F cameraOffset;
- mObjToWorld.getColumn(3,&cameraOffset);
- cameraOffset -= state->getCameraPosition();
-
- // Set up our TS render state.
- TSRenderState rdata;
- rdata.setSceneState( state );
- // We might have some forward lit materials
- // so pass down a query to gather lights.
- LightQuery query;
- query.init( getWorldSphere() );
- rdata.setLightQuery( &query );
- if( mShape )
- {
- MatrixF mat = getRenderTransform();
- GFX->setWorldMatrix( mat );
- rdata.setFadeOverride( alpha );
- mShape->render( rdata );
- }
- else
- {
- if (mPart->getCurrentObjectDetail() != -1)
- {
- MatrixF mat = getRenderTransform();
- GFX->setWorldMatrix( mat );
-
- rdata.setFadeOverride( alpha );
- mPart->render( rdata );
- }
- }
- }
- void Debris::setSize( F32 size )
- {
- mSize = size;
- }
|