DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Physics_StaticMulti.cpp (24619B)


      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 
     33 #include "../Game_local.h"
     34 
     35 CLASS_DECLARATION( idPhysics, idPhysics_StaticMulti )
     36 END_CLASS
     37 
     38 staticPState_t defaultState;
     39 staticInterpolatePState_t defaultInterpolateState;
     40 
     41 /*
     42 ================
     43 idPhysics_StaticMulti::idPhysics_StaticMulti
     44 ================
     45 */
     46 idPhysics_StaticMulti::idPhysics_StaticMulti() {
     47 	self = NULL;
     48 	hasMaster = false;
     49 	isOrientated = false;
     50 
     51 	defaultState.origin.Zero();
     52 	defaultState.axis.Identity();
     53 	defaultState.localOrigin.Zero();
     54 	defaultState.localAxis.Identity();
     55 
     56 	defaultInterpolateState.origin.Zero();
     57 	defaultInterpolateState.axis = defaultState.axis.ToQuat();
     58 	defaultInterpolateState.localAxis = defaultInterpolateState.axis;
     59 	defaultInterpolateState.localOrigin.Zero();
     60 
     61 	current.SetNum( 1 );
     62 	current[0] = defaultState;
     63 	previous.SetNum( 1 );
     64 	previous[0] = defaultInterpolateState;
     65 	next.SetNum( 1 );
     66 	next[0] = defaultInterpolateState;
     67 	clipModels.SetNum( 1 );
     68 	clipModels[0] = NULL;
     69 }
     70 
     71 /*
     72 ================
     73 idPhysics_StaticMulti::~idPhysics_StaticMulti
     74 ================
     75 */
     76 idPhysics_StaticMulti::~idPhysics_StaticMulti() {
     77 	if ( self && self->GetPhysics() == this ) {
     78 		self->SetPhysics( NULL );
     79 	}
     80 	idForce::DeletePhysics( this );
     81 	for ( int i = 0; i < clipModels.Num(); i++ ) {
     82 		delete clipModels[i];
     83 	}
     84 }
     85 
     86 /*
     87 ================
     88 idPhysics_StaticMulti::Save
     89 ================
     90 */
     91 void idPhysics_StaticMulti::Save( idSaveGame *savefile ) const {
     92 	int i;
     93 
     94 	savefile->WriteObject( self );
     95 
     96 	savefile->WriteInt(current.Num());
     97 	for  ( i = 0; i < current.Num(); i++ ) {
     98 		savefile->WriteVec3( current[i].origin );
     99 		savefile->WriteMat3( current[i].axis );
    100 		savefile->WriteVec3( current[i].localOrigin );
    101 		savefile->WriteMat3( current[i].localAxis );
    102 	}
    103 
    104 	savefile->WriteInt( clipModels.Num() );
    105 	for ( i = 0; i < clipModels.Num(); i++ ) {
    106 		savefile->WriteClipModel( clipModels[i] );
    107 	}
    108 
    109 	savefile->WriteBool(hasMaster);
    110 	savefile->WriteBool(isOrientated);
    111 }
    112 
    113 /*
    114 ================
    115 idPhysics_StaticMulti::Restore
    116 ================
    117 */
    118 void idPhysics_StaticMulti::Restore( idRestoreGame *savefile ) {
    119 	int i, num;
    120 
    121 	savefile->ReadObject( reinterpret_cast<idClass *&>( self ) );
    122 
    123 	savefile->ReadInt(num);
    124 	current.AssureSize( num );
    125 	for ( i = 0; i < num; i++ ) {
    126 		savefile->ReadVec3( current[i].origin );
    127 		savefile->ReadMat3( current[i].axis );
    128 		savefile->ReadVec3( current[i].localOrigin );
    129 		savefile->ReadMat3( current[i].localAxis );
    130 	}
    131 
    132 	savefile->ReadInt(num);
    133 	clipModels.SetNum( num );
    134 	for ( i = 0; i < num; i++ ) {
    135 		savefile->ReadClipModel( clipModels[i] );
    136 	}
    137 
    138 	savefile->ReadBool(hasMaster);
    139 	savefile->ReadBool(isOrientated);
    140 }
    141 
    142 /*
    143 ================
    144 idPhysics_StaticMulti::SetSelf
    145 ================
    146 */
    147 void idPhysics_StaticMulti::SetSelf( idEntity *e ) {
    148 	assert( e );
    149 	self = e;
    150 }
    151 
    152 /*
    153 ================
    154 idPhysics_StaticMulti::RemoveIndex
    155 ================
    156 */
    157 void idPhysics_StaticMulti::RemoveIndex( int id, bool freeClipModel ) {
    158 	if ( id < 0 || id >= clipModels.Num() ) {
    159 		return;
    160 	}
    161 	if ( clipModels[id] && freeClipModel ) {
    162 		delete clipModels[id];
    163 		clipModels[id] = NULL;
    164 	}
    165 	clipModels.RemoveIndex( id );
    166 	current.RemoveIndex( id );
    167 }
    168 
    169 /*
    170 ================
    171 idPhysics_StaticMulti::SetClipModel
    172 ================
    173 */
    174 void idPhysics_StaticMulti::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) {
    175 	int i;
    176 
    177 	assert( self );
    178 
    179 	if ( id >= clipModels.Num() ) {
    180 		current.AssureSize( id+1, defaultState );
    181 		clipModels.AssureSize( id+1, NULL );
    182 	}
    183 
    184 	if ( clipModels[id] && clipModels[id] != model && freeOld ) {
    185 		delete clipModels[id];
    186 	}
    187 	clipModels[id] = model;
    188 	if ( clipModels[id] ) {
    189 		clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis );
    190 
    191 	}
    192 
    193 	for ( i = clipModels.Num() - 1; i >= 1; i-- ) {
    194 		if ( clipModels[i] ) {
    195 			break;
    196 		}
    197 	}
    198 	current.SetNum( i+1 );
    199 	clipModels.SetNum( i+1 );
    200 
    201 	// Assure that on first setup, our next/previous is the same as current. 
    202 	previous.SetNum( current.Num() );
    203 	next.SetNum( previous.Num() );
    204 	for( int curIdx = 0; curIdx < current.Num(); curIdx++ ) {
    205 		previous[curIdx] = ConvertPStateToInterpolateState( current[curIdx] );
    206 		previous[curIdx] = next[curIdx];
    207 	}
    208 }
    209 
    210 /*
    211 ================
    212 idPhysics_StaticMulti::GetClipModel
    213 ================
    214 */
    215 idClipModel *idPhysics_StaticMulti::GetClipModel( int id ) const {
    216 	if ( id >= 0 && id < clipModels.Num() && clipModels[id] ) {
    217 		return clipModels[id];
    218 	}
    219 	return gameLocal.clip.DefaultClipModel();
    220 }
    221 
    222 /*
    223 ================
    224 idPhysics_StaticMulti::GetNumClipModels
    225 ================
    226 */
    227 int idPhysics_StaticMulti::GetNumClipModels() const {
    228 	return clipModels.Num();
    229 }
    230 
    231 /*
    232 ================
    233 idPhysics_StaticMulti::SetMass
    234 ================
    235 */
    236 void idPhysics_StaticMulti::SetMass( float mass, int id ) {
    237 }
    238 
    239 /*
    240 ================
    241 idPhysics_StaticMulti::GetMass
    242 ================
    243 */
    244 float idPhysics_StaticMulti::GetMass( int id ) const {
    245 	return 0.0f;
    246 }
    247 
    248 /*
    249 ================
    250 idPhysics_StaticMulti::SetContents
    251 ================
    252 */
    253 void idPhysics_StaticMulti::SetContents( int contents, int id ) {
    254 	int i;
    255 
    256 	if ( id >= 0 && id < clipModels.Num() ) {
    257 		if ( clipModels[id] ) {
    258 			clipModels[id]->SetContents( contents );
    259 		}
    260 	} else if ( id == -1 ) {
    261 		for ( i = 0; i < clipModels.Num(); i++ ) {
    262 			if ( clipModels[i] ) {
    263 				clipModels[i]->SetContents( contents );
    264 			}
    265 		}
    266 	}
    267 }
    268 
    269 /*
    270 ================
    271 idPhysics_StaticMulti::GetContents
    272 ================
    273 */
    274 int idPhysics_StaticMulti::GetContents( int id ) const {
    275 	int i, contents = 0;
    276 
    277 	if ( id >= 0 && id < clipModels.Num() ) {
    278 		if ( clipModels[id] ) {
    279 			contents = clipModels[id]->GetContents();
    280 		}
    281 	} else if ( id == -1 ) {
    282 		for ( i = 0; i < clipModels.Num(); i++ ) {
    283 			if ( clipModels[i] ) {
    284 				contents |= clipModels[i]->GetContents();
    285 			}
    286 		}
    287 	}
    288 	return contents;
    289 }
    290 
    291 /*
    292 ================
    293 idPhysics_StaticMulti::SetClipMask
    294 ================
    295 */
    296 void idPhysics_StaticMulti::SetClipMask( int mask, int id ) {
    297 }
    298 
    299 /*
    300 ================
    301 idPhysics_StaticMulti::GetClipMask
    302 ================
    303 */
    304 int idPhysics_StaticMulti::GetClipMask( int id ) const {
    305 	return 0;
    306 }
    307 
    308 /*
    309 ================
    310 idPhysics_StaticMulti::GetBounds
    311 ================
    312 */
    313 const idBounds &idPhysics_StaticMulti::GetBounds( int id ) const {
    314 	int i;
    315 	static idBounds bounds;
    316 
    317 	if ( id >= 0 && id < clipModels.Num() ) {
    318 		if ( clipModels[id] ) {
    319 			return clipModels[id]->GetBounds();
    320 		}
    321 	}
    322 	if ( id == -1 ) {
    323 		bounds.Clear();
    324 		for ( i = 0; i < clipModels.Num(); i++ ) {
    325 			if ( clipModels[i] ) {
    326 				bounds.AddBounds( clipModels[i]->GetAbsBounds() );
    327 			}
    328 		}
    329 		for ( i = 0; i < clipModels.Num(); i++ ) {
    330 			if ( clipModels[i] ) {
    331 				bounds[0] -= clipModels[i]->GetOrigin();
    332 				bounds[1] -= clipModels[i]->GetOrigin();
    333 				break;
    334 			}
    335 		}
    336 		return bounds;
    337 	}
    338 	return bounds_zero;
    339 }
    340 
    341 /*
    342 ================
    343 idPhysics_StaticMulti::GetAbsBounds
    344 ================
    345 */
    346 const idBounds &idPhysics_StaticMulti::GetAbsBounds( int id ) const {
    347 	int i;
    348 	static idBounds absBounds;
    349 
    350 	if ( id >= 0 && id < clipModels.Num() ) {
    351 		if ( clipModels[id] ) {
    352 			return clipModels[id]->GetAbsBounds();
    353 		}
    354 	}
    355 	if ( id == -1 ) {
    356 		absBounds.Clear();
    357 		for ( i = 0; i < clipModels.Num(); i++ ) {
    358 			if ( clipModels[i] ) {
    359 				absBounds.AddBounds( clipModels[i]->GetAbsBounds() );
    360 			}
    361 		}
    362 		return absBounds;
    363 	}
    364 	return bounds_zero;
    365 }
    366 
    367 /*
    368 ================
    369 idPhysics_StaticMulti::Evaluate
    370 ================
    371 */
    372 bool idPhysics_StaticMulti::Evaluate( int timeStepMSec, int endTimeMSec ) {
    373 	int i;
    374 	idVec3 masterOrigin;
    375 	idMat3 masterAxis;
    376 
    377 	if ( hasMaster ) {
    378 		self->GetMasterPosition( masterOrigin, masterAxis );
    379 		for ( i = 0; i < clipModels.Num(); i++ ) {
    380 			current[i].origin = masterOrigin + current[i].localOrigin * masterAxis;
    381 			if ( isOrientated ) {
    382 				current[i].axis = current[i].localAxis * masterAxis;
    383 			} else {
    384 				current[i].axis = current[i].localAxis;
    385 			}
    386 			if ( clipModels[i] ) {
    387 				clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis );
    388 			}
    389 		}
    390 
    391 		// FIXME: return false if master did not move
    392 		return true;
    393 	}
    394 	return false;
    395 }
    396 
    397 /*
    398 ================
    399 idPhysics_StaticMulti::Interpolate
    400 ================
    401 */
    402 bool idPhysics_StaticMulti::Interpolate( const float fraction ) {
    403 	// If the sizes don't match, just use the latest version.
    404 	// TODO: This might cause visual snapping, is there a better solution?
    405 	if ( current.Num() != previous.Num() ||
    406 		 current.Num() != next.Num() ) {
    407 		current.SetNum( next.Num() );
    408 		for ( int i = 0; i < next.Num(); ++i ) {
    409 			current[i] = InterpolateStaticPState( next[i], next[i], 1.0f );
    410 		}
    411 		return true;
    412 	}
    413 
    414 	for ( int i = 0; i < current.Num(); ++i ) {
    415 		current[i] = InterpolateStaticPState( previous[i], next[i], fraction );
    416 	}
    417 
    418 	return true;
    419 }
    420 
    421 /*
    422 ================
    423 idPhysics_StaticMulti::UpdateTime
    424 ================
    425 */
    426 void idPhysics_StaticMulti::UpdateTime( int endTimeMSec ) {
    427 }
    428 
    429 /*
    430 ================
    431 idPhysics_StaticMulti::GetTime
    432 ================
    433 */
    434 int idPhysics_StaticMulti::GetTime() const {
    435 	return 0;
    436 }
    437 
    438 /*
    439 ================
    440 idPhysics_StaticMulti::GetImpactInfo
    441 ================
    442 */
    443 void idPhysics_StaticMulti::GetImpactInfo( const int id, const idVec3 &point, impactInfo_t *info ) const {
    444 	memset( info, 0, sizeof( *info ) );
    445 }
    446 
    447 /*
    448 ================
    449 idPhysics_StaticMulti::ApplyImpulse
    450 ================
    451 */
    452 void idPhysics_StaticMulti::ApplyImpulse( const int id, const idVec3 &point, const idVec3 &impulse ) {
    453 }
    454 
    455 /*
    456 ================
    457 idPhysics_StaticMulti::AddForce
    458 ================
    459 */
    460 void idPhysics_StaticMulti::AddForce( const int id, const idVec3 &point, const idVec3 &force ) {
    461 }
    462 
    463 /*
    464 ================
    465 idPhysics_StaticMulti::Activate
    466 ================
    467 */
    468 void idPhysics_StaticMulti::Activate() {
    469 }
    470 
    471 /*
    472 ================
    473 idPhysics_StaticMulti::PutToRest
    474 ================
    475 */
    476 void idPhysics_StaticMulti::PutToRest() {
    477 }
    478 
    479 /*
    480 ================
    481 idPhysics_StaticMulti::IsAtRest
    482 ================
    483 */
    484 bool idPhysics_StaticMulti::IsAtRest() const {
    485 	return true;
    486 }
    487 
    488 /*
    489 ================
    490 idPhysics_StaticMulti::GetRestStartTime
    491 ================
    492 */
    493 int idPhysics_StaticMulti::GetRestStartTime() const {
    494 	return 0;
    495 }
    496 
    497 /*
    498 ================
    499 idPhysics_StaticMulti::IsPushable
    500 ================
    501 */
    502 bool idPhysics_StaticMulti::IsPushable() const {
    503 	return false;
    504 }
    505 
    506 /*
    507 ================
    508 idPhysics_StaticMulti::SaveState
    509 ================
    510 */
    511 void idPhysics_StaticMulti::SaveState() {
    512 }
    513 
    514 /*
    515 ================
    516 idPhysics_StaticMulti::RestoreState
    517 ================
    518 */
    519 void idPhysics_StaticMulti::RestoreState() {
    520 }
    521 
    522 /*
    523 ================
    524 idPhysics_StaticMulti::SetOrigin
    525 ================
    526 */
    527 void idPhysics_StaticMulti::SetOrigin( const idVec3 &newOrigin, int id ) {
    528 	idVec3 masterOrigin;
    529 	idMat3 masterAxis;
    530 
    531 	if ( id >= 0 && id < clipModels.Num() ) {
    532 		current[id].localOrigin = newOrigin;
    533 		if ( hasMaster ) {
    534 			self->GetMasterPosition( masterOrigin, masterAxis );
    535 			current[id].origin = masterOrigin + newOrigin * masterAxis;
    536 		} else {
    537 			current[id].origin = newOrigin;
    538 		}
    539 		if ( clipModels[id] ) {
    540 			clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis );
    541 		}
    542 	} else if ( id == -1 ) {
    543 		if ( hasMaster ) {
    544 			self->GetMasterPosition( masterOrigin, masterAxis );
    545 			Translate( masterOrigin + masterAxis * newOrigin - current[0].origin );
    546 		} else {
    547 			Translate( newOrigin - current[0].origin );
    548 		}
    549 	}
    550 }
    551 
    552 /*
    553 ================
    554 idPhysics_StaticMulti::SetAxis
    555 ================
    556 */
    557 void idPhysics_StaticMulti::SetAxis( const idMat3 &newAxis, int id ) {
    558 	idVec3 masterOrigin;
    559 	idMat3 masterAxis;
    560 
    561 	if ( id >= 0 && id < clipModels.Num() ) {
    562 		current[id].localAxis = newAxis;
    563 		if ( hasMaster && isOrientated ) {
    564 			self->GetMasterPosition( masterOrigin, masterAxis );
    565 			current[id].axis = newAxis * masterAxis;
    566 		} else {
    567 			current[id].axis = newAxis;
    568 		}
    569 		if ( clipModels[id] ) {
    570 			clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis );
    571 		}
    572 	} else if ( id == -1 ) {
    573 		idMat3 axis;
    574 		idRotation rotation;
    575 
    576 		if ( hasMaster ) {
    577 			self->GetMasterPosition( masterOrigin, masterAxis );
    578 			axis = current[0].axis.Transpose() * ( newAxis * masterAxis );
    579 		} else {
    580 			axis = current[0].axis.Transpose() * newAxis;
    581 		}
    582 		rotation = axis.ToRotation();
    583 		rotation.SetOrigin( current[0].origin );
    584 
    585 		Rotate( rotation );
    586 	}
    587 }
    588 
    589 /*
    590 ================
    591 idPhysics_StaticMulti::Translate
    592 ================
    593 */
    594 void idPhysics_StaticMulti::Translate( const idVec3 &translation, int id ) {
    595 	int i;
    596 
    597 	if ( id >= 0 && id < clipModels.Num() ) {
    598 		current[id].localOrigin += translation;
    599 		current[id].origin += translation;
    600 
    601 		if ( clipModels[id] ) {
    602 			clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis );
    603 		}
    604 	} else if ( id == -1 ) {
    605 		for ( i = 0; i < clipModels.Num(); i++ ) {
    606 			current[i].localOrigin += translation;
    607 			current[i].origin += translation;
    608 
    609 			if ( clipModels[i] ) {
    610 				clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis );
    611 			}
    612 		}
    613 	}
    614 }
    615 
    616 /*
    617 ================
    618 idPhysics_StaticMulti::Rotate
    619 ================
    620 */
    621 void idPhysics_StaticMulti::Rotate( const idRotation &rotation, int id ) {
    622 	int i;
    623 	idVec3 masterOrigin;
    624 	idMat3 masterAxis;
    625 
    626 	if ( id >= 0 && id < clipModels.Num() ) {
    627 		current[id].origin *= rotation;
    628 		current[id].axis *= rotation.ToMat3();
    629 
    630 		if ( hasMaster ) {
    631 			self->GetMasterPosition( masterOrigin, masterAxis );
    632 			current[id].localAxis *= rotation.ToMat3();
    633 			current[id].localOrigin = ( current[id].origin - masterOrigin ) * masterAxis.Transpose();
    634 		} else {
    635 			current[id].localAxis = current[id].axis;
    636 			current[id].localOrigin = current[id].origin;
    637 		}
    638 
    639 		if ( clipModels[id] ) {
    640 			clipModels[id]->Link( gameLocal.clip, self, id, current[id].origin, current[id].axis );
    641 		}
    642 	} else if ( id == -1 ) {
    643 		for ( i = 0; i < clipModels.Num(); i++ ) {
    644 			current[i].origin *= rotation;
    645 			current[i].axis *= rotation.ToMat3();
    646 
    647 			if ( hasMaster ) {
    648 				self->GetMasterPosition( masterOrigin, masterAxis );
    649 				current[i].localAxis *= rotation.ToMat3();
    650 				current[i].localOrigin = ( current[i].origin - masterOrigin ) * masterAxis.Transpose();
    651 			} else {
    652 				current[i].localAxis = current[i].axis;
    653 				current[i].localOrigin = current[i].origin;
    654 			}
    655 
    656 			if ( clipModels[i] ) {
    657 				clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis );
    658 			}
    659 		}
    660 	}
    661 }
    662 
    663 /*
    664 ================
    665 idPhysics_StaticMulti::GetOrigin
    666 ================
    667 */
    668 const idVec3 &idPhysics_StaticMulti::GetOrigin( int id ) const {
    669 	if ( id >= 0 && id < clipModels.Num() ) {
    670 		return current[id].origin;
    671 	}
    672 	if ( clipModels.Num() ) {
    673 		return current[0].origin;
    674 	} else {
    675 		return vec3_origin;
    676 	}
    677 }
    678 
    679 /*
    680 ================
    681 idPhysics_StaticMulti::GetAxis
    682 ================
    683 */
    684 const idMat3 &idPhysics_StaticMulti::GetAxis( int id ) const {
    685 	if ( id >= 0 && id < clipModels.Num() ) {
    686 		return current[id].axis;
    687 	}
    688 	if ( clipModels.Num() ) {
    689 		return current[0].axis;
    690 	} else {
    691 		return mat3_identity;
    692 	}
    693 }
    694 
    695 /*
    696 ================
    697 idPhysics_StaticMulti::SetLinearVelocity
    698 ================
    699 */
    700 void idPhysics_StaticMulti::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) {
    701 }
    702 
    703 /*
    704 ================
    705 idPhysics_StaticMulti::SetAngularVelocity
    706 ================
    707 */
    708 void idPhysics_StaticMulti::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) {
    709 }
    710 
    711 /*
    712 ================
    713 idPhysics_StaticMulti::GetLinearVelocity
    714 ================
    715 */
    716 const idVec3 &idPhysics_StaticMulti::GetLinearVelocity( int id ) const {
    717 	return vec3_origin;
    718 }
    719 
    720 /*
    721 ================
    722 idPhysics_StaticMulti::GetAngularVelocity
    723 ================
    724 */
    725 const idVec3 &idPhysics_StaticMulti::GetAngularVelocity( int id ) const {
    726 	return vec3_origin;
    727 }
    728 
    729 /*
    730 ================
    731 idPhysics_StaticMulti::SetGravity
    732 ================
    733 */
    734 void idPhysics_StaticMulti::SetGravity( const idVec3 &newGravity ) {
    735 }
    736 
    737 /*
    738 ================
    739 idPhysics_StaticMulti::GetGravity
    740 ================
    741 */
    742 const idVec3 &idPhysics_StaticMulti::GetGravity() const {
    743 	static idVec3 gravity( 0, 0, -g_gravity.GetFloat() );
    744 	return gravity;
    745 }
    746 
    747 /*
    748 ================
    749 idPhysics_StaticMulti::GetGravityNormal
    750 ================
    751 */
    752 const idVec3 &idPhysics_StaticMulti::GetGravityNormal() const {
    753 	static idVec3 gravity( 0, 0, -1 );
    754 	return gravity;
    755 }
    756 
    757 /*
    758 ================
    759 idPhysics_StaticMulti::ClipTranslation
    760 ================
    761 */
    762 void idPhysics_StaticMulti::ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const {
    763 	memset( &results, 0, sizeof( trace_t ) );
    764 	gameLocal.Warning( "idPhysics_StaticMulti::ClipTranslation called" );
    765 }
    766 
    767 /*
    768 ================
    769 idPhysics_StaticMulti::ClipRotation
    770 ================
    771 */
    772 void idPhysics_StaticMulti::ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const {
    773 	memset( &results, 0, sizeof( trace_t ) );
    774 	gameLocal.Warning( "idPhysics_StaticMulti::ClipRotation called" );
    775 }
    776 
    777 /*
    778 ================
    779 idPhysics_StaticMulti::ClipContents
    780 ================
    781 */
    782 int idPhysics_StaticMulti::ClipContents( const idClipModel *model ) const {
    783 	int i, contents;
    784 
    785 	contents = 0;
    786 	for ( i = 0; i < clipModels.Num(); i++ ) {
    787 		if ( clipModels[i] ) {
    788 			if ( model ) {
    789 				contents |= gameLocal.clip.ContentsModel( clipModels[i]->GetOrigin(), clipModels[i], clipModels[i]->GetAxis(), -1,
    790 											model->Handle(), model->GetOrigin(), model->GetAxis() );
    791 			} else {
    792 				contents |= gameLocal.clip.Contents( clipModels[i]->GetOrigin(), clipModels[i], clipModels[i]->GetAxis(), -1, NULL );
    793 			}
    794 		}
    795 	}
    796 	return contents;
    797 }
    798 
    799 /*
    800 ================
    801 idPhysics_StaticMulti::DisableClip
    802 ================
    803 */
    804 void idPhysics_StaticMulti::DisableClip() {
    805 	int i;
    806 
    807 	for ( i = 0; i < clipModels.Num(); i++ ) {
    808         if ( clipModels[i] ) {
    809 			clipModels[i]->Disable();
    810 		}
    811 	}
    812 }
    813 
    814 /*
    815 ================
    816 idPhysics_StaticMulti::EnableClip
    817 ================
    818 */
    819 void idPhysics_StaticMulti::EnableClip() {
    820 	int i;
    821 
    822 	for ( i = 0; i < clipModels.Num(); i++ ) {
    823 		if ( clipModels[i] ) {
    824 			clipModels[i]->Enable();
    825 		}
    826 	}
    827 }
    828 
    829 /*
    830 ================
    831 idPhysics_StaticMulti::UnlinkClip
    832 ================
    833 */
    834 void idPhysics_StaticMulti::UnlinkClip() {
    835 	int i;
    836 
    837 	for ( i = 0; i < clipModels.Num(); i++ ) {
    838         if ( clipModels[i] ) {
    839 			clipModels[i]->Unlink();
    840 		}
    841 	}
    842 }
    843 
    844 /*
    845 ================
    846 idPhysics_StaticMulti::LinkClip
    847 ================
    848 */
    849 void idPhysics_StaticMulti::LinkClip() {
    850 	int i;
    851 
    852 	for ( i = 0; i < clipModels.Num(); i++ ) {
    853 		if ( clipModels[i] ) {
    854 			clipModels[i]->Link( gameLocal.clip, self, i, current[i].origin, current[i].axis );
    855 		}
    856 	}
    857 }
    858 
    859 /*
    860 ================
    861 idPhysics_StaticMulti::EvaluateContacts
    862 ================
    863 */
    864 bool idPhysics_StaticMulti::EvaluateContacts() {
    865 	return false;
    866 }
    867 
    868 /*
    869 ================
    870 idPhysics_StaticMulti::GetNumContacts
    871 ================
    872 */
    873 int idPhysics_StaticMulti::GetNumContacts() const {
    874 	return 0;
    875 }
    876 
    877 /*
    878 ================
    879 idPhysics_StaticMulti::GetContact
    880 ================
    881 */
    882 const contactInfo_t &idPhysics_StaticMulti::GetContact( int num ) const {
    883 	static contactInfo_t info;
    884 	memset( &info, 0, sizeof( info ) );
    885 	return info;
    886 }
    887 
    888 /*
    889 ================
    890 idPhysics_StaticMulti::ClearContacts
    891 ================
    892 */
    893 void idPhysics_StaticMulti::ClearContacts() {
    894 }
    895 
    896 /*
    897 ================
    898 idPhysics_StaticMulti::AddContactEntity
    899 ================
    900 */
    901 void idPhysics_StaticMulti::AddContactEntity( idEntity *e ) {
    902 }
    903 
    904 /*
    905 ================
    906 idPhysics_StaticMulti::RemoveContactEntity
    907 ================
    908 */
    909 void idPhysics_StaticMulti::RemoveContactEntity( idEntity *e ) {
    910 }
    911 
    912 /*
    913 ================
    914 idPhysics_StaticMulti::HasGroundContacts
    915 ================
    916 */
    917 bool idPhysics_StaticMulti::HasGroundContacts() const {
    918 	return false;
    919 }
    920 
    921 /*
    922 ================
    923 idPhysics_StaticMulti::IsGroundEntity
    924 ================
    925 */
    926 bool idPhysics_StaticMulti::IsGroundEntity( int entityNum ) const {
    927 	return false;
    928 }
    929 
    930 /*
    931 ================
    932 idPhysics_StaticMulti::IsGroundClipModel
    933 ================
    934 */
    935 bool idPhysics_StaticMulti::IsGroundClipModel( int entityNum, int id ) const {
    936 	return false;
    937 }
    938 
    939 /*
    940 ================
    941 idPhysics_StaticMulti::SetPushed
    942 ================
    943 */
    944 void idPhysics_StaticMulti::SetPushed( int deltaTime ) {
    945 }
    946 
    947 /*
    948 ================
    949 idPhysics_StaticMulti::GetPushedLinearVelocity
    950 ================
    951 */
    952 const idVec3 &idPhysics_StaticMulti::GetPushedLinearVelocity( const int id ) const {
    953 	return vec3_origin;
    954 }
    955 
    956 /*
    957 ================
    958 idPhysics_StaticMulti::GetPushedAngularVelocity
    959 ================
    960 */
    961 const idVec3 &idPhysics_StaticMulti::GetPushedAngularVelocity( const int id ) const {
    962 	return vec3_origin;
    963 }
    964 
    965 /*
    966 ================
    967 idPhysics_StaticMulti::SetMaster
    968 ================
    969 */
    970 void idPhysics_StaticMulti::SetMaster( idEntity *master, const bool orientated ) {
    971 	int i;
    972 	idVec3 masterOrigin;
    973 	idMat3 masterAxis;
    974 
    975 	if ( master ) {
    976 		if ( !hasMaster ) {
    977 			// transform from world space to master space
    978 			self->GetMasterPosition( masterOrigin, masterAxis );
    979 			for ( i = 0; i < clipModels.Num(); i++ ) {
    980                 current[i].localOrigin = ( current[i].origin - masterOrigin ) * masterAxis.Transpose();
    981 				if ( orientated ) {
    982 					current[i].localAxis = current[i].axis * masterAxis.Transpose();
    983 				} else {
    984 					current[i].localAxis = current[i].axis;
    985 				}
    986 			}
    987 			hasMaster = true;
    988 			isOrientated = orientated;
    989 		}
    990 	} else {
    991 		if ( hasMaster ) {
    992 			hasMaster = false;
    993 		}
    994 	}
    995 }
    996 
    997 /*
    998 ================
    999 idPhysics_StaticMulti::GetBlockingInfo
   1000 ================
   1001 */
   1002 const trace_t *idPhysics_StaticMulti::GetBlockingInfo() const {
   1003 	return NULL;
   1004 }
   1005 
   1006 /*
   1007 ================
   1008 idPhysics_StaticMulti::GetBlockingEntity
   1009 ================
   1010 */
   1011 idEntity *idPhysics_StaticMulti::GetBlockingEntity() const {
   1012 	return NULL;
   1013 }
   1014 
   1015 /*
   1016 ================
   1017 idPhysics_StaticMulti::GetLinearEndTime
   1018 ================
   1019 */
   1020 int idPhysics_StaticMulti::GetLinearEndTime() const {
   1021 	return 0;
   1022 }
   1023 
   1024 /*
   1025 ================
   1026 idPhysics_StaticMulti::GetAngularEndTime
   1027 ================
   1028 */
   1029 int idPhysics_StaticMulti::GetAngularEndTime() const {
   1030 	return 0;
   1031 }
   1032 
   1033 /*
   1034 ================
   1035 idPhysics_StaticMulti::WriteToSnapshot
   1036 ================
   1037 */
   1038 void idPhysics_StaticMulti::WriteToSnapshot( idBitMsg &msg ) const {
   1039 	int i;
   1040 	idCQuat quat, localQuat;
   1041 
   1042 	msg.WriteByte( current.Num() );
   1043 
   1044 	for ( i = 0; i < current.Num(); i++ ) {
   1045 		quat = current[i].axis.ToCQuat();
   1046 		localQuat = current[i].localAxis.ToCQuat();
   1047 
   1048 		msg.WriteFloat( current[i].origin[0] );
   1049 		msg.WriteFloat( current[i].origin[1] );
   1050 		msg.WriteFloat( current[i].origin[2] );
   1051 		msg.WriteFloat( quat.x );
   1052 		msg.WriteFloat( quat.y );
   1053 		msg.WriteFloat( quat.z );
   1054 		msg.WriteDeltaFloat( current[i].origin[0], current[i].localOrigin[0] );
   1055 		msg.WriteDeltaFloat( current[i].origin[1], current[i].localOrigin[1] );
   1056 		msg.WriteDeltaFloat( current[i].origin[2], current[i].localOrigin[2] );
   1057 		msg.WriteDeltaFloat( quat.x, localQuat.x );
   1058 		msg.WriteDeltaFloat( quat.y, localQuat.y );
   1059 		msg.WriteDeltaFloat( quat.z, localQuat.z );
   1060 	}
   1061 }
   1062 
   1063 /*
   1064 ================
   1065 idPhysics_StaticMulti::ReadFromSnapshot
   1066 ================
   1067 */
   1068 void idPhysics_StaticMulti::ReadFromSnapshot( const idBitMsg &msg ) {
   1069 	int i, num;
   1070 	idCQuat quat, localQuat;
   1071 
   1072 	num = msg.ReadByte();
   1073 	assert( num == current.Num() );
   1074 
   1075 	previous = next;
   1076 
   1077 	next.SetNum( num );
   1078 
   1079 	for ( i = 0; i < current.Num(); i++ ) {
   1080 		next[i] = ReadStaticInterpolatePStateFromSnapshot( msg );
   1081 	}
   1082 }