Torque3D Documentation / _generateds / physicsShape.cpp

physicsShape.cpp

Engine/source/T3D/physics/physicsShape.cpp

More...

Public Functions

ConsoleDocClass(PhysicsShape , "@brief Represents <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> destructible physical object simulated through the plugin <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">system.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsShapeData.\n</a>" "@ingroup Physics" )
ConsoleDocClass(PhysicsShapeData , "@brief Defines the properties of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsShape.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsShape.\n</a>" "@ingroup Physics" )
DefineEngineMethod(PhysicsShape , applyForce , void , (Point3F force) , "@brief Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> force <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n\n</a>" "@param force <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> apply <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@note This <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> is ignored on physics shapes that are not dynamic. Wakes up the dynamic physics shape <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sleeping.\n</a>" )
DefineEngineMethod(PhysicsShape , applyTorque , void , (Point3F torque) , "@brief Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> torque <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n\n</a>" "@param torque <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> apply <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@note This <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> is ignored on physics shapes that are not dynamic. Wakes up the dynamic physics shape <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sleeping.\n</a>" )
DefineEngineMethod(PhysicsShape , destroy , void , () , "@brief Disables rendering and physical <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">simulation.\n\n</a>" "Calling destroy() will also spawn any explosions, debris , and/or destroyedShape " "defined <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> it, as well as remove it from the scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">graph.\n\n</a>" "Destroyed objects are only created on the server. Ghosting will later update the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n\n</a>" " @note This does not actually delete the PhysicsShape." )
DefineEngineMethod(PhysicsShape , isDestroyed , bool , () , "@brief Returns <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsshape/">PhysicsShape</a> has been destroyed or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.\n\n</a>" )
DefineEngineMethod(PhysicsShape , restore , void , () , "@brief Restores the shape <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> its state before being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destroyed.\n\n</a>" "Re-enables rendering and physical simulation on the object and " "adds it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the client's scene graph. " "Has no effect <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the shape is not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destroyed.\n\n</a>" )
ImplementEnumType(PhysicsSimType , "How <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> handle the physics simulation with the client's and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Physics\n\n</a>" )

Detailed Description

Public Functions

ConsoleDocClass(PhysicsShape , "@brief Represents <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> destructible physical object simulated through the plugin <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">system.\n\n</a>" "@see <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PhysicsShapeData.\n</a>" "@ingroup Physics" )

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

DefineEngineMethod(PhysicsShape , applyForce , void , (Point3F force) , "@brief Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> force <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n\n</a>" "@param force <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> apply <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@note This <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> is ignored on physics shapes that are not dynamic. Wakes up the dynamic physics shape <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sleeping.\n</a>" )

DefineEngineMethod(PhysicsShape , applyTorque , void , (Point3F torque) , "@brief Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> torque <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape.\n\n</a>" "@param torque <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> apply <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the dynamic physics <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shape\n</a>" "@note This <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> is ignored on physics shapes that are not dynamic. Wakes up the dynamic physics shape <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it is <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sleeping.\n</a>" )

DefineEngineMethod(PhysicsShape , destroy , void , () , "@brief Disables rendering and physical <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">simulation.\n\n</a>" "Calling destroy() will also spawn any explosions, debris , and/or destroyedShape " "defined <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> it, as well as remove it from the scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">graph.\n\n</a>" "Destroyed objects are only created on the server. Ghosting will later update the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">client.\n\n</a>" " @note This does not actually delete the PhysicsShape." )

DefineEngineMethod(PhysicsShape , isDestroyed , bool , () , "@brief Returns <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classphysicsshape/">PhysicsShape</a> has been destroyed or <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">not.\n\n</a>" )

DefineEngineMethod(PhysicsShape , restore , void , () , "@brief Restores the shape <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> its state before being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destroyed.\n\n</a>" "Re-enables rendering and physical simulation on the object and " "adds it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the client's scene graph. " "Has no effect <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the shape is not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">destroyed.\n\n</a>" )

IMPLEMENT_CO_DATABLOCK_V1(PhysicsShapeData )

IMPLEMENT_CO_NETOBJECT_V1(PhysicsShape )

ImplementEnumType(PhysicsSimType , "How <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> handle the physics simulation with the client's and <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">server.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Physics\n\n</a>" )

   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/physicsShape.h"
  26
  27#include "console/consoleTypes.h"
  28#include "core/stream/bitStream.h"
  29#include "core/resourceManager.h"
  30#include "math/mathIO.h"
  31#include "T3D/physics/physicsPlugin.h"
  32#include "T3D/physics/physicsBody.h"
  33#include "T3D/physics/physicsWorld.h"
  34#include "T3D/physics/physicsCollision.h"
  35#include "T3D/gameBase/gameConnection.h"
  36#include "collision/concretePolyList.h"
  37#include "ts/tsShapeInstance.h"
  38#include "scene/sceneRenderState.h"
  39#include "gfx/gfxTransformSaver.h"
  40#include "T3D/physics/physicsDebris.h"
  41#include "T3D/fx/explosion.h"
  42#include "T3D/containerQuery.h"
  43#include "lighting/lightQuery.h"
  44#include "console/engineAPI.h"
  45
  46using namespace Torque;
  47
  48bool PhysicsShape::smNoCorrections = false;
  49bool PhysicsShape::smNoSmoothing = false;
  50
  51ImplementEnumType( PhysicsSimType,
  52   "How to handle the physics simulation with the client's and server.\n"
  53   "@ingroup Physics\n\n")
  54   { PhysicsShapeData::SimType_ClientOnly,    "ClientOnly", "Only handle physics on the client.\n"  },
  55   { PhysicsShapeData::SimType_ServerOnly,   "ServerOnly", "Only handle physics on the server.\n" },
  56   { PhysicsShapeData::SimType_ClientServer,  "ClientServer", "Handle physics on both the client and server.\n"   }
  57EndImplementEnumType;
  58
  59
  60IMPLEMENT_CO_DATABLOCK_V1( PhysicsShapeData );
  61
  62ConsoleDocClass( PhysicsShapeData,
  63   
  64   "@brief Defines the properties of a PhysicsShape.\n\n"
  65   "@see PhysicsShape.\n"   
  66   "@ingroup Physics"
  67);
  68
  69PhysicsShapeData::PhysicsShapeData()
  70   :  shapeName( NULL ),
  71      mass( 1.0f ),
  72      dynamicFriction( 0.0f ),
  73      staticFriction( 0.0f ),
  74      restitution( 0.0f ),
  75      linearDamping( 0.0f ),
  76      angularDamping( 0.0f ),
  77      linearSleepThreshold( 1.0f ),
  78      angularSleepThreshold( 1.0f ),
  79      waterDampingScale( 1.0f ),
  80      buoyancyDensity( 0.0f ),
  81      simType( SimType_ClientServer )      
  82{
  83}
  84
  85PhysicsShapeData::~PhysicsShapeData()
  86{
  87}
  88
  89void PhysicsShapeData::initPersistFields()
  90{
  91   Parent::initPersistFields();
  92
  93   addGroup("Media");
  94
  95      addField( "shapeName", TypeShapeFilename, Offset( shapeName, PhysicsShapeData ),
  96         "@brief Path to the .DAE or .DTS file to use for this shape.\n\n"
  97         "Compatable with Live-Asset Reloading. ");
  98
  99      addField( "debris", TYPEID< SimObjectRef<PhysicsDebrisData> >(), Offset( debris, PhysicsShapeData ),
 100         "@brief Name of a PhysicsDebrisData to spawn when this shape is destroyed (optional)." );
 101
 102      addField( "explosion", TYPEID< SimObjectRef<ExplosionData> >(), Offset( explosion, PhysicsShapeData ),
 103         "@brief Name of an ExplosionData to spawn when this shape is destroyed (optional)." );
 104
 105      addField( "destroyedShape", TYPEID< SimObjectRef<PhysicsShapeData> >(), Offset( destroyedShape, PhysicsShapeData ),
 106         "@brief Name of a PhysicsShapeData to spawn when this shape is destroyed (optional)." );
 107
 108   endGroup("Media");
 109
 110   addGroup( "Physics" );
 111      
 112      addField( "mass", TypeF32, Offset( mass, PhysicsShapeData ),
 113         "@brief Value representing the mass of the shape.\n\n"
 114         "A shape's mass influences the magnitude of any force exerted on it. "
 115         "For example, a PhysicsShape with a large mass requires a much larger force to move than "
 116         "the same shape with a smaller mass.\n"
 117         "@note A mass of zero will create a kinematic shape while anything greater will create a dynamic shape.");
 118
 119      addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsShapeData ),
 120         "@brief Coefficient of kinetic %friction to be applied to the shape.\n\n" 
 121         "Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. "
 122         "A higher coefficient will result in a larger velocity reduction. "
 123         "A shape's friction should be lower than it's staticFriction, but larger than 0.\n\n"
 124         "@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsShape::staticFriction");
 125
 126      addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsShapeData ),
 127         "@brief Coefficient of static %friction to be applied to the shape.\n\n" 
 128         "Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
 129         "If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
 130         "A larger coefficient will require a larger force to start motion. "
 131         "This value should be larger than zero and the physicsShape's friction.\n\n"
 132         "@note This value is only applied while an object is at rest. For an object in motion, see PhysicsShape::friction");
 133
 134      addField( "restitution", TypeF32, Offset( restitution, PhysicsShapeData ),
 135         "@brief Coeffecient of a bounce applied to the shape in response to a collision.\n\n"
 136         "Restitution is a ratio of a shape's velocity before and after a collision. "
 137         "A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. "
 138         "Larger values will remove less velocity after a collision, making it \'bounce\' with a greater force. "
 139         "Normal %restitution values range between 0 and 1.0."
 140         "@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation."
 141         " Because of this it is reccomended to avoid values close to 1.0");
 142
 143      addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsShapeData ),
 144         "@brief Value that reduces an object's linear velocity over time.\n\n"
 145         "Larger values will cause velocity to decay quicker.\n\n" );
 146
 147      addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsShapeData ),
 148         "@brief Value that reduces an object's rotational velocity over time.\n\n"
 149         "Larger values will cause velocity to decay quicker.\n\n" );
 150
 151      addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsShapeData ),
 152         "@brief Minimum linear velocity before the shape can be put to sleep.\n\n"
 153         "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
 154         "@note The shape must be dynamic.");
 155
 156      addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsShapeData ),
 157         "@brief Minimum rotational velocity before the shape can be put to sleep.\n\n"
 158         "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
 159         "@note The shape must be dynamic.");
 160
 161      addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsShapeData ),
 162         "@brief Scale to apply to linear and angular dampening while underwater.\n\n "
 163         "Used with the waterViscosity of the  "
 164         "@see angularDamping linearDamping" );
 165
 166      addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsShapeData ),
 167         "@brief The density of the shape for calculating buoyant forces.\n\n"
 168         "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsShape is within.\n\n"
 169         "@see WaterObject::density");
 170
 171   endGroup( "Physics" );   
 172
 173   addGroup( "Networking" );
 174
 175      addField( "simType", TYPEID< PhysicsShapeData::SimType >(), Offset( simType, PhysicsShapeData ),
 176         "@brief Controls whether this shape is simulated on the server, client, or both physics simulations.\n\n" );
 177
 178   endGroup( "Networking" );   
 179}
 180
 181void PhysicsShapeData::packData( BitStream *stream )
 182{ 
 183   Parent::packData( stream );
 184
 185   stream->writeString( shapeName );
 186
 187   stream->write( mass );
 188   stream->write( dynamicFriction );
 189   stream->write( staticFriction );
 190   stream->write( restitution );
 191   stream->write( linearDamping );
 192   stream->write( angularDamping );
 193   stream->write( linearSleepThreshold );
 194   stream->write( angularSleepThreshold );
 195   stream->write( waterDampingScale );
 196   stream->write( buoyancyDensity );
 197
 198   stream->writeInt( simType, SimType_Bits );
 199
 200   stream->writeRangedU32( debris ? debris->getId() : 0, 0, DataBlockObjectIdLast );
 201   stream->writeRangedU32( explosion ? explosion->getId() : 0, 0, DataBlockObjectIdLast );
 202   stream->writeRangedU32( destroyedShape ? destroyedShape->getId() : 0, 0, DataBlockObjectIdLast );
 203}
 204
 205void PhysicsShapeData::unpackData( BitStream *stream )
 206{
 207   Parent::unpackData(stream);
 208
 209   shapeName = stream->readSTString();
 210
 211   stream->read( &mass );
 212   stream->read( &dynamicFriction );
 213   stream->read( &staticFriction );
 214   stream->read( &restitution );
 215   stream->read( &linearDamping );
 216   stream->read( &angularDamping );
 217   stream->read( &linearSleepThreshold );
 218   stream->read( &angularSleepThreshold );
 219   stream->read( &waterDampingScale );
 220   stream->read( &buoyancyDensity );
 221
 222   simType = (SimType)stream->readInt( SimType_Bits );
 223
 224   debris = stream->readRangedU32( 0, DataBlockObjectIdLast );
 225   explosion = stream->readRangedU32( 0, DataBlockObjectIdLast );   
 226   destroyedShape = stream->readRangedU32( 0, DataBlockObjectIdLast );
 227}
 228
 229bool PhysicsShapeData::onAdd()
 230{
 231   if ( !Parent::onAdd() )
 232      return false;
 233
 234   ResourceManager::get().getChangedSignal().notify( this, &PhysicsShapeData::_onResourceChanged );
 235   return true;
 236}
 237
 238void PhysicsShapeData::onRemove()
 239{
 240   ResourceManager::get().getChangedSignal().remove( this, &PhysicsShapeData::_onResourceChanged );
 241   Parent::onRemove();
 242}
 243
 244void PhysicsShapeData::_onResourceChanged( const Torque::Path &path )
 245{
 246   if ( path != Path( shapeName ) )
 247      return;
 248
 249   // Reload the changed shape.
 250   Resource<TSShape> reloadShape;
 251   PhysicsCollisionRef reloadcolShape;
 252
 253   reloadShape = ResourceManager::get().load( shapeName );
 254   if ( !bool(reloadShape) )
 255   {
 256      Con::warnf( ConsoleLogEntry::General, "PhysicsShapeData::_onResourceChanged: Could not reload %s.", path.getFileName().c_str() );
 257      return;
 258   }
 259
 260   // Reload the collision shape.
 261   reloadcolShape = reloadShape->buildColShape( false, Point3F::One );
 262
 263   if ( bool(reloadShape) &&  bool(reloadcolShape))
 264   {
 265      shape = reloadShape;
 266      colShape = reloadcolShape;
 267   }
 268
 269   mReloadSignal.trigger();
 270}
 271
 272bool PhysicsShapeData::preload( bool server, String &errorBuffer )
 273{
 274   if ( !Parent::preload( server, errorBuffer ) )
 275      return false;
 276      
 277   // If we don't have a physics plugin active then
 278   // we have to fail completely.
 279   if ( !PHYSICSMGR )
 280   {
 281      errorBuffer = "PhysicsShapeData::preload - No physics plugin is active!";
 282      return false;
 283   }
 284
 285   bool shapeError = false;
 286
 287   if (shapeName && shapeName[0])
 288   {
 289      // Resolve shapename
 290      shape = ResourceManager::get().load(shapeName);
 291      if (bool(shape) == false)
 292      {
 293         errorBuffer = String::ToString("PhysicsShapeData: Couldn't load shape \"%s\"", shapeName);
 294         return false;
 295      }
 296      if (!server && !shape->preloadMaterialList(shape.getPath()) && NetConnection::filesWereDownloaded())
 297         shapeError = true;
 298
 299   }
 300
 301   // Prepare the shared physics collision shape.
 302   if ( !colShape && shape )
 303   {
 304      colShape = shape->buildColShape( false, Point3F::One );
 305
 306      // If we got here and didn't get a collision shape then
 307      // we need to fail... can't have a shape without collision.
 308      if ( !colShape )
 309      {
 310         //no collision so we create a simple box collision shape from the shapes bounds and alert the user
 311         Con::warnf( "PhysicsShapeData::preload - No collision found for shape '%s', auto-creating one", shapeName );
 312         Point3F halfWidth = shape->mBounds.getExtents() * 0.5f;
 313         colShape = PHYSICSMGR->createCollision();
 314         MatrixF centerXfm(true);
 315         centerXfm.setPosition(shape->mBounds.getCenter());
 316         colShape->addBox(halfWidth, centerXfm);
 317         return true;
 318      }
 319   }   
 320
 321   // My convex demcomposion test
 322   /*
 323   // Get the verts and triangles for the first visible detail.
 324   ConcretePolyList polyList;
 325   polyList.setTransform( &MatrixF::Identity, Point3F::One );
 326   TSShapeInstance shapeInst( shape, false );
 327   shapeInst.animate(0);
 328   if ( !shapeInst.buildPolyList( &polyList, 0 ) )
 329      return false;
 330
 331   // Gah... Ratcliff's lib works on doubles... why, oh why?
 332   Vector<F64> doubleVerts;
 333   doubleVerts.setSize( polyList.mVertexList.size() * 3 );
 334   for ( U32 i=0; i < polyList.mVertexList.size(); i++ )
 335   {
 336      doubleVerts[ ( i * 3 ) + 0 ] = (F64)polyList.mVertexList[i].x;
 337      doubleVerts[ ( i * 3 ) + 1 ] = (F64)polyList.mVertexList[i].y;
 338      doubleVerts[ ( i * 3 ) + 2 ] = (F64)polyList.mVertexList[i].z;
 339   }
 340
 341   using namespace ConvexDecomposition;
 342
 343   class ConvexBuilder : public ConvexDecompInterface
 344   {
 345   public:
 346
 347      ConvexBuilder() { }
 348
 349      ~ConvexBuilder() 
 350      {
 351         for ( U32 i=0; i < mHulls.size(); i++ )
 352            delete mHulls[i];
 353      }
 354
 355      virtual void ConvexDecompResult( ConvexResult &result )
 356      {
 357         FConvexResult *hull = new FConvexResult( result );
 358         mHulls.push_back( hull );
 359      }
 360
 361      Vector<FConvexResult*> mHulls;
 362   };
 363
 364   DecompDesc d;
 365   d.mVcount       = polyList.mVertexList.size();
 366   d.mVertices     = doubleVerts.address();
 367   d.mTcount       = polyList.mIndexList.size() / 3;
 368   d.mIndices      = polyList.mIndexList.address();
 369   d.mDepth        = 3;
 370   d.mCpercent     = 20.0f;
 371   d.mPpercent     = 30.0f;
 372   d.mMaxVertices  = 32;
 373   d.mSkinWidth    = 0.05f; // Need to expose this!
 374
 375   ConvexBuilder builder;
 376   d.mCallback = &builder;
 377 
 378   if ( performConvexDecomposition( d ) < 1 || builder.mHulls.empty() )
 379      return false;
 380
 381   // Add all the convex hull results into the collision shape.
 382   colShape = PHYSICSMGR->createCollision();
 383   for ( U32 i=0; i < builder.mHulls.size(); i++ )
 384      colShape->addConvex( (const Point3F*)builder.mHulls[i]->mHullVertices, 
 385                           builder.mHulls[i]->mHullVcount,
 386                           MatrixF::Identity );
 387   */
 388
 389   return !shapeError;
 390}
 391
 392
 393IMPLEMENT_CO_NETOBJECT_V1(PhysicsShape);
 394
 395ConsoleDocClass( PhysicsShape,
 396   
 397   "@brief Represents a destructible physical object simulated through the plugin system.\n\n"
 398   "@see PhysicsShapeData.\n"   
 399   "@ingroup Physics"
 400);
 401
 402PhysicsShape::PhysicsShape()
 403   :  mPhysicsRep( NULL ),
 404      mWorld( NULL ),
 405      mResetPos( MatrixF::Identity ),
 406      mShapeInst( NULL ),
 407      mDestroyed( false ),
 408      mPlayAmbient( false ),
 409      mAmbientSeq( -1 ),
 410      mAmbientThread( NULL )
 411{
 412   mNetFlags.set( Ghostable | ScopeAlways );
 413   mTypeMask |= DynamicShapeObjectType;
 414}
 415
 416PhysicsShape::~PhysicsShape()
 417{
 418}
 419
 420void PhysicsShape::consoleInit()
 421{
 422   Con::addVariable( "$PhysicsShape::noCorrections", TypeBool, &PhysicsShape::smNoCorrections,
 423     "@brief Determines if the shape will recieve corrections from the server or "
 424     "will instead be allowed to diverge.\n\n"
 425     "In the event that the client and server object positions/orientations "
 426     "differ and if this variable is true, the server will attempt to \'correct\' "
 427     "the client object to keep it in sync. Otherwise, client and server objects may fall out of sync.\n\n");
 428
 429   Con::addVariable( "$PhysicsShape::noSmoothing", TypeBool, &PhysicsShape::smNoSmoothing,
 430     "@brief Determines if client-side shapes will attempt to smoothly transition to "
 431     "their new position after reciving a correction.\n\n"
 432     "If true, shapes will immediately render at the position they are corrected to.\n\n");
 433
 434   Parent::consoleInit();   
 435}
 436
 437void PhysicsShape::initPersistFields()
 438{   
 439   addGroup( "PhysicsShape" );
 440
 441      addField( "playAmbient", TypeBool, Offset( mPlayAmbient, PhysicsShape ),
 442            "@brief Enables or disables playing of an ambient animation upon loading the shape.\n\n"
 443            "@note The ambient animation must be named \"ambient\"." );
 444   
 445   endGroup( "PhysicsShape" );
 446
 447   Parent::initPersistFields();   
 448
 449   removeField( "scale" );
 450}
 451
 452void PhysicsShape::inspectPostApply()
 453{
 454   Parent::inspectPostApply();
 455
 456   setMaskBits( InitialUpdateMask );
 457}
 458
 459U32 PhysicsShape::packUpdate( NetConnection *con, U32 mask, BitStream *stream )
 460{
 461   U32 retMask = Parent::packUpdate( con, mask, stream );
 462
 463   if ( stream->writeFlag( mask & InitialUpdateMask ) )
 464   {
 465      stream->writeAffineTransform( getTransform() );
 466      stream->writeFlag( mPlayAmbient );
 467
 468      stream->writeFlag( mDestroyed );
 469
 470      return retMask;
 471   }
 472
 473   // If we got here its not an initial update.  So only send
 474   // the least amount of data possible.
 475
 476   if ( stream->writeFlag( mask & StateMask ) )
 477   {
 478      // This will encode the position relative to the control
 479      // object position.  
 480      //
 481      // This will compress the position to as little as 6.25
 482      // bytes if the position is within about 30 meters of the
 483      // control object.
 484      //
 485      // Worst case its a full 12 bytes + 2 bits if the position
 486      // is more than 500 meters from the control object.
 487      //
 488      stream->writeCompressedPoint( mState.position );
 489
 490      // Use only 3.5 bytes to send the orientation.
 491      stream->writeQuat( mState.orientation, 9 );
 492
 493      // If the server object has been set to sleep then
 494      // we don't need to send any velocity.
 495      if ( !stream->writeFlag( mState.sleeping ) )
 496      {
 497         // This gives me ~0.015f resolution in velocity magnitude
 498         // while only costing me 1 bit of the velocity is zero length,
 499         // <5 bytes in normal cases, and <8 bytes if the velocity is
 500         // greater than 1000.
 501         AssertWarn( mState.linVelocity.len() < 1000.0f, 
 502            "PhysicsShape::packUpdate - The linVelocity is out of range!" );
 503         stream->writeVector( mState.linVelocity, 1000.0f, 16, 9 );
 504
 505         // For angular velocity we get < 0.01f resolution in magnitude
 506         // with the most common case being under 4 bytes.
 507         AssertWarn( mState.angVelocity.len() < 10.0f, 
 508            "PhysicsShape::packUpdate - The angVelocity is out of range!" );
 509         stream->writeVector( mState.angVelocity, 10.0f, 10, 9 );
 510      }
 511   }
 512
 513   if ( stream->writeFlag( mask & DamageMask ) )
 514      stream->writeFlag( mDestroyed );
 515
 516   return retMask;
 517}   
 518
 519void PhysicsShape::unpackUpdate( NetConnection *con, BitStream *stream )
 520{
 521   Parent::unpackUpdate( con, stream );
 522
 523   if ( stream->readFlag() ) // InitialUpdateMask
 524   {
 525      MatrixF mat;
 526      stream->readAffineTransform( &mat );
 527      setTransform( mat );
 528      mPlayAmbient = stream->readFlag();
 529
 530      if ( isProperlyAdded() )
 531         _initAmbient();
 532
 533      if ( stream->readFlag() )
 534      {
 535         if ( isProperlyAdded() )
 536         {
 537            // Destroy immediately if we've already been added
 538            // to the scene.
 539            destroy();
 540         }
 541         else
 542         {
 543            // Indicate the shape should be destroyed when the
 544            // shape is added.
 545            mDestroyed = true;
 546         }
 547      }
 548
 549      return;
 550   }
 551
 552   if ( stream->readFlag() ) // StateMask
 553   {
 554      PhysicsState state;
 555      
 556      // Read the encoded and compressed position... commonly only 6.25 bytes.
 557      stream->readCompressedPoint( &state.position );
 558
 559      // Read the compressed quaternion... 3.5 bytes.
 560      stream->readQuat( &state.orientation, 9 );
 561
 562      state.sleeping = stream->readFlag();
 563      if ( !state.sleeping )
 564      {
 565         stream->readVector( &state.linVelocity, 1000.0f, 16, 9 );
 566         stream->readVector( &state.angVelocity, 10.0f, 10, 9 );
 567      }
 568
 569      if ( !smNoCorrections && mPhysicsRep && mPhysicsRep->isDynamic() && !mDestroyed )
 570      {
 571         // Set the new state on the physics object immediately.
 572         mPhysicsRep->applyCorrection( state.getTransform() );
 573
 574         mPhysicsRep->setSleeping( state.sleeping );
 575         if ( !state.sleeping )
 576         {
 577            mPhysicsRep->setLinVelocity( state.linVelocity ); 
 578            mPhysicsRep->setAngVelocity( state.angVelocity ); 
 579         }
 580
 581         mPhysicsRep->getState( &mState );
 582      }
 583
 584      // If there is no physics object then just set the
 585      // new state... the tick will take care of the 
 586      // interpolation and extrapolation.
 587      if ( !mPhysicsRep || !mPhysicsRep->isDynamic() )
 588         mState = state;
 589   }
 590
 591   if ( stream->readFlag() ) // DamageMask
 592   {
 593      if ( stream->readFlag() )
 594         destroy();
 595      else
 596         restore();
 597   }
 598}
 599
 600bool PhysicsShape::onAdd()
 601{
 602   if ( !Parent::onAdd() )
 603      return false;
 604
 605   // If we don't have a physics plugin active then
 606   // we have to fail completely.
 607   if ( !PHYSICSMGR )
 608   {
 609      Con::errorf( "PhysicsShape::onAdd - No physics plugin is active!" );
 610      return false;
 611   }
 612
 613   // 
 614   if ( !mPhysicsRep && !_createShape() )
 615   {
 616      Con::errorf( "PhysicsShape::onAdd() - Shape creation failed!" );
 617      return false;
 618   }
 619
 620   // The reset position is the transform on the server
 621   // at creation time... its not used on the client.
 622   if ( isServerObject() )
 623   {
 624      storeRestorePos();
 625      PhysicsPlugin::getPhysicsResetSignal().notify( this, &PhysicsShape::_onPhysicsReset );
 626   }
 627
 628   // Register for the resource change signal.
 629   //ResourceManager::get().getChangedSignal().notify( this, &PhysicsShape::_onResourceChanged );
 630
 631   // Only add server objects and non-destroyed client objects to the scene.
 632   if ( isServerObject() || !mDestroyed)
 633      addToScene();
 634
 635   if ( isClientObject() && mDestroyed )
 636   {
 637      // Disable all simulation of the body... no collision or dynamics.
 638      if ( mPhysicsRep )
 639         mPhysicsRep->setSimulationEnabled( false );
 640
 641      // Stop doing tick processing for this SceneObject.
 642      setProcessTick( false );
 643   }
 644
 645   return true;
 646}
 647
 648void PhysicsShape::onRemove()
 649{
 650   removeFromScene();
 651
 652   SAFE_DELETE( mPhysicsRep );
 653   SAFE_DELETE( mShapeInst );
 654   mAmbientThread = NULL;
 655   mAmbientSeq = -1;
 656   mWorld = NULL;
 657
 658   if ( isServerObject() )
 659   {
 660      PhysicsPlugin::getPhysicsResetSignal().remove( this, &PhysicsShape::_onPhysicsReset );
 661
 662      if ( mDestroyedShape )
 663        mDestroyedShape->deleteObject();
 664   }
 665
 666   // Remove the resource change signal.
 667   //ResourceManager::get().getChangedSignal().remove( this, &PhysicsShape::_onResourceChanged );
 668
 669   Parent::onRemove();
 670}
 671
 672bool PhysicsShape::onNewDataBlock( GameBaseData *dptr, bool reload )
 673{
 674   if ( !Parent::onNewDataBlock( dptr, reload ) )
 675      return false;
 676
 677   if ( !isProperlyAdded() )
 678      return true;
 679
 680   // If we don't have a physics plugin active then
 681   // we have to fail completely.
 682   if ( !PHYSICSMGR )
 683   {
 684      Con::errorf( "PhysicsShape::onNewDataBlock - No physics plugin is active!" );
 685      return false;
 686   }
 687
 688   // 
 689   if ( !_createShape() )
 690   {
 691      Con::errorf( "PhysicsShape::onNewDataBlock() - Shape creation failed!" );
 692      return false;
 693   }
 694
 695   return true;
 696}
 697
 698bool PhysicsShape::_createShape()
 699{
 700   SAFE_DELETE( mPhysicsRep );
 701   SAFE_DELETE( mShapeInst );
 702   mAmbientThread = NULL;
 703   mWorld = NULL;
 704   mAmbientSeq = -1;
 705
 706   PhysicsShapeData *db = getDataBlock();
 707   if ( !db || !db->shape)
 708      return false;
 709
 710   // Set the world box.
 711   mObjBox = db->shape->mBounds;
 712   resetWorldBox();
 713
 714   // If this is the server and its a client only simulation
 715   // object then disable our tick... the server doesn't do 
 716   // any work for this shape.
 717   if (  isServerObject() && 
 718         db->simType == PhysicsShapeData::SimType_ClientOnly )
 719   {
 720      setProcessTick( false );
 721      return true;
 722   }
 723
 724   // Create the shape instance.
 725   mShapeInst = new TSShapeInstance( db->shape, isClientObject() );
 726
 727   if ( isClientObject() )
 728   {
 729      mAmbientSeq = db->shape->findSequence( "ambient" );
 730      _initAmbient();   
 731   }
 732
 733   // If the shape has a mass then its dynamic... else
 734   // its a kinematic shape.
 735   //
 736   // While a kinematic is less optimal than a static body
 737   // it allows for us to enable/disable collision and having
 738   // all dynamic actors react correctly... waking up.
 739   // 
 740   const bool isDynamic = db->mass > 0.0f;
 741
 742   // If we aren't dynamic we don't need to tick.   
 743   setProcessTick( isDynamic || mPlayAmbient );
 744
 745   // If this is the client and we're a server only object then
 746   // we don't need any physics representation... we're done.
 747   if (  isClientObject() && 
 748         db->simType == PhysicsShapeData::SimType_ServerOnly )
 749      return true;
 750
 751   mWorld = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
 752      
 753   mPhysicsRep = PHYSICSMGR->createBody();
 754   mPhysicsRep->init(   db->colShape, 
 755                        db->mass, 
 756                        isDynamic ? 0 : PhysicsBody::BF_KINEMATIC,  
 757                        this, 
 758                        mWorld );
 759
 760   mPhysicsRep->setMaterial( db->restitution, db->dynamicFriction, db->staticFriction );
 761   
 762   if ( isDynamic )
 763   {
 764      mPhysicsRep->setDamping( db->linearDamping, db->angularDamping );
 765      mPhysicsRep->setSleepThreshold( db->linearSleepThreshold, db->angularSleepThreshold );
 766   }
 767
 768   mPhysicsRep->setTransform( getTransform() );
 769
 770   return true;
 771}
 772
 773void PhysicsShape::_initAmbient()
 774{
 775   if ( isServerObject() )
 776      return;
 777
 778   bool willPlay = mPlayAmbient && mAmbientSeq != -1;
 779
 780   if ( willPlay )
 781   {
 782      // Create thread if we dont already have.
 783      if ( mAmbientThread == NULL )
 784         mAmbientThread = mShapeInst->addThread();
 785    
 786      // Play the sequence.
 787      mShapeInst->setSequence( mAmbientThread, mAmbientSeq, 0);
 788
 789      setProcessTick(true);
 790   }
 791   else
 792   {
 793      if ( mAmbientThread != NULL )
 794      {
 795         mShapeInst->destroyThread( mAmbientThread );
 796         mAmbientThread = NULL;
 797      }
 798   }
 799}
 800
 801void PhysicsShape::_onPhysicsReset( PhysicsResetEvent reset )
 802{
 803   if ( reset == PhysicsResetEvent_Store )
 804      mResetPos = getTransform();
 805
 806   else if ( reset == PhysicsResetEvent_Restore )
 807   {
 808      setTransform( mResetPos );
 809
 810      // Restore to un-destroyed state.
 811      restore();
 812
 813      // Cheat and reset the client from here.
 814      if ( getClientObject() )
 815      {
 816         PhysicsShape *clientObj = (PhysicsShape*)getClientObject();
 817         clientObj->setTransform( mResetPos );
 818         clientObj->restore();
 819      }
 820   }
 821}
 822
 823void PhysicsShape::setTransform( const MatrixF &newMat )
 824{
 825   Parent::setTransform( newMat );
 826   
 827   // This is only called to set an absolute position
 828   // so we discard the delta state.
 829   mState.position = getPosition();
 830   mState.orientation.set( newMat );
 831   mRenderState[0] = mRenderState[1] = mState;
 832   setMaskBits( StateMask );
 833
 834   if ( mPhysicsRep )
 835      mPhysicsRep->setTransform( newMat );
 836}
 837
 838void PhysicsShape::setScale( const VectorF &scale )
 839{
 840   // Cannot scale PhysicsShape.
 841   return;
 842}
 843
 844void PhysicsShape::storeRestorePos()
 845{
 846   mResetPos = getTransform();
 847}
 848
 849F32 PhysicsShape::getMass() const 
 850{ 
 851   const PhysicsShapeData *db = const_cast<PhysicsShape*>( this )->getDataBlock();
 852   return db->mass; 
 853}
 854
 855void PhysicsShape::applyImpulse( const Point3F &pos, const VectorF &vec )
 856{
 857   if ( mPhysicsRep && mPhysicsRep->isDynamic() )
 858      mPhysicsRep->applyImpulse( pos, vec );
 859}
 860
 861void PhysicsShape::applyTorque( const Point3F &torque )
 862{
 863   if (mPhysicsRep && mPhysicsRep->isDynamic())
 864      mPhysicsRep->applyTorque( torque );
 865}
 866
 867void PhysicsShape::applyForce( const Point3F &force )
 868{
 869   if (mPhysicsRep && mPhysicsRep->isDynamic())
 870      mPhysicsRep->applyForce( force );
 871}
 872
 873void PhysicsShape::applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude )
 874{
 875   if ( !mPhysicsRep || !mPhysicsRep->isDynamic() )
 876      return;
 877
 878   // TODO: Find a better approximation of the
 879   // force vector using the object box.
 880
 881   VectorF force = getWorldBox().getCenter() - origin;
 882   F32 dist = force.magnitudeSafe();
 883   force.normalize();
 884
 885   if ( dist == 0.0f )
 886      force *= magnitude;
 887   else
 888      force *= mClampF( radius / dist, 0.0f, 1.0f ) * magnitude;   
 889
 890   mPhysicsRep->applyImpulse( origin, force );
 891
 892   // TODO: There is no simple way to really sync this sort of an 
 893   // event with the client.
 894   //
 895   // The best is to send the current physics snapshot, calculate the
 896   // time difference from when this event occured and the time when the
 897   // client recieves it, and then extrapolate where it should be.
 898   //
 899   // Even then its impossible to be absolutely sure its synced.
 900   //
 901   // Bottom line... you shouldn't use physics over the network like this.
 902   //
 903
 904   // Cheat for single player.
 905   //if ( getClientObject() )
 906      //((PhysicsShape*)getClientObject())->mPhysicsRep->applyImpulse( origin, force );
 907}
 908
 909void PhysicsShape::interpolateTick( F32 delta )
 910{
 911   AssertFatal( !mDestroyed, "PhysicsShape::interpolateTick - Shouldn't be processing a destroyed shape!" );
 912
 913   if ( !mPhysicsRep->isDynamic() )
 914      return;
 915
 916   // Interpolate the position and rotation based on the delta.
 917   PhysicsState state;
 918   state.interpolate( mRenderState[1], mRenderState[0], delta );
 919
 920   // Set the transform to the interpolated transform.
 921   setRenderTransform( state.getTransform() );
 922}
 923
 924void PhysicsShape::processTick( const Move *move )
 925{
 926   AssertFatal( mPhysicsRep && !mDestroyed, "PhysicsShape::processTick - Shouldn't be processing a destroyed shape!" );
 927
 928   // Note that unlike TSStatic, the serverside PhysicsShape does not
 929   // need to play the ambient animation because even if the animation were
 930   // to move collision shapes it would not affect the physx representation.
 931
 932   if ( !mPhysicsRep->isDynamic() )
 933      return;
 934
 935   // SINGLE PLAYER HACK!!!!
 936   if ( PHYSICSMGR->isSinglePlayer() && isClientObject() && getServerObject() )
 937   {          
 938      PhysicsShape *servObj = (PhysicsShape*)getServerObject();
 939      setTransform( servObj->mState.getTransform() );      
 940      mRenderState[0] = servObj->mRenderState[0];
 941      mRenderState[1] = servObj->mRenderState[1];
 942
 943      return;
 944   }
 945
 946   // Store the last render state.
 947   mRenderState[0] = mRenderState[1];
 948
 949   // If the last render state doesn't match the last simulation 
 950   // state then we got a correction and need to 
 951   Point3F errorDelta = mRenderState[1].position - mState.position;
 952   const bool doSmoothing = !errorDelta.isZero() && !smNoSmoothing;
 953
 954   const bool wasSleeping = mState.sleeping;
 955
 956   // Get the new physics state.
 957   if ( mPhysicsRep ) 
 958   {
 959      mPhysicsRep->getState( &mState );
 960      _updateContainerForces();
 961   }
 962   else
 963   {
 964      // This is where we could extrapolate.
 965   }
 966
 967   // Smooth the correction back into the render state.
 968   mRenderState[1] = mState;
 969   if ( doSmoothing )
 970   {
 971      F32 correction = mClampF( errorDelta.len() / 20.0f, 0.1f, 0.9f );
 972      mRenderState[1].position.interpolate( mState.position, mRenderState[0].position, correction );  
 973      mRenderState[1].orientation.interpolate( mState.orientation, mRenderState[0].orientation, correction );
 974   }
 975
 976   // If we haven't been sleeping then update our transform
 977   // and set ourselves as dirty for the next client update.
 978   if ( !wasSleeping || !mState.sleeping )
 979   {
 980      // Set the transform on the parent so that
 981      // the physics object isn't moved.
 982      Parent::setTransform( mState.getTransform() );
 983
 984      // If we're doing server simulation then we need
 985      // to send the client a state update.
 986      if ( isServerObject() && mPhysicsRep && !smNoCorrections &&
 987         
 988         !PHYSICSMGR->isSinglePlayer() // SINGLE PLAYER HACK!!!!
 989         
 990         )
 991         setMaskBits( StateMask );
 992   }
 993}
 994
 995void PhysicsShape::advanceTime( F32 timeDelta )
 996{
 997   if ( isClientObject() && mPlayAmbient && mAmbientThread != NULL )
 998      mShapeInst->advanceTime( timeDelta, mAmbientThread );
 999}
