123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- 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.
- ===========================================================================
- */
- #include "../../idlib/precompiled.h"
- #pragma hdrstop
- #include "../Game_local.h"
- /*
- ============
- idPush::InitSavingPushedEntityPositions
- ============
- */
- void idPush::InitSavingPushedEntityPositions( void ) {
- numPushed = 0;
- }
- /*
- ============
- idPush::SaveEntityPosition
- ============
- */
- void idPush::SaveEntityPosition( idEntity *ent ) {
- int i;
- // if already saved the physics state for this entity
- for ( i = 0; i < numPushed; i++ ) {
- if ( pushed[i].ent == ent ) {
- return;
- }
- }
- // don't overflow
- if ( numPushed >= MAX_GENTITIES ) {
- gameLocal.Error( "more than MAX_GENTITIES pushed entities" );
- return;
- }
- pushed[numPushed].ent = ent;
- // if the entity is an actor
- if ( ent->IsType( idActor::Type ) ) {
- // save the delta view angles
- pushed[numPushed].deltaViewAngles = static_cast<idActor *>(ent)->GetDeltaViewAngles();
- }
- // save the physics state
- ent->GetPhysics()->SaveState();
- numPushed++;
- }
- /*
- ============
- idPush::RestorePushedEntityPositions
- ============
- */
- void idPush::RestorePushedEntityPositions( void ) {
- int i;
- for ( i = 0; i < numPushed; i++ ) {
- // if the entity is an actor
- if ( pushed[i].ent->IsType( idActor::Type ) ) {
- // set back the delta view angles
- static_cast<idActor *>(pushed[i].ent)->SetDeltaViewAngles( pushed[i].deltaViewAngles );
- }
- // restore the physics state
- pushed[i].ent->GetPhysics()->RestoreState();
- }
- }
- /*
- ============
- idPush::RotateEntityToAxial
- ============
- */
- bool idPush::RotateEntityToAxial( idEntity *ent, idVec3 rotationPoint ) {
- int i;
- trace_t trace;
- idRotation rotation;
- idMat3 axis;
- idPhysics *physics;
- physics = ent->GetPhysics();
- axis = physics->GetAxis();
- if ( !axis.IsRotated() ) {
- return true;
- }
- // try to rotate the bbox back to axial with at most four rotations
- for ( i = 0; i < 4; i++ ) {
- axis = physics->GetAxis();
- rotation = axis.ToRotation();
- rotation.Scale( -1 );
- rotation.SetOrigin( rotationPoint );
- // tiny float numbers in the clip axis, this can get the entity stuck
- if ( rotation.GetAngle() == 0.0f ) {
- physics->SetAxis( mat3_identity );
- return true;
- }
- //
- ent->GetPhysics()->ClipRotation( trace, rotation, NULL );
- // if the full rotation is possible
- if ( trace.fraction >= 1.0f ) {
- // set bbox in final axial position
- physics->SetOrigin( trace.endpos );
- physics->SetAxis( mat3_identity );
- return true;
- }
- // if partial rotation was possible
- else if ( trace.fraction > 0.0f ) {
- // partial rotation
- physics->SetOrigin( trace.endpos );
- physics->SetAxis( trace.endAxis );
- }
- // next rotate around collision point
- rotationPoint = trace.c.point;
- }
- return false;
- }
- #ifdef NEW_PUSH
- /*
- ============
- idPush::CanPushEntity
- ============
- */
- bool idPush::CanPushEntity( idEntity *ent, idEntity *pusher, idEntity *initialPusher, const int flags ) {
- // if the physics object is not pushable
- if ( !ent->GetPhysics()->IsPushable() ) {
- return false;
- }
- // if the entity doesn't clip with this pusher
- if ( !( ent->GetPhysics()->GetClipMask() & pusher->GetPhysics()->GetContents() ) ) {
- return false;
- }
- // don't push players in noclip mode
- if ( ent->client && ent->client->noclip ) {
- return false;
- }
- // if we should only push idMoveable entities
- if ( ( flags & PUSHFL_ONLYMOVEABLE ) && !ent->IsType( idMoveable::Type ) ) {
- return false;
- }
- // if we shouldn't push entities the original pusher rests upon
- if ( flags & PUSHFL_NOGROUNDENTITIES ) {
- if ( initialPusher->GetPhysics()->IsGroundEntity( ent->entityNumber ) ) {
- return false;
- }
- }
- return true;
- }
- /*
- ============
- idPush::AddEntityToPushedGroup
- ============
- */
- void idPush::AddEntityToPushedGroup( idEntity *ent, float fraction, bool groundContact ) {
- int i, j;
- for ( i = 0; i < pushedGroupSize; i++ ) {
- if ( ent == pushedGroup[i].ent ) {
- if ( fraction > pushedGroup[i].fraction ) {
- pushedGroup[i].fraction = fraction;
- pushedGroup[i].groundContact &= groundContact;
- pushedGroup[i].test = true;
- }
- return;
- }
- else if ( fraction > pushedGroup[i].fraction ) {
- for ( j = pushedGroupSize; j > i; j-- ) {
- pushedGroup[j] = pushedGroup[j-1];
- }
- break;
- }
- }
- // put the entity in the group
- pushedGroupSize++;
- pushedGroup[i].ent = ent;
- pushedGroup[i].fraction = fraction;
- pushedGroup[i].groundContact = groundContact;
- pushedGroup[i].test = true;
- // remove any further occurances of the same entity in the group
- for ( i++; i < pushedGroupSize; i++ ) {
- if ( ent == pushedGroup[i].ent ) {
- for ( j = i+1; j < pushedGroupSize; j++ ) {
- pushedGroup[j-1] = pushedGroup[j];
- }
- pushedGroupSize--;
- break;
- }
- }
- }
- /*
- ============
- idPush::IsFullyPushed
- ============
- */
- bool idPush::IsFullyPushed( idEntity *ent ) {
- int i;
- for ( i = 0; i < pushedGroupSize; i++ ) {
- if ( pushedGroup[i].fraction < 1.0f ) {
- return false;
- }
- if ( ent == pushedGroup[i].ent ) {
- return true;
- }
- }
- return false;
- }
- /*
- ============
- idPush::ClipTranslationAgainstPusher
- ============
- */
- bool idPush::ClipTranslationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idVec3 &translation ) {
- int i, n;
- trace_t t;
- results.fraction = 1.0f;
- n = pusher->GetPhysics()->GetNumClipModels();
- for ( i = 0; i < n; i++ ) {
- ent->GetPhysics()->ClipTranslation( t, translation, pusher->GetPhysics()->GetClipModel( i ) );
- if ( t.fraction < results.fraction ) {
- results = t;
- }
- }
- return ( results.fraction < 1.0f );
- }
- /*
- ============
- idPush::GetPushableEntitiesForTranslation
- ============
- */
- int idPush::GetPushableEntitiesForTranslation( idEntity *pusher, idEntity *initialPusher, const int flags,
- const idVec3 &translation, idEntity *entityList[], int maxEntities ) {
- int i, n, l;
- idBounds bounds, pushBounds;
- idPhysics *physics;
- // get bounds for the whole movement
- physics = pusher->GetPhysics();
- bounds = physics->GetBounds();
- pushBounds.FromBoundsTranslation( bounds, physics->GetOrigin(), physics->GetAxis(), translation );
- pushBounds.ExpandSelf( 2.0f );
- // get all entities within the push bounds
- n = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES );
- for ( l = i = 0; i < n; i++ ) {
- if ( entityList[i] == pusher || entityList[i] == initialPusher ) {
- continue;
- }
- if ( CanPushEntity( entityList[i], pusher, initialPusher, flags ) ) {
- entityList[l++] = entityList[i];
- }
- }
- return l;
- }
- /*
- ============
- idPush::ClipTranslationalPush
- Try to push other entities by translating the given entity.
- ============
- */
- float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags,
- const idVec3 &newOrigin, const idVec3 &translation ) {
- int i, j, numListedEntities;
- idEntity *curPusher, *ent, *entityList[ MAX_GENTITIES ];
- float fraction;
- bool groundContact, blocked = false;
- float totalMass;
- trace_t trace;
- idVec3 realTranslation, partialTranslation;
- totalMass = 0.0f;
- results.fraction = 1.0f;
- results.endpos = newOrigin;
- results.endAxis = pusher->GetPhysics()->GetAxis();
- memset( results.c, 0, sizeof( results.c ) );
- if ( translation == vec3_origin ) {
- return totalMass;
- }
- // clip against all non-pushable physics objects
- if ( flags & PUSHFL_CLIP ) {
- numListedEntities = GetPushableEntitiesForTranslation( pusher, pusher, flags, translation, entityList, MAX_GENTITIES );
- // disable pushable entities for collision detection
- for ( i = 0; i < numListedEntities; i++ ) {
- entityList[i]->GetPhysics()->DisableClip();
- }
- // clip translation
- pusher->GetPhysics()->ClipTranslation( results, translation, NULL );
- // enable pushable entities
- for ( i = 0; i < numListedEntities; i++ ) {
- entityList[i]->GetPhysics()->EnableClip();
- }
- if ( results.fraction == 0.0f ) {
- return totalMass;
- }
- realTranslation = results.fraction * translation;
- }
- else {
- realTranslation = translation;
- }
- // put the pusher in the group of pushed physics objects
- pushedGroup[0].ent = pusher;
- pushedGroup[0].fraction = 1.0f;
- pushedGroup[0].groundContact = true;
- pushedGroup[0].test = true;
- pushedGroupSize = 1;
- // get all physics objects that need to be pushed
- for ( i = 0; i < pushedGroupSize; ) {
- if ( !pushedGroup[i].test ) {
- i++;
- continue;
- }
- pushedGroup[i].test = false;
- curPusher = pushedGroup[i].ent;
- fraction = pushedGroup[i].fraction;
- groundContact = pushedGroup[i].groundContact;
- i = 0;
- numListedEntities = GetPushableEntitiesForTranslation( curPusher, pusher, flags, realTranslation, entityList, MAX_GENTITIES );
- for ( j = 0; j < numListedEntities; j++ ) {
- ent = entityList[ j ];
- if ( IsFullyPushed( ent ) ) {
- continue;
- }
- if ( !CanPushEntity( ent, curPusher, pusher, flags ) ) {
- continue;
- }
- if ( ent->GetPhysics()->IsGroundEntity( curPusher->entityNumber ) ) {
- AddEntityToPushedGroup( ent, 1.0f * fraction, false );
- }
- else if ( ClipTranslationAgainstPusher( trace, ent, curPusher, -fraction * realTranslation ) ) {
- AddEntityToPushedGroup( ent, ( 1.0f - trace.fraction ) * fraction, groundContact );
- }
- }
- }
- // save physics states and disable physics objects for collision detection
- for ( i = 0; i < pushedGroupSize; i++ ) {
- SaveEntityPosition( pushedGroup[i].ent );
- pushedGroup[i].ent->GetPhysics()->DisableClip();
- }
- // clip all pushed physics objects
- for ( i = 1; i < pushedGroupSize; i++ ) {
- partialTranslation = realTranslation * pushedGroup[i].fraction;
- pushedGroup[i].ent->GetPhysics()->ClipTranslation( trace, partialTranslation, NULL );
- if ( trace.fraction < 1.0f ) {
- blocked = true;
- break;
- }
- }
- // enable all physics objects for collision detection
- for ( i = 1; i < pushedGroupSize; i++ ) {
- pushedGroup[i].ent->GetPhysics()->EnableClip();
- }
- // push all or nothing
- if ( blocked ) {
- if ( flags & PUSHFL_CLIP ) {
- pusher->GetPhysics()->ClipTranslation( results, realTranslation, NULL );
- }
- else {
- results.fraction = 0.0f;
- results.endpos = pusher->GetPhysics()->GetOrigin();
- results.endAxis = pusher->GetPhysics()->GetAxis();
- }
- }
- else {
- // translate all pushed physics objects
- for ( i = 1; i < pushedGroupSize; i++ ) {
- partialTranslation = realTranslation * pushedGroup[i].fraction;
- pushedGroup[i].ent->GetPhysics()->Translate( partialTranslation );
- totalMass += pushedGroup[i].ent->GetPhysics()->GetMass();
- }
- // translate the clip models of the pusher
- for ( i = 0; i < pusher->GetPhysics()->GetNumClipModels(); i++ ) {
- pusher->GetPhysics()->GetClipModel(i)->Translate( results.fraction * realTranslation );
- pusher->GetPhysics()->GetClipModel(i)->Link( gameLocal.clip );
- }
- }
- return totalMass;
- }
- /*
- ============
- idPush::ClipRotationAgainstPusher
- ============
- */
- bool idPush::ClipRotationAgainstPusher( trace_t &results, idEntity *ent, idEntity *pusher, const idRotation &rotation ) {
- int i, n;
- trace_t t;
- results.fraction = 1.0f;
- n = pusher->GetPhysics()->GetNumClipModels();
- for ( i = 0; i < n; i++ ) {
- ent->GetPhysics()->ClipRotation( t, rotation, pusher->GetPhysics()->GetClipModel( i ) );
- if ( t.fraction < results.fraction ) {
- results = t;
- }
- }
- return ( results.fraction < 1.0f );
- }
- /*
- ============
- idPush::GetPushableEntitiesForRotation
- ============
- */
- int idPush::GetPushableEntitiesForRotation( idEntity *pusher, idEntity *initialPusher, const int flags,
- const idRotation &rotation, idEntity *entityList[], int maxEntities ) {
- int i, n, l;
- idBounds bounds, pushBounds;
- idPhysics *physics;
- // get bounds for the whole movement
- physics = pusher->GetPhysics();
- bounds = physics->GetBounds();
- pushBounds.FromBoundsRotation( bounds, physics->GetOrigin(), physics->GetAxis(), rotation );
- pushBounds.ExpandSelf( 2.0f );
- // get all entities within the push bounds
- n = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES );
- for ( l = i = 0; i < n; i++ ) {
- if ( entityList[i] == pusher || entityList[i] == initialPusher ) {
- continue;
- }
- if ( CanPushEntity( entityList[i], pusher, initialPusher, flags ) ) {
- entityList[l++] = entityList[i];
- }
- }
- return l;
- }
- /*
- ============
- idPush::ClipRotationalPush
- Try to push other entities by rotating the given entity.
- ============
- */
- float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags,
- const idMat3 &newAxis, const idRotation &rotation ) {
- int i, j, numListedEntities;
- idEntity *curPusher, *ent, *entityList[ MAX_GENTITIES ];
- float fraction;
- bool groundContact, blocked = false;
- float totalMass;
- trace_t trace;
- idRotation realRotation, partialRotation;
- idMat3 oldAxis;
- totalMass = 0.0f;
- results.fraction = 1.0f;
- results.endpos = pusher->GetPhysics()->GetOrigin();
- results.endAxis = newAxis;
- memset( results.c, 0, sizeof( results.c ) );
- if ( !rotation.GetAngle() ) {
- return totalMass;
- }
- // clip against all non-pushable physics objects
- if ( flags & PUSHFL_CLIP ) {
- numListedEntities = GetPushableEntitiesForRotation( pusher, pusher, flags, rotation, entityList, MAX_GENTITIES );
- // disable pushable entities for collision detection
- for ( i = 0; i < numListedEntities; i++ ) {
- entityList[i]->GetPhysics()->DisableClip();
- }
- // clip rotation
- pusher->GetPhysics()->ClipRotation( results, rotation, NULL );
- // enable pushable entities
- for ( i = 0; i < numListedEntities; i++ ) {
- entityList[i]->GetPhysics()->EnableClip();
- }
- if ( results.fraction == 0.0f ) {
- return totalMass;
- }
- realRotation = results.fraction * rotation;
- }
- else {
- realRotation = rotation;
- }
- // put the pusher in the group of pushed physics objects
- pushedGroup[0].ent = pusher;
- pushedGroup[0].fraction = 1.0f;
- pushedGroup[0].groundContact = true;
- pushedGroup[0].test = true;
- pushedGroupSize = 1;
- // get all physics objects that need to be pushed
- for ( i = 0; i < pushedGroupSize; ) {
- if ( !pushedGroup[i].test ) {
- i++;
- continue;
- }
- pushedGroup[i].test = false;
- curPusher = pushedGroup[i].ent;
- fraction = pushedGroup[i].fraction;
- groundContact = pushedGroup[i].groundContact;
- i = 0;
- numListedEntities = GetPushableEntitiesForRotation( curPusher, pusher, flags, realRotation, entityList, MAX_GENTITIES );
- for ( j = 0; j < numListedEntities; j++ ) {
- ent = entityList[ j ];
- if ( IsFullyPushed( ent ) ) {
- continue;
- }
- if ( ent->GetPhysics()->IsGroundEntity( curPusher->entityNumber ) ) {
- AddEntityToPushedGroup( ent, 1.0f * fraction, false );
- }
- else if ( ClipRotationAgainstPusher( trace, ent, curPusher, -fraction * realRotation ) ) {
- AddEntityToPushedGroup( ent, ( 1.0f - trace.fraction ) * fraction, groundContact );
- }
- }
- }
- // save physics states and disable physics objects for collision detection
- for ( i = 1; i < pushedGroupSize; i++ ) {
- SaveEntityPosition( pushedGroup[i].ent );
- pushedGroup[i].ent->GetPhysics()->DisableClip();
- }
- // clip all pushed physics objects
- for ( i = 1; i < pushedGroupSize; i++ ) {
- partialRotation = realRotation * pushedGroup[i].fraction;
- pushedGroup[i].ent->GetPhysics()->ClipRotation( trace, partialRotation, NULL );
- if ( trace.fraction < 1.0f ) {
- blocked = true;
- break;
- }
- }
- // enable all physics objects for collision detection
- for ( i = 1; i < pushedGroupSize; i++ ) {
- pushedGroup[i].ent->GetPhysics()->EnableClip();
- }
- // push all or nothing
- if ( blocked ) {
- if ( flags & PUSHFL_CLIP ) {
- pusher->GetPhysics()->ClipRotation( results, realRotation, NULL );
- }
- else {
- results.fraction = 0.0f;
- results.endpos = pusher->GetPhysics()->GetOrigin();
- results.endAxis = pusher->GetPhysics()->GetAxis();
- }
- }
- else {
- // rotate all pushed physics objects
- for ( i = 1; i < pushedGroupSize; i++ ) {
- partialRotation = realRotation * pushedGroup[i].fraction;
- pushedGroup[i].ent->GetPhysics()->Rotate( partialRotation );
- totalMass += pushedGroup[i].ent->GetPhysics()->GetMass();
- }
- // rotate the clip models of the pusher
- for ( i = 0; i < pusher->GetPhysics()->GetNumClipModels(); i++ ) {
- pusher->GetPhysics()->GetClipModel(i)->Rotate( realRotation );
- pusher->GetPhysics()->GetClipModel(i)->Link( gameLocal.clip );
- pusher->GetPhysics()->GetClipModel(i)->Enable();
- }
- // rotate any actors back to axial
- for ( i = 1; i < pushedGroupSize; i++ ) {
- // if the entity is using actor physics
- if ( pushedGroup[i].ent->GetPhysics()->IsType( idPhysics_Actor::Type ) ) {
- // rotate the collision model back to axial
- if ( !RotateEntityToAxial( pushedGroup[i].ent, pushedGroup[i].ent->GetPhysics()->GetOrigin() ) ) {
- // don't allow rotation if the bbox is no longer axial
- results.fraction = 0.0f;
- results.endpos = pusher->GetPhysics()->GetOrigin();
- results.endAxis = pusher->GetPhysics()->GetAxis();
- }
- }
- }
- }
- return totalMass;
- }
- #else /* !NEW_PUSH */
- enum {
- PUSH_NO, // not pushed
- PUSH_OK, // pushed ok
- PUSH_BLOCKED // blocked
- };
- /*
- ============
- idPush::ClipEntityRotation
- ============
- */
- void idPush::ClipEntityRotation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel, idClipModel *skip, const idRotation &rotation ) {
- if ( skip ) {
- skip->Disable();
- }
- ent->GetPhysics()->ClipRotation( trace, rotation, clipModel );
- if ( skip ) {
- skip->Enable();
- }
- }
- /*
- ============
- idPush::ClipEntityTranslation
- ============
- */
- void idPush::ClipEntityTranslation( trace_t &trace, const idEntity *ent, const idClipModel *clipModel, idClipModel *skip, const idVec3 &translation ) {
- if ( skip ) {
- skip->Disable();
- }
- ent->GetPhysics()->ClipTranslation( trace, translation, clipModel );
- if ( skip ) {
- skip->Enable();
- }
- }
- /*
- ============
- idPush::TryRotatePushEntity
- ============
- */
- #ifdef _DEBUG
- // #define ROTATIONAL_PUSH_DEBUG
- #endif
- int idPush::TryRotatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags,
- const idMat3 &newAxis, const idRotation &rotation ) {
- trace_t trace;
- idVec3 rotationPoint;
- idRotation newRotation;
- float checkAngle;
- idPhysics *physics;
- physics = check->GetPhysics();
- #ifdef ROTATIONAL_PUSH_DEBUG
- bool startsolid = false;
- if ( physics->ClipContents( clipModel ) ) {
- startsolid = true;
- }
- #endif
- results.fraction = 1.0f;
- results.endpos = clipModel->GetOrigin();
- results.endAxis = newAxis;
- memset( &results.c, 0, sizeof( results.c ) );
- // always pushed when standing on the pusher
- if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) {
- // rotate the entity colliding with all other entities except the pusher itself
- ClipEntityRotation( trace, check, NULL, clipModel, rotation );
- // if there is a collision
- if ( trace.fraction < 1.0f ) {
- // angle along which the entity is pushed
- checkAngle = rotation.GetAngle() * trace.fraction;
- // test if the entity can stay at it's partly pushed position by rotating
- // the entity in reverse only colliding with pusher
- newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), -(rotation.GetAngle() - checkAngle) );
- ClipEntityRotation( results, check, clipModel, NULL, newRotation );
- // if there is a collision
- if ( results.fraction < 1.0f ) {
- // FIXME: try to push the blocking entity as well or try to slide along collision plane(s)?
- results.c.normal = -results.c.normal;
- results.c.dist = -results.c.dist;
- // the entity will be crushed between the pusher and some other entity
- return PUSH_BLOCKED;
- }
- }
- else {
- // angle along which the entity is pushed
- checkAngle = rotation.GetAngle();
- }
- // point to rotate entity bbox around back to axial
- rotationPoint = physics->GetOrigin();
- }
- else {
- // rotate entity in reverse only colliding with pusher
- newRotation = rotation;
- newRotation.Scale( -1 );
- //
- ClipEntityRotation( results, check, clipModel, NULL, newRotation );
- // if no collision with the pusher then the entity is not pushed by the pusher
- if ( results.fraction >= 1.0f ) {
- #ifdef ROTATIONAL_PUSH_DEBUG
- // set pusher into final position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );
- if ( physics->ClipContents( clipModel ) ) {
- if ( !startsolid ) {
- int bah = 1;
- }
- }
- #endif
- return PUSH_NO;
- }
- // get point to rotate bbox around back to axial
- rotationPoint = results.c.point;
- // angle along which the entity will be pushed
- checkAngle = rotation.GetAngle() * (1.0f - results.fraction);
- // rotate the entity colliding with all other entities except the pusher itself
- newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), checkAngle );
- ClipEntityRotation( trace, check, NULL, clipModel, newRotation );
- // if there is a collision
- if ( trace.fraction < 1.0f ) {
- // FIXME: try to push the blocking entity as well or try to slide along collision plane(s)?
- results.c.normal = -results.c.normal;
- results.c.dist = -results.c.dist;
- // the entity will be crushed between the pusher and some other entity
- return PUSH_BLOCKED;
- }
- }
- SaveEntityPosition( check );
- newRotation.Set( rotation.GetOrigin(), rotation.GetVec(), checkAngle );
- // NOTE: this code prevents msvc 6.0 & 7.0 from screwing up the above code in
- // release builds moving less floats than it should
- static float shit = checkAngle;
- newRotation.RotatePoint( rotationPoint );
- // rotate the entity
- physics->Rotate( newRotation );
- // set pusher into final position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );
- #ifdef ROTATIONAL_PUSH_DEBUG
- if ( physics->ClipContents( clipModel ) ) {
- if ( !startsolid ) {
- int bah = 1;
- }
- }
- #endif
- // if the entity uses actor physics
- if ( physics->IsType( idPhysics_Actor::Type ) ) {
- // rotate the collision model back to axial
- if ( !RotateEntityToAxial( check, rotationPoint ) ) {
- // don't allow rotation if the bbox is no longer axial
- return PUSH_BLOCKED;
- }
- }
- #ifdef ROTATIONAL_PUSH_DEBUG
- if ( physics->ClipContents( clipModel ) ) {
- if ( !startsolid ) {
- int bah = 1;
- }
- }
- #endif
- // if the entity is an actor using actor physics
- if ( check->IsType( idActor::Type ) && physics->IsType( idPhysics_Actor::Type ) ) {
- // if the entity is standing ontop of the pusher
- if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) {
- // rotate actor view
- idActor *actor = static_cast<idActor *>(check);
- idAngles delta = actor->GetDeltaViewAngles();
- delta.yaw += newRotation.ToMat3()[0].ToYaw();
- actor->SetDeltaViewAngles( delta );
- }
- }
- return PUSH_OK;
- }
- /*
- ============
- idPush::TryTranslatePushEntity
- ============
- */
- #ifdef _DEBUG
- // #define TRANSLATIONAL_PUSH_DEBUG
- #endif
- int idPush::TryTranslatePushEntity( trace_t &results, idEntity *check, idClipModel *clipModel, const int flags,
- const idVec3 &newOrigin, const idVec3 &move ) {
- trace_t trace;
- idVec3 checkMove;
- idVec3 oldOrigin;
- idPhysics *physics;
- physics = check->GetPhysics();
- #ifdef TRANSLATIONAL_PUSH_DEBUG
- bool startsolid = false;
- if ( physics->ClipContents( clipModel ) ) {
- startsolid = true;
- }
- #endif
- results.fraction = 1.0f;
- results.endpos = newOrigin;
- results.endAxis = clipModel->GetAxis();
- memset( &results.c, 0, sizeof( results.c ) );
- // always pushed when standing on the pusher
- if ( physics->IsGroundClipModel( clipModel->GetEntity()->entityNumber, clipModel->GetId() ) ) {
- // move the entity colliding with all other entities except the pusher itself
- ClipEntityTranslation( trace, check, NULL, clipModel, move );
- // if there is a collision
- if ( trace.fraction < 1.0f ) {
- // vector along which the entity is pushed
- checkMove = move * trace.fraction;
- // test if the entity can stay at it's partly pushed position by moving the entity in reverse only colliding with pusher
- ClipEntityTranslation( results, check, clipModel, NULL, -(move - checkMove) );
- // if there is a collision
- if ( results.fraction < 1.0f ) {
- // FIXME: try to push the blocking entity as well or try to slide along collision plane(s)?
- results.c.normal = -results.c.normal;
- results.c.dist = -results.c.dist;
- // the entity will be crushed between the pusher and some other entity
- return PUSH_BLOCKED;
- }
- }
- else {
- // vector along which the entity is pushed
- checkMove = move;
- }
- }
- else {
- // move entity in reverse only colliding with pusher
- ClipEntityTranslation( results, check, clipModel, NULL, -move );
- // if no collision with the pusher then the entity is not pushed by the pusher
- if ( results.fraction >= 1.0f ) {
- return PUSH_NO;
- }
- // vector along which the entity is pushed
- checkMove = move * (1.0f - results.fraction);
- // move the entity colliding with all other entities except the pusher itself
- ClipEntityTranslation( trace, check, NULL, clipModel, checkMove );
- // if there is a collisions
- if ( trace.fraction < 1.0f ) {
- results.c.normal = -results.c.normal;
- results.c.dist = -results.c.dist;
- // FIXME: try to push the blocking entity as well ?
- // FIXME: handle sliding along more than one collision plane ?
- // FIXME: this code has issues, player pushing box into corner in "maps/mre/aaron/test.map"
- /*
- oldOrigin = physics->GetOrigin();
- // movement still remaining
- checkMove *= (1.0f - trace.fraction);
- // project the movement along the collision plane
- if ( !checkMove.ProjectAlongPlane( trace.c.normal, 0.1f, 1.001f ) ) {
- return PUSH_BLOCKED;
- }
- checkMove *= 1.001f;
- // move entity from collision point along the collision plane
- physics->SetOrigin( trace.endpos );
- ClipEntityTranslation( trace, check, NULL, NULL, checkMove );
- if ( trace.fraction < 1.0f ) {
- physics->SetOrigin( oldOrigin );
- return PUSH_BLOCKED;
- }
- checkMove = trace.endpos - oldOrigin;
- // move entity in reverse only colliding with pusher
- physics->SetOrigin( trace.endpos );
- ClipEntityTranslation( trace, check, clipModel, NULL, -move );
- physics->SetOrigin( oldOrigin );
- */
- if ( trace.fraction < 1.0f ) {
- return PUSH_BLOCKED;
- }
- }
- }
- SaveEntityPosition( check );
- // translate the entity
- physics->Translate( checkMove );
- #ifdef TRANSLATIONAL_PUSH_DEBUG
- // set the pusher in the translated position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), newOrigin, clipModel->GetAxis() );
- if ( physics->ClipContents( clipModel ) ) {
- if ( !startsolid ) {
- int bah = 1;
- }
- }
- #endif
- return PUSH_OK;
- }
- /*
- ============
- idPush::DiscardEntities
- ============
- */
- int idPush::DiscardEntities( idEntity *entityList[], int numEntities, int flags, idEntity *pusher ) {
- int i, num;
- idEntity *check;
- // remove all entities we cannot or should not push from the list
- for ( num = i = 0; i < numEntities; i++ ) {
- check = entityList[ i ];
- // if the physics object is not pushable
- if ( !check->GetPhysics()->IsPushable() ) {
- continue;
- }
- // if the entity doesn't clip with this pusher
- if ( !( check->GetPhysics()->GetClipMask() & pusher->GetPhysics()->GetContents() ) ) {
- continue;
- }
- // don't push players in noclip mode
- if ( check->IsType( idPlayer::Type ) && static_cast<idPlayer *>(check)->noclip ) {
- continue;
- }
- // if we should only push idMoveable entities
- if ( ( flags & PUSHFL_ONLYMOVEABLE ) && !check->IsType( idMoveable::Type ) ) {
- continue;
- }
- // if we shouldn't push entities the clip model rests upon
- if ( flags & PUSHFL_NOGROUNDENTITIES ) {
- if ( pusher->GetPhysics()->IsGroundEntity( check->entityNumber ) ) {
- continue;
- }
- }
- // keep entity in list
- entityList[ num++ ] = entityList[i];
- }
- return num;
- }
- /*
- ============
- idPush::ClipTranslationalPush
- Try to push other entities by moving the given entity.
- ============
- */
- float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags,
- const idVec3 &newOrigin, const idVec3 &translation ) {
- int i, listedEntities, res;
- idEntity *check, *entityList[ MAX_GENTITIES ];
- idBounds bounds, pushBounds;
- idVec3 clipMove, clipOrigin, oldOrigin, dir, impulse;
- trace_t pushResults;
- bool wasEnabled;
- float totalMass;
- idClipModel *clipModel;
- clipModel = pusher->GetPhysics()->GetClipModel();
- totalMass = 0.0f;
- results.fraction = 1.0f;
- results.endpos = newOrigin;
- results.endAxis = clipModel->GetAxis();
- memset( &results.c, 0, sizeof( results.c ) );
- if ( translation == vec3_origin ) {
- return totalMass;
- }
- dir = translation;
- dir.Normalize();
- dir.z += 1.0f;
- dir *= 10.0f;
- // get bounds for the whole movement
- bounds = clipModel->GetBounds();
- if ( bounds[0].x >= bounds[1].x ) {
- return totalMass;
- }
- pushBounds.FromBoundsTranslation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), translation );
- wasEnabled = clipModel->IsEnabled();
- // make sure we don't get the pushing clip model in the list
- clipModel->Disable();
- listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES );
- // discard entities we cannot or should not push
- listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher );
- if ( flags & PUSHFL_CLIP ) {
- // can only clip movement of a trace model
- assert( clipModel->IsTraceModel() );
- // disable to be pushed entities for collision detection
- for ( i = 0; i < listedEntities; i++ ) {
- entityList[i]->GetPhysics()->DisableClip();
- }
- gameLocal.clip.Translation( results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL );
- // enable to be pushed entities for collision detection
- for ( i = 0; i < listedEntities; i++ ) {
- entityList[i]->GetPhysics()->EnableClip();
- }
- if ( results.fraction == 0.0f ) {
- if ( wasEnabled ) {
- clipModel->Enable();
- }
- return totalMass;
- }
- clipMove = results.endpos - clipModel->GetOrigin();
- clipOrigin = results.endpos;
- }
- else {
- clipMove = translation;
- clipOrigin = newOrigin;
- }
- // we have to enable the clip model because we use it during pushing
- clipModel->Enable();
- // save pusher old position
- oldOrigin = clipModel->GetOrigin();
- // try to push the entities
- for ( i = 0; i < listedEntities; i++ ) {
- check = entityList[ i ];
- idPhysics *physics = check->GetPhysics();
- // disable the entity for collision detection
- physics->DisableClip();
- res = TryTranslatePushEntity( pushResults, check, clipModel, flags, clipOrigin, clipMove );
- // enable the entity for collision detection
- physics->EnableClip();
- // if the entity is pushed
- if ( res == PUSH_OK ) {
- // set the pusher in the translated position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), newOrigin, clipModel->GetAxis() );
- // the entity might be pushed off the ground
- physics->EvaluateContacts();
- // put pusher back in old position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), oldOrigin, clipModel->GetAxis() );
- // wake up this object
- if ( flags & PUSHFL_APPLYIMPULSE ) {
- impulse = physics->GetMass() * dir;
- } else {
- impulse.Zero();
- }
- check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), impulse );
- // add mass of pushed entity
- totalMass += physics->GetMass();
- }
- // if the entity is not blocking
- if ( res != PUSH_BLOCKED ) {
- continue;
- }
- // if the blocking entity is a projectile
- if ( check->IsType( idProjectile::Type ) ) {
- check->ProcessEvent( &EV_Explode );
- continue;
- }
- // if blocking entities should be crushed
- if ( flags & PUSHFL_CRUSH ) {
- check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) );
- continue;
- }
- // if the entity is an active articulated figure and gibs
- if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) {
- if ( static_cast<idAFEntity_Base *>(check)->IsActiveAF() ) {
- check->ProcessEvent( &EV_Gib, "damage_Gib" );
- }
- }
- // if the entity is a moveable item and gibs
- if ( check->IsType( idMoveableItem::Type ) && check->spawnArgs.GetBool( "gib" ) ) {
- check->ProcessEvent( &EV_Gib, "damage_Gib" );
- }
- // blocked
- results = pushResults;
- results.fraction = 0.0f;
- results.endAxis = clipModel->GetAxis();
- results.endpos = clipModel->GetOrigin();
- results.c.entityNum = check->entityNumber;
- results.c.id = 0;
- if ( !wasEnabled ) {
- clipModel->Disable();
- }
- return totalMass;
- }
- if ( !wasEnabled ) {
- clipModel->Disable();
- }
- return totalMass;
- }
- /*
- ============
- idPush::ClipRotationalPush
- Try to push other entities by moving the given entity.
- ============
- */
- float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags,
- const idMat3 &newAxis, const idRotation &rotation ) {
- int i, listedEntities, res;
- idEntity *check, *entityList[ MAX_GENTITIES ];
- idBounds bounds, pushBounds;
- idRotation clipRotation;
- idMat3 clipAxis, oldAxis;
- trace_t pushResults;
- bool wasEnabled;
- float totalMass;
- idClipModel *clipModel;
- clipModel = pusher->GetPhysics()->GetClipModel();
- totalMass = 0.0f;
- results.fraction = 1.0f;
- results.endpos = clipModel->GetOrigin();
- results.endAxis = newAxis;
- memset( &results.c, 0, sizeof( results.c ) );
- if ( !rotation.GetAngle() ) {
- return totalMass;
- }
- // get bounds for the whole movement
- bounds = clipModel->GetBounds();
- if ( bounds[0].x >= bounds[1].x ) {
- return totalMass;
- }
- pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation );
- wasEnabled = clipModel->IsEnabled();
- // make sure we don't get the pushing clip model in the list
- clipModel->Disable();
- listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES );
- // discard entities we cannot or should not push
- listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher );
- if ( flags & PUSHFL_CLIP ) {
- // can only clip movement of a trace model
- assert( clipModel->IsTraceModel() );
- // disable to be pushed entities for collision detection
- for ( i = 0; i < listedEntities; i++ ) {
- entityList[i]->GetPhysics()->DisableClip();
- }
- gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL );
- // enable to be pushed entities for collision detection
- for ( i = 0; i < listedEntities; i++ ) {
- entityList[i]->GetPhysics()->EnableClip();
- }
- if ( results.fraction == 0.0f ) {
- if ( wasEnabled ) {
- clipModel->Enable();
- }
- return totalMass;
- }
- clipRotation = rotation * results.fraction;
- clipAxis = results.endAxis;
- }
- else {
- clipRotation = rotation;
- clipAxis = newAxis;
- }
- // we have to enable the clip model because we use it during pushing
- clipModel->Enable();
- // save pusher old position
- oldAxis = clipModel->GetAxis();
- // try to push all the entities
- for ( i = 0; i < listedEntities; i++ ) {
- check = entityList[ i ];
- idPhysics *physics = check->GetPhysics();
- // disable the entity for collision detection
- physics->DisableClip();
- res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation );
- // enable the entity for collision detection
- physics->EnableClip();
- // if the entity is pushed
- if ( res == PUSH_OK ) {
- // set the pusher in the rotated position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis );
- // the entity might be pushed off the ground
- physics->EvaluateContacts();
- // put pusher back in old position
- clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis );
- // wake up this object
- check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin );
- // add mass of pushed entity
- totalMass += physics->GetMass();
- }
- // if the entity is not blocking
- if ( res != PUSH_BLOCKED ) {
- continue;
- }
- // if the blocking entity is a projectile
- if ( check->IsType( idProjectile::Type ) ) {
- check->ProcessEvent( &EV_Explode );
- continue;
- }
- // if blocking entities should be crushed
- if ( flags & PUSHFL_CRUSH ) {
- check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) );
- continue;
- }
- // if the entity is an active articulated figure and gibs
- if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) {
- if ( static_cast<idAFEntity_Base *>(check)->IsActiveAF() ) {
- check->ProcessEvent( &EV_Gib, "damage_Gib" );
- }
- }
- // blocked
- results = pushResults;
- results.fraction = 0.0f;
- results.endAxis = clipModel->GetAxis();
- results.endpos = clipModel->GetOrigin();
- results.c.entityNum = check->entityNumber;
- results.c.id = 0;
- if ( !wasEnabled ) {
- clipModel->Disable();
- }
- return totalMass;
- }
- if ( !wasEnabled ) {
- clipModel->Disable();
- }
- return totalMass;
- }
- #endif /* !NEW_PUSH */
- /*
- ============
- idPush::ClipPush
- Try to push other entities by moving the given entity.
- ============
- */
- float idPush::ClipPush( trace_t &results, idEntity *pusher, const int flags,
- const idVec3 &oldOrigin, const idMat3 &oldAxis,
- idVec3 &newOrigin, idMat3 &newAxis ) {
- idVec3 translation;
- idRotation rotation;
- float mass;
- mass = 0.0f;
- results.fraction = 1.0f;
- results.endpos = newOrigin;
- results.endAxis = newAxis;
- memset( &results.c, 0, sizeof( results.c ) );
- // translational push
- translation = newOrigin - oldOrigin;
- // if the pusher translates
- if ( translation != vec3_origin ) {
- mass += ClipTranslationalPush( results, pusher, flags, newOrigin, translation );
- if ( results.fraction < 1.0f ) {
- newOrigin = oldOrigin;
- newAxis = oldAxis;
- return mass;
- }
- } else {
- newOrigin = oldOrigin;
- }
- // rotational push
- rotation = ( oldAxis.Transpose() * newAxis ).ToRotation();
- rotation.SetOrigin( newOrigin );
- rotation.Normalize180();
- rotation.ReCalculateMatrix(); // recalculate the rotation matrix to avoid accumulating rounding errors
- // if the pusher rotates
- if ( rotation.GetAngle() != 0.0f ) {
- // recalculate new axis to avoid floating point rounding problems
- newAxis = oldAxis * rotation.ToMat3();
- newAxis.OrthoNormalizeSelf();
- newAxis.FixDenormals();
- newAxis.FixDegeneracies();
- pusher->GetPhysics()->GetClipModel()->SetPosition( newOrigin, oldAxis );
- mass += ClipRotationalPush( results, pusher, flags, newAxis, rotation );
- if ( results.fraction < 1.0f ) {
- newOrigin = oldOrigin;
- newAxis = oldAxis;
- return mass;
- }
- } else {
- newAxis = oldAxis;
- }
- return mass;
- }
|