afxCamera.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //
  26. // afxCamera implements a modified camera for demonstrating a third person camera style
  27. // which is more common to RPG games than the standard FPS style camera. For the most part,
  28. // it is a hybrid of the standard TGE camera and the third person mode of the Advanced Camera
  29. // resource, authored by Thomas "Man of Ice" Lund. This camera implements the bare minimum
  30. // required for demonstrating an RPG style camera and leaves tons of room for improvement.
  31. // It should be replaced with a better camera if possible.
  32. //
  33. // Advanced Camera Resource by Thomas "Man of Ice" Lund:
  34. // http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=5471
  35. //
  36. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  37. #include "afx/arcaneFX.h"
  38. #include "math/mathUtils.h"
  39. #include "math/mathIO.h"
  40. #include "T3D/gameBase/gameConnection.h"
  41. #include "T3D/camera.h"
  42. #include "T3D/player.h"
  43. #include "T3D/sfx/sfx3DWorld.h"
  44. #include "afx/afxCamera.h"
  45. #define MaxPitch 1.3962f
  46. #define CameraRadius 0.05f;
  47. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  48. // afxCameraData
  49. IMPLEMENT_CO_DATABLOCK_V1(afxCameraData);
  50. ConsoleDocClass( afxCameraData,
  51. "@brief A datablock that describes an afxCamera.\n\n"
  52. "@ingroup afxMisc\n"
  53. "@ingroup AFX\n"
  54. "@ingroup Datablocks\n"
  55. );
  56. U32 afxCameraData::sCameraCollisionMask = TerrainObjectType | InteriorLikeObjectType | TerrainLikeObjectType;
  57. void afxCameraData::initPersistFields()
  58. {
  59. docsURL;
  60. Con::addVariable("pref::afxCamera::collisionMask", TypeS32, &sCameraCollisionMask);
  61. Parent::initPersistFields();
  62. }
  63. void afxCameraData::packData(BitStream* stream)
  64. {
  65. Parent::packData(stream);
  66. }
  67. void afxCameraData::unpackData(BitStream* stream)
  68. {
  69. Parent::unpackData(stream);
  70. }
  71. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  72. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  73. // afxCamera
  74. IMPLEMENT_CO_NETOBJECT_V1(afxCamera);
  75. ConsoleDocClass( afxCamera,
  76. "@brief A 3rd person camera object.\n\n"
  77. "@ingroup afxMisc\n"
  78. "@ingroup AFX\n"
  79. );
  80. afxCamera::afxCamera()
  81. {
  82. mNetFlags.clear(Ghostable);
  83. mTypeMask |= CameraObjectType;
  84. mDelta.pos = Point3F(0,0,100);
  85. mDelta.rot = Point3F(0,0,0);
  86. mDelta.posVec = mDelta.rotVec = VectorF(0,0,0);
  87. mObjToWorld.setColumn(3, mDelta.pos);
  88. mRot = mDelta.rot;
  89. mMinOrbitDist = 0;
  90. mMaxOrbitDist = 0;
  91. mCurOrbitDist = 0;
  92. mOrbitObject = NULL;
  93. mPosition.set(0.f, 0.f, 0.f);
  94. mObservingClientObject = false;
  95. mMode = FlyMode;
  96. mCam_subject = NULL;
  97. mCoi_offset.set(0, 0, 2);
  98. mCam_offset.set(0, 0, 0);
  99. mCam_distance = 0.0f;
  100. mCam_angle = 0.0f;
  101. mCam_dirty = false;
  102. mFlymode_saved = false;
  103. mThird_person_snap_s = 1;
  104. mThird_person_snap_c = 1;
  105. mFlymode_saved_pos.zero();
  106. mDamageState = Disabled;
  107. }
  108. afxCamera::~afxCamera()
  109. {
  110. }
  111. //----------------------------------------------------------------------------
  112. void afxCamera::cam_update(F32 dt, bool on_server)
  113. {
  114. if (mMode == ThirdPersonMode && mCam_subject)
  115. cam_update_3pov(dt, on_server);
  116. }
  117. void afxCamera::set_cam_pos(const Point3F& pos,const Point3F& rot)
  118. {
  119. MatrixF xRot, zRot;
  120. xRot.set(EulerF(rot.x, 0, 0));
  121. zRot.set(EulerF(0, 0, rot.z));
  122. MatrixF temp;
  123. temp.mul(zRot, xRot);
  124. temp.setColumn(3, pos);
  125. Parent::setTransform(temp);
  126. mRot = rot;
  127. }
  128. //----------------------------------------------------------------------------
  129. //----------------------------------------------------------------------------
  130. Point3F &afxCamera::getPosition()
  131. {
  132. static Point3F position;
  133. mObjToWorld.getColumn(3, &position);
  134. return position;
  135. }
  136. //----------------------------------------------------------------------------
  137. //----------------------------------------------------------------------------
  138. //----------------------------------------------------------------------------
  139. // NEW Observer Code
  140. //----------------------------------------------------------------------------
  141. //----------------------------------------------------------------------------
  142. void afxCamera::setFlyMode()
  143. {
  144. mMode = FlyMode;
  145. if (mFlymode_saved)
  146. snapToPosition(mFlymode_saved_pos);
  147. if (bool(mOrbitObject))
  148. {
  149. clearProcessAfter();
  150. clearNotify(mOrbitObject);
  151. }
  152. mOrbitObject = NULL;
  153. }
  154. void afxCamera::setOrbitMode(GameBase *obj, Point3F &pos, AngAxisF &rot, F32 minDist, F32 maxDist, F32 curDist, bool ownClientObject)
  155. {
  156. mObservingClientObject = ownClientObject;
  157. if(bool(mOrbitObject)) {
  158. clearProcessAfter();
  159. clearNotify(mOrbitObject);
  160. }
  161. mOrbitObject = obj;
  162. if(bool(mOrbitObject))
  163. {
  164. processAfter(mOrbitObject);
  165. deleteNotify(mOrbitObject);
  166. mOrbitObject->getWorldBox().getCenter(&mPosition);
  167. mMode = OrbitObjectMode;
  168. }
  169. else
  170. {
  171. mMode = OrbitPointMode;
  172. mPosition = pos;
  173. }
  174. QuatF q(rot);
  175. MatrixF tempMat(true);
  176. q.setMatrix(&tempMat);
  177. Point3F dir;
  178. tempMat.getColumn(1, &dir);
  179. set_cam_pos(mPosition, dir);
  180. mMinOrbitDist = minDist;
  181. mMaxOrbitDist = maxDist;
  182. mCurOrbitDist = curDist;
  183. }
  184. void afxCamera::validateEyePoint(F32 pos, MatrixF *mat)
  185. {
  186. if (pos != 0) {
  187. // Use the eye transform to orient the camera
  188. Point3F dir;
  189. mat->getColumn(1, &dir);
  190. pos *= mMaxOrbitDist - mMinOrbitDist;
  191. // Use the camera node's pos.
  192. Point3F startPos;
  193. Point3F endPos;
  194. mObjToWorld.getColumn(3,&startPos);
  195. // Make sure we don't extend the camera into anything solid
  196. if(mOrbitObject)
  197. mOrbitObject->disableCollision();
  198. disableCollision();
  199. RayInfo collision;
  200. SceneContainer* pContainer = isServerObject() ? &gServerContainer : &gClientContainer;
  201. if (!pContainer->castRay(startPos, startPos - dir * 2.5 * pos, afxCameraData::sCameraCollisionMask, &collision))
  202. endPos = startPos - dir * pos;
  203. else
  204. {
  205. float dot = mDot(dir, collision.normal);
  206. if(dot > 0.01)
  207. {
  208. float colDist = mDot(startPos - collision.point, dir) - (1 / dot) * CameraRadius;
  209. if(colDist > pos)
  210. colDist = pos;
  211. if(colDist < 0)
  212. colDist = 0;
  213. endPos = startPos - dir * colDist;
  214. }
  215. else
  216. endPos = startPos - dir * pos;
  217. }
  218. mat->setColumn(3,endPos);
  219. enableCollision();
  220. if(mOrbitObject)
  221. mOrbitObject->enableCollision();
  222. }
  223. }
  224. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  225. // Sets the position and calculates rotation
  226. void afxCamera::snapToPosition(const Point3F& tPos)
  227. {
  228. MatrixF transMat;
  229. if (mCam_subject)
  230. {
  231. // get the subject's transform
  232. MatrixF objToWorld = mCam_subject->getRenderTransform();
  233. // transform the center-of-interest to world-space
  234. Point3F objPos;
  235. objToWorld.mulP(mCoi_offset, &objPos);
  236. // find normalized direction vector looking from camera to coi
  237. VectorF dirVec = objPos - tPos;
  238. dirVec.normalize();
  239. MathUtils::getAnglesFromVector(dirVec, mRot.z, mRot.x);
  240. mRot.x = 0 - mRot.x;
  241. transMat = MathUtils::createOrientFromDir(dirVec);
  242. }
  243. else
  244. {
  245. transMat.identity();
  246. }
  247. transMat.setColumn(3, tPos);
  248. Parent::setTransform(transMat);
  249. }
  250. void afxCamera::setCameraSubject(SceneObject* new_subject)
  251. {
  252. // cleanup any existing chase subject
  253. if (mCam_subject)
  254. {
  255. if (dynamic_cast<GameBase*>(mCam_subject))
  256. clearProcessAfter();
  257. clearNotify(mCam_subject);
  258. }
  259. mCam_subject = new_subject;
  260. // set associations with new chase subject
  261. if (mCam_subject)
  262. {
  263. if (dynamic_cast<GameBase*>(mCam_subject))
  264. processAfter((GameBase*)mCam_subject);
  265. deleteNotify(mCam_subject);
  266. }
  267. mMode = (mCam_subject) ? ThirdPersonMode : FlyMode;
  268. setMaskBits(SubjectMask);
  269. }
  270. void afxCamera::setThirdPersonOffset(const Point3F& offset)
  271. {
  272. // new method
  273. if (mCam_distance > 0.0f)
  274. {
  275. if (isClientObject())
  276. {
  277. GameConnection* conn = GameConnection::getConnectionToServer();
  278. if (conn)
  279. {
  280. // this auto switches to/from first person
  281. if (conn->isFirstPerson())
  282. {
  283. if (mCam_distance >= 1.0f)
  284. conn->setFirstPerson(false);
  285. }
  286. else
  287. {
  288. if (mCam_distance < 1.0f)
  289. conn->setFirstPerson(true);
  290. }
  291. }
  292. }
  293. mCam_offset = offset;
  294. mCam_dirty = true;
  295. return;
  296. }
  297. // old backwards-compatible method
  298. if (offset.y != mCam_offset.y && isClientObject())
  299. {
  300. GameConnection* conn = GameConnection::getConnectionToServer();
  301. if (conn)
  302. {
  303. // this auto switches to/from first person
  304. if (conn->isFirstPerson())
  305. {
  306. if (offset.y <= -1.0f)
  307. conn->setFirstPerson(false);
  308. }
  309. else
  310. {
  311. if (offset.y > -1.0f)
  312. conn->setFirstPerson(true);
  313. }
  314. }
  315. }
  316. mCam_offset = offset;
  317. mCam_dirty = true;
  318. }
  319. void afxCamera::setThirdPersonOffset(const Point3F& offset, const Point3F& coi_offset)
  320. {
  321. mCoi_offset = coi_offset;
  322. setThirdPersonOffset(offset);
  323. }
  324. void afxCamera::setThirdPersonDistance(F32 distance)
  325. {
  326. mCam_distance = distance;
  327. mCam_dirty = true;
  328. }
  329. F32 afxCamera::getThirdPersonDistance()
  330. {
  331. return mCam_distance;
  332. }
  333. void afxCamera::setThirdPersonAngle(F32 angle)
  334. {
  335. mCam_angle = angle;
  336. mCam_dirty = true;
  337. }
  338. F32 afxCamera::getThirdPersonAngle()
  339. {
  340. return mCam_angle;
  341. }
  342. void afxCamera::setThirdPersonMode()
  343. {
  344. mMode = ThirdPersonMode;
  345. mFlymode_saved_pos = getPosition();
  346. mFlymode_saved = true;
  347. mCam_dirty = true;
  348. mThird_person_snap_s++;
  349. }
  350. void afxCamera::setThirdPersonSnap()
  351. {
  352. if (mMode == ThirdPersonMode)
  353. mThird_person_snap_s += 2;
  354. }
  355. void afxCamera::setThirdPersonSnapClient()
  356. {
  357. if (mMode == ThirdPersonMode)
  358. mThird_person_snap_c++;
  359. }
  360. const char* afxCamera::getMode()
  361. {
  362. switch (mMode)
  363. {
  364. case ThirdPersonMode:
  365. return "ThirdPerson";
  366. case FlyMode:
  367. return "Fly";
  368. case OrbitObjectMode:
  369. return "Orbit";
  370. }
  371. return "Unknown";
  372. }
  373. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  374. // Console Methods
  375. DefineEngineStringlyVariadicMethod(afxCamera, setOrbitMode, void, 7, 8,
  376. "(GameBase orbitObject, TransformF mat, float minDistance, float maxDistance, float curDistance, bool ownClientObject)"
  377. "Set the camera to orbit around some given object.\n\n"
  378. "@param orbitObject Object we want to orbit.\n"
  379. "@param mat A set of fields: posX posY posZ aaX aaY aaZ aaTheta\n"
  380. "@param minDistance Minimum distance to keep from object.\n"
  381. "@param maxDistance Maximum distance to keep from object.\n"
  382. "@param curDistance Distance to set initially from object.\n"
  383. "@param ownClientObj Are we observing an object owned by us?")
  384. {
  385. Point3F pos;
  386. AngAxisF aa;
  387. F32 minDis, maxDis, curDis;
  388. GameBase *orbitObject = NULL;
  389. if(Sim::findObject(argv[2],orbitObject) == false)
  390. {
  391. Con::warnf("Cannot orbit non-existing object.");
  392. object->setFlyMode();
  393. return;
  394. }
  395. dSscanf(argv[3],"%f %f %f %f %f %f %f",
  396. &pos.x,&pos.y,&pos.z,&aa.axis.x,&aa.axis.y,&aa.axis.z,&aa.angle);
  397. minDis = dAtof(argv[4]);
  398. maxDis = dAtof(argv[5]);
  399. curDis = dAtof(argv[6]);
  400. object->setOrbitMode(orbitObject, pos, aa, minDis, maxDis, curDis, (argc == 8) ? dAtob(argv[7]) : false);
  401. }
  402. DefineEngineMethod(afxCamera, setFlyMode, void, (),,
  403. "@brief Set the camera to be able to fly freely.")
  404. {
  405. object->setFlyMode();
  406. }
  407. DefineEngineMethod(afxCamera, getPosition, Point3F, (),,
  408. "@brief Get the position of the camera.\n\n"
  409. "@returns The position of the camera.")
  410. {
  411. return object->getPosition();
  412. }
  413. DefineEngineMethod(afxCamera, setCameraSubject, bool, (SceneObject* subject),, "")
  414. {
  415. if (!subject)
  416. {
  417. Con::errorf("Camera subject not found.");
  418. return false;
  419. }
  420. object->setCameraSubject(subject);
  421. return true;
  422. }
  423. DefineEngineMethod(afxCamera, setThirdPersonDistance, bool, (F32 distance),, "")
  424. {
  425. object->setThirdPersonDistance(distance);
  426. return true;
  427. }
  428. DefineEngineMethod(afxCamera, getThirdPersonDistance, F32, (),, "")
  429. {
  430. return object->getThirdPersonDistance();
  431. }
  432. DefineEngineMethod(afxCamera, setThirdPersonAngle, bool, (F32 distance),, "")
  433. {
  434. object->setThirdPersonAngle(distance);
  435. return true;
  436. }
  437. DefineEngineMethod(afxCamera, getThirdPersonAngle, F32, (),, "")
  438. {
  439. return object->getThirdPersonAngle();
  440. }
  441. DefineEngineMethod(afxCamera, setThirdPersonOffset, void, (Point3F offset, Point3F coi_offset), (Point3F::Max), "")
  442. {
  443. if (coi_offset == Point3F::Max)
  444. {
  445. object->setThirdPersonOffset(offset);
  446. }
  447. else
  448. {
  449. object->setThirdPersonOffset(offset, coi_offset);
  450. }
  451. }
  452. DefineEngineMethod(afxCamera, getThirdPersonOffset, Point3F, (),, "")
  453. {
  454. return object->getThirdPersonOffset();
  455. }
  456. DefineEngineMethod(afxCamera, getThirdPersonCOIOffset, Point3F, (),, "")
  457. {
  458. return object->getThirdPersonCOIOffset();
  459. }
  460. DefineEngineMethod(afxCamera, setThirdPersonMode, void, (),, "")
  461. {
  462. object->setThirdPersonMode();
  463. }
  464. DefineEngineMethod(afxCamera, setThirdPersonSnap, void, (),, "")
  465. {
  466. object->setThirdPersonSnap();
  467. }
  468. DefineEngineMethod(afxCamera, getMode, const char*, (),, "")
  469. {
  470. return object->getMode();
  471. }
  472. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  473. // 3POV SECTION
  474. void afxCamera::cam_update_3pov(F32 dt, bool on_server)
  475. {
  476. Point3F goal_pos;
  477. Point3F curr_pos = getRenderPosition();
  478. MatrixF xfm = mCam_subject->getRenderTransform();
  479. Point3F coi = mCam_subject->getRenderPosition() + mCoi_offset;
  480. // for player subjects, pitch is adjusted
  481. Player* player_subj = dynamic_cast<Player*>(mCam_subject);
  482. if (player_subj)
  483. {
  484. if (mCam_distance > 0.0f)
  485. {
  486. // rotate xfm by amount of cam_angle
  487. F32 look_yaw = player_subj->getHeadRotation().z + mDegToRad(-mCam_angle);
  488. MatrixF look_yaw_mtx(EulerF(0,0,look_yaw));
  489. xfm.mul(look_yaw_mtx);
  490. // rotate xfm by amount of head pitch in player
  491. F32 head_pitch = player_subj->getHeadRotation().x;
  492. MatrixF head_pitch_mtx(EulerF(head_pitch,0,0));
  493. xfm.mul(head_pitch_mtx);
  494. VectorF behind_vec(0, -mCam_distance, 0);
  495. xfm.mulP(behind_vec, &goal_pos);
  496. goal_pos += mCam_offset;
  497. }
  498. else // old backwards-compatible method
  499. {
  500. // rotate xfm by amount of head pitch in player
  501. F32 head_pitch = player_subj->getHeadRotation().x;
  502. MatrixF head_pitch_mtx(EulerF(head_pitch,0,0));
  503. xfm.mul(head_pitch_mtx);
  504. VectorF behind_vec(0, mCam_offset.y, 0);
  505. xfm.mulP(behind_vec, &goal_pos);
  506. goal_pos.z += mCam_offset.z;
  507. }
  508. }
  509. // for non-player subjects, camera will follow, but pitch won't adjust.
  510. else
  511. {
  512. xfm.mulP(mCam_offset, &goal_pos);
  513. }
  514. // avoid view occlusion
  515. if (avoid_blocked_view(coi, goal_pos, goal_pos) && !on_server)
  516. {
  517. // snap to final position if path to goal is blocked
  518. if (test_blocked_line(curr_pos, goal_pos))
  519. mThird_person_snap_c++;
  520. }
  521. // place camera into its final position
  522. // speed factor values
  523. // 15 -- tight
  524. // 10 -- normal
  525. // 5 -- loose
  526. // 1 -- very loose
  527. F32 speed_factor = 8.0f;
  528. F32 time_inc = 1.0f/speed_factor;
  529. // snap to final position
  530. if (on_server || (mThird_person_snap_c > 0 || dt > time_inc))
  531. {
  532. snapToPosition(goal_pos);
  533. if (!on_server && mThird_person_snap_c > 0)
  534. mThird_person_snap_c--;
  535. return;
  536. }
  537. // interpolate to final position
  538. else
  539. {
  540. // interpretation: always move a proportion of the distance
  541. // from current location to destination that would cover the
  542. // entire distance in time_inc duration at constant velocity.
  543. F32 t = (dt >= time_inc) ? 1.0f : dt*speed_factor;
  544. snapToPosition(goal_pos*t + curr_pos*(1.0-t));
  545. }
  546. }
  547. // See if the camera view is occluded by certain objects,
  548. // and move the camera closer to the subject in that case
  549. bool afxCamera::avoid_blocked_view(const Point3F& startpos, const Point3F& endpos, Point3F& newpos)
  550. {
  551. // cast ray to check for intersection with potential blocker objects
  552. RayInfo hit_info;
  553. if (!getContainer()->castRay(startpos, endpos, afxCameraData::sCameraCollisionMask, &hit_info))
  554. {
  555. // no hit: just return original endpos
  556. newpos = endpos;
  557. return false;
  558. }
  559. // did hit: return the hit location nudged forward slightly
  560. // to avoid seeing clipped portions of blocking object.
  561. Point3F sight_line = startpos - hit_info.point;
  562. sight_line.normalize();
  563. newpos = hit_info.point + sight_line*0.4f;
  564. return true;
  565. }
  566. bool afxCamera::test_blocked_line(const Point3F& startpos, const Point3F& endpos)
  567. {
  568. RayInfo hit_info;
  569. return getContainer()->castRay(startpos, endpos, afxCameraData::sCameraCollisionMask, &hit_info);
  570. }
  571. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  572. // STD OVERRIDES SECTION
  573. bool afxCamera::onAdd()
  574. {
  575. if(!Parent::onAdd())
  576. return false;
  577. mObjBox.maxExtents = mObjScale;
  578. mObjBox.minExtents = mObjScale;
  579. mObjBox.minExtents.neg();
  580. resetWorldBox();
  581. addToScene();
  582. return true;
  583. }
  584. void afxCamera::onRemove()
  585. {
  586. removeFromScene();
  587. Parent::onRemove();
  588. }
  589. void afxCamera::onDeleteNotify(SimObject *obj)
  590. {
  591. Parent::onDeleteNotify(obj);
  592. if (obj == (SimObject*)mOrbitObject)
  593. {
  594. mOrbitObject = NULL;
  595. if (mMode == OrbitObjectMode)
  596. mMode = OrbitPointMode;
  597. }
  598. if (obj == mCam_subject)
  599. {
  600. mCam_subject = NULL;
  601. }
  602. }
  603. void afxCamera::advanceTime(F32 dt)
  604. {
  605. Parent::advanceTime(dt);
  606. if (gSFX3DWorld)
  607. {
  608. if (mMode == ThirdPersonMode && mCam_subject)
  609. {
  610. if (gSFX3DWorld->getListener() != mCam_subject)
  611. gSFX3DWorld->setListener(mCam_subject);
  612. }
  613. else if (mMode == FlyMode)
  614. {
  615. if (gSFX3DWorld->getListener() != this)
  616. gSFX3DWorld->setListener(this);
  617. }
  618. }
  619. cam_update(dt, false);
  620. }
  621. void afxCamera::processTick(const Move* move)
  622. {
  623. Parent::processTick(move);
  624. Point3F vec,pos;
  625. // move will be NULL unless camera becomes the control object as in FlyMode
  626. if (move)
  627. {
  628. // UPDATE ORIENTATION //
  629. mDelta.rotVec = mRot;
  630. mObjToWorld.getColumn(3, &mDelta.posVec);
  631. mRot.x = mClampF(mRot.x + move->pitch, -MaxPitch, MaxPitch);
  632. mRot.z += move->yaw;
  633. // ORBIT MODE //
  634. if (mMode == OrbitObjectMode || mMode == OrbitPointMode)
  635. {
  636. if(mMode == OrbitObjectMode && bool(mOrbitObject))
  637. {
  638. // If this is a shapebase, use its render eye transform
  639. // to avoid jittering.
  640. GameBase *castObj = mOrbitObject;
  641. ShapeBase* shape = dynamic_cast<ShapeBase*>(castObj);
  642. if( shape != NULL ) {
  643. MatrixF ret;
  644. shape->getRenderEyeTransform( &ret );
  645. mPosition = ret.getPosition();
  646. }
  647. else
  648. {
  649. // Hopefully this is a static object that doesn't move,
  650. // because the worldbox doesn't get updated between ticks.
  651. mOrbitObject->getWorldBox().getCenter(&mPosition);
  652. }
  653. }
  654. set_cam_pos(mPosition, mRot);
  655. validateEyePoint(1.0f, &mObjToWorld);
  656. pos = mPosition;
  657. }
  658. // NON-ORBIT MODE (FLY MODE) //
  659. else // if (mode == FlyMode)
  660. {
  661. // Update pos
  662. bool faster = move->trigger[0] || move->trigger[1];
  663. F32 scale = Camera::getMovementSpeed() * (faster + 1);
  664. mObjToWorld.getColumn(3,&pos);
  665. mObjToWorld.getColumn(0,&vec);
  666. pos += vec * move->x * TickSec * scale;
  667. mObjToWorld.getColumn(1,&vec);
  668. pos += vec * move->y * TickSec * scale;
  669. mObjToWorld.getColumn(2,&vec);
  670. pos += vec * move->z * TickSec * scale;
  671. set_cam_pos(pos,mRot);
  672. }
  673. // If on the client, calc delta for backstepping
  674. if (isClientObject())
  675. {
  676. mDelta.pos = pos;
  677. mDelta.rot = mRot;
  678. mDelta.posVec = mDelta.posVec - mDelta.pos;
  679. mDelta.rotVec = mDelta.rotVec - mDelta.rot;
  680. }
  681. else
  682. {
  683. setMaskBits(MoveMask);
  684. }
  685. }
  686. else // if (!move)
  687. {
  688. if (isServerObject())
  689. cam_update(1.0/32.0, true);
  690. }
  691. if (getControllingClient() && mContainer)
  692. updateContainer();
  693. }
  694. void afxCamera::interpolateTick(F32 dt)
  695. {
  696. Parent::interpolateTick(dt);
  697. if (mMode == ThirdPersonMode)
  698. return;
  699. Point3F rot = mDelta.rot + mDelta.rotVec * dt;
  700. if(mMode == OrbitObjectMode || mMode == OrbitPointMode)
  701. {
  702. if(mMode == OrbitObjectMode && bool(mOrbitObject))
  703. {
  704. // If this is a shapebase, use its render eye transform
  705. // to avoid jittering.
  706. GameBase *castObj = mOrbitObject;
  707. ShapeBase* shape = dynamic_cast<ShapeBase*>(castObj);
  708. if( shape != NULL )
  709. {
  710. MatrixF ret;
  711. shape->getRenderEyeTransform( &ret );
  712. mPosition = ret.getPosition();
  713. }
  714. else
  715. {
  716. // Hopefully this is a static object that doesn't move,
  717. // because the worldbox doesn't get updated between ticks.
  718. mOrbitObject->getWorldBox().getCenter(&mPosition);
  719. }
  720. }
  721. set_cam_pos(mPosition, rot);
  722. validateEyePoint(1.0f, &mObjToWorld);
  723. }
  724. else
  725. {
  726. // NOTE - posVec is 0,0,0 unless cam is control-object and process tick is
  727. // updating the delta
  728. Point3F pos = mDelta.pos + mDelta.posVec * dt;
  729. set_cam_pos(pos,rot);
  730. }
  731. }
  732. void afxCamera::writePacketData(GameConnection *connection, BitStream *bstream)
  733. {
  734. // Update client regardless of status flags.
  735. Parent::writePacketData(connection, bstream);
  736. Point3F pos; mObjToWorld.getColumn(3, &pos);
  737. bstream->setCompressionPoint(pos); // SET COMPRESSION POINT
  738. mathWrite(*bstream, pos); // SND POS
  739. bstream->write(mRot.x); // SND X ROT
  740. bstream->write(mRot.z); // SND Z ROT
  741. if (bstream->writeFlag(mCam_dirty))
  742. {
  743. mathWrite(*bstream, mCam_offset); // SND CAM_OFFSET
  744. mathWrite(*bstream, mCoi_offset); // SND COI_OFFSET
  745. bstream->write(mCam_distance);
  746. bstream->write(mCam_angle);
  747. mCam_dirty = false;
  748. }
  749. U32 writeMode = mMode;
  750. Point3F writePos = mPosition;
  751. S32 gIndex = -1;
  752. if (mMode == OrbitObjectMode)
  753. {
  754. gIndex = bool(mOrbitObject) ? connection->getGhostIndex(mOrbitObject): -1;
  755. if(gIndex == -1)
  756. {
  757. writeMode = OrbitPointMode;
  758. mOrbitObject->getWorldBox().getCenter(&writePos);
  759. }
  760. }
  761. bstream->writeRangedU32(writeMode, CameraFirstMode, CameraLastMode); // SND MODE
  762. if (writeMode == ThirdPersonMode)
  763. {
  764. bstream->write(mThird_person_snap_s > 0); // SND SNAP
  765. if (mThird_person_snap_s > 0)
  766. mThird_person_snap_s--;
  767. }
  768. if (writeMode == OrbitObjectMode || writeMode == OrbitPointMode)
  769. {
  770. bstream->write(mMinOrbitDist); // SND ORBIT MIN DIST
  771. bstream->write(mMaxOrbitDist); // SND ORBIT MAX DIST
  772. bstream->write(mCurOrbitDist); // SND ORBIT CURR DIST
  773. if(writeMode == OrbitObjectMode)
  774. {
  775. bstream->writeFlag(mObservingClientObject); // SND OBSERVING CLIENT OBJ
  776. bstream->writeInt(gIndex, NetConnection::GhostIdBitSize); // SND ORBIT OBJ
  777. }
  778. if (writeMode == OrbitPointMode)
  779. bstream->writeCompressedPoint(writePos); // WRITE COMPRESSION POINT
  780. }
  781. }
  782. void afxCamera::readPacketData(GameConnection *connection, BitStream *bstream)
  783. {
  784. Parent::readPacketData(connection, bstream);
  785. Point3F pos,rot;
  786. mathRead(*bstream, &pos); // RCV POS
  787. bstream->setCompressionPoint(pos);
  788. bstream->read(&rot.x); // RCV X ROT
  789. bstream->read(&rot.z); // RCV Z ROT
  790. if (bstream->readFlag())
  791. {
  792. Point3F new_cam_offset, new_coi_offset;
  793. mathRead(*bstream, &new_cam_offset); // RCV CAM_OFFSET
  794. mathRead(*bstream, &new_coi_offset); // RCV COI_OFFSET
  795. bstream->read(&mCam_distance);
  796. bstream->read(&mCam_angle);
  797. setThirdPersonOffset(new_cam_offset, new_coi_offset);
  798. }
  799. GameBase* obj = 0;
  800. mMode = bstream->readRangedU32(CameraFirstMode, // RCV MODE
  801. CameraLastMode);
  802. if (mMode == ThirdPersonMode)
  803. {
  804. bool snap; bstream->read(&snap);
  805. if (snap)
  806. mThird_person_snap_c++;
  807. }
  808. mObservingClientObject = false;
  809. if (mMode == OrbitObjectMode || mMode == OrbitPointMode) {
  810. bstream->read(&mMinOrbitDist);
  811. bstream->read(&mMaxOrbitDist);
  812. bstream->read(&mCurOrbitDist);
  813. if(mMode == OrbitObjectMode)
  814. {
  815. mObservingClientObject = bstream->readFlag();
  816. S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
  817. obj = static_cast<GameBase*>(connection->resolveGhost(gIndex));
  818. }
  819. if (mMode == OrbitPointMode)
  820. bstream->readCompressedPoint(&mPosition);
  821. }
  822. if (obj != (GameBase*)mOrbitObject) {
  823. if (mOrbitObject) {
  824. clearProcessAfter();
  825. clearNotify(mOrbitObject);
  826. }
  827. mOrbitObject = obj;
  828. if (mOrbitObject) {
  829. processAfter(mOrbitObject);
  830. deleteNotify(mOrbitObject);
  831. }
  832. }
  833. if (mMode == ThirdPersonMode)
  834. return;
  835. set_cam_pos(pos,rot);
  836. mDelta.pos = pos;
  837. mDelta.rot = rot;
  838. mDelta.rotVec.set(0,0,0);
  839. mDelta.posVec.set(0,0,0);
  840. }
  841. U32 afxCamera::packUpdate(NetConnection* conn, U32 mask, BitStream *bstream)
  842. {
  843. U32 retMask = Parent::packUpdate(conn,mask,bstream);
  844. // The rest of the data is part of the control object packet update.
  845. // If we're controlled by this client, we don't need to send it.
  846. //if(bstream->writeFlag(getControllingClient() == conn && !(mask & InitialUpdateMask)))
  847. // return 0;
  848. if (bstream->writeFlag(mask & MoveMask)) {
  849. Point3F pos;
  850. mObjToWorld.getColumn(3,&pos);
  851. bstream->write(pos.x);
  852. bstream->write(pos.y);
  853. bstream->write(pos.z);
  854. bstream->write(mRot.x);
  855. bstream->write(mRot.z);
  856. }
  857. if (bstream->writeFlag(mask & SubjectMask))
  858. {
  859. S32 ghost_id = (mCam_subject) ? conn->getGhostIndex(mCam_subject) : -1;
  860. if (bstream->writeFlag(ghost_id != -1))
  861. bstream->writeRangedU32(U32(ghost_id), 0, NetConnection::MaxGhostCount);
  862. else if (mCam_subject)
  863. retMask |= SubjectMask;
  864. }
  865. return retMask;
  866. }
  867. void afxCamera::unpackUpdate(NetConnection *conn, BitStream *bstream)
  868. {
  869. Parent::unpackUpdate(conn,bstream);
  870. // controlled by the client?
  871. //if(bstream->readFlag())
  872. // return;
  873. if (bstream->readFlag()) {
  874. Point3F pos,rot;
  875. bstream->read(&pos.x);
  876. bstream->read(&pos.y);
  877. bstream->read(&pos.z);
  878. bstream->read(&rot.x);
  879. bstream->read(&rot.z);
  880. set_cam_pos(pos,rot);
  881. // New delta for client side interpolation
  882. mDelta.pos = pos;
  883. mDelta.rot = rot;
  884. mDelta.posVec = mDelta.rotVec = VectorF(0,0,0);
  885. }
  886. if (bstream->readFlag())
  887. {
  888. if (bstream->readFlag())
  889. {
  890. S32 ghost_id = bstream->readRangedU32(0, NetConnection::MaxGhostCount);
  891. mCam_subject = dynamic_cast<GameBase*>(conn->resolveGhost(ghost_id));
  892. }
  893. else
  894. mCam_subject = NULL;
  895. }
  896. }
  897. // Override to ensure both are kept in scope
  898. void afxCamera::onCameraScopeQuery(NetConnection* conn, CameraScopeQuery* query)
  899. {
  900. if (mCam_subject)
  901. conn->objectInScope(mCam_subject);
  902. Parent::onCameraScopeQuery(conn, query);
  903. }
  904. //----------------------------------------------------------------------------
  905. // check if the object needs to be observed through its own camera...
  906. void afxCamera::getCameraTransform(F32* pos, MatrixF* mat)
  907. {
  908. // The camera doesn't support a third person mode,
  909. // so we want to override the default ShapeBase behavior.
  910. ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
  911. if (obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
  912. obj->getCameraTransform(pos, mat);
  913. else
  914. getEyeTransform(mat);
  915. }
  916. void afxCamera::setTransform(const MatrixF& mat)
  917. {
  918. // This method should never be called on the client.
  919. // This currently converts all rotation in the mat into
  920. // rotations around the z and x axis.
  921. Point3F pos,vec;
  922. mat.getColumn(1,&vec);
  923. mat.getColumn(3,&pos);
  924. Point3F rot(-mAtan2(vec.z, mSqrt(vec.x*vec.x + vec.y*vec.y)),0,-mAtan2(-vec.x,vec.y));
  925. set_cam_pos(pos,rot);
  926. }
  927. void afxCamera::onEditorEnable()
  928. {
  929. mNetFlags.set(Ghostable);
  930. }
  931. void afxCamera::onEditorDisable()
  932. {
  933. mNetFlags.clear(Ghostable);
  934. }
  935. F32 afxCamera::getCameraFov()
  936. {
  937. ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
  938. if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
  939. return(obj->getCameraFov());
  940. else
  941. return(Parent::getCameraFov());
  942. }
  943. F32 afxCamera::getDefaultCameraFov()
  944. {
  945. ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
  946. if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
  947. return(obj->getDefaultCameraFov());
  948. else
  949. return(Parent::getDefaultCameraFov());
  950. }
  951. bool afxCamera::isValidCameraFov(F32 fov)
  952. {
  953. ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
  954. if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
  955. return(obj->isValidCameraFov(fov));
  956. else
  957. return(Parent::isValidCameraFov(fov));
  958. }
  959. void afxCamera::setCameraFov(F32 fov)
  960. {
  961. ShapeBase * obj = dynamic_cast<ShapeBase*>(static_cast<SimObject*>(mOrbitObject));
  962. if(obj && static_cast<ShapeBaseData*>(obj->getDataBlock())->observeThroughObject)
  963. obj->setCameraFov(fov);
  964. else
  965. Parent::setCameraFov(fov);
  966. }
  967. F32 afxCamera::getDamageFlash() const
  968. {
  969. if (mMode == OrbitObjectMode && isServerObject() && bool(mOrbitObject))
  970. {
  971. const GameBase *castObj = mOrbitObject;
  972. const ShapeBase* psb = dynamic_cast<const ShapeBase*>(castObj);
  973. if (psb)
  974. return psb->getDamageFlash();
  975. }
  976. return mDamageFlash;
  977. }
  978. F32 afxCamera::getWhiteOut() const
  979. {
  980. if (mMode == OrbitObjectMode && isServerObject() && bool(mOrbitObject))
  981. {
  982. const GameBase *castObj = mOrbitObject;
  983. const ShapeBase* psb = dynamic_cast<const ShapeBase*>(castObj);
  984. if (psb)
  985. return psb->getWhiteOut();
  986. }
  987. return mWhiteOut;
  988. }
  989. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  990. void afxCamera::setControllingClient( GameConnection* client )
  991. {
  992. GameBase::setControllingClient( client );
  993. }
  994. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//