decalRoad.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  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 "environment/decalRoad.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/engineAPI.h"
  26. #include "util/catmullRom.h"
  27. #include "math/util/quadTransforms.h"
  28. #include "scene/sceneRenderState.h"
  29. #include "scene/sceneManager.h"
  30. #include "core/stream/bitStream.h"
  31. #include "gfx/gfxDrawUtil.h"
  32. #include "gfx/gfxTransformSaver.h"
  33. #include "math/mathIO.h"
  34. #include "math/mathUtils.h"
  35. #include "terrain/terrData.h"
  36. #include "materials/materialDefinition.h"
  37. #include "materials/materialManager.h"
  38. #include "materials/baseMatInstance.h"
  39. #include "environment/nodeListManager.h"
  40. #include "lighting/lightQuery.h"
  41. #include "console/typeValidators.h"
  42. extern F32 gDecalBias;
  43. extern bool gEditingMission;
  44. //-----------------------------------------------------------------------------
  45. // DecalRoadNodeList Struct
  46. //-----------------------------------------------------------------------------
  47. struct DecalRoadNodeList : public NodeListManager::NodeList
  48. {
  49. Vector<Point3F> mPositions;
  50. Vector<F32> mWidths;
  51. DecalRoadNodeList() { }
  52. virtual ~DecalRoadNodeList() { }
  53. };
  54. //-----------------------------------------------------------------------------
  55. // DecalRoadNodeEvent Class
  56. //-----------------------------------------------------------------------------
  57. class DecalRoadNodeEvent : public NodeListEvent
  58. {
  59. typedef NodeListEvent Parent;
  60. public:
  61. Vector<Point3F> mPositions;
  62. Vector<F32> mWidths;
  63. public:
  64. DecalRoadNodeEvent() { mNodeList = NULL; }
  65. virtual ~DecalRoadNodeEvent() { }
  66. void pack(NetConnection*, BitStream*) override;
  67. void unpack(NetConnection*, BitStream*) override;
  68. void copyIntoList(NodeListManager::NodeList* copyInto) override;
  69. void padListToSize() override;
  70. DECLARE_CONOBJECT(DecalRoadNodeEvent);
  71. };
  72. void DecalRoadNodeEvent::pack(NetConnection* conn, BitStream* stream)
  73. {
  74. Parent::pack( conn, stream );
  75. stream->writeInt( mPositions.size(), 16 );
  76. for (U32 i=0; i<mPositions.size(); ++i)
  77. {
  78. mathWrite( *stream, mPositions[i] );
  79. stream->write( mWidths[i] );
  80. }
  81. }
  82. void DecalRoadNodeEvent::unpack(NetConnection* conn, BitStream* stream)
  83. {
  84. mNodeList = new DecalRoadNodeList();
  85. Parent::unpack( conn, stream );
  86. U32 count = stream->readInt( 16 );
  87. Point3F pos;
  88. F32 width;
  89. DecalRoadNodeList* list = static_cast<DecalRoadNodeList*>(mNodeList);
  90. for (U32 i=0; i<count; ++i)
  91. {
  92. mathRead( *stream, &pos );
  93. stream->read( &width );
  94. list->mPositions.push_back( pos );
  95. list->mWidths.push_back( width );
  96. }
  97. list->mTotalValidNodes = count;
  98. // Do we have a complete list?
  99. if (list->mPositions.size() >= mTotalNodes)
  100. list->mListComplete = true;
  101. }
  102. void DecalRoadNodeEvent::copyIntoList(NodeListManager::NodeList* copyInto)
  103. {
  104. DecalRoadNodeList* prevList = static_cast<DecalRoadNodeList*>(copyInto);
  105. DecalRoadNodeList* list = static_cast<DecalRoadNodeList*>(mNodeList);
  106. // Merge our list with the old list.
  107. for (U32 i=mLocalListStart, index=0; i<mLocalListStart+list->mPositions.size(); ++i, ++index)
  108. {
  109. prevList->mPositions[i] = list->mPositions[index];
  110. prevList->mWidths[i] = list->mWidths[index];
  111. }
  112. }
  113. void DecalRoadNodeEvent::padListToSize()
  114. {
  115. DecalRoadNodeList* list = static_cast<DecalRoadNodeList*>(mNodeList);
  116. U32 totalValidNodes = list->mTotalValidNodes;
  117. // Pad our list front?
  118. if (mLocalListStart)
  119. {
  120. DecalRoadNodeList* newlist = new DecalRoadNodeList();
  121. newlist->mPositions.increment(mLocalListStart);
  122. newlist->mWidths.increment(mLocalListStart);
  123. newlist->mPositions.merge(list->mPositions);
  124. newlist->mWidths.merge(list->mWidths);
  125. delete list;
  126. mNodeList = list = newlist;
  127. }
  128. // Pad our list end?
  129. if (list->mPositions.size() < mTotalNodes)
  130. {
  131. U32 delta = mTotalNodes - list->mPositions.size();
  132. list->mPositions.increment(delta);
  133. list->mWidths.increment(delta);
  134. }
  135. list->mTotalValidNodes = totalValidNodes;
  136. }
  137. IMPLEMENT_CO_NETEVENT_V1(DecalRoadNodeEvent);
  138. ConsoleDocClass( DecalRoadNodeEvent,
  139. "@brief Sends messages to the Decal Road Editor\n\n"
  140. "Editor use only.\n\n"
  141. "@internal"
  142. );
  143. //-----------------------------------------------------------------------------
  144. // DecalRoadNodeListNotify Class
  145. //-----------------------------------------------------------------------------
  146. class DecalRoadNodeListNotify : public NodeListNotify
  147. {
  148. typedef NodeListNotify Parent;
  149. protected:
  150. SimObjectPtr<DecalRoad> mRoad;
  151. public:
  152. DecalRoadNodeListNotify( DecalRoad* road, U32 listId ) { mRoad = road; mListId = listId; }
  153. virtual ~DecalRoadNodeListNotify() { mRoad = NULL; }
  154. void sendNotification( NodeListManager::NodeList* list ) override;
  155. };
  156. void DecalRoadNodeListNotify::sendNotification( NodeListManager::NodeList* list )
  157. {
  158. if (mRoad.isValid())
  159. {
  160. // Build the road's nodes
  161. DecalRoadNodeList* roadList = dynamic_cast<DecalRoadNodeList*>( list );
  162. if (roadList)
  163. mRoad->buildNodesFromList( roadList );
  164. }
  165. }
  166. //-----------------------------------------------------------------------------
  167. // DecalRoadUpdateEvent Class
  168. //-----------------------------------------------------------------------------
  169. void DecalRoadUpdateEvent::process( SimObject *object )
  170. {
  171. DecalRoad *road = dynamic_cast<DecalRoad*>( object );
  172. AssertFatal( road, "DecalRoadRegenEvent::process - wasn't a DecalRoad" );
  173. // Inform clients to perform the update.
  174. road->setMaskBits( mMask );
  175. if ( !road->isProperlyAdded() )
  176. return;
  177. // Perform the server side update.
  178. if ( mMask & DecalRoad::TerrainChangedMask )
  179. {
  180. road->_generateEdges();
  181. }
  182. if ( mMask & DecalRoad::GenEdgesMask )
  183. {
  184. // Server has already done this.
  185. //road->_generateEdges();
  186. }
  187. if ( mMask & DecalRoad::ReClipMask )
  188. {
  189. // Server does not need to capture verts.
  190. road->_captureVerts();
  191. }
  192. }
  193. //------------------------------------------------------------------------------
  194. // Class: DecalRoad
  195. //------------------------------------------------------------------------------
  196. ConsoleDocClass( DecalRoad,
  197. "@brief A strip shaped decal defined by spine nodes which clips against Terrain objects.\n\n"
  198. "DecalRoad is for representing a road or path ( or other inventive things ) across "
  199. "a TerrainBlock. It renders as a decal and is therefore only for features that do "
  200. "not need geometric depth.\n\n"
  201. "The Material assigned to DecalRoad should tile vertically.\n\n"
  202. "@ingroup Terrain"
  203. );
  204. // Init Statics
  205. // Static ConsoleVars for toggling debug rendering
  206. bool DecalRoad::smEditorOpen = false;
  207. bool DecalRoad::smWireframe = true;
  208. bool DecalRoad::smShowBatches = false;
  209. bool DecalRoad::smDiscardAll = false;
  210. bool DecalRoad::smShowSpline = true;
  211. bool DecalRoad::smShowRoad = true;
  212. S32 DecalRoad::smUpdateDelay = 500;
  213. SimObjectPtr<SimSet> DecalRoad::smServerDecalRoadSet = NULL;
  214. // Constructors
  215. DecalRoad::DecalRoad()
  216. : mBreakAngle( 3.0f ),
  217. mSegmentsPerBatch( 10 ),
  218. mTextureLength( 5.0f ),
  219. mRenderPriority( 10 ),
  220. mLoadRenderData( true ),
  221. mTriangleCount(0),
  222. mVertCount(0),
  223. mUpdateEventId( -1 ),
  224. mLastEvent(NULL),
  225. mTerrainUpdateRect( Box3F::Invalid )
  226. {
  227. // Setup NetObject.
  228. mTypeMask |= StaticObjectType | StaticShapeObjectType;
  229. mNetFlags.set(Ghostable);
  230. INIT_ASSET(Material);
  231. mMaterialInst = nullptr;
  232. }
  233. DecalRoad::~DecalRoad()
  234. {
  235. }
  236. IMPLEMENT_CO_NETOBJECT_V1(DecalRoad);
  237. // ConsoleObject
  238. FRangeValidator drTextureLengthV(0.1f,FLT_MAX);
  239. void DecalRoad::initPersistFields()
  240. {
  241. docsURL;
  242. addGroup( "DecalRoad" );
  243. INITPERSISTFIELD_MATERIALASSET(Material, DecalRoad, "Material used for rendering.");
  244. addProtectedFieldV("textureLength", TypeRangedF32, Offset(mTextureLength, DecalRoad), &DecalRoad::ptSetTextureLength, &defaultProtectedGetFn, &drTextureLengthV,
  245. "The length in meters of textures mapped to the DecalRoad" );
  246. addProtectedFieldV( "breakAngle", TypeRangedF32, Offset( mBreakAngle, DecalRoad ), &DecalRoad::ptSetBreakAngle, &defaultProtectedGetFn, &CommonValidators::PosDegreeRange,
  247. "Angle in degrees - DecalRoad will subdivided the spline if its curve is greater than this threshold." );
  248. addField( "renderPriority", TypeS16, Offset( mRenderPriority, DecalRoad ),
  249. "DecalRoad(s) are rendered in descending renderPriority order." );
  250. endGroup( "DecalRoad" );
  251. addGroup( "Internal" );
  252. addProtectedField( "node", TypeString, 0, &addNodeFromField, &emptyStringProtectedGetFn,
  253. "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors | AbstractClassRep::FIELD_SpecialtyArrayField);
  254. endGroup( "Internal" );
  255. Parent::initPersistFields();
  256. }
  257. void DecalRoad::consoleInit()
  258. {
  259. Parent::consoleInit();
  260. // Vars for debug rendering while the RoadEditor is open, only used if smEditorOpen is true.
  261. Con::addVariable( "$DecalRoad::EditorOpen", TypeBool, &DecalRoad::smEditorOpen, "For use by the Decal Editor.\n\n"
  262. "@ingroup Editors\n" );
  263. Con::addVariable( "$DecalRoad::wireframe", TypeBool, &DecalRoad::smWireframe, "For use by the Decal Editor.\n\n"
  264. "@ingroup Editors\n" );
  265. Con::addVariable( "$DecalRoad::showBatches", TypeBool, &DecalRoad::smShowBatches, "For use by the Decal Editor.\n\n"
  266. "@ingroup Editors\n" );
  267. Con::addVariable( "$DecalRoad::discardAll", TypeBool, &DecalRoad::smDiscardAll, "For use by the Decal Editor.\n\n"
  268. "@ingroup Editors\n");
  269. Con::addVariable( "$DecalRoad::showSpline", TypeBool, &DecalRoad::smShowSpline, "For use by the Decal Editor.\n\n"
  270. "@ingroup Editors\n" );
  271. Con::addVariable( "$DecalRoad::showRoad", TypeBool, &DecalRoad::smShowRoad, "For use by the Decal Editor.\n\n"
  272. "@ingroup Editors\n" );
  273. Con::addVariable( "$DecalRoad::updateDelay", TypeS32, &DecalRoad::smUpdateDelay, "For use by the Decal Editor.\n\n"
  274. "@ingroup Editors\n" );
  275. }
  276. // SimObject
  277. bool DecalRoad::onAdd()
  278. {
  279. if ( !Parent::onAdd() )
  280. return false;
  281. // DecalRoad is at position zero when created,
  282. // it sets its own position to the first node inside
  283. // _generateEdges but until it has at least one node
  284. // it will be at 0,0,0.
  285. MatrixF mat(true);
  286. Parent::setTransform( mat );
  287. // The client side calculates bounds based on clipped geometry. It would
  288. // be wasteful for the server to do this so the server uses global bounds.
  289. if ( isServerObject() )
  290. {
  291. setGlobalBounds();
  292. resetWorldBox();
  293. }
  294. // Set the Render Transform.
  295. setRenderTransform(mObjToWorld);
  296. // Add to Scene.
  297. addToScene();
  298. if ( isServerObject() )
  299. getServerSet()->addObject( this );
  300. //
  301. TerrainBlock::smUpdateSignal.notify( this, &DecalRoad::_onTerrainChanged );
  302. //
  303. if ( isClientObject() )
  304. _initMaterial();
  305. _generateEdges();
  306. _captureVerts();
  307. return true;
  308. }
  309. void DecalRoad::onRemove()
  310. {
  311. SAFE_DELETE( mMaterialInst );
  312. TerrainBlock::smUpdateSignal.remove( this, &DecalRoad::_onTerrainChanged );
  313. removeFromScene();
  314. Parent::onRemove();
  315. }
  316. void DecalRoad::inspectPostApply()
  317. {
  318. Parent::inspectPostApply();
  319. setMaskBits( DecalRoadMask );
  320. }
  321. void DecalRoad::onStaticModified( const char* slotName, const char*newValue )
  322. {
  323. Parent::onStaticModified( slotName, newValue );
  324. /*
  325. if ( isProperlyAdded() &&
  326. dStricmp( slotName, "material" ) == 0 )
  327. {
  328. setMaskBits( DecalRoadMask );
  329. }
  330. */
  331. if ( dStricmp( slotName, "renderPriority" ) == 0 )
  332. {
  333. mRenderPriority = getMax((S16)dAtoi(newValue), (S16)1 );
  334. }
  335. }
  336. SimSet* DecalRoad::getServerSet()
  337. {
  338. if ( !smServerDecalRoadSet )
  339. {
  340. smServerDecalRoadSet = new SimSet();
  341. smServerDecalRoadSet->registerObject( "ServerDecalRoadSet" );
  342. Sim::getRootGroup()->addObject( smServerDecalRoadSet );
  343. }
  344. return smServerDecalRoadSet;
  345. }
  346. void DecalRoad::writeFields( Stream &stream, U32 tabStop )
  347. {
  348. Parent::writeFields( stream, tabStop );
  349. // Now write all nodes
  350. stream.write(2, "\r\n");
  351. for ( U32 i = 0; i < mNodes.size(); i++ )
  352. {
  353. const RoadNode &node = mNodes[i];
  354. stream.writeTabs(tabStop);
  355. char buffer[1024];
  356. dMemset( buffer, 0, 1024 );
  357. dSprintf( buffer, 1024, "Node = \"%f %f %f %f\";", node.point.x, node.point.y, node.point.z, node.width );
  358. stream.writeLine( (const U8*)buffer );
  359. }
  360. }
  361. bool DecalRoad::writeField( StringTableEntry fieldname, const char *value )
  362. {
  363. if ( fieldname == StringTable->insert("node") )
  364. return false;
  365. return Parent::writeField( fieldname, value );
  366. }
  367. U32 DecalRoad::getSpecialFieldSize(StringTableEntry fieldName)
  368. {
  369. if (fieldName == StringTable->insert("node"))
  370. {
  371. return mNodes.size();
  372. }
  373. return 0;
  374. }
  375. const char* DecalRoad::getSpecialFieldOut(StringTableEntry fieldName, const U32& index)
  376. {
  377. if (fieldName == StringTable->insert("node"))
  378. {
  379. if (index >= mNodes.size())
  380. return NULL;
  381. const RoadNode& node = mNodes[index];
  382. char buffer[1024];
  383. dMemset(buffer, 0, 1024);
  384. dSprintf(buffer, 1024, "node = \"%f %f %f %f\";", node.point.x, node.point.y, node.point.z, node.width);
  385. return StringTable->insert(buffer);
  386. }
  387. return NULL;
  388. }
  389. void DecalRoad::onEditorEnable()
  390. {
  391. }
  392. void DecalRoad::onEditorDisable()
  393. {
  394. }
  395. // NetObject
  396. U32 DecalRoad::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
  397. {
  398. // Pack Parent.
  399. U32 retMask = Parent::packUpdate(con, mask, stream);
  400. if ( stream->writeFlag( mask & DecalRoadMask ) )
  401. {
  402. // Write Texture Name.
  403. PACK_ASSET(con, Material);
  404. stream->write( mBreakAngle );
  405. stream->write( mSegmentsPerBatch );
  406. stream->write( mTextureLength );
  407. stream->write( mRenderPriority );
  408. }
  409. if ( stream->writeFlag( mask & NodeMask ) )
  410. {
  411. //stream->writeInt( mNodes.size(), 16 );
  412. //for ( U32 i = 0; i < mNodes.size(); i++ )
  413. //{
  414. // mathWrite( *stream, mNodes[i].point );
  415. // stream->write( mNodes[i].width );
  416. //}
  417. const U32 nodeByteSize = 16; // Based on sending all of a node's parameters
  418. // Test if we can fit all of our nodes within the current stream.
  419. // We make sure we leave 100 bytes still free in the stream for whatever
  420. // may follow us.
  421. S32 allowedBytes = stream->getWriteByteSize() - 100;
  422. if ( stream->writeFlag( (nodeByteSize * mNodes.size()) < allowedBytes ) )
  423. {
  424. // All nodes should fit, so send them out now.
  425. stream->writeInt( mNodes.size(), 16 );
  426. for ( U32 i = 0; i < mNodes.size(); i++ )
  427. {
  428. mathWrite( *stream, mNodes[i].point );
  429. stream->write( mNodes[i].width );
  430. }
  431. }
  432. else
  433. {
  434. // There isn't enough space left in the stream for all of the
  435. // nodes. Batch them up into NetEvents.
  436. U32 id = gServerNodeListManager->nextListId();
  437. U32 count = 0;
  438. U32 index = 0;
  439. while (count < mNodes.size())
  440. {
  441. count += NodeListManager::smMaximumNodesPerEvent;
  442. if (count > mNodes.size())
  443. {
  444. count = mNodes.size();
  445. }
  446. DecalRoadNodeEvent* event = new DecalRoadNodeEvent();
  447. event->mId = id;
  448. event->mTotalNodes = mNodes.size();
  449. event->mLocalListStart = index;
  450. for (; index<count; ++index)
  451. {
  452. event->mPositions.push_back( mNodes[index].point );
  453. event->mWidths.push_back( mNodes[index].width );
  454. }
  455. con->postNetEvent( event );
  456. }
  457. stream->write( id );
  458. }
  459. }
  460. stream->writeFlag( mask & GenEdgesMask );
  461. stream->writeFlag( mask & ReClipMask );
  462. stream->writeFlag( mask & TerrainChangedMask );
  463. // Were done ...
  464. return retMask;
  465. }
  466. void DecalRoad::unpackUpdate( NetConnection *con, BitStream *stream )
  467. {
  468. // Unpack Parent.
  469. Parent::unpackUpdate( con, stream );
  470. // DecalRoadMask
  471. if ( stream->readFlag() )
  472. {
  473. UNPACK_ASSET(con, Material);
  474. if (isProperlyAdded())
  475. _initMaterial();
  476. stream->read( &mBreakAngle );
  477. stream->read( &mSegmentsPerBatch );
  478. stream->read( &mTextureLength );
  479. stream->read( &mRenderPriority );
  480. }
  481. // NodeMask
  482. if ( stream->readFlag() )
  483. {
  484. //U32 count = stream->readInt( 16 );
  485. //mNodes.clear();
  486. //Point3F pos;
  487. //F32 width;
  488. //for ( U32 i = 0; i < count; i++ )
  489. //{
  490. // mathRead( *stream, &pos );
  491. // stream->read( &width );
  492. // _addNode( pos, width );
  493. //}
  494. if (stream->readFlag())
  495. {
  496. // Nodes have been passed in this update
  497. U32 count = stream->readInt( 16 );
  498. mNodes.clear();
  499. Point3F pos;
  500. F32 width;
  501. for ( U32 i = 0; i < count; i++ )
  502. {
  503. mathRead( *stream, &pos );
  504. stream->read( &width );
  505. _addNode( pos, width );
  506. }
  507. }
  508. else
  509. {
  510. // Nodes will arrive as events
  511. U32 id;
  512. stream->read( &id );
  513. // Check if the road's nodes made it here before we did.
  514. NodeListManager::NodeList* list = NULL;
  515. if ( gClientNodeListManager->findListById( id, &list, true) )
  516. {
  517. // Work with the completed list
  518. DecalRoadNodeList* roadList = dynamic_cast<DecalRoadNodeList*>( list );
  519. if (roadList)
  520. buildNodesFromList( roadList );
  521. delete list;
  522. }
  523. else
  524. {
  525. // Nodes have not yet arrived, so register our interest in the list
  526. DecalRoadNodeListNotify* notify = new DecalRoadNodeListNotify( this, id );
  527. gClientNodeListManager->registerNotification( notify );
  528. }
  529. }
  530. }
  531. // GenEdgesMask
  532. if ( stream->readFlag() && isProperlyAdded() )
  533. _generateEdges();
  534. // ReClipMask
  535. if ( stream->readFlag() && isProperlyAdded() )
  536. _captureVerts();
  537. // TerrainChangedMask
  538. if ( stream->readFlag() )
  539. {
  540. if ( isProperlyAdded() )
  541. {
  542. if ( mTerrainUpdateRect.isOverlapped( getWorldBox() ) )
  543. {
  544. _generateEdges();
  545. _captureVerts();
  546. // Clear out the mTerrainUpdateRect since we have updated its
  547. // region and we now need to store future terrain changes
  548. // in it.
  549. mTerrainUpdateRect = Box3F::Invalid;
  550. }
  551. }
  552. }
  553. }
  554. void DecalRoad::prepRenderImage( SceneRenderState* state )
  555. {
  556. PROFILE_SCOPE( DecalRoad_prepRenderImage );
  557. if ( mNodes.size() <= 1 ||
  558. mBatches.size() == 0 ||
  559. !mMaterialInst ||
  560. state->isShadowPass() )
  561. return;
  562. // If we don't have a material instance after the override then
  563. // we can skip rendering all together.
  564. BaseMatInstance *matInst = state->getOverrideMaterial(mMaterialInst);
  565. if ( !matInst )
  566. return;
  567. RenderPassManager *renderPass = state->getRenderPass();
  568. // Debug RenderInstance
  569. // Only when editor is open.
  570. if ( smEditorOpen )
  571. {
  572. ObjectRenderInst *ri = renderPass->allocInst<ObjectRenderInst>();
  573. ri->type = RenderPassManager::RIT_Editor;
  574. ri->renderDelegate.bind( this, &DecalRoad::_debugRender );
  575. state->getRenderPass()->addInst( ri );
  576. }
  577. // Normal Road RenderInstance
  578. // Always rendered when the editor is not open
  579. // otherwise obey the smShowRoad flag
  580. if ( !smShowRoad && smEditorOpen )
  581. return;
  582. const Frustum &frustum = state->getCameraFrustum();
  583. MeshRenderInst coreRI;
  584. coreRI.clear();
  585. coreRI.objectToWorld = &MatrixF::Identity;
  586. coreRI.worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
  587. MatrixF *tempMat = renderPass->allocUniqueXform( MatrixF( true ) );
  588. MathUtils::getZBiasProjectionMatrix( gDecalBias, frustum, tempMat );
  589. coreRI.projection = tempMat;
  590. coreRI.type = RenderPassManager::RIT_DecalRoad;
  591. coreRI.vertBuff = &mVB;
  592. coreRI.primBuff = &mPB;
  593. coreRI.matInst = matInst;
  594. // Make it the sort distance the max distance so that
  595. // it renders after all the other opaque geometry in
  596. // the deferred bin.
  597. coreRI.sortDistSq = F32_MAX;
  598. // If we need lights then set them up.
  599. if ( matInst->isForwardLit() && !coreRI.lights[0])
  600. {
  601. LightQuery query;
  602. query.init( getWorldSphere() );
  603. query.getLights( coreRI.lights, 8 );
  604. }
  605. U32 startBatchIdx = -1;
  606. U32 endBatchIdx = 0;
  607. for ( U32 i = 0; i < mBatches.size(); i++ )
  608. {
  609. const RoadBatch &batch = mBatches[i];
  610. const bool isVisible = !frustum.isCulled( batch.bounds );
  611. if ( isVisible )
  612. {
  613. // If this is the start of a set of batches.
  614. if ( startBatchIdx == -1 )
  615. endBatchIdx = startBatchIdx = i;
  616. // Else we're extending the end batch index.
  617. else
  618. ++endBatchIdx;
  619. // If this isn't the last batch then continue.
  620. if ( i < mBatches.size()-1 )
  621. continue;
  622. }
  623. // We we still don't have a start batch, so skip.
  624. if ( startBatchIdx == -1 )
  625. continue;
  626. // Render this set of batches.
  627. const RoadBatch &startBatch = mBatches[startBatchIdx];
  628. const RoadBatch &endBatch = mBatches[endBatchIdx];
  629. U32 startVert = startBatch.startVert;
  630. U32 startIdx = startBatch.startIndex;
  631. U32 vertCount = endBatch.endVert - startVert;
  632. U32 idxCount = ( endBatch.endIndex - startIdx ) + 1;
  633. U32 triangleCount = idxCount / 3;
  634. AssertFatal( startVert + vertCount <= mVertCount, "DecalRoad, bad draw call!" );
  635. AssertFatal( startIdx + triangleCount < mTriangleCount * 3, "DecalRoad, bad draw call!" );
  636. MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
  637. *ri = coreRI;
  638. ri->matInst = matInst;
  639. ri->prim = renderPass->allocPrim();
  640. ri->prim->type = GFXTriangleList;
  641. ri->prim->minIndex = 0;
  642. ri->prim->startIndex = startIdx;
  643. ri->prim->numPrimitives = triangleCount;
  644. ri->prim->startVertex = 0;
  645. ri->prim->numVertices = endBatch.endVert + 1;
  646. ri->translucentSort = !matInst->getMaterial()->isTranslucent();
  647. // For sorting we first sort by render priority
  648. // and then by objectId.
  649. //
  650. // Since a road can submit more than one render instance, we want all
  651. // draw calls for a single road to occur consecutively, since they
  652. // could use the same vertex buffer.
  653. ri->defaultKey = mRenderPriority << 0 | mId << 16;
  654. ri->defaultKey2 = 0;
  655. renderPass->addInst( ri );
  656. // Reset the batching.
  657. startBatchIdx = -1;
  658. }
  659. }
  660. void DecalRoad::setTransform( const MatrixF &mat )
  661. {
  662. // We ignore transform requests from the editor
  663. // right now.
  664. }
  665. void DecalRoad::setScale( const VectorF &scale )
  666. {
  667. // We ignore scale requests from the editor
  668. // right now.
  669. }
  670. // DecalRoad Public Methods
  671. bool DecalRoad::getClosestNode( const Point3F &pos, U32 &idx )
  672. {
  673. F32 closestDist = F32_MAX;
  674. for ( U32 i = 0; i < mNodes.size(); i++ )
  675. {
  676. F32 dist = ( mNodes[i].point - pos ).len();
  677. if ( dist < closestDist )
  678. {
  679. closestDist = dist;
  680. idx = i;
  681. }
  682. }
  683. return closestDist != F32_MAX;
  684. }
  685. bool DecalRoad::containsPoint( const Point3F &worldPos, U32 *nodeIdx ) const
  686. {
  687. // This is just for making selections in the editor, we use the
  688. // client-side road because it has the proper edge's.
  689. if ( isServerObject() && getClientObject() )
  690. return ((DecalRoad*)getClientObject())->containsPoint( worldPos, nodeIdx );
  691. // If point isn't in the world box,
  692. // it's definitely not in the road.
  693. //if ( !getWorldBox().isContained( worldPos ) )
  694. // return false;
  695. if ( mEdges.size() < 2 )
  696. return false;
  697. Point2F testPt( worldPos.x,
  698. worldPos.y );
  699. Point2F poly[4];
  700. // Look through all edges, does the polygon
  701. // formed from adjacent edge's contain the worldPos?
  702. for ( U32 i = 0; i < mEdges.size() - 1; i++ )
  703. {
  704. const RoadEdge &edge0 = mEdges[i];
  705. const RoadEdge &edge1 = mEdges[i+1];
  706. poly[0].set( edge0.p0.x, edge0.p0.y );
  707. poly[1].set( edge0.p2.x, edge0.p2.y );
  708. poly[2].set( edge1.p2.x, edge1.p2.y );
  709. poly[3].set( edge1.p0.x, edge1.p0.y );
  710. if ( MathUtils::pointInPolygon( poly, 4, testPt ) )
  711. {
  712. if ( nodeIdx )
  713. *nodeIdx = edge0.parentNodeIdx;
  714. return true;
  715. }
  716. }
  717. return false;
  718. }
  719. bool DecalRoad::castray( const Point3F &start, const Point3F &end ) const
  720. {
  721. // We just cast against the object box for the editor.
  722. return mWorldBox.collideLine( start, end );
  723. }
  724. Point3F DecalRoad::getNodePosition( U32 idx )
  725. {
  726. if ( mNodes.size() - 1 < idx )
  727. return Point3F();
  728. return mNodes[idx].point;
  729. }
  730. void DecalRoad::setNodePosition( U32 idx, const Point3F &pos )
  731. {
  732. if ( mNodes.size() - 1 < idx )
  733. return;
  734. mNodes[idx].point = pos;
  735. _generateEdges();
  736. scheduleUpdate( GenEdgesMask | ReClipMask | NodeMask );
  737. }
  738. U32 DecalRoad::addNode( const Point3F &pos, F32 width )
  739. {
  740. U32 idx = _addNode( pos, width );
  741. _generateEdges();
  742. scheduleUpdate( GenEdgesMask | ReClipMask | NodeMask );
  743. return idx;
  744. }
  745. U32 DecalRoad::insertNode(const Point3F &pos, const F32 &width, const U32 &idx)
  746. {
  747. U32 ret = _insertNode( pos, width, idx );
  748. _generateEdges();
  749. scheduleUpdate( GenEdgesMask | ReClipMask | NodeMask );
  750. return ret;
  751. }
  752. void DecalRoad::setNodeWidth( U32 idx, F32 width )
  753. {
  754. if ( mNodes.size() - 1 < idx )
  755. return;
  756. mNodes[idx].width = width;
  757. _generateEdges();
  758. scheduleUpdate( GenEdgesMask | ReClipMask | NodeMask );
  759. }
  760. F32 DecalRoad::getNodeWidth( U32 idx )
  761. {
  762. if ( mNodes.size() - 1 < idx )
  763. return -1.0f;
  764. return mNodes[idx].width;
  765. }
  766. void DecalRoad::deleteNode( U32 idx )
  767. {
  768. if ( mNodes.size() - 1 < idx )
  769. return;
  770. mNodes.erase(idx);
  771. _generateEdges();
  772. scheduleUpdate( GenEdgesMask | ReClipMask | NodeMask );
  773. }
  774. void DecalRoad::buildNodesFromList( DecalRoadNodeList* list )
  775. {
  776. mNodes.clear();
  777. for (U32 i=0; i<list->mPositions.size(); ++i)
  778. {
  779. _addNode( list->mPositions[i], list->mWidths[i] );
  780. }
  781. _generateEdges();
  782. _captureVerts();
  783. }
  784. void DecalRoad::setTextureLength( F32 meters )
  785. {
  786. meters = getMax( meters, 0.1f );
  787. if ( mTextureLength == meters )
  788. return;
  789. mTextureLength = meters;
  790. _generateEdges();
  791. scheduleUpdate( DecalRoadMask | ReClipMask );
  792. }
  793. void DecalRoad::setBreakAngle( F32 degrees )
  794. {
  795. //meters = getMax( meters, MIN_METERS_PER_SEGMENT );
  796. //if ( mBreakAngle == meters )
  797. // return;
  798. mBreakAngle = degrees;
  799. _generateEdges();
  800. scheduleUpdate( DecalRoadMask | GenEdgesMask | ReClipMask );
  801. }
  802. void DecalRoad::scheduleUpdate( U32 updateMask )
  803. {
  804. scheduleUpdate( updateMask, smUpdateDelay, true );
  805. }
  806. void DecalRoad::scheduleUpdate( U32 updateMask, U32 delayMs, bool restartTimer )
  807. {
  808. if ( Sim::isEventPending( mUpdateEventId ) )
  809. {
  810. if ( !restartTimer )
  811. {
  812. mLastEvent->mMask |= updateMask;
  813. return;
  814. }
  815. else
  816. {
  817. Sim::cancelEvent( mUpdateEventId );
  818. }
  819. }
  820. mLastEvent = new DecalRoadUpdateEvent( updateMask, delayMs );
  821. mUpdateEventId = Sim::postEvent( this, mLastEvent, Sim::getCurrentTime() + delayMs );
  822. }
  823. void DecalRoad::regenerate()
  824. {
  825. _generateEdges();
  826. _captureVerts();
  827. setMaskBits( NodeMask | GenEdgesMask | ReClipMask );
  828. }
  829. bool DecalRoad::addNodeFromField( void *object, const char *index, const char *data )
  830. {
  831. DecalRoad *pObj = static_cast<DecalRoad*>(object);
  832. F32 x,y,z,width;
  833. U32 result = dSscanf( data, "%f %f %f %f", &x, &y, &z, &width );
  834. if ( result == 4 )
  835. pObj->_addNode( Point3F(x,y,z), width );
  836. return false;
  837. }
  838. // Internal Helper Methods
  839. void DecalRoad::_initMaterial()
  840. {
  841. _setMaterial(getMaterial());
  842. if (mMaterialAsset.notNull())
  843. {
  844. if (mMaterialInst && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMaterialInst->getMaterial()->getName(), String::NoCase))
  845. return;
  846. SAFE_DELETE(mMaterialInst);
  847. Material* tMat = nullptr;
  848. if (!Sim::findObject(mMaterialAsset->getMaterialDefinitionName(), tMat))
  849. Con::errorf("DecalRoad::_initMaterial - Material %s was not found.", mMaterialAsset->getMaterialDefinitionName());
  850. mMaterial = tMat;
  851. if (mMaterial)
  852. mMaterialInst = mMaterial->createMatInstance();
  853. else
  854. mMaterialInst = MATMGR->createMatInstance("WarningMaterial");
  855. if (!mMaterialInst)
  856. Con::errorf("DecalRoad::_initMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName());
  857. }
  858. if (!mMaterialInst)
  859. return;
  860. GFXStateBlockDesc desc;
  861. desc.setZReadWrite( true, false );
  862. mMaterialInst->addStateBlockDesc( desc );
  863. mMaterialInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTBT>() );
  864. }
  865. void DecalRoad::_debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance* )
  866. {
  867. //if ( mStateBlock.isNull() )
  868. // return;
  869. GFX->enterDebugEvent( ColorI( 255, 0, 0 ), "DecalRoad_debugRender" );
  870. GFXTransformSaver saver;
  871. //GFX->setStateBlock( mStateBlock );
  872. Point3F size(1,1,1);
  873. ColorI color( 255, 0, 0, 255 );
  874. GFXStateBlockDesc desc;
  875. desc.setZReadWrite( true, false );
  876. desc.setBlend( true );
  877. desc.fillMode = GFXFillWireframe;
  878. if ( smShowBatches )
  879. {
  880. for ( U32 i = 0; i < mBatches.size(); i++ )
  881. {
  882. const Box3F &box = mBatches[i].bounds;
  883. GFX->getDrawUtil()->drawCube( desc, box, ColorI(255,100,100,255) );
  884. }
  885. }
  886. //GFX->leaveDebugEvent();
  887. }
  888. void DecalRoad::_generateEdges()
  889. {
  890. PROFILE_SCOPE( DecalRoad_generateEdges );
  891. //Con::warnf( "%s - generateEdges", isServerObject() ? "server" : "client" );
  892. if ( mNodes.size() > 0 )
  893. {
  894. // Set our object position to the first node.
  895. const Point3F &nodePt = mNodes.first().point;
  896. MatrixF mat( true );
  897. mat.setPosition( nodePt );
  898. Parent::setTransform( mat );
  899. // The server object has global bounds, which Parent::setTransform
  900. // messes up so we must reset it.
  901. if ( isServerObject() )
  902. {
  903. mObjBox.minExtents.set(-1e10, -1e10, -1e10);
  904. mObjBox.maxExtents.set( 1e10, 1e10, 1e10);
  905. }
  906. }
  907. if ( mNodes.size() < 2 )
  908. return;
  909. // Ensure nodes are above the terrain height at their xy position
  910. for ( U32 i = 0; i < mNodes.size(); i++ )
  911. {
  912. _getTerrainHeight( mNodes[i].point );
  913. }
  914. // Now start generating edges...
  915. U32 nodeCount = mNodes.size();
  916. Point3F *positions = new Point3F[nodeCount];
  917. for ( U32 i = 0; i < nodeCount; i++ )
  918. {
  919. const RoadNode &node = mNodes[i];
  920. positions[i].set( node.point.x, node.point.y, node.width );
  921. }
  922. CatmullRom<Point3F> spline;
  923. spline.initialize( nodeCount, positions );
  924. delete [] positions;
  925. mEdges.clear();
  926. Point3F lastBreakVector(0,0,0);
  927. RoadEdge slice;
  928. Point3F lastBreakNode;
  929. lastBreakNode = spline.evaluate(0.0f);
  930. for ( U32 i = 1; i < mNodes.size(); i++ )
  931. {
  932. F32 t1 = spline.getTime(i);
  933. F32 t0 = spline.getTime(i-1);
  934. F32 segLength = spline.arcLength( t0, t1 );
  935. U32 numSegments = mCeil( segLength / MIN_METERS_PER_SEGMENT );
  936. numSegments = getMax( numSegments, (U32)1 );
  937. F32 tstep = ( t1 - t0 ) / numSegments;
  938. U32 startIdx = 0;
  939. U32 endIdx = ( i == nodeCount - 1 ) ? numSegments + 1 : numSegments;
  940. for ( U32 j = startIdx; j < endIdx; j++ )
  941. {
  942. F32 t = t0 + tstep * j;
  943. Point3F splineNode = spline.evaluate(t);
  944. F32 width = splineNode.z;
  945. _getTerrainHeight( splineNode );
  946. Point3F toNodeVec = splineNode - lastBreakNode;
  947. toNodeVec.normalizeSafe();
  948. if ( lastBreakVector.isZero() )
  949. lastBreakVector = toNodeVec;
  950. F32 angle = mRadToDeg( mAcos( mDot( toNodeVec, lastBreakVector ) ) );
  951. if ( j == startIdx ||
  952. ( j == endIdx - 1 && i == mNodes.size() - 1 ) ||
  953. angle > mBreakAngle )
  954. {
  955. // Push back a spline node
  956. //slice.p1.set( splineNode.x, splineNode.y, 0.0f );
  957. //_getTerrainHeight( slice.p1 );
  958. slice.p1 = splineNode;
  959. slice.uvec.set(0,0,1);
  960. slice.width = width;
  961. slice.parentNodeIdx = i-1;
  962. mEdges.push_back( slice );
  963. lastBreakVector = splineNode - lastBreakNode;
  964. lastBreakVector.normalizeSafe();
  965. lastBreakNode = splineNode;
  966. }
  967. }
  968. }
  969. /*
  970. for ( U32 i = 1; i < nodeCount; i++ )
  971. {
  972. F32 t0 = spline.getTime( i-1 );
  973. F32 t1 = spline.getTime( i );
  974. F32 segLength = spline.arcLength( t0, t1 );
  975. U32 numSegments = mCeil( segLength / mBreakAngle );
  976. numSegments = getMax( numSegments, (U32)1 );
  977. F32 tstep = ( t1 - t0 ) / numSegments;
  978. AssertFatal( numSegments > 0, "DecalRoad::_generateEdges, got zero segments!" );
  979. U32 startIdx = 0;
  980. U32 endIdx = ( i == nodeCount - 1 ) ? numSegments + 1 : numSegments;
  981. for ( U32 j = startIdx; j < endIdx; j++ )
  982. {
  983. F32 t = t0 + tstep * j;
  984. Point3F val = spline.evaluate(t);
  985. RoadEdge edge;
  986. edge.p1.set( val.x, val.y, 0.0f );
  987. _getTerrainHeight( val.x, val.y, edge.p1.z );
  988. edge.uvec.set(0,0,1);
  989. edge.width = val.z;
  990. edge.parentNodeIdx = i-1;
  991. mEdges.push_back( edge );
  992. }
  993. }
  994. */
  995. //
  996. // Calculate fvec and rvec for all edges
  997. //
  998. RoadEdge *edge = NULL;
  999. RoadEdge *nextEdge = NULL;
  1000. for ( U32 i = 0; i < mEdges.size() - 1; i++ )
  1001. {
  1002. edge = &mEdges[i];
  1003. nextEdge = &mEdges[i+1];
  1004. edge->fvec = nextEdge->p1 - edge->p1;
  1005. edge->fvec.normalize();
  1006. edge->rvec = mCross( edge->fvec, edge->uvec );
  1007. edge->rvec.normalize();
  1008. }
  1009. // Must do the last edge outside the loop
  1010. RoadEdge *lastEdge = &mEdges[mEdges.size()-1];
  1011. RoadEdge *prevEdge = &mEdges[mEdges.size()-2];
  1012. lastEdge->fvec = prevEdge->fvec;
  1013. lastEdge->rvec = prevEdge->rvec;
  1014. //
  1015. // Calculate p0/p2 for all edges
  1016. //
  1017. for ( U32 i = 0; i < mEdges.size(); i++ )
  1018. {
  1019. edge = &mEdges[i];
  1020. edge->p0 = edge->p1 - edge->rvec * edge->width * 0.5f;
  1021. edge->p2 = edge->p1 + edge->rvec * edge->width * 0.5f;
  1022. _getTerrainHeight( edge->p0 );
  1023. _getTerrainHeight( edge->p2 );
  1024. }
  1025. }
  1026. void DecalRoad::_captureVerts()
  1027. {
  1028. PROFILE_SCOPE( DecalRoad_captureVerts );
  1029. //Con::warnf( "%s - captureVerts", isServerObject() ? "server" : "client" );
  1030. if ( isServerObject() )
  1031. {
  1032. //Con::errorf( "DecalRoad::_captureVerts - called on the server side!" );
  1033. return;
  1034. }
  1035. if ( mEdges.size() == 0 )
  1036. return;
  1037. //
  1038. // Construct ClippedPolyList objects for each pair
  1039. // of roadEdges.
  1040. // Use them to capture Terrain verts.
  1041. //
  1042. SphereF sphere;
  1043. RoadEdge *edge = NULL;
  1044. RoadEdge *nextEdge = NULL;
  1045. mTriangleCount = 0;
  1046. mVertCount = 0;
  1047. Vector<ClippedPolyList> clipperList;
  1048. for ( U32 i = 0; i < mEdges.size() - 1; i++ )
  1049. {
  1050. Box3F box;
  1051. edge = &mEdges[i];
  1052. nextEdge = &mEdges[i+1];
  1053. box.minExtents = edge->p1;
  1054. box.maxExtents = edge->p1;
  1055. box.extend( edge->p0 );
  1056. box.extend( edge->p2 );
  1057. box.extend( nextEdge->p0 );
  1058. box.extend( nextEdge->p1 );
  1059. box.extend( nextEdge->p2 );
  1060. box.minExtents.z -= 5.0f;
  1061. box.maxExtents.z += 5.0f;
  1062. sphere.center = ( nextEdge->p1 + edge->p1 ) * 0.5f;
  1063. sphere.radius = 100.0f; // NOTE: no idea how to calculate this
  1064. ClippedPolyList clipper;
  1065. clipper.mNormal.set(0.0f, 0.0f, 0.0f);
  1066. VectorF n;
  1067. PlaneF plane0, plane1;
  1068. // Construct Back Plane
  1069. n = edge->p2 - edge->p0;
  1070. n.normalize();
  1071. n = mCross( n, edge->uvec );
  1072. plane0.set( edge->p0, n );
  1073. clipper.mPlaneList.push_back( plane0 );
  1074. // Construct Front Plane
  1075. n = nextEdge->p2 - nextEdge->p0;
  1076. n.normalize();
  1077. n = -mCross( edge->uvec, n );
  1078. plane1.set( nextEdge->p0, -n );
  1079. //clipper.mPlaneList.push_back( plane1 );
  1080. // Test if / where the planes intersect.
  1081. bool discardLeft = false;
  1082. bool discardRight = false;
  1083. Point3F iPos;
  1084. VectorF iDir;
  1085. if ( plane0.intersect( plane1, iPos, iDir ) )
  1086. {
  1087. Point2F iPos2F( iPos.x, iPos.y );
  1088. Point2F cPos2F( edge->p1.x, edge->p1.y );
  1089. Point2F rVec2F( edge->rvec.x, edge->rvec.y );
  1090. Point2F iVec2F = iPos2F - cPos2F;
  1091. F32 iLen = iVec2F.len();
  1092. iVec2F.normalize();
  1093. if ( iLen < edge->width * 0.5f )
  1094. {
  1095. F32 dot = mDot( rVec2F, iVec2F );
  1096. // The clipping planes intersected on the right side,
  1097. // discard the right side clipping plane.
  1098. if ( dot > 0.0f )
  1099. discardRight = true;
  1100. // The clipping planes intersected on the left side,
  1101. // discard the left side clipping plane.
  1102. else
  1103. discardLeft = true;
  1104. }
  1105. }
  1106. // Left Plane
  1107. if ( !discardLeft )
  1108. {
  1109. n = ( nextEdge->p0 - edge->p0 );
  1110. n.normalize();
  1111. n = mCross( edge->uvec, n );
  1112. clipper.mPlaneList.push_back( PlaneF(edge->p0, n) );
  1113. }
  1114. else
  1115. {
  1116. nextEdge->p0 = edge->p0;
  1117. }
  1118. // Right Plane
  1119. if ( !discardRight )
  1120. {
  1121. n = ( nextEdge->p2 - edge->p2 );
  1122. n.normalize();
  1123. n = -mCross( n, edge->uvec );
  1124. clipper.mPlaneList.push_back( PlaneF(edge->p2, -n) );
  1125. }
  1126. else
  1127. {
  1128. nextEdge->p2 = edge->p2;
  1129. }
  1130. n = nextEdge->p2 - nextEdge->p0;
  1131. n.normalize();
  1132. n = -mCross( edge->uvec, n );
  1133. plane1.set( nextEdge->p0, -n );
  1134. clipper.mPlaneList.push_back( plane1 );
  1135. // We have constructed the clipping planes,
  1136. // now grab/clip the terrain geometry
  1137. getContainer()->buildPolyList( PLC_Decal, box, TerrainObjectType, &clipper );
  1138. clipper.cullUnusedVerts();
  1139. clipper.triangulate();
  1140. clipper.generateNormals();
  1141. // If we got something, add it to the ClippedPolyList Vector
  1142. if ( !clipper.isEmpty() && !( smDiscardAll && ( discardRight || discardLeft ) ) )
  1143. {
  1144. clipperList.push_back( clipper );
  1145. mVertCount += clipper.mVertexList.size();
  1146. mTriangleCount += clipper.mPolyList.size();
  1147. }
  1148. }
  1149. //
  1150. // Set the roadEdge height to be flush with terrain
  1151. // This is not really necessary but makes the debug spline rendering better.
  1152. //
  1153. for ( U32 i = 0; i < mEdges.size() - 1; i++ )
  1154. {
  1155. edge = &mEdges[i];
  1156. _getTerrainHeight( edge->p0.x, edge->p0.y, edge->p0.z );
  1157. _getTerrainHeight( edge->p2.x, edge->p2.y, edge->p2.z );
  1158. }
  1159. //
  1160. // Allocate the RoadBatch(s)
  1161. //
  1162. // If we captured no verts, then we can return here without
  1163. // allocating any RoadBatches or the Vert/Index Buffers.
  1164. // PreprenderImage will not allocate a render instance while
  1165. // mBatches.size() is zero.
  1166. U32 numClippers = clipperList.size();
  1167. if ( numClippers == 0 )
  1168. return;
  1169. mBatches.clear();
  1170. // Allocate the VertexBuffer and PrimitiveBuffer
  1171. mVB.set( GFX, mVertCount, GFXBufferTypeStatic );
  1172. mPB.set( GFX, mTriangleCount * 3, 0, GFXBufferTypeStatic );
  1173. // Lock the VertexBuffer
  1174. GFXVertexPNTBT *vertPtr = mVB.lock();
  1175. if(!vertPtr) return;
  1176. U32 vertIdx = 0;
  1177. //
  1178. // Fill the VertexBuffer and vertex data for the RoadBatches
  1179. // Loop through the ClippedPolyList Vector
  1180. //
  1181. RoadBatch *batch = NULL;
  1182. F32 texStart = 0.0f;
  1183. F32 texEnd;
  1184. for ( U32 i = 0; i < clipperList.size(); i++ )
  1185. {
  1186. ClippedPolyList *clipper = &clipperList[i];
  1187. edge = &mEdges[i];
  1188. nextEdge = &mEdges[i+1];
  1189. VectorF segFvec = nextEdge->p1 - edge->p1;
  1190. F32 segLen = segFvec.len();
  1191. segFvec.normalize();
  1192. F32 texLen = segLen / mTextureLength;
  1193. texEnd = texStart + texLen;
  1194. BiQuadToSqr quadToSquare( Point2F( edge->p0.x, edge->p0.y ),
  1195. Point2F( edge->p2.x, edge->p2.y ),
  1196. Point2F( nextEdge->p2.x, nextEdge->p2.y ),
  1197. Point2F( nextEdge->p0.x, nextEdge->p0.y ) );
  1198. //
  1199. if ( i % mSegmentsPerBatch == 0 )
  1200. {
  1201. mBatches.increment();
  1202. batch = &mBatches.last();
  1203. batch->bounds.minExtents = clipper->mVertexList[0].point;
  1204. batch->bounds.maxExtents = clipper->mVertexList[0].point;
  1205. batch->startVert = vertIdx;
  1206. }
  1207. // Loop through each ClippedPolyList
  1208. for ( U32 j = 0; j < clipper->mVertexList.size(); j++ )
  1209. {
  1210. // Add each vert to the VertexBuffer
  1211. Point3F pos = clipper->mVertexList[j].point;
  1212. vertPtr[vertIdx].point = pos;
  1213. vertPtr[vertIdx].normal = clipper->mNormalList[j];
  1214. Point2F uv = quadToSquare.transform( Point2F(pos.x,pos.y) );
  1215. vertPtr[vertIdx].texCoord.x = uv.x;
  1216. vertPtr[vertIdx].texCoord.y = -(( texEnd - texStart ) * uv.y + texStart);
  1217. vertPtr[vertIdx].tangent = mCross( segFvec, clipper->mNormalList[j] );
  1218. vertPtr[vertIdx].binormal = segFvec;
  1219. vertIdx++;
  1220. // Expand the RoadBatch bounds to contain this vertex
  1221. batch->bounds.extend( pos );
  1222. }
  1223. batch->endVert = vertIdx - 1;
  1224. texStart = texEnd;
  1225. }
  1226. // Unlock the VertexBuffer, we are done filling it.
  1227. mVB.unlock();
  1228. // Lock the PrimitiveBuffer
  1229. U16 *idxBuff;
  1230. mPB.lock(&idxBuff);
  1231. U32 curIdx = 0;
  1232. U16 vertOffset = 0;
  1233. batch = NULL;
  1234. S32 batchIdx = -1;
  1235. // Fill the PrimitiveBuffer
  1236. // Loop through each ClippedPolyList in the Vector
  1237. for ( U32 i = 0; i < clipperList.size(); i++ )
  1238. {
  1239. ClippedPolyList *clipper = &clipperList[i];
  1240. if ( i % mSegmentsPerBatch == 0 )
  1241. {
  1242. batchIdx++;
  1243. batch = &mBatches[batchIdx];
  1244. batch->startIndex = curIdx;
  1245. }
  1246. for ( U32 j = 0; j < clipper->mPolyList.size(); j++ )
  1247. {
  1248. // Write indices for each Poly
  1249. ClippedPolyList::Poly *poly = &clipper->mPolyList[j];
  1250. AssertFatal( poly->vertexCount == 3, "Got non-triangle poly!" );
  1251. idxBuff[curIdx] = clipper->mIndexList[poly->vertexStart] + vertOffset;
  1252. curIdx++;
  1253. idxBuff[curIdx] = clipper->mIndexList[poly->vertexStart + 1] + vertOffset;
  1254. curIdx++;
  1255. idxBuff[curIdx] = clipper->mIndexList[poly->vertexStart + 2] + vertOffset;
  1256. curIdx++;
  1257. }
  1258. batch->endIndex = curIdx - 1;
  1259. vertOffset += clipper->mVertexList.size();
  1260. }
  1261. // Unlock the PrimitiveBuffer, we are done filling it.
  1262. mPB.unlock();
  1263. // Generate the object/world bounds
  1264. // Is the union of all batch bounding boxes.
  1265. Box3F box;
  1266. for ( U32 i = 0; i < mBatches.size(); i++ )
  1267. {
  1268. batch = &mBatches[i];
  1269. if ( i == 0 )
  1270. box = batch->bounds;
  1271. else
  1272. box.intersect( batch->bounds );
  1273. }
  1274. mWorldBox = box;
  1275. resetObjectBox();
  1276. // Make sure we are in the correct bins given our world box.
  1277. if( getSceneManager() != NULL )
  1278. getSceneManager()->notifyObjectDirty( this );
  1279. }
  1280. U32 DecalRoad::_addNode( const Point3F &pos, F32 width )
  1281. {
  1282. mNodes.increment();
  1283. RoadNode &node = mNodes.last();
  1284. node.point = pos;
  1285. node.width = width;
  1286. return mNodes.size() - 1;
  1287. }
  1288. U32 DecalRoad::_insertNode( const Point3F &pos, const F32 &width, const U32 &idx )
  1289. {
  1290. U32 ret;
  1291. RoadNode *node;
  1292. if ( idx == U32_MAX )
  1293. {
  1294. mNodes.increment();
  1295. node = &mNodes.last();
  1296. ret = mNodes.size() - 1;
  1297. }
  1298. else
  1299. {
  1300. mNodes.insert( idx );
  1301. node = &mNodes[idx];
  1302. ret = idx;
  1303. }
  1304. node->point = pos;
  1305. //node->t = -1.0f;
  1306. //node->rot.identity();
  1307. node->width = width;
  1308. return ret;
  1309. }
  1310. bool DecalRoad::_getTerrainHeight( Point3F &pos )
  1311. {
  1312. return _getTerrainHeight( pos.x, pos.y, pos.z );
  1313. }
  1314. bool DecalRoad::_getTerrainHeight( const Point2F &pos, F32 &height )
  1315. {
  1316. return _getTerrainHeight( pos.x, pos.y, height );
  1317. }
  1318. bool DecalRoad::_getTerrainHeight( const F32 &x, const F32 &y, F32 &height )
  1319. {
  1320. Point3F startPnt( x, y, 10000.0f );
  1321. Point3F endPnt( x, y, -10000.0f );
  1322. RayInfo ri;
  1323. bool hit;
  1324. hit = getContainer()->castRay(startPnt, endPnt, TerrainObjectType, &ri);
  1325. if ( hit )
  1326. height = ri.point.z;
  1327. return hit;
  1328. }
  1329. void DecalRoad::_onTerrainChanged( U32 type, TerrainBlock* tblock, const Point2I &min, const Point2I &max )
  1330. {
  1331. // The client side object just stores the area that has changed
  1332. // and waits for the (delayed) update event from the server
  1333. // to actually perform the update.
  1334. if ( isClientObject() && tblock->isClientObject() )
  1335. {
  1336. // Convert the min and max into world space.
  1337. const F32 size = tblock->getSquareSize();
  1338. const Point3F pos = tblock->getPosition();
  1339. // TODO: I don't think this works right with tiling!
  1340. Box3F dirty( F32( min.x * size ) + pos.x, F32( min.y * size ) + pos.y, -F32_MAX,
  1341. F32( max.x * size ) + pos.x, F32( max.y * size ) + pos.y, F32_MAX );
  1342. if ( !mTerrainUpdateRect.isValidBox() )
  1343. mTerrainUpdateRect = dirty;
  1344. else
  1345. mTerrainUpdateRect.intersect( dirty );
  1346. }
  1347. // The server object only updates edges (doesn't clip to geometry)
  1348. // and schedules an update to be sent to the client.
  1349. else if ( isServerObject() && tblock->isServerObject() )
  1350. {
  1351. //_generateEdges();
  1352. scheduleUpdate( TerrainChangedMask );
  1353. }
  1354. }
  1355. // Static protected field set methods
  1356. bool DecalRoad::ptSetBreakAngle( void *object, const char *index, const char *data )
  1357. {
  1358. DecalRoad *road = static_cast<DecalRoad*>( object );
  1359. F32 val = dAtof( data );
  1360. road->setBreakAngle( val );
  1361. // we already set the field
  1362. return false;
  1363. }
  1364. bool DecalRoad::ptSetTextureLength( void *object, const char *index, const char *data )
  1365. {
  1366. DecalRoad *road = static_cast<DecalRoad*>( object );
  1367. F32 val = dAtof( data );
  1368. road->setTextureLength( val );
  1369. // we already set the field
  1370. return false;
  1371. }
  1372. // ConsoleMethods
  1373. DefineEngineMethod( DecalRoad, regenerate, void, (),,
  1374. "Intended as a helper to developers and editor scripts.\n"
  1375. "Force DecalRoad to update it's spline and reclip geometry."
  1376. )
  1377. {
  1378. object->regenerate();
  1379. }
  1380. DefineEngineMethod( DecalRoad, postApply, void, (),,
  1381. "Intended as a helper to developers and editor scripts.\n"
  1382. "Force trigger an inspectPostApply. This will transmit "
  1383. "the material and other fields ( not including nodes ) "
  1384. "to client objects."
  1385. )
  1386. {
  1387. object->inspectPostApply();
  1388. }