1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174 |
- //-----------------------------------------------------------------------------
- // 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()
- {
- docsURL;
- 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 );
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|