pathCamera.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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. #include "platform/platform.h"
  23. #include "math/mMath.h"
  24. #include "math/mathIO.h"
  25. #include "console/simBase.h"
  26. #include "console/console.h"
  27. #include "console/consoleTypes.h"
  28. #include "core/stream/bitStream.h"
  29. #include "core/dnet.h"
  30. #include "scene/pathManager.h"
  31. #include "app/game.h"
  32. #include "T3D/gameBase/gameConnection.h"
  33. #include "T3D/fx/cameraFXMgr.h"
  34. #include "console/engineAPI.h"
  35. #include "math/mTransform.h"
  36. #include "T3D/pathCamera.h"
  37. //----------------------------------------------------------------------------
  38. IMPLEMENT_CO_DATABLOCK_V1(PathCameraData);
  39. ConsoleDocClass( PathCameraData,
  40. "@brief General interface to control a PathCamera object from the script level.\n"
  41. "@see PathCamera\n"
  42. "@tsexample\n"
  43. "datablock PathCameraData(LoopingCam)\n"
  44. " {\n"
  45. " mode = \"\";\n"
  46. " };\n"
  47. "@endtsexample\n"
  48. "@ingroup PathCameras\n"
  49. "@ingroup Datablocks\n"
  50. );
  51. void PathCameraData::consoleInit()
  52. {
  53. }
  54. void PathCameraData::initPersistFields()
  55. {
  56. docsURL;
  57. Parent::initPersistFields();
  58. }
  59. void PathCameraData::packData(BitStream* stream)
  60. {
  61. Parent::packData(stream);
  62. }
  63. void PathCameraData::unpackData(BitStream* stream)
  64. {
  65. Parent::unpackData(stream);
  66. }
  67. //----------------------------------------------------------------------------
  68. IMPLEMENT_CO_NETOBJECT_V1(PathCamera);
  69. ConsoleDocClass( PathCamera,
  70. "@brief A camera that moves along a path. The camera can then be made to travel along this path forwards or backwards.\n\n"
  71. "A camera's path is made up of knots, which define a position, rotation and speed for the camera. Traversal from one knot to "
  72. "another may be either linear or using a Catmull-Rom spline. If the knot is part of a spline, then it may be a normal knot "
  73. "or defined as a kink. Kinked knots are a hard transition on the spline rather than a smooth one. A knot may also be defined "
  74. "as a position only. In this case the knot is treated as a normal knot but is ignored when determining how to smoothly rotate "
  75. "the camera while it is travelling along the path (the algorithm moves on to the next knot in the path for determining rotation).\n\n"
  76. "The datablock field for a PathCamera is a previously created PathCameraData, which acts as the interface between the script and the engine "
  77. "for this PathCamera object.\n\n"
  78. "@see PathCameraData\n"
  79. "@tsexample\n"
  80. "%newPathCamera = new PathCamera()\n"
  81. "{\n"
  82. " dataBlock = LoopingCam;\n"
  83. " position = \"0 0 300 1 0 0 0\";\n"
  84. "};\n"
  85. "@endtsexample\n"
  86. "@ingroup PathCameras\n"
  87. );
  88. IMPLEMENT_CALLBACK( PathCamera, onNode, void, (S32 node), (node),
  89. "A script callback that indicates the path camera has arrived at a specific node in its path. Server side only.\n"
  90. "@param Node Unique ID assigned to this node.\n");
  91. PathCamera::PathCamera()
  92. {
  93. mNetFlags.clear(Ghostable);
  94. mTypeMask |= CameraObjectType;
  95. delta.time = 0;
  96. delta.timeVec = 0;
  97. mDataBlock = 0;
  98. mState = Forward;
  99. mNodeBase = 0;
  100. mNodeCount = 0;
  101. mPosition = 0;
  102. mTarget = 0;
  103. mTargetSet = false;
  104. MatrixF mat(1);
  105. mat.setPosition(Point3F(0,0,700));
  106. Parent::setTransform(mat);
  107. }
  108. PathCamera::~PathCamera()
  109. {
  110. }
  111. //----------------------------------------------------------------------------
  112. bool PathCamera::onAdd()
  113. {
  114. if(!Parent::onAdd())
  115. return false;
  116. // Initialize from the current transform.
  117. if (!mNodeCount) {
  118. QuatF rot(getTransform());
  119. Point3F pos = getPosition();
  120. mSpline.removeAll();
  121. mSpline.push_back(new CameraSpline::Knot(pos,rot,1,
  122. CameraSpline::Knot::NORMAL, CameraSpline::Knot::SPLINE));
  123. mNodeCount = 1;
  124. }
  125. //
  126. mObjBox.maxExtents = mObjScale;
  127. mObjBox.minExtents = mObjScale;
  128. mObjBox.minExtents.neg();
  129. resetWorldBox();
  130. if (mShapeInstance)
  131. {
  132. mNetFlags.set(Ghostable);
  133. setScopeAlways();
  134. }
  135. addToScene();
  136. return true;
  137. }
  138. void PathCamera::onRemove()
  139. {
  140. removeFromScene();
  141. Parent::onRemove();
  142. }
  143. bool PathCamera::onNewDataBlock( GameBaseData *dptr, bool reload )
  144. {
  145. mDataBlock = dynamic_cast< PathCameraData* >( dptr );
  146. if ( !mDataBlock || !Parent::onNewDataBlock( dptr, reload ) )
  147. return false;
  148. scriptOnNewDataBlock();
  149. return true;
  150. }
  151. //----------------------------------------------------------------------------
  152. void PathCamera::onEditorEnable()
  153. {
  154. mNetFlags.set(Ghostable);
  155. }
  156. void PathCamera::onEditorDisable()
  157. {
  158. mNetFlags.clear(Ghostable);
  159. }
  160. //----------------------------------------------------------------------------
  161. void PathCamera::initPersistFields()
  162. {
  163. docsURL;
  164. Parent::initPersistFields();
  165. }
  166. void PathCamera::consoleInit()
  167. {
  168. }
  169. //----------------------------------------------------------------------------
  170. void PathCamera::processTick(const Move* move)
  171. {
  172. // client and server
  173. Parent::processTick(move);
  174. // Move to new time
  175. advancePosition(TickMs);
  176. // Set new position
  177. MatrixF mat;
  178. interpolateMat(mPosition,&mat);
  179. Parent::setTransform(mat);
  180. updateContainer();
  181. }
  182. void PathCamera::interpolateTick(F32 dt)
  183. {
  184. Parent::interpolateTick(dt);
  185. MatrixF mat;
  186. interpolateMat(delta.time + (delta.timeVec * dt),&mat);
  187. Parent::setRenderTransform(mat);
  188. }
  189. void PathCamera::interpolateMat(F32 pos,MatrixF* mat)
  190. {
  191. CameraSpline::Knot knot;
  192. mSpline.value(pos - mNodeBase,&knot);
  193. knot.mRotation.setMatrix(mat);
  194. mat->setPosition(knot.mPosition);
  195. }
  196. void PathCamera::advancePosition(S32 ms)
  197. {
  198. delta.timeVec = mPosition;
  199. // Advance according to current speed
  200. if (mState == Forward) {
  201. mPosition = mSpline.advanceTime(mPosition - mNodeBase,ms);
  202. if (mPosition > F32(mNodeCount - 1))
  203. mPosition = F32(mNodeCount - 1);
  204. mPosition += (F32)mNodeBase;
  205. if (mTargetSet && mPosition >= mTarget) {
  206. mTargetSet = false;
  207. mPosition = mTarget;
  208. mState = Stop;
  209. }
  210. }
  211. else
  212. if (mState == Backward) {
  213. mPosition = mSpline.advanceTime(mPosition - mNodeBase,-ms);
  214. if (mPosition < 0)
  215. mPosition = 0;
  216. mPosition += mNodeBase;
  217. if (mTargetSet && mPosition <= mTarget) {
  218. mTargetSet = false;
  219. mPosition = mTarget;
  220. mState = Stop;
  221. }
  222. }
  223. // Script callbacks
  224. if (int(mPosition) != int(delta.timeVec))
  225. onNode(int(mPosition));
  226. // Set frame interpolation
  227. delta.time = mPosition;
  228. delta.timeVec -= mPosition;
  229. }
  230. //----------------------------------------------------------------------------
  231. void PathCamera::getCameraTransform(F32* pos, MatrixF* mat)
  232. {
  233. // Overide the ShapeBase method to skip all the first/third person support.
  234. getRenderEyeTransform(mat);
  235. // Apply Camera FX.
  236. mat->mul( gCamFXMgr.getTrans() );
  237. }
  238. //----------------------------------------------------------------------------
  239. void PathCamera::setPosition(F32 pos)
  240. {
  241. mPosition = mClampF(pos, (F32)mNodeBase, (F32)(mNodeBase + mNodeCount - 1));
  242. MatrixF mat;
  243. interpolateMat(mPosition,&mat);
  244. Parent::setTransform(mat);
  245. setMaskBits(PositionMask);
  246. }
  247. void PathCamera::setTarget(F32 pos)
  248. {
  249. mTarget = pos;
  250. mTargetSet = true;
  251. if (mTarget > mPosition)
  252. mState = Forward;
  253. else
  254. if (mTarget < mPosition)
  255. mState = Backward;
  256. else {
  257. mTargetSet = false;
  258. mState = Stop;
  259. }
  260. setMaskBits(TargetMask | StateMask);
  261. }
  262. void PathCamera::setState(State s)
  263. {
  264. mState = s;
  265. setMaskBits(StateMask);
  266. }
  267. //-----------------------------------------------------------------------------
  268. void PathCamera::reset(F32 speed)
  269. {
  270. CameraSpline::Knot *knot = new CameraSpline::Knot;
  271. mSpline.value(mPosition - mNodeBase,knot);
  272. if (speed)
  273. knot->mSpeed = speed;
  274. mSpline.removeAll();
  275. mSpline.push_back(knot);
  276. mNodeBase = 0;
  277. mNodeCount = 1;
  278. mPosition = 0;
  279. mTargetSet = false;
  280. mState = Forward;
  281. setMaskBits(StateMask | PositionMask | WindowMask | TargetMask);
  282. }
  283. void PathCamera::pushBack(CameraSpline::Knot *knot)
  284. {
  285. // Make room at the end
  286. if (mNodeCount == NodeWindow) {
  287. delete mSpline.remove(mSpline.getKnot(0));
  288. mNodeBase++;
  289. }
  290. else
  291. mNodeCount++;
  292. // Fill in the new node
  293. mSpline.push_back(knot);
  294. setMaskBits(WindowMask);
  295. // Make sure the position doesn't fall off
  296. if (mPosition < mNodeBase) {
  297. mPosition = (F32)mNodeBase;
  298. setMaskBits(PositionMask);
  299. }
  300. }
  301. void PathCamera::pushFront(CameraSpline::Knot *knot)
  302. {
  303. // Make room at the front
  304. if (mNodeCount == NodeWindow)
  305. delete mSpline.remove(mSpline.getKnot(mNodeCount));
  306. else
  307. mNodeCount++;
  308. mNodeBase--;
  309. // Fill in the new node
  310. mSpline.push_front(knot);
  311. setMaskBits(WindowMask);
  312. // Make sure the position doesn't fall off
  313. if (mPosition > F32(mNodeBase + (NodeWindow - 1)))
  314. {
  315. mPosition = F32(mNodeBase + (NodeWindow - 1));
  316. setMaskBits(PositionMask);
  317. }
  318. }
  319. void PathCamera::popFront()
  320. {
  321. if (mNodeCount < 2)
  322. return;
  323. // Remove the first node. Node base and position are unaffected.
  324. mNodeCount--;
  325. delete mSpline.remove(mSpline.getKnot(0));
  326. if( mPosition > 0 )
  327. mPosition --;
  328. }
  329. //----------------------------------------------------------------------------
  330. void PathCamera::onNode(S32 node)
  331. {
  332. if (!isGhost())
  333. onNode_callback(node);
  334. }
  335. U32 PathCamera::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  336. {
  337. Parent::packUpdate(con,mask,stream);
  338. if (stream->writeFlag(mask & StateMask))
  339. stream->writeInt(mState,StateBits);
  340. if (stream->writeFlag(mask & PositionMask))
  341. stream->write(mPosition);
  342. if (stream->writeFlag(mask & TargetMask))
  343. if (stream->writeFlag(mTargetSet))
  344. stream->write(mTarget);
  345. if (stream->writeFlag(mask & WindowMask)) {
  346. stream->write(mNodeBase);
  347. stream->write(mNodeCount);
  348. for (S32 i = 0; i < mNodeCount; i++) {
  349. CameraSpline::Knot *knot = mSpline.getKnot(i);
  350. mathWrite(*stream, knot->mPosition);
  351. mathWrite(*stream, knot->mRotation);
  352. stream->write(knot->mSpeed);
  353. stream->writeInt(knot->mType, CameraSpline::Knot::NUM_TYPE_BITS);
  354. stream->writeInt(knot->mPath, CameraSpline::Knot::NUM_PATH_BITS);
  355. }
  356. }
  357. // The rest of the data is part of the control object packet update.
  358. // If we're controlled by this client, we don't need to send it.
  359. if(stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask)))
  360. return 0;
  361. return 0;
  362. }
  363. void PathCamera::unpackUpdate(NetConnection *con, BitStream *stream)
  364. {
  365. Parent::unpackUpdate(con,stream);
  366. // StateMask
  367. if (stream->readFlag())
  368. mState = stream->readInt(StateBits);
  369. // PositionMask
  370. if (stream->readFlag())
  371. {
  372. stream->read(&mPosition);
  373. delta.time = mPosition;
  374. delta.timeVec = 0;
  375. }
  376. // TargetMask
  377. if (stream->readFlag())
  378. {
  379. mTargetSet = stream->readFlag();
  380. if (mTargetSet)
  381. stream->read(&mTarget);
  382. }
  383. // WindowMask
  384. if (stream->readFlag())
  385. {
  386. mSpline.removeAll();
  387. stream->read(&mNodeBase);
  388. stream->read(&mNodeCount);
  389. for (S32 i = 0; i < mNodeCount; i++)
  390. {
  391. CameraSpline::Knot *knot = new CameraSpline::Knot();
  392. mathRead(*stream, &knot->mPosition);
  393. mathRead(*stream, &knot->mRotation);
  394. stream->read(&knot->mSpeed);
  395. knot->mType = (CameraSpline::Knot::Type)stream->readInt(CameraSpline::Knot::NUM_TYPE_BITS);
  396. knot->mPath = (CameraSpline::Knot::Path)stream->readInt(CameraSpline::Knot::NUM_PATH_BITS);
  397. mSpline.push_back(knot);
  398. }
  399. }
  400. // Controlled by the client?
  401. if (stream->readFlag())
  402. return;
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Console access methods
  406. //-----------------------------------------------------------------------------
  407. DefineEngineMethod(PathCamera, setPosition, void, (F32 position),(0.0f), "Set the current position of the camera along the path.\n"
  408. "@param position Position along the path, from 0.0 (path start) - 1.0 (path end), to place the camera.\n"
  409. "@tsexample\n"
  410. "// Set the camera on a position along its path from 0.0 - 1.0.\n"
  411. "%position = \"0.35\";\n\n"
  412. "// Force the pathCamera to its new position along the path.\n"
  413. "%pathCamera.setPosition(%position);\n"
  414. "@endtsexample\n")
  415. {
  416. object->setPosition(position);
  417. }
  418. DefineEngineMethod(PathCamera, setTarget, void, (F32 position),(1.0f), "@brief Set the movement target for this camera along its path.\n\n"
  419. "The camera will attempt to move along the path to the given target in the direction provided "
  420. "by setState() (the default is forwards). Once the camera moves past this target it will come "
  421. "to a stop, and the target state will be cleared.\n"
  422. "@param position Target position, between 0.0 (path start) and 1.0 (path end), for the camera to move to along its path.\n"
  423. "@tsexample\n"
  424. "// Set the position target, between 0.0 (path start) and 1.0 (path end), for this camera to move to.\n"
  425. "%position = \"0.50\";\n\n"
  426. "// Inform the pathCamera of the new target position it will move to.\n"
  427. "%pathCamera.setTarget(%position);\n"
  428. "@endtsexample\n")
  429. {
  430. object->setTarget(position);
  431. }
  432. DefineEngineMethod(PathCamera, setState, void, (const char* newState),("forward"), "Set the movement state for this path camera.\n"
  433. "@param newState New movement state type for this camera. Forward, Backward or Stop.\n"
  434. "@tsexample\n"
  435. "// Set the state type (forward, backward, stop).\n"
  436. "// In this example, the camera will travel from the first node\n"
  437. "// to the last node (or target if given with setTarget())\n"
  438. "%state = \"forward\";\n\n"
  439. "// Inform the pathCamera to change its movement state to the defined value.\n"
  440. "%pathCamera.setState(%state);\n"
  441. "@endtsexample\n")
  442. {
  443. if (!dStricmp(newState,"forward"))
  444. object->setState(PathCamera::Forward);
  445. else
  446. if (!dStricmp(newState,"backward"))
  447. object->setState(PathCamera::Backward);
  448. else
  449. object->setState(PathCamera::Stop);
  450. }
  451. DefineEngineMethod(PathCamera, reset, void, (F32 speed),(1.0f), "@brief Clear the camera's path and set the camera's current transform as the start of the new path.\n\n"
  452. "What specifically occurs is a new knot is created from the camera's current transform. Then the current path "
  453. "is cleared and the new knot is pushed onto the path. Any previous target is cleared and the camera's movement "
  454. "state is set to Forward. The camera is now ready for a new path to be defined.\n"
  455. "@param speed Speed for the camera to move along its path after being reset.\n"
  456. "@tsexample\n"
  457. "//Determine the new movement speed of this camera. If not set, the speed will default to 1.0.\n"
  458. "%speed = \"0.50\";\n\n"
  459. "// Inform the path camera to start a new path at"
  460. "// the camera's current position, and set the new "
  461. "// path's speed value.\n"
  462. "%pathCamera.reset(%speed);\n"
  463. "@endtsexample\n")
  464. {
  465. object->reset(speed);
  466. }
  467. static CameraSpline::Knot::Type resolveKnotType(const char *arg)
  468. {
  469. if (dStricmp(arg, "Position Only") == 0)
  470. return CameraSpline::Knot::POSITION_ONLY;
  471. if (dStricmp(arg, "Kink") == 0)
  472. return CameraSpline::Knot::KINK;
  473. return CameraSpline::Knot::NORMAL;
  474. }
  475. static CameraSpline::Knot::Path resolveKnotPath(const char *arg)
  476. {
  477. if (!dStricmp(arg, "Linear"))
  478. return CameraSpline::Knot::LINEAR;
  479. return CameraSpline::Knot::SPLINE;
  480. }
  481. DefineEngineMethod(PathCamera, pushBack, void, (TransformF transform, F32 speed, const char* type, const char* path),
  482. (1.0f, "Normal", "Linear"),
  483. "@brief Adds a new knot to the back of a path camera's path.\n"
  484. "@param transform Transform for the new knot. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform()\n"
  485. "@param speed Speed setting for this knot.\n"
  486. "@param type Knot type (Normal, Position Only, Kink).\n"
  487. "@param path %Path type (Linear, Spline).\n"
  488. "@tsexample\n"
  489. "// Transform vector for new knot. (Pos_X Pos_Y Pos_Z Rot_X Rot_Y Rot_Z Angle)\n"
  490. "%transform = \"15.0 5.0 5.0 1.4 1.0 0.2 1.0\"\n\n"
  491. "// Speed setting for knot.\n"
  492. "%speed = \"1.0\"\n\n"
  493. "// Knot type. (Normal, Position Only, Kink)\n"
  494. "%type = \"Normal\";\n\n"
  495. "// Path Type. (Linear, Spline)\n"
  496. "%path = \"Linear\";\n\n"
  497. "// Inform the path camera to add a new knot to the back of its path\n"
  498. "%pathCamera.pushBack(%transform,%speed,%type,%path);\n"
  499. "@endtsexample\n")
  500. {
  501. QuatF rot(transform.getOrientation());
  502. object->pushBack( new CameraSpline::Knot(transform.getPosition(), rot, speed, resolveKnotType(type), resolveKnotPath(path)) );
  503. }
  504. DefineEngineMethod(PathCamera, pushFront, void, (TransformF transform, F32 speed, const char* type, const char* path),
  505. (1.0f, "Normal", "Linear"),
  506. "@brief Adds a new knot to the front of a path camera's path.\n"
  507. "@param transform Transform for the new knot. In the form of \"x y z ax ay az aa\" such as returned by SceneObject::getTransform()\n"
  508. "@param speed Speed setting for this knot.\n"
  509. "@param type Knot type (Normal, Position Only, Kink).\n"
  510. "@param path %Path type (Linear, Spline).\n"
  511. "@tsexample\n"
  512. "// Transform vector for new knot. (Pos_X,Pos_Y,Pos_Z,Rot_X,Rot_Y,Rot_Z,Angle)\n"
  513. "%transform = \"15.0 5.0 5.0 1.4 1.0 0.2 1.0\"\n\n"
  514. "// Speed setting for knot.\n"
  515. "%speed = \"1.0\";\n\n"
  516. "// Knot type. (Normal, Position Only, Kink)\n"
  517. "%type = \"Normal\";\n\n"
  518. "// Path Type. (Linear, Spline)\n"
  519. "%path = \"Linear\";\n\n"
  520. "// Inform the path camera to add a new knot to the front of its path\n"
  521. "%pathCamera.pushFront(%transform, %speed, %type, %path);\n"
  522. "@endtsexample\n")
  523. {
  524. QuatF rot(transform.getOrientation());
  525. object->pushFront( new CameraSpline::Knot(transform.getPosition(), rot, speed, resolveKnotType(type), resolveKnotPath(path)) );
  526. }
  527. DefineEngineMethod(PathCamera, popFront, void, (),, "Removes the knot at the front of the camera's path.\n"
  528. "@tsexample\n"
  529. "// Remove the first knot in the camera's path.\n"
  530. "%pathCamera.popFront();\n"
  531. "@endtsexample\n")
  532. {
  533. object->popFront();
  534. }