pathShape.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. //-----------------------------------------------------------------------------
  2. // Torque Game Engine
  3. // Copyright (C) GarageGames.com, Inc.
  4. // @author Stefan "Beffy" Moises
  5. // this is a modified version of PathCamera that allows to move shapes along paths
  6. //-----------------------------------------------------------------------------
  7. #include "platform/platform.h"
  8. #include "math/mMath.h"
  9. #include "math/mathIO.h"
  10. #include "console/simBase.h"
  11. #include "console/console.h"
  12. #include "console/consoleTypes.h"
  13. #include "core/stream/bitStream.h"
  14. #include "core/dnet.h"
  15. #include "scene/pathManager.h"
  16. #include "T3D/gameFunctions.h"
  17. #include "T3D/gameBase/gameConnection.h"
  18. #include "gui/worldEditor/editor.h"
  19. #include "console/engineAPI.h"
  20. #include "math/mTransform.h"
  21. #include "T3D/pathShape.h"
  22. //----------------------------------------------------------------------------
  23. IMPLEMENT_CO_DATABLOCK_V1(PathShapeData);
  24. void PathShapeData::consoleInit()
  25. {
  26. }
  27. bool PathShapeData::preload(bool server, String &errorStr)
  28. {
  29. if(!Parent::preload(server, errorStr))
  30. return false;
  31. return true;
  32. }
  33. void PathShapeData::initPersistFields()
  34. {
  35. docsURL;
  36. Parent::initPersistFields();
  37. }
  38. void PathShapeData::packData(BitStream* stream)
  39. {
  40. Parent::packData(stream);
  41. }
  42. void PathShapeData::unpackData(BitStream* stream)
  43. {
  44. Parent::unpackData(stream);
  45. }
  46. //----------------------------------------------------------------------------
  47. IMPLEMENT_CO_NETOBJECT_V1(PathShape);
  48. PathShape::PathShape()
  49. {
  50. mNetFlags.set(Ghostable|ScopeAlways);
  51. mTypeMask |= PathShapeObjectType | StaticShapeObjectType;
  52. delta.time = 0;
  53. delta.timeVec = 0;
  54. mDataBlock = NULL;
  55. mState = Forward;
  56. mNodeBase = 0;
  57. mNodeCount = 0;
  58. mPosition = 0;
  59. mTarget = 0;
  60. mTargetSet = false;
  61. MatrixF mat = MatrixF::Identity;
  62. mLastXform = MatrixF::Identity;
  63. Parent::setTransform(mat);
  64. for (U32 i = 0; i < 4; i++)
  65. {
  66. mControl[i] = StringTable->insert("");
  67. }
  68. }
  69. PathShape::~PathShape()
  70. {
  71. }
  72. //----------------------------------------------------------------------------
  73. bool PathShape::onAdd()
  74. {
  75. if(!Parent::onAdd() && !mDataBlock)
  76. return false;
  77. mTypeMask |= PathShapeObjectType | StaticShapeObjectType;
  78. // Initialize from the current transform.
  79. if (!mNodeCount) {
  80. QuatF rot(getTransform());
  81. Point3F pos = getPosition();
  82. mSpline.removeAll();
  83. mSpline.push_back(new CameraSpline::Knot(pos,rot,1,
  84. CameraSpline::Knot::NORMAL, CameraSpline::Knot::SPLINE));
  85. mNodeCount = 1;
  86. }
  87. if (isServerObject()) scriptOnAdd();
  88. return true;
  89. }
  90. void PathShape::onRemove()
  91. {
  92. scriptOnRemove();
  93. removeFromScene();
  94. unmount();
  95. Parent::onRemove();
  96. if (isGhost())
  97. for (S32 i = 0; i < MaxSoundThreads; i++)
  98. stopAudio(i);
  99. }
  100. bool PathShape::onNewDataBlock(GameBaseData* dptr, bool reload)
  101. {
  102. mDataBlock = dynamic_cast<PathShapeData*>(dptr);
  103. if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
  104. return false;
  105. scriptOnNewDataBlock();
  106. return true;
  107. }
  108. PathShapeData::PathShapeData()
  109. {
  110. }
  111. //----------------------------------------------------------------------------
  112. void PathShape::initPersistFields()
  113. {
  114. docsURL;
  115. addField( "Path", TYPEID< SimObjectRef<SimPath::Path> >(), Offset( mSimPath, PathShape ),
  116. "@brief Name of a Path to follow." );
  117. addField("Controler", TypeString, Offset(mControl, PathShape), 4, "controlers");
  118. Parent::initPersistFields();
  119. }
  120. void PathShape::consoleInit()
  121. {
  122. }
  123. //----------------------------------------------------------------------------
  124. void PathShape::processTick(const Move* move)
  125. {
  126. // client and server
  127. Parent::processTick(move);
  128. // Move to new time
  129. advancePosition(TickMs);
  130. MatrixF mat;
  131. interpolateMat(mPosition,&mat);
  132. Parent::setTransform(mat);
  133. updateContainer();
  134. }
  135. void PathShape::interpolateTick(F32 dt)
  136. {
  137. Parent::interpolateTick(dt);
  138. MatrixF mat;
  139. interpolateMat(delta.time + (delta.timeVec * dt),&mat);
  140. Parent::setRenderTransform(mat);
  141. }
  142. void PathShape::interpolateMat(F32 pos,MatrixF* mat)
  143. {
  144. CameraSpline::Knot knot;
  145. mSpline.value(pos - mNodeBase,&knot);
  146. knot.mRotation.setMatrix(mat);
  147. mat->setPosition(knot.mPosition);
  148. }
  149. void PathShape::advancePosition(S32 ms)
  150. {
  151. delta.timeVec = mPosition;
  152. // Advance according to current speed
  153. if (mState == Forward) {
  154. mPosition = mSpline.advanceTime(mPosition - mNodeBase,ms);
  155. if (mPosition > F32(mNodeCount - 1))
  156. mPosition = F32(mNodeCount - 1);
  157. mPosition += (F32)mNodeBase;
  158. if (mTargetSet && mPosition >= mTarget) {
  159. mTargetSet = false;
  160. mPosition = mTarget;
  161. mState = Stop;
  162. }
  163. }
  164. else
  165. if (mState == Backward) {
  166. mPosition = mSpline.advanceTime(mPosition - mNodeBase,-ms);
  167. if (mPosition < 0)
  168. mPosition = 0;
  169. mPosition += mNodeBase;
  170. if (mTargetSet && mPosition <= mTarget) {
  171. mTargetSet = false;
  172. mPosition = mTarget;
  173. mState = Stop;
  174. }
  175. }
  176. // Script callbacks
  177. if (int(mPosition) != int(delta.timeVec))
  178. onNode(int(mPosition));
  179. // Set frame interpolation
  180. delta.time = mPosition;
  181. delta.timeVec -= mPosition;
  182. }
  183. //----------------------------------------------------------------------------
  184. void PathShape::setPosition(F32 pos)
  185. {
  186. mPosition = mClampF(pos,mNodeBase,mNodeBase + mNodeCount - 1);
  187. MatrixF mat;
  188. interpolateMat(mPosition,&mat);
  189. Parent::setTransform(mat);
  190. setMaskBits(PositionMask);
  191. }
  192. void PathShape::setTarget(F32 pos)
  193. {
  194. mTarget = pos;
  195. mTargetSet = true;
  196. if (mTarget > mPosition)
  197. mState = Forward;
  198. else
  199. if (mTarget < mPosition)
  200. mState = Backward;
  201. else {
  202. mTargetSet = false;
  203. mState = Stop;
  204. }
  205. setMaskBits(TargetMask | StateMask);
  206. }
  207. void PathShape::setState(State s)
  208. {
  209. mState = s;
  210. setMaskBits(StateMask);
  211. }
  212. S32 PathShape::getState()
  213. {
  214. return mState;
  215. }
  216. //-----------------------------------------------------------------------------
  217. void PathShape::reset(F32 speed)
  218. {
  219. CameraSpline::Knot *knot = new CameraSpline::Knot;
  220. mSpline.value(mPosition - mNodeBase,knot);
  221. if (speed)
  222. knot->mSpeed = speed;
  223. mSpline.removeAll();
  224. mSpline.push_back(knot);
  225. mNodeBase = 0;
  226. mNodeCount = 1;
  227. mPosition = 0;
  228. mTargetSet = false;
  229. mState = Forward;
  230. setMaskBits(StateMask | PositionMask | WindowMask | TargetMask);
  231. }
  232. void PathShape::pushBack(CameraSpline::Knot *knot)
  233. {
  234. // Make room at the end
  235. if (mNodeCount == NodeWindow) {
  236. delete mSpline.remove(mSpline.getKnot(0));
  237. mNodeBase++;
  238. }
  239. else
  240. mNodeCount++;
  241. // Fill in the new node
  242. mSpline.push_back(knot);
  243. setMaskBits(WindowMask);
  244. // Make sure the position doesn't fall off
  245. if (mPosition < mNodeBase) {
  246. mPosition = mNodeBase;
  247. setMaskBits(PositionMask);
  248. }
  249. }
  250. void PathShape::pushFront(CameraSpline::Knot *knot)
  251. {
  252. // Make room at the front
  253. if (mNodeCount == NodeWindow)
  254. delete mSpline.remove(mSpline.getKnot(mNodeCount));
  255. else
  256. mNodeCount++;
  257. mNodeBase--;
  258. // Fill in the new node
  259. mSpline.push_front(knot);
  260. setMaskBits(WindowMask);
  261. // Make sure the position doesn't fall off
  262. if (mPosition > mNodeBase + (NodeWindow - 1)) {
  263. mPosition = mNodeBase + (NodeWindow - 1);
  264. setMaskBits(PositionMask);
  265. }
  266. }
  267. void PathShape::popFront()
  268. {
  269. if (mNodeCount < 2)
  270. return;
  271. // Remove the first node. Node base and position are unaffected.
  272. mNodeCount--;
  273. delete mSpline.remove(mSpline.getKnot(0));
  274. }
  275. //----------------------------------------------------------------------------
  276. void PathShape::onNode(S32 node)
  277. {
  278. if (!isGhost())
  279. {
  280. Con::executef(mDataBlock, "onNode", getIdString(), Con::getIntArg(node));
  281. Con::executef(mDataBlock, mSpline.getKnot(node)->mHitCommand.c_str(), getIdString());
  282. }
  283. }
  284. //----------------------------------------------------------------------------
  285. //----------------------------------------------------------------------------
  286. U32 PathShape::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  287. {
  288. Parent::packUpdate(con,mask,stream);
  289. if (stream->writeFlag(mask & StateMask))
  290. stream->writeInt(mState,StateBits);
  291. if (stream->writeFlag(mask & PositionMask))
  292. stream->write(mPosition);
  293. if (stream->writeFlag(mask & TargetMask))
  294. if (stream->writeFlag(mTargetSet))
  295. stream->write(mTarget);
  296. if (stream->writeFlag(mask & WindowMask)) {
  297. stream->write(mNodeBase);
  298. stream->write(mNodeCount);
  299. for (S32 i = 0; i < mNodeCount; i++) {
  300. CameraSpline::Knot *knot = mSpline.getKnot(i);
  301. mathWrite(*stream, knot->mPosition);
  302. mathWrite(*stream, knot->mRotation);
  303. stream->write(knot->mSpeed);
  304. stream->writeInt(knot->mType, CameraSpline::Knot::NUM_TYPE_BITS);
  305. stream->writeInt(knot->mPath, CameraSpline::Knot::NUM_PATH_BITS);
  306. }
  307. }
  308. // The rest of the data is part of the control object packet update.
  309. // If we're controlled by this client, we don't need to send it.
  310. if(stream->writeFlag(getControllingClient() == con && !(mask & InitialUpdateMask)))
  311. return 0;
  312. return 0;
  313. }
  314. void PathShape::unpackUpdate(NetConnection *con, BitStream *stream)
  315. {
  316. Parent::unpackUpdate(con,stream);
  317. // StateMask
  318. if (stream->readFlag())
  319. mState = stream->readInt(StateBits);
  320. // PositionMask
  321. if (stream->readFlag()) {
  322. stream->read(&mPosition);
  323. delta.time = mPosition;
  324. delta.timeVec = 0;
  325. }
  326. // TargetMask
  327. if (stream->readFlag()) {
  328. mTargetSet = stream->readFlag();
  329. if (mTargetSet) {
  330. stream->read(&mTarget);
  331. }
  332. }
  333. // WindowMask
  334. if (stream->readFlag()) {
  335. mSpline.removeAll();
  336. stream->read(&mNodeBase);
  337. stream->read(&mNodeCount);
  338. for (S32 i = 0; i < mNodeCount; i++) {
  339. CameraSpline::Knot *knot = new CameraSpline::Knot();
  340. mathRead(*stream, &knot->mPosition);
  341. mathRead(*stream, &knot->mRotation);
  342. stream->read(&knot->mSpeed);
  343. knot->mType = (CameraSpline::Knot::Type)stream->readInt(CameraSpline::Knot::NUM_TYPE_BITS);
  344. knot->mPath = (CameraSpline::Knot::Path)stream->readInt(CameraSpline::Knot::NUM_PATH_BITS);
  345. mSpline.push_back(knot);
  346. }
  347. }
  348. // Controlled by the client?
  349. if (stream->readFlag()) return;
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Console access methods
  353. //-----------------------------------------------------------------------------
  354. DefineEngineMethod(PathShape, setPosition, void, (F32 position), (0.0f), "Set the current position of the camera along the path.\n"
  355. "@param position Position along the path, from 0.0 (path start) - 1.0 (path end), to place the camera.\n"
  356. "@tsexample\n"
  357. "// Set the camera on a position along its path from 0.0 - 1.0.\n"
  358. "%position = \"0.35\";\n\n"
  359. "// Force the pathCamera to its new position along the path.\n"
  360. "%pathCamera.setPosition(%position);\n"
  361. "@endtsexample\n")
  362. {
  363. object->setPosition(position);
  364. }
  365. DefineEngineMethod(PathShape, setTarget, void, (F32 position), (1.0f), "@brief Set the movement target for this camera along its path.\n\n"
  366. "The camera will attempt to move along the path to the given target in the direction provided "
  367. "by setState() (the default is forwards). Once the camera moves past this target it will come "
  368. "to a stop, and the target state will be cleared.\n"
  369. "@param position Target position, between 0.0 (path start) and 1.0 (path end), for the camera to move to along its path.\n"
  370. "@tsexample\n"
  371. "// Set the position target, between 0.0 (path start) and 1.0 (path end), for this camera to move to.\n"
  372. "%position = \"0.50\";\n\n"
  373. "// Inform the pathCamera of the new target position it will move to.\n"
  374. "%pathCamera.setTarget(%position);\n"
  375. "@endtsexample\n")
  376. {
  377. object->setTarget(position);
  378. }
  379. DefineEngineMethod(PathShape, setState, void, (const char* newState), ("forward"), "Set the movement state for this path camera.\n"
  380. "@param newState New movement state type for this camera. Forward, Backward or Stop.\n"
  381. "@tsexample\n"
  382. "// Set the state type (forward, backward, stop).\n"
  383. "// In this example, the camera will travel from the first node\n"
  384. "// to the last node (or target if given with setTarget())\n"
  385. "%state = \"forward\";\n\n"
  386. "// Inform the pathCamera to change its movement state to the defined value.\n"
  387. "%pathCamera.setState(%state);\n"
  388. "@endtsexample\n")
  389. {
  390. if (!dStricmp(newState, "forward"))
  391. object->setState(PathShape::Forward);
  392. else
  393. if (!dStricmp(newState, "backward"))
  394. object->setState(PathShape::Backward);
  395. else
  396. object->setState(PathShape::Stop);
  397. }
  398. DefineEngineMethod(PathShape, 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"
  399. "What specifically occurs is a new knot is created from the camera's current transform. Then the current path "
  400. "is cleared and the new knot is pushed onto the path. Any previous target is cleared and the camera's movement "
  401. "state is set to Forward. The camera is now ready for a new path to be defined.\n"
  402. "@param speed Speed for the camera to move along its path after being reset.\n"
  403. "@tsexample\n"
  404. "//Determine the new movement speed of this camera. If not set, the speed will default to 1.0.\n"
  405. "%speed = \"0.50\";\n\n"
  406. "// Inform the path camera to start a new path at"
  407. "// the camera's current position, and set the new "
  408. "// path's speed value.\n"
  409. "%pathCamera.reset(%speed);\n"
  410. "@endtsexample\n")
  411. {
  412. object->reset(speed);
  413. }
  414. static CameraSpline::Knot::Type resolveKnotType(const char *arg)
  415. {
  416. if (dStricmp(arg, "Position Only") == 0)
  417. return CameraSpline::Knot::POSITION_ONLY;
  418. if (dStricmp(arg, "Kink") == 0)
  419. return CameraSpline::Knot::KINK;
  420. return CameraSpline::Knot::NORMAL;
  421. }
  422. static CameraSpline::Knot::Path resolveKnotPath(const char *arg)
  423. {
  424. if (!dStricmp(arg, "Linear"))
  425. return CameraSpline::Knot::LINEAR;
  426. return CameraSpline::Knot::SPLINE;
  427. }
  428. DefineEngineMethod(PathShape, pushBack, void, (TransformF transform, F32 speed, const char* type, const char* path, const char *hitCommand),
  429. (TransformF::Identity, 1.0f, "Normal", "Linear",""),
  430. "@brief Adds a new knot to the back of a path camera's path.\n"
  431. "@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"
  432. "@param speed Speed setting for this knot.\n"
  433. "@param type Knot type (Normal, Position Only, Kink).\n"
  434. "@param path %Path type (Linear, Spline).\n"
  435. "@tsexample\n"
  436. "// Transform vector for new knot. (Pos_X Pos_Y Pos_Z Rot_X Rot_Y Rot_Z Angle)\n"
  437. "%transform = \"15.0 5.0 5.0 1.4 1.0 0.2 1.0\"\n\n"
  438. "// Speed setting for knot.\n"
  439. "%speed = \"1.0\"\n\n"
  440. "// Knot type. (Normal, Position Only, Kink)\n"
  441. "%type = \"Normal\";\n\n"
  442. "// Path Type. (Linear, Spline)\n"
  443. "%path = \"Linear\";\n\n"
  444. "// Inform the path camera to add a new knot to the back of its path\n"
  445. "%pathCamera.pushBack(%transform,%speed,%type,%path);\n"
  446. "@endtsexample\n")
  447. {
  448. QuatF rot(transform.getOrientation());
  449. object->pushBack(new CameraSpline::Knot(transform.getPosition(), rot, speed, resolveKnotType(type), resolveKnotPath(path), String(hitCommand)));
  450. }
  451. DefineEngineMethod(PathShape, pushFront, void, (TransformF transform, F32 speed, const char* type, const char* path),
  452. (1.0f, "Normal", "Linear"),
  453. "@brief Adds a new knot to the front of a path camera's path.\n"
  454. "@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"
  455. "@param speed Speed setting for this knot.\n"
  456. "@param type Knot type (Normal, Position Only, Kink).\n"
  457. "@param path %Path type (Linear, Spline).\n"
  458. "@tsexample\n"
  459. "// Transform vector for new knot. (Pos_X,Pos_Y,Pos_Z,Rot_X,Rot_Y,Rot_Z,Angle)\n"
  460. "%transform = \"15.0 5.0 5.0 1.4 1.0 0.2 1.0\"\n\n"
  461. "// Speed setting for knot.\n"
  462. "%speed = \"1.0\";\n\n"
  463. "// Knot type. (Normal, Position Only, Kink)\n"
  464. "%type = \"Normal\";\n\n"
  465. "// Path Type. (Linear, Spline)\n"
  466. "%path = \"Linear\";\n\n"
  467. "// Inform the path camera to add a new knot to the front of its path\n"
  468. "%pathCamera.pushFront(%transform, %speed, %type, %path);\n"
  469. "@endtsexample\n")
  470. {
  471. QuatF rot(transform.getOrientation());
  472. object->pushFront(new CameraSpline::Knot(transform.getPosition(), rot, speed, resolveKnotType(type), resolveKnotPath(path)));
  473. }
  474. DefineEngineMethod(PathShape, popFront, void, (), , "Removes the knot at the front of the camera's path.\n"
  475. "@tsexample\n"
  476. "// Remove the first knot in the camera's path.\n"
  477. "%pathCamera.popFront();\n"
  478. "@endtsexample\n")
  479. {
  480. object->popFront();
  481. }
  482. DefineEngineMethod(PathShape, getState, S32, (), , "PathShape.getState()")
  483. {
  484. return object->getState();
  485. }