Physics_AF.cpp (201633B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 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. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../../idlib/precompiled.h" 31 32 #include "../Game_local.h" 33 34 CLASS_DECLARATION( idPhysics_Base, idPhysics_AF ) 35 END_CLASS 36 37 const float ERROR_REDUCTION = 0.5f; 38 const float ERROR_REDUCTION_MAX = 256.0f; 39 const float LIMIT_ERROR_REDUCTION = 0.3f; 40 const float LCP_EPSILON = 1e-7f; 41 const float LIMIT_LCP_EPSILON = 1e-4f; 42 const float CONTACT_LCP_EPSILON = 1e-6f; 43 const float CENTER_OF_MASS_EPSILON = 1e-4f; 44 const float NO_MOVE_TIME = 1.0f; 45 const float NO_MOVE_TRANSLATION_TOLERANCE = 10.0f; 46 const float NO_MOVE_ROTATION_TOLERANCE = 10.0f; 47 const float MIN_MOVE_TIME = -1.0f; 48 const float MAX_MOVE_TIME = -1.0f; 49 const float IMPULSE_THRESHOLD = 500.0f; 50 const float SUSPEND_LINEAR_VELOCITY = 10.0f; 51 const float SUSPEND_ANGULAR_VELOCITY = 15.0f; 52 const float SUSPEND_LINEAR_ACCELERATION = 20.0f; 53 const float SUSPEND_ANGULAR_ACCELERATION = 30.0f; 54 const idVec6 vec6_lcp_epsilon = idVec6( LCP_EPSILON, LCP_EPSILON, LCP_EPSILON, 55 LCP_EPSILON, LCP_EPSILON, LCP_EPSILON ); 56 57 #define AF_TIMINGS 58 59 #ifdef AF_TIMINGS 60 static int lastTimerReset = 0; 61 static int numArticulatedFigures = 0; 62 static idTimer timer_total, timer_pc, timer_ac, timer_collision, timer_lcp; 63 #endif 64 65 66 67 //=============================================================== 68 // 69 // idAFConstraint 70 // 71 //=============================================================== 72 73 /* 74 ================ 75 idAFConstraint::idAFConstraint 76 ================ 77 */ 78 idAFConstraint::idAFConstraint() { 79 type = CONSTRAINT_INVALID; 80 name = "noname"; 81 body1 = NULL; 82 body2 = NULL; 83 physics = NULL; 84 85 lo.Zero( 6 ); 86 lo.SubVec6(0) = -vec6_infinity; 87 hi.Zero( 6 ); 88 hi.SubVec6(0) = vec6_infinity; 89 e.SetSize( 6 ); 90 e.SubVec6(0) = vec6_lcp_epsilon; 91 92 boxConstraint = NULL; 93 boxIndex[0] = -1; 94 boxIndex[1] = -1; 95 boxIndex[2] = -1; 96 boxIndex[3] = -1; 97 boxIndex[4] = -1; 98 boxIndex[5] = -1; 99 100 firstIndex = 0; 101 102 memset( &fl, 0, sizeof( fl ) ); 103 } 104 105 /* 106 ================ 107 idAFConstraint::~idAFConstraint 108 ================ 109 */ 110 idAFConstraint::~idAFConstraint() { 111 } 112 113 /* 114 ================ 115 idAFConstraint::SetBody1 116 ================ 117 */ 118 void idAFConstraint::SetBody1( idAFBody *body ) { 119 if ( body1 != body) { 120 body1 = body; 121 if ( physics ) { 122 physics->SetChanged(); 123 } 124 } 125 } 126 127 /* 128 ================ 129 idAFConstraint::SetBody2 130 ================ 131 */ 132 void idAFConstraint::SetBody2( idAFBody *body ) { 133 if ( body2 != body ) { 134 body2 = body; 135 if ( physics ) { 136 physics->SetChanged(); 137 } 138 } 139 } 140 141 /* 142 ================ 143 idAFConstraint::GetMultiplier 144 ================ 145 */ 146 const idVecX &idAFConstraint::GetMultiplier() { 147 return lm; 148 } 149 150 /* 151 ================ 152 idAFConstraint::Evaluate 153 ================ 154 */ 155 void idAFConstraint::Evaluate( float invTimeStep ) { 156 assert( 0 ); 157 } 158 159 /* 160 ================ 161 idAFConstraint::ApplyFriction 162 ================ 163 */ 164 void idAFConstraint::ApplyFriction( float invTimeStep ) { 165 } 166 167 /* 168 ================ 169 idAFConstraint::GetForce 170 ================ 171 */ 172 void idAFConstraint::GetForce( idAFBody *body, idVec6 &force ) { 173 idVecX v; 174 175 v.SetData( 6, VECX_ALLOCA( 6 ) ); 176 if ( body == body1 ) { 177 J1.TransposeMultiply( v, lm ); 178 } 179 else if ( body == body2 ) { 180 J2.TransposeMultiply( v, lm ); 181 } 182 else { 183 v.Zero(); 184 } 185 force[0] = v[0]; force[1] = v[1]; force[2] = v[2]; force[3] = v[3]; force[4] = v[4]; force[5] = v[5]; 186 } 187 188 /* 189 ================ 190 idAFConstraint::Translate 191 ================ 192 */ 193 void idAFConstraint::Translate( const idVec3 &translation ) { 194 assert( 0 ); 195 } 196 197 /* 198 ================ 199 idAFConstraint::Rotate 200 ================ 201 */ 202 void idAFConstraint::Rotate( const idRotation &rotation ) { 203 assert( 0 ); 204 } 205 206 /* 207 ================ 208 idAFConstraint::GetCenter 209 ================ 210 */ 211 void idAFConstraint::GetCenter( idVec3 ¢er ) { 212 center.Zero(); 213 } 214 215 /* 216 ================ 217 idAFConstraint::DebugDraw 218 ================ 219 */ 220 void idAFConstraint::DebugDraw() { 221 } 222 223 /* 224 ================ 225 idAFConstraint::InitSize 226 ================ 227 */ 228 void idAFConstraint::InitSize( int size ) { 229 J1.Zero( size, 6 ); 230 J2.Zero( size, 6 ); 231 c1.Zero( size ); 232 c2.Zero( size ); 233 s.Zero( size ); 234 lm.Zero( size ); 235 } 236 237 /* 238 ================ 239 idAFConstraint::Save 240 ================ 241 */ 242 void idAFConstraint::Save( idSaveGame *saveFile ) const { 243 saveFile->WriteInt( type ); 244 } 245 246 /* 247 ================ 248 idAFConstraint::Restore 249 ================ 250 */ 251 void idAFConstraint::Restore( idRestoreGame *saveFile ) { 252 constraintType_t t; 253 saveFile->ReadInt( (int &)t ); 254 assert( t == type ); 255 } 256 257 258 //=============================================================== 259 // 260 // idAFConstraint_Fixed 261 // 262 //=============================================================== 263 264 /* 265 ================ 266 idAFConstraint_Fixed::idAFConstraint_Fixed 267 ================ 268 */ 269 idAFConstraint_Fixed::idAFConstraint_Fixed( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 270 assert( body1 ); 271 type = CONSTRAINT_FIXED; 272 this->name = name; 273 this->body1 = body1; 274 this->body2 = body2; 275 InitSize( 6 ); 276 fl.allowPrimary = true; 277 fl.noCollision = true; 278 279 InitOffset(); 280 } 281 282 /* 283 ================ 284 idAFConstraint_Fixed::InitOffset 285 ================ 286 */ 287 void idAFConstraint_Fixed::InitOffset() { 288 if ( body2 ) { 289 offset = ( body1->GetWorldOrigin() - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); 290 relAxis = body1->GetWorldAxis() * body2->GetWorldAxis().Transpose(); 291 } 292 else { 293 offset = body1->GetWorldOrigin(); 294 relAxis = body1->GetWorldAxis(); 295 } 296 } 297 298 /* 299 ================ 300 idAFConstraint_Fixed::SetBody1 301 ================ 302 */ 303 void idAFConstraint_Fixed::SetBody1( idAFBody *body ) { 304 if ( body1 != body) { 305 body1 = body; 306 InitOffset(); 307 if ( physics ) { 308 physics->SetChanged(); 309 } 310 } 311 } 312 313 /* 314 ================ 315 idAFConstraint_Fixed::SetBody2 316 ================ 317 */ 318 void idAFConstraint_Fixed::SetBody2( idAFBody *body ) { 319 if ( body2 != body ) { 320 body2 = body; 321 InitOffset(); 322 if ( physics ) { 323 physics->SetChanged(); 324 } 325 } 326 } 327 328 /* 329 ================ 330 idAFConstraint_Fixed::Evaluate 331 ================ 332 */ 333 void idAFConstraint_Fixed::Evaluate( float invTimeStep ) { 334 idVec3 ofs, a2; 335 idMat3 ax; 336 idRotation r; 337 idAFBody *master; 338 339 master = body2 ? body2 : physics->GetMasterBody(); 340 341 if ( master ) { 342 a2 = offset * master->GetWorldAxis(); 343 ofs = a2 + master->GetWorldOrigin(); 344 ax = relAxis * master->GetWorldAxis(); 345 } 346 else { 347 a2.Zero(); 348 ofs = offset; 349 ax = relAxis; 350 } 351 352 J1.Set( mat3_identity, mat3_zero, 353 mat3_zero, mat3_identity ); 354 355 if ( body2 ) { 356 J2.Set( -mat3_identity, SkewSymmetric( a2 ), 357 mat3_zero, -mat3_identity ); 358 } 359 else { 360 J2.Zero( 6, 6 ); 361 } 362 363 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( ofs - body1->GetWorldOrigin() ); 364 r = ( body1->GetWorldAxis().Transpose() * ax ).ToRotation(); 365 c1.SubVec3(1) = -( invTimeStep * ERROR_REDUCTION ) * ( r.GetVec() * -(float) DEG2RAD( r.GetAngle() ) ); 366 367 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 368 } 369 370 /* 371 ================ 372 idAFConstraint_Fixed::ApplyFriction 373 ================ 374 */ 375 void idAFConstraint_Fixed::ApplyFriction( float invTimeStep ) { 376 // no friction 377 } 378 379 /* 380 ================ 381 idAFConstraint_Fixed::Translate 382 ================ 383 */ 384 void idAFConstraint_Fixed::Translate( const idVec3 &translation ) { 385 if ( !body2 ) { 386 offset += translation; 387 } 388 } 389 390 /* 391 ================ 392 idAFConstraint_Fixed::Rotate 393 ================ 394 */ 395 void idAFConstraint_Fixed::Rotate( const idRotation &rotation ) { 396 if ( !body2 ) { 397 offset *= rotation; 398 relAxis *= rotation.ToMat3(); 399 } 400 } 401 402 /* 403 ================ 404 idAFConstraint_Fixed::GetCenter 405 ================ 406 */ 407 void idAFConstraint_Fixed::GetCenter( idVec3 ¢er ) { 408 center = body1->GetWorldOrigin(); 409 } 410 411 /* 412 ================ 413 idAFConstraint_Fixed::DebugDraw 414 ================ 415 */ 416 void idAFConstraint_Fixed::DebugDraw() { 417 idAFBody *master; 418 419 master = body2 ? body2 : physics->GetMasterBody(); 420 if ( master ) { 421 gameRenderWorld->DebugLine( colorRed, body1->GetWorldOrigin(), master->GetWorldOrigin() ); 422 } 423 else { 424 gameRenderWorld->DebugLine( colorRed, body1->GetWorldOrigin(), vec3_origin ); 425 } 426 } 427 428 /* 429 ================ 430 idAFConstraint_Fixed::Save 431 ================ 432 */ 433 void idAFConstraint_Fixed::Save( idSaveGame *saveFile ) const { 434 idAFConstraint::Save( saveFile ); 435 saveFile->WriteVec3( offset ); 436 saveFile->WriteMat3( relAxis ); 437 } 438 439 /* 440 ================ 441 idAFConstraint_Fixed::Restore 442 ================ 443 */ 444 void idAFConstraint_Fixed::Restore( idRestoreGame *saveFile ) { 445 idAFConstraint::Restore( saveFile ); 446 saveFile->ReadVec3( offset ); 447 saveFile->ReadMat3( relAxis ); 448 } 449 450 451 //=============================================================== 452 // 453 // idAFConstraint_BallAndSocketJoint 454 // 455 //=============================================================== 456 457 /* 458 ================ 459 idAFConstraint_BallAndSocketJoint::idAFConstraint_BallAndSocketJoint 460 ================ 461 */ 462 idAFConstraint_BallAndSocketJoint::idAFConstraint_BallAndSocketJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 463 assert( body1 ); 464 type = CONSTRAINT_BALLANDSOCKETJOINT; 465 this->name = name; 466 this->body1 = body1; 467 this->body2 = body2; 468 InitSize( 3 ); 469 coneLimit = NULL; 470 pyramidLimit = NULL; 471 friction = 0.0f; 472 fc = NULL; 473 fl.allowPrimary = true; 474 fl.noCollision = true; 475 } 476 477 /* 478 ================ 479 idAFConstraint_BallAndSocketJoint::~idAFConstraint_BallAndSocketJoint 480 ================ 481 */ 482 idAFConstraint_BallAndSocketJoint::~idAFConstraint_BallAndSocketJoint() { 483 if ( coneLimit ) { 484 delete coneLimit; 485 } 486 if ( pyramidLimit ) { 487 delete pyramidLimit; 488 } 489 } 490 491 /* 492 ================ 493 idAFConstraint_BallAndSocketJoint::SetAnchor 494 ================ 495 */ 496 void idAFConstraint_BallAndSocketJoint::SetAnchor( const idVec3 &worldPosition ) { 497 498 // get anchor relative to center of mass of body1 499 anchor1 = ( worldPosition - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 500 if ( body2 ) { 501 // get anchor relative to center of mass of body2 502 anchor2 = ( worldPosition - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); 503 } 504 else { 505 anchor2 = worldPosition; 506 } 507 508 if ( coneLimit ) { 509 coneLimit->SetAnchor( anchor2 ); 510 } 511 if ( pyramidLimit ) { 512 pyramidLimit->SetAnchor( anchor2 ); 513 } 514 } 515 516 /* 517 ================ 518 idAFConstraint_BallAndSocketJoint::GetAnchor 519 ================ 520 */ 521 idVec3 idAFConstraint_BallAndSocketJoint::GetAnchor() const { 522 if ( body2 ) { 523 return body2->GetWorldOrigin() + body2->GetWorldAxis() * anchor2; 524 } 525 return anchor2; 526 } 527 528 /* 529 ================ 530 idAFConstraint_BallAndSocketJoint::SetNoLimit 531 ================ 532 */ 533 void idAFConstraint_BallAndSocketJoint::SetNoLimit() { 534 if ( coneLimit ) { 535 delete coneLimit; 536 coneLimit = NULL; 537 } 538 if ( pyramidLimit ) { 539 delete pyramidLimit; 540 pyramidLimit = NULL; 541 } 542 } 543 544 /* 545 ================ 546 idAFConstraint_BallAndSocketJoint::SetConeLimit 547 ================ 548 */ 549 void idAFConstraint_BallAndSocketJoint::SetConeLimit( const idVec3 &coneAxis, const float coneAngle, const idVec3 &body1Axis ) { 550 if ( pyramidLimit ) { 551 delete pyramidLimit; 552 pyramidLimit = NULL; 553 } 554 if ( !coneLimit ) { 555 coneLimit = new (TAG_PHYSICS_AF) idAFConstraint_ConeLimit; 556 coneLimit->SetPhysics( physics ); 557 } 558 if ( body2 ) { 559 coneLimit->Setup( body1, body2, anchor2, coneAxis * body2->GetWorldAxis().Transpose(), coneAngle, body1Axis * body1->GetWorldAxis().Transpose() ); 560 } 561 else { 562 coneLimit->Setup( body1, body2, anchor2, coneAxis, coneAngle, body1Axis * body1->GetWorldAxis().Transpose() ); 563 } 564 } 565 566 /* 567 ================ 568 idAFConstraint_BallAndSocketJoint::SetPyramidLimit 569 ================ 570 */ 571 void idAFConstraint_BallAndSocketJoint::SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis, 572 const float angle1, const float angle2, const idVec3 &body1Axis ) { 573 if ( coneLimit ) { 574 delete coneLimit; 575 coneLimit = NULL; 576 } 577 if ( !pyramidLimit ) { 578 pyramidLimit = new (TAG_PHYSICS_AF) idAFConstraint_PyramidLimit; 579 pyramidLimit->SetPhysics( physics ); 580 } 581 if ( body2 ) { 582 pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis * body2->GetWorldAxis().Transpose(), 583 baseAxis * body2->GetWorldAxis().Transpose(), angle1, angle2, 584 body1Axis * body1->GetWorldAxis().Transpose() ); 585 } 586 else { 587 pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis, baseAxis, angle1, angle2, 588 body1Axis * body1->GetWorldAxis().Transpose() ); 589 } 590 } 591 592 /* 593 ================ 594 idAFConstraint_BallAndSocketJoint::SetLimitEpsilon 595 ================ 596 */ 597 void idAFConstraint_BallAndSocketJoint::SetLimitEpsilon( const float e ) { 598 if ( coneLimit ) { 599 coneLimit->SetEpsilon( e ); 600 } 601 if ( pyramidLimit ) { 602 pyramidLimit->SetEpsilon( e ); 603 } 604 } 605 606 /* 607 ================ 608 idAFConstraint_BallAndSocketJoint::GetFriction 609 ================ 610 */ 611 float idAFConstraint_BallAndSocketJoint::GetFriction() const { 612 if ( af_forceFriction.GetFloat() > 0.0f ) { 613 return af_forceFriction.GetFloat(); 614 } 615 return friction * physics->GetJointFrictionScale(); 616 } 617 618 /* 619 ================ 620 idAFConstraint_BallAndSocketJoint::Evaluate 621 ================ 622 */ 623 void idAFConstraint_BallAndSocketJoint::Evaluate( float invTimeStep ) { 624 idVec3 a1, a2; 625 idAFBody *master; 626 627 master = body2 ? body2 : physics->GetMasterBody(); 628 629 a1 = anchor1 * body1->GetWorldAxis(); 630 631 if ( master ) { 632 a2 = anchor2 * master->GetWorldAxis(); 633 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 + master->GetWorldOrigin() - ( a1 + body1->GetWorldOrigin() ) ); 634 } 635 else { 636 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( anchor2 - ( a1 + body1->GetWorldOrigin() ) ); 637 } 638 639 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 640 641 J1.Set( mat3_identity, -SkewSymmetric( a1 ) ); 642 643 if ( body2 ) { 644 J2.Set( -mat3_identity, SkewSymmetric( a2 ) ); 645 } 646 else { 647 J2.Zero( 3, 6 ); 648 } 649 650 if ( coneLimit ) { 651 coneLimit->Add( physics, invTimeStep ); 652 } 653 else if ( pyramidLimit ) { 654 pyramidLimit->Add( physics, invTimeStep ); 655 } 656 } 657 658 /* 659 ================ 660 idAFConstraint_BallAndSocketJoint::ApplyFriction 661 ================ 662 */ 663 void idAFConstraint_BallAndSocketJoint::ApplyFriction( float invTimeStep ) { 664 idVec3 angular; 665 float invMass, currentFriction; 666 667 currentFriction = GetFriction(); 668 669 if ( currentFriction <= 0.0f ) { 670 return; 671 } 672 673 if ( af_useImpulseFriction.GetBool() || af_useJointImpulseFriction.GetBool() ) { 674 675 angular = body1->GetAngularVelocity(); 676 invMass = body1->GetInverseMass(); 677 if ( body2 ) { 678 angular -= body2->GetAngularVelocity(); 679 invMass += body2->GetInverseMass(); 680 } 681 682 angular *= currentFriction / invMass; 683 684 body1->SetAngularVelocity( body1->GetAngularVelocity() - angular * body1->GetInverseMass() ); 685 if ( body2 ) { 686 body2->SetAngularVelocity( body2->GetAngularVelocity() + angular * body2->GetInverseMass() ); 687 } 688 } 689 else { 690 if ( !fc ) { 691 fc = new (TAG_PHYSICS_AF) idAFConstraint_BallAndSocketJointFriction; 692 fc->Setup( this ); 693 } 694 695 fc->Add( physics, invTimeStep ); 696 } 697 } 698 699 /* 700 ================ 701 idAFConstraint_BallAndSocketJoint::GetForce 702 ================ 703 */ 704 void idAFConstraint_BallAndSocketJoint::GetForce( idAFBody *body, idVec6 &force ) { 705 idAFConstraint::GetForce( body, force ); 706 // FIXME: add limit force 707 } 708 709 /* 710 ================ 711 idAFConstraint_BallAndSocketJoint::Translate 712 ================ 713 */ 714 void idAFConstraint_BallAndSocketJoint::Translate( const idVec3 &translation ) { 715 if ( !body2 ) { 716 anchor2 += translation; 717 } 718 if ( coneLimit ) { 719 coneLimit->Translate( translation ); 720 } 721 else if ( pyramidLimit ) { 722 pyramidLimit->Translate( translation ); 723 } 724 } 725 726 /* 727 ================ 728 idAFConstraint_BallAndSocketJoint::Rotate 729 ================ 730 */ 731 void idAFConstraint_BallAndSocketJoint::Rotate( const idRotation &rotation ) { 732 if ( !body2 ) { 733 anchor2 *= rotation; 734 } 735 if ( coneLimit ) { 736 coneLimit->Rotate( rotation ); 737 } 738 else if ( pyramidLimit ) { 739 pyramidLimit->Rotate( rotation ); 740 } 741 } 742 743 /* 744 ================ 745 idAFConstraint_BallAndSocketJoint::GetCenter 746 ================ 747 */ 748 void idAFConstraint_BallAndSocketJoint::GetCenter( idVec3 ¢er ) { 749 center = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 750 } 751 752 /* 753 ================ 754 idAFConstraint_BallAndSocketJoint::DebugDraw 755 ================ 756 */ 757 void idAFConstraint_BallAndSocketJoint::DebugDraw() { 758 idVec3 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 759 gameRenderWorld->DebugLine( colorBlue, a1 - idVec3( 5, 0, 0 ), a1 + idVec3( 5, 0, 0 ) ); 760 gameRenderWorld->DebugLine( colorBlue, a1 - idVec3( 0, 5, 0 ), a1 + idVec3( 0, 5, 0 ) ); 761 gameRenderWorld->DebugLine( colorBlue, a1 - idVec3( 0, 0, 5 ), a1 + idVec3( 0, 0, 5 ) ); 762 763 if ( af_showLimits.GetBool() ) { 764 if ( coneLimit ) { 765 coneLimit->DebugDraw(); 766 } 767 if ( pyramidLimit ) { 768 pyramidLimit->DebugDraw(); 769 } 770 } 771 } 772 773 /* 774 ================ 775 idAFConstraint_BallAndSocketJoint::Save 776 ================ 777 */ 778 void idAFConstraint_BallAndSocketJoint::Save( idSaveGame *saveFile ) const { 779 idAFConstraint::Save( saveFile ); 780 saveFile->WriteVec3( anchor1 ); 781 saveFile->WriteVec3( anchor2 ); 782 saveFile->WriteFloat( friction ); 783 if ( coneLimit ) { 784 coneLimit->Save( saveFile ); 785 } 786 if ( pyramidLimit ) { 787 pyramidLimit->Save( saveFile ); 788 } 789 } 790 791 /* 792 ================ 793 idAFConstraint_BallAndSocketJoint::Restore 794 ================ 795 */ 796 void idAFConstraint_BallAndSocketJoint::Restore( idRestoreGame *saveFile ) { 797 idAFConstraint::Restore( saveFile ); 798 saveFile->ReadVec3( anchor1 ); 799 saveFile->ReadVec3( anchor2 ); 800 saveFile->ReadFloat( friction ); 801 if ( coneLimit ) { 802 coneLimit->Restore( saveFile ); 803 } 804 if ( pyramidLimit ) { 805 pyramidLimit->Restore( saveFile ); 806 } 807 } 808 809 810 //=============================================================== 811 // 812 // idAFConstraint_BallAndSocketJointFriction 813 // 814 //=============================================================== 815 816 /* 817 ================ 818 idAFConstraint_BallAndSocketJointFriction::idAFConstraint_BallAndSocketJointFriction 819 ================ 820 */ 821 idAFConstraint_BallAndSocketJointFriction::idAFConstraint_BallAndSocketJointFriction() { 822 type = CONSTRAINT_FRICTION; 823 name = "ballAndSocketJointFriction"; 824 InitSize( 3 ); 825 joint = NULL; 826 fl.allowPrimary = false; 827 fl.frameConstraint = true; 828 } 829 830 /* 831 ================ 832 idAFConstraint_BallAndSocketJointFriction::Setup 833 ================ 834 */ 835 void idAFConstraint_BallAndSocketJointFriction::Setup( idAFConstraint_BallAndSocketJoint *bsj ) { 836 this->joint = bsj; 837 body1 = bsj->GetBody1(); 838 body2 = bsj->GetBody2(); 839 } 840 841 /* 842 ================ 843 idAFConstraint_BallAndSocketJointFriction::Evaluate 844 ================ 845 */ 846 void idAFConstraint_BallAndSocketJointFriction::Evaluate( float invTimeStep ) { 847 // do nothing 848 } 849 850 /* 851 ================ 852 idAFConstraint_BallAndSocketJointFriction::ApplyFriction 853 ================ 854 */ 855 void idAFConstraint_BallAndSocketJointFriction::ApplyFriction( float invTimeStep ) { 856 // do nothing 857 } 858 859 /* 860 ================ 861 idAFConstraint_BallAndSocketJointFriction::Add 862 ================ 863 */ 864 bool idAFConstraint_BallAndSocketJointFriction::Add( idPhysics_AF *phys, float invTimeStep ) { 865 float f; 866 867 physics = phys; 868 869 f = joint->GetFriction() * joint->GetMultiplier().Length(); 870 if ( f == 0.0f ) { 871 return false; 872 } 873 874 lo[0] = lo[1] = lo[2] = -f; 875 hi[0] = hi[1] = hi[2] = f; 876 877 J1.Zero( 3, 6 ); 878 J1[0][3] = J1[1][4] = J1[2][5] = 1.0f; 879 880 if ( body2 ) { 881 882 J2.Zero( 3, 6 ); 883 J2[0][3] = J2[1][4] = J2[2][5] = 1.0f; 884 } 885 886 physics->AddFrameConstraint( this ); 887 888 return true; 889 } 890 891 /* 892 ================ 893 idAFConstraint_BallAndSocketJointFriction::Translate 894 ================ 895 */ 896 void idAFConstraint_BallAndSocketJointFriction::Translate( const idVec3 &translation ) { 897 } 898 899 /* 900 ================ 901 idAFConstraint_BallAndSocketJointFriction::Rotate 902 ================ 903 */ 904 void idAFConstraint_BallAndSocketJointFriction::Rotate( const idRotation &rotation ) { 905 } 906 907 908 //=============================================================== 909 // 910 // idAFConstraint_UniversalJoint 911 // 912 //=============================================================== 913 914 /* 915 ================ 916 idAFConstraint_UniversalJoint::idAFConstraint_UniversalJoint 917 ================ 918 */ 919 idAFConstraint_UniversalJoint::idAFConstraint_UniversalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 920 assert( body1 ); 921 type = CONSTRAINT_UNIVERSALJOINT; 922 this->name = name; 923 this->body1 = body1; 924 this->body2 = body2; 925 InitSize( 4 ); 926 coneLimit = NULL; 927 pyramidLimit = NULL; 928 friction = 0.0f; 929 fc = NULL; 930 fl.allowPrimary = true; 931 fl.noCollision = true; 932 } 933 934 /* 935 ================ 936 idAFConstraint_UniversalJoint::~idAFConstraint_UniversalJoint 937 ================ 938 */ 939 idAFConstraint_UniversalJoint::~idAFConstraint_UniversalJoint() { 940 if ( coneLimit ) { 941 delete coneLimit; 942 } 943 if ( pyramidLimit ) { 944 delete pyramidLimit; 945 } 946 if ( fc ) { 947 delete fc; 948 } 949 } 950 951 /* 952 ================ 953 idAFConstraint_UniversalJoint::SetAnchor 954 ================ 955 */ 956 void idAFConstraint_UniversalJoint::SetAnchor( const idVec3 &worldPosition ) { 957 958 // get anchor relative to center of mass of body1 959 anchor1 = ( worldPosition - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 960 if ( body2 ) { 961 // get anchor relative to center of mass of body2 962 anchor2 = ( worldPosition - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); 963 } 964 else { 965 anchor2 = worldPosition; 966 } 967 968 if ( coneLimit ) { 969 coneLimit->SetAnchor( anchor2 ); 970 } 971 if ( pyramidLimit ) { 972 pyramidLimit->SetAnchor( anchor2 ); 973 } 974 } 975 976 /* 977 ================ 978 idAFConstraint_UniversalJoint::GetAnchor 979 ================ 980 */ 981 idVec3 idAFConstraint_UniversalJoint::GetAnchor() const { 982 if ( body2 ) { 983 return body2->GetWorldOrigin() + body2->GetWorldAxis() * anchor2; 984 } 985 return anchor2; 986 } 987 988 /* 989 ================ 990 idAFConstraint_UniversalJoint::SetShafts 991 ================ 992 */ 993 void idAFConstraint_UniversalJoint::SetShafts( const idVec3 &cardanShaft1, const idVec3 &cardanShaft2 ) { 994 idVec3 cardanAxis; 995 float l; 996 997 shaft1 = cardanShaft1; 998 l = shaft1.Normalize(); 999 assert( l != 0.0f ); 1000 shaft2 = cardanShaft2; 1001 l = shaft2.Normalize(); 1002 assert( l != 0.0f ); 1003 1004 // the cardan axis is a vector orthogonal to both cardan shafts 1005 cardanAxis = shaft1.Cross( shaft2 ); 1006 if ( cardanAxis.Normalize() == 0.0f ) { 1007 idVec3 vecY; 1008 shaft1.OrthogonalBasis( cardanAxis, vecY ); 1009 cardanAxis.Normalize(); 1010 } 1011 1012 shaft1 *= body1->GetWorldAxis().Transpose(); 1013 axis1 = cardanAxis * body1->GetWorldAxis().Transpose(); 1014 if ( body2 ) { 1015 shaft2 *= body2->GetWorldAxis().Transpose(); 1016 axis2 = cardanAxis * body2->GetWorldAxis().Transpose(); 1017 } 1018 else { 1019 axis2 = cardanAxis; 1020 } 1021 1022 if ( coneLimit ) { 1023 coneLimit->SetBody1Axis( shaft1 ); 1024 } 1025 if ( pyramidLimit ) { 1026 pyramidLimit->SetBody1Axis( shaft1 ); 1027 } 1028 } 1029 1030 /* 1031 ================ 1032 idAFConstraint_UniversalJoint::SetNoLimit 1033 ================ 1034 */ 1035 void idAFConstraint_UniversalJoint::SetNoLimit() { 1036 if ( coneLimit ) { 1037 delete coneLimit; 1038 coneLimit = NULL; 1039 } 1040 if ( pyramidLimit ) { 1041 delete pyramidLimit; 1042 pyramidLimit = NULL; 1043 } 1044 } 1045 1046 /* 1047 ================ 1048 idAFConstraint_UniversalJoint::SetConeLimit 1049 ================ 1050 */ 1051 void idAFConstraint_UniversalJoint::SetConeLimit( const idVec3 &coneAxis, const float coneAngle ) { 1052 if ( pyramidLimit ) { 1053 delete pyramidLimit; 1054 pyramidLimit = NULL; 1055 } 1056 if ( !coneLimit ) { 1057 coneLimit = new (TAG_PHYSICS_AF) idAFConstraint_ConeLimit; 1058 coneLimit->SetPhysics( physics ); 1059 } 1060 if ( body2 ) { 1061 coneLimit->Setup( body1, body2, anchor2, coneAxis * body2->GetWorldAxis().Transpose(), coneAngle, shaft1 ); 1062 } 1063 else { 1064 coneLimit->Setup( body1, body2, anchor2, coneAxis, coneAngle, shaft1 ); 1065 } 1066 } 1067 1068 /* 1069 ================ 1070 idAFConstraint_UniversalJoint::SetPyramidLimit 1071 ================ 1072 */ 1073 void idAFConstraint_UniversalJoint::SetPyramidLimit( const idVec3 &pyramidAxis, const idVec3 &baseAxis, 1074 const float angle1, const float angle2 ) { 1075 if ( coneLimit ) { 1076 delete coneLimit; 1077 coneLimit = NULL; 1078 } 1079 if ( !pyramidLimit ) { 1080 pyramidLimit = new (TAG_PHYSICS_AF) idAFConstraint_PyramidLimit; 1081 pyramidLimit->SetPhysics( physics ); 1082 } 1083 if ( body2 ) { 1084 pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis * body2->GetWorldAxis().Transpose(), 1085 baseAxis * body2->GetWorldAxis().Transpose(), angle1, angle2, shaft1 ); 1086 } 1087 else { 1088 pyramidLimit->Setup( body1, body2, anchor2, pyramidAxis, baseAxis, angle1, angle2, shaft1 ); 1089 } 1090 } 1091 1092 /* 1093 ================ 1094 idAFConstraint_UniversalJoint::SetLimitEpsilon 1095 ================ 1096 */ 1097 void idAFConstraint_UniversalJoint::SetLimitEpsilon( const float e ) { 1098 if ( coneLimit ) { 1099 coneLimit->SetEpsilon( e ); 1100 } 1101 if ( pyramidLimit ) { 1102 pyramidLimit->SetEpsilon( e ); 1103 } 1104 } 1105 1106 /* 1107 ================ 1108 idAFConstraint_UniversalJoint::GetFriction 1109 ================ 1110 */ 1111 float idAFConstraint_UniversalJoint::GetFriction() const { 1112 if ( af_forceFriction.GetFloat() > 0.0f ) { 1113 return af_forceFriction.GetFloat(); 1114 } 1115 return friction * physics->GetJointFrictionScale(); 1116 } 1117 1118 /* 1119 ================ 1120 idAFConstraint_UniversalJoint::Evaluate 1121 1122 NOTE: this joint is homokinetic 1123 ================ 1124 */ 1125 void idAFConstraint_UniversalJoint::Evaluate( float invTimeStep ) { 1126 idVec3 a1, a2, s1, s2, d1, d2, v; 1127 idAFBody *master; 1128 1129 master = body2 ? body2 : physics->GetMasterBody(); 1130 1131 a1 = anchor1 * body1->GetWorldAxis(); 1132 s1 = shaft1 * body1->GetWorldAxis(); 1133 d1 = s1.Cross( axis1 * body1->GetWorldAxis() ); 1134 1135 if ( master ) { 1136 a2 = anchor2 * master->GetWorldAxis(); 1137 s2 = shaft2 * master->GetWorldAxis(); 1138 d2 = axis2 * master->GetWorldAxis(); 1139 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 + master->GetWorldOrigin() - ( a1 + body1->GetWorldOrigin() ) ); 1140 } 1141 else { 1142 a2 = anchor2; 1143 s2 = shaft2; 1144 d2 = axis2; 1145 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 - ( a1 + body1->GetWorldOrigin() ) ); 1146 } 1147 1148 J1.Set( mat3_identity, -SkewSymmetric( a1 ), 1149 mat3_zero, idMat3( s1[0], s1[1], s1[2], 1150 0.0f, 0.0f, 0.0f, 1151 0.0f, 0.0f, 0.0f ) ); 1152 J1.SetSize( 4, 6 ); 1153 1154 if ( body2 ) { 1155 J2.Set( -mat3_identity, SkewSymmetric( a2 ), 1156 mat3_zero, idMat3( s2[0], s2[1], s2[2], 1157 0.0f, 0.0f, 0.0f, 1158 0.0f, 0.0f, 0.0f ) ); 1159 J2.SetSize( 4, 6 ); 1160 } 1161 else { 1162 J2.Zero( 4, 6 ); 1163 } 1164 1165 v = s1.Cross( s2 ); 1166 if ( v.Normalize() != 0.0f ) { 1167 idMat3 m1, m2; 1168 1169 m1[0] = s1; 1170 m1[1] = v; 1171 m1[2] = v.Cross( m1[0] ); 1172 1173 m2[0] = -s2; 1174 m2[1] = v; 1175 m2[2] = v.Cross( m2[0] ); 1176 1177 d2 *= m2.Transpose() * m1; 1178 } 1179 1180 c1[3] = -( invTimeStep * ERROR_REDUCTION ) * ( d1 * d2 ); 1181 1182 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 1183 1184 if ( coneLimit ) { 1185 coneLimit->Add( physics, invTimeStep ); 1186 } 1187 else if ( pyramidLimit ) { 1188 pyramidLimit->Add( physics, invTimeStep ); 1189 } 1190 } 1191 1192 /* 1193 ================ 1194 idAFConstraint_UniversalJoint::ApplyFriction 1195 ================ 1196 */ 1197 void idAFConstraint_UniversalJoint::ApplyFriction( float invTimeStep ) { 1198 idVec3 angular; 1199 float invMass, currentFriction; 1200 1201 currentFriction = GetFriction(); 1202 1203 if ( currentFriction <= 0.0f ) { 1204 return; 1205 } 1206 1207 if ( af_useImpulseFriction.GetBool() || af_useJointImpulseFriction.GetBool() ) { 1208 1209 angular = body1->GetAngularVelocity(); 1210 invMass = body1->GetInverseMass(); 1211 if ( body2 ) { 1212 angular -= body2->GetAngularVelocity(); 1213 invMass += body2->GetInverseMass(); 1214 } 1215 1216 angular *= currentFriction / invMass; 1217 1218 body1->SetAngularVelocity( body1->GetAngularVelocity() - angular * body1->GetInverseMass() ); 1219 if ( body2 ) { 1220 body2->SetAngularVelocity( body2->GetAngularVelocity() + angular * body2->GetInverseMass() ); 1221 } 1222 } 1223 else { 1224 if ( !fc ) { 1225 fc = new (TAG_PHYSICS_AF) idAFConstraint_UniversalJointFriction; 1226 fc->Setup( this ); 1227 } 1228 1229 fc->Add( physics, invTimeStep ); 1230 } 1231 } 1232 1233 /* 1234 ================ 1235 idAFConstraint_UniversalJoint::GetForce 1236 ================ 1237 */ 1238 void idAFConstraint_UniversalJoint::GetForce( idAFBody *body, idVec6 &force ) { 1239 idAFConstraint::GetForce( body, force ); 1240 // FIXME: add limit force 1241 } 1242 1243 /* 1244 ================ 1245 idAFConstraint_UniversalJoint::Translate 1246 ================ 1247 */ 1248 void idAFConstraint_UniversalJoint::Translate( const idVec3 &translation ) { 1249 if ( !body2 ) { 1250 anchor2 += translation; 1251 } 1252 if ( coneLimit ) { 1253 coneLimit->Translate( translation ); 1254 } 1255 else if ( pyramidLimit ) { 1256 pyramidLimit->Translate( translation ); 1257 } 1258 } 1259 1260 /* 1261 ================ 1262 idAFConstraint_UniversalJoint::Rotate 1263 ================ 1264 */ 1265 void idAFConstraint_UniversalJoint::Rotate( const idRotation &rotation ) { 1266 if ( !body2 ) { 1267 anchor2 *= rotation; 1268 shaft2 *= rotation.ToMat3(); 1269 axis2 *= rotation.ToMat3(); 1270 } 1271 if ( coneLimit ) { 1272 coneLimit->Rotate( rotation ); 1273 } 1274 else if ( pyramidLimit ) { 1275 pyramidLimit->Rotate( rotation ); 1276 } 1277 } 1278 1279 /* 1280 ================ 1281 idAFConstraint_UniversalJoint::GetCenter 1282 ================ 1283 */ 1284 void idAFConstraint_UniversalJoint::GetCenter( idVec3 ¢er ) { 1285 center = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 1286 } 1287 1288 /* 1289 ================ 1290 idAFConstraint_UniversalJoint::DebugDraw 1291 ================ 1292 */ 1293 void idAFConstraint_UniversalJoint::DebugDraw() { 1294 idVec3 a1, a2, s1, s2, d1, d2, v; 1295 idAFBody *master; 1296 1297 master = body2 ? body2 : physics->GetMasterBody(); 1298 1299 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 1300 s1 = shaft1 * body1->GetWorldAxis(); 1301 d1 = axis1 * body1->GetWorldAxis(); 1302 1303 if ( master ) { 1304 a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); 1305 s2 = shaft2 * master->GetWorldAxis(); 1306 d2 = axis2 * master->GetWorldAxis(); 1307 } 1308 else { 1309 a2 = anchor2; 1310 s2 = shaft2; 1311 d2 = axis2; 1312 } 1313 1314 v = s1.Cross( s2 ); 1315 if ( v.Normalize() != 0.0f ) { 1316 idMat3 m1, m2; 1317 1318 m1[0] = s1; 1319 m1[1] = v; 1320 m1[2] = v.Cross( m1[0] ); 1321 1322 m2[0] = -s2; 1323 m2[1] = v; 1324 m2[2] = v.Cross( m2[0] ); 1325 1326 d2 *= m2.Transpose() * m1; 1327 } 1328 1329 gameRenderWorld->DebugArrow( colorCyan, a1, a1 + s1 * 5.0f, 1.0f ); 1330 gameRenderWorld->DebugArrow( colorBlue, a2, a2 + s2 * 5.0f, 1.0f ); 1331 gameRenderWorld->DebugLine( colorGreen, a1, a1 + d1 * 5.0f ); 1332 gameRenderWorld->DebugLine( colorGreen, a2, a2 + d2 * 5.0f ); 1333 1334 if ( af_showLimits.GetBool() ) { 1335 if ( coneLimit ) { 1336 coneLimit->DebugDraw(); 1337 } 1338 if ( pyramidLimit ) { 1339 pyramidLimit->DebugDraw(); 1340 } 1341 } 1342 } 1343 1344 /* 1345 ================ 1346 idAFConstraint_UniversalJoint::Save 1347 ================ 1348 */ 1349 void idAFConstraint_UniversalJoint::Save( idSaveGame *saveFile ) const { 1350 idAFConstraint::Save( saveFile ); 1351 saveFile->WriteVec3( anchor1 ); 1352 saveFile->WriteVec3( anchor2 ); 1353 saveFile->WriteVec3( shaft1 ); 1354 saveFile->WriteVec3( shaft2 ); 1355 saveFile->WriteVec3( axis1 ); 1356 saveFile->WriteVec3( axis2 ); 1357 saveFile->WriteFloat( friction ); 1358 if ( coneLimit ) { 1359 coneLimit->Save( saveFile ); 1360 } 1361 if ( pyramidLimit ) { 1362 pyramidLimit->Save( saveFile ); 1363 } 1364 } 1365 1366 /* 1367 ================ 1368 idAFConstraint_UniversalJoint::Restore 1369 ================ 1370 */ 1371 void idAFConstraint_UniversalJoint::Restore( idRestoreGame *saveFile ) { 1372 idAFConstraint::Restore( saveFile ); 1373 saveFile->ReadVec3( anchor1 ); 1374 saveFile->ReadVec3( anchor2 ); 1375 saveFile->ReadVec3( shaft1 ); 1376 saveFile->ReadVec3( shaft2 ); 1377 saveFile->ReadVec3( axis1 ); 1378 saveFile->ReadVec3( axis2 ); 1379 saveFile->ReadFloat( friction ); 1380 if ( coneLimit ) { 1381 coneLimit->Restore( saveFile ); 1382 } 1383 if ( pyramidLimit ) { 1384 pyramidLimit->Restore( saveFile ); 1385 } 1386 } 1387 1388 1389 //=============================================================== 1390 // 1391 // idAFConstraint_UniversalJointFriction 1392 // 1393 //=============================================================== 1394 1395 /* 1396 ================ 1397 idAFConstraint_UniversalJointFriction::idAFConstraint_UniversalJointFriction 1398 ================ 1399 */ 1400 idAFConstraint_UniversalJointFriction::idAFConstraint_UniversalJointFriction() { 1401 type = CONSTRAINT_FRICTION; 1402 name = "universalJointFriction"; 1403 InitSize( 2 ); 1404 joint = NULL; 1405 fl.allowPrimary = false; 1406 fl.frameConstraint = true; 1407 } 1408 1409 /* 1410 ================ 1411 idAFConstraint_UniversalJointFriction::Setup 1412 ================ 1413 */ 1414 void idAFConstraint_UniversalJointFriction::Setup( idAFConstraint_UniversalJoint *uj ) { 1415 this->joint = uj; 1416 body1 = uj->GetBody1(); 1417 body2 = uj->GetBody2(); 1418 } 1419 1420 /* 1421 ================ 1422 idAFConstraint_UniversalJointFriction::Evaluate 1423 ================ 1424 */ 1425 void idAFConstraint_UniversalJointFriction::Evaluate( float invTimeStep ) { 1426 // do nothing 1427 } 1428 1429 /* 1430 ================ 1431 idAFConstraint_UniversalJointFriction::ApplyFriction 1432 ================ 1433 */ 1434 void idAFConstraint_UniversalJointFriction::ApplyFriction( float invTimeStep ) { 1435 // do nothing 1436 } 1437 1438 /* 1439 ================ 1440 idAFConstraint_UniversalJointFriction::Add 1441 ================ 1442 */ 1443 bool idAFConstraint_UniversalJointFriction::Add( idPhysics_AF *phys, float invTimeStep ) { 1444 idVec3 s1, s2, dir1, dir2; 1445 float f; 1446 1447 physics = phys; 1448 1449 f = joint->GetFriction() * joint->GetMultiplier().Length(); 1450 if ( f == 0.0f ) { 1451 return false; 1452 } 1453 1454 lo[0] = lo[1] = -f; 1455 hi[0] = hi[1] = f; 1456 1457 joint->GetShafts( s1, s2 ); 1458 1459 s1 *= body1->GetWorldAxis(); 1460 s1.NormalVectors( dir1, dir2 ); 1461 1462 J1.SetSize( 2, 6 ); 1463 J1.SubVec6(0).SubVec3(0).Zero(); 1464 J1.SubVec6(0).SubVec3(1) = dir1; 1465 J1.SubVec6(1).SubVec3(0).Zero(); 1466 J1.SubVec6(1).SubVec3(1) = dir2; 1467 1468 if ( body2 ) { 1469 1470 J2.SetSize( 2, 6 ); 1471 J2.SubVec6(0).SubVec3(0).Zero(); 1472 J2.SubVec6(0).SubVec3(1) = -dir1; 1473 J2.SubVec6(1).SubVec3(0).Zero(); 1474 J2.SubVec6(1).SubVec3(1) = -dir2; 1475 } 1476 1477 physics->AddFrameConstraint( this ); 1478 1479 return true; 1480 } 1481 1482 /* 1483 ================ 1484 idAFConstraint_UniversalJointFriction::Translate 1485 ================ 1486 */ 1487 void idAFConstraint_UniversalJointFriction::Translate( const idVec3 &translation ) { 1488 } 1489 1490 /* 1491 ================ 1492 idAFConstraint_UniversalJointFriction::Rotate 1493 ================ 1494 */ 1495 void idAFConstraint_UniversalJointFriction::Rotate( const idRotation &rotation ) { 1496 } 1497 1498 1499 //=============================================================== 1500 // 1501 // idAFConstraint_CylindricalJoint 1502 // 1503 //=============================================================== 1504 1505 /* 1506 ================ 1507 idAFConstraint_CylindricalJoint::idAFConstraint_CylindricalJoint 1508 ================ 1509 */ 1510 idAFConstraint_CylindricalJoint::idAFConstraint_CylindricalJoint( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 1511 assert( 0 ); // FIXME: implement 1512 } 1513 1514 /* 1515 ================ 1516 idAFConstraint_CylindricalJoint::Evaluate 1517 ================ 1518 */ 1519 void idAFConstraint_CylindricalJoint::Evaluate( float invTimeStep ) { 1520 assert( 0 ); // FIXME: implement 1521 } 1522 1523 /* 1524 ================ 1525 idAFConstraint_CylindricalJoint::ApplyFriction 1526 ================ 1527 */ 1528 void idAFConstraint_CylindricalJoint::ApplyFriction( float invTimeStep ) { 1529 assert( 0 ); // FIXME: implement 1530 } 1531 1532 /* 1533 ================ 1534 idAFConstraint_CylindricalJoint::Translate 1535 ================ 1536 */ 1537 void idAFConstraint_CylindricalJoint::Translate( const idVec3 &translation ) { 1538 assert( 0 ); // FIXME: implement 1539 } 1540 1541 /* 1542 ================ 1543 idAFConstraint_CylindricalJoint::Rotate 1544 ================ 1545 */ 1546 void idAFConstraint_CylindricalJoint::Rotate( const idRotation &rotation ) { 1547 assert( 0 ); // FIXME: implement 1548 } 1549 1550 /* 1551 ================ 1552 idAFConstraint_CylindricalJoint::DebugDraw 1553 ================ 1554 */ 1555 void idAFConstraint_CylindricalJoint::DebugDraw() { 1556 assert( 0 ); // FIXME: implement 1557 } 1558 1559 1560 //=============================================================== 1561 // 1562 // idAFConstraint_Hinge 1563 // 1564 //=============================================================== 1565 1566 /* 1567 ================ 1568 idAFConstraint_Hinge::idAFConstraint_Hinge 1569 ================ 1570 */ 1571 idAFConstraint_Hinge::idAFConstraint_Hinge( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 1572 assert( body1 ); 1573 type = CONSTRAINT_HINGE; 1574 this->name = name; 1575 this->body1 = body1; 1576 this->body2 = body2; 1577 InitSize( 5 ); 1578 coneLimit = NULL; 1579 steering = NULL; 1580 friction = 0.0f; 1581 fc = NULL; 1582 fl.allowPrimary = true; 1583 fl.noCollision = true; 1584 initialAxis = body1->GetWorldAxis(); 1585 if ( body2 ) { 1586 initialAxis *= body2->GetWorldAxis().Transpose(); 1587 } 1588 } 1589 1590 /* 1591 ================ 1592 idAFConstraint_Hinge::~idAFConstraint_Hinge 1593 ================ 1594 */ 1595 idAFConstraint_Hinge::~idAFConstraint_Hinge() { 1596 if ( coneLimit ) { 1597 delete coneLimit; 1598 } 1599 if ( fc ) { 1600 delete fc; 1601 } 1602 if ( steering ) { 1603 delete steering; 1604 } 1605 } 1606 1607 /* 1608 ================ 1609 idAFConstraint_Hinge::SetAnchor 1610 ================ 1611 */ 1612 void idAFConstraint_Hinge::SetAnchor( const idVec3 &worldPosition ) { 1613 // get anchor relative to center of mass of body1 1614 anchor1 = ( worldPosition - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 1615 if ( body2 ) { 1616 // get anchor relative to center of mass of body2 1617 anchor2 = ( worldPosition - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); 1618 } 1619 else { 1620 anchor2 = worldPosition; 1621 } 1622 1623 if ( coneLimit ) { 1624 coneLimit->SetAnchor( anchor2 ); 1625 } 1626 } 1627 1628 /* 1629 ================ 1630 idAFConstraint_Hinge::GetAnchor 1631 ================ 1632 */ 1633 idVec3 idAFConstraint_Hinge::GetAnchor() const { 1634 if ( body2 ) { 1635 return body2->GetWorldOrigin() + body2->GetWorldAxis() * anchor2; 1636 } 1637 return anchor2; 1638 } 1639 1640 /* 1641 ================ 1642 idAFConstraint_Hinge::SetAxis 1643 ================ 1644 */ 1645 void idAFConstraint_Hinge::SetAxis( const idVec3 &axis ) { 1646 idVec3 normAxis; 1647 1648 normAxis = axis; 1649 normAxis.Normalize(); 1650 1651 // get axis relative to body1 1652 axis1 = normAxis * body1->GetWorldAxis().Transpose(); 1653 if ( body2 ) { 1654 // get axis relative to body2 1655 axis2 = normAxis * body2->GetWorldAxis().Transpose(); 1656 } 1657 else { 1658 axis2 = normAxis; 1659 } 1660 } 1661 1662 /* 1663 ================ 1664 idAFConstraint_Hinge::GetAxis 1665 ================ 1666 */ 1667 idVec3 idAFConstraint_Hinge::GetAxis() const { 1668 if ( body2 ) { 1669 return axis2 * body2->GetWorldAxis(); 1670 } 1671 return axis2; 1672 } 1673 1674 /* 1675 ================ 1676 idAFConstraint_Hinge::SetNoLimit 1677 ================ 1678 */ 1679 void idAFConstraint_Hinge::SetNoLimit() { 1680 if ( coneLimit ) { 1681 delete coneLimit; 1682 coneLimit = NULL; 1683 } 1684 } 1685 1686 /* 1687 ================ 1688 idAFConstraint_Hinge::SetLimit 1689 ================ 1690 */ 1691 void idAFConstraint_Hinge::SetLimit( const idVec3 &axis, const float angle, const idVec3 &body1Axis ) { 1692 if ( !coneLimit ) { 1693 coneLimit = new (TAG_PHYSICS_AF) idAFConstraint_ConeLimit; 1694 coneLimit->SetPhysics( physics ); 1695 } 1696 if ( body2 ) { 1697 coneLimit->Setup( body1, body2, anchor2, axis * body2->GetWorldAxis().Transpose(), angle, body1Axis * body1->GetWorldAxis().Transpose() ); 1698 } 1699 else { 1700 coneLimit->Setup( body1, body2, anchor2, axis, angle, body1Axis * body1->GetWorldAxis().Transpose() ); 1701 } 1702 } 1703 1704 /* 1705 ================ 1706 idAFConstraint_Hinge::SetLimitEpsilon 1707 ================ 1708 */ 1709 void idAFConstraint_Hinge::SetLimitEpsilon( const float e ) { 1710 if ( coneLimit ) { 1711 coneLimit->SetEpsilon( e ); 1712 } 1713 } 1714 1715 /* 1716 ================ 1717 idAFConstraint_Hinge::GetFriction 1718 ================ 1719 */ 1720 float idAFConstraint_Hinge::GetFriction() const { 1721 if ( af_forceFriction.GetFloat() > 0.0f ) { 1722 return af_forceFriction.GetFloat(); 1723 } 1724 return friction * physics->GetJointFrictionScale(); 1725 } 1726 1727 /* 1728 ================ 1729 idAFConstraint_Hinge::GetAngle 1730 ================ 1731 */ 1732 float idAFConstraint_Hinge::GetAngle() const { 1733 idMat3 axis; 1734 idRotation rotation; 1735 float angle; 1736 1737 axis = body1->GetWorldAxis() * body2->GetWorldAxis().Transpose() * initialAxis.Transpose(); 1738 rotation = axis.ToRotation(); 1739 angle = rotation.GetAngle(); 1740 if ( rotation.GetVec() * axis1 < 0.0f ) { 1741 return -angle; 1742 } 1743 return angle; 1744 } 1745 1746 /* 1747 ================ 1748 idAFConstraint_Hinge::SetSteerAngle 1749 ================ 1750 */ 1751 void idAFConstraint_Hinge::SetSteerAngle( const float degrees ) { 1752 if ( coneLimit ) { 1753 delete coneLimit; 1754 coneLimit = NULL; 1755 } 1756 if ( !steering ) { 1757 steering = new (TAG_PHYSICS_AF) idAFConstraint_HingeSteering(); 1758 steering->Setup( this ); 1759 } 1760 steering->SetSteerAngle( degrees ); 1761 } 1762 1763 /* 1764 ================ 1765 idAFConstraint_Hinge::SetSteerSpeed 1766 ================ 1767 */ 1768 void idAFConstraint_Hinge::SetSteerSpeed( const float speed ) { 1769 if ( steering ) { 1770 steering->SetSteerSpeed( speed ); 1771 } 1772 } 1773 1774 /* 1775 ================ 1776 idAFConstraint_Hinge::Evaluate 1777 ================ 1778 */ 1779 void idAFConstraint_Hinge::Evaluate( float invTimeStep ) { 1780 idVec3 a1, a2; 1781 idVec3 x1, x2, cross; 1782 idVec3 vecX, vecY; 1783 idAFBody *master; 1784 1785 master = body2 ? body2 : physics->GetMasterBody(); 1786 1787 x1 = axis1 * body1->GetWorldAxis(); // axis in body1 space 1788 x1.OrthogonalBasis( vecX, vecY ); // basis for axis in body1 space 1789 1790 a1 = anchor1 * body1->GetWorldAxis(); // anchor in body1 space 1791 1792 if ( master ) { 1793 a2 = anchor2 * master->GetWorldAxis(); // anchor in master space 1794 x2 = axis2 * master->GetWorldAxis(); 1795 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 + master->GetWorldOrigin() - ( a1 + body1->GetWorldOrigin() ) ); 1796 } 1797 else { 1798 a2 = anchor2; 1799 x2 = axis2; 1800 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( a2 - ( a1 + body1->GetWorldOrigin() ) ); 1801 } 1802 1803 J1.Set( mat3_identity, -SkewSymmetric( a1 ), 1804 mat3_zero, idMat3( vecX[0], vecX[1], vecX[2], 1805 vecY[0], vecY[1], vecY[2], 1806 0.0f, 0.0f, 0.0f ) ); 1807 J1.SetSize( 5, 6 ); 1808 1809 if ( body2 ) { 1810 J2.Set( -mat3_identity, SkewSymmetric( a2 ), 1811 mat3_zero, idMat3( -vecX[0], -vecX[1], -vecX[2], 1812 -vecY[0], -vecY[1], -vecY[2], 1813 0.0f, 0.0f, 0.0f ) ); 1814 J2.SetSize( 5, 6 ); 1815 } 1816 else { 1817 J2.Zero( 5, 6 ); 1818 } 1819 1820 cross = x1.Cross( x2 ); 1821 1822 c1[3] = -( invTimeStep * ERROR_REDUCTION ) * ( cross * vecX ); 1823 c1[4] = -( invTimeStep * ERROR_REDUCTION ) * ( cross * vecY ); 1824 1825 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 1826 1827 if ( steering ) { 1828 steering->Add( physics, invTimeStep ); 1829 } 1830 else if ( coneLimit ) { 1831 coneLimit->Add( physics, invTimeStep ); 1832 } 1833 } 1834 1835 /* 1836 ================ 1837 idAFConstraint_Hinge::ApplyFriction 1838 ================ 1839 */ 1840 void idAFConstraint_Hinge::ApplyFriction( float invTimeStep ) { 1841 idVec3 angular; 1842 float invMass, currentFriction; 1843 1844 currentFriction = GetFriction(); 1845 1846 if ( currentFriction <= 0.0f ) { 1847 return; 1848 } 1849 1850 if ( af_useImpulseFriction.GetBool() || af_useJointImpulseFriction.GetBool() ) { 1851 1852 angular = body1->GetAngularVelocity(); 1853 invMass = body1->GetInverseMass(); 1854 if ( body2 ) { 1855 angular -= body2->GetAngularVelocity(); 1856 invMass += body2->GetInverseMass(); 1857 } 1858 1859 angular *= currentFriction / invMass; 1860 1861 body1->SetAngularVelocity( body1->GetAngularVelocity() - angular * body1->GetInverseMass() ); 1862 if ( body2 ) { 1863 body2->SetAngularVelocity( body2->GetAngularVelocity() + angular * body2->GetInverseMass() ); 1864 } 1865 } 1866 else { 1867 if ( !fc ) { 1868 fc = new (TAG_PHYSICS_AF) idAFConstraint_HingeFriction; 1869 fc->Setup( this ); 1870 } 1871 1872 fc->Add( physics, invTimeStep ); 1873 } 1874 } 1875 1876 /* 1877 ================ 1878 idAFConstraint_Hinge::GetForce 1879 ================ 1880 */ 1881 void idAFConstraint_Hinge::GetForce( idAFBody *body, idVec6 &force ) { 1882 idAFConstraint::GetForce( body, force ); 1883 // FIXME: add limit force 1884 } 1885 1886 /* 1887 ================ 1888 idAFConstraint_Hinge::Translate 1889 ================ 1890 */ 1891 void idAFConstraint_Hinge::Translate( const idVec3 &translation ) { 1892 if ( !body2 ) { 1893 anchor2 += translation; 1894 } 1895 if ( coneLimit ) { 1896 coneLimit->Translate( translation ); 1897 } 1898 } 1899 1900 /* 1901 ================ 1902 idAFConstraint_Hinge::Rotate 1903 ================ 1904 */ 1905 void idAFConstraint_Hinge::Rotate( const idRotation &rotation ) { 1906 if ( !body2 ) { 1907 anchor2 *= rotation; 1908 axis2 *= rotation.ToMat3(); 1909 } 1910 if ( coneLimit ) { 1911 coneLimit->Rotate( rotation ); 1912 } 1913 } 1914 1915 /* 1916 ================ 1917 idAFConstraint_Hinge::GetCenter 1918 ================ 1919 */ 1920 void idAFConstraint_Hinge::GetCenter( idVec3 ¢er ) { 1921 center = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 1922 } 1923 1924 /* 1925 ================ 1926 idAFConstraint_Hinge::DebugDraw 1927 ================ 1928 */ 1929 void idAFConstraint_Hinge::DebugDraw() { 1930 idVec3 vecX, vecY; 1931 idVec3 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 1932 idVec3 x1 = axis1 * body1->GetWorldAxis(); 1933 x1.OrthogonalBasis( vecX, vecY ); 1934 1935 gameRenderWorld->DebugArrow( colorBlue, a1 - 4.0f * x1, a1 + 4.0f * x1, 1 ); 1936 gameRenderWorld->DebugLine( colorBlue, a1 - 2.0f * vecX, a1 + 2.0f * vecX ); 1937 gameRenderWorld->DebugLine( colorBlue, a1 - 2.0f * vecY, a1 + 2.0f * vecY ); 1938 1939 if ( af_showLimits.GetBool() ) { 1940 if ( coneLimit ) { 1941 coneLimit->DebugDraw(); 1942 } 1943 } 1944 } 1945 1946 /* 1947 ================ 1948 idAFConstraint_Hinge::Save 1949 ================ 1950 */ 1951 void idAFConstraint_Hinge::Save( idSaveGame *saveFile ) const { 1952 idAFConstraint::Save( saveFile ); 1953 saveFile->WriteVec3( anchor1 ); 1954 saveFile->WriteVec3( anchor2 ); 1955 saveFile->WriteVec3( axis1 ); 1956 saveFile->WriteVec3( axis2 ); 1957 saveFile->WriteMat3( initialAxis ); 1958 saveFile->WriteFloat( friction ); 1959 if ( coneLimit ) { 1960 saveFile->WriteBool( true ); 1961 coneLimit->Save( saveFile ); 1962 } else { 1963 saveFile->WriteBool( false ); 1964 } 1965 if ( steering ) { 1966 saveFile->WriteBool( true ); 1967 steering->Save( saveFile ); 1968 } else { 1969 saveFile->WriteBool( false ); 1970 } 1971 if ( fc ) { 1972 saveFile->WriteBool( true ); 1973 fc->Save( saveFile ); 1974 } else { 1975 saveFile->WriteBool( false ); 1976 } 1977 } 1978 1979 /* 1980 ================ 1981 idAFConstraint_Hinge::Restore 1982 ================ 1983 */ 1984 void idAFConstraint_Hinge::Restore( idRestoreGame *saveFile ) { 1985 bool b; 1986 idAFConstraint::Restore( saveFile ); 1987 saveFile->ReadVec3( anchor1 ); 1988 saveFile->ReadVec3( anchor2 ); 1989 saveFile->ReadVec3( axis1 ); 1990 saveFile->ReadVec3( axis2 ); 1991 saveFile->ReadMat3( initialAxis ); 1992 saveFile->ReadFloat( friction ); 1993 1994 saveFile->ReadBool( b ); 1995 if ( b ) { 1996 if ( !coneLimit ) { 1997 coneLimit = new (TAG_PHYSICS_AF) idAFConstraint_ConeLimit; 1998 } 1999 coneLimit->SetPhysics( physics ); 2000 coneLimit->Restore( saveFile ); 2001 } 2002 saveFile->ReadBool( b ); 2003 if ( b ) { 2004 if ( !steering ) { 2005 steering = new (TAG_PHYSICS_AF) idAFConstraint_HingeSteering; 2006 } 2007 steering->Setup( this ); 2008 steering->Restore( saveFile ); 2009 } 2010 saveFile->ReadBool( b ); 2011 if ( b ) { 2012 if ( !fc ) { 2013 fc = new (TAG_PHYSICS_AF) idAFConstraint_HingeFriction; 2014 } 2015 fc->Setup( this ); 2016 fc->Restore( saveFile ); 2017 } 2018 } 2019 2020 2021 //=============================================================== 2022 // 2023 // idAFConstraint_HingeFriction 2024 // 2025 //=============================================================== 2026 2027 /* 2028 ================ 2029 idAFConstraint_HingeFriction::idAFConstraint_HingeFriction 2030 ================ 2031 */ 2032 idAFConstraint_HingeFriction::idAFConstraint_HingeFriction() { 2033 type = CONSTRAINT_FRICTION; 2034 name = "hingeFriction"; 2035 InitSize( 1 ); 2036 hinge = NULL; 2037 fl.allowPrimary = false; 2038 fl.frameConstraint = true; 2039 } 2040 2041 /* 2042 ================ 2043 idAFConstraint_HingeFriction::Setup 2044 ================ 2045 */ 2046 void idAFConstraint_HingeFriction::Setup( idAFConstraint_Hinge *h ) { 2047 this->hinge = h; 2048 body1 = h->GetBody1(); 2049 body2 = h->GetBody2(); 2050 } 2051 2052 /* 2053 ================ 2054 idAFConstraint_HingeFriction::Evaluate 2055 ================ 2056 */ 2057 void idAFConstraint_HingeFriction::Evaluate( float invTimeStep ) { 2058 // do nothing 2059 } 2060 2061 /* 2062 ================ 2063 idAFConstraint_HingeFriction::ApplyFriction 2064 ================ 2065 */ 2066 void idAFConstraint_HingeFriction::ApplyFriction( float invTimeStep ) { 2067 // do nothing 2068 } 2069 2070 /* 2071 ================ 2072 idAFConstraint_HingeFriction::Add 2073 ================ 2074 */ 2075 bool idAFConstraint_HingeFriction::Add( idPhysics_AF *phys, float invTimeStep ) { 2076 idVec3 a1, a2; 2077 float f; 2078 2079 physics = phys; 2080 2081 f = hinge->GetFriction() * hinge->GetMultiplier().Length(); 2082 if ( f == 0.0f ) { 2083 return false; 2084 } 2085 2086 lo[0] = -f; 2087 hi[0] = f; 2088 2089 hinge->GetAxis( a1, a2 ); 2090 2091 a1 *= body1->GetWorldAxis(); 2092 2093 J1.SetSize( 1, 6 ); 2094 J1.SubVec6(0).SubVec3(0).Zero(); 2095 J1.SubVec6(0).SubVec3(1) = a1; 2096 2097 if ( body2 ) { 2098 a2 *= body2->GetWorldAxis(); 2099 2100 J2.SetSize( 1, 6 ); 2101 J2.SubVec6(0).SubVec3(0).Zero(); 2102 J2.SubVec6(0).SubVec3(1) = -a2; 2103 } 2104 2105 physics->AddFrameConstraint( this ); 2106 2107 return true; 2108 } 2109 2110 /* 2111 ================ 2112 idAFConstraint_HingeFriction::Translate 2113 ================ 2114 */ 2115 void idAFConstraint_HingeFriction::Translate( const idVec3 &translation ) { 2116 } 2117 2118 /* 2119 ================ 2120 idAFConstraint_HingeFriction::Rotate 2121 ================ 2122 */ 2123 void idAFConstraint_HingeFriction::Rotate( const idRotation &rotation ) { 2124 } 2125 2126 2127 //=============================================================== 2128 // 2129 // idAFConstraint_HingeSteering 2130 // 2131 //=============================================================== 2132 2133 /* 2134 ================ 2135 idAFConstraint_HingeSteering::idAFConstraint_HingeSteering 2136 ================ 2137 */ 2138 idAFConstraint_HingeSteering::idAFConstraint_HingeSteering() { 2139 type = CONSTRAINT_HINGESTEERING; 2140 name = "hingeFriction"; 2141 InitSize( 1 ); 2142 hinge = NULL; 2143 fl.allowPrimary = false; 2144 fl.frameConstraint = true; 2145 steerSpeed = 0.0f; 2146 epsilon = LCP_EPSILON; 2147 } 2148 2149 /* 2150 ================ 2151 idAFConstraint_HingeSteering::Save 2152 ================ 2153 */ 2154 void idAFConstraint_HingeSteering::Save( idSaveGame *saveFile ) const { 2155 saveFile->WriteFloat(steerAngle); 2156 saveFile->WriteFloat(steerSpeed); 2157 saveFile->WriteFloat(epsilon); 2158 } 2159 2160 /* 2161 ================ 2162 idAFConstraint_HingeSteering::Restore 2163 ================ 2164 */ 2165 void idAFConstraint_HingeSteering::Restore( idRestoreGame *saveFile ) { 2166 saveFile->ReadFloat(steerAngle); 2167 saveFile->ReadFloat(steerSpeed); 2168 saveFile->ReadFloat(epsilon); 2169 } 2170 2171 /* 2172 ================ 2173 idAFConstraint_HingeSteering::Setup 2174 ================ 2175 */ 2176 void idAFConstraint_HingeSteering::Setup( idAFConstraint_Hinge *h ) { 2177 this->hinge = h; 2178 body1 = h->GetBody1(); 2179 body2 = h->GetBody2(); 2180 } 2181 2182 /* 2183 ================ 2184 idAFConstraint_HingeSteering::Evaluate 2185 ================ 2186 */ 2187 void idAFConstraint_HingeSteering::Evaluate( float invTimeStep ) { 2188 // do nothing 2189 } 2190 2191 /* 2192 ================ 2193 idAFConstraint_HingeSteering::ApplyFriction 2194 ================ 2195 */ 2196 void idAFConstraint_HingeSteering::ApplyFriction( float invTimeStep ) { 2197 // do nothing 2198 } 2199 2200 /* 2201 ================ 2202 idAFConstraint_HingeSteering::Add 2203 ================ 2204 */ 2205 bool idAFConstraint_HingeSteering::Add( idPhysics_AF *phys, float invTimeStep ) { 2206 float angle, speed; 2207 idVec3 a1, a2; 2208 2209 physics = phys; 2210 2211 hinge->GetAxis( a1, a2 ); 2212 angle = hinge->GetAngle(); 2213 2214 a1 *= body1->GetWorldAxis(); 2215 2216 J1.SetSize( 1, 6 ); 2217 J1.SubVec6(0).SubVec3(0).Zero(); 2218 J1.SubVec6(0).SubVec3(1) = a1; 2219 2220 if ( body2 ) { 2221 a2 *= body2->GetWorldAxis(); 2222 2223 J2.SetSize( 1, 6 ); 2224 J2.SubVec6(0).SubVec3(0).Zero(); 2225 J2.SubVec6(0).SubVec3(1) = -a2; 2226 } 2227 2228 speed = steerAngle - angle; 2229 if ( steerSpeed != 0.0f ) { 2230 if ( speed > steerSpeed ) { 2231 speed = steerSpeed; 2232 } 2233 else if ( speed < -steerSpeed ) { 2234 speed = -steerSpeed; 2235 } 2236 } 2237 2238 c1[0] = DEG2RAD( speed ) * invTimeStep; 2239 2240 physics->AddFrameConstraint( this ); 2241 2242 return true; 2243 } 2244 2245 /* 2246 ================ 2247 idAFConstraint_HingeSteering::Translate 2248 ================ 2249 */ 2250 void idAFConstraint_HingeSteering::Translate( const idVec3 &translation ) { 2251 } 2252 2253 /* 2254 ================ 2255 idAFConstraint_HingeSteering::Rotate 2256 ================ 2257 */ 2258 void idAFConstraint_HingeSteering::Rotate( const idRotation &rotation ) { 2259 } 2260 2261 2262 //=============================================================== 2263 // 2264 // idAFConstraint_Slider 2265 // 2266 //=============================================================== 2267 2268 /* 2269 ================ 2270 idAFConstraint_Slider::idAFConstraint_Slider 2271 ================ 2272 */ 2273 idAFConstraint_Slider::idAFConstraint_Slider( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 2274 assert( body1 ); 2275 type = CONSTRAINT_SLIDER; 2276 this->name = name; 2277 this->body1 = body1; 2278 this->body2 = body2; 2279 InitSize( 5 ); 2280 fl.allowPrimary = true; 2281 fl.noCollision = true; 2282 2283 if ( body2 ) { 2284 offset = ( body1->GetWorldOrigin() - body2->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 2285 relAxis = body1->GetWorldAxis() * body2->GetWorldAxis().Transpose(); 2286 } 2287 else { 2288 offset = body1->GetWorldOrigin(); 2289 relAxis = body1->GetWorldAxis(); 2290 } 2291 } 2292 2293 /* 2294 ================ 2295 idAFConstraint_Slider::SetAxis 2296 ================ 2297 */ 2298 void idAFConstraint_Slider::SetAxis( const idVec3 &ax ) { 2299 idVec3 normAxis; 2300 2301 // get normalized axis relative to body1 2302 normAxis = ax; 2303 normAxis.Normalize(); 2304 if ( body2 ) { 2305 axis = normAxis * body2->GetWorldAxis().Transpose(); 2306 } 2307 else { 2308 axis = normAxis; 2309 } 2310 } 2311 2312 /* 2313 ================ 2314 idAFConstraint_Slider::Evaluate 2315 ================ 2316 */ 2317 void idAFConstraint_Slider::Evaluate( float invTimeStep ) { 2318 idVec3 vecX, vecY, ofs; 2319 idRotation r; 2320 idAFBody *master; 2321 2322 master = body2 ? body2 : physics->GetMasterBody(); 2323 2324 if ( master ) { 2325 (axis * master->GetWorldAxis()).OrthogonalBasis( vecX, vecY ); 2326 ofs = master->GetWorldOrigin() + master->GetWorldAxis() * offset - body1->GetWorldOrigin(); 2327 r = ( body1->GetWorldAxis().Transpose() * (relAxis * master->GetWorldAxis()) ).ToRotation(); 2328 } 2329 else { 2330 axis.OrthogonalBasis( vecX, vecY ); 2331 ofs = offset - body1->GetWorldOrigin(); 2332 r = ( body1->GetWorldAxis().Transpose() * relAxis ).ToRotation(); 2333 } 2334 2335 J1.Set( mat3_zero, mat3_identity, 2336 idMat3( vecX, vecY, vec3_origin ), mat3_zero ); 2337 J1.SetSize( 5, 6 ); 2338 2339 if ( body2 ) { 2340 2341 J2.Set( mat3_zero, -mat3_identity, 2342 idMat3( -vecX, -vecY, vec3_origin ), mat3_zero ); 2343 J2.SetSize( 5, 6 ); 2344 } 2345 else { 2346 J2.Zero( 5, 6 ); 2347 } 2348 2349 c1.SubVec3(0) = -( invTimeStep * ERROR_REDUCTION ) * ( r.GetVec() * - (float) DEG2RAD( r.GetAngle() ) ); 2350 2351 c1[3] = -( invTimeStep * ERROR_REDUCTION ) * ( vecX * ofs ); 2352 c1[4] = -( invTimeStep * ERROR_REDUCTION ) * ( vecY * ofs ); 2353 2354 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 2355 } 2356 2357 /* 2358 ================ 2359 idAFConstraint_Slider::ApplyFriction 2360 ================ 2361 */ 2362 void idAFConstraint_Slider::ApplyFriction( float invTimeStep ) { 2363 // no friction 2364 } 2365 2366 /* 2367 ================ 2368 idAFConstraint_Slider::Translate 2369 ================ 2370 */ 2371 void idAFConstraint_Slider::Translate( const idVec3 &translation ) { 2372 if ( !body2 ) { 2373 offset += translation; 2374 } 2375 } 2376 2377 /* 2378 ================ 2379 idAFConstraint_Slider::Rotate 2380 ================ 2381 */ 2382 void idAFConstraint_Slider::Rotate( const idRotation &rotation ) { 2383 if ( !body2 ) { 2384 offset *= rotation; 2385 } 2386 } 2387 2388 /* 2389 ================ 2390 idAFConstraint_Slider::GetCenter 2391 ================ 2392 */ 2393 void idAFConstraint_Slider::GetCenter( idVec3 ¢er ) { 2394 idAFBody *master; 2395 2396 master = body2 ? body2 : physics->GetMasterBody(); 2397 if ( master ) { 2398 center = master->GetWorldOrigin() + master->GetWorldAxis() * offset - body1->GetWorldOrigin(); 2399 } 2400 else { 2401 center = offset - body1->GetWorldOrigin(); 2402 } 2403 } 2404 2405 /* 2406 ================ 2407 idAFConstraint_Slider::DebugDraw 2408 ================ 2409 */ 2410 void idAFConstraint_Slider::DebugDraw() { 2411 idVec3 ofs; 2412 idAFBody *master; 2413 2414 master = body2 ? body2 : physics->GetMasterBody(); 2415 if ( master ) { 2416 ofs = master->GetWorldOrigin() + master->GetWorldAxis() * offset - body1->GetWorldOrigin(); 2417 } 2418 else { 2419 ofs = offset - body1->GetWorldOrigin(); 2420 } 2421 gameRenderWorld->DebugLine( colorGreen, ofs, ofs + axis * body1->GetWorldAxis() ); 2422 } 2423 2424 /* 2425 ================ 2426 idAFConstraint_Slider::Save 2427 ================ 2428 */ 2429 void idAFConstraint_Slider::Save( idSaveGame *saveFile ) const { 2430 idAFConstraint::Save( saveFile ); 2431 saveFile->WriteVec3( axis ); 2432 saveFile->WriteVec3( offset ); 2433 saveFile->WriteMat3( relAxis ); 2434 } 2435 2436 /* 2437 ================ 2438 idAFConstraint_Slider::Restore 2439 ================ 2440 */ 2441 void idAFConstraint_Slider::Restore( idRestoreGame *saveFile ) { 2442 idAFConstraint::Restore( saveFile ); 2443 saveFile->ReadVec3( axis ); 2444 saveFile->ReadVec3( offset ); 2445 saveFile->ReadMat3( relAxis ); 2446 } 2447 2448 2449 //=============================================================== 2450 // 2451 // idAFConstraint_Line 2452 // 2453 //=============================================================== 2454 2455 /* 2456 ================ 2457 idAFConstraint_Line::idAFConstraint_Line 2458 ================ 2459 */ 2460 idAFConstraint_Line::idAFConstraint_Line( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 2461 assert( 0 ); // FIXME: implement 2462 } 2463 2464 /* 2465 ================ 2466 idAFConstraint_Line::Evaluate 2467 ================ 2468 */ 2469 void idAFConstraint_Line::Evaluate( float invTimeStep ) { 2470 assert( 0 ); // FIXME: implement 2471 } 2472 2473 /* 2474 ================ 2475 idAFConstraint_Line::ApplyFriction 2476 ================ 2477 */ 2478 void idAFConstraint_Line::ApplyFriction( float invTimeStep ) { 2479 assert( 0 ); // FIXME: implement 2480 } 2481 2482 /* 2483 ================ 2484 idAFConstraint_Line::Translate 2485 ================ 2486 */ 2487 void idAFConstraint_Line::Translate( const idVec3 &translation ) { 2488 assert( 0 ); // FIXME: implement 2489 } 2490 2491 /* 2492 ================ 2493 idAFConstraint_Line::Rotate 2494 ================ 2495 */ 2496 void idAFConstraint_Line::Rotate( const idRotation &rotation ) { 2497 assert( 0 ); // FIXME: implement 2498 } 2499 2500 /* 2501 ================ 2502 idAFConstraint_Line::DebugDraw 2503 ================ 2504 */ 2505 void idAFConstraint_Line::DebugDraw() { 2506 assert( 0 ); // FIXME: implement 2507 } 2508 2509 2510 //=============================================================== 2511 // 2512 // idAFConstraint_Plane 2513 // 2514 //=============================================================== 2515 2516 /* 2517 ================ 2518 idAFConstraint_Plane::idAFConstraint_Plane 2519 ================ 2520 */ 2521 idAFConstraint_Plane::idAFConstraint_Plane( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 2522 assert( body1 ); 2523 type = CONSTRAINT_PLANE; 2524 this->name = name; 2525 this->body1 = body1; 2526 this->body2 = body2; 2527 InitSize( 1 ); 2528 fl.allowPrimary = true; 2529 fl.noCollision = true; 2530 } 2531 2532 /* 2533 ================ 2534 idAFConstraint_Plane::SetPlane 2535 ================ 2536 */ 2537 void idAFConstraint_Plane::SetPlane( const idVec3 &normal, const idVec3 &anchor ) { 2538 // get anchor relative to center of mass of body1 2539 anchor1 = ( anchor - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 2540 if ( body2 ) { 2541 // get anchor relative to center of mass of body2 2542 anchor2 = ( anchor - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); 2543 planeNormal = normal * body2->GetWorldAxis().Transpose(); 2544 } 2545 else { 2546 anchor2 = anchor; 2547 planeNormal = normal; 2548 } 2549 } 2550 2551 /* 2552 ================ 2553 idAFConstraint_Plane::Evaluate 2554 ================ 2555 */ 2556 void idAFConstraint_Plane::Evaluate( float invTimeStep ) { 2557 idVec3 a1, a2, normal, p; 2558 idVec6 v; 2559 idAFBody *master; 2560 2561 master = body2 ? body2 : physics->GetMasterBody(); 2562 2563 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 2564 if ( master ) { 2565 a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); 2566 normal = planeNormal * master->GetWorldAxis(); 2567 } 2568 else { 2569 a2 = anchor2; 2570 normal = planeNormal; 2571 } 2572 2573 p = a1 - body1->GetWorldOrigin(); 2574 v.SubVec3(0) = normal; 2575 v.SubVec3(1) = p.Cross( normal ); 2576 J1.Set( 1, 6, v.ToFloatPtr() ); 2577 2578 if ( body2 ) { 2579 p = a1 - body2->GetWorldOrigin(); 2580 v.SubVec3(0) = -normal; 2581 v.SubVec3(1) = p.Cross( -normal ); 2582 J2.Set( 1, 6, v.ToFloatPtr() ); 2583 } 2584 2585 c1[0] = -( invTimeStep * ERROR_REDUCTION ) * (a1 * normal - a2 * normal); 2586 2587 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 2588 } 2589 2590 /* 2591 ================ 2592 idAFConstraint_Plane::ApplyFriction 2593 ================ 2594 */ 2595 void idAFConstraint_Plane::ApplyFriction( float invTimeStep ) { 2596 // no friction 2597 } 2598 2599 /* 2600 ================ 2601 idAFConstraint_Plane::Translate 2602 ================ 2603 */ 2604 void idAFConstraint_Plane::Translate( const idVec3 &translation ) { 2605 if ( !body2 ) { 2606 anchor2 += translation; 2607 } 2608 } 2609 2610 /* 2611 ================ 2612 idAFConstraint_Plane::Rotate 2613 ================ 2614 */ 2615 void idAFConstraint_Plane::Rotate( const idRotation &rotation ) { 2616 if ( !body2 ) { 2617 anchor2 *= rotation; 2618 planeNormal *= rotation.ToMat3(); 2619 } 2620 } 2621 2622 /* 2623 ================ 2624 idAFConstraint_Plane::DebugDraw 2625 ================ 2626 */ 2627 void idAFConstraint_Plane::DebugDraw() { 2628 idVec3 a1, normal, right, up; 2629 idAFBody *master; 2630 2631 master = body2 ? body2 : physics->GetMasterBody(); 2632 2633 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 2634 if ( master ) { 2635 normal = planeNormal * master->GetWorldAxis(); 2636 } 2637 else { 2638 normal = planeNormal; 2639 } 2640 normal.NormalVectors( right, up ); 2641 normal *= 4.0f; 2642 right *= 4.0f; 2643 up *= 4.0f; 2644 2645 gameRenderWorld->DebugLine( colorCyan, a1 - right, a1 + right ); 2646 gameRenderWorld->DebugLine( colorCyan, a1 - up, a1 + up ); 2647 gameRenderWorld->DebugArrow( colorCyan, a1, a1 + normal, 1 ); 2648 } 2649 2650 /* 2651 ================ 2652 idAFConstraint_Plane::Save 2653 ================ 2654 */ 2655 void idAFConstraint_Plane::Save( idSaveGame *saveFile ) const { 2656 idAFConstraint::Save( saveFile ); 2657 saveFile->WriteVec3( anchor1 ); 2658 saveFile->WriteVec3( anchor2 ); 2659 saveFile->WriteVec3( planeNormal ); 2660 } 2661 2662 /* 2663 ================ 2664 idAFConstraint_Plane::Restore 2665 ================ 2666 */ 2667 void idAFConstraint_Plane::Restore( idRestoreGame *saveFile ) { 2668 idAFConstraint::Restore( saveFile ); 2669 saveFile->ReadVec3( anchor1 ); 2670 saveFile->ReadVec3( anchor2 ); 2671 saveFile->ReadVec3( planeNormal ); 2672 } 2673 2674 2675 //=============================================================== 2676 // 2677 // idAFConstraint_Spring 2678 // 2679 //=============================================================== 2680 2681 /* 2682 ================ 2683 idAFConstraint_Spring::idAFConstraint_Spring 2684 ================ 2685 */ 2686 idAFConstraint_Spring::idAFConstraint_Spring( const idStr &name, idAFBody *body1, idAFBody *body2 ) { 2687 assert( body1 ); 2688 type = CONSTRAINT_SPRING; 2689 this->name = name; 2690 this->body1 = body1; 2691 this->body2 = body2; 2692 InitSize( 1 ); 2693 fl.allowPrimary = false; 2694 kstretch = kcompress = damping = 1.0f; 2695 minLength = maxLength = restLength = 0.0f; 2696 } 2697 2698 /* 2699 ================ 2700 idAFConstraint_Spring::SetAnchor 2701 ================ 2702 */ 2703 void idAFConstraint_Spring::SetAnchor( const idVec3 &worldAnchor1, const idVec3 &worldAnchor2 ) { 2704 // get anchor relative to center of mass of body1 2705 anchor1 = ( worldAnchor1 - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 2706 if ( body2 ) { 2707 // get anchor relative to center of mass of body2 2708 anchor2 = ( worldAnchor2 - body2->GetWorldOrigin() ) * body2->GetWorldAxis().Transpose(); 2709 } 2710 else { 2711 anchor2 = worldAnchor2; 2712 } 2713 } 2714 2715 /* 2716 ================ 2717 idAFConstraint_Spring::SetSpring 2718 ================ 2719 */ 2720 void idAFConstraint_Spring::SetSpring( const float stretch, const float compress, const float damping, const float restLength ) { 2721 assert( stretch >= 0.0f && compress >= 0.0f && restLength >= 0.0f ); 2722 this->kstretch = stretch; 2723 this->kcompress = compress; 2724 this->damping = damping; 2725 this->restLength = restLength; 2726 } 2727 2728 /* 2729 ================ 2730 idAFConstraint_Spring::SetLimit 2731 ================ 2732 */ 2733 void idAFConstraint_Spring::SetLimit( const float minLength, const float maxLength ) { 2734 assert( minLength >= 0.0f && maxLength >= 0.0f && maxLength >= minLength ); 2735 this->minLength = minLength; 2736 this->maxLength = maxLength; 2737 } 2738 2739 /* 2740 ================ 2741 idAFConstraint_Spring::Evaluate 2742 ================ 2743 */ 2744 void idAFConstraint_Spring::Evaluate( float invTimeStep ) { 2745 idVec3 a1, a2, velocity1, velocity2, force; 2746 idVec6 v1, v2; 2747 float d, dampingForce, length, error; 2748 bool limit; 2749 idAFBody *master; 2750 2751 master = body2 ? body2 : physics->GetMasterBody(); 2752 2753 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 2754 velocity1 = body1->GetPointVelocity( a1 ); 2755 2756 if ( master ) { 2757 a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); 2758 velocity2 = master->GetPointVelocity( a2 ); 2759 } 2760 else { 2761 a2 = anchor2; 2762 velocity2.Zero(); 2763 } 2764 2765 force = a2 - a1; 2766 d = force * force; 2767 if ( d != 0.0f ) { 2768 dampingForce = damping * idMath::Fabs( (velocity2 - velocity1) * force ) / d; 2769 } 2770 else { 2771 dampingForce = 0.0f; 2772 } 2773 length = force.Normalize(); 2774 2775 if ( length > restLength ) { 2776 if ( kstretch > 0.0f ) { 2777 idVec3 springForce = force * ( Square( length - restLength ) * kstretch - dampingForce ); 2778 body1->AddForce( a1, springForce ); 2779 if ( master ) { 2780 master->AddForce( a2, -springForce ); 2781 } 2782 } 2783 } 2784 else { 2785 if ( kcompress > 0.0f ) { 2786 idVec3 springForce = force * -( Square( restLength - length ) * kcompress - dampingForce ); 2787 body1->AddForce( a1, springForce ); 2788 if ( master ) { 2789 master->AddForce( a2, -springForce ); 2790 } 2791 } 2792 } 2793 2794 // check for spring limits 2795 if ( length < minLength ) { 2796 force = -force; 2797 error = minLength - length; 2798 limit = true; 2799 } 2800 else if ( maxLength > 0.0f && length > maxLength ) { 2801 error = length - maxLength; 2802 limit = true; 2803 } 2804 else { 2805 error = 0.0f; 2806 limit = false; 2807 } 2808 2809 if ( limit ) { 2810 a1 -= body1->GetWorldOrigin(); 2811 v1.SubVec3(0) = force; 2812 v1.SubVec3(1) = a1.Cross( force ); 2813 J1.Set( 1, 6, v1.ToFloatPtr() ); 2814 if ( body2 ) { 2815 a2 -= body2->GetWorldOrigin(); 2816 v2.SubVec3(0) = -force; 2817 v2.SubVec3(1) = a2.Cross( -force ); 2818 J2.Set( 1, 6, v2.ToFloatPtr() ); 2819 } 2820 c1[0] = -( invTimeStep * ERROR_REDUCTION ) * error; 2821 lo[0] = 0.0f; 2822 } 2823 else { 2824 J1.Zero( 0, 0 ); 2825 J2.Zero( 0, 0 ); 2826 } 2827 2828 c1.Clamp( -ERROR_REDUCTION_MAX, ERROR_REDUCTION_MAX ); 2829 } 2830 2831 /* 2832 ================ 2833 idAFConstraint_Spring::ApplyFriction 2834 ================ 2835 */ 2836 void idAFConstraint_Spring::ApplyFriction( float invTimeStep ) { 2837 // no friction 2838 } 2839 2840 /* 2841 ================ 2842 idAFConstraint_Spring::Translate 2843 ================ 2844 */ 2845 void idAFConstraint_Spring::Translate( const idVec3 &translation ) { 2846 if ( !body2 ) { 2847 anchor2 += translation; 2848 } 2849 } 2850 2851 /* 2852 ================ 2853 idAFConstraint_Spring::Rotate 2854 ================ 2855 */ 2856 void idAFConstraint_Spring::Rotate( const idRotation &rotation ) { 2857 if ( !body2 ) { 2858 anchor2 *= rotation; 2859 } 2860 } 2861 2862 /* 2863 ================ 2864 idAFConstraint_Spring::GetCenter 2865 ================ 2866 */ 2867 void idAFConstraint_Spring::GetCenter( idVec3 ¢er ) { 2868 idAFBody *master; 2869 idVec3 a1, a2; 2870 2871 master = body2 ? body2 : physics->GetMasterBody(); 2872 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 2873 if ( master ) { 2874 a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); 2875 } 2876 else { 2877 a2 = anchor2; 2878 } 2879 center = ( a1 + a2 ) * 0.5f; 2880 } 2881 2882 /* 2883 ================ 2884 idAFConstraint_Spring::DebugDraw 2885 ================ 2886 */ 2887 void idAFConstraint_Spring::DebugDraw() { 2888 idAFBody *master; 2889 float length; 2890 idVec3 a1, a2, dir, mid, p; 2891 2892 master = body2 ? body2 : physics->GetMasterBody(); 2893 a1 = body1->GetWorldOrigin() + anchor1 * body1->GetWorldAxis(); 2894 if ( master ) { 2895 a2 = master->GetWorldOrigin() + anchor2 * master->GetWorldAxis(); 2896 } 2897 else { 2898 a2 = anchor2; 2899 } 2900 dir = a2 - a1; 2901 mid = a1 + 0.5f * dir; 2902 length = dir.Normalize(); 2903 2904 // draw spring 2905 gameRenderWorld->DebugLine( colorGreen, a1, a2 ); 2906 2907 // draw rest length 2908 p = restLength * 0.5f * dir; 2909 gameRenderWorld->DebugCircle( colorWhite, mid + p, dir, 1.0f, 10 ); 2910 gameRenderWorld->DebugCircle( colorWhite, mid - p, dir, 1.0f, 10 ); 2911 if ( restLength > length ) { 2912 gameRenderWorld->DebugLine( colorWhite, a2, mid + p ); 2913 gameRenderWorld->DebugLine( colorWhite, a1, mid - p ); 2914 } 2915 2916 if ( minLength > 0.0f ) { 2917 // draw min length 2918 gameRenderWorld->DebugCircle( colorBlue, mid + minLength * 0.5f * dir, dir, 2.0f, 10 ); 2919 gameRenderWorld->DebugCircle( colorBlue, mid - minLength * 0.5f * dir, dir, 2.0f, 10 ); 2920 } 2921 2922 if ( maxLength > 0.0f ) { 2923 // draw max length 2924 gameRenderWorld->DebugCircle( colorRed, mid + maxLength * 0.5f * dir, dir, 2.0f, 10 ); 2925 gameRenderWorld->DebugCircle( colorRed, mid - maxLength * 0.5f * dir, dir, 2.0f, 10 ); 2926 } 2927 } 2928 2929 /* 2930 ================ 2931 idAFConstraint_Spring::Save 2932 ================ 2933 */ 2934 void idAFConstraint_Spring::Save( idSaveGame *saveFile ) const { 2935 idAFConstraint::Save( saveFile ); 2936 saveFile->WriteVec3( anchor1 ); 2937 saveFile->WriteVec3( anchor2 ); 2938 saveFile->WriteFloat( kstretch ); 2939 saveFile->WriteFloat( kcompress ); 2940 saveFile->WriteFloat( damping ); 2941 saveFile->WriteFloat( restLength ); 2942 saveFile->WriteFloat( minLength ); 2943 saveFile->WriteFloat( maxLength ); 2944 } 2945 2946 /* 2947 ================ 2948 idAFConstraint_Spring::Restore 2949 ================ 2950 */ 2951 void idAFConstraint_Spring::Restore( idRestoreGame *saveFile ) { 2952 idAFConstraint::Restore( saveFile ); 2953 saveFile->ReadVec3( anchor1 ); 2954 saveFile->ReadVec3( anchor2 ); 2955 saveFile->ReadFloat( kstretch ); 2956 saveFile->ReadFloat( kcompress ); 2957 saveFile->ReadFloat( damping ); 2958 saveFile->ReadFloat( restLength ); 2959 saveFile->ReadFloat( minLength ); 2960 saveFile->ReadFloat( maxLength ); 2961 } 2962 2963 2964 //=============================================================== 2965 // 2966 // idAFConstraint_Contact 2967 // 2968 //=============================================================== 2969 2970 /* 2971 ================ 2972 idAFConstraint_Contact::idAFConstraint_Contact 2973 ================ 2974 */ 2975 idAFConstraint_Contact::idAFConstraint_Contact() { 2976 name = "contact"; 2977 type = CONSTRAINT_CONTACT; 2978 InitSize( 1 ); 2979 fc = NULL; 2980 fl.allowPrimary = false; 2981 fl.frameConstraint = true; 2982 } 2983 2984 /* 2985 ================ 2986 idAFConstraint_Contact::~idAFConstraint_Contact 2987 ================ 2988 */ 2989 idAFConstraint_Contact::~idAFConstraint_Contact() { 2990 if ( fc ) { 2991 delete fc; 2992 } 2993 } 2994 2995 /* 2996 ================ 2997 idAFConstraint_Contact::Setup 2998 ================ 2999 */ 3000 void idAFConstraint_Contact::Setup( idAFBody *b1, idAFBody *b2, contactInfo_t &c ) { 3001 idVec3 p; 3002 idVec6 v; 3003 float vel; 3004 float minBounceVelocity = 2.0f; 3005 3006 assert( b1 ); 3007 3008 body1 = b1; 3009 body2 = b2; 3010 contact = c; 3011 3012 p = c.point - body1->GetWorldOrigin(); 3013 v.SubVec3(0) = c.normal; 3014 v.SubVec3(1) = p.Cross( c.normal ); 3015 J1.Set( 1, 6, v.ToFloatPtr() ); 3016 vel = v.SubVec3(0) * body1->GetLinearVelocity() + v.SubVec3(1) * body1->GetAngularVelocity(); 3017 3018 if ( body2 ) { 3019 p = c.point - body2->GetWorldOrigin(); 3020 v.SubVec3(0) = -c.normal; 3021 v.SubVec3(1) = p.Cross( -c.normal ); 3022 J2.Set( 1, 6, v.ToFloatPtr() ); 3023 vel += v.SubVec3(0) * body2->GetLinearVelocity() + v.SubVec3(1) * body2->GetAngularVelocity(); 3024 c2[0] = 0.0f; 3025 } 3026 3027 if ( body1->GetBouncyness() > 0.0f && -vel > minBounceVelocity ) { 3028 c1[0] = body1->GetBouncyness() * vel; 3029 } 3030 else { 3031 c1[0] = 0.0f; 3032 } 3033 3034 e[0] = CONTACT_LCP_EPSILON; 3035 lo[0] = 0.0f; 3036 hi[0] = idMath::INFINITY; 3037 boxConstraint = NULL; 3038 boxIndex[0] = -1; 3039 } 3040 3041 /* 3042 ================ 3043 idAFConstraint_Contact::Evaluate 3044 ================ 3045 */ 3046 void idAFConstraint_Contact::Evaluate( float invTimeStep ) { 3047 // do nothing 3048 } 3049 3050 /* 3051 ================ 3052 idAFConstraint_Contact::ApplyFriction 3053 ================ 3054 */ 3055 void idAFConstraint_Contact::ApplyFriction( float invTimeStep ) { 3056 idVec3 r, velocity, normal, dir1, dir2; 3057 float friction, magnitude, forceNumerator, forceDenominator; 3058 idVecX impulse, dv; 3059 3060 if ( !body1 ) { 3061 return; 3062 } 3063 friction = body1->GetContactFriction(); 3064 if ( body2 && body2->GetContactFriction() < friction ) { 3065 friction = body2->GetContactFriction(); 3066 } 3067 3068 friction *= physics->GetContactFrictionScale(); 3069 3070 if ( friction <= 0.0f ) { 3071 return; 3072 } 3073 3074 // seperate friction per contact is silly but it's fast and often looks close enough 3075 if ( af_useImpulseFriction.GetBool() ) { 3076 3077 impulse.SetData( 6, VECX_ALLOCA( 6 ) ); 3078 dv.SetData( 6, VECX_ALLOCA( 6 ) ); 3079 3080 // calculate velocity in the contact plane 3081 r = contact.point - body1->GetWorldOrigin(); 3082 velocity = body1->GetLinearVelocity() + body1->GetAngularVelocity().Cross( r ); 3083 velocity -= contact.normal * velocity * contact.normal; 3084 3085 // get normalized direction of friction and magnitude of velocity 3086 normal = -velocity; 3087 magnitude = normal.Normalize(); 3088 3089 forceNumerator = friction * magnitude; 3090 forceDenominator = body1->GetInverseMass() + ( ( body1->GetInverseWorldInertia() * r.Cross( normal ) ).Cross( r ) * normal ); 3091 impulse.SubVec3(0) = (forceNumerator / forceDenominator) * normal; 3092 impulse.SubVec3(1) = r.Cross( impulse.SubVec3(0) ); 3093 body1->InverseWorldSpatialInertiaMultiply( dv, impulse.ToFloatPtr() ); 3094 3095 // modify velocity with friction force 3096 body1->SetLinearVelocity( body1->GetLinearVelocity() + dv.SubVec3(0) ); 3097 body1->SetAngularVelocity( body1->GetAngularVelocity() + dv.SubVec3(1) ); 3098 } 3099 else { 3100 3101 if ( !fc ) { 3102 fc = new (TAG_PHYSICS_AF) idAFConstraint_ContactFriction; 3103 } 3104 // call setup each frame because contact constraints are re-used for different bodies 3105 fc->Setup( this ); 3106 fc->Add( physics, invTimeStep ); 3107 } 3108 } 3109 3110 /* 3111 ================ 3112 idAFConstraint_Contact::Translate 3113 ================ 3114 */ 3115 void idAFConstraint_Contact::Translate( const idVec3 &translation ) { 3116 assert( 0 ); // contact should never be translated 3117 } 3118 3119 /* 3120 ================ 3121 idAFConstraint_Contact::Rotate 3122 ================ 3123 */ 3124 void idAFConstraint_Contact::Rotate( const idRotation &rotation ) { 3125 assert( 0 ); // contact should never be rotated 3126 } 3127 3128 /* 3129 ================ 3130 idAFConstraint_Contact::GetCenter 3131 ================ 3132 */ 3133 void idAFConstraint_Contact::GetCenter( idVec3 ¢er ) { 3134 center = contact.point; 3135 } 3136 3137 /* 3138 ================ 3139 idAFConstraint_Contact::DebugDraw 3140 ================ 3141 */ 3142 void idAFConstraint_Contact::DebugDraw() { 3143 idVec3 x, y; 3144 contact.normal.NormalVectors( x, y ); 3145 gameRenderWorld->DebugLine( colorWhite, contact.point, contact.point + 6.0f * contact.normal ); 3146 gameRenderWorld->DebugLine( colorWhite, contact.point - 2.0f * x, contact.point + 2.0f * x ); 3147 gameRenderWorld->DebugLine( colorWhite, contact.point - 2.0f * y, contact.point + 2.0f * y ); 3148 } 3149 3150 3151 //=============================================================== 3152 // 3153 // idAFConstraint_ContactFriction 3154 // 3155 //=============================================================== 3156 3157 /* 3158 ================ 3159 idAFConstraint_ContactFriction::idAFConstraint_ContactFriction 3160 ================ 3161 */ 3162 idAFConstraint_ContactFriction::idAFConstraint_ContactFriction() { 3163 type = CONSTRAINT_FRICTION; 3164 name = "contactFriction"; 3165 InitSize( 2 ); 3166 cc = NULL; 3167 fl.allowPrimary = false; 3168 fl.frameConstraint = true; 3169 } 3170 3171 /* 3172 ================ 3173 idAFConstraint_ContactFriction::Setup 3174 ================ 3175 */ 3176 void idAFConstraint_ContactFriction::Setup( idAFConstraint_Contact *cc ) { 3177 this->cc = cc; 3178 body1 = cc->GetBody1(); 3179 body2 = cc->GetBody2(); 3180 } 3181 3182 /* 3183 ================ 3184 idAFConstraint_ContactFriction::Evaluate 3185 ================ 3186 */ 3187 void idAFConstraint_ContactFriction::Evaluate( float invTimeStep ) { 3188 // do nothing 3189 } 3190 3191 /* 3192 ================ 3193 idAFConstraint_ContactFriction::ApplyFriction 3194 ================ 3195 */ 3196 void idAFConstraint_ContactFriction::ApplyFriction( float invTimeStep ) { 3197 // do nothing 3198 } 3199 3200 /* 3201 ================ 3202 idAFConstraint_ContactFriction::Add 3203 ================ 3204 */ 3205 bool idAFConstraint_ContactFriction::Add( idPhysics_AF *phys, float invTimeStep ) { 3206 idVec3 r, dir1, dir2; 3207 float friction; 3208 int newRow; 3209 3210 physics = phys; 3211 3212 friction = body1->GetContactFriction() * physics->GetContactFrictionScale(); 3213 3214 // if the body only has friction in one direction 3215 if ( body1->GetFrictionDirection( dir1 ) ) { 3216 // project the friction direction into the contact plane 3217 dir1 -= dir1 * cc->GetContact().normal * dir1; 3218 dir1.Normalize(); 3219 3220 r = cc->GetContact().point - body1->GetWorldOrigin(); 3221 3222 J1.SetSize( 1, 6 ); 3223 J1.SubVec6(0).SubVec3(0) = dir1; 3224 J1.SubVec6(0).SubVec3(1) = r.Cross( dir1 ); 3225 c1.SetSize( 1 ); 3226 c1[0] = 0.0f; 3227 3228 if ( body2 ) { 3229 r = cc->GetContact().point - body2->GetWorldOrigin(); 3230 3231 J2.SetSize( 1, 6 ); 3232 J2.SubVec6(0).SubVec3(0) = -dir1; 3233 J2.SubVec6(0).SubVec3(1) = r.Cross( -dir1 ); 3234 c2.SetSize( 1 ); 3235 c2[0] = 0.0f; 3236 } 3237 3238 lo[0] = -friction; 3239 hi[0] = friction; 3240 boxConstraint = cc; 3241 boxIndex[0] = 0; 3242 } 3243 else { 3244 // get two friction directions orthogonal to contact normal 3245 cc->GetContact().normal.NormalVectors( dir1, dir2 ); 3246 3247 r = cc->GetContact().point - body1->GetWorldOrigin(); 3248 3249 J1.SetSize( 2, 6 ); 3250 J1.SubVec6(0).SubVec3(0) = dir1; 3251 J1.SubVec6(0).SubVec3(1) = r.Cross( dir1 ); 3252 J1.SubVec6(1).SubVec3(0) = dir2; 3253 J1.SubVec6(1).SubVec3(1) = r.Cross( dir2 ); 3254 c1.SetSize( 2 ); 3255 c1[0] = c1[1] = 0.0f; 3256 3257 if ( body2 ) { 3258 r = cc->GetContact().point - body2->GetWorldOrigin(); 3259 3260 J2.SetSize( 2, 6 ); 3261 J2.SubVec6(0).SubVec3(0) = -dir1; 3262 J2.SubVec6(0).SubVec3(1) = r.Cross( -dir1 ); 3263 J2.SubVec6(1).SubVec3(0) = -dir2; 3264 J2.SubVec6(1).SubVec3(1) = r.Cross( -dir2 ); 3265 c2.SetSize( 2 ); 3266 c2[0] = c2[1] = 0.0f; 3267 3268 if ( body2->GetContactFriction() < friction ) { 3269 friction = body2->GetContactFriction(); 3270 } 3271 } 3272 3273 lo[0] = -friction; 3274 hi[0] = friction; 3275 boxConstraint = cc; 3276 boxIndex[0] = 0; 3277 lo[1] = -friction; 3278 hi[1] = friction; 3279 boxIndex[1] = 0; 3280 } 3281 3282 if ( body1->GetContactMotorDirection( dir1 ) && body1->GetContactMotorForce() > 0.0f ) { 3283 // project the motor force direction into the contact plane 3284 dir1 -= dir1 * cc->GetContact().normal * dir1; 3285 dir1.Normalize(); 3286 3287 r = cc->GetContact().point - body1->GetWorldOrigin(); 3288 3289 newRow = J1.GetNumRows(); 3290 J1.ChangeSize( newRow+1, J1.GetNumColumns() ); 3291 J1.SubVec6(newRow).SubVec3(0) = -dir1; 3292 J1.SubVec6(newRow).SubVec3(1) = r.Cross( -dir1 ); 3293 c1.ChangeSize( newRow+1 ); 3294 c1[newRow] = body1->GetContactMotorVelocity(); 3295 3296 if ( body2 ) { 3297 r = cc->GetContact().point - body2->GetWorldOrigin(); 3298 3299 J2.ChangeSize( newRow+1, J2.GetNumColumns() ); 3300 J2.SubVec6(newRow).SubVec3(0) = -dir1; 3301 J2.SubVec6(newRow).SubVec3(1) = r.Cross( -dir1 ); 3302 c2.ChangeSize( newRow+1 ); 3303 c2[newRow] = 0.0f; 3304 } 3305 3306 lo[newRow] = -body1->GetContactMotorForce(); 3307 hi[newRow] = body1->GetContactMotorForce(); 3308 boxIndex[newRow] = -1; 3309 } 3310 3311 physics->AddFrameConstraint( this ); 3312 3313 return true; 3314 } 3315 3316 /* 3317 ================ 3318 idAFConstraint_ContactFriction::Translate 3319 ================ 3320 */ 3321 void idAFConstraint_ContactFriction::Translate( const idVec3 &translation ) { 3322 } 3323 3324 /* 3325 ================ 3326 idAFConstraint_ContactFriction::Rotate 3327 ================ 3328 */ 3329 void idAFConstraint_ContactFriction::Rotate( const idRotation &rotation ) { 3330 } 3331 3332 /* 3333 ================ 3334 idAFConstraint_ContactFriction::DebugDraw 3335 ================ 3336 */ 3337 void idAFConstraint_ContactFriction::DebugDraw() { 3338 } 3339 3340 3341 //=============================================================== 3342 // 3343 // idAFConstraint_ConeLimit 3344 // 3345 //=============================================================== 3346 3347 /* 3348 ================ 3349 idAFConstraint_ConeLimit::idAFConstraint_ConeLimit 3350 ================ 3351 */ 3352 idAFConstraint_ConeLimit::idAFConstraint_ConeLimit() { 3353 type = CONSTRAINT_CONELIMIT; 3354 name = "coneLimit"; 3355 InitSize( 1 ); 3356 fl.allowPrimary = false; 3357 fl.frameConstraint = true; 3358 } 3359 3360 /* 3361 ================ 3362 idAFConstraint_ConeLimit::Setup 3363 3364 the coneAnchor is the top of the cone in body2 space 3365 the coneAxis is the axis of the cone in body2 space 3366 the coneAngle is the angle the cone hull makes at the top 3367 the body1Axis is the axis in body1 space that should stay within the cone 3368 ================ 3369 */ 3370 void idAFConstraint_ConeLimit::Setup( idAFBody *b1, idAFBody *b2, const idVec3 &coneAnchor, const idVec3 &coneAxis, const float coneAngle, const idVec3 &body1Axis ) { 3371 this->body1 = b1; 3372 this->body2 = b2; 3373 this->coneAxis = coneAxis; 3374 this->coneAxis.Normalize(); 3375 this->coneAnchor = coneAnchor; 3376 this->body1Axis = body1Axis; 3377 this->body1Axis.Normalize(); 3378 this->cosAngle = (float) cos( DEG2RAD( coneAngle * 0.5f ) ); 3379 this->sinHalfAngle = (float) sin( DEG2RAD( coneAngle * 0.25f ) ); 3380 this->cosHalfAngle = (float) cos( DEG2RAD( coneAngle * 0.25f ) ); 3381 } 3382 3383 /* 3384 ================ 3385 idAFConstraint_ConeLimit::SetAnchor 3386 ================ 3387 */ 3388 void idAFConstraint_ConeLimit::SetAnchor( const idVec3 &coneAnchor ) { 3389 this->coneAnchor = coneAnchor; 3390 } 3391 3392 /* 3393 ================ 3394 idAFConstraint_ConeLimit::SetBody1Axis 3395 ================ 3396 */ 3397 void idAFConstraint_ConeLimit::SetBody1Axis( const idVec3 &body1Axis ) { 3398 this->body1Axis = body1Axis; 3399 } 3400 3401 /* 3402 ================ 3403 idAFConstraint_ConeLimit::Evaluate 3404 ================ 3405 */ 3406 void idAFConstraint_ConeLimit::Evaluate( float invTimeStep ) { 3407 // do nothing 3408 } 3409 3410 /* 3411 ================ 3412 idAFConstraint_ConeLimit::ApplyFriction 3413 ================ 3414 */ 3415 void idAFConstraint_ConeLimit::ApplyFriction( float invTimeStep ) { 3416 } 3417 3418 /* 3419 ================ 3420 idAFConstraint_ConeLimit::Add 3421 ================ 3422 */ 3423 bool idAFConstraint_ConeLimit::Add( idPhysics_AF *phys, float invTimeStep ) { 3424 float a; 3425 idVec6 J1row, J2row; 3426 idVec3 ax, anchor, body1ax, normal, coneVector, p1, p2; 3427 idQuat q; 3428 idAFBody *master; 3429 3430 if ( af_skipLimits.GetBool() ) { 3431 lm.Zero(); // constraint exerts no force 3432 return false; 3433 } 3434 3435 physics = phys; 3436 3437 master = body2 ? body2 : physics->GetMasterBody(); 3438 3439 if ( master ) { 3440 ax = coneAxis * master->GetWorldAxis(); 3441 anchor = master->GetWorldOrigin() + coneAnchor * master->GetWorldAxis(); 3442 } 3443 else { 3444 ax = coneAxis; 3445 anchor = coneAnchor; 3446 } 3447 3448 body1ax = body1Axis * body1->GetWorldAxis(); 3449 3450 a = ax * body1ax; 3451 3452 // if the body1 axis is inside the cone 3453 if ( a > cosAngle ) { 3454 lm.Zero(); // constraint exerts no force 3455 return false; 3456 } 3457 3458 // calculate the inward cone normal for the position the body1 axis went outside the cone 3459 normal = body1ax.Cross( ax ); 3460 normal.Normalize(); 3461 q.x = normal.x * sinHalfAngle; 3462 q.y = normal.y * sinHalfAngle; 3463 q.z = normal.z * sinHalfAngle; 3464 q.w = cosHalfAngle; 3465 coneVector = ax * q.ToMat3(); 3466 normal = coneVector.Cross( ax ).Cross( coneVector ); 3467 normal.Normalize(); 3468 3469 p1 = anchor + 32.0f * coneVector - body1->GetWorldOrigin(); 3470 3471 J1row.SubVec3(0) = normal; 3472 J1row.SubVec3(1) = p1.Cross( normal ); 3473 J1.Set( 1, 6, J1row.ToFloatPtr() ); 3474 3475 c1[0] = (invTimeStep * LIMIT_ERROR_REDUCTION) * ( normal * (32.0f * body1ax) ); 3476 3477 if ( body2 ) { 3478 3479 p2 = anchor + 32.0f * coneVector - master->GetWorldOrigin(); 3480 3481 J2row.SubVec3(0) = -normal; 3482 J2row.SubVec3(1) = p2.Cross( -normal ); 3483 J2.Set( 1, 6, J2row.ToFloatPtr() ); 3484 3485 c2[0] = 0.0f; 3486 } 3487 3488 lo[0] = 0.0f; 3489 e[0] = LIMIT_LCP_EPSILON; 3490 3491 physics->AddFrameConstraint( this ); 3492 3493 return true; 3494 } 3495 3496 /* 3497 ================ 3498 idAFConstraint_ConeLimit::Translate 3499 ================ 3500 */ 3501 void idAFConstraint_ConeLimit::Translate( const idVec3 &translation ) { 3502 if ( !body2 ) { 3503 coneAnchor += translation; 3504 } 3505 } 3506 3507 /* 3508 ================ 3509 idAFConstraint_ConeLimit::Rotate 3510 ================ 3511 */ 3512 void idAFConstraint_ConeLimit::Rotate( const idRotation &rotation ) { 3513 if ( !body2 ) { 3514 coneAnchor *= rotation; 3515 coneAxis *= rotation.ToMat3(); 3516 } 3517 } 3518 3519 /* 3520 ================ 3521 idAFConstraint_ConeLimit::DebugDraw 3522 ================ 3523 */ 3524 void idAFConstraint_ConeLimit::DebugDraw() { 3525 idVec3 ax, anchor, x, y, z, start, end; 3526 float sinAngle, a, size = 10.0f; 3527 idAFBody *master; 3528 3529 master = body2 ? body2 : physics->GetMasterBody(); 3530 3531 if ( master ) { 3532 ax = coneAxis * master->GetWorldAxis(); 3533 anchor = master->GetWorldOrigin() + coneAnchor * master->GetWorldAxis(); 3534 } 3535 else { 3536 ax = coneAxis; 3537 anchor = coneAnchor; 3538 } 3539 3540 // draw body1 axis 3541 gameRenderWorld->DebugLine( colorGreen, anchor, anchor + size * (body1Axis * body1->GetWorldAxis()) ); 3542 3543 // draw cone 3544 ax.NormalVectors( x, y ); 3545 sinAngle = idMath::Sqrt( 1.0f - cosAngle * cosAngle ); 3546 x *= size * sinAngle; 3547 y *= size * sinAngle; 3548 z = anchor + ax * size * cosAngle; 3549 start = x + z; 3550 for ( a = 0.0f; a < 360.0f; a += 45.0f ) { 3551 end = x * (float) cos( DEG2RAD(a + 45.0f) ) + y * (float) sin( DEG2RAD(a + 45.0f) ) + z; 3552 gameRenderWorld->DebugLine( colorMagenta, anchor, start ); 3553 gameRenderWorld->DebugLine( colorMagenta, start, end ); 3554 start = end; 3555 } 3556 } 3557 3558 /* 3559 ================ 3560 idAFConstraint_ConeLimit::Save 3561 ================ 3562 */ 3563 void idAFConstraint_ConeLimit::Save( idSaveGame *saveFile ) const { 3564 idAFConstraint::Save( saveFile ); 3565 saveFile->WriteVec3( coneAnchor ); 3566 saveFile->WriteVec3( coneAxis ); 3567 saveFile->WriteVec3( body1Axis ); 3568 saveFile->WriteFloat( cosAngle ); 3569 saveFile->WriteFloat( sinHalfAngle ); 3570 saveFile->WriteFloat( cosHalfAngle ); 3571 saveFile->WriteFloat( epsilon ); 3572 } 3573 3574 /* 3575 ================ 3576 idAFConstraint_ConeLimit::Restore 3577 ================ 3578 */ 3579 void idAFConstraint_ConeLimit::Restore( idRestoreGame *saveFile ) { 3580 idAFConstraint::Restore( saveFile ); 3581 saveFile->ReadVec3( coneAnchor ); 3582 saveFile->ReadVec3( coneAxis ); 3583 saveFile->ReadVec3( body1Axis ); 3584 saveFile->ReadFloat( cosAngle ); 3585 saveFile->ReadFloat( sinHalfAngle ); 3586 saveFile->ReadFloat( cosHalfAngle ); 3587 saveFile->ReadFloat( epsilon ); 3588 } 3589 3590 3591 //=============================================================== 3592 // 3593 // idAFConstraint_PyramidLimit 3594 // 3595 //=============================================================== 3596 3597 /* 3598 ================ 3599 idAFConstraint_PyramidLimit::idAFConstraint_PyramidLimit 3600 ================ 3601 */ 3602 idAFConstraint_PyramidLimit::idAFConstraint_PyramidLimit() { 3603 type = CONSTRAINT_PYRAMIDLIMIT; 3604 name = "pyramidLimit"; 3605 InitSize( 1 ); 3606 fl.allowPrimary = false; 3607 fl.frameConstraint = true; 3608 } 3609 3610 /* 3611 ================ 3612 idAFConstraint_PyramidLimit::Setup 3613 ================ 3614 */ 3615 void idAFConstraint_PyramidLimit::Setup( idAFBody *b1, idAFBody *b2, const idVec3 &pyramidAnchor, 3616 const idVec3 &pyramidAxis, const idVec3 &baseAxis, 3617 const float pyramidAngle1, const float pyramidAngle2, const idVec3 &body1Axis ) { 3618 body1 = b1; 3619 body2 = b2; 3620 // setup the base and make sure the basis is orthonormal 3621 pyramidBasis[2] = pyramidAxis; 3622 pyramidBasis[2].Normalize(); 3623 pyramidBasis[0] = baseAxis; 3624 pyramidBasis[0] -= pyramidBasis[2] * baseAxis * pyramidBasis[2]; 3625 pyramidBasis[0].Normalize(); 3626 pyramidBasis[1] = pyramidBasis[0].Cross( pyramidBasis[2] ); 3627 // pyramid top 3628 this->pyramidAnchor = pyramidAnchor; 3629 // angles 3630 cosAngle[0] = (float) cos( DEG2RAD( pyramidAngle1 * 0.5f ) ); 3631 cosAngle[1] = (float) cos( DEG2RAD( pyramidAngle2 * 0.5f ) ); 3632 sinHalfAngle[0] = (float) sin( DEG2RAD( pyramidAngle1 * 0.25f ) ); 3633 sinHalfAngle[1] = (float) sin( DEG2RAD( pyramidAngle2 * 0.25f ) ); 3634 cosHalfAngle[0] = (float) cos( DEG2RAD( pyramidAngle1 * 0.25f ) ); 3635 cosHalfAngle[1] = (float) cos( DEG2RAD( pyramidAngle2 * 0.25f ) ); 3636 3637 this->body1Axis = body1Axis; 3638 } 3639 3640 /* 3641 ================ 3642 idAFConstraint_PyramidLimit::SetAnchor 3643 ================ 3644 */ 3645 void idAFConstraint_PyramidLimit::SetAnchor( const idVec3 &pyramidAnchor ) { 3646 this->pyramidAnchor = pyramidAnchor; 3647 } 3648 3649 /* 3650 ================ 3651 idAFConstraint_PyramidLimit::SetBody1Axis 3652 ================ 3653 */ 3654 void idAFConstraint_PyramidLimit::SetBody1Axis( const idVec3 &body1Axis ) { 3655 this->body1Axis = body1Axis; 3656 } 3657 3658 /* 3659 ================ 3660 idAFConstraint_PyramidLimit::Evaluate 3661 ================ 3662 */ 3663 void idAFConstraint_PyramidLimit::Evaluate( float invTimeStep ) { 3664 // do nothing 3665 } 3666 3667 /* 3668 ================ 3669 idAFConstraint_PyramidLimit::ApplyFriction 3670 ================ 3671 */ 3672 void idAFConstraint_PyramidLimit::ApplyFriction( float invTimeStep ) { 3673 } 3674 3675 /* 3676 ================ 3677 idAFConstraint_PyramidLimit::Add 3678 ================ 3679 */ 3680 bool idAFConstraint_PyramidLimit::Add( idPhysics_AF *phys, float invTimeStep ) { 3681 int i; 3682 float a[2]; 3683 idVec6 J1row, J2row; 3684 idMat3 worldBase; 3685 idVec3 anchor, body1ax, ax[2], v, normal, pyramidVector, p1, p2; 3686 idQuat q; 3687 idAFBody *master; 3688 3689 if ( af_skipLimits.GetBool() ) { 3690 lm.Zero(); // constraint exerts no force 3691 return false; 3692 } 3693 3694 physics = phys; 3695 master = body2 ? body2 : physics->GetMasterBody(); 3696 3697 if ( master ) { 3698 worldBase[0] = pyramidBasis[0] * master->GetWorldAxis(); 3699 worldBase[1] = pyramidBasis[1] * master->GetWorldAxis(); 3700 worldBase[2] = pyramidBasis[2] * master->GetWorldAxis(); 3701 anchor = master->GetWorldOrigin() + pyramidAnchor * master->GetWorldAxis(); 3702 } 3703 else { 3704 worldBase = pyramidBasis; 3705 anchor = pyramidAnchor; 3706 } 3707 3708 body1ax = body1Axis * body1->GetWorldAxis(); 3709 3710 for ( i = 0; i < 2; i++ ) { 3711 ax[i] = body1ax - worldBase[!i] * body1ax * worldBase[!i]; 3712 ax[i].Normalize(); 3713 a[i] = worldBase[2] * ax[i]; 3714 } 3715 3716 // if the body1 axis is inside the pyramid 3717 if ( a[0] > cosAngle[0] && a[1] > cosAngle[1] ) { 3718 lm.Zero(); // constraint exerts no force 3719 return false; 3720 } 3721 3722 // calculate the inward pyramid normal for the position the body1 axis went outside the pyramid 3723 pyramidVector = worldBase[2]; 3724 for ( i = 0; i < 2; i++ ) { 3725 if ( a[i] <= cosAngle[i] ) { 3726 v = ax[i].Cross( worldBase[2] ); 3727 v.Normalize(); 3728 q.x = v.x * sinHalfAngle[i]; 3729 q.y = v.y * sinHalfAngle[i]; 3730 q.z = v.z * sinHalfAngle[i]; 3731 q.w = cosHalfAngle[i]; 3732 pyramidVector *= q.ToMat3(); 3733 } 3734 } 3735 normal = pyramidVector.Cross( worldBase[2] ).Cross( pyramidVector ); 3736 normal.Normalize(); 3737 3738 p1 = anchor + 32.0f * pyramidVector - body1->GetWorldOrigin(); 3739 3740 J1row.SubVec3(0) = normal; 3741 J1row.SubVec3(1) = p1.Cross( normal ); 3742 J1.Set( 1, 6, J1row.ToFloatPtr() ); 3743 3744 c1[0] = (invTimeStep * LIMIT_ERROR_REDUCTION) * ( normal * (32.0f * body1ax) ); 3745 3746 if ( body2 ) { 3747 3748 p2 = anchor + 32.0f * pyramidVector - master->GetWorldOrigin(); 3749 3750 J2row.SubVec3(0) = -normal; 3751 J2row.SubVec3(1) = p2.Cross( -normal ); 3752 J2.Set( 1, 6, J2row.ToFloatPtr() ); 3753 3754 c2[0] = 0.0f; 3755 } 3756 3757 lo[0] = 0.0f; 3758 e[0] = LIMIT_LCP_EPSILON; 3759 3760 physics->AddFrameConstraint( this ); 3761 3762 return true; 3763 } 3764 3765 /* 3766 ================ 3767 idAFConstraint_PyramidLimit::Translate 3768 ================ 3769 */ 3770 void idAFConstraint_PyramidLimit::Translate( const idVec3 &translation ) { 3771 if ( !body2 ) { 3772 pyramidAnchor += translation; 3773 } 3774 } 3775 3776 /* 3777 ================ 3778 idAFConstraint_PyramidLimit::Rotate 3779 ================ 3780 */ 3781 void idAFConstraint_PyramidLimit::Rotate( const idRotation &rotation ) { 3782 if ( !body2 ) { 3783 pyramidAnchor *= rotation; 3784 pyramidBasis[0] *= rotation.ToMat3(); 3785 pyramidBasis[1] *= rotation.ToMat3(); 3786 pyramidBasis[2] *= rotation.ToMat3(); 3787 } 3788 } 3789 3790 /* 3791 ================ 3792 idAFConstraint_PyramidLimit::DebugDraw 3793 ================ 3794 */ 3795 void idAFConstraint_PyramidLimit::DebugDraw() { 3796 int i; 3797 float size = 10.0f; 3798 idVec3 anchor, dir, p[4]; 3799 idMat3 worldBase, m[2]; 3800 idQuat q; 3801 idAFBody *master; 3802 3803 master = body2 ? body2 : physics->GetMasterBody(); 3804 3805 if ( master ) { 3806 worldBase[0] = pyramidBasis[0] * master->GetWorldAxis(); 3807 worldBase[1] = pyramidBasis[1] * master->GetWorldAxis(); 3808 worldBase[2] = pyramidBasis[2] * master->GetWorldAxis(); 3809 anchor = master->GetWorldOrigin() + pyramidAnchor * master->GetWorldAxis(); 3810 } 3811 else { 3812 worldBase = pyramidBasis; 3813 anchor = pyramidAnchor; 3814 } 3815 3816 // draw body1 axis 3817 gameRenderWorld->DebugLine( colorGreen, anchor, anchor + size * (body1Axis * body1->GetWorldAxis()) ); 3818 3819 // draw the pyramid 3820 for ( i = 0; i < 2; i++ ) { 3821 q.x = worldBase[!i].x * sinHalfAngle[i]; 3822 q.y = worldBase[!i].y * sinHalfAngle[i]; 3823 q.z = worldBase[!i].z * sinHalfAngle[i]; 3824 q.w = cosHalfAngle[i]; 3825 m[i] = q.ToMat3(); 3826 } 3827 3828 dir = worldBase[2] * size; 3829 p[0] = anchor + m[0] * (m[1] * dir); 3830 p[1] = anchor + m[0] * (m[1].Transpose() * dir); 3831 p[2] = anchor + m[0].Transpose() * (m[1].Transpose() * dir); 3832 p[3] = anchor + m[0].Transpose() * (m[1] * dir); 3833 3834 for ( i = 0; i < 4; i++ ) { 3835 gameRenderWorld->DebugLine( colorMagenta, anchor, p[i] ); 3836 gameRenderWorld->DebugLine( colorMagenta, p[i], p[(i+1)&3] ); 3837 } 3838 } 3839 3840 /* 3841 ================ 3842 idAFConstraint_PyramidLimit::Save 3843 ================ 3844 */ 3845 void idAFConstraint_PyramidLimit::Save( idSaveGame *saveFile ) const { 3846 idAFConstraint::Save( saveFile ); 3847 saveFile->WriteVec3( pyramidAnchor ); 3848 saveFile->WriteMat3( pyramidBasis ); 3849 saveFile->WriteVec3( body1Axis ); 3850 saveFile->WriteFloat( cosAngle[0] ); 3851 saveFile->WriteFloat( cosAngle[1] ); 3852 saveFile->WriteFloat( sinHalfAngle[0] ); 3853 saveFile->WriteFloat( sinHalfAngle[1] ); 3854 saveFile->WriteFloat( cosHalfAngle[0] ); 3855 saveFile->WriteFloat( cosHalfAngle[1] ); 3856 saveFile->WriteFloat( epsilon ); 3857 } 3858 3859 /* 3860 ================ 3861 idAFConstraint_PyramidLimit::Restore 3862 ================ 3863 */ 3864 void idAFConstraint_PyramidLimit::Restore( idRestoreGame *saveFile ) { 3865 idAFConstraint::Restore( saveFile ); 3866 saveFile->ReadVec3( pyramidAnchor ); 3867 saveFile->ReadMat3( pyramidBasis ); 3868 saveFile->ReadVec3( body1Axis ); 3869 saveFile->ReadFloat( cosAngle[0] ); 3870 saveFile->ReadFloat( cosAngle[1] ); 3871 saveFile->ReadFloat( sinHalfAngle[0] ); 3872 saveFile->ReadFloat( sinHalfAngle[1] ); 3873 saveFile->ReadFloat( cosHalfAngle[0] ); 3874 saveFile->ReadFloat( cosHalfAngle[1] ); 3875 saveFile->ReadFloat( epsilon ); 3876 } 3877 3878 3879 //=============================================================== 3880 // 3881 // idAFConstraint_Suspension 3882 // 3883 //=============================================================== 3884 3885 /* 3886 ================ 3887 idAFConstraint_Suspension::idAFConstraint_Suspension 3888 ================ 3889 */ 3890 idAFConstraint_Suspension::idAFConstraint_Suspension() { 3891 type = CONSTRAINT_SUSPENSION; 3892 name = "suspension"; 3893 InitSize( 3 ); 3894 fl.allowPrimary = false; 3895 fl.frameConstraint = true; 3896 3897 localOrigin.Zero(); 3898 localAxis.Identity(); 3899 suspensionUp = 0.0f; 3900 suspensionDown = 0.0f; 3901 suspensionKCompress = 0.0f; 3902 suspensionDamping = 0.0f; 3903 steerAngle = 0.0f; 3904 friction = 2.0f; 3905 motorEnabled = false; 3906 motorForce = 0.0f; 3907 motorVelocity = 0.0f; 3908 wheelModel = NULL; 3909 memset( &trace, 0, sizeof( trace ) ); 3910 epsilon = LCP_EPSILON; 3911 } 3912 3913 /* 3914 ================ 3915 idAFConstraint_Suspension::Setup 3916 ================ 3917 */ 3918 void idAFConstraint_Suspension::Setup( const char *name, idAFBody *body, const idVec3 &origin, const idMat3 &axis, idClipModel *clipModel ) { 3919 this->name = name; 3920 body1 = body; 3921 body2 = NULL; 3922 localOrigin = ( origin - body->GetWorldOrigin() ) * body->GetWorldAxis().Transpose(); 3923 localAxis = axis * body->GetWorldAxis().Transpose(); 3924 wheelModel = clipModel; 3925 } 3926 3927 /* 3928 ================ 3929 idAFConstraint_Suspension::SetSuspension 3930 ================ 3931 */ 3932 void idAFConstraint_Suspension::SetSuspension( const float up, const float down, const float k, const float d, const float f ) { 3933 suspensionUp = up; 3934 suspensionDown = down; 3935 suspensionKCompress = k; 3936 suspensionDamping = d; 3937 friction = f; 3938 } 3939 3940 /* 3941 ================ 3942 idAFConstraint_Suspension::GetWheelOrigin 3943 ================ 3944 */ 3945 const idVec3 idAFConstraint_Suspension::GetWheelOrigin() const { 3946 return body1->GetWorldOrigin() + wheelOffset * body1->GetWorldAxis(); 3947 } 3948 3949 /* 3950 ================ 3951 idAFConstraint_Suspension::Evaluate 3952 ================ 3953 */ 3954 void idAFConstraint_Suspension::Evaluate( float invTimeStep ) { 3955 float velocity, suspensionLength, springLength, compression, dampingForce, springForce; 3956 idVec3 origin, start, end, vel1, vel2, springDir, r, frictionDir, motorDir; 3957 idMat3 axis; 3958 idRotation rotation; 3959 3960 axis = localAxis * body1->GetWorldAxis(); 3961 origin = body1->GetWorldOrigin() + localOrigin * body1->GetWorldAxis(); 3962 start = origin + suspensionUp * axis[2]; 3963 end = origin - suspensionDown * axis[2]; 3964 3965 rotation.SetVec( axis[2] ); 3966 rotation.SetAngle( steerAngle ); 3967 3968 axis *= rotation.ToMat3(); 3969 3970 gameLocal.clip.Translation( trace, start, end, wheelModel, axis, MASK_SOLID, NULL ); 3971 3972 wheelOffset = ( trace.endpos - body1->GetWorldOrigin() ) * body1->GetWorldAxis().Transpose(); 3973 3974 if ( trace.fraction >= 1.0f ) { 3975 J1.SetSize( 0, 6 ); 3976 if ( body2 ) { 3977 J2.SetSize( 0, 6 ); 3978 } 3979 return; 3980 } 3981 3982 // calculate and add spring force 3983 vel1 = body1->GetPointVelocity( start ); 3984 if ( body2 ) { 3985 vel2 = body2->GetPointVelocity( trace.c.point ); 3986 } else { 3987 vel2.Zero(); 3988 } 3989 3990 suspensionLength = suspensionUp + suspensionDown; 3991 springDir = trace.endpos - start; 3992 springLength = trace.fraction * suspensionLength; 3993 dampingForce = suspensionDamping * idMath::Fabs( ( vel2 - vel1 ) * springDir ) / ( 1.0f + springLength * springLength ); 3994 compression = suspensionLength - springLength; 3995 springForce = compression * compression * suspensionKCompress - dampingForce; 3996 3997 r = trace.c.point - body1->GetWorldOrigin(); 3998 J1.SetSize( 2, 6 ); 3999 J1.SubVec6(0).SubVec3(0) = trace.c.normal; 4000 J1.SubVec6(0).SubVec3(1) = r.Cross( trace.c.normal ); 4001 c1.SetSize( 2 ); 4002 c1[0] = 0.0f; 4003 velocity = J1.SubVec6(0).SubVec3(0) * body1->GetLinearVelocity() + J1.SubVec6(0).SubVec3(1) * body1->GetAngularVelocity(); 4004 4005 if ( body2 ) { 4006 r = trace.c.point - body2->GetWorldOrigin(); 4007 J2.SetSize( 2, 6 ); 4008 J2.SubVec6(0).SubVec3(0) = -trace.c.normal; 4009 J2.SubVec6(0).SubVec3(1) = r.Cross( -trace.c.normal ); 4010 c2.SetSize( 2 ); 4011 c2[0] = 0.0f; 4012 velocity += J2.SubVec6(0).SubVec3(0) * body2->GetLinearVelocity() + J2.SubVec6(0).SubVec3(1) * body2->GetAngularVelocity(); 4013 } 4014 4015 c1[0] = -compression; // + 0.5f * -velocity; 4016 4017 e[0] = 1e-4f; 4018 lo[0] = 0.0f; 4019 hi[0] = springForce; 4020 boxConstraint = NULL; 4021 boxIndex[0] = -1; 4022 4023 // project the friction direction into the contact plane 4024 frictionDir = axis[1] - axis[1] * trace.c.normal * axis[1]; 4025 frictionDir.Normalize(); 4026 4027 r = trace.c.point - body1->GetWorldOrigin(); 4028 4029 J1.SubVec6(1).SubVec3(0) = frictionDir; 4030 J1.SubVec6(1).SubVec3(1) = r.Cross( frictionDir ); 4031 c1[1] = 0.0f; 4032 4033 if ( body2 ) { 4034 r = trace.c.point - body2->GetWorldOrigin(); 4035 4036 J2.SubVec6(1).SubVec3(0) = -frictionDir; 4037 J2.SubVec6(1).SubVec3(1) = r.Cross( -frictionDir ); 4038 c2[1] = 0.0f; 4039 } 4040 4041 lo[1] = -friction * physics->GetContactFrictionScale(); 4042 hi[1] = friction * physics->GetContactFrictionScale(); 4043 4044 boxConstraint = this; 4045 boxIndex[1] = 0; 4046 4047 4048 if ( motorEnabled ) { 4049 // project the motor force direction into the contact plane 4050 motorDir = axis[0] - axis[0] * trace.c.normal * axis[0]; 4051 motorDir.Normalize(); 4052 4053 r = trace.c.point - body1->GetWorldOrigin(); 4054 4055 J1.ChangeSize( 3, J1.GetNumColumns() ); 4056 J1.SubVec6(2).SubVec3(0) = -motorDir; 4057 J1.SubVec6(2).SubVec3(1) = r.Cross( -motorDir ); 4058 c1.ChangeSize( 3 ); 4059 c1[2] = motorVelocity; 4060 4061 if ( body2 ) { 4062 r = trace.c.point - body2->GetWorldOrigin(); 4063 4064 J2.ChangeSize( 3, J2.GetNumColumns() ); 4065 J2.SubVec6(2).SubVec3(0) = -motorDir; 4066 J2.SubVec6(2).SubVec3(1) = r.Cross( -motorDir ); 4067 c2.ChangeSize( 3 ); 4068 c2[2] = 0.0f; 4069 } 4070 4071 lo[2] = -motorForce; 4072 hi[2] = motorForce; 4073 boxIndex[2] = -1; 4074 } 4075 } 4076 4077 /* 4078 ================ 4079 idAFConstraint_Suspension::ApplyFriction 4080 ================ 4081 */ 4082 void idAFConstraint_Suspension::ApplyFriction( float invTimeStep ) { 4083 // do nothing 4084 } 4085 4086 /* 4087 ================ 4088 idAFConstraint_Suspension::Translate 4089 ================ 4090 */ 4091 void idAFConstraint_Suspension::Translate( const idVec3 &translation ) { 4092 } 4093 4094 /* 4095 ================ 4096 idAFConstraint_Suspension::Rotate 4097 ================ 4098 */ 4099 void idAFConstraint_Suspension::Rotate( const idRotation &rotation ) { 4100 } 4101 4102 /* 4103 ================ 4104 idAFConstraint_Suspension::DebugDraw 4105 ================ 4106 */ 4107 void idAFConstraint_Suspension::DebugDraw() { 4108 idVec3 origin; 4109 idMat3 axis; 4110 idRotation rotation; 4111 4112 axis = localAxis * body1->GetWorldAxis(); 4113 4114 rotation.SetVec( axis[2] ); 4115 rotation.SetAngle( steerAngle ); 4116 4117 axis *= rotation.ToMat3(); 4118 4119 if ( trace.fraction < 1.0f ) { 4120 origin = trace.c.point; 4121 4122 gameRenderWorld->DebugLine( colorWhite, origin, origin + 6.0f * axis[2] ); 4123 gameRenderWorld->DebugLine( colorWhite, origin - 4.0f * axis[0], origin + 4.0f * axis[0] ); 4124 gameRenderWorld->DebugLine( colorWhite, origin - 2.0f * axis[1], origin + 2.0f * axis[1] ); 4125 } 4126 } 4127 4128 4129 //=============================================================== 4130 // 4131 // idAFBody 4132 // 4133 //=============================================================== 4134 4135 /* 4136 ================ 4137 idAFBody::idAFBody 4138 ================ 4139 */ 4140 idAFBody::idAFBody() { 4141 Init(); 4142 } 4143 4144 /* 4145 ================ 4146 idAFBody::idAFBody 4147 ================ 4148 */ 4149 idAFBody::idAFBody( const idStr &name, idClipModel *clipModel, float density ) { 4150 4151 assert( clipModel ); 4152 assert( clipModel->IsTraceModel() ); 4153 4154 Init(); 4155 4156 this->name = name; 4157 this->clipModel = NULL; 4158 4159 SetClipModel( clipModel ); 4160 SetDensity( density ); 4161 4162 current->worldOrigin = clipModel->GetOrigin(); 4163 current->worldAxis = clipModel->GetAxis(); 4164 *next = *current; 4165 4166 } 4167 4168 /* 4169 ================ 4170 idAFBody::~idAFBody 4171 ================ 4172 */ 4173 idAFBody::~idAFBody() { 4174 delete clipModel; 4175 } 4176 4177 /* 4178 ================ 4179 idAFBody::Init 4180 ================ 4181 */ 4182 void idAFBody::Init() { 4183 name = "noname"; 4184 parent = NULL; 4185 clipModel = NULL; 4186 primaryConstraint = NULL; 4187 tree = NULL; 4188 4189 linearFriction = -1.0f; 4190 angularFriction = -1.0f; 4191 contactFriction = -1.0f; 4192 bouncyness = -1.0f; 4193 clipMask = 0; 4194 4195 frictionDir = vec3_zero; 4196 contactMotorDir = vec3_zero; 4197 contactMotorVelocity = 0.0f; 4198 contactMotorForce = 0.0f; 4199 4200 mass = 1.0f; 4201 invMass = 1.0f; 4202 centerOfMass = vec3_zero; 4203 inertiaTensor = mat3_identity; 4204 inverseInertiaTensor = mat3_identity; 4205 4206 current = &state[0]; 4207 next = &state[1]; 4208 current->worldOrigin = vec3_zero; 4209 current->worldAxis = mat3_identity; 4210 current->spatialVelocity = vec6_zero; 4211 current->externalForce = vec6_zero; 4212 *next = *current; 4213 saved = *current; 4214 atRestOrigin = vec3_zero; 4215 atRestAxis = mat3_identity; 4216 4217 s.Zero( 6 ); 4218 totalForce.Zero( 6 ); 4219 auxForce.Zero( 6 ); 4220 acceleration.Zero( 6 ); 4221 4222 response = NULL; 4223 responseIndex = NULL; 4224 numResponses = 0; 4225 maxAuxiliaryIndex = 0; 4226 maxSubTreeAuxiliaryIndex = 0; 4227 4228 memset( &fl, 0, sizeof( fl ) ); 4229 4230 fl.selfCollision = true; 4231 fl.isZero = true; 4232 } 4233 4234 /* 4235 ================ 4236 idAFBody::SetClipModel 4237 ================ 4238 */ 4239 void idAFBody::SetClipModel( idClipModel *clipModel ) { 4240 if ( this->clipModel && this->clipModel != clipModel ) { 4241 delete this->clipModel; 4242 } 4243 this->clipModel = clipModel; 4244 } 4245 4246 /* 4247 ================ 4248 idAFBody::SetFriction 4249 ================ 4250 */ 4251 void idAFBody::SetFriction( float linear, float angular, float contact ) { 4252 if ( linear < 0.0f || linear > 1.0f || 4253 angular < 0.0f || angular > 1.0f || 4254 contact < 0.0f ) { 4255 gameLocal.Warning( "idAFBody::SetFriction: friction out of range, linear = %.1f, angular = %.1f, contact = %.1f", linear, angular, contact ); 4256 return; 4257 } 4258 linearFriction = linear; 4259 angularFriction = angular; 4260 contactFriction = contact; 4261 } 4262 4263 /* 4264 ================ 4265 idAFBody::SetBouncyness 4266 ================ 4267 */ 4268 void idAFBody::SetBouncyness( float bounce ) { 4269 if ( bounce < 0.0f || bounce > 1.0f ) { 4270 gameLocal.Warning( "idAFBody::SetBouncyness: bouncyness out of range, bounce = %.1f", bounce ); 4271 return; 4272 } 4273 bouncyness = bounce; 4274 } 4275 4276 /* 4277 ================ 4278 idAFBody::SetDensity 4279 ================ 4280 */ 4281 void idAFBody::SetDensity( float density, const idMat3 &inertiaScale ) { 4282 4283 // get the body mass properties 4284 clipModel->GetMassProperties( density, mass, centerOfMass, inertiaTensor ); 4285 4286 // make sure we have a valid mass 4287 if ( mass <= 0.0f || IEEE_FLT_IS_NAN( mass ) ) { 4288 gameLocal.Warning( "idAFBody::SetDensity: invalid mass for body '%s'", name.c_str() ); 4289 mass = 1.0f; 4290 centerOfMass.Zero(); 4291 inertiaTensor.Identity(); 4292 } 4293 4294 // make sure the center of mass is at the body origin 4295 if ( !centerOfMass.Compare( vec3_origin, CENTER_OF_MASS_EPSILON ) ) { 4296 gameLocal.Warning( "idAFBody::SetDentity: center of mass not at origin for body '%s'", name.c_str() ); 4297 } 4298 centerOfMass.Zero(); 4299 4300 // calculate the inverse mass and inverse inertia tensor 4301 invMass = 1.0f / mass; 4302 if ( inertiaScale != mat3_identity ) { 4303 inertiaTensor *= inertiaScale; 4304 } 4305 if ( inertiaTensor.IsDiagonal( 1e-3f ) ) { 4306 inertiaTensor[0][1] = inertiaTensor[0][2] = 0.0f; 4307 inertiaTensor[1][0] = inertiaTensor[1][2] = 0.0f; 4308 inertiaTensor[2][0] = inertiaTensor[2][1] = 0.0f; 4309 inverseInertiaTensor.Identity(); 4310 inverseInertiaTensor[0][0] = 1.0f / inertiaTensor[0][0]; 4311 inverseInertiaTensor[1][1] = 1.0f / inertiaTensor[1][1]; 4312 inverseInertiaTensor[2][2] = 1.0f / inertiaTensor[2][2]; 4313 } 4314 else { 4315 inverseInertiaTensor = inertiaTensor.Inverse(); 4316 } 4317 } 4318 4319 /* 4320 ================ 4321 idAFBody::SetFrictionDirection 4322 ================ 4323 */ 4324 void idAFBody::SetFrictionDirection( const idVec3 &dir ) { 4325 frictionDir = dir * current->worldAxis.Transpose(); 4326 fl.useFrictionDir = true; 4327 } 4328 4329 /* 4330 ================ 4331 idAFBody::GetFrictionDirection 4332 ================ 4333 */ 4334 bool idAFBody::GetFrictionDirection( idVec3 &dir ) const { 4335 if ( fl.useFrictionDir ) { 4336 dir = frictionDir * current->worldAxis; 4337 return true; 4338 } 4339 return false; 4340 } 4341 4342 /* 4343 ================ 4344 idAFBody::SetContactMotorDirection 4345 ================ 4346 */ 4347 void idAFBody::SetContactMotorDirection( const idVec3 &dir ) { 4348 contactMotorDir = dir * current->worldAxis.Transpose(); 4349 fl.useContactMotorDir = true; 4350 } 4351 4352 /* 4353 ================ 4354 idAFBody::GetContactMotorDirection 4355 ================ 4356 */ 4357 bool idAFBody::GetContactMotorDirection( idVec3 &dir ) const { 4358 if ( fl.useContactMotorDir ) { 4359 dir = contactMotorDir * current->worldAxis; 4360 return true; 4361 } 4362 return false; 4363 } 4364 4365 /* 4366 ================ 4367 idAFBody::GetPointVelocity 4368 ================ 4369 */ 4370 idVec3 idAFBody::GetPointVelocity( const idVec3 &point ) const { 4371 idVec3 r = point - current->worldOrigin; 4372 return current->spatialVelocity.SubVec3(0) + current->spatialVelocity.SubVec3(1).Cross( r ); 4373 } 4374 4375 /* 4376 ================ 4377 idAFBody::AddForce 4378 ================ 4379 */ 4380 void idAFBody::AddForce( const idVec3 &point, const idVec3 &force ) { 4381 current->externalForce.SubVec3(0) += force; 4382 current->externalForce.SubVec3(1) += (point - current->worldOrigin).Cross( force ); 4383 } 4384 4385 /* 4386 ================ 4387 idAFBody::InverseWorldSpatialInertiaMultiply 4388 4389 dst = this->inverseWorldSpatialInertia * v; 4390 ================ 4391 */ 4392 ID_INLINE void idAFBody::InverseWorldSpatialInertiaMultiply( idVecX &dst, const float *v ) const { 4393 const float *mPtr = inverseWorldSpatialInertia.ToFloatPtr(); 4394 const float *vPtr = v; 4395 float *dstPtr = dst.ToFloatPtr(); 4396 4397 if ( fl.spatialInertiaSparse ) { 4398 dstPtr[0] = mPtr[0*6+0] * vPtr[0]; 4399 dstPtr[1] = mPtr[1*6+1] * vPtr[1]; 4400 dstPtr[2] = mPtr[2*6+2] * vPtr[2]; 4401 dstPtr[3] = mPtr[3*6+3] * vPtr[3] + mPtr[3*6+4] * vPtr[4] + mPtr[3*6+5] * vPtr[5]; 4402 dstPtr[4] = mPtr[4*6+3] * vPtr[3] + mPtr[4*6+4] * vPtr[4] + mPtr[4*6+5] * vPtr[5]; 4403 dstPtr[5] = mPtr[5*6+3] * vPtr[3] + mPtr[5*6+4] * vPtr[4] + mPtr[5*6+5] * vPtr[5]; 4404 } else { 4405 gameLocal.Warning( "spatial inertia is not sparse for body %s", name.c_str() ); 4406 } 4407 } 4408 4409 /* 4410 ================ 4411 idAFBody::Save 4412 ================ 4413 */ 4414 void idAFBody::Save( idSaveGame *saveFile ) { 4415 saveFile->WriteFloat( linearFriction ); 4416 saveFile->WriteFloat( angularFriction ); 4417 saveFile->WriteFloat( contactFriction ); 4418 saveFile->WriteFloat( bouncyness ); 4419 saveFile->WriteInt( clipMask ); 4420 saveFile->WriteVec3( frictionDir ); 4421 saveFile->WriteVec3( contactMotorDir ); 4422 saveFile->WriteFloat( contactMotorVelocity ); 4423 saveFile->WriteFloat( contactMotorForce ); 4424 4425 saveFile->WriteFloat( mass ); 4426 saveFile->WriteFloat( invMass ); 4427 saveFile->WriteVec3( centerOfMass ); 4428 saveFile->WriteMat3( inertiaTensor ); 4429 saveFile->WriteMat3( inverseInertiaTensor ); 4430 4431 saveFile->WriteVec3( current->worldOrigin ); 4432 saveFile->WriteMat3( current->worldAxis ); 4433 saveFile->WriteVec6( current->spatialVelocity ); 4434 saveFile->WriteVec6( current->externalForce ); 4435 saveFile->WriteVec3( atRestOrigin ); 4436 saveFile->WriteMat3( atRestAxis ); 4437 } 4438 4439 /* 4440 ================ 4441 idAFBody::Restore 4442 ================ 4443 */ 4444 void idAFBody::Restore( idRestoreGame *saveFile ) { 4445 saveFile->ReadFloat( linearFriction ); 4446 saveFile->ReadFloat( angularFriction ); 4447 saveFile->ReadFloat( contactFriction ); 4448 saveFile->ReadFloat( bouncyness ); 4449 saveFile->ReadInt( clipMask ); 4450 saveFile->ReadVec3( frictionDir ); 4451 saveFile->ReadVec3( contactMotorDir ); 4452 saveFile->ReadFloat( contactMotorVelocity ); 4453 saveFile->ReadFloat( contactMotorForce ); 4454 4455 saveFile->ReadFloat( mass ); 4456 saveFile->ReadFloat( invMass ); 4457 saveFile->ReadVec3( centerOfMass ); 4458 saveFile->ReadMat3( inertiaTensor ); 4459 saveFile->ReadMat3( inverseInertiaTensor ); 4460 4461 saveFile->ReadVec3( current->worldOrigin ); 4462 saveFile->ReadMat3( current->worldAxis ); 4463 saveFile->ReadVec6( current->spatialVelocity ); 4464 saveFile->ReadVec6( current->externalForce ); 4465 saveFile->ReadVec3( atRestOrigin ); 4466 saveFile->ReadMat3( atRestAxis ); 4467 } 4468 4469 4470 4471 //=============================================================== 4472 // M 4473 // idAFTree MrE 4474 // E 4475 //=============================================================== 4476 4477 /* 4478 ================ 4479 idAFTree::Factor 4480 4481 factor matrix for the primary constraints in the tree 4482 ================ 4483 */ 4484 void idAFTree::Factor() const { 4485 int i, j; 4486 idAFBody *body; 4487 idAFConstraint *child = NULL; 4488 idMatX childI; 4489 4490 childI.SetData( 6, 6, MATX_ALLOCA( 6 * 6 ) ); 4491 4492 // from the leaves up towards the root 4493 for ( i = sortedBodies.Num() - 1; i >= 0; i-- ) { 4494 body = sortedBodies[i]; 4495 4496 if ( body->children.Num() ) { 4497 4498 for ( j = 0; j < body->children.Num(); j++ ) { 4499 4500 child = body->children[j]->primaryConstraint; 4501 4502 // child->I = - child->body1->J.Transpose() * child->body1->I * child->body1->J; 4503 childI.SetSize( child->J1.GetNumRows(), child->J1.GetNumRows() ); 4504 child->body1->J.TransposeMultiply( child->body1->I ).Multiply( childI, child->body1->J ); 4505 childI.Negate(); 4506 4507 child->invI = childI; 4508 if ( !child->invI.InverseFastSelf() ) { 4509 gameLocal.Warning( "idAFTree::Factor: couldn't invert %dx%d matrix for constraint '%s'", 4510 child->invI.GetNumRows(), child->invI.GetNumColumns(), child->GetName().c_str() ); 4511 } 4512 child->J = child->invI * child->J; 4513 4514 body->I -= child->J.TransposeMultiply( childI ) * child->J; 4515 } 4516 4517 body->invI = body->I; 4518 if ( !body->invI.InverseFastSelf() && child != NULL ) { 4519 gameLocal.Warning( "idAFTree::Factor: couldn't invert %dx%d matrix for body %s", 4520 child->invI.GetNumRows(), child->invI.GetNumColumns(), body->GetName().c_str() ); 4521 } 4522 if ( body->primaryConstraint ) { 4523 body->J = body->invI * body->J; 4524 } 4525 } 4526 else if ( body->primaryConstraint ) { 4527 body->J = body->inverseWorldSpatialInertia * body->J; 4528 } 4529 } 4530 } 4531 4532 /* 4533 ================ 4534 idAFTree::Solve 4535 4536 solve for primary constraints in the tree 4537 ================ 4538 */ 4539 void idAFTree::Solve( int auxiliaryIndex ) const { 4540 int i, j; 4541 idAFBody *body, *child; 4542 idAFConstraint *primaryConstraint; 4543 4544 // from the leaves up towards the root 4545 for ( i = sortedBodies.Num() - 1; i >= 0; i-- ) { 4546 body = sortedBodies[i]; 4547 4548 for ( j = 0; j < body->children.Num(); j++ ) { 4549 child = body->children[j]; 4550 primaryConstraint = child->primaryConstraint; 4551 4552 if ( !child->fl.isZero ) { 4553 child->J.TransposeMultiplySub( primaryConstraint->s, child->s ); 4554 primaryConstraint->fl.isZero = false; 4555 } 4556 if ( !primaryConstraint->fl.isZero ) { 4557 primaryConstraint->J.TransposeMultiplySub( body->s, primaryConstraint->s ); 4558 body->fl.isZero = false; 4559 } 4560 } 4561 } 4562 4563 bool useSymmetry = af_useSymmetry.GetBool(); 4564 4565 // from the root down towards the leaves 4566 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4567 body = sortedBodies[i]; 4568 primaryConstraint = body->primaryConstraint; 4569 4570 if ( primaryConstraint ) { 4571 4572 if ( useSymmetry && body->parent->maxSubTreeAuxiliaryIndex < auxiliaryIndex ) { 4573 continue; 4574 } 4575 4576 if ( !primaryConstraint->fl.isZero ) { 4577 primaryConstraint->s = primaryConstraint->invI * primaryConstraint->s; 4578 } 4579 primaryConstraint->J.MultiplySub( primaryConstraint->s, primaryConstraint->body2->s ); 4580 4581 primaryConstraint->lm = primaryConstraint->s; 4582 4583 if ( useSymmetry && body->maxSubTreeAuxiliaryIndex < auxiliaryIndex ) { 4584 continue; 4585 } 4586 4587 if ( body->children.Num() ) { 4588 if ( !body->fl.isZero ) { 4589 body->s = body->invI * body->s; 4590 } 4591 body->J.MultiplySub( body->s, primaryConstraint->s ); 4592 } 4593 } else if ( body->children.Num() ) { 4594 body->s = body->invI * body->s; 4595 } 4596 } 4597 } 4598 4599 /* 4600 ================ 4601 idAFTree::Response 4602 4603 calculate body forces in the tree in response to a constraint force 4604 ================ 4605 */ 4606 void idAFTree::Response( const idAFConstraint *constraint, int row, int auxiliaryIndex ) const { 4607 int i, j; 4608 idAFBody *body; 4609 idAFConstraint *child, *primaryConstraint; 4610 idVecX v; 4611 4612 // if a single body don't waste time because there aren't any primary constraints 4613 if ( sortedBodies.Num() == 1 ) { 4614 body = constraint->body1; 4615 if ( body->tree == this ) { 4616 body->GetResponseForce( body->numResponses ) = constraint->J1.SubVec6( row ); 4617 body->responseIndex[body->numResponses++] = auxiliaryIndex; 4618 } 4619 else { 4620 body = constraint->body2; 4621 body->GetResponseForce( body->numResponses ) = constraint->J2.SubVec6( row ); 4622 body->responseIndex[body->numResponses++] = auxiliaryIndex; 4623 } 4624 return; 4625 } 4626 4627 v.SetData( 6, VECX_ALLOCA( 6 ) ); 4628 4629 // initialize right hand side to zero 4630 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4631 body = sortedBodies[i]; 4632 primaryConstraint = body->primaryConstraint; 4633 if ( primaryConstraint ) { 4634 primaryConstraint->s.Zero(); 4635 primaryConstraint->fl.isZero = true; 4636 } 4637 body->s.Zero(); 4638 body->fl.isZero = true; 4639 body->GetResponseForce( body->numResponses ).Zero(); 4640 } 4641 4642 // set right hand side for first constrained body 4643 body = constraint->body1; 4644 if ( body->tree == this ) { 4645 body->InverseWorldSpatialInertiaMultiply( v, constraint->J1[row] ); 4646 primaryConstraint = body->primaryConstraint; 4647 if ( primaryConstraint ) { 4648 primaryConstraint->J1.Multiply( primaryConstraint->s, v ); 4649 primaryConstraint->fl.isZero = false; 4650 } 4651 for ( i = 0; i < body->children.Num(); i++ ) { 4652 child = body->children[i]->primaryConstraint; 4653 child->J2.Multiply( child->s, v ); 4654 child->fl.isZero = false; 4655 } 4656 body->GetResponseForce( body->numResponses ) = constraint->J1.SubVec6( row ); 4657 } 4658 4659 // set right hand side for second constrained body 4660 body = constraint->body2; 4661 if ( body && body->tree == this ) { 4662 body->InverseWorldSpatialInertiaMultiply( v, constraint->J2[row] ); 4663 primaryConstraint = body->primaryConstraint; 4664 if ( primaryConstraint ) { 4665 primaryConstraint->J1.MultiplyAdd( primaryConstraint->s, v ); 4666 primaryConstraint->fl.isZero = false; 4667 } 4668 for ( i = 0; i < body->children.Num(); i++ ) { 4669 child = body->children[i]->primaryConstraint; 4670 child->J2.MultiplyAdd( child->s, v ); 4671 child->fl.isZero = false; 4672 } 4673 body->GetResponseForce( body->numResponses ) = constraint->J2.SubVec6( row ); 4674 } 4675 4676 4677 // solve for primary constraints 4678 Solve( auxiliaryIndex ); 4679 4680 bool useSymmetry = af_useSymmetry.GetBool(); 4681 4682 // store body forces in response to the constraint force 4683 idVecX force; 4684 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4685 body = sortedBodies[i]; 4686 4687 if ( useSymmetry && body->maxAuxiliaryIndex < auxiliaryIndex ) { 4688 continue; 4689 } 4690 4691 force.SetData( 6, body->response + body->numResponses * 8 ); 4692 4693 // add forces of all primary constraints acting on this body 4694 primaryConstraint = body->primaryConstraint; 4695 if ( primaryConstraint ) { 4696 primaryConstraint->J1.TransposeMultiplyAdd( force, primaryConstraint->lm ); 4697 } 4698 for ( j = 0; j < body->children.Num(); j++ ) { 4699 child = body->children[j]->primaryConstraint; 4700 child->J2.TransposeMultiplyAdd( force, child->lm ); 4701 } 4702 4703 body->responseIndex[body->numResponses++] = auxiliaryIndex; 4704 } 4705 } 4706 4707 /* 4708 ================ 4709 idAFTree::CalculateForces 4710 4711 calculate forces on the bodies in the tree 4712 ================ 4713 */ 4714 void idAFTree::CalculateForces( float timeStep ) const { 4715 int i, j; 4716 float invStep; 4717 idAFBody *body; 4718 idAFConstraint *child, *c, *primaryConstraint; 4719 4720 // forces on bodies 4721 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4722 body = sortedBodies[i]; 4723 4724 body->totalForce.SubVec6(0) = body->current->externalForce + body->auxForce.SubVec6(0); 4725 } 4726 4727 // if a single body don't waste time because there aren't any primary constraints 4728 if ( sortedBodies.Num() == 1 ) { 4729 return; 4730 } 4731 4732 invStep = 1.0f / timeStep; 4733 4734 // initialize right hand side 4735 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4736 body = sortedBodies[i]; 4737 4738 body->InverseWorldSpatialInertiaMultiply( body->acceleration, body->totalForce.ToFloatPtr() ); 4739 body->acceleration.SubVec6(0) += body->current->spatialVelocity * invStep; 4740 primaryConstraint = body->primaryConstraint; 4741 if ( primaryConstraint ) { 4742 // b = ( J * acc + c ) 4743 c = primaryConstraint; 4744 c->s = c->J1 * c->body1->acceleration + c->J2 * c->body2->acceleration + invStep * ( c->c1 + c->c2 ); 4745 c->fl.isZero = false; 4746 } 4747 body->s.Zero(); 4748 body->fl.isZero = true; 4749 } 4750 4751 // solve for primary constraints 4752 Solve(); 4753 4754 // calculate forces on bodies after applying primary constraints 4755 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4756 body = sortedBodies[i]; 4757 4758 // add forces of all primary constraints acting on this body 4759 primaryConstraint = body->primaryConstraint; 4760 if ( primaryConstraint ) { 4761 primaryConstraint->J1.TransposeMultiplyAdd( body->totalForce, primaryConstraint->lm ); 4762 } 4763 for ( j = 0; j < body->children.Num(); j++ ) { 4764 child = body->children[j]->primaryConstraint; 4765 child->J2.TransposeMultiplyAdd( body->totalForce, child->lm ); 4766 } 4767 } 4768 } 4769 4770 /* 4771 ================ 4772 idAFTree::SetMaxSubTreeAuxiliaryIndex 4773 ================ 4774 */ 4775 void idAFTree::SetMaxSubTreeAuxiliaryIndex() { 4776 int i, j; 4777 idAFBody *body, *child; 4778 4779 // from the leaves up towards the root 4780 for ( i = sortedBodies.Num() - 1; i >= 0; i-- ) { 4781 body = sortedBodies[i]; 4782 4783 body->maxSubTreeAuxiliaryIndex = body->maxAuxiliaryIndex; 4784 for ( j = 0; j < body->children.Num(); j++ ) { 4785 child = body->children[j]; 4786 if ( child->maxSubTreeAuxiliaryIndex > body->maxSubTreeAuxiliaryIndex ) { 4787 body->maxSubTreeAuxiliaryIndex = child->maxSubTreeAuxiliaryIndex; 4788 } 4789 } 4790 } 4791 } 4792 4793 /* 4794 ================ 4795 idAFTree::SortBodies_r 4796 ================ 4797 */ 4798 void idAFTree::SortBodies_r( idList<idAFBody*>&sortedList, idAFBody *body ) { 4799 int i; 4800 4801 for ( i = 0; i < body->children.Num(); i++ ) { 4802 sortedList.Append( body->children[i] ); 4803 } 4804 for ( i = 0; i < body->children.Num(); i++ ) { 4805 SortBodies_r( sortedList, body->children[i] ); 4806 } 4807 } 4808 4809 /* 4810 ================ 4811 idAFTree::SortBodies 4812 4813 sort body list to make sure parents come first 4814 ================ 4815 */ 4816 void idAFTree::SortBodies() { 4817 int i; 4818 idAFBody *body; 4819 4820 // find the root 4821 for ( i = 0; i < sortedBodies.Num(); i++ ) { 4822 if ( !sortedBodies[i]->parent ) { 4823 break; 4824 } 4825 } 4826 4827 if ( i >= sortedBodies.Num() ) { 4828 gameLocal.Error( "Articulated figure tree has no root." ); 4829 } 4830 4831 body = sortedBodies[i]; 4832 sortedBodies.Clear(); 4833 sortedBodies.Append( body ); 4834 SortBodies_r( sortedBodies, body ); 4835 } 4836 4837 /* 4838 ================ 4839 idAFTree::DebugDraw 4840 ================ 4841 */ 4842 void idAFTree::DebugDraw( const idVec4 &color ) const { 4843 int i; 4844 idAFBody *body; 4845 4846 for ( i = 1; i < sortedBodies.Num(); i++ ) { 4847 body = sortedBodies[i]; 4848 gameRenderWorld->DebugArrow( color, body->parent->current->worldOrigin, body->current->worldOrigin, 1 ); 4849 } 4850 } 4851 4852 4853 //=============================================================== 4854 // M 4855 // idPhysics_AF MrE 4856 // E 4857 //=============================================================== 4858 4859 /* 4860 ================ 4861 idPhysics_AF::EvaluateConstraints 4862 ================ 4863 */ 4864 void idPhysics_AF::EvaluateConstraints( float timeStep ) { 4865 int i; 4866 float invTimeStep; 4867 idAFBody *body; 4868 idAFConstraint *c; 4869 4870 invTimeStep = 1.0f / timeStep; 4871 4872 // setup the constraint equations for the current position and orientation of the bodies 4873 for ( i = 0; i < primaryConstraints.Num(); i++ ) { 4874 c = primaryConstraints[i]; 4875 c->Evaluate( invTimeStep ); 4876 c->J = c->J2; 4877 } 4878 for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { 4879 auxiliaryConstraints[i]->Evaluate( invTimeStep ); 4880 } 4881 4882 // add contact constraints to the list with frame constraints 4883 for ( i = 0; i < contactConstraints.Num(); i++ ) { 4884 AddFrameConstraint( contactConstraints[i] ); 4885 } 4886 4887 // setup body primary constraint matrix 4888 for ( i = 0; i < bodies.Num(); i++ ) { 4889 body = bodies[i]; 4890 4891 if ( body->primaryConstraint ) { 4892 body->J = body->primaryConstraint->J1.Transpose(); 4893 } 4894 } 4895 } 4896 4897 /* 4898 ================ 4899 idPhysics_AF::EvaluateBodies 4900 ================ 4901 */ 4902 void idPhysics_AF::EvaluateBodies( float timeStep ) { 4903 int i; 4904 idAFBody *body; 4905 idMat3 axis; 4906 4907 for ( i = 0; i < bodies.Num(); i++ ) { 4908 body = bodies[i]; 4909 4910 // we transpose the axis before using it because idMat3 is column-major 4911 axis = body->current->worldAxis.Transpose(); 4912 4913 // if the center of mass is at the body point of reference 4914 if ( body->centerOfMass.Compare( vec3_origin, CENTER_OF_MASS_EPSILON ) ) { 4915 4916 // spatial inertia in world space 4917 body->I.Set( body->mass * mat3_identity, mat3_zero, 4918 mat3_zero, axis * body->inertiaTensor * axis.Transpose() ); 4919 4920 // inverse spatial inertia in world space 4921 body->inverseWorldSpatialInertia.Set( body->invMass * mat3_identity, mat3_zero, 4922 mat3_zero, axis * body->inverseInertiaTensor * axis.Transpose() ); 4923 4924 body->fl.spatialInertiaSparse = true; 4925 } 4926 else { 4927 idMat3 massMoment = body->mass * SkewSymmetric( body->centerOfMass ); 4928 4929 // spatial inertia in world space 4930 body->I.Set( body->mass * mat3_identity, massMoment, 4931 massMoment.Transpose(), axis * body->inertiaTensor * axis.Transpose() ); 4932 4933 // inverse spatial inertia in world space 4934 body->inverseWorldSpatialInertia = body->I.InverseFast(); 4935 4936 body->fl.spatialInertiaSparse = false; 4937 } 4938 4939 // initialize auxiliary constraint force to zero 4940 body->auxForce.Zero(); 4941 } 4942 } 4943 4944 /* 4945 ================ 4946 idPhysics_AF::AddFrameConstraints 4947 ================ 4948 */ 4949 void idPhysics_AF::AddFrameConstraints() { 4950 int i; 4951 4952 // add frame constraints to auxiliary constraints 4953 for ( i = 0; i < frameConstraints.Num(); i++ ) { 4954 auxiliaryConstraints.Append( frameConstraints[i] ); 4955 } 4956 } 4957 4958 /* 4959 ================ 4960 idPhysics_AF::RemoveFrameConstraints 4961 ================ 4962 */ 4963 void idPhysics_AF::RemoveFrameConstraints() { 4964 // remove all the frame constraints from the auxiliary constraints 4965 auxiliaryConstraints.SetNum( auxiliaryConstraints.Num() - frameConstraints.Num() ); 4966 frameConstraints.SetNum( 0 ); 4967 } 4968 4969 /* 4970 ================ 4971 idPhysics_AF::ApplyFriction 4972 ================ 4973 */ 4974 void idPhysics_AF::ApplyFriction( float timeStep, float endTimeMSec ) { 4975 int i; 4976 float invTimeStep; 4977 4978 if ( af_skipFriction.GetBool() ) { 4979 return; 4980 } 4981 4982 if ( jointFrictionDentStart < MS2SEC( endTimeMSec ) && jointFrictionDentEnd > MS2SEC( endTimeMSec ) ) { 4983 float halfTime = ( jointFrictionDentEnd - jointFrictionDentStart ) * 0.5f; 4984 if ( jointFrictionDentStart + halfTime > MS2SEC( endTimeMSec ) ) { 4985 jointFrictionDentScale = 1.0f - ( 1.0f - jointFrictionDent ) * ( MS2SEC( endTimeMSec ) - jointFrictionDentStart ) / halfTime; 4986 } else { 4987 jointFrictionDentScale = jointFrictionDent + ( 1.0f - jointFrictionDent ) * ( MS2SEC( endTimeMSec ) - jointFrictionDentStart - halfTime ) / halfTime; 4988 } 4989 } else { 4990 jointFrictionDentScale = 0.0f; 4991 } 4992 4993 if ( contactFrictionDentStart < MS2SEC( endTimeMSec ) && contactFrictionDentEnd > MS2SEC( endTimeMSec ) ) { 4994 float halfTime = ( contactFrictionDentEnd - contactFrictionDentStart ) * 0.5f; 4995 if ( contactFrictionDentStart + halfTime > MS2SEC( endTimeMSec ) ) { 4996 contactFrictionDentScale = 1.0f - ( 1.0f - contactFrictionDent ) * ( MS2SEC( endTimeMSec ) - contactFrictionDentStart ) / halfTime; 4997 } else { 4998 contactFrictionDentScale = contactFrictionDent + ( 1.0f - contactFrictionDent ) * ( MS2SEC( endTimeMSec ) - contactFrictionDentStart - halfTime ) / halfTime; 4999 } 5000 } else { 5001 contactFrictionDentScale = 0.0f; 5002 } 5003 5004 invTimeStep = 1.0f / timeStep; 5005 5006 for ( i = 0; i < primaryConstraints.Num(); i++ ) { 5007 primaryConstraints[i]->ApplyFriction( invTimeStep ); 5008 } 5009 for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5010 auxiliaryConstraints[i]->ApplyFriction( invTimeStep ); 5011 } 5012 for ( i = 0; i < frameConstraints.Num(); i++ ) { 5013 frameConstraints[i]->ApplyFriction( invTimeStep ); 5014 } 5015 } 5016 5017 /* 5018 ================ 5019 idPhysics_AF::PrimaryFactor 5020 ================ 5021 */ 5022 void idPhysics_AF::PrimaryFactor() { 5023 int i; 5024 5025 for ( i = 0; i < trees.Num(); i++ ) { 5026 trees[i]->Factor(); 5027 } 5028 } 5029 5030 /* 5031 ================ 5032 idPhysics_AF::PrimaryForces 5033 ================ 5034 */ 5035 void idPhysics_AF::PrimaryForces( float timeStep ) { 5036 int i; 5037 5038 for ( i = 0; i < trees.Num(); i++ ) { 5039 trees[i]->CalculateForces( timeStep ); 5040 } 5041 } 5042 5043 /* 5044 ================ 5045 idPhysics_AF::AuxiliaryForces 5046 ================ 5047 */ 5048 void idPhysics_AF::AuxiliaryForces( float timeStep ) { 5049 int i, j, k, l, n, m, s, numAuxConstraints, *index, *boxIndex; 5050 float *ptr, *j1, *j2, *dstPtr, *forcePtr; 5051 float invStep, u; 5052 idAFBody *body; 5053 idAFConstraint *constraint; 5054 idVecX tmp; 5055 idMatX jmk; 5056 idVecX rhs, w, lm, lo, hi; 5057 5058 // get the number of one dimensional auxiliary constraints 5059 for ( numAuxConstraints = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5060 numAuxConstraints += auxiliaryConstraints[i]->J1.GetNumRows(); 5061 } 5062 5063 if ( numAuxConstraints == 0 ) { 5064 return; 5065 } 5066 5067 // allocate memory to store the body response to auxiliary constraint forces 5068 forcePtr = (float *) _alloca16( bodies.Num() * numAuxConstraints * 8 * sizeof( float ) ); 5069 index = (int *) _alloca16( bodies.Num() * numAuxConstraints * sizeof( int ) ); 5070 for ( i = 0; i < bodies.Num(); i++ ) { 5071 body = bodies[i]; 5072 body->response = forcePtr; 5073 body->responseIndex = index; 5074 body->numResponses = 0; 5075 body->maxAuxiliaryIndex = 0; 5076 forcePtr += numAuxConstraints * 8; 5077 index += numAuxConstraints; 5078 } 5079 5080 // set on each body the largest index of an auxiliary constraint constraining the body 5081 if ( af_useSymmetry.GetBool() ) { 5082 for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5083 constraint = auxiliaryConstraints[i]; 5084 for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { 5085 if ( k > constraint->body1->maxAuxiliaryIndex ) { 5086 constraint->body1->maxAuxiliaryIndex = k; 5087 } 5088 if ( constraint->body2 && k > constraint->body2->maxAuxiliaryIndex ) { 5089 constraint->body2->maxAuxiliaryIndex = k; 5090 } 5091 } 5092 } 5093 for ( i = 0; i < trees.Num(); i++ ) { 5094 trees[i]->SetMaxSubTreeAuxiliaryIndex(); 5095 } 5096 } 5097 5098 // calculate forces of primary constraints in response to the auxiliary constraint forces 5099 for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5100 constraint = auxiliaryConstraints[i]; 5101 5102 for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { 5103 5104 // calculate body forces in the tree in response to the constraint force 5105 constraint->body1->tree->Response( constraint, j, k ); 5106 // if there is a second body which is part of a different tree 5107 if ( constraint->body2 && constraint->body2->tree != constraint->body1->tree ) { 5108 // calculate body forces in the second tree in response to the constraint force 5109 constraint->body2->tree->Response( constraint, j, k ); 5110 } 5111 } 5112 } 5113 5114 // NOTE: the rows are 16 byte padded 5115 jmk.SetData( numAuxConstraints, ((numAuxConstraints+3)&~3), MATX_ALLOCA( numAuxConstraints * ((numAuxConstraints+3)&~3) ) ); 5116 tmp.SetData( 6, VECX_ALLOCA( 6 ) ); 5117 5118 // create constraint matrix for auxiliary constraints using a mass matrix adjusted for the primary constraints 5119 for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5120 constraint = auxiliaryConstraints[i]; 5121 5122 for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { 5123 constraint->body1->InverseWorldSpatialInertiaMultiply( tmp, constraint->J1[j] ); 5124 j1 = tmp.ToFloatPtr(); 5125 ptr = constraint->body1->response; 5126 index = constraint->body1->responseIndex; 5127 dstPtr = jmk[k]; 5128 s = af_useSymmetry.GetBool() ? k + 1 : numAuxConstraints; 5129 for ( l = n = 0, m = index[n]; n < constraint->body1->numResponses && m < s; n++, m = index[n] ) { 5130 while( l < m ) { 5131 dstPtr[l++] = 0.0f; 5132 } 5133 dstPtr[l++] = j1[0] * ptr[0] + j1[1] * ptr[1] + j1[2] * ptr[2] + 5134 j1[3] * ptr[3] + j1[4] * ptr[4] + j1[5] * ptr[5]; 5135 ptr += 8; 5136 } 5137 5138 while( l < s ) { 5139 dstPtr[l++] = 0.0f; 5140 } 5141 5142 if ( constraint->body2 ) { 5143 constraint->body2->InverseWorldSpatialInertiaMultiply( tmp, constraint->J2[j] ); 5144 j2 = tmp.ToFloatPtr(); 5145 ptr = constraint->body2->response; 5146 index = constraint->body2->responseIndex; 5147 for ( n = 0, m = index[n]; n < constraint->body2->numResponses && m < s; n++, m = index[n] ) { 5148 dstPtr[m] += j2[0] * ptr[0] + j2[1] * ptr[1] + j2[2] * ptr[2] + 5149 j2[3] * ptr[3] + j2[4] * ptr[4] + j2[5] * ptr[5]; 5150 ptr += 8; 5151 } 5152 } 5153 } 5154 } 5155 5156 if ( af_useSymmetry.GetBool() ) { 5157 n = jmk.GetNumColumns(); 5158 for ( i = 0; i < numAuxConstraints; i++ ) { 5159 ptr = jmk.ToFloatPtr() + ( i + 1 ) * n + i; 5160 dstPtr = jmk.ToFloatPtr() + i * n + i + 1; 5161 for ( j = i+1; j < numAuxConstraints; j++ ) { 5162 *dstPtr++ = *ptr; 5163 ptr += n; 5164 } 5165 } 5166 } 5167 5168 invStep = 1.0f / timeStep; 5169 5170 // calculate body acceleration 5171 for ( i = 0; i < bodies.Num(); i++ ) { 5172 body = bodies[i]; 5173 body->InverseWorldSpatialInertiaMultiply( body->acceleration, body->totalForce.ToFloatPtr() ); 5174 body->acceleration.SubVec6(0) += body->current->spatialVelocity * invStep; 5175 } 5176 5177 rhs.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); 5178 lo.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); 5179 hi.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); 5180 lm.SetData( numAuxConstraints, VECX_ALLOCA( numAuxConstraints ) ); 5181 boxIndex = (int *) _alloca16( numAuxConstraints * sizeof( int ) ); 5182 5183 // set first index for special box constrained variables 5184 for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5185 auxiliaryConstraints[i]->firstIndex = k; 5186 k += auxiliaryConstraints[i]->J1.GetNumRows(); 5187 } 5188 5189 // initialize right hand side and low and high bounds for auxiliary constraints 5190 for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5191 constraint = auxiliaryConstraints[i]; 5192 n = k; 5193 5194 for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { 5195 5196 j1 = constraint->J1[j]; 5197 ptr = constraint->body1->acceleration.ToFloatPtr(); 5198 rhs[k] = j1[0] * ptr[0] + j1[1] * ptr[1] + j1[2] * ptr[2] + j1[3] * ptr[3] + j1[4] * ptr[4] + j1[5] * ptr[5]; 5199 rhs[k] += constraint->c1[j] * invStep; 5200 5201 if ( constraint->body2 ) { 5202 j2 = constraint->J2[j]; 5203 ptr = constraint->body2->acceleration.ToFloatPtr(); 5204 rhs[k] += j2[0] * ptr[0] + j2[1] * ptr[1] + j2[2] * ptr[2] + j2[3] * ptr[3] + j2[4] * ptr[4] + j2[5] * ptr[5]; 5205 rhs[k] += constraint->c2[j] * invStep; 5206 } 5207 5208 rhs[k] = -rhs[k]; 5209 lo[k] = constraint->lo[j]; 5210 hi[k] = constraint->hi[j]; 5211 5212 if ( constraint->boxIndex[j] >= 0 ) { 5213 if ( constraint->boxConstraint->fl.isPrimary ) { 5214 gameLocal.Error( "cannot reference primary constraints for the box index" ); 5215 } 5216 boxIndex[k] = constraint->boxConstraint->firstIndex + constraint->boxIndex[j]; 5217 } 5218 else { 5219 boxIndex[k] = -1; 5220 } 5221 jmk[k][k] += constraint->e[j] * invStep; 5222 } 5223 } 5224 5225 #ifdef AF_TIMINGS 5226 timer_lcp.Start(); 5227 #endif 5228 5229 // calculate lagrange multipliers for auxiliary constraints 5230 if ( !lcp->Solve( jmk, lm, rhs, lo, hi, boxIndex ) ) { 5231 return; // bad monkey! 5232 } 5233 5234 #ifdef AF_TIMINGS 5235 timer_lcp.Stop(); 5236 #endif 5237 5238 // calculate auxiliary constraint forces 5239 for ( k = 0, i = 0; i < auxiliaryConstraints.Num(); i++ ) { 5240 constraint = auxiliaryConstraints[i]; 5241 5242 for ( j = 0; j < constraint->J1.GetNumRows(); j++, k++ ) { 5243 constraint->lm[j] = u = lm[k]; 5244 5245 j1 = constraint->J1[j]; 5246 ptr = constraint->body1->auxForce.ToFloatPtr(); 5247 ptr[0] += j1[0] * u; ptr[1] += j1[1] * u; ptr[2] += j1[2] * u; 5248 ptr[3] += j1[3] * u; ptr[4] += j1[4] * u; ptr[5] += j1[5] * u; 5249 5250 if ( constraint->body2 ) { 5251 j2 = constraint->J2[j]; 5252 ptr = constraint->body2->auxForce.ToFloatPtr(); 5253 ptr[0] += j2[0] * u; ptr[1] += j2[1] * u; ptr[2] += j2[2] * u; 5254 ptr[3] += j2[3] * u; ptr[4] += j2[4] * u; ptr[5] += j2[5] * u; 5255 } 5256 } 5257 } 5258 5259 // recalculate primary constraint forces in response to auxiliary constraint forces 5260 PrimaryForces( timeStep ); 5261 5262 // clear pointers pointing to stack space so tools don't get confused 5263 for ( i = 0; i < bodies.Num(); i++ ) { 5264 body = bodies[i]; 5265 body->response = NULL; 5266 body->responseIndex = NULL; 5267 } 5268 } 5269 5270 /* 5271 ================ 5272 idPhysics_AF::VerifyContactConstraints 5273 ================ 5274 */ 5275 void idPhysics_AF::VerifyContactConstraints() { 5276 #if 0 5277 int i; 5278 float impulseNumerator, impulseDenominator; 5279 idVec3 r, velocity, normalVelocity, normal, impulse; 5280 idAFBody *body; 5281 5282 for ( i = 0; i < contactConstraints.Num(); i++ ) { 5283 body = contactConstraints[i]->body1; 5284 const contactInfo_t &contact = contactConstraints[i]->GetContact(); 5285 5286 r = contact.point - body->GetCenterOfMass(); 5287 5288 // calculate velocity at contact point 5289 velocity = body->GetLinearVelocity() + body->GetAngularVelocity().Cross( r ); 5290 5291 // velocity along normal vector 5292 normalVelocity = ( velocity * contact.normal ) * contact.normal; 5293 5294 // if moving towards the surface at the contact point 5295 if ( normalVelocity * contact.normal < 0.0f ) { 5296 // calculate impulse 5297 normal = -normalVelocity; 5298 impulseNumerator = normal.Normalize(); 5299 impulseDenominator = body->GetInverseMass() + ( ( body->GetInverseWorldInertia() * r.Cross( normal ) ).Cross( r ) * normal ); 5300 impulse = (impulseNumerator / impulseDenominator) * normal * 1.0001f; 5301 5302 // apply impulse 5303 body->SetLinearVelocity( body->GetLinearVelocity() + impulse ); 5304 body->SetAngularVelocity( body->GetAngularVelocity() + r.Cross( impulse ) ); 5305 } 5306 } 5307 #else 5308 int i; 5309 idAFBody *body; 5310 idVec3 normal; 5311 5312 for ( i = 0; i < contactConstraints.Num(); i++ ) { 5313 body = contactConstraints[i]->body1; 5314 normal = contactConstraints[i]->GetContact().normal; 5315 if ( normal * body->next->spatialVelocity.SubVec3(0) <= 0.0f ) { 5316 body->next->spatialVelocity.SubVec3(0) -= 1.0001f * (normal * body->next->spatialVelocity.SubVec3(0)) * normal; 5317 } 5318 body = contactConstraints[i]->body2; 5319 if ( !body ) { 5320 continue; 5321 } 5322 normal = -normal; 5323 if ( normal * body->next->spatialVelocity.SubVec3(0) <= 0.0f ) { 5324 body->next->spatialVelocity.SubVec3(0) -= 1.0001f * (normal * body->next->spatialVelocity.SubVec3(0)) * normal; 5325 } 5326 } 5327 #endif 5328 } 5329 5330 /* 5331 ================ 5332 idPhysics_AF::Evolve 5333 ================ 5334 */ 5335 void idPhysics_AF::Evolve( float timeStep ) { 5336 int i; 5337 float angle; 5338 idVec3 vec; 5339 idAFBody *body; 5340 idVec6 force; 5341 idRotation rotation; 5342 float vSqr, maxLinearVelocity, maxAngularVelocity; 5343 5344 maxLinearVelocity = af_maxLinearVelocity.GetFloat() / timeStep; 5345 maxAngularVelocity = af_maxAngularVelocity.GetFloat() / timeStep; 5346 5347 for ( i = 0; i < bodies.Num(); i++ ) { 5348 body = bodies[i]; 5349 5350 // calculate the spatial velocity for the next physics state 5351 body->InverseWorldSpatialInertiaMultiply( body->acceleration, body->totalForce.ToFloatPtr() ); 5352 body->next->spatialVelocity = body->current->spatialVelocity + timeStep * body->acceleration.SubVec6(0); 5353 5354 if ( maxLinearVelocity > 0.0f ) { 5355 // cap the linear velocity 5356 vSqr = body->next->spatialVelocity.SubVec3(0).LengthSqr(); 5357 if ( vSqr > Square( maxLinearVelocity ) ) { 5358 body->next->spatialVelocity.SubVec3(0) *= idMath::InvSqrt( vSqr ) * maxLinearVelocity; 5359 } 5360 } 5361 5362 if ( maxAngularVelocity > 0.0f ) { 5363 // cap the angular velocity 5364 vSqr = body->next->spatialVelocity.SubVec3(1).LengthSqr(); 5365 if ( vSqr > Square( maxAngularVelocity ) ) { 5366 body->next->spatialVelocity.SubVec3(1) *= idMath::InvSqrt( vSqr ) * maxAngularVelocity; 5367 } 5368 } 5369 } 5370 5371 // make absolutely sure all contact constraints are satisfied 5372 VerifyContactConstraints(); 5373 5374 // calculate the position of the bodies for the next physics state 5375 for ( i = 0; i < bodies.Num(); i++ ) { 5376 body = bodies[i]; 5377 5378 // translate world origin 5379 body->next->worldOrigin = body->current->worldOrigin + timeStep * body->next->spatialVelocity.SubVec3( 0 ); 5380 5381 // convert angular velocity to a rotation matrix 5382 vec = body->next->spatialVelocity.SubVec3( 1 ); 5383 angle = -timeStep * (float) RAD2DEG( vec.Normalize() ); 5384 rotation = idRotation( vec3_origin, vec, angle ); 5385 rotation.Normalize180(); 5386 5387 // rotate world axis 5388 body->next->worldAxis = body->current->worldAxis * rotation.ToMat3(); 5389 body->next->worldAxis.OrthoNormalizeSelf(); 5390 5391 // linear and angular friction 5392 body->next->spatialVelocity.SubVec3(0) -= body->linearFriction * body->next->spatialVelocity.SubVec3(0); 5393 body->next->spatialVelocity.SubVec3(1) -= body->angularFriction * body->next->spatialVelocity.SubVec3(1); 5394 } 5395 } 5396 5397 /* 5398 ================ 5399 idPhysics_AF::CollisionImpulse 5400 5401 apply impulse to the colliding bodies 5402 the current state of the body should be set to the moment of impact 5403 this is silly as it doesn't take the AF structure into account 5404 ================ 5405 */ 5406 bool idPhysics_AF::CollisionImpulse( float timeStep, idAFBody *body, trace_t &collision ) { 5407 idVec3 r, velocity, impulse; 5408 idMat3 inverseWorldInertiaTensor; 5409 float impulseNumerator, impulseDenominator; 5410 impactInfo_t info; 5411 idEntity *ent; 5412 5413 ent = gameLocal.entities[collision.c.entityNum]; 5414 if ( ent == self ) { 5415 return false; 5416 } 5417 5418 // get info from other entity involved 5419 ent->GetImpactInfo( self, collision.c.id, collision.c.point, &info ); 5420 // collision point relative to the body center of mass 5421 r = collision.c.point - (body->current->worldOrigin + body->centerOfMass * body->current->worldAxis); 5422 // the velocity at the collision point 5423 velocity = body->current->spatialVelocity.SubVec3(0) + body->current->spatialVelocity.SubVec3(1).Cross(r); 5424 // subtract velocity of other entity 5425 velocity -= info.velocity; 5426 // never stick 5427 if ( velocity * collision.c.normal > 0.0f ) { 5428 velocity = collision.c.normal; 5429 } 5430 inverseWorldInertiaTensor = body->current->worldAxis.Transpose() * body->inverseInertiaTensor * body->current->worldAxis; 5431 impulseNumerator = -( 1.0f + body->bouncyness ) * ( velocity * collision.c.normal ); 5432 impulseDenominator = body->invMass + ( ( inverseWorldInertiaTensor * r.Cross( collision.c.normal ) ).Cross( r ) * collision.c.normal ); 5433 if ( info.invMass ) { 5434 impulseDenominator += info.invMass + ( ( info.invInertiaTensor * info.position.Cross( collision.c.normal ) ).Cross( info.position ) * collision.c.normal ); 5435 } 5436 impulse = (impulseNumerator / impulseDenominator) * collision.c.normal; 5437 5438 // apply impact to other entity 5439 ent->ApplyImpulse( self, collision.c.id, collision.c.point, -impulse ); 5440 5441 // callback to self to let the entity know about the impact 5442 return self->Collide( collision, velocity ); 5443 } 5444 5445 /* 5446 ================ 5447 idPhysics_AF::ApplyCollisions 5448 ================ 5449 */ 5450 bool idPhysics_AF::ApplyCollisions( float timeStep ) { 5451 int i; 5452 5453 for ( i = 0; i < collisions.Num(); i++ ) { 5454 if ( CollisionImpulse( timeStep, collisions[i].body, collisions[i].trace ) ) { 5455 return true; 5456 } 5457 } 5458 return false; 5459 } 5460 5461 /* 5462 ================ 5463 idPhysics_AF::SetupCollisionForBody 5464 ================ 5465 */ 5466 idEntity *idPhysics_AF::SetupCollisionForBody( idAFBody *body ) const { 5467 int i; 5468 idAFBody *b; 5469 idEntity *passEntity; 5470 5471 passEntity = NULL; 5472 5473 if ( !selfCollision || !body->fl.selfCollision || af_skipSelfCollision.GetBool() ) { 5474 5475 // disable all bodies 5476 for ( i = 0; i < bodies.Num(); i++ ) { 5477 bodies[i]->clipModel->Disable(); 5478 } 5479 5480 // don't collide with world collision model if attached to the world 5481 for ( i = 0; i < body->constraints.Num(); i++ ) { 5482 if ( !body->constraints[i]->fl.noCollision ) { 5483 continue; 5484 } 5485 // if this constraint attaches the body to the world 5486 if ( body->constraints[i]->body2 == NULL ) { 5487 // don't collide with the world collision model 5488 passEntity = gameLocal.world; 5489 } 5490 } 5491 5492 } else { 5493 5494 // enable all bodies that have self collision 5495 for ( i = 0; i < bodies.Num(); i++ ) { 5496 if ( bodies[i]->fl.selfCollision ) { 5497 bodies[i]->clipModel->Enable(); 5498 } else { 5499 bodies[i]->clipModel->Disable(); 5500 } 5501 } 5502 5503 // don't let the body collide with itself 5504 body->clipModel->Disable(); 5505 5506 // disable any bodies attached with constraints 5507 for ( i = 0; i < body->constraints.Num(); i++ ) { 5508 if ( !body->constraints[i]->fl.noCollision ) { 5509 continue; 5510 } 5511 // if this constraint attaches the body to the world 5512 if ( body->constraints[i]->body2 == NULL ) { 5513 // don't collide with the world collision model 5514 passEntity = gameLocal.world; 5515 } else { 5516 if ( body->constraints[i]->body1 == body ) { 5517 b = body->constraints[i]->body2; 5518 } else if ( body->constraints[i]->body2 == body ) { 5519 b = body->constraints[i]->body1; 5520 } else { 5521 continue; 5522 } 5523 // don't collide with this body 5524 b->clipModel->Disable(); 5525 } 5526 } 5527 } 5528 5529 return passEntity; 5530 } 5531 5532 /* 5533 ================ 5534 idPhysics_AF::CheckForCollisions 5535 5536 check for collisions between the current and next state 5537 if there is a collision the next state is set to the state at the moment of impact 5538 assumes all bodies are linked for collision detection and relinks all bodies after moving them 5539 ================ 5540 */ 5541 void idPhysics_AF::CheckForCollisions( float timeStep ) { 5542 // #define TEST_COLLISION_DETECTION 5543 int i, index; 5544 idAFBody *body; 5545 idMat3 axis; 5546 idRotation rotation; 5547 trace_t collision; 5548 idEntity *passEntity; 5549 5550 // clear list with collisions 5551 collisions.SetNum( 0 ); 5552 5553 if ( !enableCollision ) { 5554 return; 5555 } 5556 5557 for ( i = 0; i < bodies.Num(); i++ ) { 5558 body = bodies[i]; 5559 5560 if ( body->clipMask != 0 ) { 5561 5562 passEntity = SetupCollisionForBody( body ); 5563 5564 #ifdef TEST_COLLISION_DETECTION 5565 bool startsolid = false; 5566 if ( gameLocal.clip.Contents( body->current->worldOrigin, body->clipModel, 5567 body->current->worldAxis, body->clipMask, passEntity ) ) { 5568 startsolid = true; 5569 } 5570 #endif 5571 5572 TransposeMultiply( body->current->worldAxis, body->next->worldAxis, axis ); 5573 rotation = axis.ToRotation(); 5574 rotation.SetOrigin( body->current->worldOrigin ); 5575 5576 // if there was a collision 5577 if ( gameLocal.clip.Motion( collision, body->current->worldOrigin, body->next->worldOrigin, rotation, 5578 body->clipModel, body->current->worldAxis, body->clipMask, passEntity ) ) { 5579 5580 // set the next state to the state at the moment of impact 5581 body->next->worldOrigin = collision.endpos; 5582 body->next->worldAxis = collision.endAxis; 5583 5584 // add collision to the list 5585 index = collisions.Num(); 5586 collisions.SetNum( index + 1 ); 5587 collisions[index].trace = collision; 5588 collisions[index].body = body; 5589 } 5590 5591 #ifdef TEST_COLLISION_DETECTION 5592 if ( gameLocal.clip.Contents( body->next->worldOrigin, body->clipModel, 5593 body->next->worldAxis, body->clipMask, passEntity ) ) { 5594 if ( !startsolid ) { 5595 int bah = 1; 5596 } 5597 } 5598 #endif 5599 } 5600 5601 body->clipModel->Link( gameLocal.clip, self, body->clipModel->GetId(), body->next->worldOrigin, body->next->worldAxis ); 5602 } 5603 } 5604 5605 /* 5606 ================ 5607 idPhysics_AF::EvaluateContacts 5608 ================ 5609 */ 5610 bool idPhysics_AF::EvaluateContacts() { 5611 int i, j, k, numContacts, numBodyContacts; 5612 idAFBody *body; 5613 contactInfo_t contactInfo[10]; 5614 idEntity *passEntity; 5615 idVecX dir( 6, VECX_ALLOCA( 6 ) ); 5616 5617 // evaluate bodies 5618 EvaluateBodies( current.lastTimeStep ); 5619 5620 // remove all existing contacts 5621 ClearContacts(); 5622 5623 contactBodies.SetNum( 0 ); 5624 5625 if ( !enableCollision ) { 5626 return false; 5627 } 5628 5629 // find all the contacts 5630 for ( i = 0; i < bodies.Num(); i++ ) { 5631 body = bodies[i]; 5632 5633 if ( body->clipMask == 0 ) { 5634 continue; 5635 } 5636 5637 passEntity = SetupCollisionForBody( body ); 5638 5639 body->InverseWorldSpatialInertiaMultiply( dir, body->current->externalForce.ToFloatPtr() ); 5640 dir.SubVec6(0) = body->current->spatialVelocity + current.lastTimeStep * dir.SubVec6(0); 5641 dir.SubVec3(0).Normalize(); 5642 dir.SubVec3(1).Normalize(); 5643 5644 numContacts = gameLocal.clip.Contacts( contactInfo, 10, body->current->worldOrigin, dir.SubVec6(0), 2.0f, //CONTACT_EPSILON, 5645 body->clipModel, body->current->worldAxis, body->clipMask, passEntity ); 5646 5647 #if 1 5648 // merge nearby contacts between the same bodies 5649 // and assure there are at most three planar contacts between any pair of bodies 5650 for ( j = 0; j < numContacts; j++ ) { 5651 5652 numBodyContacts = 0; 5653 for ( k = 0; k < contacts.Num(); k++ ) { 5654 if ( contacts[k].entityNum == contactInfo[j].entityNum ) { 5655 if ( ( contacts[k].id == i && contactInfo[j].id == contactBodies[k] ) || 5656 ( contactBodies[k] == i && contacts[k].id == contactInfo[j].id ) ) { 5657 5658 if ( ( contacts[k].point - contactInfo[j].point ).LengthSqr() < Square( 2.0f ) ) { 5659 break; 5660 } 5661 if ( idMath::Fabs( contacts[k].normal * contactInfo[j].normal ) > 0.9f ) { 5662 numBodyContacts++; 5663 } 5664 } 5665 } 5666 } 5667 5668 if ( k >= contacts.Num() && numBodyContacts < 3 ) { 5669 contacts.Append( contactInfo[j] ); 5670 contactBodies.Append( i ); 5671 } 5672 } 5673 5674 #else 5675 5676 for ( j = 0; j < numContacts; j++ ) { 5677 contacts.Append( contactInfo[j] ); 5678 contactBodies.Append( i ); 5679 } 5680 #endif 5681 5682 } 5683 5684 AddContactEntitiesForContacts(); 5685 5686 return ( contacts.Num() != 0 ); 5687 } 5688 5689 /* 5690 ================ 5691 idPhysics_AF::SetupContactConstraints 5692 ================ 5693 */ 5694 void idPhysics_AF::SetupContactConstraints() { 5695 int i; 5696 5697 // make sure enough contact constraints are allocated 5698 contactConstraints.AssureSizeAlloc( contacts.Num(), idListNewElement<idAFConstraint_Contact> ); 5699 contactConstraints.SetNum( contacts.Num() ); 5700 5701 // setup contact constraints 5702 for ( i = 0; i < contacts.Num(); i++ ) { 5703 // add contact constraint 5704 contactConstraints[i]->physics = this; 5705 if ( contacts[i].entityNum == self->entityNumber ) { 5706 contactConstraints[i]->Setup( bodies[contactBodies[i]], bodies[ contacts[i].id ], contacts[i] ); 5707 } 5708 else { 5709 contactConstraints[i]->Setup( bodies[contactBodies[i]], NULL, contacts[i] ); 5710 } 5711 } 5712 } 5713 5714 /* 5715 ================ 5716 idPhysics_AF::ApplyContactForces 5717 ================ 5718 */ 5719 void idPhysics_AF::ApplyContactForces() { 5720 #if 0 5721 int i; 5722 idEntity *ent; 5723 idVec3 force; 5724 5725 for ( i = 0; i < contactConstraints.Num(); i++ ) { 5726 if ( contactConstraints[i]->body2 != NULL ) { 5727 continue; 5728 } 5729 const contactInfo_t &contact = contactConstraints[i]->GetContact(); 5730 ent = gameLocal.entities[contact.entityNum]; 5731 if ( !ent ) { 5732 continue; 5733 } 5734 force.Zero(); 5735 ent->AddForce( self, contact.id, contact.point, force ); 5736 } 5737 #endif 5738 } 5739 5740 /* 5741 ================ 5742 idPhysics_AF::ClearExternalForce 5743 ================ 5744 */ 5745 void idPhysics_AF::ClearExternalForce() { 5746 int i; 5747 idAFBody *body; 5748 5749 for ( i = 0; i < bodies.Num(); i++ ) { 5750 body = bodies[i]; 5751 5752 // clear external force 5753 body->current->externalForce.Zero(); 5754 body->next->externalForce.Zero(); 5755 } 5756 } 5757 5758 /* 5759 ================ 5760 idPhysics_AF::AddGravity 5761 ================ 5762 */ 5763 void idPhysics_AF::AddGravity() { 5764 int i; 5765 idAFBody *body; 5766 5767 for ( i = 0; i < bodies.Num(); i++ ) { 5768 body = bodies[i]; 5769 // add gravitational force 5770 body->current->externalForce.SubVec3( 0 ) += body->mass * gravityVector; 5771 } 5772 } 5773 5774 /* 5775 ================ 5776 idPhysics_AF::SwapStates 5777 ================ 5778 */ 5779 void idPhysics_AF::SwapStates() { 5780 int i; 5781 idAFBody *body; 5782 AFBodyPState_t *swap; 5783 5784 for ( i = 0; i < bodies.Num(); i++ ) { 5785 5786 body = bodies[i]; 5787 5788 // swap the current and next state for next simulation step 5789 swap = body->current; 5790 body->current = body->next; 5791 body->next = swap; 5792 } 5793 } 5794 5795 /* 5796 ================ 5797 idPhysics_AF::UpdateClipModels 5798 ================ 5799 */ 5800 void idPhysics_AF::UpdateClipModels() { 5801 int i; 5802 idAFBody *body; 5803 5804 for ( i = 0; i < bodies.Num(); i++ ) { 5805 body = bodies[i]; 5806 body->clipModel->Link( gameLocal.clip, self, body->clipModel->GetId(), body->current->worldOrigin, body->current->worldAxis ); 5807 } 5808 } 5809 5810 /* 5811 ================ 5812 idPhysics_AF::SetSuspendSpeed 5813 ================ 5814 */ 5815 void idPhysics_AF::SetSuspendSpeed( const idVec2 &velocity, const idVec2 &acceleration ) { 5816 this->suspendVelocity = velocity; 5817 this->suspendAcceleration = acceleration; 5818 } 5819 5820 /* 5821 ================ 5822 idPhysics_AF::SetSuspendTime 5823 ================ 5824 */ 5825 void idPhysics_AF::SetSuspendTime( const float minTime, const float maxTime ) { 5826 this->minMoveTime = minTime; 5827 this->maxMoveTime = maxTime; 5828 } 5829 5830 /* 5831 ================ 5832 idPhysics_AF::SetSuspendTolerance 5833 ================ 5834 */ 5835 void idPhysics_AF::SetSuspendTolerance( const float noMoveTime, const float noMoveTranslation, const float noMoveRotation ) { 5836 this->noMoveTime = noMoveTime; 5837 this->noMoveTranslation = noMoveTranslation; 5838 this->noMoveRotation = noMoveRotation; 5839 } 5840 5841 /* 5842 ================ 5843 idPhysics_AF::SetTimeScaleRamp 5844 ================ 5845 */ 5846 void idPhysics_AF::SetTimeScaleRamp( const float start, const float end ) { 5847 timeScaleRampStart = start; 5848 timeScaleRampEnd = end; 5849 } 5850 5851 /* 5852 ================ 5853 idPhysics_AF::SetJointFrictionDent 5854 ================ 5855 */ 5856 void idPhysics_AF::SetJointFrictionDent( const float dent, const float start, const float end ) { 5857 jointFrictionDent = dent; 5858 jointFrictionDentStart = start; 5859 jointFrictionDentEnd = end; 5860 } 5861 5862 /* 5863 ================ 5864 idPhysics_AF::GetJointFrictionScale 5865 ================ 5866 */ 5867 float idPhysics_AF::GetJointFrictionScale() const { 5868 if ( jointFrictionDentScale > 0.0f ) { 5869 return jointFrictionDentScale; 5870 } else if ( jointFrictionScale > 0.0f ) { 5871 return jointFrictionScale; 5872 } else if ( af_jointFrictionScale.GetFloat() > 0.0f ) { 5873 return af_jointFrictionScale.GetFloat(); 5874 } 5875 return 1.0f; 5876 } 5877 5878 /* 5879 ================ 5880 idPhysics_AF::SetContactFrictionDent 5881 ================ 5882 */ 5883 void idPhysics_AF::SetContactFrictionDent( const float dent, const float start, const float end ) { 5884 contactFrictionDent = dent; 5885 contactFrictionDentStart = start; 5886 contactFrictionDentEnd = end; 5887 } 5888 5889 /* 5890 ================ 5891 idPhysics_AF::GetContactFrictionScale 5892 ================ 5893 */ 5894 float idPhysics_AF::GetContactFrictionScale() const { 5895 if ( contactFrictionDentScale > 0.0f ) { 5896 return contactFrictionDentScale; 5897 } else if ( contactFrictionScale > 0.0f ) { 5898 return contactFrictionScale; 5899 } else if ( af_contactFrictionScale.GetFloat() > 0.0f ) { 5900 return af_contactFrictionScale.GetFloat(); 5901 } 5902 return 1.0f; 5903 } 5904 5905 /* 5906 ================ 5907 idPhysics_AF::TestIfAtRest 5908 ================ 5909 */ 5910 bool idPhysics_AF::TestIfAtRest( float timeStep ) { 5911 int i; 5912 float translationSqr, maxTranslationSqr, rotation, maxRotation; 5913 idAFBody *body; 5914 5915 if ( current.atRest >= 0 ) { 5916 return true; 5917 } 5918 5919 current.activateTime += timeStep; 5920 5921 // if the simulation should never be suspended before a certaint amount of time passed 5922 if ( minMoveTime > 0.0f && current.activateTime < minMoveTime ) { 5923 return false; 5924 } 5925 5926 // if the simulation should always be suspended after a certain amount time passed 5927 if ( maxMoveTime > 0.0f && current.activateTime > maxMoveTime ) { 5928 return true; 5929 } 5930 5931 // test if all bodies hardly moved over a period of time 5932 if ( current.noMoveTime == 0.0f ) { 5933 for ( i = 0; i < bodies.Num(); i++ ) { 5934 body = bodies[i]; 5935 body->atRestOrigin = body->current->worldOrigin; 5936 body->atRestAxis = body->current->worldAxis; 5937 } 5938 current.noMoveTime += timeStep; 5939 } 5940 else if ( current.noMoveTime > noMoveTime ) { 5941 current.noMoveTime = 0.0f; 5942 maxTranslationSqr = 0.0f; 5943 maxRotation = 0.0f; 5944 for ( i = 0; i < bodies.Num(); i++ ) { 5945 body = bodies[i]; 5946 5947 translationSqr = ( body->current->worldOrigin - body->atRestOrigin ).LengthSqr(); 5948 if ( translationSqr > maxTranslationSqr ) { 5949 maxTranslationSqr = translationSqr; 5950 } 5951 rotation = ( body->atRestAxis.Transpose() * body->current->worldAxis ).ToRotation().GetAngle(); 5952 if ( rotation > maxRotation ) { 5953 maxRotation = rotation; 5954 } 5955 } 5956 5957 if ( maxTranslationSqr < Square( noMoveTranslation ) && maxRotation < noMoveRotation ) { 5958 // hardly moved over a period of time so the articulated figure may come to rest 5959 return true; 5960 } 5961 } else { 5962 current.noMoveTime += timeStep; 5963 } 5964 5965 // test if the velocity or acceleration of any body is still too large to come to rest 5966 for ( i = 0; i < bodies.Num(); i++ ) { 5967 body = bodies[i]; 5968 5969 if ( body->current->spatialVelocity.SubVec3(0).LengthSqr() > Square( suspendVelocity[0] ) ) { 5970 return false; 5971 } 5972 if ( body->current->spatialVelocity.SubVec3(1).LengthSqr() > Square( suspendVelocity[1] ) ) { 5973 return false; 5974 } 5975 if ( body->acceleration.SubVec3(0).LengthSqr() > Square( suspendAcceleration[0] ) ) { 5976 return false; 5977 } 5978 if ( body->acceleration.SubVec3(1).LengthSqr() > Square( suspendAcceleration[1] ) ) { 5979 return false; 5980 } 5981 } 5982 5983 // all bodies have a velocity and acceleration small enough to come to rest 5984 return true; 5985 } 5986 5987 /* 5988 ================ 5989 idPhysics_AF::Rest 5990 ================ 5991 */ 5992 void idPhysics_AF::Rest() { 5993 int i; 5994 5995 current.atRest = gameLocal.time; 5996 5997 for ( i = 0; i < bodies.Num(); i++ ) { 5998 bodies[i]->current->spatialVelocity.Zero(); 5999 bodies[i]->current->externalForce.Zero(); 6000 } 6001 6002 self->BecomeInactive( TH_PHYSICS ); 6003 } 6004 6005 /* 6006 ================ 6007 idPhysics_AF::Activate 6008 ================ 6009 */ 6010 void idPhysics_AF::Activate() { 6011 // if the articulated figure was at rest 6012 if ( current.atRest >= 0 ) { 6013 // normally gravity is added at the end of a simulation frame 6014 // if the figure was at rest add gravity here so it is applied this simulation frame 6015 AddGravity(); 6016 // reset the active time for the max move time 6017 current.activateTime = 0.0f; 6018 } 6019 current.atRest = -1; 6020 current.noMoveTime = 0.0f; 6021 self->BecomeActive( TH_PHYSICS ); 6022 } 6023 6024 /* 6025 ================ 6026 idPhysics_AF::PutToRest 6027 6028 put to rest untill something collides with this physics object 6029 ================ 6030 */ 6031 void idPhysics_AF::PutToRest() { 6032 Rest(); 6033 } 6034 6035 /* 6036 ================ 6037 idPhysics_AF::EnableImpact 6038 ================ 6039 */ 6040 void idPhysics_AF::EnableImpact() { 6041 noImpact = false; 6042 } 6043 6044 /* 6045 ================ 6046 idPhysics_AF::DisableImpact 6047 ================ 6048 */ 6049 void idPhysics_AF::DisableImpact() { 6050 noImpact = true; 6051 } 6052 6053 /* 6054 ================ 6055 idPhysics_AF::AddPushVelocity 6056 ================ 6057 */ 6058 void idPhysics_AF::AddPushVelocity( const idVec6 &pushVelocity ) { 6059 int i; 6060 6061 if ( pushVelocity != vec6_origin ) { 6062 for ( i = 0; i < bodies.Num(); i++ ) { 6063 bodies[i]->current->spatialVelocity += pushVelocity; 6064 } 6065 } 6066 } 6067 6068 /* 6069 ================ 6070 idPhysics_AF::SetClipModel 6071 ================ 6072 */ 6073 void idPhysics_AF::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { 6074 } 6075 6076 /* 6077 ================ 6078 idPhysics_AF::GetClipModel 6079 ================ 6080 */ 6081 idClipModel *idPhysics_AF::GetClipModel( int id ) const { 6082 if ( id >= 0 && id < bodies.Num() ) { 6083 return bodies[id]->GetClipModel(); 6084 } 6085 return NULL; 6086 } 6087 6088 /* 6089 ================ 6090 idPhysics_AF::GetNumClipModels 6091 ================ 6092 */ 6093 int idPhysics_AF::GetNumClipModels() const { 6094 return bodies.Num(); 6095 } 6096 6097 /* 6098 ================ 6099 idPhysics_AF::SetMass 6100 ================ 6101 */ 6102 void idPhysics_AF::SetMass( float mass, int id ) { 6103 if ( id >= 0 && id < bodies.Num() ) { 6104 } 6105 else { 6106 forceTotalMass = mass; 6107 } 6108 SetChanged(); 6109 } 6110 6111 /* 6112 ================ 6113 idPhysics_AF::GetMass 6114 ================ 6115 */ 6116 float idPhysics_AF::GetMass( int id ) const { 6117 if ( id >= 0 && id < bodies.Num() ) { 6118 return bodies[id]->mass; 6119 } 6120 return totalMass; 6121 } 6122 6123 /* 6124 ================ 6125 idPhysics_AF::SetContents 6126 ================ 6127 */ 6128 void idPhysics_AF::SetContents( int contents, int id ) { 6129 int i; 6130 6131 if ( id >= 0 && id < bodies.Num() ) { 6132 bodies[id]->GetClipModel()->SetContents( contents ); 6133 } 6134 else { 6135 for ( i = 0; i < bodies.Num(); i++ ) { 6136 bodies[i]->GetClipModel()->SetContents( contents ); 6137 } 6138 } 6139 } 6140 6141 /* 6142 ================ 6143 idPhysics_AF::GetContents 6144 ================ 6145 */ 6146 int idPhysics_AF::GetContents( int id ) const { 6147 int i, contents; 6148 6149 if ( id >= 0 && id < bodies.Num() ) { 6150 return bodies[id]->GetClipModel()->GetContents(); 6151 } 6152 else { 6153 contents = 0; 6154 for ( i = 0; i < bodies.Num(); i++ ) { 6155 contents |= bodies[i]->GetClipModel()->GetContents(); 6156 } 6157 return contents; 6158 } 6159 } 6160 6161 /* 6162 ================ 6163 idPhysics_AF::GetBounds 6164 ================ 6165 */ 6166 const idBounds &idPhysics_AF::GetBounds( int id ) const { 6167 int i; 6168 static idBounds relBounds; 6169 6170 if ( id >= 0 && id < bodies.Num() ) { 6171 return bodies[id]->GetClipModel()->GetBounds(); 6172 } 6173 else if ( !bodies.Num() ) { 6174 relBounds.Zero(); 6175 return relBounds; 6176 } 6177 else { 6178 relBounds = bodies[0]->GetClipModel()->GetBounds(); 6179 for ( i = 1; i < bodies.Num(); i++ ) { 6180 idBounds bounds; 6181 idVec3 origin = ( bodies[i]->GetWorldOrigin() - bodies[0]->GetWorldOrigin() ) * bodies[0]->GetWorldAxis().Transpose(); 6182 idMat3 axis = bodies[i]->GetWorldAxis() * bodies[0]->GetWorldAxis().Transpose(); 6183 bounds.FromTransformedBounds( bodies[i]->GetClipModel()->GetBounds(), origin, axis ); 6184 relBounds += bounds; 6185 } 6186 return relBounds; 6187 } 6188 } 6189 6190 /* 6191 ================ 6192 idPhysics_AF::GetAbsBounds 6193 ================ 6194 */ 6195 const idBounds &idPhysics_AF::GetAbsBounds( int id ) const { 6196 int i; 6197 static idBounds absBounds; 6198 6199 if ( id >= 0 && id < bodies.Num() ) { 6200 return bodies[id]->GetClipModel()->GetAbsBounds(); 6201 } 6202 else if ( !bodies.Num() ) { 6203 absBounds.Zero(); 6204 return absBounds; 6205 } 6206 else { 6207 absBounds = bodies[0]->GetClipModel()->GetAbsBounds(); 6208 for ( i = 1; i < bodies.Num(); i++ ) { 6209 absBounds += bodies[i]->GetClipModel()->GetAbsBounds(); 6210 } 6211 return absBounds; 6212 } 6213 } 6214 6215 /* 6216 ================ 6217 idPhysics_AF::Evaluate 6218 ================ 6219 */ 6220 bool idPhysics_AF::Evaluate( int timeStepMSec, int endTimeMSec ) { 6221 float timeStep; 6222 6223 if ( timeScaleRampStart < MS2SEC( endTimeMSec ) && timeScaleRampEnd > MS2SEC( endTimeMSec ) ) { 6224 timeStep = MS2SEC( timeStepMSec ) * ( MS2SEC( endTimeMSec ) - timeScaleRampStart ) / ( timeScaleRampEnd - timeScaleRampStart ); 6225 } else if ( af_timeScale.GetFloat() != 1.0f ) { 6226 timeStep = MS2SEC( timeStepMSec ) * af_timeScale.GetFloat(); 6227 } else { 6228 timeStep = MS2SEC( timeStepMSec ) * timeScale; 6229 } 6230 current.lastTimeStep = timeStep; 6231 6232 6233 // if the articulated figure changed 6234 if ( changedAF || ( linearTime != af_useLinearTime.GetBool() ) ) { 6235 BuildTrees(); 6236 changedAF = false; 6237 linearTime = af_useLinearTime.GetBool(); 6238 } 6239 6240 // get the new master position 6241 if ( masterBody ) { 6242 idVec3 masterOrigin; 6243 idMat3 masterAxis; 6244 self->GetMasterPosition( masterOrigin, masterAxis ); 6245 if ( current.atRest >= 0 && ( masterBody->current->worldOrigin != masterOrigin || masterBody->current->worldAxis != masterAxis ) ) { 6246 Activate(); 6247 } 6248 masterBody->current->worldOrigin = masterOrigin; 6249 masterBody->current->worldAxis = masterAxis; 6250 } 6251 6252 // if the simulation is suspended because the figure is at rest 6253 if ( current.atRest >= 0 || timeStep <= 0.0f ) { 6254 DebugDraw(); 6255 return false; 6256 } 6257 6258 // move the af velocity into the frame of a pusher 6259 AddPushVelocity( -current.pushVelocity ); 6260 6261 #ifdef AF_TIMINGS 6262 timer_total.Start(); 6263 #endif 6264 6265 #ifdef AF_TIMINGS 6266 timer_collision.Start(); 6267 #endif 6268 6269 // evaluate contacts 6270 EvaluateContacts(); 6271 6272 // setup contact constraints 6273 SetupContactConstraints(); 6274 6275 #ifdef AF_TIMINGS 6276 timer_collision.Stop(); 6277 #endif 6278 6279 // evaluate constraint equations 6280 EvaluateConstraints( timeStep ); 6281 6282 // apply friction 6283 ApplyFriction( timeStep, endTimeMSec ); 6284 6285 // add frame constraints 6286 AddFrameConstraints(); 6287 6288 #ifdef AF_TIMINGS 6289 int i, numPrimary = 0, numAuxiliary = 0; 6290 for ( i = 0; i < primaryConstraints.Num(); i++ ) { 6291 numPrimary += primaryConstraints[i]->J1.GetNumRows(); 6292 } 6293 for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { 6294 numAuxiliary += auxiliaryConstraints[i]->J1.GetNumRows(); 6295 } 6296 timer_pc.Start(); 6297 #endif 6298 6299 // factor matrices for primary constraints 6300 PrimaryFactor(); 6301 6302 // calculate forces on bodies after applying primary constraints 6303 PrimaryForces( timeStep ); 6304 6305 #ifdef AF_TIMINGS 6306 timer_pc.Stop(); 6307 timer_ac.Start(); 6308 #endif 6309 6310 // calculate and apply auxiliary constraint forces 6311 AuxiliaryForces( timeStep ); 6312 6313 #ifdef AF_TIMINGS 6314 timer_ac.Stop(); 6315 #endif 6316 6317 // evolve current state to next state 6318 Evolve( timeStep ); 6319 6320 // debug graphics 6321 DebugDraw(); 6322 6323 // clear external forces on all bodies 6324 ClearExternalForce(); 6325 6326 // apply contact force to other entities 6327 ApplyContactForces(); 6328 6329 // remove all frame constraints 6330 RemoveFrameConstraints(); 6331 6332 #ifdef AF_TIMINGS 6333 timer_collision.Start(); 6334 #endif 6335 6336 // check for collisions between current and next state 6337 CheckForCollisions( timeStep ); 6338 6339 #ifdef AF_TIMINGS 6340 timer_collision.Stop(); 6341 #endif 6342 6343 // swap the current and next state 6344 SwapStates(); 6345 6346 // make sure all clip models are disabled in case they were enabled for self collision 6347 if ( selfCollision && !af_skipSelfCollision.GetBool() ) { 6348 DisableClip(); 6349 } 6350 6351 // apply collision impulses 6352 if ( ApplyCollisions( timeStep ) ) { 6353 current.atRest = gameLocal.time; 6354 comeToRest = true; 6355 } 6356 6357 // test if the simulation can be suspended because the whole figure is at rest 6358 if ( comeToRest && TestIfAtRest( timeStep ) ) { 6359 Rest(); 6360 } else { 6361 ActivateContactEntities(); 6362 } 6363 6364 // add gravitational force 6365 AddGravity(); 6366 6367 // move the af velocity back into the world frame 6368 AddPushVelocity( current.pushVelocity ); 6369 current.pushVelocity.Zero(); 6370 6371 if ( IsOutsideWorld() ) { 6372 gameLocal.Warning( "articulated figure moved outside world bounds for entity '%s' type '%s' at (%s)", 6373 self->name.c_str(), self->GetType()->classname, bodies[0]->current->worldOrigin.ToString(0) ); 6374 Rest(); 6375 } 6376 6377 #ifdef AF_TIMINGS 6378 timer_total.Stop(); 6379 6380 if ( af_showTimings.GetInteger() == 1 ) { 6381 gameLocal.Printf( "%12s: t %1.4f pc %2d, %1.4f ac %2d %1.4f lcp %1.4f cd %1.4f\n", 6382 self->name.c_str(), 6383 timer_total.Milliseconds(), 6384 numPrimary, timer_pc.Milliseconds(), 6385 numAuxiliary, timer_ac.Milliseconds() - timer_lcp.Milliseconds(), 6386 timer_lcp.Milliseconds(), timer_collision.Milliseconds() ); 6387 } 6388 else if ( af_showTimings.GetInteger() == 2 ) { 6389 numArticulatedFigures++; 6390 if ( endTimeMSec > lastTimerReset ) { 6391 gameLocal.Printf( "af %d: t %1.4f pc %2d, %1.4f ac %2d %1.4f lcp %1.4f cd %1.4f\n", 6392 numArticulatedFigures, 6393 timer_total.Milliseconds(), 6394 numPrimary, timer_pc.Milliseconds(), 6395 numAuxiliary, timer_ac.Milliseconds() - timer_lcp.Milliseconds(), 6396 timer_lcp.Milliseconds(), timer_collision.Milliseconds() ); 6397 } 6398 } 6399 6400 if ( endTimeMSec > lastTimerReset ) { 6401 lastTimerReset = endTimeMSec; 6402 numArticulatedFigures = 0; 6403 timer_total.Clear(); 6404 timer_pc.Clear(); 6405 timer_ac.Clear(); 6406 timer_collision.Clear(); 6407 timer_lcp.Clear(); 6408 } 6409 #endif 6410 6411 return true; 6412 } 6413 6414 /* 6415 ================ 6416 idPhysics_AF::UpdateTime 6417 ================ 6418 */ 6419 void idPhysics_AF::UpdateTime( int endTimeMSec ) { 6420 } 6421 6422 /* 6423 ================ 6424 idPhysics_AF::GetTime 6425 ================ 6426 */ 6427 int idPhysics_AF::GetTime() const { 6428 return gameLocal.time; 6429 } 6430 6431 /* 6432 ================ 6433 DrawTraceModelSilhouette 6434 ================ 6435 */ 6436 void DrawTraceModelSilhouette( const idVec3 &projectionOrigin, const idClipModel *clipModel ) { 6437 int i, numSilEdges; 6438 int silEdges[MAX_TRACEMODEL_EDGES]; 6439 idVec3 v1, v2; 6440 const idTraceModel *trm = clipModel->GetTraceModel(); 6441 const idVec3 &origin = clipModel->GetOrigin(); 6442 const idMat3 &axis = clipModel->GetAxis(); 6443 6444 numSilEdges = trm->GetProjectionSilhouetteEdges( ( projectionOrigin - origin ) * axis.Transpose(), silEdges ); 6445 for ( i = 0; i < numSilEdges; i++ ) { 6446 v1 = trm->verts[ trm->edges[ abs(silEdges[i]) ].v[ INT32_SIGNBITSET( silEdges[i] ) ] ]; 6447 v2 = trm->verts[ trm->edges[ abs(silEdges[i]) ].v[ INT32_SIGNBITNOTSET( silEdges[i] ) ] ]; 6448 gameRenderWorld->DebugArrow( colorRed, origin + v1 * axis, origin + v2 * axis, 1 ); 6449 } 6450 } 6451 6452 /* 6453 ================ 6454 idPhysics_AF::DebugDraw 6455 ================ 6456 */ 6457 void idPhysics_AF::DebugDraw() { 6458 int i; 6459 idAFBody *body, *highlightBody = NULL, *constrainedBody1 = NULL, *constrainedBody2 = NULL; 6460 idAFConstraint *constraint; 6461 idVec3 center; 6462 idMat3 axis; 6463 6464 if ( af_highlightConstraint.GetString()[0] ) { 6465 constraint = GetConstraint( af_highlightConstraint.GetString() ); 6466 if ( constraint ) { 6467 constraint->GetCenter( center ); 6468 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3(); 6469 gameRenderWorld->DebugCone( colorYellow, center, (axis[2] - axis[1]) * 4.0f, 0.0f, 1.0f, 0 ); 6470 6471 if ( af_showConstrainedBodies.GetBool() ) { 6472 cvarSystem->SetCVarString( "cm_drawColor", colorCyan.ToString( 0 ) ); 6473 constrainedBody1 = constraint->body1; 6474 if ( constrainedBody1 ) { 6475 collisionModelManager->DrawModel( constrainedBody1->clipModel->Handle(), constrainedBody1->clipModel->GetOrigin(), 6476 constrainedBody1->clipModel->GetAxis(), vec3_origin, 0.0f ); 6477 } 6478 cvarSystem->SetCVarString( "cm_drawColor", colorBlue.ToString( 0 ) ); 6479 constrainedBody2 = constraint->body2; 6480 if ( constrainedBody2 ) { 6481 collisionModelManager->DrawModel( constrainedBody2->clipModel->Handle(), constrainedBody2->clipModel->GetOrigin(), 6482 constrainedBody2->clipModel->GetAxis(), vec3_origin, 0.0f ); 6483 } 6484 cvarSystem->SetCVarString( "cm_drawColor", colorRed.ToString( 0 ) ); 6485 } 6486 } 6487 } 6488 6489 if ( af_highlightBody.GetString()[0] ) { 6490 highlightBody = GetBody( af_highlightBody.GetString() ); 6491 if ( highlightBody ) { 6492 cvarSystem->SetCVarString( "cm_drawColor", colorYellow.ToString( 0 ) ); 6493 collisionModelManager->DrawModel( highlightBody->clipModel->Handle(), highlightBody->clipModel->GetOrigin(), 6494 highlightBody->clipModel->GetAxis(), vec3_origin, 0.0f ); 6495 cvarSystem->SetCVarString( "cm_drawColor", colorRed.ToString( 0 ) ); 6496 } 6497 } 6498 6499 if ( af_showBodies.GetBool() ) { 6500 for ( i = 0; i < bodies.Num(); i++ ) { 6501 body = bodies[i]; 6502 if ( body == constrainedBody1 || body == constrainedBody2 ) { 6503 continue; 6504 } 6505 if ( body == highlightBody ) { 6506 continue; 6507 } 6508 collisionModelManager->DrawModel( body->clipModel->Handle(), body->clipModel->GetOrigin(), 6509 body->clipModel->GetAxis(), vec3_origin, 0.0f ); 6510 //DrawTraceModelSilhouette( gameLocal.GetLocalPlayer()->GetEyePosition(), body->clipModel ); 6511 } 6512 } 6513 6514 if ( af_showBodyNames.GetBool() ) { 6515 for ( i = 0; i < bodies.Num(); i++ ) { 6516 body = bodies[i]; 6517 gameRenderWorld->DrawText( body->GetName().c_str(), body->GetWorldOrigin(), 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); 6518 } 6519 } 6520 6521 if ( af_showMass.GetBool() ) { 6522 for ( i = 0; i < bodies.Num(); i++ ) { 6523 body = bodies[i]; 6524 gameRenderWorld->DrawText( va( "\n%1.2f", 1.0f / body->GetInverseMass() ), body->GetWorldOrigin(), 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); 6525 } 6526 } 6527 6528 if ( af_showTotalMass.GetBool() ) { 6529 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3(); 6530 gameRenderWorld->DrawText( va( "\n%1.2f", totalMass ), bodies[0]->GetWorldOrigin() + axis[2] * 8.0f, 0.15f, colorCyan, axis, 1 ); 6531 } 6532 6533 if ( af_showInertia.GetBool() ) { 6534 for ( i = 0; i < bodies.Num(); i++ ) { 6535 body = bodies[i]; 6536 idMat3 &I = body->inertiaTensor; 6537 gameRenderWorld->DrawText( va( "\n\n\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )\n( %.1f %.1f %.1f )", 6538 I[0].x, I[0].y, I[0].z, 6539 I[1].x, I[1].y, I[1].z, 6540 I[2].x, I[2].y, I[2].z ), 6541 body->GetWorldOrigin(), 0.05f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); 6542 } 6543 } 6544 6545 if ( af_showVelocity.GetBool() ) { 6546 for ( i = 0; i < bodies.Num(); i++ ) { 6547 DrawVelocity( bodies[i]->clipModel->GetId(), 0.1f, 4.0f ); 6548 } 6549 } 6550 6551 if ( af_showConstraints.GetBool() ) { 6552 for ( i = 0; i < primaryConstraints.Num(); i++ ) { 6553 constraint = primaryConstraints[i]; 6554 constraint->DebugDraw(); 6555 } 6556 if ( !af_showPrimaryOnly.GetBool() ) { 6557 for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { 6558 constraint = auxiliaryConstraints[i]; 6559 constraint->DebugDraw(); 6560 } 6561 } 6562 } 6563 6564 if ( af_showConstraintNames.GetBool() ) { 6565 for ( i = 0; i < primaryConstraints.Num(); i++ ) { 6566 constraint = primaryConstraints[i]; 6567 constraint->GetCenter( center ); 6568 gameRenderWorld->DrawText( constraint->GetName().c_str(), center, 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); 6569 } 6570 if ( !af_showPrimaryOnly.GetBool() ) { 6571 for ( i = 0; i < auxiliaryConstraints.Num(); i++ ) { 6572 constraint = auxiliaryConstraints[i]; 6573 constraint->GetCenter( center ); 6574 gameRenderWorld->DrawText( constraint->GetName().c_str(), center, 0.08f, colorCyan, gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), 1 ); 6575 } 6576 } 6577 } 6578 6579 if ( af_showTrees.GetBool() || ( af_showActive.GetBool() && current.atRest < 0 ) ) { 6580 for ( i = 0; i < trees.Num(); i++ ) { 6581 trees[i]->DebugDraw( idStr::ColorForIndex( i+3 ) ); 6582 } 6583 } 6584 } 6585 6586 /* 6587 ================ 6588 idPhysics_AF::idPhysics_AF 6589 ================ 6590 */ 6591 idPhysics_AF::idPhysics_AF() { 6592 trees.Clear(); 6593 bodies.Clear(); 6594 constraints.Clear(); 6595 primaryConstraints.Clear(); 6596 auxiliaryConstraints.Clear(); 6597 frameConstraints.Clear(); 6598 contacts.Clear(); 6599 collisions.Clear(); 6600 changedAF = true; 6601 masterBody = NULL; 6602 6603 lcp = idLCP::AllocSymmetric(); 6604 6605 memset( ¤t, 0, sizeof( current ) ); 6606 current.atRest = -1; 6607 current.lastTimeStep = 0.0f; 6608 saved = current; 6609 6610 linearFriction = 0.005f; 6611 angularFriction = 0.005f; 6612 contactFriction = 0.8f; 6613 bouncyness = 0.4f; 6614 totalMass = 0.0f; 6615 forceTotalMass = -1.0f; 6616 6617 suspendVelocity.Set( SUSPEND_LINEAR_VELOCITY, SUSPEND_ANGULAR_VELOCITY ); 6618 suspendAcceleration.Set( SUSPEND_LINEAR_ACCELERATION, SUSPEND_LINEAR_ACCELERATION ); 6619 noMoveTime = NO_MOVE_TIME; 6620 noMoveTranslation = NO_MOVE_TRANSLATION_TOLERANCE; 6621 noMoveRotation = NO_MOVE_ROTATION_TOLERANCE; 6622 minMoveTime = MIN_MOVE_TIME; 6623 maxMoveTime = MAX_MOVE_TIME; 6624 impulseThreshold = IMPULSE_THRESHOLD; 6625 6626 timeScale = 1.0f; 6627 timeScaleRampStart = 0.0f; 6628 timeScaleRampEnd = 0.0f; 6629 6630 jointFrictionScale = 0.0f; 6631 jointFrictionDent = 0.0f; 6632 jointFrictionDentStart = 0.0f; 6633 jointFrictionDentEnd = 0.0f; 6634 jointFrictionDentScale = 0.0f; 6635 6636 contactFrictionScale = 0.0f; 6637 contactFrictionDent = 0.0f; 6638 contactFrictionDentStart = 0.0f; 6639 contactFrictionDentEnd = 0.0f; 6640 contactFrictionDentScale = 0.0f; 6641 6642 enableCollision = true; 6643 selfCollision = true; 6644 comeToRest = true; 6645 linearTime = true; 6646 noImpact = false; 6647 worldConstraintsLocked = false; 6648 forcePushable = false; 6649 6650 #ifdef AF_TIMINGS 6651 lastTimerReset = 0; 6652 #endif 6653 } 6654 6655 /* 6656 ================ 6657 idPhysics_AF::~idPhysics_AF 6658 ================ 6659 */ 6660 idPhysics_AF::~idPhysics_AF() { 6661 int i; 6662 6663 trees.DeleteContents( true ); 6664 6665 for ( i = 0; i < bodies.Num(); i++ ) { 6666 delete bodies[i]; 6667 } 6668 6669 for ( i = 0; i < constraints.Num(); i++ ) { 6670 delete constraints[i]; 6671 } 6672 6673 contactConstraints.SetNum( contactConstraints.NumAllocated() ); 6674 for ( i = 0; i < contactConstraints.Num(); i++ ) { 6675 delete contactConstraints[i]; 6676 } 6677 6678 delete lcp; 6679 6680 if ( masterBody ) { 6681 delete masterBody; 6682 } 6683 } 6684 6685 /* 6686 ================ 6687 idPhysics_AF_SavePState 6688 ================ 6689 */ 6690 void idPhysics_AF_SavePState( idSaveGame *saveFile, const AFPState_t &state ) { 6691 saveFile->WriteInt( state.atRest ); 6692 saveFile->WriteFloat( state.noMoveTime ); 6693 saveFile->WriteFloat( state.activateTime ); 6694 saveFile->WriteFloat( state.lastTimeStep ); 6695 saveFile->WriteVec6( state.pushVelocity ); 6696 } 6697 6698 /* 6699 ================ 6700 idPhysics_AF_RestorePState 6701 ================ 6702 */ 6703 void idPhysics_AF_RestorePState( idRestoreGame *saveFile, AFPState_t &state ) { 6704 saveFile->ReadInt( state.atRest ); 6705 saveFile->ReadFloat( state.noMoveTime ); 6706 saveFile->ReadFloat( state.activateTime ); 6707 saveFile->ReadFloat( state.lastTimeStep ); 6708 saveFile->ReadVec6( state.pushVelocity ); 6709 } 6710 6711 /* 6712 ================ 6713 idPhysics_AF::Save 6714 ================ 6715 */ 6716 void idPhysics_AF::Save( idSaveGame *saveFile ) const { 6717 int i; 6718 6719 // the articulated figure structure is handled by the owner 6720 6721 idPhysics_AF_SavePState( saveFile, current ); 6722 idPhysics_AF_SavePState( saveFile, saved ); 6723 6724 saveFile->WriteInt( bodies.Num() ); 6725 for ( i = 0; i < bodies.Num(); i++ ) { 6726 bodies[i]->Save( saveFile ); 6727 } 6728 if ( masterBody ) { 6729 saveFile->WriteBool( true ); 6730 masterBody->Save( saveFile ); 6731 } else { 6732 saveFile->WriteBool( false ); 6733 } 6734 6735 saveFile->WriteInt( constraints.Num() ); 6736 for ( i = 0; i < constraints.Num(); i++ ) { 6737 constraints[i]->Save( saveFile ); 6738 } 6739 6740 saveFile->WriteBool( changedAF ); 6741 6742 saveFile->WriteFloat( linearFriction ); 6743 saveFile->WriteFloat( angularFriction ); 6744 saveFile->WriteFloat( contactFriction ); 6745 saveFile->WriteFloat( bouncyness ); 6746 saveFile->WriteFloat( totalMass ); 6747 saveFile->WriteFloat( forceTotalMass ); 6748 6749 saveFile->WriteVec2( suspendVelocity ); 6750 saveFile->WriteVec2( suspendAcceleration ); 6751 saveFile->WriteFloat( noMoveTime ); 6752 saveFile->WriteFloat( noMoveTranslation ); 6753 saveFile->WriteFloat( noMoveRotation ); 6754 saveFile->WriteFloat( minMoveTime ); 6755 saveFile->WriteFloat( maxMoveTime ); 6756 saveFile->WriteFloat( impulseThreshold ); 6757 6758 saveFile->WriteFloat( timeScale ); 6759 saveFile->WriteFloat( timeScaleRampStart ); 6760 saveFile->WriteFloat( timeScaleRampEnd ); 6761 6762 saveFile->WriteFloat( jointFrictionScale ); 6763 saveFile->WriteFloat( jointFrictionDent ); 6764 saveFile->WriteFloat( jointFrictionDentStart ); 6765 saveFile->WriteFloat( jointFrictionDentEnd ); 6766 saveFile->WriteFloat( jointFrictionDentScale ); 6767 6768 saveFile->WriteFloat( contactFrictionScale ); 6769 saveFile->WriteFloat( contactFrictionDent ); 6770 saveFile->WriteFloat( contactFrictionDentStart ); 6771 saveFile->WriteFloat( contactFrictionDentEnd ); 6772 saveFile->WriteFloat( contactFrictionDentScale ); 6773 6774 saveFile->WriteBool( enableCollision ); 6775 saveFile->WriteBool( selfCollision ); 6776 saveFile->WriteBool( comeToRest ); 6777 saveFile->WriteBool( linearTime ); 6778 saveFile->WriteBool( noImpact ); 6779 saveFile->WriteBool( worldConstraintsLocked ); 6780 saveFile->WriteBool( forcePushable ); 6781 } 6782 6783 /* 6784 ================ 6785 idPhysics_AF::Restore 6786 ================ 6787 */ 6788 void idPhysics_AF::Restore( idRestoreGame *saveFile ) { 6789 int i, num; 6790 bool hasMaster; 6791 6792 // the articulated figure structure should have already been restored 6793 6794 idPhysics_AF_RestorePState( saveFile, current ); 6795 idPhysics_AF_RestorePState( saveFile, saved ); 6796 6797 saveFile->ReadInt( num ); 6798 assert( num == bodies.Num() ); 6799 for ( i = 0; i < bodies.Num(); i++ ) { 6800 bodies[i]->Restore( saveFile ); 6801 } 6802 saveFile->ReadBool( hasMaster ); 6803 if ( hasMaster ) { 6804 masterBody = new (TAG_PHYSICS_AF) idAFBody(); 6805 masterBody->Restore( saveFile ); 6806 } 6807 6808 saveFile->ReadInt( num ); 6809 assert( num == constraints.Num() ); 6810 for ( i = 0; i < constraints.Num(); i++ ) { 6811 constraints[i]->Restore( saveFile ); 6812 } 6813 6814 saveFile->ReadBool( changedAF ); 6815 6816 saveFile->ReadFloat( linearFriction ); 6817 saveFile->ReadFloat( angularFriction ); 6818 saveFile->ReadFloat( contactFriction ); 6819 saveFile->ReadFloat( bouncyness ); 6820 saveFile->ReadFloat( totalMass ); 6821 saveFile->ReadFloat( forceTotalMass ); 6822 6823 saveFile->ReadVec2( suspendVelocity ); 6824 saveFile->ReadVec2( suspendAcceleration ); 6825 saveFile->ReadFloat( noMoveTime ); 6826 saveFile->ReadFloat( noMoveTranslation ); 6827 saveFile->ReadFloat( noMoveRotation ); 6828 saveFile->ReadFloat( minMoveTime ); 6829 saveFile->ReadFloat( maxMoveTime ); 6830 saveFile->ReadFloat( impulseThreshold ); 6831 6832 saveFile->ReadFloat( timeScale ); 6833 saveFile->ReadFloat( timeScaleRampStart ); 6834 saveFile->ReadFloat( timeScaleRampEnd ); 6835 6836 saveFile->ReadFloat( jointFrictionScale ); 6837 saveFile->ReadFloat( jointFrictionDent ); 6838 saveFile->ReadFloat( jointFrictionDentStart ); 6839 saveFile->ReadFloat( jointFrictionDentEnd ); 6840 saveFile->ReadFloat( jointFrictionDentScale ); 6841 6842 saveFile->ReadFloat( contactFrictionScale ); 6843 saveFile->ReadFloat( contactFrictionDent ); 6844 saveFile->ReadFloat( contactFrictionDentStart ); 6845 saveFile->ReadFloat( contactFrictionDentEnd ); 6846 saveFile->ReadFloat( contactFrictionDentScale ); 6847 6848 saveFile->ReadBool( enableCollision ); 6849 saveFile->ReadBool( selfCollision ); 6850 saveFile->ReadBool( comeToRest ); 6851 saveFile->ReadBool( linearTime ); 6852 saveFile->ReadBool( noImpact ); 6853 saveFile->ReadBool( worldConstraintsLocked ); 6854 saveFile->ReadBool( forcePushable ); 6855 6856 changedAF = true; 6857 6858 UpdateClipModels(); 6859 } 6860 6861 /* 6862 ================ 6863 idPhysics_AF::IsClosedLoop 6864 ================ 6865 */ 6866 bool idPhysics_AF::IsClosedLoop( const idAFBody *body1, const idAFBody *body2 ) const { 6867 const idAFBody *b1, *b2; 6868 6869 for ( b1 = body1; b1->parent; b1 = b1->parent ) { 6870 } 6871 for ( b2 = body2; b2->parent; b2 = b2->parent ) { 6872 } 6873 return ( b1 == b2 ); 6874 } 6875 6876 /* 6877 ================ 6878 idPhysics_AF::BuildTrees 6879 ================ 6880 */ 6881 void idPhysics_AF::BuildTrees() { 6882 int i; 6883 float scale; 6884 idAFBody *b; 6885 idAFConstraint *c; 6886 idAFTree *tree; 6887 6888 primaryConstraints.Clear(); 6889 auxiliaryConstraints.Clear(); 6890 trees.DeleteContents( true ); 6891 6892 totalMass = 0.0f; 6893 for ( i = 0; i < bodies.Num(); i++ ) { 6894 b = bodies[i]; 6895 b->parent = NULL; 6896 b->primaryConstraint = NULL; 6897 b->constraints.SetNum( 0 ); 6898 b->children.Clear(); 6899 b->tree = NULL; 6900 totalMass += b->mass; 6901 } 6902 6903 if ( forceTotalMass > 0.0f ) { 6904 scale = forceTotalMass / totalMass; 6905 for ( i = 0; i < bodies.Num(); i++ ) { 6906 b = bodies[i]; 6907 b->mass *= scale; 6908 b->invMass = 1.0f / b->mass; 6909 b->inertiaTensor *= scale; 6910 b->inverseInertiaTensor = b->inertiaTensor.Inverse(); 6911 } 6912 totalMass = forceTotalMass; 6913 } 6914 6915 if ( af_useLinearTime.GetBool() ) { 6916 6917 for ( i = 0; i < constraints.Num(); i++ ) { 6918 c = constraints[i]; 6919 6920 c->body1->constraints.Append( c ); 6921 if ( c->body2 ) { 6922 c->body2->constraints.Append( c ); 6923 } 6924 6925 // only bilateral constraints between two non-world bodies that do not 6926 // create loops can be used as primary constraints 6927 if ( !c->body1->primaryConstraint && c->fl.allowPrimary && c->body2 != NULL && !IsClosedLoop( c->body1, c->body2 ) ) { 6928 c->body1->primaryConstraint = c; 6929 c->body1->parent = c->body2; 6930 c->body2->children.Append( c->body1 ); 6931 c->fl.isPrimary = true; 6932 c->firstIndex = 0; 6933 primaryConstraints.Append( c ); 6934 } else { 6935 c->fl.isPrimary = false; 6936 auxiliaryConstraints.Append( c ); 6937 } 6938 } 6939 6940 // create trees for all parent bodies 6941 for ( i = 0; i < bodies.Num(); i++ ) { 6942 if ( !bodies[i]->parent ) { 6943 tree = new (TAG_PHYSICS_AF) idAFTree(); 6944 tree->sortedBodies.Clear(); 6945 tree->sortedBodies.Append( bodies[i] ); 6946 bodies[i]->tree = tree; 6947 trees.Append( tree ); 6948 } 6949 } 6950 6951 // add each child body to the appropriate tree 6952 for ( i = 0; i < bodies.Num(); i++ ) { 6953 if ( bodies[i]->parent ) { 6954 for ( b = bodies[i]->parent; !b->tree; b = b->parent ) { 6955 } 6956 b->tree->sortedBodies.Append( bodies[i] ); 6957 bodies[i]->tree = b->tree; 6958 } 6959 } 6960 6961 if ( trees.Num() > 1 ) { 6962 gameLocal.Warning( "Articulated figure has multiple seperate tree structures for entity '%s' type '%s'.", 6963 self->name.c_str(), self->GetType()->classname ); 6964 } 6965 6966 // sort bodies in each tree to make sure parents come first 6967 for ( i = 0; i < trees.Num(); i++ ) { 6968 trees[i]->SortBodies(); 6969 } 6970 6971 } else { 6972 6973 // create a tree for each body 6974 for ( i = 0; i < bodies.Num(); i++ ) { 6975 tree = new (TAG_PHYSICS_AF) idAFTree(); 6976 tree->sortedBodies.Clear(); 6977 tree->sortedBodies.Append( bodies[i] ); 6978 bodies[i]->tree = tree; 6979 trees.Append( tree ); 6980 } 6981 6982 for ( i = 0; i < constraints.Num(); i++ ) { 6983 c = constraints[i]; 6984 6985 c->body1->constraints.Append( c ); 6986 if ( c->body2 ) { 6987 c->body2->constraints.Append( c ); 6988 } 6989 6990 c->fl.isPrimary = false; 6991 auxiliaryConstraints.Append( c ); 6992 } 6993 } 6994 } 6995 6996 /* 6997 ================ 6998 idPhysics_AF::AddBody 6999 7000 bodies get an id in the order they are added starting at zero 7001 as such the first body added will get id zero 7002 ================ 7003 */ 7004 int idPhysics_AF::AddBody( idAFBody *body ) { 7005 int id = 0; 7006 7007 if ( body->clipModel == NULL ) { 7008 gameLocal.Error( "idPhysics_AF::AddBody: body '%s' has no clip model.", body->name.c_str() ); 7009 return 0; 7010 } 7011 7012 if ( bodies.Find( body ) ) { 7013 gameLocal.Error( "idPhysics_AF::AddBody: body '%s' added twice.", body->name.c_str() ); 7014 } 7015 7016 if ( GetBody( body->name ) ) { 7017 gameLocal.Error( "idPhysics_AF::AddBody: a body with the name '%s' already exists.", body->name.c_str() ); 7018 } 7019 7020 id = bodies.Num(); 7021 body->clipModel->SetId( id ); 7022 if ( body->linearFriction < 0.0f ) { 7023 body->linearFriction = linearFriction; 7024 body->angularFriction = angularFriction; 7025 body->contactFriction = contactFriction; 7026 } 7027 if ( body->bouncyness < 0.0f ) { 7028 body->bouncyness = bouncyness; 7029 } 7030 if ( !body->fl.clipMaskSet ) { 7031 body->clipMask = clipMask; 7032 } 7033 7034 bodies.Append( body ); 7035 7036 changedAF = true; 7037 7038 return id; 7039 } 7040 7041 /* 7042 ================ 7043 idPhysics_AF::AddConstraint 7044 ================ 7045 */ 7046 void idPhysics_AF::AddConstraint( idAFConstraint *constraint ) { 7047 7048 if ( constraints.Find( constraint ) ) { 7049 gameLocal.Error( "idPhysics_AF::AddConstraint: constraint '%s' added twice.", constraint->name.c_str() ); 7050 } 7051 if ( GetConstraint( constraint->name ) ) { 7052 gameLocal.Error( "idPhysics_AF::AddConstraint: a constraint with the name '%s' already exists.", constraint->name.c_str() ); 7053 } 7054 if ( !constraint->body1 ) { 7055 gameLocal.Error( "idPhysics_AF::AddConstraint: body1 == NULL on constraint '%s'.", constraint->name.c_str() ); 7056 } 7057 if ( !bodies.Find( constraint->body1 ) ) { 7058 gameLocal.Error( "idPhysics_AF::AddConstraint: body1 of constraint '%s' is not part of the articulated figure.", constraint->name.c_str() ); 7059 } 7060 if ( constraint->body2 && !bodies.Find( constraint->body2 ) ) { 7061 gameLocal.Error( "idPhysics_AF::AddConstraint: body2 of constraint '%s' is not part of the articulated figure.", constraint->name.c_str() ); 7062 } 7063 if ( constraint->body1 == constraint->body2 ) { 7064 gameLocal.Error( "idPhysics_AF::AddConstraint: body1 and body2 of constraint '%s' are the same.", constraint->name.c_str() ); 7065 } 7066 7067 constraints.Append( constraint ); 7068 constraint->physics = this; 7069 7070 changedAF = true; 7071 } 7072 7073 /* 7074 ================ 7075 idPhysics_AF::AddFrameConstraint 7076 ================ 7077 */ 7078 void idPhysics_AF::AddFrameConstraint( idAFConstraint *constraint ) { 7079 frameConstraints.Append( constraint ); 7080 constraint->physics = this; 7081 } 7082 7083 /* 7084 ================ 7085 idPhysics_AF::ForceBodyId 7086 ================ 7087 */ 7088 void idPhysics_AF::ForceBodyId( idAFBody *body, int newId ) { 7089 int id; 7090 7091 id = bodies.FindIndex( body ); 7092 if ( id == -1 ) { 7093 gameLocal.Error( "ForceBodyId: body '%s' is not part of the articulated figure.\n", body->name.c_str() ); 7094 } 7095 if ( id != newId ) { 7096 idAFBody *b = bodies[newId]; 7097 bodies[newId] = bodies[id]; 7098 bodies[id] = b; 7099 changedAF = true; 7100 } 7101 } 7102 7103 /* 7104 ================ 7105 idPhysics_AF::GetBodyId 7106 ================ 7107 */ 7108 int idPhysics_AF::GetBodyId( idAFBody *body ) const { 7109 int id; 7110 7111 id = bodies.FindIndex( body ); 7112 if ( id == -1 && body ) { 7113 gameLocal.Error( "GetBodyId: body '%s' is not part of the articulated figure.\n", body->name.c_str() ); 7114 } 7115 return id; 7116 } 7117 7118 /* 7119 ================ 7120 idPhysics_AF::GetBodyId 7121 ================ 7122 */ 7123 int idPhysics_AF::GetBodyId( const char *bodyName ) const { 7124 int i; 7125 7126 for ( i = 0; i < bodies.Num(); i++ ) { 7127 if ( !bodies[i]->name.Icmp( bodyName ) ) { 7128 return i; 7129 } 7130 } 7131 gameLocal.Error( "GetBodyId: no body with the name '%s' is not part of the articulated figure.\n", bodyName ); 7132 return 0; 7133 } 7134 7135 /* 7136 ================ 7137 idPhysics_AF::GetConstraintId 7138 ================ 7139 */ 7140 int idPhysics_AF::GetConstraintId( idAFConstraint *constraint ) const { 7141 int id; 7142 7143 id = constraints.FindIndex( constraint ); 7144 if ( id == -1 && constraint ) { 7145 gameLocal.Error( "GetConstraintId: constraint '%s' is not part of the articulated figure.\n", constraint->name.c_str() ); 7146 } 7147 return id; 7148 } 7149 7150 /* 7151 ================ 7152 idPhysics_AF::GetConstraintId 7153 ================ 7154 */ 7155 int idPhysics_AF::GetConstraintId( const char *constraintName ) const { 7156 int i; 7157 7158 for ( i = 0; i < constraints.Num(); i++ ) { 7159 if ( constraints[i]->name.Icmp( constraintName ) == 0 ) { 7160 return i; 7161 } 7162 } 7163 gameLocal.Error( "GetConstraintId: no constraint with the name '%s' is not part of the articulated figure.\n", constraintName ); 7164 return 0; 7165 } 7166 7167 /* 7168 ================ 7169 idPhysics_AF::GetNumBodies 7170 ================ 7171 */ 7172 int idPhysics_AF::GetNumBodies() const { 7173 return bodies.Num(); 7174 } 7175 7176 /* 7177 ================ 7178 idPhysics_AF::GetNumConstraints 7179 ================ 7180 */ 7181 int idPhysics_AF::GetNumConstraints() const { 7182 return constraints.Num(); 7183 } 7184 7185 /* 7186 ================ 7187 idPhysics_AF::GetBody 7188 ================ 7189 */ 7190 idAFBody *idPhysics_AF::GetBody( const char *bodyName ) const { 7191 int i; 7192 7193 for ( i = 0; i < bodies.Num(); i++ ) { 7194 if ( !bodies[i]->name.Icmp( bodyName ) ) { 7195 return bodies[i]; 7196 } 7197 } 7198 7199 return NULL; 7200 } 7201 7202 /* 7203 ================ 7204 idPhysics_AF::GetBody 7205 ================ 7206 */ 7207 idAFBody *idPhysics_AF::GetBody( const int id ) const { 7208 if ( id < 0 || id >= bodies.Num() ) { 7209 gameLocal.Error( "GetBody: no body with id %d exists\n", id ); 7210 return NULL; 7211 } 7212 return bodies[id]; 7213 } 7214 7215 /* 7216 ================ 7217 idPhysics_AF::GetConstraint 7218 ================ 7219 */ 7220 idAFConstraint *idPhysics_AF::GetConstraint( const char *constraintName ) const { 7221 int i; 7222 7223 for ( i = 0; i < constraints.Num(); i++ ) { 7224 if ( constraints[i]->name.Icmp( constraintName ) == 0 ) { 7225 return constraints[i]; 7226 } 7227 } 7228 7229 return NULL; 7230 } 7231 7232 /* 7233 ================ 7234 idPhysics_AF::GetConstraint 7235 ================ 7236 */ 7237 idAFConstraint *idPhysics_AF::GetConstraint( const int id ) const { 7238 if ( id < 0 || id >= constraints.Num() ) { 7239 gameLocal.Error( "GetConstraint: no constraint with id %d exists\n", id ); 7240 return NULL; 7241 } 7242 return constraints[id]; 7243 } 7244 7245 /* 7246 ================ 7247 idPhysics_AF::DeleteBody 7248 ================ 7249 */ 7250 void idPhysics_AF::DeleteBody( const char *bodyName ) { 7251 int i; 7252 7253 // find the body with the given name 7254 for ( i = 0; i < bodies.Num(); i++ ) { 7255 if ( !bodies[i]->name.Icmp( bodyName ) ) { 7256 break; 7257 } 7258 } 7259 7260 if ( i >= bodies.Num() ) { 7261 gameLocal.Warning( "DeleteBody: no body found in the articulated figure with the name '%s' for entity '%s' type '%s'.", 7262 bodyName, self->name.c_str(), self->GetType()->classname ); 7263 return; 7264 } 7265 7266 DeleteBody( i ); 7267 } 7268 7269 /* 7270 ================ 7271 idPhysics_AF::DeleteBody 7272 ================ 7273 */ 7274 void idPhysics_AF::DeleteBody( const int id ) { 7275 int j; 7276 7277 if ( id < 0 || id > bodies.Num() ) { 7278 gameLocal.Error( "DeleteBody: no body with id %d.", id ); 7279 return; 7280 } 7281 7282 // remove any constraints attached to this body 7283 for ( j = 0; j < constraints.Num(); j++ ) { 7284 if ( constraints[j]->body1 == bodies[id] || constraints[j]->body2 == bodies[id] ) { 7285 delete constraints[j]; 7286 constraints.RemoveIndex( j ); 7287 j--; 7288 } 7289 } 7290 7291 // remove the body 7292 delete bodies[id]; 7293 bodies.RemoveIndex( id ); 7294 7295 // set new body ids 7296 for ( j = 0; j < bodies.Num(); j++ ) { 7297 bodies[j]->clipModel->SetId( j ); 7298 } 7299 7300 changedAF = true; 7301 } 7302 7303 /* 7304 ================ 7305 idPhysics_AF::DeleteConstraint 7306 ================ 7307 */ 7308 void idPhysics_AF::DeleteConstraint( const char *constraintName ) { 7309 int i; 7310 7311 // find the constraint with the given name 7312 for ( i = 0; i < constraints.Num(); i++ ) { 7313 if ( !constraints[i]->name.Icmp( constraintName ) ) { 7314 break; 7315 } 7316 } 7317 7318 if ( i >= constraints.Num() ) { 7319 gameLocal.Warning( "DeleteConstraint: no constriant found in the articulated figure with the name '%s' for entity '%s' type '%s'.", 7320 constraintName, self->name.c_str(), self->GetType()->classname ); 7321 return; 7322 } 7323 7324 DeleteConstraint( i ); 7325 } 7326 7327 /* 7328 ================ 7329 idPhysics_AF::DeleteConstraint 7330 ================ 7331 */ 7332 void idPhysics_AF::DeleteConstraint( const int id ) { 7333 7334 if ( id < 0 || id >= constraints.Num() ) { 7335 gameLocal.Error( "DeleteConstraint: no constraint with id %d.", id ); 7336 return; 7337 } 7338 7339 // remove the constraint 7340 delete constraints[id]; 7341 constraints.RemoveIndex( id ); 7342 7343 changedAF = true; 7344 } 7345 7346 /* 7347 ================ 7348 idPhysics_AF::GetBodyContactConstraints 7349 ================ 7350 */ 7351 int idPhysics_AF::GetBodyContactConstraints( const int id, idAFConstraint_Contact *contacts[], int maxContacts ) const { 7352 int i, numContacts; 7353 idAFBody *body; 7354 idAFConstraint_Contact *contact; 7355 7356 if ( id < 0 || id >= bodies.Num() || maxContacts <= 0 ) { 7357 return 0; 7358 } 7359 7360 numContacts = 0; 7361 body = bodies[id]; 7362 for ( i = 0; i < contactConstraints.Num(); i++ ) { 7363 contact = contactConstraints[i]; 7364 if ( contact->body1 == body || contact->body2 == body ) { 7365 contacts[numContacts++] = contact; 7366 if ( numContacts >= maxContacts ) { 7367 return numContacts; 7368 } 7369 } 7370 } 7371 return numContacts; 7372 } 7373 7374 /* 7375 ================ 7376 idPhysics_AF::SetDefaultFriction 7377 ================ 7378 */ 7379 void idPhysics_AF::SetDefaultFriction( float linear, float angular, float contact ) { 7380 if ( linear < 0.0f || linear > 1.0f || 7381 angular < 0.0f || angular > 1.0f || 7382 contact < 0.0f || contact > 1.0f ) { 7383 return; 7384 } 7385 linearFriction = linear; 7386 angularFriction = angular; 7387 contactFriction = contact; 7388 } 7389 7390 /* 7391 ================ 7392 idPhysics_AF::GetImpactInfo 7393 ================ 7394 */ 7395 void idPhysics_AF::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const { 7396 if ( id < 0 || id >= bodies.Num() ) { 7397 memset( info, 0, sizeof( *info ) ); 7398 return; 7399 } 7400 info->invMass = 1.0f / bodies[id]->mass; 7401 info->invInertiaTensor = bodies[id]->current->worldAxis.Transpose() * bodies[id]->inverseInertiaTensor * bodies[id]->current->worldAxis; 7402 info->position = point - bodies[id]->current->worldOrigin; 7403 info->velocity = bodies[id]->current->spatialVelocity.SubVec3(0) + bodies[id]->current->spatialVelocity.SubVec3(1).Cross( info->position ); 7404 } 7405 7406 /* 7407 ================ 7408 idPhysics_AF::ApplyImpulse 7409 ================ 7410 */ 7411 void idPhysics_AF::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) { 7412 if ( id < 0 || id >= bodies.Num() ) { 7413 return; 7414 } 7415 if ( noImpact || impulse.LengthSqr() < Square( impulseThreshold ) ) { 7416 return; 7417 } 7418 const float maxImpulse = 100000.0f; 7419 const float maxRotation = 100000.0f; 7420 idMat3 invWorldInertiaTensor = bodies[id]->current->worldAxis.Transpose() * bodies[id]->inverseInertiaTensor * bodies[id]->current->worldAxis; 7421 bodies[id]->current->spatialVelocity.SubVec3(0) += bodies[id]->invMass * impulse.Truncate( maxImpulse ); 7422 bodies[id]->current->spatialVelocity.SubVec3(1) += invWorldInertiaTensor * (point - bodies[id]->current->worldOrigin).Cross( impulse ).Truncate( maxRotation ); 7423 Activate(); 7424 } 7425 7426 /* 7427 ================ 7428 idPhysics_AF::AddForce 7429 ================ 7430 */ 7431 void idPhysics_AF::AddForce( const int id, const idVec3 &point, const idVec3 &force ) { 7432 if ( noImpact ) { 7433 return; 7434 } 7435 if ( id < 0 || id >= bodies.Num() ) { 7436 return; 7437 } 7438 bodies[id]->current->externalForce.SubVec3( 0 ) += force; 7439 bodies[id]->current->externalForce.SubVec3( 1 ) += (point - bodies[id]->current->worldOrigin).Cross( force ); 7440 Activate(); 7441 } 7442 7443 /* 7444 ================ 7445 idPhysics_AF::IsAtRest 7446 ================ 7447 */ 7448 bool idPhysics_AF::IsAtRest() const { 7449 return current.atRest >= 0; 7450 } 7451 7452 /* 7453 ================ 7454 idPhysics_AF::GetRestStartTime 7455 ================ 7456 */ 7457 int idPhysics_AF::GetRestStartTime() const { 7458 return current.atRest; 7459 } 7460 7461 /* 7462 ================ 7463 idPhysics_AF::IsPushable 7464 ================ 7465 */ 7466 bool idPhysics_AF::IsPushable() const { 7467 return ( !noImpact && ( masterBody == NULL || forcePushable ) ); 7468 } 7469 7470 /* 7471 ================ 7472 idPhysics_AF::SaveState 7473 ================ 7474 */ 7475 void idPhysics_AF::SaveState() { 7476 int i; 7477 7478 saved = current; 7479 7480 for ( i = 0; i < bodies.Num(); i++ ) { 7481 memcpy( &bodies[i]->saved, bodies[i]->current, sizeof( AFBodyPState_t ) ); 7482 } 7483 } 7484 7485 /* 7486 ================ 7487 idPhysics_AF::RestoreState 7488 ================ 7489 */ 7490 void idPhysics_AF::RestoreState() { 7491 int i; 7492 7493 current = saved; 7494 7495 for ( i = 0; i < bodies.Num(); i++ ) { 7496 *(bodies[i]->current) = bodies[i]->saved; 7497 } 7498 7499 EvaluateContacts(); 7500 } 7501 7502 /* 7503 ================ 7504 idPhysics_AF::SetOrigin 7505 ================ 7506 */ 7507 void idPhysics_AF::SetOrigin( const idVec3 &newOrigin, int id ) { 7508 if ( masterBody ) { 7509 Translate( masterBody->current->worldOrigin + masterBody->current->worldAxis * newOrigin - bodies[0]->current->worldOrigin ); 7510 } else { 7511 Translate( newOrigin - bodies[0]->current->worldOrigin ); 7512 } 7513 } 7514 7515 /* 7516 ================ 7517 idPhysics_AF::SetAxis 7518 ================ 7519 */ 7520 void idPhysics_AF::SetAxis( const idMat3 &newAxis, int id ) { 7521 idMat3 axis; 7522 idRotation rotation; 7523 7524 if ( masterBody ) { 7525 axis = bodies[0]->current->worldAxis.Transpose() * ( newAxis * masterBody->current->worldAxis ); 7526 } else { 7527 axis = bodies[0]->current->worldAxis.Transpose() * newAxis; 7528 } 7529 rotation = axis.ToRotation(); 7530 rotation.SetOrigin( bodies[0]->current->worldOrigin ); 7531 7532 Rotate( rotation ); 7533 } 7534 7535 /* 7536 ================ 7537 idPhysics_AF::Translate 7538 ================ 7539 */ 7540 void idPhysics_AF::Translate( const idVec3 &translation, int id ) { 7541 int i; 7542 idAFBody *body; 7543 7544 if ( !worldConstraintsLocked ) { 7545 // translate constraints attached to the world 7546 for ( i = 0; i < constraints.Num(); i++ ) { 7547 constraints[i]->Translate( translation ); 7548 } 7549 } 7550 7551 // translate all the bodies 7552 for ( i = 0; i < bodies.Num(); i++ ) { 7553 7554 body = bodies[i]; 7555 body->current->worldOrigin += translation; 7556 } 7557 7558 Activate(); 7559 7560 UpdateClipModels(); 7561 } 7562 7563 /* 7564 ================ 7565 idPhysics_AF::Rotate 7566 ================ 7567 */ 7568 void idPhysics_AF::Rotate( const idRotation &rotation, int id ) { 7569 int i; 7570 idAFBody *body; 7571 7572 if ( !worldConstraintsLocked ) { 7573 // rotate constraints attached to the world 7574 for ( i = 0; i < constraints.Num(); i++ ) { 7575 constraints[i]->Rotate( rotation ); 7576 } 7577 } 7578 7579 // rotate all the bodies 7580 for ( i = 0; i < bodies.Num(); i++ ) { 7581 body = bodies[i]; 7582 7583 body->current->worldOrigin *= rotation; 7584 body->current->worldAxis *= rotation.ToMat3(); 7585 } 7586 7587 Activate(); 7588 7589 UpdateClipModels(); 7590 } 7591 7592 /* 7593 ================ 7594 idPhysics_AF::GetOrigin 7595 ================ 7596 */ 7597 const idVec3 &idPhysics_AF::GetOrigin( int id ) const { 7598 if ( id < 0 || id >= bodies.Num() ) { 7599 return vec3_origin; 7600 } 7601 else { 7602 return bodies[id]->current->worldOrigin; 7603 } 7604 } 7605 7606 /* 7607 ================ 7608 idPhysics_AF::GetAxis 7609 ================ 7610 */ 7611 const idMat3 &idPhysics_AF::GetAxis( int id ) const { 7612 if ( id < 0 || id >= bodies.Num() ) { 7613 return mat3_identity; 7614 } 7615 else { 7616 return bodies[id]->current->worldAxis; 7617 } 7618 } 7619 7620 /* 7621 ================ 7622 idPhysics_AF::SetLinearVelocity 7623 ================ 7624 */ 7625 void idPhysics_AF::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { 7626 if ( id < 0 || id >= bodies.Num() ) { 7627 return; 7628 } 7629 bodies[id]->current->spatialVelocity.SubVec3( 0 ) = newLinearVelocity; 7630 Activate(); 7631 } 7632 7633 /* 7634 ================ 7635 idPhysics_AF::SetAngularVelocity 7636 ================ 7637 */ 7638 void idPhysics_AF::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { 7639 if ( id < 0 || id >= bodies.Num() ) { 7640 return; 7641 } 7642 bodies[id]->current->spatialVelocity.SubVec3( 1 ) = newAngularVelocity; 7643 Activate(); 7644 } 7645 7646 /* 7647 ================ 7648 idPhysics_AF::GetLinearVelocity 7649 ================ 7650 */ 7651 const idVec3 &idPhysics_AF::GetLinearVelocity( int id ) const { 7652 if ( id < 0 || id >= bodies.Num() ) { 7653 return vec3_origin; 7654 } 7655 else { 7656 return bodies[id]->current->spatialVelocity.SubVec3( 0 ); 7657 } 7658 } 7659 7660 /* 7661 ================ 7662 idPhysics_AF::GetAngularVelocity 7663 ================ 7664 */ 7665 const idVec3 &idPhysics_AF::GetAngularVelocity( int id ) const { 7666 if ( id < 0 || id >= bodies.Num() ) { 7667 return vec3_origin; 7668 } 7669 else { 7670 return bodies[id]->current->spatialVelocity.SubVec3( 1 ); 7671 } 7672 } 7673 7674 /* 7675 ================ 7676 idPhysics_AF::ClipTranslation 7677 ================ 7678 */ 7679 void idPhysics_AF::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const { 7680 int i; 7681 idAFBody *body; 7682 trace_t bodyResults; 7683 7684 results.fraction = 1.0f; 7685 7686 for ( i = 0; i < bodies.Num(); i++ ) { 7687 body = bodies[i]; 7688 7689 if ( body->clipModel->IsTraceModel() ) { 7690 if ( model ) { 7691 gameLocal.clip.TranslationModel( bodyResults, body->current->worldOrigin, body->current->worldOrigin + translation, 7692 body->clipModel, body->current->worldAxis, body->clipMask, 7693 model->Handle(), model->GetOrigin(), model->GetAxis() ); 7694 } 7695 else { 7696 gameLocal.clip.Translation( bodyResults, body->current->worldOrigin, body->current->worldOrigin + translation, 7697 body->clipModel, body->current->worldAxis, body->clipMask, self ); 7698 } 7699 if ( bodyResults.fraction < results.fraction ) { 7700 results = bodyResults; 7701 } 7702 } 7703 } 7704 7705 results.endpos = bodies[0]->current->worldOrigin + results.fraction * translation; 7706 results.endAxis = bodies[0]->current->worldAxis; 7707 } 7708 7709 /* 7710 ================ 7711 idPhysics_AF::ClipRotation 7712 ================ 7713 */ 7714 void idPhysics_AF::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const { 7715 int i; 7716 idAFBody *body; 7717 trace_t bodyResults; 7718 idRotation partialRotation; 7719 7720 results.fraction = 1.0f; 7721 7722 for ( i = 0; i < bodies.Num(); i++ ) { 7723 body = bodies[i]; 7724 7725 if ( body->clipModel->IsTraceModel() ) { 7726 if ( model ) { 7727 gameLocal.clip.RotationModel( bodyResults, body->current->worldOrigin, rotation, 7728 body->clipModel, body->current->worldAxis, body->clipMask, 7729 model->Handle(), model->GetOrigin(), model->GetAxis() ); 7730 } 7731 else { 7732 gameLocal.clip.Rotation( bodyResults, body->current->worldOrigin, rotation, 7733 body->clipModel, body->current->worldAxis, body->clipMask, self ); 7734 } 7735 if ( bodyResults.fraction < results.fraction ) { 7736 results = bodyResults; 7737 } 7738 } 7739 } 7740 7741 partialRotation = rotation * results.fraction; 7742 results.endpos = bodies[0]->current->worldOrigin * partialRotation; 7743 results.endAxis = bodies[0]->current->worldAxis * partialRotation.ToMat3(); 7744 } 7745 7746 /* 7747 ================ 7748 idPhysics_AF::ClipContents 7749 ================ 7750 */ 7751 int idPhysics_AF::ClipContents( const idClipModel *model ) const { 7752 int i, contents; 7753 idAFBody *body; 7754 7755 contents = 0; 7756 7757 for ( i = 0; i < bodies.Num(); i++ ) { 7758 body = bodies[i]; 7759 7760 if ( body->clipModel->IsTraceModel() ) { 7761 if ( model ) { 7762 contents |= gameLocal.clip.ContentsModel( body->current->worldOrigin, 7763 body->clipModel, body->current->worldAxis, -1, 7764 model->Handle(), model->GetOrigin(), model->GetAxis() ); 7765 } 7766 else { 7767 contents |= gameLocal.clip.Contents( body->current->worldOrigin, 7768 body->clipModel, body->current->worldAxis, -1, NULL ); 7769 } 7770 } 7771 } 7772 7773 return contents; 7774 } 7775 7776 /* 7777 ================ 7778 idPhysics_AF::DisableClip 7779 ================ 7780 */ 7781 void idPhysics_AF::DisableClip() { 7782 int i; 7783 7784 for ( i = 0; i < bodies.Num(); i++ ) { 7785 bodies[i]->clipModel->Disable(); 7786 } 7787 } 7788 7789 /* 7790 ================ 7791 idPhysics_AF::EnableClip 7792 ================ 7793 */ 7794 void idPhysics_AF::EnableClip() { 7795 int i; 7796 7797 for ( i = 0; i < bodies.Num(); i++ ) { 7798 bodies[i]->clipModel->Enable(); 7799 } 7800 } 7801 7802 /* 7803 ================ 7804 idPhysics_AF::UnlinkClip 7805 ================ 7806 */ 7807 void idPhysics_AF::UnlinkClip() { 7808 int i; 7809 7810 for ( i = 0; i < bodies.Num(); i++ ) { 7811 bodies[i]->clipModel->Unlink(); 7812 } 7813 } 7814 7815 /* 7816 ================ 7817 idPhysics_AF::LinkClip 7818 ================ 7819 */ 7820 void idPhysics_AF::LinkClip() { 7821 UpdateClipModels(); 7822 } 7823 7824 /* 7825 ================ 7826 idPhysics_AF::SetPushed 7827 ================ 7828 */ 7829 void idPhysics_AF::SetPushed( int deltaTime ) { 7830 idAFBody *body; 7831 idRotation rotation; 7832 7833 if ( bodies.Num() ) { 7834 body = bodies[0]; 7835 rotation = ( body->saved.worldAxis.Transpose() * body->current->worldAxis ).ToRotation(); 7836 7837 // velocity with which the af is pushed 7838 current.pushVelocity.SubVec3(0) += ( body->current->worldOrigin - body->saved.worldOrigin ) / ( deltaTime * idMath::M_MS2SEC ); 7839 current.pushVelocity.SubVec3(1) += rotation.GetVec() * -DEG2RAD( rotation.GetAngle() ) / ( deltaTime * idMath::M_MS2SEC ); 7840 } 7841 } 7842 7843 /* 7844 ================ 7845 idPhysics_AF::GetPushedLinearVelocity 7846 ================ 7847 */ 7848 const idVec3 &idPhysics_AF::GetPushedLinearVelocity( const int id ) const { 7849 return current.pushVelocity.SubVec3(0); 7850 } 7851 7852 /* 7853 ================ 7854 idPhysics_AF::GetPushedAngularVelocity 7855 ================ 7856 */ 7857 const idVec3 &idPhysics_AF::GetPushedAngularVelocity( const int id ) const { 7858 return current.pushVelocity.SubVec3(1); 7859 } 7860 7861 /* 7862 ================ 7863 idPhysics_AF::SetMaster 7864 7865 the binding is orientated based on the constraints being used 7866 ================ 7867 */ 7868 void idPhysics_AF::SetMaster( idEntity *master, const bool orientated ) { 7869 int i; 7870 idVec3 masterOrigin; 7871 idMat3 masterAxis; 7872 idRotation rotation; 7873 7874 if ( master ) { 7875 self->GetMasterPosition( masterOrigin, masterAxis ); 7876 if ( !masterBody ) { 7877 masterBody = new (TAG_PHYSICS_AF) idAFBody(); 7878 // translate and rotate all the constraints with body2 == NULL from world space to master space 7879 rotation = masterAxis.Transpose().ToRotation(); 7880 for ( i = 0; i < constraints.Num(); i++ ) { 7881 if ( constraints[i]->GetBody2() == NULL ) { 7882 constraints[i]->Translate( -masterOrigin ); 7883 constraints[i]->Rotate( rotation ); 7884 } 7885 } 7886 Activate(); 7887 } 7888 masterBody->current->worldOrigin = masterOrigin; 7889 masterBody->current->worldAxis = masterAxis; 7890 } 7891 else { 7892 if ( masterBody ) { 7893 // translate and rotate all the constraints with body2 == NULL from master space to world space 7894 rotation = masterBody->current->worldAxis.ToRotation(); 7895 for ( i = 0; i < constraints.Num(); i++ ) { 7896 if ( constraints[i]->GetBody2() == NULL ) { 7897 constraints[i]->Rotate( rotation ); 7898 constraints[i]->Translate( masterBody->current->worldOrigin ); 7899 } 7900 } 7901 delete masterBody; 7902 masterBody = NULL; 7903 Activate(); 7904 } 7905 } 7906 } 7907 7908 7909 const float AF_VELOCITY_MAX = 16000; 7910 const int AF_VELOCITY_TOTAL_BITS = 16; 7911 const int AF_VELOCITY_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( AF_VELOCITY_MAX ) ) + 1; 7912 const int AF_VELOCITY_MANTISSA_BITS = AF_VELOCITY_TOTAL_BITS - 1 - AF_VELOCITY_EXPONENT_BITS; 7913 const float AF_FORCE_MAX = 1e20f; 7914 const int AF_FORCE_TOTAL_BITS = 16; 7915 const int AF_FORCE_EXPONENT_BITS = idMath::BitsForInteger( idMath::BitsForFloat( AF_FORCE_MAX ) ) + 1; 7916 const int AF_FORCE_MANTISSA_BITS = AF_FORCE_TOTAL_BITS - 1 - AF_FORCE_EXPONENT_BITS; 7917 7918 /* 7919 ================ 7920 idPhysics_AF::WriteToSnapshot 7921 ================ 7922 */ 7923 void idPhysics_AF::WriteToSnapshot( idBitMsg &msg ) const { 7924 int i; 7925 idCQuat quat; 7926 7927 msg.WriteLong( current.atRest ); 7928 msg.WriteFloat( current.noMoveTime ); 7929 msg.WriteFloat( current.activateTime ); 7930 msg.WriteDeltaFloat( 0.0f, current.pushVelocity[0], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7931 msg.WriteDeltaFloat( 0.0f, current.pushVelocity[1], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7932 msg.WriteDeltaFloat( 0.0f, current.pushVelocity[2], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7933 msg.WriteDeltaFloat( 0.0f, current.pushVelocity[3], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7934 msg.WriteDeltaFloat( 0.0f, current.pushVelocity[4], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7935 msg.WriteDeltaFloat( 0.0f, current.pushVelocity[5], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7936 7937 msg.WriteByte( bodies.Num() ); 7938 7939 for ( i = 0; i < bodies.Num(); i++ ) { 7940 AFBodyPState_t *state = bodies[i]->current; 7941 quat = state->worldAxis.ToCQuat(); 7942 7943 msg.WriteFloat( state->worldOrigin[0] ); 7944 msg.WriteFloat( state->worldOrigin[1] ); 7945 msg.WriteFloat( state->worldOrigin[2] ); 7946 msg.WriteFloat( quat.x ); 7947 msg.WriteFloat( quat.y ); 7948 msg.WriteFloat( quat.z ); 7949 msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[0], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7950 msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[1], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7951 msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[2], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7952 msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[3], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7953 msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[4], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7954 msg.WriteDeltaFloat( 0.0f, state->spatialVelocity[5], AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7955 /* msg.WriteDeltaFloat( 0.0f, state->externalForce[0], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 7956 msg.WriteDeltaFloat( 0.0f, state->externalForce[1], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 7957 msg.WriteDeltaFloat( 0.0f, state->externalForce[2], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 7958 msg.WriteDeltaFloat( 0.0f, state->externalForce[3], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 7959 msg.WriteDeltaFloat( 0.0f, state->externalForce[4], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 7960 msg.WriteDeltaFloat( 0.0f, state->externalForce[5], AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 7961 */ 7962 } 7963 } 7964 7965 /* 7966 ================ 7967 idPhysics_AF::ReadFromSnapshot 7968 ================ 7969 */ 7970 void idPhysics_AF::ReadFromSnapshot( const idBitMsg &msg ) { 7971 int i, num; 7972 idCQuat quat; 7973 7974 current.atRest = msg.ReadLong(); 7975 current.noMoveTime = msg.ReadFloat(); 7976 current.activateTime = msg.ReadFloat(); 7977 current.pushVelocity[0] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7978 current.pushVelocity[1] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7979 current.pushVelocity[2] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7980 current.pushVelocity[3] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7981 current.pushVelocity[4] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7982 current.pushVelocity[5] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7983 7984 num = msg.ReadByte(); 7985 assert( num == bodies.Num() ); 7986 7987 for ( i = 0; i < bodies.Num(); i++ ) { 7988 AFBodyPState_t *state = bodies[i]->current; 7989 7990 state->worldOrigin[0] = msg.ReadFloat(); 7991 state->worldOrigin[1] = msg.ReadFloat(); 7992 state->worldOrigin[2] = msg.ReadFloat(); 7993 quat.x = msg.ReadFloat(); 7994 quat.y = msg.ReadFloat(); 7995 quat.z = msg.ReadFloat(); 7996 state->spatialVelocity[0] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7997 state->spatialVelocity[1] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7998 state->spatialVelocity[2] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 7999 state->spatialVelocity[3] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 8000 state->spatialVelocity[4] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 8001 state->spatialVelocity[5] = msg.ReadDeltaFloat( 0.0f, AF_VELOCITY_EXPONENT_BITS, AF_VELOCITY_MANTISSA_BITS ); 8002 /* state->externalForce[0] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 8003 state->externalForce[1] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 8004 state->externalForce[2] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 8005 state->externalForce[3] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 8006 state->externalForce[4] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 8007 state->externalForce[5] = msg.ReadDeltaFloat( 0.0f, AF_FORCE_EXPONENT_BITS, AF_FORCE_MANTISSA_BITS ); 8008 */ 8009 state->worldAxis = quat.ToMat3(); 8010 } 8011 8012 UpdateClipModels(); 8013 }