physicsShape.cpp 38 KB

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