debris.cpp

Engine/source/T3D/debris.cpp

More...

Public Functions

ConsoleDocClass(Debris , "@brief Base debris class. Uses the <a href="/coding/class/structdebrisdata/">DebrisData</a> datablock <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> properties of individual debris <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "<a href="/coding/class/classdebris/">Debris</a> is typically made up of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape and up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> two particle emitters. In most cases <a href="/coding/class/classdebris/">Debris</a> objects are " "not created directly. They are usually produced automatically by other means, such as through the <a href="/coding/class/classexplosion/">Explosion</a> " "class. When an explosion goes off, its <a href="/coding/class/classexplosiondata/">ExplosionData</a> datablock determines what <a href="/coding/class/classdebris/">Debris</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">emit.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classexplosiondata/">ExplosionData</a>(GrenadeLauncherExplosion)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Assiging debris <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">data\n</a>" " debris=GrenadeDebris;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "//Adjust how debris is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ejected\n</a>" " debrisThetaMin=10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisThetaMax=60;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNum=4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNumVariance=2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocity=25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocityVariance=5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "//Note:other <a href="/coding/class/classexplosiondata/">ExplosionData</a> properties are not listed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">example\n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @note <a href="/coding/class/classdebris/">Debris</a> are client side only <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">DebrisData\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ExplosionData\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Explosion\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )
ConsoleDocClass(DebrisData , "@brief Stores properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an individual debris <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">type.\n\n</a>" "<a href="/coding/class/structdebrisdata/">DebrisData</a> defines the base properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object. Typically you'll want <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> consist of " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape and possibly up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> two particle emitters. The <a href="/coding/class/structdebrisdata/">DebrisData</a> datablock provides the definition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> these items, " "along with physical properties and how <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object will react <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> other game objects, such as water and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">terrain.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/structdebrisdata/">DebrisData</a>(GrenadeDebris)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeFile=\"art/shapes/weapons/ramrifle/debris.dts\";\n" "   emitters[0] = GrenadeDebrisFireEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elasticity = 0.4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   friction = 0.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   numBounces = 3;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   bounceVariance = 1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   explodeOnMaxBounce = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   staticOnMaxBounce = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   snapOnMaxBounce = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   minSpinSpeed = 200;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   maxSpinSpeed = 600;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   lifetime = 4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   lifetimeVariance = 1.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   velocity = 15;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   velocityVariance = 5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   fade = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   useRadiusMass = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   baseRadius = 0.3;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gravModifier = 1.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   terminalVelocity = 20;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   ignoreWater = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Debris\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )
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 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">velocity.\n\n</a>" "Usually you do not manually create <a href="/coding/class/classdebris/">Debris</a> objects as they are generated through other means, " "such as an Explosion. This method exists when you do manually create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object and " "want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have it start <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moving.\n</a>" " @param inputPosition Position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> place the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">debris.\n</a>" " @param inputVelocity Velocity <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move the debris after it has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">placed.\n</a>" " @return Always returns <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Define the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n</a>" "% position)

Detailed Description

Public Variables

const U32 csmStaticCollisionMask 

Public Functions

ConsoleDocClass(Debris , "@brief Base debris class. Uses the <a href="/coding/class/structdebrisdata/">DebrisData</a> datablock <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> properties of individual debris <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n\n</a>" "<a href="/coding/class/classdebris/">Debris</a> is typically made up of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape and up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> two particle emitters. In most cases <a href="/coding/class/classdebris/">Debris</a> objects are " "not created directly. They are usually produced automatically by other means, such as through the <a href="/coding/class/classexplosion/">Explosion</a> " "class. When an explosion goes off, its <a href="/coding/class/classexplosiondata/">ExplosionData</a> datablock determines what <a href="/coding/class/classdebris/">Debris</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">emit.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/classexplosiondata/">ExplosionData</a>(GrenadeLauncherExplosion)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "//Assiging debris <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">data\n</a>" " debris=GrenadeDebris;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "//Adjust how debris is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ejected\n</a>" " debrisThetaMin=10;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisThetaMax=60;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNum=4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisNumVariance=2;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocity=25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " debrisVelocityVariance=5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "//Note:other <a href="/coding/class/classexplosiondata/">ExplosionData</a> properties are not listed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">example\n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" " @note <a href="/coding/class/classdebris/">Debris</a> are client side only <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">DebrisData\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">ExplosionData\n</a>" " @see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Explosion\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )

ConsoleDocClass(DebrisData , "@brief Stores properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an individual debris <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">type.\n\n</a>" "<a href="/coding/class/structdebrisdata/">DebrisData</a> defines the base properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object. Typically you'll want <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> consist of " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> shape and possibly up <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> two particle emitters. The <a href="/coding/class/structdebrisdata/">DebrisData</a> datablock provides the definition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> these items, " "along with physical properties and how <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object will react <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> other game objects, such as water and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">terrain.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "datablock <a href="/coding/class/structdebrisdata/">DebrisData</a>(GrenadeDebris)\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " shapeFile=\"art/shapes/weapons/ramrifle/debris.dts\";\n" "   emitters[0] = GrenadeDebrisFireEmitter;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   elasticity = 0.4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   friction = 0.25;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   numBounces = 3;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   bounceVariance = 1;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   explodeOnMaxBounce = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   staticOnMaxBounce = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   snapOnMaxBounce = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   minSpinSpeed = 200;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   maxSpinSpeed = 600;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   lifetime = 4;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   lifetimeVariance = 1.5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   velocity = 15;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   velocityVariance = 5;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   fade = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   useRadiusMass = true;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   baseRadius = 0.3;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gravModifier = 1.0;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   terminalVelocity = 20;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   ignoreWater = false;\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Debris\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )

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 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">velocity.\n\n</a>" "Usually you do not manually create <a href="/coding/class/classdebris/">Debris</a> objects as they are generated through other means, " "such as an Explosion. This method exists when you do manually create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classdebris/">Debris</a> object and " "want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have it start <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">moving.\n</a>" " @param inputPosition Position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> place the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">debris.\n</a>" " @param inputVelocity Velocity <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> move the debris after it has been <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">placed.\n</a>" " @return Always returns <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">true.\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//Define the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position\n</a>" "% position)

IMPLEMENT_CO_DATABLOCK_V1(DebrisData )

IMPLEMENT_CO_NETOBJECT_V1(Debris )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  26// Copyright (C) 2015 Faust Logic, Inc.
  27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  28
  29#include "platform/platform.h"
  30#include "T3D/debris.h"
  31
  32#include "core/stream/bitStream.h"
  33#include "math/mathUtils.h"
  34#include "console/consoleTypes.h"
  35#include "console/consoleObject.h"
  36#include "sim/netConnection.h"
  37#include "scene/sceneRenderState.h"
  38#include "scene/sceneManager.h"
  39#include "ts/tsShapeInstance.h"
  40#include "ts/tsPartInstance.h"
  41#include "T3D/fx/particleEmitter.h"
  42#include "T3D/fx/explosion.h"
  43#include "T3D/gameBase/gameProcess.h"
  44#include "core/resourceManager.h"
  45#include "gfx/gfxTransformSaver.h"
  46#include "console/engineAPI.h"
  47#include "lighting/lightQuery.h"
  48
  49
  50const U32 csmStaticCollisionMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType;
  51
  52IMPLEMENT_CO_DATABLOCK_V1(DebrisData);
  53
  54ConsoleDocClass( DebrisData,
  55   "@brief Stores properties for an individual debris type.\n\n"
  56
  57   "DebrisData defines the base properties for a Debris object.  Typically you'll want a Debris object to consist of "
  58   "a shape and possibly up to two particle emitters.  The DebrisData datablock provides the definition for these items, "
  59   "along with physical properties and how a Debris object will react to other game objects, such as water and terrain.\n"
  60
  61   "@tsexample\n"
  62   "datablock DebrisData(GrenadeDebris)\n"
  63   "{\n"
  64   "   shapeFile = \"art/shapes/weapons/ramrifle/debris.dts\";\n"
  65   "   emitters[0] = GrenadeDebrisFireEmitter;\n"
  66   "   elasticity = 0.4;\n"
  67   "   friction = 0.25;\n"
  68   "   numBounces = 3;\n"
  69   "   bounceVariance = 1;\n"
  70   "   explodeOnMaxBounce = false;\n"
  71   "   staticOnMaxBounce = false;\n"
  72   "   snapOnMaxBounce = false;\n"
  73   "   minSpinSpeed = 200;\n"
  74   "   maxSpinSpeed = 600;\n"
  75   "   lifetime = 4;\n"
  76   "   lifetimeVariance = 1.5;\n"
  77   "   velocity = 15;\n"
  78   "   velocityVariance = 5;\n"
  79   "   fade = true;\n"
  80   "   useRadiusMass = true;\n"
  81   "   baseRadius = 0.3;\n"
  82   "   gravModifier = 1.0;\n"
  83   "   terminalVelocity = 20;\n"
  84   "   ignoreWater = false;\n"
  85   "};\n"
  86   "@endtsexample\n\n"
  87   "@see Debris\n\n"
  88   "@ingroup FX\n"
  89);
  90
  91DebrisData::DebrisData()
  92{
  93   dMemset( emitterList, 0, sizeof( emitterList ) );
  94   dMemset( emitterIDList, 0, sizeof( emitterIDList ) );
  95
  96   explosion = NULL;
  97   explosionId = 0;
  98
  99   velocity = 0.0f;
 100   velocityVariance = 0.0;
 101   elasticity = 0.3f;
 102   friction   = 0.2f;
 103   numBounces = 0;
 104   bounceVariance = 0;
 105   staticOnMaxBounce = false;
 106   explodeOnMaxBounce = false;
 107   snapOnMaxBounce = false;
 108   lifetime = 3.0f;
 109   lifetimeVariance = 0.0f;
 110   minSpinSpeed = 0.0f;
 111   maxSpinSpeed = 0.0f;
 112   textureName = NULL;
 113   shapeName = NULL;
 114   fade = true;
 115   useRadiusMass = false;
 116   baseRadius = 1.0f;
 117   gravModifier = 1.0f;
 118   terminalVelocity = 0.0f;
 119   ignoreWater = true;
 120}
 121
 122//#define TRACK_DEBRIS_DATA_CLONES
 123
 124#ifdef TRACK_DEBRIS_DATA_CLONES
 125static int debris_data_clones = 0;
 126#endif
 127
 128DebrisData::DebrisData(const DebrisData& other, bool temp_clone) : GameBaseData(other, temp_clone)
 129{
 130#ifdef TRACK_DEBRIS_DATA_CLONES
 131   debris_data_clones++;
 132   if (debris_data_clones == 1)
 133      Con::errorf("DebrisData -- Clones are on the loose!");
 134#endif
 135   velocity = other.velocity;
 136   velocityVariance = other.velocityVariance;
 137   friction = other.friction;
 138   elasticity = other.elasticity;
 139   lifetime = other.lifetime;
 140   lifetimeVariance = other.lifetimeVariance;
 141   numBounces = other.numBounces;
 142   bounceVariance = other.bounceVariance;
 143   minSpinSpeed = other.minSpinSpeed;
 144   maxSpinSpeed = other.maxSpinSpeed;
 145   explodeOnMaxBounce = other.explodeOnMaxBounce;
 146   staticOnMaxBounce = other.staticOnMaxBounce;
 147   snapOnMaxBounce = other.snapOnMaxBounce;
 148   fade = other.fade;
 149   useRadiusMass = other.useRadiusMass;
 150   baseRadius = other.baseRadius;
 151   gravModifier = other.gravModifier;
 152   terminalVelocity = other.terminalVelocity;
 153   ignoreWater = other.ignoreWater;
 154   shapeName = other.shapeName;
 155   shape = other.shape; // -- TSShape loaded using shapeName
 156   textureName = other.textureName;
 157   explosionId = other.explosionId; // -- for pack/unpack of explosion ptr
 158   explosion = other.explosion;
 159   dMemcpy( emitterList, other.emitterList, sizeof( emitterList ) );
 160   dMemcpy( emitterIDList, other.emitterIDList, sizeof( emitterIDList ) ); // -- for pack/unpack of emitterList ptrs
 161}
 162
 163DebrisData::~DebrisData()
 164{
 165   if (!isTempClone())
 166      return;
 167
 168#ifdef TRACK_DEBRIS_DATA_CLONES
 169   if (debris_data_clones > 0)
 170   {
 171      debris_data_clones--;
 172      if (debris_data_clones == 0)
 173         Con::errorf("DebrisData -- Clones eliminated!");
 174   }
 175   else
 176      Con::errorf("DebrisData -- Too many clones deleted!");
 177#endif
 178}
 179
 180DebrisData* DebrisData::cloneAndPerformSubstitutions(const SimObject* owner, S32 index)
 181{
 182   if (!owner || getSubstitutionCount() == 0)
 183      return this;
 184
 185   DebrisData* sub_debris_db = new DebrisData(*this, true);
 186   performSubstitutions(sub_debris_db, owner, index);
 187
 188   return sub_debris_db;
 189}
 190
 191void DebrisData::onPerformSubstitutions() 
 192{ 
 193   if( shapeName && shapeName[0] != '\0')
 194   {
 195      shape = ResourceManager::get().load(shapeName);
 196      if( bool(shape) == false )
 197         Con::errorf("DebrisData::onPerformSubstitutions(): failed to load shape \"%s\"", shapeName);
 198   }
 199}
 200
 201bool DebrisData::onAdd()
 202{
 203   if(!Parent::onAdd())
 204      return false;
 205
 206   for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
 207   {
 208      if( !emitterList[i] && emitterIDList[i] != 0 )
 209      {
 210         if( Sim::findObject( emitterIDList[i], emitterList[i] ) == false)
 211         {
 212            Con::errorf( ConsoleLogEntry::General, "DebrisData::onAdd: Invalid packet, bad datablockId(emitter): 0x%x", emitterIDList[i]);
 213         }
 214      }
 215   }
 216
 217   if (!explosion && explosionId != 0)
 218   {
 219      if (!Sim::findObject( SimObjectId( explosionId ), explosion ))
 220            Con::errorf( ConsoleLogEntry::General, "DebrisData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", explosionId);
 221   }
 222
 223   // validate data
 224
 225   if( velocityVariance > velocity )
 226   {
 227      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: velocityVariance invalid", getName());
 228      velocityVariance = velocity;
 229   }
 230   if( friction < -10.0f || friction > 10.0f )
 231   {
 232      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: friction invalid", getName());
 233      friction = 0.2f;
 234   }
 235   if( elasticity < -10.0f || elasticity > 10.0f )
 236   {
 237      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: elasticity invalid", getName());
 238      elasticity = 0.2f;
 239   }
 240   if( lifetime < 0.0f || lifetime > 1000.0f )
 241   {
 242      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: lifetime invalid", getName());
 243      lifetime = 3.0f;
 244   }
 245   if( lifetimeVariance < 0.0f || lifetimeVariance > lifetime )
 246   {
 247      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: lifetimeVariance invalid", getName());
 248      lifetimeVariance = 0.0f;
 249   }
 250   if( numBounces < 0 || numBounces > 10000 )
 251   {
 252      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: numBounces invalid", getName());
 253      numBounces = 3;
 254   }
 255   if( bounceVariance < 0 || bounceVariance > numBounces )
 256   {
 257      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: bounceVariance invalid", getName());
 258      bounceVariance = 0;
 259   }
 260   if( minSpinSpeed < -10000.0f || minSpinSpeed > 10000.0f || minSpinSpeed > maxSpinSpeed )
 261   {
 262      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: minSpinSpeed invalid", getName());
 263      minSpinSpeed = maxSpinSpeed - 1.0f;
 264   }
 265   if( maxSpinSpeed < -10000.0f || maxSpinSpeed > 10000.0f )
 266   {
 267      Con::warnf(ConsoleLogEntry::General, "DebrisData(%s)::onAdd: maxSpinSpeed invalid", getName());
 268      maxSpinSpeed = 0.0f;
 269   }
 270
 271   return true;
 272}
 273
 274bool DebrisData::preload(bool server, String &errorStr)
 275{
 276   if (Parent::preload(server, errorStr) == false)
 277      return false;
 278
 279   if( server ) return true;
 280
 281   if( shapeName && shapeName[0] != '\0' && !bool(shape) )
 282   {
 283      shape = ResourceManager::get().load(shapeName);
 284      if( bool(shape) == false )
 285      {
 286         errorStr = String::ToString("DebrisData::load: Couldn't load shape \"%s\"", shapeName);
 287         return false;
 288      }
 289      else
 290      {
 291         TSShapeInstance* pDummy = new TSShapeInstance(shape, !server);
 292         delete pDummy;
 293      }
 294
 295   }
 296
 297   return true;
 298}
 299
 300void DebrisData::initPersistFields()
 301{
 302   addGroup("Display");
 303   addField("texture",              TypeString,                  Offset(textureName,         DebrisData), 
 304      "@brief Texture imagemap to use for this debris object.\n\nNot used any more.\n");
 305   addField("shapeFile",            TypeShapeFilename,           Offset(shapeName,           DebrisData), 
 306      "@brief Object model to use for this debris object.\n\nThis shape is optional.  You could have Debris made up of only particles.\n");
 307   endGroup("Display");
 308
 309   addGroup("Datablocks");
 310   addField("emitters",             TYPEID< ParticleEmitterData >(),  Offset(emitterList,    DebrisData), DDC_NUM_EMITTERS, 
 311      "@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");
 312   addField("explosion",            TYPEID< ExplosionData >(),   Offset(explosion,           DebrisData), 
 313      "@brief ExplosionData to spawn along with this debris object.\n\nThis is optional as not all Debris explode.\n");
 314   endGroup("Datablocks");
 315
 316   addGroup("Physical Properties");
 317   addField("elasticity",           TypeF32,                     Offset(elasticity,          DebrisData), 
 318      "@brief A floating-point value specifying how 'bouncy' this object is.\n\nMust be in the range of -10 to 10.\n");
 319   addField("friction",             TypeF32,                     Offset(friction,            DebrisData), 
 320      "@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");
 321   addField("numBounces",           TypeS32,                     Offset(numBounces,          DebrisData), 
 322      "@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"
 323      "Must be within the range of 0 to 10000.\n"
 324      "@see bounceVariance\n");
 325   addField("bounceVariance",       TypeS32,                     Offset(bounceVariance,      DebrisData), 
 326      "@brief Allowed variance in the value of numBounces.\n\nMust be less than numBounces.\n@see numBounces\n");
 327   addField("minSpinSpeed",         TypeF32,                     Offset(minSpinSpeed,        DebrisData), 
 328      "@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");
 329   addField("maxSpinSpeed",         TypeF32,                     Offset(maxSpinSpeed,        DebrisData), 
 330      "@brief Maximum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 10000.\n@see minSpinSpeed\n");
 331   addField("gravModifier",         TypeF32,                     Offset(gravModifier,        DebrisData), "How much gravity affects debris.");
 332   addField("terminalVelocity",     TypeF32,                     Offset(terminalVelocity,    DebrisData), "Max velocity magnitude.");
 333   addField("velocity",             TypeF32,                     Offset(velocity,            DebrisData), 
 334      "@brief Speed at which this debris object will move.\n\n@see velocityVariance\n");
 335   addField("velocityVariance",     TypeF32,                     Offset(velocityVariance,    DebrisData), 
 336      "@brief Allowed variance in the value of velocity\n\nMust be less than velocity.\n@see velocity\n");
 337   addField("lifetime",             TypeF32,                     Offset(lifetime,            DebrisData), 
 338      "@brief Amount of time until this debris object is destroyed.\n\nMust be in the range of 0 to 1000.\n@see lifetimeVariance");
 339   addField("lifetimeVariance",     TypeF32,                     Offset(lifetimeVariance,    DebrisData), 
 340      "@brief Allowed variance in the value of lifetime.\n\nMust be less than lifetime.\n@see lifetime\n");
 341   addField("useRadiusMass",        TypeBool,                    Offset(useRadiusMass,       DebrisData), 
 342      "@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");
 343   addField("baseRadius",           TypeF32,                     Offset(baseRadius,          DebrisData), 
 344      "@brief Radius at which the standard elasticity and friction apply.\n\nOnly used when useRaduisMass is true.\n@see useRadiusMass.\n");
 345   endGroup("Physical Properties");
 346
 347   addGroup("Behavior");
 348   addField("explodeOnMaxBounce",   TypeBool,                    Offset(explodeOnMaxBounce,  DebrisData), 
 349      "@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");
 350   addField("staticOnMaxBounce",    TypeBool,                    Offset(staticOnMaxBounce,   DebrisData), "If true, this debris object becomes static after it has bounced max times.");
 351   addField("snapOnMaxBounce",      TypeBool,                    Offset(snapOnMaxBounce,     DebrisData), "If true, this debris object will snap into a resting position on the last bounce.");
 352   addField("fade",                 TypeBool,                    Offset(fade,                DebrisData), 
 353      "@brief If true, this debris object will fade out when destroyed.\n\nThis fade occurs over the last second of the Debris' lifetime.\n");
 354   addField("ignoreWater",          TypeBool,                    Offset(ignoreWater,         DebrisData), "If true, this debris object will not collide with water, acting as if the water is not there.");
 355   endGroup("Behavior");
 356
 357   // disallow some field substitutions
 358   onlyKeepClearSubstitutions("emitters"); // subs resolving to "~~", or "~0" are OK
 359   onlyKeepClearSubstitutions("explosion");
 360   Parent::initPersistFields();
 361}
 362
 363void DebrisData::packData(BitStream* stream)
 364{
 365   Parent::packData(stream);
 366
 367   stream->write(elasticity);
 368   stream->write(friction);
 369   stream->write(numBounces);
 370   stream->write(bounceVariance);
 371   stream->write(minSpinSpeed);
 372   stream->write(maxSpinSpeed);
 373   stream->write(explodeOnMaxBounce);
 374   stream->write(staticOnMaxBounce);
 375   stream->write(snapOnMaxBounce);
 376   stream->write(lifetime);
 377   stream->write(lifetimeVariance);
 378   stream->write(velocity);
 379   stream->write(velocityVariance);
 380   stream->write(fade);
 381   stream->write(useRadiusMass);
 382   stream->write(baseRadius);
 383   stream->write(gravModifier);
 384   stream->write(terminalVelocity);
 385   stream->write(ignoreWater);
 386
 387   stream->writeString( textureName );
 388   stream->writeString( shapeName );
 389
 390   for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
 391   {
 392      if( stream->writeFlag( emitterList[i] != NULL ) )
 393      {
 394         stream->writeRangedU32( emitterList[i]->getId(), DataBlockObjectIdFirst,  DataBlockObjectIdLast );
 395      }
 396   }
 397
 398   if( stream->writeFlag( explosion ) )
 399   {
 400      stream->writeRangedU32(mPacked ? SimObjectId((uintptr_t)explosion):
 401         explosion->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
 402   }
 403
 404}
 405
 406void DebrisData::unpackData(BitStream* stream)
 407{
 408   Parent::unpackData(stream);
 409
 410   stream->read(&elasticity);
 411   stream->read(&friction);
 412   stream->read(&numBounces);
 413   stream->read(&bounceVariance);
 414   stream->read(&minSpinSpeed);
 415   stream->read(&maxSpinSpeed);
 416   stream->read(&explodeOnMaxBounce);
 417   stream->read(&staticOnMaxBounce);
 418   stream->read(&snapOnMaxBounce);
 419   stream->read(&lifetime);
 420   stream->read(&lifetimeVariance);
 421   stream->read(&velocity);
 422   stream->read(&velocityVariance);
 423   stream->read(&fade);
 424   stream->read(&useRadiusMass);
 425   stream->read(&baseRadius);
 426   stream->read(&gravModifier);
 427   stream->read(&terminalVelocity);
 428   stream->read(&ignoreWater);
 429
 430   textureName = stream->readSTString();
 431   shapeName   = stream->readSTString();
 432
 433   for( S32 i=0; i<DDC_NUM_EMITTERS; i++ )
 434   {
 435      if( stream->readFlag() )
 436      {
 437         emitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
 438      }
 439   }
 440
 441   if(stream->readFlag())
 442   {
 443      explosionId = (S32)stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
 444   }
 445   else
 446   {
 447      explosionId = 0;
 448   }
 449
 450}
 451
 452
 453IMPLEMENT_CO_NETOBJECT_V1(Debris);
 454
 455ConsoleDocClass( Debris,
 456   "@brief Base debris class. Uses the DebrisData datablock for properties of individual debris objects.\n\n"
 457
 458   "Debris is typically made up of a shape and up to two particle emitters.  In most cases Debris objects are "
 459   "not created directly.  They are usually produced automatically by other means, such as through the Explosion "
 460   "class.  When an explosion goes off, its ExplosionData datablock determines what Debris to emit.\n"
 461   
 462   "@tsexample\n"
 463   "datablock ExplosionData(GrenadeLauncherExplosion)\n"
 464   "{\n"
 465   "   // Assiging debris data\n"
 466   "   debris = GrenadeDebris;\n\n"
 467   "   // Adjust how debris is ejected\n"
 468   "   debrisThetaMin = 10;\n"
 469   "   debrisThetaMax = 60;\n"
 470   "   debrisNum = 4;\n"
 471   "   debrisNumVariance = 2;\n"
 472   "   debrisVelocity = 25;\n"
 473   "   debrisVelocityVariance = 5;\n\n"
 474   "   // Note: other ExplosionData properties are not listed for this example\n"
 475   "};\n"
 476   "@endtsexample\n\n"
 477
 478   "@note Debris are client side only objects.\n"
 479
 480   "@see DebrisData\n"
 481   "@see ExplosionData\n"
 482   "@see Explosion\n"
 483
 484   "@ingroup FX\n"
 485);
 486
 487DefineEngineMethod(Debris, init, bool, (const char* inputPosition, const char* inputVelocity),
 488   ("1.0 1.0 1.0", "1.0 0.0 0.0"), 
 489   "@brief Manually set this piece of debris at the given position with the given velocity.\n\n"
 490
 491   "Usually you do not manually create Debris objects as they are generated through other means, "
 492   "such as an Explosion.  This method exists when you do manually create a Debris object and "
 493   "want to have it start moving.\n"
 494
 495   "@param inputPosition Position to place the debris.\n"
 496   "@param inputVelocity Velocity to move the debris after it has been placed.\n"
 497   "@return Always returns true.\n"
 498
 499   "@tsexample\n"
 500      "// Define the position\n"
 501      "%position = \"1.0 1.0 1.0\";\n\n"
 502      "// Define the velocity\n"
 503      "%velocity = \"1.0 0.0 0.0\";\n\n"
 504      "// Inform the debris object of its new position and velocity\n"
 505      "%debris.init(%position,%velocity);\n"
 506   "@endtsexample\n")
 507{
 508   Point3F pos;
 509   dSscanf( inputPosition, "%f %f %f", &pos.x, &pos.y, &pos.z );
 510
 511   Point3F vel;
 512   dSscanf( inputVelocity, "%f %f %f", &vel.x, &vel.y, &vel.z );
 513
 514   object->init( pos, vel );
 515
 516   return true;
 517}
 518
 519Debris::Debris()
 520{
 521   mTypeMask |= DebrisObjectType | DynamicShapeObjectType;
 522
 523   mVelocity = Point3F( 0.0f, 0.0f, 4.0f );
 524   mLifetime = gRandGen.randF( 1.0f, 10.0f );
 525   mLastPos =  getPosition();
 526   mNumBounces = gRandGen.randI( 0, 1 );
 527   mSize = 2.0f;
 528   mElapsedTime = 0.0f;
 529   mShape = NULL;
 530   mPart = NULL;
 531   mDataBlock = NULL;
 532   mXRotSpeed = 0.0f;
 533   mZRotSpeed = 0.0f;
 534   mInitialTrans.identity();
 535   mRadius = 0.2f;
 536   mStatic = false;
 537   mElasticity = 0.5f;
 538   mFriction = 0.5f;
 539
 540   dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
 541
 542   // Only allocated client side.
 543   mNetFlags.set( IsGhost );
 544   ss_object = 0;
 545   ss_index = 0;
 546}
 547
 548Debris::~Debris()
 549{
 550   if( mShape )
 551   {
 552      delete mShape;
 553      mShape = NULL;
 554   }
 555
 556   if( mPart )
 557   {
 558      delete mPart;
 559      mPart = NULL;
 560   }
 561   
 562   if (mDataBlock && mDataBlock->isTempClone())
 563   { 
 564      delete mDataBlock;
 565      mDataBlock = 0;
 566   }
 567}
 568
 569void Debris::initPersistFields()
 570{
 571   addGroup( "Debris" );   
 572   
 573      addField( "lifetime", TypeF32, Offset(mLifetime, Debris), 
 574         "@brief Length of time for this debris object to exist. When expired, the object will be deleted.\n\n"
 575         "The initial lifetime value comes from the DebrisData datablock.\n"
 576         "@see DebrisData::lifetime\n"
 577         "@see DebrisData::lifetimeVariance\n");
 578      
 579   endGroup( "Debris" );
 580   
 581   Parent::initPersistFields();
 582}
 583
 584void Debris::init( const Point3F &position, const Point3F &velocity )
 585{
 586   setPosition( position );
 587   setVelocity( velocity );
 588}
 589
 590bool Debris::onNewDataBlock( GameBaseData *dptr, bool reload )
 591{
 592   mDataBlock = dynamic_cast< DebrisData* >( dptr );
 593   if( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
 594      return false;
 595
 596   if (mDataBlock->isTempClone())
 597      return true;
 598   scriptOnNewDataBlock();
 599   return true;
 600
 601}
 602
 603bool Debris::onAdd()
 604{
 605   if( !Parent::onAdd() )
 606   {
 607      return false;
 608   }
 609
 610   if( !mDataBlock )
 611   {
 612      Con::errorf("Debris::onAdd - Fail - No datablock");
 613      return false;
 614   }
 615
 616   // create emitters
 617   for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
 618   {
 619      if( mDataBlock->emitterList[i] != NULL )
 620      {
 621         ParticleEmitter * pEmitter = new ParticleEmitter;
 622         pEmitter->onNewDataBlock(mDataBlock->emitterList[i]->cloneAndPerformSubstitutions(ss_object, ss_index), false);
 623         if( !pEmitter->registerObject() )
 624         {
 625            Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
 626            delete pEmitter;
 627            pEmitter = NULL;
 628         }
 629         mEmitterList[i] = pEmitter;
 630      }
 631   }
 632
 633   // set particle sizes based on debris size
 634   F32 sizeList[ParticleData::PDC_NUM_KEYS];
 635
 636   if( mEmitterList[0] )
 637   {
 638      sizeList[0] = mSize * 0.5;
 639      sizeList[1] = mSize;
 640      for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
 641         sizeList[i] = mSize * 1.5;
 642
 643      mEmitterList[0]->setSizes( sizeList );
 644   }
 645
 646   if( mEmitterList[1] )
 647   {
 648      sizeList[0] = 0.0;
 649      sizeList[1] = mSize * 0.5;
 650      for (U32 i = 2; i < ParticleData::PDC_NUM_KEYS; i++)
 651         sizeList[i] = mSize;
 652
 653      mEmitterList[1]->setSizes( sizeList );
 654   }
 655
 656   S32 bounceVar = (S32)mDataBlock->bounceVariance;
 657   bounceVar = gRandGen.randI( -bounceVar, bounceVar );
 658   mNumBounces = mDataBlock->numBounces + bounceVar;
 659
 660   F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance;
 661   mLifetime = mDataBlock->lifetime + lifeVar;
 662
 663   F32 xRotSpeed = gRandGen.randF( mDataBlock->minSpinSpeed, mDataBlock->maxSpinSpeed );
 664   F32 zRotSpeed = gRandGen.randF( mDataBlock->minSpinSpeed, mDataBlock->maxSpinSpeed );
 665   zRotSpeed *= gRandGen.randF( 0.1f, 0.5f );
 666
 667   mRotAngles.set( xRotSpeed, 0.0f, zRotSpeed );
 668
 669   mElasticity = mDataBlock->elasticity;
 670   mFriction = mDataBlock->friction;
 671
 672   // Setup our bounding box
 673   if( mDataBlock->shape )
 674   {
 675      mObjBox = mDataBlock->shape->mBounds;
 676   }
 677   else
 678   {
 679      mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1));
 680   }
 681
 682   if( mDataBlock->shape )
 683   {
 684      mShape = new TSShapeInstance( mDataBlock->shape, true);
 685   }
 686
 687   if( mPart )
 688   {
 689      // use half radius becuase we want debris to stick in ground
 690      mRadius = mPart->getRadius() * 0.5;
 691      mObjBox = mPart->getBounds();
 692   }
 693
 694   resetWorldBox();
 695
 696   mInitialTrans = getTransform();
 697
 698   if( mDataBlock->velocity != 0.0 )
 699   {
 700      F32 velocity = mDataBlock->velocity + gRandGen.randF( -mDataBlock->velocityVariance, mDataBlock->velocityVariance );
 701
 702      mVelocity.normalizeSafe();
 703      mVelocity *= velocity;
 704   }
 705
 706   // mass calculations
 707   if( mDataBlock->useRadiusMass )
 708   {
 709      if( mRadius < mDataBlock->baseRadius )
 710      {
 711         mRadius = mDataBlock->baseRadius;
 712      }
 713
 714      // linear falloff
 715      F32 multFactor = mDataBlock->baseRadius / mRadius;
 716
 717      mElasticity *= multFactor;
 718      mFriction *= multFactor;
 719      mRotAngles *= multFactor;
 720   }
 721
 722
 723   // tell engine the debris exists
 724   gClientSceneGraph->addObjectToScene(this);
 725
 726   removeFromProcessList();
 727   ClientProcessList::get()->addObject(this);
 728
 729   NetConnection* pNC = NetConnection::getConnectionToServer();
 730   AssertFatal(pNC != NULL, "Error, must have a connection to the server!");
 731   pNC->addObject(this);
 732
 733   return true;
 734}
 735
 736void Debris::onRemove()
 737{
 738   for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
 739   {
 740      if( mEmitterList[i] )
 741      {
 742         mEmitterList[i]->deleteWhenEmpty();
 743         mEmitterList[i] = NULL;
 744      }
 745   }
 746
 747   if( mPart )
 748   {
 749      TSShapeInstance *ss = mPart->getSourceShapeInstance();
 750      if( ss )
 751      {
 752         ss->decDebrisRefCount();
 753         if( ss->getDebrisRefCount() == 0 )
 754         {
 755            delete ss;
 756         }
 757      }
 758   }
 759
 760   removeFromScene();
 761
 762   Parent::onRemove();
 763}
 764
 765void Debris::processTick(const Move*)
 766{
 767   if (mLifetime <= 0.0)
 768      deleteObject();
 769}
 770
 771void Debris::advanceTime( F32 dt )
 772{
 773   mElapsedTime += dt;
 774
 775   mLifetime -= dt;
 776   if( mLifetime <= 0.0 )
 777   {
 778      mLifetime = 0.0;
 779      return;
 780   }
 781
 782   mLastPos = getPosition();
 783
 784   if( !mStatic )
 785   {
 786      rotate( dt );
 787
 788      Point3F nextPos = getPosition();
 789      computeNewState( nextPos, mVelocity, dt );
 790
 791      if( bounce( nextPos, dt ) )
 792      {
 793         --mNumBounces;
 794         if( mNumBounces <= 0 )
 795         {
 796            if( mDataBlock->explodeOnMaxBounce )
 797            {
 798               explode();
 799               mLifetime = 0.0;
 800            }
 801            if( mDataBlock->snapOnMaxBounce )
 802            {
 803               // orient debris so it's flat
 804               MatrixF stat = getTransform();
 805
 806               Point3F dir;
 807               stat.getColumn( 1, &dir );
 808               dir.z = 0.0;
 809
 810               MatrixF newTrans = MathUtils::createOrientFromDir( dir );
 811
 812               // hack for shell casings to get them above ground.  Need something better - bramage
 813               newTrans.setPosition( getPosition() + Point3F( 0.0f, 0.0f, 0.10f ) );
 814
 815               setTransform( newTrans );
 816            }
 817            if( mDataBlock->staticOnMaxBounce )
 818            {
 819               mStatic = true;
 820            }
 821         }
 822      }
 823      else
 824      {
 825         setPosition( nextPos );
 826      }
 827   }
 828
 829   Point3F pos( getPosition( ) );
 830   updateEmitters( pos, mVelocity, (U32)(dt * 1000.0));
 831
 832}
 833
 834void Debris::rotate( F32 dt )
 835{
 836   MatrixF curTrans = getTransform();
 837   curTrans.setPosition( Point3F(0.0f, 0.0f, 0.0f) );
 838
 839   Point3F curAngles = mRotAngles * dt * M_PI_F/180.0f;
 840   MatrixF rotMatrix( EulerF( curAngles.x, curAngles.y, curAngles.z ) );
 841
 842   curTrans.mul( rotMatrix );
 843   curTrans.setPosition( getPosition() );
 844   setTransform( curTrans );
 845}
 846
 847bool Debris::bounce( const Point3F &nextPos, F32 dt )
 848{
 849   Point3F curPos = getPosition();
 850
 851   Point3F dir = nextPos - curPos;
 852   if( dir.magnitudeSafe() == 0.0f ) return false;
 853   dir.normalizeSafe();
 854   Point3F extent = nextPos + dir * mRadius;
 855   F32 totalDist = Point3F( extent - curPos ).magnitudeSafe();
 856   F32 moveDist = Point3F( nextPos - curPos ).magnitudeSafe();
 857   F32 movePercent = (moveDist / totalDist);
 858
 859   RayInfo rayInfo;
 860   U32 collisionMask = csmStaticCollisionMask;
 861   if( !mDataBlock->ignoreWater )
 862   {
 863      collisionMask |= WaterObjectType;
 864   }
 865
 866   if( getContainer()->castRay( curPos, extent, collisionMask, &rayInfo ) )
 867   {
 868
 869      Point3F reflection = mVelocity - rayInfo.normal * (mDot( mVelocity, rayInfo.normal ) * 2.0f);
 870      mVelocity = reflection;
 871
 872      Point3F tangent = reflection - rayInfo.normal * mDot( reflection, rayInfo.normal );
 873      mVelocity -= tangent * mFriction;
 874
 875      Point3F velDir = mVelocity;
 876      velDir.normalizeSafe();
 877
 878      mVelocity *= mElasticity;
 879
 880      Point3F bouncePos = curPos + dir * rayInfo.t * movePercent;
 881      bouncePos += mVelocity * dt;
 882
 883      setPosition( bouncePos );
 884
 885      mRotAngles *= mElasticity;
 886
 887      return true;
 888
 889   }
 890
 891   return false;
 892
 893}
 894
 895void Debris::explode()
 896{
 897
 898   if( !mDataBlock->explosion ) return;
 899
 900   Point3F explosionPos = getPosition();
 901
 902   Explosion* pExplosion = new Explosion;
 903   pExplosion->setSubstitutionData(ss_object, ss_index);
 904   pExplosion->onNewDataBlock(mDataBlock->explosion->cloneAndPerformSubstitutions(ss_object, ss_index), false);
 905
 906   MatrixF trans( true );
 907   trans.setPosition( getPosition() );
 908
 909   pExplosion->setTransform( trans );
 910   pExplosion->setInitialState( explosionPos, VectorF(0,0,1), 1);
 911   if (!pExplosion->registerObject())
 912      delete pExplosion;
 913}
 914
 915void Debris::computeNewState( Point3F &newPos, Point3F &newVel, F32 dt )
 916{
 917   // apply gravity
 918   Point3F force = Point3F(0, 0, -9.81 * mDataBlock->gravModifier );
 919
 920   if( mDataBlock->terminalVelocity > 0.0001 )
 921   {
 922      if( newVel.magnitudeSafe() > mDataBlock->terminalVelocity )
 923      {
 924         newVel.normalizeSafe();
 925         newVel *= mDataBlock->terminalVelocity;
 926      }
 927      else
 928      {
 929         newVel += force * dt;
 930      }
 931   }
 932   else
 933   {
 934      newVel += force * dt;
 935   }
 936
 937   newPos += newVel * dt;
 938
 939}
 940
 941void Debris::updateEmitters( Point3F &pos, Point3F &vel, U32 ms )
 942{
 943
 944   Point3F axis = -vel;
 945
 946   if( axis.magnitudeSafe() == 0.0 )
 947   {
 948      axis = Point3F( 0.0, 0.0, 1.0 );
 949   }
 950   axis.normalizeSafe();
 951
 952
 953   Point3F lastPos = mLastPos;
 954
 955   for( S32 i=0; i<DebrisData::DDC_NUM_EMITTERS; i++ )
 956   {
 957      if( mEmitterList[i] )
 958      {
 959         mEmitterList[i]->emitParticles( lastPos, pos, axis, vel, ms );
 960      }
 961   }
 962
 963}
 964
 965void Debris::prepRenderImage( SceneRenderState *state )
 966{
 967   if( !mPart && !mShape )
 968      return;
 969
 970   Point3F cameraOffset;
 971   mObjToWorld.getColumn(3,&cameraOffset);
 972   cameraOffset -= state->getDiffuseCameraPosition();
 973   F32 dist = cameraOffset.len();
 974   F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));
 975
 976   if( mShape )
 977   {
 978      mShape->setDetailFromDistance( state, dist * invScale );
 979      if( mShape->getCurrentDetail() < 0 )
 980         return;
 981   }
 982
 983   if( mPart )
 984   {
 985      // get the shapeInstance that we are using for the debris parts
 986      TSShapeInstance *si = mPart->getSourceShapeInstance();
 987      if ( si )
 988         si->setDetailFromDistance( state, dist * invScale );
 989   }
 990
 991   prepBatchRender( state );
 992}
 993
 994void Debris::prepBatchRender( SceneRenderState *state )
 995{
 996   if ( !mShape && !mPart )
 997      return;
 998
 999   GFXTransformSaver saver;
1000
1001   F32 alpha = 1.0;
1002   if( mDataBlock->fade )
1003   {
1004      if( mLifetime < 1.0 ) alpha = mLifetime;
1005   }
1006
1007   Point3F cameraOffset;
1008   mObjToWorld.getColumn(3,&cameraOffset);
1009   cameraOffset -= state->getCameraPosition();
1010      
1011   // Set up our TS render state.
1012   TSRenderState rdata;
1013   rdata.setSceneState( state );
1014
1015   // We might have some forward lit materials
1016   // so pass down a query to gather lights.
1017   LightQuery query;
1018   query.init( getWorldSphere() );
1019   rdata.setLightQuery( &query );
1020
1021   if( mShape )
1022   {
1023      MatrixF mat = getRenderTransform();
1024      GFX->setWorldMatrix( mat );
1025
1026      rdata.setFadeOverride( alpha );
1027      mShape->render( rdata );
1028   }
1029   else
1030   {
1031      if (mPart->getCurrentObjectDetail() != -1)
1032      {
1033         MatrixF mat = getRenderTransform();
1034         GFX->setWorldMatrix( mat );
1035           
1036         rdata.setFadeOverride( alpha );
1037         mPart->render( rdata );
1038      }
1039   }
1040}
1041
1042void Debris::setSize( F32 size )
1043{
1044   mSize = size;
1045}
1046