afxCamera.cpp 32 KB

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