Physics_RigidBody.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "../Game_local.h"
  23. CLASS_DECLARATION( idPhysics_Base, idPhysics_RigidBody )
  24. END_CLASS
  25. const float STOP_SPEED = 10.0f;
  26. #undef RB_TIMINGS
  27. #ifdef RB_TIMINGS
  28. static int lastTimerReset = 0;
  29. static int numRigidBodies = 0;
  30. static idTimer timer_total, timer_collision;
  31. #endif
  32. /*
  33. ================
  34. RigidBodyDerivatives
  35. ================
  36. */
  37. void RigidBodyDerivatives( const float t, const void *clientData, const float *state, float *derivatives ) {
  38. const idPhysics_RigidBody *p = (idPhysics_RigidBody *) clientData;
  39. rigidBodyIState_t *s = (rigidBodyIState_t *) state;
  40. // NOTE: this struct should be build conform rigidBodyIState_t
  41. struct rigidBodyDerivatives_s {
  42. idVec3 linearVelocity;
  43. idMat3 angularMatrix;
  44. idVec3 force;
  45. idVec3 torque;
  46. } *d = (struct rigidBodyDerivatives_s *) derivatives;
  47. idVec3 angularVelocity;
  48. idMat3 inverseWorldInertiaTensor;
  49. inverseWorldInertiaTensor = s->orientation * p->inverseInertiaTensor * s->orientation.Transpose();
  50. angularVelocity = inverseWorldInertiaTensor * s->angularMomentum;
  51. // derivatives
  52. d->linearVelocity = p->inverseMass * s->linearMomentum;
  53. d->angularMatrix = SkewSymmetric( angularVelocity ) * s->orientation;
  54. d->force = - p->linearFriction * s->linearMomentum + p->current.externalForce;
  55. d->torque = - p->angularFriction * s->angularMomentum + p->current.externalTorque;
  56. }
  57. /*
  58. ================
  59. idPhysics_RigidBody::Integrate
  60. Calculate next state from the current state using an integrator.
  61. ================
  62. */
  63. void idPhysics_RigidBody::Integrate( float deltaTime, rigidBodyPState_t &next ) {
  64. idVec3 position;
  65. position = current.i.position;
  66. current.i.position += centerOfMass * current.i.orientation;
  67. current.i.orientation.TransposeSelf();
  68. integrator->Evaluate( (float *) &current.i, (float *) &next.i, 0, deltaTime );
  69. next.i.orientation.OrthoNormalizeSelf();
  70. // apply gravity
  71. next.i.linearMomentum += deltaTime * gravityVector * mass;
  72. current.i.orientation.TransposeSelf();
  73. next.i.orientation.TransposeSelf();
  74. current.i.position = position;
  75. next.i.position -= centerOfMass * next.i.orientation;
  76. next.atRest = current.atRest;
  77. }
  78. /*
  79. ================
  80. idPhysics_RigidBody::CollisionImpulse
  81. Calculates the collision impulse using the velocity relative to the collision object.
  82. The current state should be set to the moment of impact.
  83. ================
  84. */
  85. bool idPhysics_RigidBody::CollisionImpulse( const trace_t &collision, idVec3 &impulse ) {
  86. idVec3 r, linearVelocity, angularVelocity, velocity;
  87. idMat3 inverseWorldInertiaTensor;
  88. float impulseNumerator, impulseDenominator, vel;
  89. impactInfo_t info;
  90. idEntity *ent;
  91. // get info from other entity involved
  92. ent = gameLocal.entities[collision.c.entityNum];
  93. ent->GetImpactInfo( self, collision.c.id, collision.c.point, &info );
  94. // collision point relative to the body center of mass
  95. r = collision.c.point - ( current.i.position + centerOfMass * current.i.orientation );
  96. // the velocity at the collision point
  97. linearVelocity = inverseMass * current.i.linearMomentum;
  98. inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation;
  99. angularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum;
  100. velocity = linearVelocity + angularVelocity.Cross(r);
  101. // subtract velocity of other entity
  102. velocity -= info.velocity;
  103. // velocity in normal direction
  104. vel = velocity * collision.c.normal;
  105. if ( vel > -STOP_SPEED ) {
  106. impulseNumerator = STOP_SPEED;
  107. }
  108. else {
  109. impulseNumerator = -( 1.0f + bouncyness ) * vel;
  110. }
  111. impulseDenominator = inverseMass + ( ( inverseWorldInertiaTensor * r.Cross( collision.c.normal ) ).Cross( r ) * collision.c.normal );
  112. if ( info.invMass ) {
  113. impulseDenominator += info.invMass + ( ( info.invInertiaTensor * info.position.Cross( collision.c.normal ) ).Cross( info.position ) * collision.c.normal );
  114. }
  115. impulse = (impulseNumerator / impulseDenominator) * collision.c.normal;
  116. // update linear and angular momentum with impulse
  117. current.i.linearMomentum += impulse;
  118. current.i.angularMomentum += r.Cross(impulse);
  119. // if no movement at all don't blow up
  120. if ( collision.fraction < 0.0001f ) {
  121. current.i.linearMomentum *= 0.5f;
  122. current.i.angularMomentum *= 0.5f;
  123. }
  124. // callback to self to let the entity know about the collision
  125. return self->Collide( collision, velocity );
  126. }
  127. /*
  128. ================
  129. idPhysics_RigidBody::CheckForCollisions
  130. Check for collisions between the current and next state.
  131. If there is a collision the next state is set to the state at the moment of impact.
  132. ================
  133. */
  134. bool idPhysics_RigidBody::CheckForCollisions( const float deltaTime, rigidBodyPState_t &next, trace_t &collision ) {
  135. //#define TEST_COLLISION_DETECTION
  136. idMat3 axis;
  137. idRotation rotation;
  138. bool collided = false;
  139. #ifdef TEST_COLLISION_DETECTION
  140. bool startsolid;
  141. if ( gameLocal.clip.Contents( current.i.position, clipModel, current.i.orientation, clipMask, self ) ) {
  142. startsolid = true;
  143. }
  144. #endif
  145. TransposeMultiply( current.i.orientation, next.i.orientation, axis );
  146. rotation = axis.ToRotation();
  147. rotation.SetOrigin( current.i.position );
  148. // if there was a collision
  149. if ( gameLocal.clip.Motion( collision, current.i.position, next.i.position, rotation, clipModel, current.i.orientation, clipMask, self ) ) {
  150. // set the next state to the state at the moment of impact
  151. next.i.position = collision.endpos;
  152. next.i.orientation = collision.endAxis;
  153. next.i.linearMomentum = current.i.linearMomentum;
  154. next.i.angularMomentum = current.i.angularMomentum;
  155. collided = true;
  156. }
  157. #ifdef TEST_COLLISION_DETECTION
  158. if ( gameLocal.clip.Contents( next.i.position, clipModel, next.i.orientation, clipMask, self ) ) {
  159. if ( !startsolid ) {
  160. int bah = 1;
  161. }
  162. }
  163. #endif
  164. return collided;
  165. }
  166. /*
  167. ================
  168. idPhysics_RigidBody::ContactFriction
  169. Does not solve friction for multiple simultaneous contacts but applies contact friction in isolation.
  170. Uses absolute velocity at the contact points instead of the velocity relative to the contact object.
  171. ================
  172. */
  173. void idPhysics_RigidBody::ContactFriction( float deltaTime ) {
  174. int i;
  175. float magnitude, impulseNumerator, impulseDenominator;
  176. idMat3 inverseWorldInertiaTensor;
  177. idVec3 linearVelocity, angularVelocity;
  178. idVec3 massCenter, r, velocity, normal, impulse, normalVelocity;
  179. inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation;
  180. massCenter = current.i.position + centerOfMass * current.i.orientation;
  181. for ( i = 0; i < contacts.Num(); i++ ) {
  182. r = contacts[i].point - massCenter;
  183. // calculate velocity at contact point
  184. linearVelocity = inverseMass * current.i.linearMomentum;
  185. angularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum;
  186. velocity = linearVelocity + angularVelocity.Cross(r);
  187. // velocity along normal vector
  188. normalVelocity = ( velocity * contacts[i].normal ) * contacts[i].normal;
  189. // calculate friction impulse
  190. normal = -( velocity - normalVelocity );
  191. magnitude = normal.Normalize();
  192. impulseNumerator = contactFriction * magnitude;
  193. impulseDenominator = inverseMass + ( ( inverseWorldInertiaTensor * r.Cross( normal ) ).Cross( r ) * normal );
  194. impulse = (impulseNumerator / impulseDenominator) * normal;
  195. // apply friction impulse
  196. current.i.linearMomentum += impulse;
  197. current.i.angularMomentum += r.Cross(impulse);
  198. // if moving towards the surface at the contact point
  199. if ( normalVelocity * contacts[i].normal < 0.0f ) {
  200. // calculate impulse
  201. normal = -normalVelocity;
  202. impulseNumerator = normal.Normalize();
  203. impulseDenominator = inverseMass + ( ( inverseWorldInertiaTensor * r.Cross( normal ) ).Cross( r ) * normal );
  204. impulse = (impulseNumerator / impulseDenominator) * normal;
  205. // apply impulse
  206. current.i.linearMomentum += impulse;
  207. current.i.angularMomentum += r.Cross( impulse );
  208. }
  209. }
  210. }
  211. /*
  212. ================
  213. idPhysics_RigidBody::TestIfAtRest
  214. Returns true if the body is considered at rest.
  215. Does not catch all cases where the body is at rest but is generally good enough.
  216. ================
  217. */
  218. bool idPhysics_RigidBody::TestIfAtRest( void ) const {
  219. int i;
  220. float gv;
  221. idVec3 v, av, normal, point;
  222. idMat3 inverseWorldInertiaTensor;
  223. idFixedWinding contactWinding;
  224. if ( current.atRest >= 0 ) {
  225. return true;
  226. }
  227. // need at least 3 contact points to come to rest
  228. if ( contacts.Num() < 3 ) {
  229. return false;
  230. }
  231. // get average contact plane normal
  232. normal.Zero();
  233. for ( i = 0; i < contacts.Num(); i++ ) {
  234. normal += contacts[i].normal;
  235. }
  236. normal /= (float) contacts.Num();
  237. normal.Normalize();
  238. // if on a too steep surface
  239. if ( (normal * gravityNormal) > -0.7f ) {
  240. return false;
  241. }
  242. // create bounds for contact points
  243. contactWinding.Clear();
  244. for ( i = 0; i < contacts.Num(); i++ ) {
  245. // project point onto plane through origin orthogonal to the gravity
  246. point = contacts[i].point - (contacts[i].point * gravityNormal) * gravityNormal;
  247. contactWinding.AddToConvexHull( point, gravityNormal );
  248. }
  249. // need at least 3 contact points to come to rest
  250. if ( contactWinding.GetNumPoints() < 3 ) {
  251. return false;
  252. }
  253. // center of mass in world space
  254. point = current.i.position + centerOfMass * current.i.orientation;
  255. point -= (point * gravityNormal) * gravityNormal;
  256. // if the point is not inside the winding
  257. if ( !contactWinding.PointInside( gravityNormal, point, 0 ) ) {
  258. return false;
  259. }
  260. // linear velocity of body
  261. v = inverseMass * current.i.linearMomentum;
  262. // linear velocity in gravity direction
  263. gv = v * gravityNormal;
  264. // linear velocity orthogonal to gravity direction
  265. v -= gv * gravityNormal;
  266. // if too much velocity orthogonal to gravity direction
  267. if ( v.Length() > STOP_SPEED ) {
  268. return false;
  269. }
  270. // if too much velocity in gravity direction
  271. if ( gv > 2.0f * STOP_SPEED || gv < -2.0f * STOP_SPEED ) {
  272. return false;
  273. }
  274. // calculate rotational velocity
  275. inverseWorldInertiaTensor = current.i.orientation * inverseInertiaTensor * current.i.orientation.Transpose();
  276. av = inverseWorldInertiaTensor * current.i.angularMomentum;
  277. // if too much rotational velocity
  278. if ( av.LengthSqr() > STOP_SPEED ) {
  279. return false;
  280. }
  281. return true;
  282. }
  283. /*
  284. ================
  285. idPhysics_RigidBody::DropToFloorAndRest
  286. Drops the object straight down to the floor and verifies if the object is at rest on the floor.
  287. ================
  288. */
  289. void idPhysics_RigidBody::DropToFloorAndRest( void ) {
  290. idVec3 down;
  291. trace_t tr;
  292. if ( testSolid ) {
  293. testSolid = false;
  294. if ( gameLocal.clip.Contents( current.i.position, clipModel, current.i.orientation, clipMask, self ) ) {
  295. gameLocal.DWarning( "rigid body in solid for entity '%s' type '%s' at (%s)",
  296. self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) );
  297. Rest();
  298. dropToFloor = false;
  299. return;
  300. }
  301. }
  302. // put the body on the floor
  303. down = current.i.position + gravityNormal * 128.0f;
  304. gameLocal.clip.Translation( tr, current.i.position, down, clipModel, current.i.orientation, clipMask, self );
  305. current.i.position = tr.endpos;
  306. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), tr.endpos, current.i.orientation );
  307. // if on the floor already
  308. if ( tr.fraction == 0.0f ) {
  309. // test if we are really at rest
  310. EvaluateContacts();
  311. if ( !TestIfAtRest() ) {
  312. gameLocal.DWarning( "rigid body not at rest for entity '%s' type '%s' at (%s)",
  313. self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) );
  314. }
  315. Rest();
  316. dropToFloor = false;
  317. } else if ( IsOutsideWorld() ) {
  318. gameLocal.Warning( "rigid body outside world bounds for entity '%s' type '%s' at (%s)",
  319. self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) );
  320. Rest();
  321. dropToFloor = false;
  322. }
  323. }
  324. /*
  325. ================
  326. idPhysics_RigidBody::DebugDraw
  327. ================
  328. */
  329. void idPhysics_RigidBody::DebugDraw( void ) {
  330. if ( rb_showBodies.GetBool() || ( rb_showActive.GetBool() && current.atRest < 0 ) ) {
  331. collisionModelManager->DrawModel( clipModel->Handle(), clipModel->GetOrigin(), clipModel->GetAxis(), vec3_origin, 0.0f );
  332. }
  333. if ( rb_showMass.GetBool() ) {
  334. gameRenderWorld->DrawText( va( "\n%1.2f", mass ), current.i.position, 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 );
  335. }
  336. if ( rb_showInertia.GetBool() ) {
  337. idMat3 &I = inertiaTensor;
  338. gameRenderWorld->DrawText( va( "\n\n\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )",
  339. I[0].x, I[0].y, I[0].z,
  340. I[1].x, I[1].y, I[1].z,
  341. I[2].x, I[2].y, I[2].z ),
  342. current.i.position, 0.05f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 );
  343. }
  344. if ( rb_showVelocity.GetBool() ) {
  345. DrawVelocity( clipModel->GetId(), 0.1f, 4.0f );
  346. }
  347. }
  348. /*
  349. ================
  350. idPhysics_RigidBody::idPhysics_RigidBody
  351. ================
  352. */
  353. idPhysics_RigidBody::idPhysics_RigidBody( void ) {
  354. // set default rigid body properties
  355. SetClipMask( MASK_SOLID );
  356. SetBouncyness( 0.6f );
  357. SetFriction( 0.6f, 0.6f, 0.0f );
  358. clipModel = NULL;
  359. memset( &current, 0, sizeof( current ) );
  360. current.atRest = -1;
  361. current.lastTimeStep = USERCMD_MSEC;
  362. current.i.position.Zero();
  363. current.i.orientation.Identity();
  364. current.i.linearMomentum.Zero();
  365. current.i.angularMomentum.Zero();
  366. saved = current;
  367. mass = 1.0f;
  368. inverseMass = 1.0f;
  369. centerOfMass.Zero();
  370. inertiaTensor.Identity();
  371. inverseInertiaTensor.Identity();
  372. // use the least expensive euler integrator
  373. integrator = new idODE_Euler( sizeof(rigidBodyIState_t) / sizeof(float), RigidBodyDerivatives, this );
  374. dropToFloor = false;
  375. noImpact = false;
  376. noContact = false;
  377. hasMaster = false;
  378. isOrientated = false;
  379. #ifdef RB_TIMINGS
  380. lastTimerReset = 0;
  381. #endif
  382. }
  383. /*
  384. ================
  385. idPhysics_RigidBody::~idPhysics_RigidBody
  386. ================
  387. */
  388. idPhysics_RigidBody::~idPhysics_RigidBody( void ) {
  389. if ( clipModel ) {
  390. delete clipModel;
  391. clipModel = NULL;
  392. }
  393. delete integrator;
  394. }
  395. /*
  396. ================
  397. idPhysics_RigidBody_SavePState
  398. ================
  399. */
  400. void idPhysics_RigidBody_SavePState( idSaveGame *savefile, const rigidBodyPState_t &state ) {
  401. savefile->WriteInt( state.atRest );
  402. savefile->WriteFloat( state.lastTimeStep );
  403. savefile->WriteVec3( state.localOrigin );
  404. savefile->WriteMat3( state.localAxis );
  405. savefile->WriteVec6( state.pushVelocity );
  406. savefile->WriteVec3( state.externalForce );
  407. savefile->WriteVec3( state.externalTorque );
  408. savefile->WriteVec3( state.i.position );
  409. savefile->WriteMat3( state.i.orientation );
  410. savefile->WriteVec3( state.i.linearMomentum );
  411. savefile->WriteVec3( state.i.angularMomentum );
  412. }
  413. /*
  414. ================
  415. idPhysics_RigidBody_RestorePState
  416. ================
  417. */
  418. void idPhysics_RigidBody_RestorePState( idRestoreGame *savefile, rigidBodyPState_t &state ) {
  419. savefile->ReadInt( state.atRest );
  420. savefile->ReadFloat( state.lastTimeStep );
  421. savefile->ReadVec3( state.localOrigin );
  422. savefile->ReadMat3( state.localAxis );
  423. savefile->ReadVec6( state.pushVelocity );
  424. savefile->ReadVec3( state.externalForce );
  425. savefile->ReadVec3( state.externalTorque );
  426. savefile->ReadVec3( state.i.position );
  427. savefile->ReadMat3( state.i.orientation );
  428. savefile->ReadVec3( state.i.linearMomentum );
  429. savefile->ReadVec3( state.i.angularMomentum );
  430. }
  431. /*
  432. ================
  433. idPhysics_RigidBody::Save
  434. ================
  435. */
  436. void idPhysics_RigidBody::Save( idSaveGame *savefile ) const {
  437. idPhysics_RigidBody_SavePState( savefile, current );
  438. idPhysics_RigidBody_SavePState( savefile, saved );
  439. savefile->WriteFloat( linearFriction );
  440. savefile->WriteFloat( angularFriction );
  441. savefile->WriteFloat( contactFriction );
  442. savefile->WriteFloat( bouncyness );
  443. savefile->WriteClipModel( clipModel );
  444. savefile->WriteFloat( mass );
  445. savefile->WriteFloat( inverseMass );
  446. savefile->WriteVec3( centerOfMass );
  447. savefile->WriteMat3( inertiaTensor );
  448. savefile->WriteMat3( inverseInertiaTensor );
  449. savefile->WriteBool( dropToFloor );
  450. savefile->WriteBool( testSolid );
  451. savefile->WriteBool( noImpact );
  452. savefile->WriteBool( noContact );
  453. savefile->WriteBool( hasMaster );
  454. savefile->WriteBool( isOrientated );
  455. }
  456. /*
  457. ================
  458. idPhysics_RigidBody::Restore
  459. ================
  460. */
  461. void idPhysics_RigidBody::Restore( idRestoreGame *savefile ) {
  462. idPhysics_RigidBody_RestorePState( savefile, current );
  463. idPhysics_RigidBody_RestorePState( savefile, saved );
  464. savefile->ReadFloat( linearFriction );
  465. savefile->ReadFloat( angularFriction );
  466. savefile->ReadFloat( contactFriction );
  467. savefile->ReadFloat( bouncyness );
  468. savefile->ReadClipModel( clipModel );
  469. savefile->ReadFloat( mass );
  470. savefile->ReadFloat( inverseMass );
  471. savefile->ReadVec3( centerOfMass );
  472. savefile->ReadMat3( inertiaTensor );
  473. savefile->ReadMat3( inverseInertiaTensor );
  474. savefile->ReadBool( dropToFloor );
  475. savefile->ReadBool( testSolid );
  476. savefile->ReadBool( noImpact );
  477. savefile->ReadBool( noContact );
  478. savefile->ReadBool( hasMaster );
  479. savefile->ReadBool( isOrientated );
  480. }
  481. /*
  482. ================
  483. idPhysics_RigidBody::SetClipModel
  484. ================
  485. */
  486. #define MAX_INERTIA_SCALE 10.0f
  487. void idPhysics_RigidBody::SetClipModel( idClipModel *model, const float density, int id, bool freeOld ) {
  488. int minIndex;
  489. idMat3 inertiaScale;
  490. assert( self );
  491. assert( model ); // we need a clip model
  492. assert( model->IsTraceModel() ); // and it should be a trace model
  493. assert( density > 0.0f ); // density should be valid
  494. if ( clipModel && clipModel != model && freeOld ) {
  495. delete clipModel;
  496. }
  497. clipModel = model;
  498. clipModel->Link( gameLocal.clip, self, 0, current.i.position, current.i.orientation );
  499. // get mass properties from the trace model
  500. clipModel->GetMassProperties( density, mass, centerOfMass, inertiaTensor );
  501. // check whether or not the clip model has valid mass properties
  502. if ( mass <= 0.0f || FLOAT_IS_NAN( mass ) ) {
  503. gameLocal.Warning( "idPhysics_RigidBody::SetClipModel: invalid mass for entity '%s' type '%s'",
  504. self->name.c_str(), self->GetType()->classname );
  505. mass = 1.0f;
  506. centerOfMass.Zero();
  507. inertiaTensor.Identity();
  508. }
  509. // check whether or not the inertia tensor is balanced
  510. minIndex = Min3Index( inertiaTensor[0][0], inertiaTensor[1][1], inertiaTensor[2][2] );
  511. inertiaScale.Identity();
  512. inertiaScale[0][0] = inertiaTensor[0][0] / inertiaTensor[minIndex][minIndex];
  513. inertiaScale[1][1] = inertiaTensor[1][1] / inertiaTensor[minIndex][minIndex];
  514. inertiaScale[2][2] = inertiaTensor[2][2] / inertiaTensor[minIndex][minIndex];
  515. if ( inertiaScale[0][0] > MAX_INERTIA_SCALE || inertiaScale[1][1] > MAX_INERTIA_SCALE || inertiaScale[2][2] > MAX_INERTIA_SCALE ) {
  516. gameLocal.DWarning( "idPhysics_RigidBody::SetClipModel: unbalanced inertia tensor for entity '%s' type '%s'",
  517. self->name.c_str(), self->GetType()->classname );
  518. float min = inertiaTensor[minIndex][minIndex] * MAX_INERTIA_SCALE;
  519. inertiaScale[(minIndex+1)%3][(minIndex+1)%3] = min / inertiaTensor[(minIndex+1)%3][(minIndex+1)%3];
  520. inertiaScale[(minIndex+2)%3][(minIndex+2)%3] = min / inertiaTensor[(minIndex+2)%3][(minIndex+2)%3];
  521. inertiaTensor *= inertiaScale;
  522. }
  523. inverseMass = 1.0f / mass;
  524. inverseInertiaTensor = inertiaTensor.Inverse() * ( 1.0f / 6.0f );
  525. current.i.linearMomentum.Zero();
  526. current.i.angularMomentum.Zero();
  527. }
  528. /*
  529. ================
  530. idPhysics_RigidBody::GetClipModel
  531. ================
  532. */
  533. idClipModel *idPhysics_RigidBody::GetClipModel( int id ) const {
  534. return clipModel;
  535. }
  536. /*
  537. ================
  538. idPhysics_RigidBody::GetNumClipModels
  539. ================
  540. */
  541. int idPhysics_RigidBody::GetNumClipModels( void ) const {
  542. return 1;
  543. }
  544. /*
  545. ================
  546. idPhysics_RigidBody::SetMass
  547. ================
  548. */
  549. void idPhysics_RigidBody::SetMass( float mass, int id ) {
  550. assert( mass > 0.0f );
  551. inertiaTensor *= mass / this->mass;
  552. inverseInertiaTensor = inertiaTensor.Inverse() * (1.0f / 6.0f);
  553. this->mass = mass;
  554. inverseMass = 1.0f / mass;
  555. }
  556. /*
  557. ================
  558. idPhysics_RigidBody::GetMass
  559. ================
  560. */
  561. float idPhysics_RigidBody::GetMass( int id ) const {
  562. return mass;
  563. }
  564. /*
  565. ================
  566. idPhysics_RigidBody::SetFriction
  567. ================
  568. */
  569. void idPhysics_RigidBody::SetFriction( const float linear, const float angular, const float contact ) {
  570. if ( linear < 0.0f || linear > 1.0f ||
  571. angular < 0.0f || angular > 1.0f ||
  572. contact < 0.0f || contact > 1.0f ) {
  573. return;
  574. }
  575. linearFriction = linear;
  576. angularFriction = angular;
  577. contactFriction = contact;
  578. }
  579. /*
  580. ================
  581. idPhysics_RigidBody::SetBouncyness
  582. ================
  583. */
  584. void idPhysics_RigidBody::SetBouncyness( const float b ) {
  585. if ( b < 0.0f || b > 1.0f ) {
  586. return;
  587. }
  588. bouncyness = b;
  589. }
  590. /*
  591. ================
  592. idPhysics_RigidBody::Rest
  593. ================
  594. */
  595. void idPhysics_RigidBody::Rest( void ) {
  596. current.atRest = gameLocal.time;
  597. current.i.linearMomentum.Zero();
  598. current.i.angularMomentum.Zero();
  599. self->BecomeInactive( TH_PHYSICS );
  600. }
  601. /*
  602. ================
  603. idPhysics_RigidBody::DropToFloor
  604. ================
  605. */
  606. void idPhysics_RigidBody::DropToFloor( void ) {
  607. dropToFloor = true;
  608. testSolid = true;
  609. }
  610. /*
  611. ================
  612. idPhysics_RigidBody::NoContact
  613. ================
  614. */
  615. void idPhysics_RigidBody::NoContact( void ) {
  616. noContact = true;
  617. }
  618. /*
  619. ================
  620. idPhysics_RigidBody::Activate
  621. ================
  622. */
  623. void idPhysics_RigidBody::Activate( void ) {
  624. current.atRest = -1;
  625. self->BecomeActive( TH_PHYSICS );
  626. }
  627. /*
  628. ================
  629. idPhysics_RigidBody::PutToRest
  630. put to rest untill something collides with this physics object
  631. ================
  632. */
  633. void idPhysics_RigidBody::PutToRest( void ) {
  634. Rest();
  635. }
  636. /*
  637. ================
  638. idPhysics_RigidBody::EnableImpact
  639. ================
  640. */
  641. void idPhysics_RigidBody::EnableImpact( void ) {
  642. noImpact = false;
  643. }
  644. /*
  645. ================
  646. idPhysics_RigidBody::DisableImpact
  647. ================
  648. */
  649. void idPhysics_RigidBody::DisableImpact( void ) {
  650. noImpact = true;
  651. }
  652. /*
  653. ================
  654. idPhysics_RigidBody::SetContents
  655. ================
  656. */
  657. void idPhysics_RigidBody::SetContents( int contents, int id ) {
  658. clipModel->SetContents( contents );
  659. }
  660. /*
  661. ================
  662. idPhysics_RigidBody::GetContents
  663. ================
  664. */
  665. int idPhysics_RigidBody::GetContents( int id ) const {
  666. return clipModel->GetContents();
  667. }
  668. /*
  669. ================
  670. idPhysics_RigidBody::GetBounds
  671. ================
  672. */
  673. const idBounds &idPhysics_RigidBody::GetBounds( int id ) const {
  674. return clipModel->GetBounds();
  675. }
  676. /*
  677. ================
  678. idPhysics_RigidBody::GetAbsBounds
  679. ================
  680. */
  681. const idBounds &idPhysics_RigidBody::GetAbsBounds( int id ) const {
  682. return clipModel->GetAbsBounds();
  683. }
  684. /*
  685. ================
  686. idPhysics_RigidBody::Evaluate
  687. Evaluate the impulse based rigid body physics.
  688. When a collision occurs an impulse is applied at the moment of impact but
  689. the remaining time after the collision is ignored.
  690. ================
  691. */
  692. bool idPhysics_RigidBody::Evaluate( int timeStepMSec, int endTimeMSec ) {
  693. rigidBodyPState_t next;
  694. idAngles angles;
  695. trace_t collision;
  696. idVec3 impulse;
  697. idEntity *ent;
  698. idVec3 oldOrigin, masterOrigin;
  699. idMat3 oldAxis, masterAxis;
  700. float timeStep;
  701. bool collided, cameToRest = false;
  702. timeStep = MS2SEC( timeStepMSec );
  703. current.lastTimeStep = timeStep;
  704. if ( hasMaster ) {
  705. oldOrigin = current.i.position;
  706. oldAxis = current.i.orientation;
  707. self->GetMasterPosition( masterOrigin, masterAxis );
  708. current.i.position = masterOrigin + current.localOrigin * masterAxis;
  709. if ( isOrientated ) {
  710. current.i.orientation = current.localAxis * masterAxis;
  711. }
  712. else {
  713. current.i.orientation = current.localAxis;
  714. }
  715. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
  716. current.i.linearMomentum = mass * ( ( current.i.position - oldOrigin ) / timeStep );
  717. current.i.angularMomentum = inertiaTensor * ( ( current.i.orientation * oldAxis.Transpose() ).ToAngularVelocity() / timeStep );
  718. current.externalForce.Zero();
  719. current.externalTorque.Zero();
  720. return ( current.i.position != oldOrigin || current.i.orientation != oldAxis );
  721. }
  722. // if the body is at rest
  723. if ( current.atRest >= 0 || timeStep <= 0.0f ) {
  724. DebugDraw();
  725. return false;
  726. }
  727. // if putting the body to rest
  728. if ( dropToFloor ) {
  729. DropToFloorAndRest();
  730. current.externalForce.Zero();
  731. current.externalTorque.Zero();
  732. return true;
  733. }
  734. #ifdef RB_TIMINGS
  735. timer_total.Start();
  736. #endif
  737. // move the rigid body velocity into the frame of a pusher
  738. // current.i.linearMomentum -= current.pushVelocity.SubVec3( 0 ) * mass;
  739. // current.i.angularMomentum -= current.pushVelocity.SubVec3( 1 ) * inertiaTensor;
  740. clipModel->Unlink();
  741. next = current;
  742. // calculate next position and orientation
  743. Integrate( timeStep, next );
  744. #ifdef RB_TIMINGS
  745. timer_collision.Start();
  746. #endif
  747. // check for collisions from the current to the next state
  748. collided = CheckForCollisions( timeStep, next, collision );
  749. #ifdef RB_TIMINGS
  750. timer_collision.Stop();
  751. #endif
  752. // set the new state
  753. current = next;
  754. if ( collided ) {
  755. // apply collision impulse
  756. if ( CollisionImpulse( collision, impulse ) ) {
  757. current.atRest = gameLocal.time;
  758. }
  759. }
  760. // update the position of the clip model
  761. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
  762. DebugDraw();
  763. if ( !noContact ) {
  764. #ifdef RB_TIMINGS
  765. timer_collision.Start();
  766. #endif
  767. // get contacts
  768. EvaluateContacts();
  769. #ifdef RB_TIMINGS
  770. timer_collision.Stop();
  771. #endif
  772. // check if the body has come to rest
  773. if ( TestIfAtRest() ) {
  774. // put to rest
  775. Rest();
  776. cameToRest = true;
  777. } else {
  778. // apply contact friction
  779. ContactFriction( timeStep );
  780. }
  781. }
  782. if ( current.atRest < 0 ) {
  783. ActivateContactEntities();
  784. }
  785. if ( collided ) {
  786. // if the rigid body didn't come to rest or the other entity is not at rest
  787. ent = gameLocal.entities[collision.c.entityNum];
  788. if ( ent && ( !cameToRest || !ent->IsAtRest() ) ) {
  789. // apply impact to other entity
  790. ent->ApplyImpulse( self, collision.c.id, collision.c.point, -impulse );
  791. }
  792. }
  793. // move the rigid body velocity back into the world frame
  794. // current.i.linearMomentum += current.pushVelocity.SubVec3( 0 ) * mass;
  795. // current.i.angularMomentum += current.pushVelocity.SubVec3( 1 ) * inertiaTensor;
  796. current.pushVelocity.Zero();
  797. current.lastTimeStep = timeStep;
  798. current.externalForce.Zero();
  799. current.externalTorque.Zero();
  800. if ( IsOutsideWorld() ) {
  801. gameLocal.Warning( "rigid body moved outside world bounds for entity '%s' type '%s' at (%s)",
  802. self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) );
  803. Rest();
  804. }
  805. #ifdef RB_TIMINGS
  806. timer_total.Stop();
  807. if ( rb_showTimings->integer == 1 ) {
  808. gameLocal.Printf( "%12s: t %1.4f cd %1.4f\n",
  809. self->name.c_str(),
  810. timer_total.Milliseconds(), timer_collision.Milliseconds() );
  811. lastTimerReset = 0;
  812. }
  813. else if ( rb_showTimings->integer == 2 ) {
  814. numRigidBodies++;
  815. if ( endTimeMSec > lastTimerReset ) {
  816. gameLocal.Printf( "rb %d: t %1.4f cd %1.4f\n",
  817. numRigidBodies,
  818. timer_total.Milliseconds(), timer_collision.Milliseconds() );
  819. }
  820. }
  821. if ( endTimeMSec > lastTimerReset ) {
  822. lastTimerReset = endTimeMSec;
  823. numRigidBodies = 0;
  824. timer_total.Clear();
  825. timer_collision.Clear();
  826. }
  827. #endif
  828. return true;
  829. }
  830. /*
  831. ================
  832. idPhysics_RigidBody::UpdateTime
  833. ================
  834. */
  835. void idPhysics_RigidBody::UpdateTime( int endTimeMSec ) {
  836. }
  837. /*
  838. ================
  839. idPhysics_RigidBody::GetTime
  840. ================
  841. */
  842. int idPhysics_RigidBody::GetTime( void ) const {
  843. return gameLocal.time;
  844. }
  845. /*
  846. ================
  847. idPhysics_RigidBody::GetImpactInfo
  848. ================
  849. */
  850. void idPhysics_RigidBody::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
  851. idVec3 linearVelocity, angularVelocity;
  852. idMat3 inverseWorldInertiaTensor;
  853. linearVelocity = inverseMass * current.i.linearMomentum;
  854. inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation;
  855. angularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum;
  856. info->invMass = inverseMass;
  857. info->invInertiaTensor = inverseWorldInertiaTensor;
  858. info->position = point - ( current.i.position + centerOfMass * current.i.orientation );
  859. info->velocity = linearVelocity + angularVelocity.Cross( info->position );
  860. }
  861. /*
  862. ================
  863. idPhysics_RigidBody::ApplyImpulse
  864. ================
  865. */
  866. void idPhysics_RigidBody::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
  867. if ( noImpact ) {
  868. return;
  869. }
  870. current.i.linearMomentum += impulse;
  871. current.i.angularMomentum += ( point - ( current.i.position + centerOfMass * current.i.orientation ) ).Cross( impulse );
  872. Activate();
  873. }
  874. /*
  875. ================
  876. idPhysics_RigidBody::AddForce
  877. ================
  878. */
  879. void idPhysics_RigidBody::AddForce( const int id, const idVec3 &point, const idVec3 &force ) {
  880. if ( noImpact ) {
  881. return;
  882. }
  883. current.externalForce += force;
  884. current.externalTorque += ( point - ( current.i.position + centerOfMass * current.i.orientation ) ).Cross( force );
  885. Activate();
  886. }
  887. /*
  888. ================
  889. idPhysics_RigidBody::IsAtRest
  890. ================
  891. */
  892. bool idPhysics_RigidBody::IsAtRest( void ) const {
  893. return current.atRest >= 0;
  894. }
  895. /*
  896. ================
  897. idPhysics_RigidBody::GetRestStartTime
  898. ================
  899. */
  900. int idPhysics_RigidBody::GetRestStartTime( void ) const {
  901. return current.atRest;
  902. }
  903. /*
  904. ================
  905. idPhysics_RigidBody::IsPushable
  906. ================
  907. */
  908. bool idPhysics_RigidBody::IsPushable( void ) const {
  909. return ( !noImpact && !hasMaster );
  910. }
  911. /*
  912. ================
  913. idPhysics_RigidBody::SaveState
  914. ================
  915. */
  916. void idPhysics_RigidBody::SaveState( void ) {
  917. saved = current;
  918. }
  919. /*
  920. ================
  921. idPhysics_RigidBody::RestoreState
  922. ================
  923. */
  924. void idPhysics_RigidBody::RestoreState( void ) {
  925. current = saved;
  926. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
  927. EvaluateContacts();
  928. }
  929. /*
  930. ================
  931. idPhysics::SetOrigin
  932. ================
  933. */
  934. void idPhysics_RigidBody::SetOrigin( const idVec3 &newOrigin, int id ) {
  935. idVec3 masterOrigin;
  936. idMat3 masterAxis;
  937. current.localOrigin = newOrigin;
  938. if ( hasMaster ) {
  939. self->GetMasterPosition( masterOrigin, masterAxis );
  940. current.i.position = masterOrigin + newOrigin * masterAxis;
  941. }
  942. else {
  943. current.i.position = newOrigin;
  944. }
  945. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, clipModel->GetAxis() );
  946. Activate();
  947. }
  948. /*
  949. ================
  950. idPhysics::SetAxis
  951. ================
  952. */
  953. void idPhysics_RigidBody::SetAxis( const idMat3 &newAxis, int id ) {
  954. idVec3 masterOrigin;
  955. idMat3 masterAxis;
  956. current.localAxis = newAxis;
  957. if ( hasMaster && isOrientated ) {
  958. self->GetMasterPosition( masterOrigin, masterAxis );
  959. current.i.orientation = newAxis * masterAxis;
  960. }
  961. else {
  962. current.i.orientation = newAxis;
  963. }
  964. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), clipModel->GetOrigin(), current.i.orientation );
  965. Activate();
  966. }
  967. /*
  968. ================
  969. idPhysics::Move
  970. ================
  971. */
  972. void idPhysics_RigidBody::Translate( const idVec3 &translation, int id ) {
  973. current.localOrigin += translation;
  974. current.i.position += translation;
  975. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, clipModel->GetAxis() );
  976. Activate();
  977. }
  978. /*
  979. ================
  980. idPhysics::Rotate
  981. ================
  982. */
  983. void idPhysics_RigidBody::Rotate( const idRotation &rotation, int id ) {
  984. idVec3 masterOrigin;
  985. idMat3 masterAxis;
  986. current.i.orientation *= rotation.ToMat3();
  987. current.i.position *= rotation;
  988. if ( hasMaster ) {
  989. self->GetMasterPosition( masterOrigin, masterAxis );
  990. current.localAxis *= rotation.ToMat3();
  991. current.localOrigin = ( current.i.position - masterOrigin ) * masterAxis.Transpose();
  992. }
  993. else {
  994. current.localAxis = current.i.orientation;
  995. current.localOrigin = current.i.position;
  996. }
  997. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
  998. Activate();
  999. }
  1000. /*
  1001. ================
  1002. idPhysics_RigidBody::GetOrigin
  1003. ================
  1004. */
  1005. const idVec3 &idPhysics_RigidBody::GetOrigin( int id ) const {
  1006. return current.i.position;
  1007. }
  1008. /*
  1009. ================
  1010. idPhysics_RigidBody::GetAxis
  1011. ================
  1012. */
  1013. const idMat3 &idPhysics_RigidBody::GetAxis( int id ) const {
  1014. return current.i.orientation;
  1015. }
  1016. /*
  1017. ================
  1018. idPhysics_RigidBody::SetLinearVelocity
  1019. ================
  1020. */
  1021. void idPhysics_RigidBody::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
  1022. current.i.linearMomentum = newLinearVelocity * mass;
  1023. Activate();
  1024. }
  1025. /*
  1026. ================
  1027. idPhysics_RigidBody::SetAngularVelocity
  1028. ================
  1029. */
  1030. void idPhysics_RigidBody::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) {
  1031. current.i.angularMomentum = newAngularVelocity * inertiaTensor;
  1032. Activate();
  1033. }
  1034. /*
  1035. ================
  1036. idPhysics_RigidBody::GetLinearVelocity
  1037. ================
  1038. */
  1039. const idVec3 &idPhysics_RigidBody::GetLinearVelocity( int id ) const {
  1040. static idVec3 curLinearVelocity;
  1041. curLinearVelocity = current.i.linearMomentum * inverseMass;
  1042. return curLinearVelocity;
  1043. }
  1044. /*
  1045. ================
  1046. idPhysics_RigidBody::GetAngularVelocity
  1047. ================
  1048. */
  1049. const idVec3 &idPhysics_RigidBody::GetAngularVelocity( int id ) const {
  1050. static idVec3 curAngularVelocity;
  1051. idMat3 inverseWorldInertiaTensor;
  1052. inverseWorldInertiaTensor = current.i.orientation.Transpose() * inverseInertiaTensor * current.i.orientation;
  1053. curAngularVelocity = inverseWorldInertiaTensor * current.i.angularMomentum;
  1054. return curAngularVelocity;
  1055. }
  1056. /*
  1057. ================
  1058. idPhysics_RigidBody::ClipTranslation
  1059. ================
  1060. */
  1061. void idPhysics_RigidBody::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const {
  1062. if ( model ) {
  1063. gameLocal.clip.TranslationModel( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation,
  1064. clipModel, clipModel->GetAxis(), clipMask,
  1065. model->Handle(), model->GetOrigin(), model->GetAxis() );
  1066. }
  1067. else {
  1068. gameLocal.clip.Translation( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation,
  1069. clipModel, clipModel->GetAxis(), clipMask, self );
  1070. }
  1071. }
  1072. /*
  1073. ================
  1074. idPhysics_RigidBody::ClipRotation
  1075. ================
  1076. */
  1077. void idPhysics_RigidBody::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const {
  1078. if ( model ) {
  1079. gameLocal.clip.RotationModel( results, clipModel->GetOrigin(), rotation,
  1080. clipModel, clipModel->GetAxis(), clipMask,
  1081. model->Handle(), model->GetOrigin(), model->GetAxis() );
  1082. }
  1083. else {
  1084. gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation,
  1085. clipModel, clipModel->GetAxis(), clipMask, self );
  1086. }
  1087. }
  1088. /*
  1089. ================
  1090. idPhysics_RigidBody::ClipContents
  1091. ================
  1092. */
  1093. int idPhysics_RigidBody::ClipContents( const idClipModel *model ) const {
  1094. if ( model ) {
  1095. return gameLocal.clip.ContentsModel( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1,
  1096. model->Handle(), model->GetOrigin(), model->GetAxis() );
  1097. }
  1098. else {
  1099. return gameLocal.clip.Contents( clipModel->GetOrigin(), clipModel, clipModel->GetAxis(), -1, NULL );
  1100. }
  1101. }
  1102. /*
  1103. ================
  1104. idPhysics_RigidBody::DisableClip
  1105. ================
  1106. */
  1107. void idPhysics_RigidBody::DisableClip( void ) {
  1108. clipModel->Disable();
  1109. }
  1110. /*
  1111. ================
  1112. idPhysics_RigidBody::EnableClip
  1113. ================
  1114. */
  1115. void idPhysics_RigidBody::EnableClip( void ) {
  1116. clipModel->Enable();
  1117. }
  1118. /*
  1119. ================
  1120. idPhysics_RigidBody::UnlinkClip
  1121. ================
  1122. */
  1123. void idPhysics_RigidBody::UnlinkClip( void ) {
  1124. clipModel->Unlink();
  1125. }
  1126. /*
  1127. ================
  1128. idPhysics_RigidBody::LinkClip
  1129. ================
  1130. */
  1131. void idPhysics_RigidBody::LinkClip( void ) {
  1132. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
  1133. }
  1134. /*
  1135. ================
  1136. idPhysics_RigidBody::EvaluateContacts
  1137. ================
  1138. */
  1139. bool idPhysics_RigidBody::EvaluateContacts( void ) {
  1140. idVec6 dir;
  1141. int num;
  1142. ClearContacts();
  1143. contacts.SetNum( 10, false );
  1144. dir.SubVec3(0) = current.i.linearMomentum + current.lastTimeStep * gravityVector * mass;
  1145. dir.SubVec3(1) = current.i.angularMomentum;
  1146. dir.SubVec3(0).Normalize();
  1147. dir.SubVec3(1).Normalize();
  1148. num = gameLocal.clip.Contacts( &contacts[0], 10, clipModel->GetOrigin(),
  1149. dir, CONTACT_EPSILON, clipModel, clipModel->GetAxis(), clipMask, self );
  1150. contacts.SetNum( num, false );
  1151. AddContactEntitiesForContacts();
  1152. return ( contacts.Num() != 0 );
  1153. }
  1154. /*
  1155. ================
  1156. idPhysics_RigidBody::SetPushed
  1157. ================
  1158. */
  1159. void idPhysics_RigidBody::SetPushed( int deltaTime ) {
  1160. idRotation rotation;
  1161. rotation = ( saved.i.orientation * current.i.orientation ).ToRotation();
  1162. // velocity with which the af is pushed
  1163. current.pushVelocity.SubVec3(0) += ( current.i.position - saved.i.position ) / ( deltaTime * idMath::M_MS2SEC );
  1164. current.pushVelocity.SubVec3(1) += rotation.GetVec() * -DEG2RAD( rotation.GetAngle() ) / ( deltaTime * idMath::M_MS2SEC );
  1165. }
  1166. /*
  1167. ================
  1168. idPhysics_RigidBody::GetPushedLinearVelocity
  1169. ================
  1170. */
  1171. const idVec3 &idPhysics_RigidBody::GetPushedLinearVelocity( const int id ) const {
  1172. return current.pushVelocity.SubVec3(0);
  1173. }
  1174. /*
  1175. ================
  1176. idPhysics_RigidBody::GetPushedAngularVelocity
  1177. ================
  1178. */
  1179. const idVec3 &idPhysics_RigidBody::GetPushedAngularVelocity( const int id ) const {
  1180. return current.pushVelocity.SubVec3(1);
  1181. }
  1182. /*
  1183. ================
  1184. idPhysics_RigidBody::SetMaster
  1185. ================
  1186. */
  1187. void idPhysics_RigidBody::SetMaster( idEntity *master, const bool orientated ) {
  1188. idVec3 masterOrigin;
  1189. idMat3 masterAxis;
  1190. if ( master ) {
  1191. if ( !hasMaster ) {
  1192. // transform from world space to master space
  1193. self->GetMasterPosition( masterOrigin, masterAxis );
  1194. current.localOrigin = ( current.i.position - masterOrigin ) * masterAxis.Transpose();
  1195. if ( orientated ) {
  1196. current.localAxis = current.i.orientation * masterAxis.Transpose();
  1197. }
  1198. else {
  1199. current.localAxis = current.i.orientation;
  1200. }
  1201. hasMaster = true;
  1202. isOrientated = orientated;
  1203. ClearContacts();
  1204. }
  1205. }
  1206. else {
  1207. if ( hasMaster ) {
  1208. hasMaster = false;
  1209. Activate();
  1210. }
  1211. }
  1212. }
  1213. const float RB_VELOCITY_MAX = 16000;
  1214. const int RB_VELOCITY_TOTAL_BITS = 16;
  1215. const int RB_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( RB_VELOCITY_MAX ) ) + 1;
  1216. const int RB_VELOCITY_MANTISSA_BITS = RB_VELOCITY_TOTAL_BITS - 1 - RB_VELOCITY_EXPONENT_BITS;
  1217. const float RB_MOMENTUM_MAX = 1e20f;
  1218. const int RB_MOMENTUM_TOTAL_BITS = 16;
  1219. const int RB_MOMENTUM_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( RB_MOMENTUM_MAX ) ) + 1;
  1220. const int RB_MOMENTUM_MANTISSA_BITS = RB_MOMENTUM_TOTAL_BITS - 1 - RB_MOMENTUM_EXPONENT_BITS;
  1221. const float RB_FORCE_MAX = 1e20f;
  1222. const int RB_FORCE_TOTAL_BITS = 16;
  1223. const int RB_FORCE_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( RB_FORCE_MAX ) ) + 1;
  1224. const int RB_FORCE_MANTISSA_BITS = RB_FORCE_TOTAL_BITS - 1 - RB_FORCE_EXPONENT_BITS;
  1225. /*
  1226. ================
  1227. idPhysics_RigidBody::WriteToSnapshot
  1228. ================
  1229. */
  1230. void idPhysics_RigidBody::WriteToSnapshot( idBitMsgDelta &msg ) const {
  1231. idCQuat quat, localQuat;
  1232. quat = current.i.orientation.ToCQuat();
  1233. localQuat = current.localAxis.ToCQuat();
  1234. msg.WriteLong( current.atRest );
  1235. msg.WriteFloat( current.i.position[0] );
  1236. msg.WriteFloat( current.i.position[1] );
  1237. msg.WriteFloat( current.i.position[2] );
  1238. msg.WriteFloat( quat.x );
  1239. msg.WriteFloat( quat.y );
  1240. msg.WriteFloat( quat.z );
  1241. msg.WriteFloat( current.i.linearMomentum[0], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1242. msg.WriteFloat( current.i.linearMomentum[1], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1243. msg.WriteFloat( current.i.linearMomentum[2], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1244. msg.WriteFloat( current.i.angularMomentum[0], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1245. msg.WriteFloat( current.i.angularMomentum[1], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1246. msg.WriteFloat( current.i.angularMomentum[2], RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1247. msg.WriteDeltaFloat( current.i.position[0], current.localOrigin[0] );
  1248. msg.WriteDeltaFloat( current.i.position[1], current.localOrigin[1] );
  1249. msg.WriteDeltaFloat( current.i.position[2], current.localOrigin[2] );
  1250. msg.WriteDeltaFloat( quat.x, localQuat.x );
  1251. msg.WriteDeltaFloat( quat.y, localQuat.y );
  1252. msg.WriteDeltaFloat( quat.z, localQuat.z );
  1253. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS );
  1254. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS );
  1255. msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS );
  1256. msg.WriteDeltaFloat( 0.0f, current.externalForce[0], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1257. msg.WriteDeltaFloat( 0.0f, current.externalForce[1], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1258. msg.WriteDeltaFloat( 0.0f, current.externalForce[2], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1259. msg.WriteDeltaFloat( 0.0f, current.externalTorque[0], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1260. msg.WriteDeltaFloat( 0.0f, current.externalTorque[1], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1261. msg.WriteDeltaFloat( 0.0f, current.externalTorque[2], RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1262. }
  1263. /*
  1264. ================
  1265. idPhysics_RigidBody::ReadFromSnapshot
  1266. ================
  1267. */
  1268. void idPhysics_RigidBody::ReadFromSnapshot( const idBitMsgDelta &msg ) {
  1269. idCQuat quat, localQuat;
  1270. current.atRest = msg.ReadLong();
  1271. current.i.position[0] = msg.ReadFloat();
  1272. current.i.position[1] = msg.ReadFloat();
  1273. current.i.position[2] = msg.ReadFloat();
  1274. quat.x = msg.ReadFloat();
  1275. quat.y = msg.ReadFloat();
  1276. quat.z = msg.ReadFloat();
  1277. current.i.linearMomentum[0] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1278. current.i.linearMomentum[1] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1279. current.i.linearMomentum[2] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1280. current.i.angularMomentum[0] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1281. current.i.angularMomentum[1] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1282. current.i.angularMomentum[2] = msg.ReadFloat( RB_MOMENTUM_EXPONENT_BITS, RB_MOMENTUM_MANTISSA_BITS );
  1283. current.localOrigin[0] = msg.ReadDeltaFloat( current.i.position[0] );
  1284. current.localOrigin[1] = msg.ReadDeltaFloat( current.i.position[1] );
  1285. current.localOrigin[2] = msg.ReadDeltaFloat( current.i.position[2] );
  1286. localQuat.x = msg.ReadDeltaFloat( quat.x );
  1287. localQuat.y = msg.ReadDeltaFloat( quat.y );
  1288. localQuat.z = msg.ReadDeltaFloat( quat.z );
  1289. current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS );
  1290. current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS );
  1291. current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, RB_VELOCITY_EXPONENT_BITS, RB_VELOCITY_MANTISSA_BITS );
  1292. current.externalForce[0] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1293. current.externalForce[1] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1294. current.externalForce[2] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1295. current.externalTorque[0] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1296. current.externalTorque[1] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1297. current.externalTorque[2] = msg.ReadDeltaFloat( 0.0f, RB_FORCE_EXPONENT_BITS, RB_FORCE_MANTISSA_BITS );
  1298. current.i.orientation = quat.ToMat3();
  1299. current.localAxis = localQuat.ToMat3();
  1300. if ( clipModel ) {
  1301. clipModel->Link( gameLocal.clip, self, clipModel->GetId(), current.i.position, current.i.orientation );
  1302. }
  1303. }