simPath.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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 "scene/simPath.h"
  24. #include "gfx/gfxDevice.h"
  25. #include "gfx/gfxVertexBuffer.h"
  26. #include "gfx/gfxPrimitiveBuffer.h"
  27. #include "gfx/gfxTransformSaver.h"
  28. #include "console/consoleTypes.h"
  29. #include "scene/pathManager.h"
  30. #include "scene/sceneRenderState.h"
  31. #include "math/mathIO.h"
  32. #include "core/stream/bitStream.h"
  33. #include "renderInstance/renderPassManager.h"
  34. #include "console/engineAPI.h"
  35. #include "T3D/pathShape.h"
  36. #include "T3D/physics/physicsShape.h"
  37. #include "T3D/Scene.h"
  38. extern bool gEditingMission;
  39. //--------------------------------------------------------------------------
  40. //-------------------------------------- Console functions and cmp funcs
  41. //
  42. DefineEngineFunction(pathOnMissionLoadDone, void, (),,
  43. "@brief Load all Path information from the mission.\n\n"
  44. "This function is usually called from the loadMissionStage2() server-side function "
  45. "after the mission file has loaded. Internally it places all Paths into the server's "
  46. "PathManager. From this point the Paths are ready for transmission to the clients.\n\n"
  47. "@tsexample\n"
  48. "// Inform the engine to load all Path information from the mission.\n"
  49. "pathOnMissionLoadDone();\n\n"
  50. "@endtsexample\n"
  51. "@see NetConnection::transmitPaths()\n"
  52. "@see NetConnection::clearPaths()\n"
  53. "@see Path\n"
  54. "@ingroup Networking")
  55. {
  56. // Need to load subobjects for all loaded interiors...
  57. Scene* scene = Scene::getRootScene();
  58. AssertFatal(scene != NULL, "Error, mission done loading and no scene?");
  59. U32 currStart = 0;
  60. U32 currEnd = 1;
  61. Vector<SimGroup*> groups;
  62. groups.push_back(scene);
  63. while (true) {
  64. for (U32 i = currStart; i < currEnd; i++) {
  65. for (SimGroup::iterator itr = groups[i]->begin(); itr != groups[i]->end(); itr++) {
  66. if (dynamic_cast<SimGroup*>(*itr) != NULL)
  67. groups.push_back(static_cast<SimGroup*>(*itr));
  68. }
  69. }
  70. if (groups.size() == currEnd) {
  71. break;
  72. } else {
  73. currStart = currEnd;
  74. currEnd = groups.size();
  75. }
  76. }
  77. for (U32 i = 0; i < groups.size(); i++) {
  78. SimPath::Path* pPath = dynamic_cast<SimPath::Path*>(groups[i]);
  79. if (pPath)
  80. pPath->updatePath();
  81. }
  82. }
  83. S32 FN_CDECL cmpPathObject(const void* p1, const void* p2)
  84. {
  85. SimObject* o1 = *((SimObject**)p1);
  86. SimObject* o2 = *((SimObject**)p2);
  87. Marker* m1 = dynamic_cast<Marker*>(o1);
  88. Marker* m2 = dynamic_cast<Marker*>(o2);
  89. if (m1 == NULL && m2 == NULL)
  90. return 0;
  91. else if (m1 != NULL && m2 == NULL)
  92. return 1;
  93. else if (m1 == NULL && m2 != NULL)
  94. return -1;
  95. else {
  96. // Both markers...
  97. return S32(m1->mSeqNum) - S32(m2->mSeqNum);
  98. }
  99. }
  100. ConsoleDocClass(SimPath::Path,
  101. "@brief A spline along which various objects can move along. The spline object acts like a container for Marker objects, which make\n"
  102. "up the joints, or knots, along the path. Paths can be assigned a speed, can be looping or non-looping. Each of a path's markers can be\n"
  103. "one of three primary movement types: \"normal\", \"Position Only\", or \"Kink\". \n"
  104. "@tsexample\n"
  105. "new path()\n"
  106. " {\n"
  107. " isLooping = \"1\";\n"
  108. "\n"
  109. " new Marker()\n"
  110. " {\n"
  111. " seqNum = \"0\";\n"
  112. " type = \"Normal\";\n"
  113. " msToNext = \"1000\";\n"
  114. " smoothingType = \"Spline\";\n"
  115. " position = \"-0.054708 -35.0612 234.802\";\n"
  116. " rotation = \"1 0 0 0\";\n"
  117. " };\n"
  118. "\n"
  119. " };\n"
  120. "@endtsexample\n"
  121. "@see Marker\n"
  122. "@see NetConnection::transmitPaths()\n"
  123. "@see NetConnection::clearPaths()\n"
  124. "@see Path\n"
  125. "@ingroup enviroMisc\n"
  126. );
  127. namespace SimPath
  128. {
  129. //--------------------------------------------------------------------------
  130. //-------------------------------------- Implementation
  131. //
  132. IMPLEMENT_CONOBJECT(Path);
  133. Path::Path()
  134. {
  135. mPathIndex = NoPathIndex;
  136. mIsLooping = true;
  137. mPathSpeed = 1.0f;
  138. mDataBlock = NULL;
  139. mSpawnCount = 1;
  140. mMinDelay = 0;
  141. mMaxDelay = 0;
  142. }
  143. Path::~Path()
  144. {
  145. //
  146. }
  147. //--------------------------------------------------------------------------
  148. void Path::initPersistFields()
  149. {
  150. docsURL;
  151. addField("isLooping", TypeBool, Offset(mIsLooping, Path), "If this is true, the loop is closed, otherwise it is open.\n");
  152. addField("Speed", TypeF32, Offset(mPathSpeed, Path), "Speed.\n");
  153. addProtectedField("mPathShape", TYPEID< PathShapeData >(), Offset(mDataBlock, Path),
  154. &setDataBlockProperty, &defaultProtectedGetFn,
  155. "@brief Spawned PathShape.\n\n");
  156. addField("spawnCount", TypeS32, Offset(mSpawnCount, Path), "Spawn Count.\n");
  157. addField("minDelay", TypeS32, Offset(mMinDelay, Path), "Spawn Delay (min).\n");
  158. addField("maxDelay", TypeS32, Offset(mMaxDelay, Path), "Spawn Delay (max).\n");
  159. Parent::initPersistFields();
  160. //
  161. }
  162. //--------------------------------------------------------------------------
  163. bool Path::onAdd()
  164. {
  165. if(!Parent::onAdd())
  166. return false;
  167. onAdd_callback(getId());
  168. return true;
  169. }
  170. void Path::onPostAdd()
  171. {
  172. Parent::onPostAdd();
  173. if (isServerObject())
  174. updatePath();
  175. }
  176. IMPLEMENT_CALLBACK(Path, onAdd, void, (SimObjectId ID), (ID),
  177. "Called when this ScriptGroup is added to the system.\n"
  178. "@param ID Unique object ID assigned when created (%this in script).\n"
  179. );
  180. void Path::onRemove()
  181. {
  182. //
  183. Parent::onRemove();
  184. }
  185. //--------------------------------------------------------------------------
  186. /// Sort the markers objects into sequence order
  187. void Path::sortMarkers()
  188. {
  189. dQsort(mObjectList.address(), mObjectList.size(), sizeof(SimObject*), cmpPathObject);
  190. }
  191. void Path::updatePath()
  192. {
  193. // If we need to, allocate a path index from the manager
  194. if (mPathIndex == NoPathIndex)
  195. mPathIndex = gServerPathManager->allocatePathId();
  196. sortMarkers();
  197. Vector<Point3F> positions;
  198. Vector<QuatF> rotations;
  199. Vector<U32> times;
  200. Vector<U32> smoothingTypes;
  201. for (iterator itr = begin(); itr != end(); itr++)
  202. {
  203. Marker* pMarker = dynamic_cast<Marker*>(*itr);
  204. if (pMarker != NULL)
  205. {
  206. Point3F pos;
  207. pMarker->getTransform().getColumn(3, &pos);
  208. positions.push_back(pos);
  209. QuatF rot;
  210. rot.set(pMarker->getTransform());
  211. rotations.push_back(rot);
  212. times.push_back(pMarker->mMSToNext);
  213. smoothingTypes.push_back(pMarker->mSmoothingType);
  214. }
  215. }
  216. gServerPathManager->updatePath(mPathIndex, positions, rotations, times, smoothingTypes, mIsLooping);
  217. }
  218. void Path::setTransform(const MatrixF& mat)
  219. {
  220. if (isServerObject())
  221. {
  222. MatrixF newXform = mat;
  223. MatrixF oldXform = getTransform();
  224. oldXform.affineInverse();
  225. MatrixF offset;
  226. offset.mul(newXform, oldXform);
  227. // Update all child transforms
  228. for (SimSetIterator itr(this); *itr; ++itr)
  229. {
  230. SceneObject* child = dynamic_cast<SceneObject*>(*itr);
  231. if (child)
  232. {
  233. MatrixF childMat;
  234. //add the "offset" caused by the parents change, and add it to it's own
  235. // This is needed by objects that update their own render transform thru interpolate tick
  236. // Mostly for stationary objects.
  237. childMat.mul(offset, child->getTransform());
  238. child->setTransform(childMat);
  239. PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
  240. if (childPS)
  241. childPS->storeRestorePos();
  242. }
  243. }
  244. updatePath();
  245. }
  246. Parent::setTransform(mat);
  247. }
  248. void Path::addObject(SimObject* obj)
  249. {
  250. Parent::addObject(obj);
  251. if (mPathIndex != NoPathIndex) {
  252. // If we're already finished, and this object is a marker, then we need to
  253. // update our path information...
  254. if (dynamic_cast<Marker*>(obj) != NULL)
  255. updatePath();
  256. }
  257. }
  258. void Path::removeObject(SimObject* obj)
  259. {
  260. bool recalc = dynamic_cast<Marker*>(obj) != NULL;
  261. Parent::removeObject(obj);
  262. if (mPathIndex != NoPathIndex && recalc == true)
  263. updatePath();
  264. }
  265. DefineEngineMethod( Path, getPathId, S32, (),,
  266. "@brief Returns the PathID (not the object ID) of this path.\n\n"
  267. "@return PathID (not the object ID) of this path.\n"
  268. "@tsexample\n"
  269. "// Acquire the PathID of this path object.\n"
  270. "%pathID = %thisPath.getPathId();\n\n"
  271. "@endtsexample\n\n"
  272. )
  273. {
  274. Path *path = static_cast<Path *>(object);
  275. return path->getPathIndex();
  276. }
  277. } // Namespace
  278. //--------------------------------------------------------------------------
  279. //--------------------------------------------------------------------------
  280. GFXStateBlockRef Marker::smStateBlock;
  281. GFXVertexBufferHandle<GFXVertexPCT> Marker::smVertexBuffer;
  282. GFXPrimitiveBufferHandle Marker::smPrimitiveBuffer;
  283. static Point3F wedgePoints[4] = {
  284. Point3F(-1, -1, 0),
  285. Point3F( 0, 1, 0),
  286. Point3F( 1, -1, 0),
  287. Point3F( 0,-.75, .5),
  288. };
  289. void Marker::initGFXResources()
  290. {
  291. if(smVertexBuffer != NULL)
  292. return;
  293. GFXStateBlockDesc d;
  294. d.cullDefined = true;
  295. d.cullMode = GFXCullNone;
  296. smStateBlock = GFX->createStateBlock(d);
  297. smVertexBuffer.set(GFX, 4, GFXBufferTypeStatic);
  298. GFXVertexPCT* verts = smVertexBuffer.lock();
  299. verts[0].point = wedgePoints[0] * 1.25f;
  300. verts[1].point = wedgePoints[1] * 1.25f;
  301. verts[2].point = wedgePoints[2] * 1.25f;
  302. verts[3].point = wedgePoints[3] * 1.25f;
  303. verts[1].color = GFXVertexColor(ColorI(255, 0, 0, 255));
  304. verts[0].color = verts[2].color = verts[3].color = GFXVertexColor(ColorI(0, 0, 255, 255));
  305. smVertexBuffer.unlock();
  306. smPrimitiveBuffer.set(GFX, 24, 12, GFXBufferTypeStatic);
  307. U16* prims;
  308. smPrimitiveBuffer.lock(&prims);
  309. prims[0] = 0;
  310. prims[1] = 3;
  311. prims[2] = 3;
  312. prims[3] = 1;
  313. prims[4] = 1;
  314. prims[5] = 0;
  315. prims[6] = 3;
  316. prims[7] = 1;
  317. prims[8] = 1;
  318. prims[9] = 2;
  319. prims[10] = 2;
  320. prims[11] = 3;
  321. prims[12] = 0;
  322. prims[13] = 3;
  323. prims[14] = 3;
  324. prims[15] = 2;
  325. prims[16] = 2;
  326. prims[17] = 0;
  327. prims[18] = 0;
  328. prims[19] = 2;
  329. prims[20] = 2;
  330. prims[21] = 1;
  331. prims[22] = 1;
  332. prims[23] = 0;
  333. smPrimitiveBuffer.unlock();
  334. }
  335. IMPLEMENT_CO_NETOBJECT_V1(Marker);
  336. ConsoleDocClass( Marker,
  337. "@brief A single joint, or knot, along a path. Should be stored inside a Path container object. A path markers can be\n"
  338. "one of three primary movement types: \"normal\", \"Position Only\", or \"Kink\". \n"
  339. "@tsexample\n"
  340. "new path()\n"
  341. " {\n"
  342. " isLooping = \"1\";\n"
  343. "\n"
  344. " new Marker()\n"
  345. " {\n"
  346. " seqNum = \"0\";\n"
  347. " type = \"Normal\";\n"
  348. " msToNext = \"1000\";\n"
  349. " smoothingType = \"Spline\";\n"
  350. " position = \"-0.054708 -35.0612 234.802\";\n"
  351. " rotation = \"1 0 0 0\";\n"
  352. " };\n"
  353. "\n"
  354. " };\n"
  355. "@endtsexample\n"
  356. "@see Path\n"
  357. "@ingroup enviroMisc\n"
  358. );
  359. Marker::Marker()
  360. {
  361. // Not ghostable unless we're editing...
  362. mNetFlags.clear(Ghostable);
  363. mTypeMask |= MarkerObjectType;
  364. mHitCommand = String::EmptyString;
  365. mSeqNum = 0;
  366. mMSToNext = 1000;
  367. mSmoothingType = SmoothingTypeSpline;
  368. mKnotType = KnotTypeNormal;
  369. }
  370. Marker::~Marker()
  371. {
  372. //
  373. }
  374. //--------------------------------------------------------------------------
  375. ImplementEnumType( MarkerSmoothingType,
  376. "The type of smoothing this marker will have for pathed objects.\n"
  377. "@ingroup enviroMisc\n\n")
  378. { Marker::SmoothingTypeSpline , "Spline", "Marker will cause the movements of the pathed object to be smooth.\n" },
  379. { Marker::SmoothingTypeLinear , "Linear", "Marker will have no smoothing effect.\n" },
  380. //{ Marker::SmoothingTypeAccelerate , "Accelerate" },
  381. EndImplementEnumType;
  382. ImplementEnumType( MarkerKnotType,
  383. "The type of knot that this marker will be.\n"
  384. "@ingroup enviroMisc\n\n")
  385. { Marker::KnotTypeNormal , "Normal", "Knot will have a smooth camera translation/rotation effect.\n" },
  386. { Marker::KnotTypePositionOnly, "Position Only", "Will do the same for translations, leaving rotation un-touched.\n" },
  387. { Marker::KnotTypeKink, "Kink", "The rotation will take effect immediately for an abrupt rotation change.\n" },
  388. EndImplementEnumType;
  389. void Marker::initPersistFields()
  390. {
  391. docsURL;
  392. addGroup( "Misc" );
  393. addField("seqNum", TypeS32, Offset(mSeqNum, Marker), "Marker position in sequence of markers on this path.\n");
  394. addField("hitCommand", TypeCommand, Offset(mHitCommand, Marker), "The command to execute when a path follower reaches this marker.");
  395. addField("type", TYPEID< KnotType >(), Offset(mKnotType, Marker), "Type of this marker/knot. A \"normal\" knot will have a smooth camera translation/rotation effect.\n\"Position Only\" will do the same for translations, leaving rotation un-touched.\nLastly, a \"Kink\" means the rotation will take effect immediately for an abrupt rotation change.\n");
  396. addField("msToNext", TypeS32, Offset(mMSToNext, Marker), "Milliseconds to next marker in sequence.\n");
  397. addField("smoothingType", TYPEID< SmoothingType >(), Offset(mSmoothingType, Marker), "Path smoothing at this marker/knot. \"Linear\" means no smoothing, while \"Spline\" means to smooth.\n");
  398. endGroup("Misc");
  399. Parent::initPersistFields();
  400. }
  401. //--------------------------------------------------------------------------
  402. bool Marker::onAdd()
  403. {
  404. if(!Parent::onAdd())
  405. return false;
  406. mObjBox = Box3F(Point3F(-1.25, -1.25, -1.25), Point3F(1.25, 1.25, 1.25));
  407. resetWorldBox();
  408. if(gEditingMission)
  409. onEditorEnable();
  410. return true;
  411. }
  412. void Marker::onRemove()
  413. {
  414. if(gEditingMission)
  415. onEditorDisable();
  416. Parent::onRemove();
  417. smVertexBuffer = NULL;
  418. smPrimitiveBuffer = NULL;
  419. }
  420. void Marker::onGroupAdd()
  421. {
  422. mSeqNum = getGroup()->size() - 1;
  423. }
  424. /// Enable scoping so we can see this thing on the client.
  425. void Marker::onEditorEnable()
  426. {
  427. mNetFlags.set(Ghostable);
  428. setScopeAlways();
  429. addToScene();
  430. }
  431. /// Disable scoping so we can see this thing on the client
  432. void Marker::onEditorDisable()
  433. {
  434. removeFromScene();
  435. mNetFlags.clear(Ghostable);
  436. clearScopeAlways();
  437. }
  438. /// Tell our parent that this Path has been modified
  439. void Marker::inspectPostApply()
  440. {
  441. SimPath::Path *path = dynamic_cast<SimPath::Path*>(getGroup());
  442. if (path)
  443. path->updatePath();
  444. }
  445. //--------------------------------------------------------------------------
  446. void Marker::prepRenderImage( SceneRenderState* state )
  447. {
  448. // This should be sufficient for most objects that don't manage zones, and
  449. // don't need to return a specialized RenderImage...
  450. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  451. ri->renderDelegate.bind( this, &Marker::renderObject );
  452. ri->type = RenderPassManager::RIT_Editor;
  453. state->getRenderPass()->addInst(ri);
  454. }
  455. void Marker::renderObject(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* overrideMat)
  456. {
  457. initGFXResources();
  458. for(U32 i = 0; i < GFX->getNumSamplers(); i++)
  459. GFX->setTexture(i, NULL);
  460. GFXTransformSaver saver;
  461. MatrixF mat = getRenderTransform();
  462. mat.scale(mObjScale);
  463. GFX->multWorld(mat);
  464. GFX->setStateBlock(smStateBlock);
  465. GFX->setVertexBuffer(smVertexBuffer);
  466. GFX->setPrimitiveBuffer(smPrimitiveBuffer);
  467. GFX->setupGenericShaders();
  468. GFX->drawIndexedPrimitive(GFXLineList, 0, 0, 4, 0, 12);
  469. }
  470. //--------------------------------------------------------------------------
  471. U32 Marker::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
  472. {
  473. U32 retMask = Parent::packUpdate(con, mask, stream);
  474. // Note that we don't really care about efficiency here, since this is an
  475. // edit-only ghost...
  476. stream->writeAffineTransform(mObjToWorld);
  477. return retMask;
  478. }
  479. void Marker::unpackUpdate(NetConnection* con, BitStream* stream)
  480. {
  481. Parent::unpackUpdate(con, stream);
  482. // Transform
  483. MatrixF otow;
  484. stream->readAffineTransform(&otow);
  485. setTransform(otow);
  486. }