Torque3D Documentation / _generateds / physicsDebris.cpp

physicsDebris.cpp

Engine/source/T3D/physics/physicsDebris.cpp

More...

Public Variables

bool

For frame signal.

Public Functions

ConsoleDocClass(PhysicsDebris , "@brief Represents one or more rigid bodies defined in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> with " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> limited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lifetime.\n\n</a>" "A <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object can be viewed as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single system capable of generating multiple " "@link <a href="/coding/class/classphysicsbody/">PhysicsBody</a> PhysicsBodies@endlink as debris when triggered. Vaguely similar <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> how " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> is capable of creating Particles, but isn '<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> particle in itself. " "After it 's lifetime has elapsed, the object will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> loads <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> standard .DAE or .DTS <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and creates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> rigid body <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "each defined collision <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "For collision nodes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> work correctly, they must be setup as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">follows:\n</a>" " - Visible mesh nodes are siblings of the collision node under <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> common parent dummy <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" " - <a href="/coding/class/structcollision/">Collision</a> node is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> child of its visible mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "Colmesh type nodes are NOT supported;physx and most standard rigid " "body simulations do not support arbitrary triangle meshs <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamics " "do <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the computational <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">expense.\n\n</a>" " Therefore, collision nodes must be one of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">following:\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colbox\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colsphere\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colcapsule\n</a>" " - Col(convex).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> should NOT be created on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" " @ingroup Physics" )
ConsoleDocClass(PhysicsDebrisData , "@brief Defines the properties of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsDebris.\n</a>" "@ingroup Physics" )
DefineEngineMethod(PhysicsDebrisData , preload , void , () , "@brief Loads some information <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have readily available at simulation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time.\n\n</a>" "Forces generation of shaders, materials , and other data used by the %<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object. " "This function should be used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> level is loading in order <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> shorten " "the amount of time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">game.\n\n</a>" )

Detailed Description

Public Variables

bool gEditingMission 

For frame signal.

Public Functions

ConsoleDocClass(PhysicsDebris , "@brief Represents one or more rigid bodies defined in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> with " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> limited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lifetime.\n\n</a>" "A <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object can be viewed as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> single system capable of generating multiple " "@link <a href="/coding/class/classphysicsbody/">PhysicsBody</a> PhysicsBodies@endlink as debris when triggered. Vaguely similar <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> how " "<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classparticleemitter/">ParticleEmitter</a> is capable of creating Particles, but isn '<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1aded116371789db1fd63c90ef00c95a3d">t</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> particle in itself. " "After it 's lifetime has elapsed, the object will be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> loads <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> standard .DAE or .DTS <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> and creates <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> rigid body <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> " "each defined collision <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "For collision nodes <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> work correctly, they must be setup as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">follows:\n</a>" " - Visible mesh nodes are siblings of the collision node under <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> common parent dummy <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" " - <a href="/coding/class/structcollision/">Collision</a> node is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> child of its visible mesh <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n\n</a>" "Colmesh type nodes are NOT supported;physx and most standard rigid " "body simulations do not support arbitrary triangle meshs <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> dynamics " "do <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the computational <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">expense.\n\n</a>" " Therefore, collision nodes must be one of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">following:\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colbox\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colsphere\n</a>" " - <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Colcapsule\n</a>" " - Col(convex).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "%<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> should NOT be created on the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n\n</a>" " @ingroup Physics" )

ConsoleDocClass(PhysicsDebrisData , "@brief Defines the properties of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsDebris.\n</a>" "@ingroup Physics" )

DefineEngineMethod(PhysicsDebrisData , preload , void , () , "@brief Loads some information <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> have readily available at simulation <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time.\n\n</a>" "Forces generation of shaders, materials , and other data used by the %<a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> object. " "This function should be used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> level is loading in order <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> shorten " "the amount of time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> create <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsdebris/">PhysicsDebris</a> in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">game.\n\n</a>" )

IMPLEMENT_CO_DATABLOCK_V1(PhysicsDebrisData )

IMPLEMENT_CO_NETOBJECT_V1(PhysicsDebris )

  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#include "platform/platform.h"
 25#include "T3D/physics/physicsDebris.h"
 26
 27#include "core/stream/bitStream.h"
 28#include "math/mathUtils.h"
 29#include "console/consoleTypes.h"
 30#include "console/consoleObject.h"
 31#include "console/engineAPI.h"
 32#include "sim/netConnection.h"
 33#include "scene/sceneRenderState.h"
 34#include "scene/sceneManager.h"
 35#include "ts/tsShapeInstance.h"
 36#include "T3D/gameBase/gameProcess.h"
 37#include "core/resourceManager.h"
 38#include "gfx/gfxTransformSaver.h"
 39#include "lighting/lightQuery.h"
 40#include "T3D/physics/physicsBody.h"
 41#include "T3D/physics/physicsCollision.h"
 42#include "T3D/physics/physicsWorld.h"
 43#include "collision/concretePolyList.h"
 44#include "T3D/physics/physicsPlugin.h"
 45#include "math/mathUtils.h"
 46#include "gui/worldEditor/worldEditor.h"
 47#include "T3D/containerQuery.h"
 48
 49
 50F32 PhysicsDebris::smLifetimeScale = 1.0f;
 51
 52
 53IMPLEMENT_CO_DATABLOCK_V1( PhysicsDebrisData );
 54
 55ConsoleDocClass( PhysicsDebrisData,
 56   
 57   "@brief Defines the properties of a PhysicsDebris object.\n\n"
 58   "@see PhysicsDebris.\n"   
 59   "@ingroup Physics"
 60);
 61
 62PhysicsDebrisData::PhysicsDebrisData()
 63: mass( 1.0f ),
 64  dynamicFriction( 0.0f ),
 65  staticFriction( 0.0f ),
 66  restitution( 0.0f ),
 67  linearDamping( 0.0f ),
 68  angularDamping( 0.0f ),
 69  linearSleepThreshold( 1.0f ),
 70  angularSleepThreshold( 1.0f ),
 71  waterDampingScale( 1.0f ),
 72  buoyancyDensity( 0.0f ),
 73  castShadows( true )
 74{
 75   lifetime = 5.0f;
 76   lifetimeVariance = 0.0f;
 77   shapeName = NULL;
 78}
 79
 80bool PhysicsDebrisData::onAdd()
 81{
 82   if(!Parent::onAdd())
 83      return false;
 84
 85   return true;
 86}
 87
 88bool PhysicsDebrisData::preload( bool server, String &errorStr )
 89{
 90   if ( Parent::preload( server, errorStr ) == false )
 91      return false;
 92
 93   if ( server ) return true;
 94
 95   if ( shapeName && shapeName[0] != '\0' && !bool(shape) )
 96   {
 97      shape = ResourceManager::get().load( shapeName );
 98      if ( bool(shape) == false )
 99      {
100         errorStr = String::ToString( "PhysicsDebrisData::load: Couldn't load shape \"%s\"", shapeName );
101         return false;
102      }
103      else
104      {
105         // Create a dummy shape to force the generation of shaders and materials
106         // during the level load and not during gameplay.
107         TSShapeInstance *pDummy = new TSShapeInstance( shape, !server );
108         delete pDummy;
109      }
110   }
111
112   return true;
113}
114
115void PhysicsDebrisData::initPersistFields()
116{
117   addGroup( "Display" );
118
119      addField( "shapeFile", TypeShapeFilename, Offset( shapeName, PhysicsDebrisData ),
120         "@brief Path to the .DAE or .DTS file to use for this shape.\n\n"
121         "Compatable with Live-Asset Reloading.");
122
123      addField( "castShadows", TypeBool, Offset( castShadows, PhysicsDebrisData ), 
124        "@brief Determines if the shape's shadow should be cast onto the environment.\n\n" );
125
126   endGroup( "Display" );
127
128   addGroup( "Physical Properties" );
129
130      addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ),
131         "@brief Base time, in seconds, that debris persists after time of creation.\n\n"
132         "@note A %PhysicsDebris' lifetime multiplied by it's $pref::PhysicsDebris::lifetimeScale "
133         "must be equal to or greater than 1.0.\n\n");
134
135      addField("lifetimeVariance", TypeF32, Offset( lifetimeVariance, PhysicsDebrisData ),
136         "@brief Range of variation randomly applied to lifetime when debris is created.\n\n"
137         "Represents the maximum amount of seconds that will be added or subtracted to a shape's base lifetime. "
138         "A value of 0 will apply the same lifetime to each shape created.\n\n");
139
140      addField( "mass", TypeF32, Offset( mass, PhysicsDebrisData ),
141         "@brief Value representing the mass of the shape.\n\n"
142         "A shape's mass influences the magnitude of any force applied to it. "
143         "@note All PhysicsDebris objects are dynamic.");
144
145      addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsDebrisData ),
146         "@brief Coefficient of kinetic %friction to be applied to the shape.\n\n" 
147         "Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. "
148         "A larger coefficient will result in a larger reduction in velocity. "
149         "A shape's friction should be smaller than it's staticFriction, but greater than 0.\n\n"
150         "@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsDebrisData::staticFriction");
151
152      addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsDebrisData ),
153         "@brief Coefficient of static %friction to be applied to the shape.\n\n" 
154         "Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
155         "If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
156         "A higher coefficient will require a larger force to start motion. "
157         "This value should be both greater than 0 and the PhysicsDebrisData::friction.\n\n"
158         "@note This value is only applied while an object is at rest. For an object in motion, see PhysicsDebrisData::friction");
159
160      addField( "restitution", TypeF32, Offset( restitution, PhysicsDebrisData ),
161         "@brief Bounce coeffecient applied to the shape in response to a collision.\n\n"
162         "Restitution is a ratio of a shape's velocity before and after a collision. "
163         "A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. "
164         "Larger values will remove less velocity after a collision, making it \'bounce\' with greater force. "
165         "Normal %restitution values range between 0 and 1.0."
166         "@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation."
167         " Because of this, it is reccomended to avoid values close to 1.0");
168
169      addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsDebrisData ),
170         "@brief Value that reduces an object's linear velocity over time.\n\n"
171         "Larger values will cause velocity to decay quicker.\n\n" );
172
173      addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsDebrisData ),
174         "@brief Value that reduces an object's rotational velocity over time.\n\n"
175         "Larger values will cause velocity to decay quicker.\n\n" );
176
177      addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsDebrisData ),
178         "@brief Minimum linear velocity before the shape can be put to sleep.\n\n"
179         "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
180         "@note The shape must be dynamic.");
181
182      addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsDebrisData ),
183         "@brief Minimum rotational velocity before the shape can be put to sleep.\n\n"
184         "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
185         "@note The shape must be dynamic.");
186
187      addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsDebrisData ),
188         "@brief Scale to apply to linear and angular dampening while underwater.\n\n "
189         "@see angularDamping linearDamping" );
190
191      addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsDebrisData ),
192         "@brief The density of this shape for purposes of calculating buoyant forces.\n\n"
193         "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within."
194         "@see WaterObject::density");
195
196   endGroup( "Physical Properties" );
197
198   Parent::initPersistFields();
199}
200
201void PhysicsDebrisData::packData(BitStream* stream)
202{
203   Parent::packData(stream);
204
205   stream->writeFlag( castShadows );
206   stream->write( lifetime );
207   stream->write( lifetimeVariance );
208   stream->write( mass );
209   stream->write( dynamicFriction );
210   stream->write( staticFriction );
211   stream->write( restitution );
212   stream->write( linearDamping );
213   stream->write( angularDamping );
214   stream->write( linearSleepThreshold );
215   stream->write( angularSleepThreshold );
216   stream->write( waterDampingScale );
217   stream->write( buoyancyDensity );
218   stream->writeString( shapeName );
219}
220
221void PhysicsDebrisData::unpackData(BitStream* stream)
222{
223   Parent::unpackData(stream);
224
225   castShadows = stream->readFlag();
226   stream->read( &lifetime );
227   stream->read( &lifetimeVariance );
228   stream->read( &mass );
229   stream->read( &dynamicFriction );
230   stream->read( &staticFriction );
231   stream->read( &restitution );
232   stream->read( &linearDamping );
233   stream->read( &angularDamping );
234   stream->read( &linearSleepThreshold );
235   stream->read( &angularSleepThreshold );
236   stream->read( &waterDampingScale );
237   stream->read( &buoyancyDensity );
238
239   shapeName   = stream->readSTString();
240}
241
242DefineEngineMethod( PhysicsDebrisData, preload, void, (), , 
243   "@brief Loads some information to have readily available at simulation time.\n\n"
244   "Forces generation of shaders, materials, and other data used by the %PhysicsDebris object. "
245   "This function should be used while a level is loading in order to shorten "
246   "the amount of time to create a PhysicsDebris in game.\n\n")
247{
248   String errorStr;
249
250   object->shape = NULL;
251   if( !object->preload( false, errorStr ) )
252      Con::errorf( "PhsysicsDebrisData::preload - error: %s", errorStr.c_str() );
253}
254
255
256IMPLEMENT_CO_NETOBJECT_V1( PhysicsDebris );
257
258ConsoleDocClass( PhysicsDebris,
259   
260   "@brief Represents one or more rigid bodies defined in a single mesh file with "
261   "a limited lifetime.\n\n"
262
263   "A PhysicsDebris object can be viewed as a single system capable of generating multiple "
264   "@link PhysicsBody PhysicsBodies@endlink as debris when triggered. Vaguely similar to how "
265   "a ParticleEmitter is capable of creating Particles, but isn't a particle in itself. "
266
267   "After it's lifetime has elapsed, the object will be deleted.\n\n"
268
269   "%PhysicsDebris loads a standard .DAE or .DTS file and creates a rigid body for "
270   "each defined collision node.\n\n"
271
272   "For collision nodes to work correctly, they must be setup as follows:\n"
273   " - Visible mesh nodes are siblings of the collision node under a common parent dummy node.\n"
274   " -  Collision node is a child of its visible mesh node.\n\n"
275
276   "Colmesh type nodes are NOT supported; physx and most standard rigid "
277   "body simulations do not support arbitrary triangle meshs for dynamics "
278   "do to the computational expense.\n\n"
279   "Therefore, collision nodes must be one of the following:\n"
280   " - Colbox\n"
281   " - Colsphere\n"
282   " - Colcapsule\n"
283   " - Col (convex).\n\n"
284
285   "%PhysicsDebris should NOT be created on the server.\n\n"
286   
287   "@ingroup Physics"
288);
289
290PhysicsDebris* PhysicsDebris::create(  PhysicsDebrisData *datablock,
291                                       const MatrixF &transform,
292                                       const VectorF &linVel )
293{
294   // Skip out if we don't have a datablock or the
295   // global lifetime scale has it living less than
296   // a second.
297   if (  !datablock || 
298         (  datablock->lifetime > 0.0f && 
299            datablock->lifetime * smLifetimeScale < 1.0f ) )
300      return NULL;
301
302   PhysicsDebris *debris = new PhysicsDebris();
303   debris->setDataBlock( datablock );
304   debris->setTransform( transform );
305   debris->mInitialLinVel = linVel;
306   if ( !debris->registerObject() )
307   {
308      delete debris;
309      return NULL;
310   }
311
312   return debris; 
313}
314
315PhysicsDebris::PhysicsDebris()
316   :  mLifetime( 0.0f ),
317      mInitialLinVel( Point3F::Zero ),
318      mDataBlock( NULL ),
319      mShapeInstance( NULL ),
320      mWorld( NULL )
321{
322   mTypeMask |= DebrisObjectType | DynamicShapeObjectType;
323
324   // Only allocated client side.
325   mNetFlags.set( IsGhost );   
326}
327
328PhysicsDebris::~PhysicsDebris()
329{
330}
331
332void PhysicsDebris::initPersistFields()
333{
334   Con::addVariable( "$pref::PhysicsDebris::lifetimeScale", TypeF32, &smLifetimeScale,
335      "@brief Scales how long %PhysicsDebris will live before being removed.\n"
336      "@note A value of 0 will disable PhysicsDebris entirely.");
337
338   Parent::initPersistFields();
339}
340
341bool PhysicsDebris::onAdd()
342{
343   AssertFatal( isClientObject(), "PhysicsDebris::onAdd - This shouldn't be added on the server!" );
344
345   if ( !Parent::onAdd() )  
346      return false;  
347
348   if( !mDataBlock )
349   {
350      Con::errorf("PhysicsDebris::onAdd - Fail - No datablock");
351      return false;
352   }
353
354   // If it has a fixed lifetime then calculate it.
355   if ( mDataBlock->lifetime > 0.0f )
356   {
357      F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance;
358      mLifetime = mDataBlock->lifetime + lifeVar;
359   }
360
361   // Setup our bounding box
362   mObjBox = mDataBlock->shape->mBounds;
363   resetWorldBox();
364
365   // Add it to the client scene.
366   addToScene();
367
368   // We add the debris to the net connection so that
369   // it is cleaned up when the client disconnects.
370   NetConnection *conn = NetConnection::getConnectionToServer();
371   AssertFatal( conn != NULL, "PhysicsDebris::onAdd - Got null net connection!");
372   conn->addObject(this);
373
374   PhysicsPlugin::getPhysicsResetSignal().notify( this, &PhysicsDebris::_onPhysicsReset );
375   _createFragments();
376
377   return true;
378}
379
380bool PhysicsDebris::onNewDataBlock( GameBaseData *dptr, bool reload )
381{
382   if ( !dptr )
383      return false;
384
385   mDataBlock = dynamic_cast< PhysicsDebrisData* >( dptr );
386   if ( !mDataBlock )
387   {
388      Con::errorf( ConsoleLogEntry::General, "PhysicsDebris::onNewDataBlock - datablock ( %i ) is not of type PhysicsDebrisData.", dptr->getId() );
389      return false;
390   }
391
392   return true;
393}
394
395void PhysicsDebris::onRemove()
396{   
397   PhysicsPlugin::getPhysicsResetSignal().remove( this, &PhysicsDebris::_onPhysicsReset );
398
399   _deleteFragments();
400
401   removeFromScene();
402
403   Parent::onRemove();
404}
405
406void PhysicsDebris::processTick( const Move* )
407{
408   PROFILE_SCOPE( PhysicsDebris_processTick );
409
410   // Delete the debris if our lifetime has expired.
411   if (  mDataBlock->lifetime > 0.0f && 
412         mIsZero( mLifetime ) )
413   {
414      deleteObject();
415      return;
416   }
417
418   MatrixF mat;
419   mWorldBox = Box3F::Invalid;
420   Box3F bounds;
421
422   FragmentVector::iterator fragment = mFragments.begin();
423   for ( ; fragment != mFragments.end(); fragment++ )
424   {      
425      // Store the last position.
426      fragment->lastPos = fragment->pos;
427      fragment->lastRot = fragment->rot;
428
429      // Get the new position.
430      fragment->body->getTransform( &mat );
431
432      // Calculate the delta between the current
433      // global pose and the last global pose.
434      fragment->pos = mat.getPosition();
435      fragment->rot.set( mat );
436
437      // Update the bounds.
438      bounds = fragment->body->getWorldBounds();
439      mWorldBox.intersect( bounds );
440
441      // Apply forces for the next tick.
442      _updateForces( fragment->body, bounds );
443   }
444
445   // Finish up the bounds update.
446   mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
447   mObjBox = mWorldBox;
448   mWorldToObj.mul(mObjBox);
449   mRenderWorldBox = mWorldBox;
450   mRenderWorldSphere = mWorldSphere;
451}
452
453void PhysicsDebris::_updateForces( PhysicsBody *body, const Box3F &bounds )
454{
455   PROFILE_SCOPE( PhysicsDebris_updateForces );
456
457   // If we're not simulating don't update forces.
458   if ( !mWorld->isEnabled() )
459      return;
460
461   ContainerQueryInfo info;
462   info.box = bounds;
463   info.mass = mDataBlock->mass;
464
465   // Find and retreive physics info from intersecting WaterObject(s)
466   getContainer()->findObjects( bounds, WaterObjectType</a>|<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084a1af121084d5760a7eaef4bb8828ce1cf">PhysicalZoneObjectType, findRouter, &info );
467
468   // Calculate buoyancy and drag
469   F32 angDrag = mDataBlock->angularDamping;
470   F32 linDrag = mDataBlock->linearDamping;
471   F32 buoyancy = 0.0f;
472   Point3F cmass = body->getCMassPosition();
473
474   F32 density = mDataBlock->buoyancyDensity;
475   if ( density > 0.0f )
476   {
477      if ( info.waterCoverage > 0.0f )
478      {
479         F32 waterDragScale = info.waterViscosity * mDataBlock->waterDampingScale;
480         F32 powCoverage = mPow( info.waterCoverage, 0.25f );
481
482         angDrag = mLerp( angDrag, angDrag * waterDragScale, powCoverage );
483         linDrag = mLerp( linDrag, linDrag * waterDragScale, powCoverage );
484      }
485
486      // A little hackery to prevent oscillation
487      // Based on this blog post:
488      // (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html)
489
490      buoyancy = ( info.waterDensity / density ) * mPow( info.waterCoverage, 2.0f );            
491      
492      Point3F buoyancyForce = buoyancy * -mWorld->getGravity() * TickSec * mDataBlock->mass;
493      body->applyImpulse( cmass, buoyancyForce );      
494   }
495
496   // Update the dampening as the container might have changed.
497   body->setDamping( linDrag, angDrag );
498
499   // Apply physical zone forces.
500   if ( !info.appliedForce.isZero() )
501      body->applyImpulse( cmass, info.appliedForce );
502}
503
504void PhysicsDebris::advanceTime( F32 dt )
505{
506   // Decrement the lifetime.
507   if ( smLifetimeScale > 0.0f )
508      mLifetime = getMax( 0.0f, mLifetime - ( dt / smLifetimeScale ) );
509   else
510      mLifetime = 0.0f;
511}
512
513void PhysicsDebris::interpolateTick( F32 dt )
514{
515   PROFILE_SCOPE( PhysicsDebris_interpolateTick );
516
517   mShapeInstance->animate();
518   if ( mShapeInstance->getCurrentDetail() < 0 )
519      return;
520
521   const MatrixF &objectXfm = getRenderWorldTransform();
522   Vector<MatrixF> &nodeXfms = mShapeInstance->mNodeTransforms;
523
524   MatrixF globalXfm;
525   MatrixF tempXfm;
526   QuatF newRot;
527   Point3F newPos;
528
529   FragmentVector::iterator fragment = mFragments.begin();
530   for ( ; fragment != mFragments.end(); fragment++ )
531   {      
532      // Do the interpolation.
533      newRot.interpolate( fragment->rot, fragment->lastRot, dt );
534      newRot.setMatrix( &globalXfm );
535      newPos.interpolate( fragment->pos, fragment->lastPos, dt );
536      globalXfm.setPosition( newPos );
537
538      tempXfm = objectXfm * globalXfm;
539
540      for ( S32 i = 0; i < fragment->nodeIds.size(); i++ )
541      {
542         S32 n = fragment->nodeIds[i];
543         nodeXfms[n] = tempXfm;
544      }
545   }
546}
547
548void PhysicsDebris::prepRenderImage( SceneRenderState *state )
549{
550   if( !mShapeInstance )
551      return;
552
553   // Skip shadow rendering if this debris doesn't support it.
554   if (  state->isShadowPass() && 
555         !mDataBlock->castShadows )
556      return;
557
558   // If the debris is completed LOD'd out then skip it.
559   if ( mShapeInstance->setDetailFromPosAndScale( state, getRenderPosition(), getScale() ) < 0 )
560      return;
561
562   // Fade out the debris over the last second of its lifetime.
563   F32 alpha = 1.0;
564   if ( mDataBlock->lifetime > 0.0f )
565      alpha = getMin( mLifetime * smLifetimeScale, 1.0f );
566
567   // Set up our TS render state.
568   TSRenderState rdata;
569   rdata.setSceneState( state );
570   rdata.setFadeOverride( alpha );
571
572   // We might have some forward lit materials
573   // so pass down a query to gather lights.
574   LightQuery query;
575   query.init( getWorldSphere() );
576   rdata.setLightQuery( &query );
577
578   GFXTransformSaver saver;   
579
580   MatrixF mat = getRenderTransform();
581   mat.scale( getScale() );
582   GFX->setWorldMatrix( mat );       
583
584   mShapeInstance->animate();
585   mShapeInstance->render( rdata );
586}
587
588void PhysicsDebris::applyImpulse( const Point3F &pos, const VectorF &vec )
589{
590   FragmentVector::iterator fragment = mFragments.begin();
591   for ( ; fragment != mFragments.end(); fragment++ )
592      fragment->body->applyImpulse( pos, vec );
593}
594
595void PhysicsDebris::applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude )
596{
597   FragmentVector::iterator fragment = mFragments.begin();
598   for ( ; fragment != mFragments.end(); fragment++ )
599   {
600      PhysicsBody &body = *fragment->body;
601
602      Box3F bounds = body.getWorldBounds();
603
604      VectorF force = bounds.getCenter() - origin;
605      F32 dist = force.magnitudeSafe();
606      force.normalize();
607
608      if ( dist == 0.0f )
609         force *= magnitude;
610      else
611         force *= mClampF( radius / dist, 0.0f, 1.0f ) * magnitude;
612
613      body.applyImpulse( origin, force );
614   }
615}
616
617void PhysicsDebris::_createFragments()
618{
619   _deleteFragments();
620
621   mWorld = PHYSICSMGR->getWorld( "client" );
622   if ( !mWorld )
623      return;
624
625   TSShape *shape = mDataBlock->shape;
626
627   mShapeInstance = new TSShapeInstance( shape, true );
628   mShapeInstance->animate();
629   
630   Vector< CollisionShapeInfo> infoList;
631   shape->buildColShapes( false, Point3F::One, &infoList );
632      
633   mFragments.setSize( infoList.size() );
634   dMemset( mFragments.address(), 0, mFragments.memSize() );
635
636   const Point3F damageDir( 0, 0, 1 );
637
638   MatrixF bodyMat( true );
639   bodyMat = getTransform();
640
641   const U32 bodyFlags = PhysicsBody::BF_DEBRIS;
642   mWorldBox = Box3F::Invalid;
643
644   for ( S32 i = 0; i < infoList.size(); i++ )
645   {      
646      const CollisionShapeInfo &info = infoList[i];      
647
648      Fragment &fragment = mFragments[i];
649
650      if ( info.colNode == -1 )      
651         Con::errorf( "PhysicsDebris::_createFragments, Missing or couldnt find a colNode." );                  
652      else
653         _findNodes( info.colNode, fragment.nodeIds );               
654
655      PhysicsBody *body = PHYSICSMGR->createBody();
656      body->init( info.colShape, mDataBlock->mass, bodyFlags, this, mWorld );
657      body->setMaterial( mDataBlock->restitution, mDataBlock->dynamicFriction, mDataBlock->staticFriction );
658      body->setDamping( mDataBlock->linearDamping, mDataBlock->angularDamping );
659      body->setSleepThreshold( mDataBlock->linearSleepThreshold, mDataBlock->angularSleepThreshold );
660      body->setTransform( bodyMat );
661      body->setLinVelocity( mInitialLinVel );
662      fragment.body = body;
663
664      // Set the initial delta state.
665      fragment.pos = bodyMat.getPosition();
666      fragment.rot.set( bodyMat );
667      fragment.lastPos = fragment.pos;
668      fragment.lastRot = fragment.rot;
669
670      // Update the bounds.
671      mWorldBox.intersect( body->getWorldBounds() );
672   }   
673
674   // Finish up updating the bounds.
675   mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
676   mObjBox = mWorldBox;
677   mWorldToObj.mul(mObjBox);
678   mRenderWorldBox = mWorldBox;
679   mRenderWorldSphere = mWorldSphere;
680}
681
682void PhysicsDebris::_deleteFragments()
683{
684   FragmentVector::iterator fragment = mFragments.begin();
685   for ( ; fragment != mFragments.end(); fragment++ )
686      delete fragment->body;
687
688   mFragments.clear();
689
690   SAFE_DELETE( mShapeInstance );
691}
692
693void PhysicsDebris::_findNodes( U32 colNode, Vector<U32> &nodeIds )
694{   
695   // Two possible cases:
696   // 1. Visible mesh nodes are siblings of the collision node under a common parent dummy node
697   // 2. Collision node is a child of its visible mesh node
698
699   TSShape *shape = mDataBlock->shape;
700   S32 itr = shape->nodes[colNode].parentIndex;
701   itr = shape->nodes[itr].firstChild;
702
703   while ( itr != -1 )
704   {
705      if ( itr != colNode )
706         nodeIds.push_back(itr);
707      itr = shape->nodes[itr].nextSibling;
708   }
709
710   // If we didn't find any siblings of the collision node we assume
711   // it is case #2 and the collision nodes direct parent is the visible mesh.
712   if ( nodeIds.size() == 0 && shape->nodes[colNode].parentIndex != -1 )
713      nodeIds.push_back( shape->nodes[colNode].parentIndex );
714}
715
716extern bool gEditingMission;
717
718void PhysicsDebris::_onPhysicsReset( PhysicsResetEvent reset )
719{
720   if ( gEditingMission )
721   {
722      // Editing stuff, clean up the trash!
723      safeDeleteObject();
724   }
725}
726