123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
- // Copyright (C) 2015 Faust Logic, Inc.
- //
- // afxCamera implements a modified camera for demonstrating a third person camera style
- // which is more common to RPG games than the standard FPS style camera. For the most part,
- // it is a hybrid of the standard TGE camera and the third person mode of the Advanced Camera
- // resource, authored by Thomas "Man of Ice" Lund. This camera implements the bare minimum
- // required for demonstrating an RPG style camera and leaves tons of room for improvement.
- // It should be replaced with a better camera if possible.
- //
- // Advanced Camera Resource by Thomas "Man of Ice" Lund:
- // http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5471
- //
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- #include "afx/arcaneFX.h"
- #include "math/mathUtils.h"
- #include "math/mathIO.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "T3D/camera.h"
- #include "T3D/player.h"
- #include "T3D/sfx/sfx3DWorld.h"
- #include "afx/afxCamera.h"
- #define MaxPitch 1.3962f
- #define CameraRadius 0.05f;
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // afxCameraData
- IMPLEMENT_CO_DATABLOCK_V1(afxCameraData);
- ConsoleDocClass( afxCameraData,
- "@brief A datablock that describes an afxCamera.\n\n"
- "@ingroup afxMisc\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- U32 afxCameraData::sCameraCollisionMask = TerrainObjectType | InteriorLikeObjectType | TerrainLikeObjectType;
- void afxCameraData::initPersistFields()
- {
- Con::addVariable("pref::afxCamera::collisionMask", TypeS32, &sCameraCollisionMask);
- Parent::initPersistFields();
- }
- void afxCameraData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- }
- void afxCameraData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // afxCamera
- IMPLEMENT_CO_NETOBJECT_V1(afxCamera);
- ConsoleDocClass( afxCamera,
- "@brief A 3rd person camera object.\n\n"
- "@ingroup afxMisc\n"
- "@ingroup AFX\n"
- );
- afxCamera::afxCamera()
- {
- mNetFlags.clear(Ghostable);
- mTypeMask |= CameraObjectType;
- mDelta.pos = Point3F(0,0,100);
- mDelta.rot = Point3F(0,0,0);
- mDelta.posVec = mDelta.rotVec = VectorF(0,0,0);
- mObjToWorld.setColumn(3, mDelta.pos);
- mRot = mDelta.rot;
-
- mMinOrbitDist = 0;
- mMaxOrbitDist = 0;
- mCurOrbitDist = 0;
- mOrbitObject = NULL;
- mPosition.set(0.f, 0.f, 0.f);
- mObservingClientObject = false;
- mMode = FlyMode;
-
- mCam_subject = NULL;
- mCoi_offset.set(0, 0, 2);
- mCam_offset.set(0, 0, 0);
- mCam_distance = 0.0f;
- mCam_angle = 0.0f;
- mCam_dirty = false;
-
- mFlymode_saved = false;
- mThird_person_snap_s = 1;
- mThird_person_snap_c = 1;
- mFlymode_saved_pos.zero();
- mDamageState = Disabled;
- }
- afxCamera::~afxCamera()
- {
- }
- //----------------------------------------------------------------------------
- void afxCamera::cam_update(F32 dt, bool on_server)
- {
- if (mMode == ThirdPersonMode && mCam_subject)
- cam_update_3pov(dt, on_server);
- }
- void afxCamera::set_cam_pos(const Point3F& pos,const Point3F& rot)
- {
- MatrixF xRot, zRot;
- xRot.set(EulerF(rot.x, 0, 0));
- zRot.set(EulerF(0, 0, rot.z));
- MatrixF temp;
- temp.mul(zRot, xRot);
- temp.setColumn(3, pos);
- Parent::setTransform(temp);
- mRot = rot;
- }
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- Point3F &afxCamera::getPosition()
- {
- static Point3F position;
- mObjToWorld.getColumn(3, &position);
- return position;
- }
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // NEW Observer Code
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- void afxCamera::setFlyMode()
- {
- mMode = FlyMode;
- if (mFlymode_saved)
- snapToPosition(mFlymode_saved_pos);
-
- if (bool(mOrbitObject))
- {
- clearProcessAfter();
- clearNotify(mOrbitObject);
- }
- mOrbitObject = NULL;
- }
- void afxCamera::setOrbitMode(GameBase *obj, Point3F &pos, AngAxisF &rot, F32 minDist, F32 maxDist, F32 curDist, bool ownClientObject)
- {
- mObservingClientObject = ownClientObject;
- if(bool(mOrbitObject)) {
- clearProcessAfter();
- clearNotify(mOrbitObject);
- }
- mOrbitObject = obj;
- if(bool(mOrbitObject))
- {
- processAfter(mOrbitObject);
- deleteNotify(mOrbitObject);
- mOrbitObject->getWorldBox().getCenter(&mPosition);
- mMode = OrbitObjectMode;
- }
- else
- {
- mMode = OrbitPointMode;
- mPosition = pos;
- }
- QuatF q(rot);
- MatrixF tempMat(true);
- q.setMatrix(&tempMat);
- Point3F dir;
- tempMat.getColumn(1, &dir);
- set_cam_pos(mPosition, dir);
- mMinOrbitDist = minDist;
- mMaxOrbitDist = maxDist;
- mCurOrbitDist = curDist;
- }
- void afxCamera::validateEyePoint(F32 pos, MatrixF *mat)
- {
- if (pos != 0) {
- // Use the eye transform to orient the camera
- Point3F dir;
- mat->getColumn(1, &dir);
- pos *= mMaxOrbitDist - mMinOrbitDist;
- // Use the camera node's pos.
- Point3F startPos;
- Point3F endPos;
- mObjToWorld.getColumn(3,&startPos);
- // Make sure we don't extend the camera into anything solid
- if(mOrbitObject)
- mOrbitObject->disableCollision();
- disableCollision();
- RayInfo collision;
- SceneContainer* pContainer = isServerObject() ? &gServerContainer : &gClientContainer;
- if (!pContainer->castRay(startPos, startPos - dir * 2.5 * pos, afxCameraData::sCameraCollisionMask, &collision))
- endPos = startPos - dir * pos;
- else
- {
- float dot = mDot(dir, collision.normal);
- if(dot > 0.01)
- {
- float colDist = mDot(startPos - collision.point, dir) - (1 / dot) * CameraRadius;
- if(colDist > pos)
- colDist = pos;
- if(colDist < 0)
- colDist = 0;
- endPos = startPos - dir * colDist;
- }
- else
- endPos = startPos - dir * pos;
- }
- mat->setColumn(3,endPos);
- enableCollision();
- if(mOrbitObject)
- mOrbitObject->enableCollision();
- }
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Sets the position and calculates rotation
- void afxCamera::snapToPosition(const Point3F& tPos)
- {
- MatrixF transMat;
- if (mCam_subject)
- {
- // get the subject's transform
- MatrixF objToWorld = mCam_subject->getRenderTransform();
- // transform the center-of-interest to world-space
- Point3F objPos;
- objToWorld.mulP(mCoi_offset, &objPos);
- // find normalized direction vector looking from camera to coi
- VectorF dirVec = objPos - tPos;
- dirVec.normalize();
- MathUtils::getAnglesFromVector(dirVec, mRot.z, mRot.x);
- mRot.x = 0 - mRot.x;
- transMat = MathUtils::createOrientFromDir(dirVec);
- }
- else
- {
- transMat.identity();
- }
- transMat.setColumn(3, tPos);
- Parent::setTransform(transMat);
- }
- void afxCamera::setCameraSubject(SceneObject* new_subject)
- {
- // cleanup any existing chase subject
- if (mCam_subject)
- {
- if (dynamic_cast<GameBase*>(mCam_subject))
- clearProcessAfter();
- clearNotify(mCam_subject);
- }
-
- mCam_subject = new_subject;
-
- // set associations with new chase subject
- if (mCam_subject)
- {
- if (dynamic_cast<GameBase*>(mCam_subject))
- processAfter((GameBase*)mCam_subject);
- deleteNotify(mCam_subject);
- }
- mMode = (mCam_subject) ? ThirdPersonMode : FlyMode;
- setMaskBits(SubjectMask);
- }
- void afxCamera::setThirdPersonOffset(const Point3F& offset)
- {
- // new method
- if (mCam_distance > 0.0f)
- {
- if (isClientObject())
- {
- GameConnection* conn = GameConnection::getConnectionToServer();
- if (conn)
- {
- // this auto switches to/from first person
- if (conn->isFirstPerson())
- {
- if (mCam_distance >= 1.0f)
- conn->setFirstPerson(false);
- }
- else
- {
- if (mCam_distance < 1.0f)
- conn->setFirstPerson(true);
- }
- }
- }
- mCam_offset = offset;
- mCam_dirty = true;
- return;
- }
- // old backwards-compatible method
- if (offset.y != mCam_offset.y && isClientObject())
- {
- GameConnection* conn = GameConnection::getConnectionToServer();
- if (conn)
- {
- // this auto switches to/from first person
- if (conn->isFirstPerson())
- {
- if (offset.y <= -1.0f)
- conn->setFirstPerson(false);
- }
- else
- {
- if (offset.y > -1.0f)
- conn->setFirstPerson(true);
- }
- }
- }
- mCam_offset = offset;
- mCam_dirty = true;
- }
- void afxCamera::setThirdPersonOffset(const Point3F& offset, const Point3F& coi_offset)
- {
- mCoi_offset = coi_offset;
- setThirdPersonOffset(offset);
- }
- void afxCamera::setThirdPersonDistance(F32 distance)
- {
- mCam_distance = distance;
- mCam_dirty = true;
- }
- F32 afxCamera::getThirdPersonDistance()
- {
- return mCam_distance;
- }
- void afxCamera::setThirdPersonAngle(F32 angle)
- {
- mCam_angle = angle;
- mCam_dirty = true;
- }
- F32 afxCamera::getThirdPersonAngle()
- {
- return mCam_angle;
- }
- void afxCamera::setThirdPersonMode()
- {
- mMode = ThirdPersonMode;
- mFlymode_saved_pos = getPosition();
- mFlymode_saved = true;
- mCam_dirty = true;
- mThird_person_snap_s++;
- }
- void afxCamera::setThirdPersonSnap()
- {
- if (mMode == ThirdPersonMode)
- mThird_person_snap_s += 2;
- }
- void afxCamera::setThirdPersonSnapClient()
- {
- if (mMode == ThirdPersonMode)
- mThird_person_snap_c++;
- }
- const char* afxCamera::getMode()
- {
- switch (mMode)
- {
- case ThirdPersonMode:
- return "ThirdPerson";
- case FlyMode:
- return "Fly";
- case OrbitObjectMode:
- return "Orbit";
- }
- return "Unknown";
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Console Methods
- DefineEngineStringlyVariadicMethod(afxCamera, setOrbitMode, void, 7, 8,
- "(GameBase orbitObject, TransformF mat, float minDistance, float maxDistance, float curDistance, bool ownClientObject)"
- "Set the camera to orbit around some given object.\n\n"
- "@param orbitObject Object we want to orbit.\n"
- "@param mat A set of fields: posX posY posZ aaX aaY aaZ aaTheta\n"
- "@param minDistance Minimum distance to keep from object.\n"
- "@param maxDistance Maximum distance to keep from object.\n"
- "@param curDistance Distance to set initially from object.\n"
- "@param ownClientObj Are we observing an object owned by us?")
- {
- Point3F pos;
- AngAxisF aa;
- F32 minDis, maxDis, curDis;
-
- GameBase *orbitObject = NULL;
- if(Sim::findObject(argv[2],orbitObject) == false)
- {
- Con::warnf("Cannot orbit non-existing object.");
- object->setFlyMode();
- return;
- }
-
- dSscanf(argv[3],"%f %f %f %f %f %f %f",
- &pos.x,&pos.y,&pos.z,&aa.axis.x,&aa.axis.y,&aa.axis.z,&aa.angle);
- minDis = dAtof(argv[4]);
- maxDis = dAtof(argv[5]);
- curDis = dAtof(argv[6]);
-
- object->setOrbitMode(orbitObject, pos, aa, minDis, maxDis, curDis, (argc == 8) ? dAtob(argv[7]) : false);
- }
- DefineEngineMethod(afxCamera, setFlyMode, void, (),,
- "@brief Set the camera to be able to fly freely.")
- {
- object->setFlyMode();
- }
- DefineEngineMethod(afxCamera, getPosition, Point3F, (),,
- "@brief Get the position of the camera.\n\n"
- "@returns The position of the camera.")
- {
- return object->getPosition();
- }
- DefineEngineMethod(afxCamera, setCameraSubject, bool, (SceneObject* subject),, "")
- {
- if (!subject)
- {
- Con::errorf("Camera subject not found.");
- return false;
- }
- object->setCameraSubject(subject);
- return true;
- }
- DefineEngineMethod(afxCamera, setThirdPersonDistance, bool, (F32 distance),, "")
- {
- object->setThirdPersonDistance(distance);
- return true;
- }
- DefineEngineMethod(afxCamera, getThirdPersonDistance, F32, (),, "")
- {
- return object->getThirdPersonDistance();
- }
- DefineEngineMethod(afxCamera, setThirdPersonAngle, bool, (F32 distance),, "")
- {
- object->setThirdPersonAngle(distance);
- return true;
- }
- DefineEngineMethod(afxCamera, getThirdPersonAngle, F32, (),, "")
- {
- return object->getThirdPersonAngle();
- }
- DefineEngineMethod(afxCamera, setThirdPersonOffset, void, (Point3F offset, Point3F coi_offset), (Point3F::Max), "")
- {
- if (coi_offset == Point3F::Max)
- {
- object->setThirdPersonOffset(offset);
- }
- else
- {
- object->setThirdPersonOffset(offset, coi_offset);
- }
- }
- DefineEngineMethod(afxCamera, getThirdPersonOffset, Point3F, (),, "")
- {
- return object->getThirdPersonOffset();
- }
- DefineEngineMethod(afxCamera, getThirdPersonCOIOffset, Point3F, (),, "")
- {
- return object->getThirdPersonCOIOffset();
- }
- DefineEngineMethod(afxCamera, setThirdPersonMode, void, (),, "")
- {
- object->setThirdPersonMode();
- }
- DefineEngineMethod(afxCamera, setThirdPersonSnap, void, (),, "")
- {
- object->setThirdPersonSnap();
- }
- DefineEngineMethod(afxCamera, getMode, const char*, (),, "")
- {
- return object->getMode();
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // 3POV SECTION
- void afxCamera::cam_update_3pov(F32 dt, bool on_server)
- {
- Point3F goal_pos;
- Point3F curr_pos = getRenderPosition();
- MatrixF xfm = mCam_subject->getRenderTransform();
- Point3F coi = mCam_subject->getRenderPosition() + mCoi_offset;
- // for player subjects, pitch is adjusted
- Player* player_subj = dynamic_cast<Player*>(mCam_subject);
- if (player_subj)
- {
- if (mCam_distance > 0.0f)
- {
- // rotate xfm by amount of cam_angle
- F32 look_yaw = player_subj->getHeadRotation().z + mDegToRad(-mCam_angle);
- MatrixF look_yaw_mtx(EulerF(0,0,look_yaw));
- xfm.mul(look_yaw_mtx);
- // rotate xfm by amount of head pitch in player
- F32 head_pitch = player_subj->getHeadRotation().x;
- MatrixF head_pitch_mtx(EulerF(head_pitch,0,0));
- xfm.mul(head_pitch_mtx);
- VectorF behind_vec(0, -mCam_distance, 0);
- xfm.mulP(behind_vec, &goal_pos);
- goal_pos += mCam_offset;
- }
- else // old backwards-compatible method
- {
- // rotate xfm by amount of head pitch in player
- F32 head_pitch = player_subj->getHeadRotation().x;
- MatrixF head_pitch_mtx(EulerF(head_pitch,0,0));
- xfm.mul(head_pitch_mtx);
- VectorF behind_vec(0, mCam_offset.y, 0);
- xfm.mulP(behind_vec, &goal_pos);
- goal_pos.z += mCam_offset.z;
- }
- }
- // for non-player subjects, camera will follow, but pitch won't adjust.
- else
- {
- xfm.mulP(mCam_offset, &goal_pos);
- }
- // avoid view occlusion
- if (avoid_blocked_view(coi, goal_pos, goal_pos) && !on_server)
- {
- // snap to final position if path to goal is blocked
- if (test_blocked_line(curr_pos, goal_pos))
- mThird_person_snap_c++;
- }
- // place camera into its final position
- // speed factor values
- // 15 -- tight
- // 10 -- normal
- // 5 -- loose
- // 1 -- very loose
- F32 speed_factor = 8.0f;
- F32 time_inc = 1.0f/speed_factor;
- // snap to final position
- if (on_server || (mThird_person_snap_c > 0 || dt > time_inc))
- {
- snapToPosition(goal_pos);
- if (!on_server && mThird_person_snap_c > 0)
- mThird_person_snap_c--;
- return;
- }
- // interpolate to final position
- else
- {
- // interpretation: always move a proportion of the distance
- // from current location to destination that would cover the
- // entire distance in time_inc duration at constant velocity.
- F32 t = (dt >= time_inc) ? 1.0f : dt*speed_factor;
- snapToPosition(goal_pos*t + curr_pos*(1.0-t));
- }
- }
- // See if the camera view is occluded by certain objects,
- // and move the camera closer to the subject in that case
- bool afxCamera::avoid_blocked_view(const Point3F& startpos, const Point3F& endpos, Point3F& newpos)
- {
- // cast ray to check for intersection with potential blocker objects
- RayInfo hit_info;
- if (!getContainer()->castRay(startpos, endpos, afxCameraData::sCameraCollisionMask, &hit_info))
- {
- // no hit: just return original endpos
- newpos = endpos;
- return false;
- }
- // did hit: return the hit location nudged forward slightly
- // to avoid seeing clipped portions of blocking object.
- Point3F sight_line = startpos - hit_info.point;
- sight_line.normalize();
- newpos = hit_info.point + sight_line*0.4f;
- return true;
- }
- bool afxCamera::test_blocked_line(const Point3F& startpos, const Point3F& endpos)
- {
- RayInfo hit_info;
- return getContainer()->castRay(startpos, endpos, afxCameraData::sCameraCollisionMask, &hit_info);
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // STD OVERRIDES SECTION
- bool afxCamera::onAdd()
- {
- if(!Parent::onAdd())
- return false;
- mObjBox.maxExtents = mObjScale;
- mObjBox.minExtents = mObjScale;
- mObjBox.minExtents.neg();
- resetWorldBox();
- addToScene();
- return true;
- }
- void afxCamera::onRemove()
- {
- removeFromScene();
- Parent::onRemove();
- }
- void afxCamera::onDeleteNotify(SimObject *obj)
- {
- Parent::onDeleteNotify(obj);
- if (obj == (SimObject*)mOrbitObject)
- {
- mOrbitObject = NULL;
- if (mMode == OrbitObjectMode)
- mMode = OrbitPointMode;
- }
- if (obj == mCam_subject)
- {
- mCam_subject = NULL;
- }
- }
- void afxCamera::advanceTime(F32 dt)
- {
- Parent::advanceTime(dt);
- if (gSFX3DWorld)
- {
- if (mMode == ThirdPersonMode && mCam_subject)
- {
- if (gSFX3DWorld->getListener() != mCam_subject)
- gSFX3DWorld->setListener(mCam_subject);
- }
- else if (mMode == FlyMode)
- {
- if (gSFX3DWorld->getListener() != this)
- gSFX3DWorld->setListener(this);
- }
- }
- cam_update(dt, false);
- }
- void afxCamera::processTick(const Move* move)
- {
- Parent::processTick(move);
- Point3F vec,pos;
- // move will be NULL unless camera becomes the control object as in FlyMode
- if (move)
- {
- // UPDATE ORIENTATION //
- mDelta.rotVec = mRot;
- mObjToWorld.getColumn(3, &mDelta.posVec);
- mRot.x = mClampF(mRot.x + move->pitch, -MaxPitch, MaxPitch);
- mRot.z += move->yaw;
- // ORBIT MODE //
- if (mMode == OrbitObjectMode || mMode == OrbitPointMode)
- {
- if(mMode == OrbitObjectMode && bool(mOrbitObject))
- {
- // If this is a shapebase, use its render eye transform
- // to avoid jittering.
- GameBase *castObj = mOrbitObject;
- ShapeBase* shape = dynamic_cast<ShapeBase*>(castObj);
- if( shape != NULL ) {
- MatrixF ret;
- shape->getRenderEyeTransform( &ret );
- mPosition = ret.getPosition();
- }
- else
- {
- // Hopefully this is a static object that doesn't move,
- // because the worldbox doesn't get updated between ticks.
- mOrbitObject->getWorldBox().getCenter(&mPosition);
- }
- }
- set_cam_pos(mPosition, mRot);
- validateEyePoint(1.0f, &mObjToWorld);
- pos = mPosition;
- }
- // NON-ORBIT MODE (FLY MODE) //
- else // if (mode == FlyMode)
- {
- // Update pos
- bool faster = move->trigger[0] || move->trigger[1];
- F32 scale = Camera::getMovementSpeed() * (faster + 1);
- mObjToWorld.getColumn(3,&pos);
- mObjToWorld.getColumn(0,&vec);
- pos += vec * move->x * TickSec * scale;
- mObjToWorld.getColumn(1,&vec);
- pos += vec * move->y * TickSec * scale;
- mObjToWorld.getColumn(2,&vec);
- pos += vec * move->z * TickSec * scale;
- set_cam_pos(pos,mRot);
- }
- // If on the client, calc delta for backstepping
- if (isClientObject())
- {
- mDelta.pos = pos;
- mDelta.rot = mRot;
- mDelta.posVec = mDelta.posVec - mDelta.pos;
- mDelta.rotVec = mDelta.rotVec - mDelta.rot;
- }
- else
- {
- setMaskBits(MoveMask);
- }
- }
- else // if (!move)
- {
- if (isServerObject())
- cam_update(1.0/32.0, true);
- }
- if (getControllingClient() && mContainer)
- updateContainer();
- }
- void afxCamera::interpolateTick(F32 dt)
- {
- Parent::interpolateTick(dt);
- if (mMode == ThirdPersonMode)
- return;
- Point3F rot = mDelta.rot + mDelta.rotVec * dt;
- if(mMode == OrbitObjectMode || mMode == OrbitPointMode)
- {
- if(mMode == OrbitObjectMode && bool(mOrbitObject))
- {
- // If this is a shapebase, use its render eye transform
- // to avoid jittering.
- GameBase *castObj = mOrbitObject;
- ShapeBase* shape = dynamic_cast<ShapeBase*>(castObj);
- if( shape != NULL )
- {
- MatrixF ret;
- shape->getRenderEyeTransform( &ret );
- mPosition = ret.getPosition();
- }
- else
- {
- // Hopefully this is a static object that doesn't move,
- // because the worldbox doesn't get updated between ticks.
- mOrbitObject->getWorldBox().getCenter(&mPosition);
- }
- }
- set_cam_pos(mPosition, rot);
- validateEyePoint(1.0f, &mObjToWorld);
- }
- else
- {
- // NOTE - posVec is 0,0,0 unless cam is control-object and process tick is
- // updating the delta
- Point3F pos = mDelta.pos + mDelta.posVec * dt;
- set_cam_pos(pos,rot);
- }
- }
- void afxCamera::writePacketData(GameConnection *connection, BitStream *bstream)
- {
- // Update client regardless of status flags.
- Parent::writePacketData(connection, bstream);
- Point3F pos; mObjToWorld.getColumn(3, &pos);
- bstream->setCompressionPoint(pos); // SET COMPRESSION POINT
- mathWrite(*bstream, pos); // SND POS
- bstream->write(mRot.x); // SND X ROT
- bstream->write(mRot.z); // SND Z ROT
- if (bstream->writeFlag(mCam_dirty))
- {
- mathWrite(*bstream, mCam_offset); // SND CAM_OFFSET
- mathWrite(*bstream, mCoi_offset); // SND COI_OFFSET
- bstream->write(mCam_distance);
- bstream->write(mCam_angle);
- mCam_dirty = false;
- }
- U32 writeMode = mMode;
- Point3F writePos = mPosition;
- S32 gIndex = -1;
- if (mMode == OrbitObjectMode)
- {
- gIndex = bool(mOrbitObject) ? connection->getGhostIndex(mOrbitObject): -1;
- if(gIndex == -1)
- {
- writeMode = OrbitPointMode;
- mOrbitObject->getWorldBox().getCenter(&writePos);
- }
- }
- bstream->writeRangedU32(writeMode, CameraFirstMode, CameraLastMode); // SND MODE
- if (writeMode == ThirdPersonMode)
- {
- bstream->write(mThird_person_snap_s > 0); // SND SNAP
- if (mThird_person_snap_s > 0)
- mThird_person_snap_s--;
- }
- if (writeMode == OrbitObjectMode || writeMode == OrbitPointMode)
- {
- bstream->write(mMinOrbitDist); // SND ORBIT MIN DIST
- bstream->write(mMaxOrbitDist); // SND ORBIT MAX DIST
- bstream->write(mCurOrbitDist); // SND ORBIT CURR DIST
- if(writeMode == OrbitObjectMode)
- {
- bstream->writeFlag(mObservingClientObject); // SND OBSERVING CLIENT OBJ
- bstream->writeInt(gIndex, NetConnection::GhostIdBitSize); // SND ORBIT OBJ
- }
- if (writeMode == OrbitPointMode)
- bstream->writeCompressedPoint(writePos); // WRITE COMPRESSION POINT
- }
- }
- void afxCamera::readPacketData(GameConnection *connection, BitStream *bstream)
- {
- Parent::readPacketData(connection, bstream);
- Point3F pos,rot;
- mathRead(*bstream, &pos); // RCV POS
- bstream->setCompressionPoint(pos);
- bstream->read(&rot.x); // RCV X ROT
- bstream->read(&rot.z); // RCV Z ROT
- if (bstream->readFlag())
- {
- Point3F new_cam_offset, new_coi_offset;
- mathRead(*bstream, &new_cam_offset); // RCV CAM_OFFSET
- mathRead(*bstream, &new_coi_offset); // RCV COI_OFFSET
- bstream->read(&mCam_distance);
- bstream->read(&mCam_angle);
- setThirdPersonOffset(new_cam_offset, new_coi_offset);
- }
- GameBase* obj = 0;
- mMode = bstream->readRangedU32(CameraFirstMode, // RCV MODE
- CameraLastMode);
- if (mMode == ThirdPersonMode)
- {
- bool snap; bstream->read(&snap);
- if (snap)
- mThird_person_snap_c++;
- }
- mObservingClientObject = false;
- if (mMode == OrbitObjectMode || mMode == OrbitPointMode) {
- bstream->read(&mMinOrbitDist);
- bstream->read(&mMaxOrbitDist);
- bstream->read(&mCurOrbitDist);
- if(mMode == OrbitObjectMode)
- {
- mObservingClientObject = bstream->readFlag();
- S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
- obj = static_cast<GameBase*>(connection->resolveGhost(gIndex));
- }
- if (mMode == OrbitPointMode)
- bstream->readCompressedPoint(&mPosition);
- }
- if (obj != (GameBase*)mOrbitObject) {
- if (mOrbitObject) {
- clearProcessAfter();
- clearNotify(mOrbitObject);
- }
- mOrbitObject = obj;
- if (mOrbitObject) {
- processAfter(mOrbitObject);
- deleteNotify(mOrbitObject);
- }
- }
- if (mMode == ThirdPersonMode)
- return;
- set_cam_pos(pos,rot);
- mDelta.pos = pos;
- mDelta.rot = rot;
- mDelta.rotVec.set(0,0,0);
- mDelta.posVec.set(0,0,0);
- }
- U32 afxCamera::packUpdate(NetConnection* conn, U32 mask, BitStream *bstream)
- {
- U32 retMask = Parent::packUpdate(conn,mask,bstream);
- // The rest of the data is part of the control object packet update.
- // If we're controlled by this client, we don't need to send it.
- //if(bstream->writeFlag(getControllingClient() == conn && !(mask & InitialUpdateMask)))
- // return 0;
- if (bstream->writeFlag(mask & MoveMask)) {
- Point3F pos;
- mObjToWorld.getColumn(3,&pos);
- bstream->write(pos.x);
- bstream->write(pos.y);
- bstream->write(pos.z);
- bstream->write(mRot.x);
- bstream->write(mRot.z);
- }
- if (bstream->writeFlag(mask & SubjectMask))
- {
- S32 ghost_id = (mCam_subject) ? conn->getGhostIndex(mCam_subject) : -1;
- if (bstream->writeFlag(ghost_id != -1))
- bstream->writeRangedU32(U32(ghost_id), 0, NetConnection::MaxGhostCount);
- else if (mCam_subject)
- retMask |= SubjectMask;
- }
- return retMask;
- }
- void afxCamera::unpackUpdate(NetConnection *conn, BitStream *bstream)
- {
- Parent::unpackUpdate(conn,bstream);
- // controlled by the client?
- //if(bstream->readFlag())
- // return;
- if (bstream->readFlag()) {
- Point3F pos,rot;
- bstream->read(&pos.x);
- bstream->read(&pos.y);
- bstream->read(&pos.z);
- bstream->read(&rot.x);
- bstream->read(&rot.z);
- set_cam_pos(pos,rot);
- // New delta for client side interpolation
- mDelta.pos = pos;
- mDelta.rot = rot;
- mDelta.posVec = mDelta.rotVec = VectorF(0,0,0);
- }
- if (bstream->readFlag())
- {
- if (bstream->readFlag())
- {
- S32 ghost_id = bstream->readRangedU32(0, NetConnection::MaxGhostCount);
- mCam_subject = dynamic_cast<GameBase*>(conn->resolveGhost(ghost_id));
- }
- else
- mCam_subject = NULL;
- }
- }
- // Override to ensure both are kept in scope
- void afxCamera::onCameraScopeQuery(NetConnection* conn, CameraScopeQuery* query)
- {
- if (mCam_subject)
- conn->objectInScope(mCam_subject);
- Parent::onCameraScopeQuery(conn, query);
- }
- //----------------------------------------------------------------------------
- // check if the object needs to be observed through its own camera...
- void afxCamera::getCameraTransform(F32* pos, MatrixF* mat)
- {
- // The camera doesn't support a third person mode,
- // so we want to override the default ShapeBase behavior.
- ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
- if (obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
- obj->getCameraTransform(pos, mat);
- else
- getEyeTransform(mat);
- }
- void afxCamera::setTransform(const MatrixF& mat)
- {
- // This method should never be called on the client.
- // This currently converts all rotation in the mat into
- // rotations around the z and x axis.
- Point3F pos,vec;
- mat.getColumn(1,&vec);
- mat.getColumn(3,&pos);
- Point3F rot(-mAtan2(vec.z, mSqrt(vec.x*vec.x + vec.y*vec.y)),0,-mAtan2(-vec.x,vec.y));
- set_cam_pos(pos,rot);
- }
- void afxCamera::onEditorEnable()
- {
- mNetFlags.set(Ghostable);
- }
- void afxCamera::onEditorDisable()
- {
- mNetFlags.clear(Ghostable);
- }
- F32 afxCamera::getCameraFov()
- {
- ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
- if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
- return(obj->getCameraFov());
- else
- return(Parent::getCameraFov());
- }
- F32 afxCamera::getDefaultCameraFov()
- {
- ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
- if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
- return(obj->getDefaultCameraFov());
- else
- return(Parent::getDefaultCameraFov());
- }
- bool afxCamera::isValidCameraFov(F32 fov)
- {
- ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
- if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
- return(obj->isValidCameraFov(fov));
- else
- return(Parent::isValidCameraFov(fov));
- }
- void afxCamera::setCameraFov(F32 fov)
- {
- ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
- if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
- obj->setCameraFov(fov);
- else
- Parent::setCameraFov(fov);
- }
- F32 afxCamera::getDamageFlash() const
- {
- if (mMode == OrbitObjectMode && isServerObject() && bool(mOrbitObject))
- {
- const GameBase *castObj = mOrbitObject;
- const ShapeBase* psb = dynamic_cast<const ShapeBase*>(castObj);
- if (psb)
- return psb->getDamageFlash();
- }
- return mDamageFlash;
- }
- F32 afxCamera::getWhiteOut() const
- {
- if (mMode == OrbitObjectMode && isServerObject() && bool(mOrbitObject))
- {
- const GameBase *castObj = mOrbitObject;
- const ShapeBase* psb = dynamic_cast<const ShapeBase*>(castObj);
- if (psb)
- return psb->getWhiteOut();
- }
- return mWhiteOut;
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- void afxCamera::setControllingClient( GameConnection* client )
- {
- GameBase::setControllingClient( client );
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|