2
0

simPath.cpp 17 KB

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