/* =========================================================================== Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Doom 3 BFG Edition Source Code. If not, see . 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. 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. =========================================================================== */ #pragma hdrstop #include "../../idlib/precompiled.h" #include "../Game_local.h" CLASS_DECLARATION( idPhysics_Base, idPhysics_Parametric ) END_CLASS /* ================ idPhysics_Parametric::Activate ================ */ void idPhysics_Parametric::Activate() { current.atRest = -1; self->BecomeActive( TH_PHYSICS ); } /* ================ idPhysics_Parametric::TestIfAtRest ================ */ bool idPhysics_Parametric::TestIfAtRest() const { if ( ( current.linearExtrapolation.GetExtrapolationType() & ~EXTRAPOLATION_NOSTOP ) == EXTRAPOLATION_NONE && ( current.angularExtrapolation.GetExtrapolationType() & ~EXTRAPOLATION_NOSTOP ) == EXTRAPOLATION_NONE && current.linearInterpolation.GetDuration() == 0 && current.angularInterpolation.GetDuration() == 0 && current.spline == NULL ) { return true; } if ( !current.linearExtrapolation.IsDone( current.time ) ) { return false; } if ( !current.angularExtrapolation.IsDone( current.time ) ) { return false; } if ( !current.linearInterpolation.IsDone( current.time ) ) { return false; } if ( !current.angularInterpolation.IsDone( current.time ) ) { return false; } if ( current.spline != NULL && !current.spline->IsDone( current.time ) ) { return false; } return true; } /* ================ idPhysics_Parametric::Rest ================ */ void idPhysics_Parametric::Rest() { current.atRest = gameLocal.time; self->BecomeInactive( TH_PHYSICS ); } /* ================ idPhysics_Parametric::idPhysics_Parametric ================ */ idPhysics_Parametric::idPhysics_Parametric() { current.time = gameLocal.time; current.atRest = -1; current.useSplineAngles = false; current.origin.Zero(); current.angles.Zero(); current.axis.Identity(); current.localOrigin.Zero(); current.localAngles.Zero(); current.linearExtrapolation.Init( 0, 0, vec3_zero, vec3_zero, vec3_zero, EXTRAPOLATION_NONE ); current.angularExtrapolation.Init( 0, 0, ang_zero, ang_zero, ang_zero, EXTRAPOLATION_NONE ); current.linearInterpolation.Init( 0, 0, 0, 0, vec3_zero, vec3_zero ); current.angularInterpolation.Init( 0, 0, 0, 0, ang_zero, ang_zero ); current.spline = NULL; current.splineInterpolate.Init( 0, 1, 1, 2, 0, 0 ); saved = current; isPusher = false; pushFlags = 0; clipModel = NULL; isBlocked = false; memset( &pushResults, 0, sizeof( pushResults ) ); hasMaster = false; isOrientated = false; } /* ================ idPhysics_Parametric::~idPhysics_Parametric ================ */ idPhysics_Parametric::~idPhysics_Parametric() { if ( clipModel != NULL ) { delete clipModel; clipModel = NULL; } if ( current.spline != NULL ) { delete current.spline; current.spline = NULL; } } /* ================ idPhysics_Parametric_SavePState ================ */ void idPhysics_Parametric_SavePState( idSaveGame *savefile, const parametricPState_t &state ) { savefile->WriteInt( state.time ); savefile->WriteInt( state.atRest ); savefile->WriteBool( state.useSplineAngles ); savefile->WriteVec3( state.origin ); savefile->WriteAngles( state.angles ); savefile->WriteMat3( state.axis ); savefile->WriteVec3( state.localOrigin ); savefile->WriteAngles( state.localAngles ); savefile->WriteInt( (int)state.linearExtrapolation.GetExtrapolationType() ); savefile->WriteFloat( state.linearExtrapolation.GetStartTime() ); savefile->WriteFloat( state.linearExtrapolation.GetDuration() ); savefile->WriteVec3( state.linearExtrapolation.GetStartValue() ); savefile->WriteVec3( state.linearExtrapolation.GetBaseSpeed() ); savefile->WriteVec3( state.linearExtrapolation.GetSpeed() ); savefile->WriteInt( (int)state.angularExtrapolation.GetExtrapolationType() ); savefile->WriteFloat( state.angularExtrapolation.GetStartTime() ); savefile->WriteFloat( state.angularExtrapolation.GetDuration() ); savefile->WriteAngles( state.angularExtrapolation.GetStartValue() ); savefile->WriteAngles( state.angularExtrapolation.GetBaseSpeed() ); savefile->WriteAngles( state.angularExtrapolation.GetSpeed() ); savefile->WriteFloat( state.linearInterpolation.GetStartTime() ); savefile->WriteFloat( state.linearInterpolation.GetAcceleration() ); savefile->WriteFloat( state.linearInterpolation.GetDeceleration() ); savefile->WriteFloat( state.linearInterpolation.GetDuration() ); savefile->WriteVec3( state.linearInterpolation.GetStartValue() ); savefile->WriteVec3( state.linearInterpolation.GetEndValue() ); savefile->WriteFloat( state.angularInterpolation.GetStartTime() ); savefile->WriteFloat( state.angularInterpolation.GetAcceleration() ); savefile->WriteFloat( state.angularInterpolation.GetDeceleration() ); savefile->WriteFloat( state.angularInterpolation.GetDuration() ); savefile->WriteAngles( state.angularInterpolation.GetStartValue() ); savefile->WriteAngles( state.angularInterpolation.GetEndValue() ); // spline is handled by owner savefile->WriteFloat( state.splineInterpolate.GetStartTime() ); savefile->WriteFloat( state.splineInterpolate.GetAcceleration() ); savefile->WriteFloat( state.splineInterpolate.GetDuration() ); savefile->WriteFloat( state.splineInterpolate.GetDeceleration() ); savefile->WriteFloat( state.splineInterpolate.GetStartValue() ); savefile->WriteFloat( state.splineInterpolate.GetEndValue() ); } /* ================ idPhysics_Parametric_RestorePState ================ */ void idPhysics_Parametric_RestorePState( idRestoreGame *savefile, parametricPState_t &state ) { extrapolation_t etype; float startTime, duration, accelTime, decelTime, startValue, endValue; idVec3 linearStartValue, linearBaseSpeed, linearSpeed, startPos, endPos; idAngles angularStartValue, angularBaseSpeed, angularSpeed, startAng, endAng; savefile->ReadInt( state.time ); savefile->ReadInt( state.atRest ); savefile->ReadBool( state.useSplineAngles ); savefile->ReadVec3( state.origin ); savefile->ReadAngles( state.angles ); savefile->ReadMat3( state.axis ); savefile->ReadVec3( state.localOrigin ); savefile->ReadAngles( state.localAngles ); savefile->ReadInt( (int &)etype ); savefile->ReadFloat( startTime ); savefile->ReadFloat( duration ); savefile->ReadVec3( linearStartValue ); savefile->ReadVec3( linearBaseSpeed ); savefile->ReadVec3( linearSpeed ); state.linearExtrapolation.Init( startTime, duration, linearStartValue, linearBaseSpeed, linearSpeed, etype ); savefile->ReadInt( (int &)etype ); savefile->ReadFloat( startTime ); savefile->ReadFloat( duration ); savefile->ReadAngles( angularStartValue ); savefile->ReadAngles( angularBaseSpeed ); savefile->ReadAngles( angularSpeed ); state.angularExtrapolation.Init( startTime, duration, angularStartValue, angularBaseSpeed, angularSpeed, etype ); savefile->ReadFloat( startTime ); savefile->ReadFloat( accelTime ); savefile->ReadFloat( decelTime ); savefile->ReadFloat( duration ); savefile->ReadVec3( startPos ); savefile->ReadVec3( endPos ); state.linearInterpolation.Init( startTime, accelTime, decelTime, duration, startPos, endPos ); savefile->ReadFloat( startTime ); savefile->ReadFloat( accelTime ); savefile->ReadFloat( decelTime ); savefile->ReadFloat( duration ); savefile->ReadAngles( startAng ); savefile->ReadAngles( endAng ); state.angularInterpolation.Init( startTime, accelTime, decelTime, duration, startAng, endAng ); // spline is handled by owner savefile->ReadFloat( startTime ); savefile->ReadFloat( accelTime ); savefile->ReadFloat( duration ); savefile->ReadFloat( decelTime ); savefile->ReadFloat( startValue ); savefile->ReadFloat( endValue ); state.splineInterpolate.Init( startTime, accelTime, decelTime, duration, startValue, endValue ); } /* ================ idPhysics_Parametric::Save ================ */ void idPhysics_Parametric::Save( idSaveGame *savefile ) const { idPhysics_Parametric_SavePState( savefile, current ); idPhysics_Parametric_SavePState( savefile, saved ); savefile->WriteBool( isPusher ); savefile->WriteClipModel( clipModel ); savefile->WriteInt( pushFlags ); savefile->WriteTrace( pushResults ); savefile->WriteBool( isBlocked ); savefile->WriteBool( hasMaster ); savefile->WriteBool( isOrientated ); } /* ================ idPhysics_Parametric::Restore ================ */ void idPhysics_Parametric::Restore( idRestoreGame *savefile ) { idPhysics_Parametric_RestorePState( savefile, current ); idPhysics_Parametric_RestorePState( savefile, saved ); savefile->ReadBool( isPusher ); savefile->ReadClipModel( clipModel ); savefile->ReadInt( pushFlags ); savefile->ReadTrace( pushResults ); savefile->ReadBool( isBlocked ); savefile->ReadBool( hasMaster ); savefile->ReadBool( isOrientated ); } /* ================ idPhysics_Parametric::SetPusher ================ */ void idPhysics_Parametric::SetPusher( int flags ) { assert( clipModel ); isPusher = true; pushFlags = flags; } /* ================ idPhysics_Parametric::IsPusher ================ */ bool idPhysics_Parametric::IsPusher() const { return isPusher; } /* ================ idPhysics_Parametric::SetLinearExtrapolation ================ */ void idPhysics_Parametric::SetLinearExtrapolation( extrapolation_t type, int time, int duration, const idVec3 &base, const idVec3 &speed, const idVec3 &baseSpeed ) { current.time = gameLocal.time; current.linearExtrapolation.Init( time, duration, base, baseSpeed, speed, type ); current.localOrigin = base; Activate(); } /* ================ idPhysics_Parametric::SetAngularExtrapolation ================ */ void idPhysics_Parametric::SetAngularExtrapolation( extrapolation_t type, int time, int duration, const idAngles &base, const idAngles &speed, const idAngles &baseSpeed ) { current.time = gameLocal.time; current.angularExtrapolation.Init( time, duration, base, baseSpeed, speed, type ); current.localAngles = base; Activate(); } /* ================ idPhysics_Parametric::GetLinearExtrapolationType ================ */ extrapolation_t idPhysics_Parametric::GetLinearExtrapolationType() const { return current.linearExtrapolation.GetExtrapolationType(); } /* ================ idPhysics_Parametric::GetAngularExtrapolationType ================ */ extrapolation_t idPhysics_Parametric::GetAngularExtrapolationType() const { return current.angularExtrapolation.GetExtrapolationType(); } /* ================ idPhysics_Parametric::SetLinearInterpolation ================ */ void idPhysics_Parametric::SetLinearInterpolation( int time, int accelTime, int decelTime, int duration, const idVec3 &startPos, const idVec3 &endPos ) { current.time = gameLocal.time; current.linearInterpolation.Init( time, accelTime, decelTime, duration, startPos, endPos ); current.localOrigin = startPos; Activate(); } /* ================ idPhysics_Parametric::SetAngularInterpolation ================ */ void idPhysics_Parametric::SetAngularInterpolation( int time, int accelTime, int decelTime, int duration, const idAngles &startAng, const idAngles &endAng ) { current.time = gameLocal.time; current.angularInterpolation.Init( time, accelTime, decelTime, duration, startAng, endAng ); current.localAngles = startAng; Activate(); } /* ================ idPhysics_Parametric::SetSpline ================ */ void idPhysics_Parametric::SetSpline( idCurve_Spline *spline, int accelTime, int decelTime, bool useSplineAngles ) { if ( current.spline != NULL ) { delete current.spline; current.spline = NULL; } current.spline = spline; if ( current.spline != NULL ) { float startTime = current.spline->GetTime( 0 ); float endTime = current.spline->GetTime( current.spline->GetNumValues() - 1 ); float length = current.spline->GetLengthForTime( endTime ); current.splineInterpolate.Init( startTime, accelTime, decelTime, endTime - startTime, 0.0f, length ); } current.useSplineAngles = useSplineAngles; Activate(); } /* ================ idPhysics_Parametric::GetSpline ================ */ idCurve_Spline *idPhysics_Parametric::GetSpline() const { return current.spline; } /* ================ idPhysics_Parametric::GetSplineAcceleration ================ */ int idPhysics_Parametric::GetSplineAcceleration() const { return current.splineInterpolate.GetAcceleration(); } /* ================ idPhysics_Parametric::GetSplineDeceleration ================ */ int idPhysics_Parametric::GetSplineDeceleration() const { return current.splineInterpolate.GetDeceleration(); } /* ================ idPhysics_Parametric::UsingSplineAngles ================ */ bool idPhysics_Parametric::UsingSplineAngles() const { return current.useSplineAngles; } /* ================ idPhysics_Parametric::GetLocalOrigin ================ */ void idPhysics_Parametric::GetLocalOrigin( idVec3 &curOrigin ) const { curOrigin = current.localOrigin; } /* ================ idPhysics_Parametric::GetLocalAngles ================ */ void idPhysics_Parametric::GetLocalAngles( idAngles &curAngles ) const { curAngles = current.localAngles; } /* ================ idPhysics_Parametric::SetClipModel ================ */ void idPhysics_Parametric::SetClipModel( idClipModel *model, float density, int id, bool freeOld ) { assert( self ); assert( model ); if ( clipModel && clipModel != model && freeOld ) { delete clipModel; } clipModel = model; clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } /* ================ idPhysics_Parametric::GetClipModel ================ */ idClipModel *idPhysics_Parametric::GetClipModel( int id ) const { return clipModel; } /* ================ idPhysics_Parametric::GetNumClipModels ================ */ int idPhysics_Parametric::GetNumClipModels() const { return ( clipModel != NULL ); } /* ================ idPhysics_Parametric::SetMass ================ */ void idPhysics_Parametric::SetMass( float mass, int id ) { } /* ================ idPhysics_Parametric::GetMass ================ */ float idPhysics_Parametric::GetMass( int id ) const { return 0.0f; } /* ================ idPhysics_Parametric::SetClipMask ================ */ void idPhysics_Parametric::SetContents( int contents, int id ) { if ( clipModel ) { clipModel->SetContents( contents ); } } /* ================ idPhysics_Parametric::SetClipMask ================ */ int idPhysics_Parametric::GetContents( int id ) const { if ( clipModel ) { return clipModel->GetContents(); } return 0; } /* ================ idPhysics_Parametric::GetBounds ================ */ const idBounds &idPhysics_Parametric::GetBounds( int id ) const { if ( clipModel ) { return clipModel->GetBounds(); } return idPhysics_Base::GetBounds(); } /* ================ idPhysics_Parametric::GetAbsBounds ================ */ const idBounds &idPhysics_Parametric::GetAbsBounds( int id ) const { if ( clipModel ) { return clipModel->GetAbsBounds(); } return idPhysics_Base::GetAbsBounds(); } /* ================ idPhysics_Parametric::Evaluate ================ */ bool idPhysics_Parametric::Evaluate( int timeStepMSec, int endTimeMSec ) { idVec3 oldLocalOrigin, oldOrigin, masterOrigin; idAngles oldLocalAngles, oldAngles; idMat3 oldAxis, masterAxis; isBlocked = false; oldLocalOrigin = current.localOrigin; oldOrigin = current.origin; oldLocalAngles = current.localAngles; oldAngles = current.angles; oldAxis = current.axis; current.localOrigin.Zero(); current.localAngles.Zero(); if ( current.spline != NULL ) { float length = current.splineInterpolate.GetCurrentValue( endTimeMSec ); float t = current.spline->GetTimeForLength( length, 0.01f ); current.localOrigin = current.spline->GetCurrentValue( t ); if ( current.useSplineAngles ) { current.localAngles = current.spline->GetCurrentFirstDerivative( t ).ToAngles(); } } else if ( current.linearInterpolation.GetDuration() != 0 ) { current.localOrigin += current.linearInterpolation.GetCurrentValue( endTimeMSec ); } else { current.localOrigin += current.linearExtrapolation.GetCurrentValue( endTimeMSec ); } if ( current.angularInterpolation.GetDuration() != 0 ) { current.localAngles += current.angularInterpolation.GetCurrentValue( endTimeMSec ); } else { current.localAngles += current.angularExtrapolation.GetCurrentValue( endTimeMSec ); } current.localAngles.Normalize360(); current.origin = current.localOrigin; current.angles = current.localAngles; current.axis = current.localAngles.ToMat3(); if ( hasMaster ) { self->GetMasterPosition( masterOrigin, masterAxis ); if ( masterAxis.IsRotated() ) { current.origin = current.origin * masterAxis + masterOrigin; if ( isOrientated ) { current.axis *= masterAxis; current.angles = current.axis.ToAngles(); } } else { current.origin += masterOrigin; } } if ( isPusher ) { gameLocal.push.ClipPush( pushResults, self, pushFlags, oldOrigin, oldAxis, current.origin, current.axis ); if ( pushResults.fraction < 1.0f ) { if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, oldOrigin, oldAxis ); } current.localOrigin = oldLocalOrigin; current.origin = oldOrigin; current.localAngles = oldLocalAngles; current.angles = oldAngles; current.axis = oldAxis; isBlocked = true; return false; } current.angles = current.axis.ToAngles(); } if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } current.time = endTimeMSec; if ( TestIfAtRest() ) { Rest(); } return ( current.origin != oldOrigin || current.axis != oldAxis ); } /* ================ Sets the currentInterpolated state based on previous, next, and the fraction. ================ */ bool idPhysics_Parametric::Interpolate( const float fraction ) { if( self->GetNumSnapshotsReceived() <= 1 ) { return false; } idVec3 oldOrigin = current.origin; idMat3 oldAxis = current.axis; const bool hasChanged = InterpolatePhysicsState( current, previous, next, fraction ); gameLocal.push.ClipPush( pushResults, self, pushFlags, oldOrigin, oldAxis, current.origin, current.axis ); if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } return hasChanged; } /* ================ idPhysics_Parametric::UpdateTime ================ */ void idPhysics_Parametric::UpdateTime( int endTimeMSec ) { int timeLeap = endTimeMSec - current.time; current.time = endTimeMSec; // move the trajectory start times to sync the trajectory with the current endTime current.linearExtrapolation.SetStartTime( current.linearExtrapolation.GetStartTime() + timeLeap ); current.angularExtrapolation.SetStartTime( current.angularExtrapolation.GetStartTime() + timeLeap ); current.linearInterpolation.SetStartTime( current.linearInterpolation.GetStartTime() + timeLeap ); current.angularInterpolation.SetStartTime( current.angularInterpolation.GetStartTime() + timeLeap ); if ( current.spline != NULL ) { current.spline->ShiftTime( timeLeap ); current.splineInterpolate.SetStartTime( current.splineInterpolate.GetStartTime() + timeLeap ); } } /* ================ idPhysics_Parametric::GetTime ================ */ int idPhysics_Parametric::GetTime() const { return current.time; } /* ================ idPhysics_Parametric::IsAtRest ================ */ bool idPhysics_Parametric::IsAtRest() const { return current.atRest >= 0; } /* ================ idPhysics_Parametric::GetRestStartTime ================ */ int idPhysics_Parametric::GetRestStartTime() const { return current.atRest; } /* ================ idPhysics_Parametric::IsPushable ================ */ bool idPhysics_Parametric::IsPushable() const { return false; } /* ================ idPhysics_Parametric::SaveState ================ */ void idPhysics_Parametric::SaveState() { saved = current; } /* ================ idPhysics_Parametric::RestoreState ================ */ void idPhysics_Parametric::RestoreState() { current = saved; if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } } /* ================ idPhysics_Parametric::SetOrigin ================ */ void idPhysics_Parametric::SetOrigin( const idVec3 &newOrigin, int id ) { idVec3 masterOrigin; idMat3 masterAxis; current.linearExtrapolation.SetStartValue( newOrigin ); current.linearInterpolation.SetStartValue( newOrigin ); current.localOrigin = current.linearExtrapolation.GetCurrentValue( current.time ); if ( hasMaster ) { self->GetMasterPosition( masterOrigin, masterAxis ); current.origin = masterOrigin + current.localOrigin * masterAxis; } else { current.origin = current.localOrigin; } if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } Activate(); } /* ================ idPhysics_Parametric::SetAxis ================ */ void idPhysics_Parametric::SetAxis( const idMat3 &newAxis, int id ) { idVec3 masterOrigin; idMat3 masterAxis; current.localAngles = newAxis.ToAngles(); current.angularExtrapolation.SetStartValue( current.localAngles ); current.angularInterpolation.SetStartValue( current.localAngles ); current.localAngles = current.angularExtrapolation.GetCurrentValue( current.time ); if ( hasMaster && isOrientated ) { self->GetMasterPosition( masterOrigin, masterAxis ); current.axis = current.localAngles.ToMat3() * masterAxis; current.angles = current.axis.ToAngles(); } else { current.axis = current.localAngles.ToMat3(); current.angles = current.localAngles; } if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } Activate(); } /* ================ idPhysics_Parametric::Move ================ */ void idPhysics_Parametric::Translate( const idVec3 &translation, int id ) { } /* ================ idPhysics_Parametric::Rotate ================ */ void idPhysics_Parametric::Rotate( const idRotation &rotation, int id ) { } /* ================ idPhysics_Parametric::GetOrigin ================ */ const idVec3 &idPhysics_Parametric::GetOrigin( int id ) const { return current.origin; } /* ================ idPhysics_Parametric::GetAxis ================ */ const idMat3 &idPhysics_Parametric::GetAxis( int id ) const { return current.axis; } /* ================ idPhysics_Parametric::GetAngles ================ */ void idPhysics_Parametric::GetAngles( idAngles &curAngles ) const { curAngles = current.angles; } /* ================ idPhysics_Parametric::SetLinearVelocity ================ */ void idPhysics_Parametric::SetLinearVelocity( const idVec3 &newLinearVelocity, int id ) { SetLinearExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, current.origin, newLinearVelocity, vec3_origin ); current.linearInterpolation.Init( 0, 0, 0, 0, vec3_zero, vec3_zero ); Activate(); } /* ================ idPhysics_Parametric::SetAngularVelocity ================ */ void idPhysics_Parametric::SetAngularVelocity( const idVec3 &newAngularVelocity, int id ) { idRotation rotation; idVec3 vec; float angle; vec = newAngularVelocity; angle = vec.Normalize(); rotation.Set( vec3_origin, vec, (float) RAD2DEG( angle ) ); SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, current.angles, rotation.ToAngles(), ang_zero ); current.angularInterpolation.Init( 0, 0, 0, 0, ang_zero, ang_zero ); Activate(); } /* ================ idPhysics_Parametric::GetLinearVelocity ================ */ const idVec3 &idPhysics_Parametric::GetLinearVelocity( int id ) const { static idVec3 curLinearVelocity; curLinearVelocity = current.linearExtrapolation.GetCurrentSpeed( gameLocal.time ); return curLinearVelocity; } /* ================ idPhysics_Parametric::GetAngularVelocity ================ */ const idVec3 &idPhysics_Parametric::GetAngularVelocity( int id ) const { static idVec3 curAngularVelocity; idAngles angles; angles = current.angularExtrapolation.GetCurrentSpeed( gameLocal.time ); curAngularVelocity = angles.ToAngularVelocity(); return curAngularVelocity; } /* ================ idPhysics_Parametric::DisableClip ================ */ void idPhysics_Parametric::DisableClip() { if ( clipModel ) { clipModel->Disable(); } } /* ================ idPhysics_Parametric::EnableClip ================ */ void idPhysics_Parametric::EnableClip() { if ( clipModel ) { clipModel->Enable(); } } /* ================ idPhysics_Parametric::UnlinkClip ================ */ void idPhysics_Parametric::UnlinkClip() { if ( clipModel ) { clipModel->Unlink(); } } /* ================ idPhysics_Parametric::LinkClip ================ */ void idPhysics_Parametric::LinkClip() { if ( clipModel ) { clipModel->Link( gameLocal.clip, self, 0, current.origin, current.axis ); } } /* ================ idPhysics_Parametric::GetBlockingInfo ================ */ const trace_t *idPhysics_Parametric::GetBlockingInfo() const { return ( isBlocked ? &pushResults : NULL ); } /* ================ idPhysics_Parametric::GetBlockingEntity ================ */ idEntity *idPhysics_Parametric::GetBlockingEntity() const { if ( isBlocked ) { return gameLocal.entities[ pushResults.c.entityNum ]; } return NULL; } /* ================ idPhysics_Parametric::SetMaster ================ */ void idPhysics_Parametric::SetMaster( idEntity *master, const bool orientated ) { idVec3 masterOrigin; idMat3 masterAxis; if ( master ) { if ( !hasMaster ) { // transform from world space to master space self->GetMasterPosition( masterOrigin, masterAxis ); current.localOrigin = ( current.origin - masterOrigin ) * masterAxis.Transpose(); if ( orientated ) { current.localAngles = ( current.axis * masterAxis.Transpose() ).ToAngles(); } else { current.localAngles = current.axis.ToAngles(); } current.linearExtrapolation.SetStartValue( current.localOrigin ); current.angularExtrapolation.SetStartValue( current.localAngles ); hasMaster = true; isOrientated = orientated; } } else { if ( hasMaster ) { // transform from master space to world space current.localOrigin = current.origin; current.localAngles = current.angles; SetLinearExtrapolation( EXTRAPOLATION_NONE, 0, 0, current.origin, vec3_origin, vec3_origin ); SetAngularExtrapolation( EXTRAPOLATION_NONE, 0, 0, current.angles, ang_zero, ang_zero ); hasMaster = false; } } } /* ================ idPhysics_Parametric::GetLinearEndTime ================ */ int idPhysics_Parametric::GetLinearEndTime() const { if ( current.spline != NULL ) { if ( current.spline->GetBoundaryType() != idCurve_Spline::BT_CLOSED ) { return current.spline->GetTime( current.spline->GetNumValues() - 1 ); } else { return 0; } } else if ( current.linearInterpolation.GetDuration() != 0 ) { return current.linearInterpolation.GetEndTime(); } else { return current.linearExtrapolation.GetEndTime(); } } /* ================ idPhysics_Parametric::GetAngularEndTime ================ */ int idPhysics_Parametric::GetAngularEndTime() const { if ( current.angularInterpolation.GetDuration() != 0 ) { return current.angularInterpolation.GetEndTime(); } else { return current.angularExtrapolation.GetEndTime(); } } /* ================ idPhysics_Parametric::WriteToSnapshot ================ */ void idPhysics_Parametric::WriteToSnapshot( idBitMsg &msg ) const { const idQuat currentQuat = current.axis.ToQuat(); WriteFloatArray( msg, current.origin ); WriteFloatArray( msg, currentQuat ); } /* ================ idPhysics_Parametric::ReadFromSnapshot ================ */ void idPhysics_Parametric::ReadFromSnapshot( const idBitMsg &msg ) { previous = next; next.origin = ReadFloatArray< idVec3 >( msg ); next.axis = ReadFloatArray< idQuat >( msg ); if( self->GetNumSnapshotsReceived() <= 1 ) { current.origin = next.origin; previous.origin = next.origin; current.axis = next.axis.ToMat3(); previous.axis = next.axis; } }