1000
1001void PhysicsShape::_updateContainerForces()
1002{
1003   PROFILE_SCOPE( PhysicsShape_updateContainerForces );
1004
1005   // If we're not simulating don't update forces.
1006   if ( !mWorld->isEnabled() )
1007      return;
1008
1009   ContainerQueryInfo info;
1010   info.box = getWorldBox();
1011   info.mass = getDataBlock()->mass;
1012
1013   // Find and retreive physics info from intersecting WaterObject(s)
1014   getContainer()->findObjects( getWorldBox(), WaterObjectType</a>|<a href="/coding/file/objecttypes_8h/#objecttypes_8h_1ac18d4a11e9446825e48fd474d7529084a1af121084d5760a7eaef4bb8828ce1cf">PhysicalZoneObjectType, findRouter, &info );
1015
1016   // Calculate buoyancy and drag
1017   F32 angDrag = getDataBlock()->angularDamping;
1018   F32 linDrag = getDataBlock()->linearDamping;
1019   F32 buoyancy = 0.0f;
1020   Point3F cmass = mPhysicsRep->getCMassPosition();
1021
1022   F32 density = getDataBlock()->buoyancyDensity;
1023   if ( density > 0.0f )
1024   {
1025      if ( info.waterCoverage > 0.0f )
1026      {
1027         F32 waterDragScale = info.waterViscosity * getDataBlock()->waterDampingScale;
1028         F32 powCoverage = mPow( info.waterCoverage, 0.25f );
1029
1030         angDrag = mLerp( angDrag, angDrag * waterDragScale, powCoverage );
1031         linDrag = mLerp( linDrag, linDrag * waterDragScale, powCoverage );
1032      }
1033
1034      buoyancy = ( info.waterDensity / density ) * mPow( info.waterCoverage, 2.0f );
1035      
1036      // A little hackery to prevent oscillation
1037      // Based on this blog post:
1038      // (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html)
1039      // JCF: disabled!
1040      Point3F buoyancyForce = buoyancy * -mWorld->getGravity() * TickSec * getDataBlock()->mass;
1041      mPhysicsRep->applyImpulse( cmass, buoyancyForce );      
1042   }
1043
1044   // Update the dampening as the container might have changed.
1045   mPhysicsRep->setDamping( linDrag, angDrag );
1046   
1047   // Apply physical zone forces.
1048   if ( !info.appliedForce.isZero() )
1049      mPhysicsRep->applyImpulse( cmass, info.appliedForce );
1050}
1051
1052void PhysicsShape::prepRenderImage( SceneRenderState *state )
1053{
1054   AssertFatal( !mDestroyed, "PhysicsShape::prepRenderImage - Shouldn't be processing a destroyed shape!" );
1055
1056   PROFILE_SCOPE( PhysicsShape_prepRenderImage );
1057
1058   if( !mShapeInst )
1059         return;
1060
1061   Point3F cameraOffset;
1062   getRenderTransform().getColumn(3,&cameraOffset);
1063   cameraOffset -= state->getDiffuseCameraPosition();
1064   F32 dist = cameraOffset.len();
1065   if (dist < 0.01f)
1066      dist = 0.01f;
1067
1068   F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z));   
1069   if ( mShapeInst->setDetailFromDistance( state, dist * invScale ) < 0 )
1070      return;
1071
1072   GFXTransformSaver saver;
1073
1074   // Set up our TS render state.
1075   TSRenderState rdata;
1076   rdata.setSceneState( state );
1077   rdata.setFadeOverride( 1.0f );
1078
1079   // We might have some forward lit materials
1080   // so pass down a query to gather lights.
1081   LightQuery query;
1082   query.init( getWorldSphere() );
1083   rdata.setLightQuery( &query );
1084
1085   MatrixF mat = getRenderTransform();
1086   mat.scale( mObjScale );
1087   GFX->setWorldMatrix( mat );
1088
1089   mShapeInst->animate();
1090   mShapeInst->render( rdata );
1091}
1092
1093void PhysicsShape::destroy()
1094{
1095   if ( mDestroyed )
1096      return;
1097
1098   mDestroyed = true;
1099   setMaskBits( DamageMask );
1100
1101   const Point3F lastLinVel = mPhysicsRep->isDynamic() ? mPhysicsRep->getLinVelocity() : Point3F::Zero;
1102
1103   // Disable all simulation of the body... no collision or dynamics.
1104   mPhysicsRep->setSimulationEnabled( false );
1105
1106   // On the client side we remove it from the scene graph
1107   // to disable rendering and volume queries.
1108   if ( isClientObject() )
1109      removeFromScene();
1110
1111   // Stop doing tick processing for this SceneObject.
1112   setProcessTick( false );
1113
1114   PhysicsShapeData *db = getDataBlock();
1115   if ( !db )
1116      return;
1117
1118   const MatrixF &mat = getTransform();
1119   if ( isServerObject() )
1120   {
1121      // We only create the destroyed object on the server
1122      // and let ghosting deal with updating the client.
1123
1124      if ( db->destroyedShape )
1125      {
1126         mDestroyedShape = new PhysicsShape();
1127         mDestroyedShape->setDataBlock( db->destroyedShape );
1128         mDestroyedShape->setTransform( mat );
1129         if ( !mDestroyedShape->registerObject() )
1130            delete mDestroyedShape.getObject();
1131      }
1132
1133      return;
1134   }
1135   
1136   // Let the physics debris create itself.
1137   PhysicsDebris::create( db->debris, mat, lastLinVel );
1138
1139   if ( db->explosion )
1140   {
1141      Explosion *splod = new Explosion();
1142      splod->setDataBlock( db->explosion );
1143      splod->setTransform( mat );
1144      splod->setInitialState( getPosition(), mat.getUpVector(), 1.0f );
1145      if ( !splod->registerObject() )
1146         delete splod;
1147   }   
1148}
1149
1150void PhysicsShape::restore()
1151{
1152   if ( !mDestroyed )
1153      return;
1154
1155   PhysicsShapeData *db = getDataBlock();
1156   const bool isDynamic = db && db->mass > 0.0f;
1157
1158   if ( mDestroyedShape )   
1159      mDestroyedShape->deleteObject();
1160
1161   // Restore tick processing, add it back to 
1162   // the scene, and enable collision and simulation.
1163   setProcessTick( isDynamic || mPlayAmbient );   
1164   if ( isClientObject() )
1165      addToScene();
1166   mPhysicsRep->setSimulationEnabled( true );
1167
1168   mDestroyed = false;
1169   setMaskBits( DamageMask );
1170}
1171
1172DefineEngineMethod( PhysicsShape, isDestroyed, bool, (),, 
1173   "@brief Returns if a PhysicsShape has been destroyed or not.\n\n" )
1174{
1175   return object->isDestroyed();
1176}
1177
1178DefineEngineMethod( PhysicsShape, destroy, void, (),,
1179   "@brief Disables rendering and physical simulation.\n\n"
1180   "Calling destroy() will also spawn any explosions, debris, and/or destroyedShape "
1181   "defined for it, as well as remove it from the scene graph.\n\n"
1182   "Destroyed objects are only created on the server. Ghosting will later update the client.\n\n"
1183   "@note This does not actually delete the PhysicsShape." )
1184{
1185   object->destroy();
1186}
1187
1188DefineEngineMethod( PhysicsShape, restore, void, (),,
1189   "@brief Restores the shape to its state before being destroyed.\n\n"
1190   "Re-enables rendering and physical simulation on the object and "
1191   "adds it to the client's scene graph. "
1192   "Has no effect if the shape is not destroyed.\n\n")
1193{
1194   object->restore();
1195}
1196
1197DefineEngineMethod( PhysicsShape, applyTorque, void, (Point3F torque), ,
1198   "@brief Add a torque to a dynamic physics shape.\n\n"
1199   "@param torque to apply to the dynamic physics shape\n"
1200   "@note This value is ignored on physics shapes that are not dynamic. Wakes up the dynamic physics shape if it is sleeping.\n")
1201{
1202   object->applyTorque( torque );
1203}
1204
1205DefineEngineMethod(PhysicsShape, applyForce, void, (Point3F force), ,
1206   "@brief Add a force to a dynamic physics shape.\n\n"
1207   "@param force to apply to the dynamic physics shape\n"
1208   "@note This value is ignored on physics shapes that are not dynamic. Wakes up the dynamic physics shape if it is sleeping.\n")
1209{
1210   object->applyForce( force );
1211}
1212