decalManager.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746
  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 "T3D/decal/decalManager.h"
  24. #include "scene/sceneManager.h"
  25. #include "scene/sceneRenderState.h"
  26. #include "ts/tsShapeInstance.h"
  27. #include "console/console.h"
  28. #include "console/dynamicTypes.h"
  29. #include "gfx/primBuilder.h"
  30. #include "console/consoleTypes.h"
  31. #include "platform/profiler.h"
  32. #include "gfx/gfxTransformSaver.h"
  33. #include "lighting/lightManager.h"
  34. #include "lighting/lightInfo.h"
  35. #include "gfx/gfxDrawUtil.h"
  36. #include "gfx/sim/gfxStateBlockData.h"
  37. #include "materials/shaderData.h"
  38. #include "materials/matInstance.h"
  39. #include "renderInstance/renderPassManager.h"
  40. #include "core/resourceManager.h"
  41. #include "core/stream/fileStream.h"
  42. #include "gfx/gfxDebugEvent.h"
  43. #include "math/util/quadTransforms.h"
  44. #include "math/mathUtils.h"
  45. #include "core/volume.h"
  46. #include "core/module.h"
  47. #include "T3D/decal/decalData.h"
  48. #include "console/engineAPI.h"
  49. extern bool gEditingMission;
  50. MODULE_BEGIN( DecalManager )
  51. MODULE_INIT_AFTER( Scene )
  52. MODULE_SHUTDOWN_BEFORE( Scene )
  53. MODULE_INIT
  54. {
  55. gDecalManager = new DecalManager;
  56. gClientSceneGraph->addObjectToScene( gDecalManager );
  57. }
  58. MODULE_SHUTDOWN
  59. {
  60. gClientSceneGraph->removeObjectFromScene( gDecalManager );
  61. SAFE_DELETE( gDecalManager );
  62. }
  63. MODULE_END;
  64. /// A bias applied to the nearPlane for Decal and DecalRoad rendering.
  65. /// Is set by by LevelInfo.
  66. F32 gDecalBias = 0.0015f;
  67. bool DecalManager::smDecalsOn = true;
  68. bool DecalManager::smDebugRender = false;
  69. F32 DecalManager::smDecalLifeTimeScale = 1.0f;
  70. bool DecalManager::smPoolBuffers = true;
  71. const U32 DecalManager::smMaxVerts = 6000;
  72. const U32 DecalManager::smMaxIndices = 10000;
  73. DecalManager *gDecalManager = NULL;
  74. IMPLEMENT_CONOBJECT(DecalManager);
  75. ConsoleDoc(
  76. "@defgroup Decals\n"
  77. "@brief Decals are non-SimObject derived objects that are stored and loaded "
  78. "separately from the normal mission file.\n\n"
  79. "The DecalManager handles all aspects of decal management including loading, "
  80. "creation, saving, and automatically deleting decals that have exceeded their "
  81. "lifeSpan.\n\n"
  82. "The static decals associated with a mission are normally loaded immediately "
  83. "after the mission itself has loaded as shown below.\n"
  84. "@tsexample\n"
  85. "// Load the static mission decals.\n"
  86. "decalManagerLoad( %missionName @ \".decals\" );\n"
  87. "@endtsexample\n"
  88. "@ingroup FX\n"
  89. );
  90. ConsoleDocClass( DecalManager,
  91. "@brief The object that manages all of the decals in the active mission.\n\n"
  92. "@see Decals\n"
  93. "@ingroup Decals\n"
  94. "@ingroup FX\n"
  95. );
  96. namespace {
  97. S32 QSORT_CALLBACK cmpDecalInstance(const void* p1, const void* p2)
  98. {
  99. const DecalInstance** pd1 = (const DecalInstance**)p1;
  100. const DecalInstance** pd2 = (const DecalInstance**)p2;
  101. return int(((char *)(*pd1)->mDataBlock) - ((char *)(*pd2)->mDataBlock));
  102. }
  103. S32 QSORT_CALLBACK cmpPointsXY( const void *p1, const void *p2 )
  104. {
  105. const Point3F *pnt1 = (const Point3F*)p1;
  106. const Point3F *pnt2 = (const Point3F*)p2;
  107. if ( pnt1->x < pnt2->x )
  108. return -1;
  109. else if ( pnt1->x > pnt2->x )
  110. return 1;
  111. else if ( pnt1->y < pnt2->y )
  112. return -1;
  113. else if ( pnt1->y > pnt2->y )
  114. return 1;
  115. else
  116. return 0;
  117. }
  118. S32 QSORT_CALLBACK cmpQuadPointTheta( const void *p1, const void *p2 )
  119. {
  120. const Point4F *pnt1 = (const Point4F*)p1;
  121. const Point4F *pnt2 = (const Point4F*)p2;
  122. if ( mFabs( pnt1->w ) > mFabs( pnt2->w ) )
  123. return 1;
  124. else if ( mFabs( pnt1->w ) < mFabs( pnt2->w ) )
  125. return -1;
  126. else
  127. return 0;
  128. }
  129. static Point3F gSortPoint;
  130. S32 QSORT_CALLBACK cmpDecalDistance( const void *p1, const void *p2 )
  131. {
  132. const DecalInstance** pd1 = (const DecalInstance**)p1;
  133. const DecalInstance** pd2 = (const DecalInstance**)p2;
  134. F32 dist1 = ( (*pd1)->mPosition - gSortPoint ).lenSquared();
  135. F32 dist2 = ( (*pd2)->mPosition - gSortPoint ).lenSquared();
  136. return mSign( dist1 - dist2 );
  137. }
  138. S32 QSORT_CALLBACK cmpDecalRenderOrder( const void *p1, const void *p2 )
  139. {
  140. const DecalInstance** pd1 = (const DecalInstance**)p1;
  141. const DecalInstance** pd2 = (const DecalInstance**)p2;
  142. if ( ( (*pd2)->mFlags & SaveDecal ) && !( (*pd1)->mFlags & SaveDecal ) )
  143. return -1;
  144. else if ( !( (*pd2)->mFlags & SaveDecal ) && ( (*pd1)->mFlags & SaveDecal ) )
  145. return 1;
  146. else
  147. {
  148. S32 priority = (*pd1)->getRenderPriority() - (*pd2)->getRenderPriority();
  149. if ( priority != 0 )
  150. return priority;
  151. if ( (*pd2)->mFlags & SaveDecal )
  152. {
  153. S32 id = ( (*pd1)->mDataBlock->getMaterialDefinition()->getId() - (*pd2)->mDataBlock->getMaterialDefinition()->getId() );
  154. if ( id != 0 )
  155. return id;
  156. return (*pd1)->mCreateTime - (*pd2)->mCreateTime;
  157. }
  158. else
  159. return (*pd1)->mCreateTime - (*pd2)->mCreateTime;
  160. }
  161. }
  162. } // namespace {}
  163. //-------------------------------------------------------------------------
  164. // DecalManager
  165. //-------------------------------------------------------------------------
  166. DecalManager::DecalManager()
  167. {
  168. #ifdef DECALMANAGER_DEBUG
  169. VECTOR_SET_ASSOCIATION( mDebugPlanes );
  170. #endif
  171. setGlobalBounds();
  172. mDataFileName = NULL;
  173. mTypeMask |= EnvironmentObjectType;
  174. mDirty = false;
  175. GFXDevice::getDeviceEventSignal().notify(this, &DecalManager::_handleGFXEvent);
  176. }
  177. DecalManager::~DecalManager()
  178. {
  179. GFXDevice::getDeviceEventSignal().remove(this, &DecalManager::_handleGFXEvent);
  180. clearData();
  181. }
  182. void DecalManager::consoleInit()
  183. {
  184. Con::addVariable( "$pref::Decals::enabled", TypeBool, &smDecalsOn,
  185. "Controls whether decals are rendered.\n"
  186. "@ingroup Decals" );
  187. Con::addVariable( "$pref::Decals::lifeTimeScale", TypeF32, &smDecalLifeTimeScale,
  188. "@brief Lifetime that decals will last after being created in the world.\n"
  189. "Deprecated. Use DecalData::lifeSpan instead.\n"
  190. "@ingroup Decals" );
  191. Con::addVariable( "$Decals::poolBuffers", TypeBool, &smPoolBuffers,
  192. "If true, will merge all PrimitiveBuffers and VertexBuffers into a pair "
  193. "of pools before clearing them at the end of a frame.\n"
  194. "If false, will just clear them at the end of a frame.\n"
  195. "@ingroup Decals" );
  196. Con::addVariable( "$Decals::debugRender", TypeBool, &smDebugRender,
  197. "If true, the decal spheres will be visualized when in the editor.\n\n"
  198. "@ingroup Decals" );
  199. Con::addVariable( "$Decals::sphereDistanceTolerance", TypeF32, &DecalSphere::smDistanceTolerance,
  200. "The distance at which the decal system will start breaking up decal "
  201. "spheres when adding new decals.\n\n"
  202. "@ingroup Decals" );
  203. Con::addVariable( "$Decals::sphereRadiusTolerance", TypeF32, &DecalSphere::smRadiusTolerance,
  204. "The radius beyond which the decal system will start breaking up decal "
  205. "spheres when adding new decals.\n\n"
  206. "@ingroup Decals" );
  207. }
  208. bool DecalManager::_handleGFXEvent(GFXDevice::GFXDeviceEventType event)
  209. {
  210. switch(event)
  211. {
  212. case GFXDevice::deEndOfFrame:
  213. // Return PrimitiveBuffers and VertexBuffers used this frame to the pool.
  214. if ( smPoolBuffers )
  215. {
  216. mPBPool.merge( mPBs );
  217. mPBs.clear();
  218. mVBPool.merge( mVBs );
  219. mVBs.clear();
  220. }
  221. else
  222. {
  223. _freePools();
  224. }
  225. break;
  226. default: ;
  227. }
  228. return true;
  229. }
  230. bool DecalManager::clipDecal( DecalInstance *decal, Vector<Point3F> *edgeVerts, const Point2F *clipDepth )
  231. {
  232. PROFILE_SCOPE( DecalManager_clipDecal );
  233. // Free old verts and indices.
  234. _freeBuffers( decal );
  235. const Point2F& halfSize = decal->mSize * 0.5f * decal->mDataBlock->texRect[decal->mTextureRectIdx].extent;
  236. // Ugly hack for ProjectedShadow!
  237. F32 halfSizeZ = clipDepth ? clipDepth->x : halfSize.x;
  238. F32 negHalfSize = clipDepth ? clipDepth->y : halfSize.y;
  239. Point3F decalHalfSize( halfSize.x, halfSize.y, halfSize.x );
  240. Point3F decalHalfSizeZ( halfSizeZ, halfSizeZ, halfSizeZ );
  241. MatrixF projMat( true );
  242. decal->getWorldMatrix( &projMat );
  243. const VectorF &crossVec = decal->mNormal;
  244. const Point3F &decalPos = decal->mPosition;
  245. VectorF newFwd, newRight;
  246. projMat.getColumn( 0, &newRight );
  247. projMat.getColumn( 1, &newFwd );
  248. VectorF objRight( 1.0f, 0, 0 );
  249. VectorF objFwd( 0, 1.0f, 0 );
  250. VectorF objUp( 0, 0, 1.0f );
  251. // See above re: decalHalfSizeZ hack.
  252. mClipper.clear();
  253. mClipper.mPlaneList.setSize(6);
  254. mClipper.mPlaneList[0].set( ( decalPos + ( -newRight * halfSize.x ) ), -newRight );
  255. mClipper.mPlaneList[1].set( ( decalPos + ( -newFwd * halfSize.y ) ), -newFwd );
  256. mClipper.mPlaneList[2].set( ( decalPos + ( -crossVec * decalHalfSizeZ ) ), -crossVec );
  257. mClipper.mPlaneList[3].set( ( decalPos + ( newRight * halfSize.x ) ), newRight );
  258. mClipper.mPlaneList[4].set( ( decalPos + ( newFwd * halfSize.y ) ), newFwd );
  259. mClipper.mPlaneList[5].set( ( decalPos + ( crossVec * negHalfSize ) ), crossVec );
  260. mClipper.mNormal = decal->mNormal;
  261. const DecalData *decalData = decal->mDataBlock;
  262. mClipper.mNormalTolCosineRadians = mCos( mDegToRad( decalData->clippingAngle ) );
  263. Box3F box( -decalHalfSizeZ, decalHalfSizeZ );
  264. projMat.mul( box );
  265. PROFILE_START( DecalManager_clipDecal_buildPolyList );
  266. getContainer()->buildPolyList( PLC_Decal, box, decalData->clippingMasks, &mClipper );
  267. PROFILE_END();
  268. mClipper.cullUnusedVerts();
  269. mClipper.triangulate();
  270. const U32 numVerts = mClipper.mVertexList.size();
  271. const U32 numIndices = mClipper.mIndexList.size();
  272. if ( !numVerts || !numIndices )
  273. return false;
  274. // Fail if either of the buffer metrics exceeds our limits
  275. // on dynamic geometry buffers.
  276. if ( numVerts > smMaxVerts ||
  277. numIndices > smMaxIndices )
  278. return false;
  279. if ( !decalData->skipVertexNormals )
  280. mClipper.generateNormals();
  281. #ifdef DECALMANAGER_DEBUG
  282. mDebugPlanes.clear();
  283. mDebugPlanes.merge( mClipper.mPlaneList );
  284. #endif
  285. decal->mVertCount = numVerts;
  286. decal->mIndxCount = numIndices;
  287. Vector<Point3F> tmpPoints;
  288. tmpPoints.push_back(( objFwd * decalHalfSize ) + ( objRight * decalHalfSize ));
  289. tmpPoints.push_back(( objFwd * decalHalfSize ) + ( -objRight * decalHalfSize ));
  290. tmpPoints.push_back(( -objFwd * decalHalfSize ) + ( -objRight * decalHalfSize ));
  291. Point3F lowerLeft(( -objFwd * decalHalfSize ) + ( objRight * decalHalfSize ));
  292. projMat.inverse();
  293. _generateWindingOrder( lowerLeft, &tmpPoints );
  294. BiQuadToSqr quadToSquare( Point2F( lowerLeft.x, lowerLeft.y ),
  295. Point2F( tmpPoints[0].x, tmpPoints[0].y ),
  296. Point2F( tmpPoints[1].x, tmpPoints[1].y ),
  297. Point2F( tmpPoints[2].x, tmpPoints[2].y ) );
  298. Point2F uv( 0, 0 );
  299. Point3F vecX(0.0f, 0.0f, 0.0f);
  300. // Allocate memory for vert and index arrays
  301. _allocBuffers( decal );
  302. // Mark this so that the color will be assigned on these verts the next
  303. // time it renders, since we just threw away the previous verts.
  304. decal->mLastAlpha = -1;
  305. Point3F vertPoint( 0, 0, 0 );
  306. for ( U32 i = 0; i < mClipper.mVertexList.size(); i++ )
  307. {
  308. const ClippedPolyList::Vertex &vert = mClipper.mVertexList[i];
  309. vertPoint = vert.point;
  310. // Transform this point to
  311. // object space to look up the
  312. // UV coordinate for this vertex.
  313. projMat.mulP( vertPoint );
  314. // Clamp the point to be within the quad.
  315. vertPoint.x = mClampF( vertPoint.x, -decalHalfSize.x, decalHalfSize.x );
  316. vertPoint.y = mClampF( vertPoint.y, -decalHalfSize.y, decalHalfSize.y );
  317. // Get our UV.
  318. uv = quadToSquare.transform( Point2F( vertPoint.x, vertPoint.y ) );
  319. const RectF &rect = decal->mDataBlock->texRect[decal->mTextureRectIdx];
  320. uv *= rect.extent;
  321. uv += rect.point;
  322. // Set the world space vertex position.
  323. decal->mVerts[i].point = vert.point;
  324. decal->mVerts[i].texCoord.set( uv.x, uv.y );
  325. if ( mClipper.mNormalList.empty() )
  326. continue;
  327. decal->mVerts[i].normal = mClipper.mNormalList[i];
  328. decal->mVerts[i].normal.normalize();
  329. if( mFabs( decal->mVerts[i].normal.z ) > 0.8f )
  330. mCross( decal->mVerts[i].normal, Point3F( 1.0f, 0.0f, 0.0f ), &vecX );
  331. else if ( mFabs( decal->mVerts[i].normal.x ) > 0.8f )
  332. mCross( decal->mVerts[i].normal, Point3F( 0.0f, 1.0f, 0.0f ), &vecX );
  333. else if ( mFabs( decal->mVerts[i].normal.y ) > 0.8f )
  334. mCross( decal->mVerts[i].normal, Point3F( 0.0f, 0.0f, 1.0f ), &vecX );
  335. decal->mVerts[i].tangent = mCross( decal->mVerts[i].normal, vecX );
  336. }
  337. U32 curIdx = 0;
  338. for ( U32 j = 0; j < mClipper.mPolyList.size(); j++ )
  339. {
  340. // Write indices for each Poly
  341. ClippedPolyList::Poly *poly = &mClipper.mPolyList[j];
  342. AssertFatal( poly->vertexCount == 3, "Got non-triangle poly!" );
  343. decal->mIndices[curIdx] = mClipper.mIndexList[poly->vertexStart];
  344. curIdx++;
  345. decal->mIndices[curIdx] = mClipper.mIndexList[poly->vertexStart + 1];
  346. curIdx++;
  347. decal->mIndices[curIdx] = mClipper.mIndexList[poly->vertexStart + 2];
  348. curIdx++;
  349. }
  350. if ( !edgeVerts )
  351. return true;
  352. Point3F tmpHullPt( 0, 0, 0 );
  353. Vector<Point3F> tmpHullPts;
  354. for ( U32 i = 0; i < mClipper.mVertexList.size(); i++ )
  355. {
  356. const ClippedPolyList::Vertex &vert = mClipper.mVertexList[i];
  357. tmpHullPt = vert.point;
  358. projMat.mulP( tmpHullPt );
  359. tmpHullPts.push_back( tmpHullPt );
  360. }
  361. edgeVerts->clear();
  362. U32 verts = _generateConvexHull( tmpHullPts, edgeVerts );
  363. edgeVerts->setSize( verts );
  364. projMat.inverse();
  365. for ( U32 i = 0; i < edgeVerts->size(); i++ )
  366. projMat.mulP( (*edgeVerts)[i] );
  367. return true;
  368. }
  369. DecalInstance* DecalManager::addDecal( const Point3F &pos,
  370. const Point3F &normal,
  371. F32 rotAroundNormal,
  372. DecalData *decalData,
  373. F32 decalScale,
  374. S32 decalTexIndex,
  375. U8 flags )
  376. {
  377. MatrixF mat( true );
  378. MathUtils::getMatrixFromUpVector( normal, &mat );
  379. AngAxisF rot( normal, rotAroundNormal );
  380. MatrixF rotmat;
  381. rot.setMatrix( &rotmat );
  382. mat.mul( rotmat );
  383. Point3F tangent;
  384. mat.getColumn( 1, &tangent );
  385. return addDecal( pos, normal, tangent, decalData, decalScale, decalTexIndex, flags );
  386. }
  387. DecalInstance* DecalManager::addDecal( const Point3F& pos,
  388. const Point3F& normal,
  389. const Point3F& tangent,
  390. DecalData* decalData,
  391. F32 decalScale,
  392. S32 decalTexIndex,
  393. U8 flags )
  394. {
  395. if ( !mData && !_createDataFile() )
  396. return NULL;
  397. // only dirty the manager if this decal should be saved
  398. if ( flags & SaveDecal )
  399. mDirty = true;
  400. return mData->addDecal( pos, normal, tangent, decalData, decalScale, decalTexIndex, flags );
  401. }
  402. void DecalManager::removeDecal( DecalInstance *inst )
  403. {
  404. // If this is a decal we save then we need
  405. // to set the dirty flag.
  406. if ( inst->mFlags & SaveDecal )
  407. mDirty = true;
  408. // Remove the decal from the instance vector.
  409. if( inst->mId != -1 && inst->mId < mDecalInstanceVec.size() )
  410. mDecalInstanceVec[ inst->mId ] = NULL;
  411. // Release its geometry (if it has any).
  412. _freeBuffers( inst );
  413. // Remove it from the decal file.
  414. if ( mData )
  415. mData->removeDecal( inst );
  416. }
  417. DecalInstance* DecalManager::getDecal( S32 id )
  418. {
  419. if( id < 0 || id >= mDecalInstanceVec.size() )
  420. return NULL;
  421. return mDecalInstanceVec[id];
  422. }
  423. void DecalManager::notifyDecalModified( DecalInstance *inst )
  424. {
  425. // If this is a decal we save then we need
  426. // to set the dirty flag.
  427. if ( inst->mFlags & SaveDecal )
  428. mDirty = true;
  429. if ( mData )
  430. mData->notifyDecalModified( inst );
  431. }
  432. DecalInstance* DecalManager::getClosestDecal( const Point3F &pos )
  433. {
  434. if ( !mData )
  435. return NULL;
  436. const Vector<DecalSphere*> &grid = mData->getSphereList();
  437. DecalInstance *inst = NULL;
  438. SphereF worldPickSphere( pos, 0.5f );
  439. SphereF worldInstSphere( Point3F( 0, 0, 0 ), 1.0f );
  440. Vector<DecalInstance*> collectedInsts;
  441. for ( U32 i = 0; i < grid.size(); i++ )
  442. {
  443. DecalSphere *decalSphere = grid[i];
  444. const SphereF &worldSphere = decalSphere->mWorldSphere;
  445. if ( !worldSphere.isIntersecting( worldPickSphere ) &&
  446. !worldSphere.isContained( pos ) )
  447. continue;
  448. const Vector<DecalInstance*> &items = decalSphere->mItems;
  449. for ( U32 n = 0; n < items.size(); n++ )
  450. {
  451. inst = items[n];
  452. if ( !inst )
  453. continue;
  454. worldInstSphere.center = inst->mPosition;
  455. worldInstSphere.radius = inst->mSize;
  456. if ( !worldInstSphere.isContained( inst->mPosition ) )
  457. continue;
  458. collectedInsts.push_back( inst );
  459. }
  460. }
  461. F32 closestDistance = F32_MAX;
  462. F32 currentDist = 0;
  463. U32 closestIndex = 0;
  464. for ( U32 i = 0; i < collectedInsts.size(); i++ )
  465. {
  466. inst = collectedInsts[i];
  467. currentDist = (inst->mPosition - pos).len();
  468. if ( currentDist < closestDistance )
  469. {
  470. closestIndex = i;
  471. closestDistance = currentDist;
  472. worldInstSphere.center = inst->mPosition;
  473. worldInstSphere.radius = inst->mSize;
  474. }
  475. }
  476. if ( (!collectedInsts.empty() &&
  477. collectedInsts[closestIndex] &&
  478. closestDistance < 1.0f) ||
  479. worldInstSphere.isContained( pos ) )
  480. return collectedInsts[closestIndex];
  481. else
  482. return NULL;
  483. }
  484. DecalInstance* DecalManager::raycast( const Point3F &start, const Point3F &end, bool savedDecalsOnly )
  485. {
  486. if ( !mData )
  487. return NULL;
  488. const Vector<DecalSphere*> &grid = mData->getSphereList();
  489. DecalInstance *inst = NULL;
  490. SphereF worldSphere( Point3F( 0, 0, 0 ), 1.0f );
  491. Vector<DecalInstance*> hitDecals;
  492. for ( U32 i = 0; i < grid.size(); i++ )
  493. {
  494. DecalSphere *decalSphere = grid[i];
  495. if ( !decalSphere->mWorldSphere.intersectsRay( start, end ) )
  496. continue;
  497. const Vector<DecalInstance*> &items = decalSphere->mItems;
  498. for ( U32 n = 0; n < items.size(); n++ )
  499. {
  500. inst = items[n];
  501. if ( !inst )
  502. continue;
  503. if ( savedDecalsOnly && !(inst->mFlags & SaveDecal) )
  504. continue;
  505. worldSphere.center = inst->mPosition;
  506. worldSphere.radius = inst->mSize;
  507. if ( !worldSphere.intersectsRay( start, end ) )
  508. continue;
  509. RayInfo ri;
  510. bool containsPoint = false;
  511. if ( gServerContainer.castRayRendered( start, end, STATIC_COLLISION_TYPEMASK, &ri ) )
  512. {
  513. Point2F poly[4];
  514. poly[0].set( inst->mPosition.x - (inst->mSize / 2), inst->mPosition.y + (inst->mSize / 2));
  515. poly[1].set( inst->mPosition.x - (inst->mSize / 2), inst->mPosition.y - (inst->mSize / 2));
  516. poly[2].set( inst->mPosition.x + (inst->mSize / 2), inst->mPosition.y - (inst->mSize / 2));
  517. poly[3].set( inst->mPosition.x + (inst->mSize / 2), inst->mPosition.y + (inst->mSize / 2));
  518. if ( MathUtils::pointInPolygon( poly, 4, Point2F(ri.point.x, ri.point.y) ) )
  519. containsPoint = true;
  520. }
  521. if( !containsPoint )
  522. continue;
  523. hitDecals.push_back( inst );
  524. }
  525. }
  526. if ( hitDecals.empty() )
  527. return NULL;
  528. gSortPoint = start;
  529. dQsort( hitDecals.address(), hitDecals.size(), sizeof(DecalInstance*), cmpDecalDistance );
  530. return hitDecals[0];
  531. }
  532. U32 DecalManager::_generateConvexHull( const Vector<Point3F> &points, Vector<Point3F> *outPoints )
  533. {
  534. PROFILE_SCOPE( DecalManager_generateConvexHull );
  535. // chainHull_2D(): Andrew's monotone chain 2D convex hull algorithm
  536. // Input: P[] = an array of 2D points
  537. // presorted by increasing x- and y-coordinates
  538. // n = the number of points in P[]
  539. // Output: H[] = an array of the convex hull vertices (max is n)
  540. // Return: the number of points in H[]
  541. //int
  542. if ( points.size() < 3 )
  543. {
  544. outPoints->merge( points );
  545. return outPoints->size();
  546. }
  547. // Sort our input points.
  548. dQsort( points.address(), points.size(), sizeof( Point3F ), cmpPointsXY );
  549. U32 n = points.size();
  550. Vector<Point3F> tmpPoints;
  551. tmpPoints.setSize( n );
  552. // the output array H[] will be used as the stack
  553. S32 bot=0, top=(-1); // indices for bottom and top of the stack
  554. S32 i; // array scan index
  555. S32 toptmp = 0;
  556. // Get the indices of points with min x-coord and min|max y-coord
  557. S32 minmin = 0, minmax;
  558. F32 xmin = points[0].x;
  559. for ( i = 1; i < n; i++ )
  560. if (points[i].x != xmin)
  561. break;
  562. minmax = i - 1;
  563. if ( minmax == n - 1 )
  564. {
  565. // degenerate case: all x-coords == xmin
  566. toptmp = top + 1;
  567. if ( toptmp < n )
  568. tmpPoints[++top] = points[minmin];
  569. if ( points[minmax].y != points[minmin].y ) // a nontrivial segment
  570. {
  571. toptmp = top + 1;
  572. if ( toptmp < n )
  573. tmpPoints[++top] = points[minmax];
  574. }
  575. toptmp = top + 1;
  576. if ( toptmp < n )
  577. tmpPoints[++top] = points[minmin]; // add polygon endpoint
  578. return top+1;
  579. }
  580. // Get the indices of points with max x-coord and min|max y-coord
  581. S32 maxmin, maxmax = n-1;
  582. F32 xmax = points[n-1].x;
  583. for ( i = n - 2; i >= 0; i-- )
  584. if ( points[i].x != xmax )
  585. break;
  586. maxmin = i + 1;
  587. // Compute the lower hull on the stack H
  588. toptmp = top + 1;
  589. if ( toptmp < n )
  590. tmpPoints[++top] = points[minmin]; // push minmin point onto stack
  591. i = minmax;
  592. while ( ++i <= maxmin )
  593. {
  594. // the lower line joins P[minmin] with P[maxmin]
  595. if (i < maxmin && isLeft(points[minmin], points[maxmin], points[i]) >= 0)
  596. continue; // ignore P[i] above or on the lower line
  597. while (top > 0) // there are at least 2 points on the stack
  598. {
  599. // test if P[i] is left of the line at the stack top
  600. if ( isLeft( tmpPoints[top-1], tmpPoints[top], points[i]) > 0)
  601. break; // P[i] is a new hull vertex
  602. else
  603. top--; // pop top point off stack
  604. }
  605. toptmp = top + 1;
  606. if ( toptmp < n )
  607. tmpPoints[++top] = points[i]; // push P[i] onto stack
  608. }
  609. // Next, compute the upper hull on the stack H above the bottom hull
  610. if (maxmax != maxmin) // if distinct xmax points
  611. {
  612. toptmp = top + 1;
  613. if ( toptmp < n )
  614. tmpPoints[++top] = points[maxmax]; // push maxmax point onto stack
  615. }
  616. bot = top; // the bottom point of the upper hull stack
  617. i = maxmin;
  618. while (--i >= minmax)
  619. {
  620. // the upper line joins P[maxmax] with P[minmax]
  621. if ( isLeft( points[maxmax], points[minmax], points[i] ) >= 0 && i > minmax )
  622. continue; // ignore P[i] below or on the upper line
  623. while ( top > bot ) // at least 2 points on the upper stack
  624. {
  625. // test if P[i] is left of the line at the stack top
  626. if ( isLeft( tmpPoints[top-1], tmpPoints[top], points[i] ) > 0 )
  627. break; // P[i] is a new hull vertex
  628. else
  629. top--; // pop top point off stack
  630. }
  631. toptmp = top + 1;
  632. if ( toptmp < n )
  633. tmpPoints[++top] = points[i]; // push P[i] onto stack
  634. }
  635. if (minmax != minmin)
  636. {
  637. toptmp = top + 1;
  638. if ( toptmp < n )
  639. tmpPoints[++top] = points[minmin]; // push joining endpoint onto stack
  640. }
  641. outPoints->merge( tmpPoints );
  642. return top + 1;
  643. }
  644. void DecalManager::_generateWindingOrder( const Point3F &cornerPoint, Vector<Point3F> *sortPoints )
  645. {
  646. // This block of code is used to find
  647. // the winding order for the points in our quad.
  648. // First, choose an arbitrary corner point.
  649. // We'll use the "lowerRight" point.
  650. Point3F relPoint( 0, 0, 0 );
  651. // See comment below about radius.
  652. //F32 radius = 0;
  653. F32 theta = 0;
  654. Vector<Point4F> tmpPoints;
  655. for ( U32 i = 0; i < (*sortPoints).size(); i++ )
  656. {
  657. const Point3F &pnt = (*sortPoints)[i];
  658. relPoint = cornerPoint - pnt;
  659. // Get the radius (r^2 = x^2 + y^2).
  660. // This is commented because for a quad
  661. // you typically can't have the same values
  662. // for theta, which is the caveat which would
  663. // require sorting by the radius.
  664. //radius = mSqrt( (relPoint.x * relPoint.x) + (relPoint.y * relPoint.y) );
  665. // Get the theta value for the
  666. // interval -PI, PI.
  667. // This algorithm for determining the
  668. // theta value is defined by
  669. // | arctan( y / x ) if x > 0
  670. // | arctan( y / x ) if x < 0 and y >= 0
  671. // theta = | arctan( y / x ) if x < 0 and y < 0
  672. // | PI / 2 if x = 0 and y > 0
  673. // | -( PI / 2 ) if x = 0 and y < 0
  674. if ( relPoint.x > 0.0f )
  675. theta = mAtan2( relPoint.y, relPoint.x );
  676. else if ( relPoint.x < 0.0f )
  677. {
  678. if ( relPoint.y >= 0.0f )
  679. theta = mAtan2( relPoint.y, relPoint.x ) + M_PI_F;
  680. else if ( relPoint.y < 0.0f )
  681. theta = mAtan2( relPoint.y, relPoint.x ) - M_PI_F;
  682. }
  683. else if ( relPoint.x == 0.0f )
  684. {
  685. if ( relPoint.y > 0.0f )
  686. theta = M_PI_F / 2.0f;
  687. else if ( relPoint.y < 0.0f )
  688. theta = -(M_PI_F / 2.0f);
  689. }
  690. tmpPoints.push_back( Point4F( pnt.x, pnt.y, pnt.z, theta ) );
  691. }
  692. dQsort( tmpPoints.address(), tmpPoints.size(), sizeof( Point4F ), cmpQuadPointTheta );
  693. for ( U32 i = 0; i < tmpPoints.size(); i++ )
  694. {
  695. const Point4F &tmpPoint = tmpPoints[i];
  696. (*sortPoints)[i].set( tmpPoint.x, tmpPoint.y, tmpPoint.z );
  697. }
  698. }
  699. void DecalManager::_allocBuffers( DecalInstance *inst )
  700. {
  701. inst->mAllocHandle = mChunkers.alloc(sizeof(DecalVertex) * inst->mVertCount + sizeof(U16) * inst->mIndxCount);
  702. U8* data = (U8*)inst->mAllocHandle.ptr;
  703. inst->mVerts = reinterpret_cast< DecalVertex* >( data );
  704. data = (U8*)data + sizeof( DecalVertex ) * inst->mVertCount;
  705. inst->mIndices = reinterpret_cast< U16* >( data );
  706. }
  707. void DecalManager::_freeBuffers( DecalInstance *inst )
  708. {
  709. if ( inst->mVerts != NULL )
  710. {
  711. mChunkers.free(inst->mAllocHandle);
  712. inst->mVerts = NULL;
  713. inst->mVertCount = 0;
  714. inst->mIndices = NULL;
  715. inst->mIndxCount = 0;
  716. }
  717. }
  718. void DecalManager::_freePools()
  719. {
  720. while ( !mVBPool.empty() )
  721. {
  722. delete mVBPool.last();
  723. mVBPool.pop_back();
  724. }
  725. while ( !mVBs.empty() )
  726. {
  727. delete mVBs.last();
  728. mVBs.pop_back();
  729. }
  730. while ( !mPBPool.empty() )
  731. {
  732. delete mPBPool.last();
  733. mPBPool.pop_back();
  734. }
  735. while ( !mPBs.empty() )
  736. {
  737. delete mPBs.last();
  738. mPBs.pop_back();
  739. }
  740. }
  741. void DecalManager::prepRenderImage( SceneRenderState* state )
  742. {
  743. PROFILE_SCOPE( DecalManager_RenderDecals );
  744. if ( !smDecalsOn || !mData )
  745. return;
  746. // Decals only render in the diffuse pass!
  747. // We technically could render them into reflections but prefer to save
  748. // the performance. This would also break the DecalInstance::mLastAlpha
  749. // optimization.
  750. if ( !state->isDiffusePass() )
  751. return;
  752. PROFILE_START( DecalManager_RenderDecals_SphereTreeCull );
  753. const Frustum& rootFrustum = state->getCameraFrustum();
  754. // Populate vector of decal instances to be rendered with all
  755. // decals from visible decal spheres.
  756. SceneManager* sceneManager = state->getSceneManager();
  757. SceneZoneSpaceManager* zoneManager = sceneManager->getZoneManager();
  758. AssertFatal( zoneManager, "DecalManager::prepRenderImage - No zone manager!" );
  759. const Vector<DecalSphere*> &grid = mData->getSphereList();
  760. const bool haveOnlyOutdoorZone = ( zoneManager->getNumActiveZones() == 1 );
  761. mDecalQueue.clear();
  762. for ( U32 i = 0; i < grid.size(); i++ )
  763. {
  764. DecalSphere* decalSphere = grid[i];
  765. const SphereF& worldSphere = decalSphere->mWorldSphere;
  766. // See if this decal sphere can be culled.
  767. const SceneCullingState& cullingState = state->getCullingState();
  768. if( haveOnlyOutdoorZone )
  769. {
  770. U32 outdoorZone = SceneZoneSpaceManager::RootZoneId;
  771. if( cullingState.isCulled( worldSphere, &outdoorZone, 1 ) )
  772. continue;
  773. }
  774. else
  775. {
  776. // Update the zoning state of the sphere, if we need to.
  777. if( decalSphere->mZones.size() == 0 )
  778. decalSphere->updateZoning( zoneManager );
  779. // Skip the sphere if it is not visible in any of its zones.
  780. if( cullingState.isCulled( worldSphere, decalSphere->mZones.address(), decalSphere->mZones.size() ) )
  781. continue;
  782. }
  783. // TODO: If each sphere stored its largest decal instance we
  784. // could do an LOD step on it here and skip adding any of the
  785. // decals in the sphere.
  786. mDecalQueue.merge( decalSphere->mItems );
  787. }
  788. PROFILE_END();
  789. PROFILE_START( DecalManager_RenderDecals_Update );
  790. const U32 &curSimTime = Sim::getCurrentTime();
  791. F32 pixelSize;
  792. U32 delta, diff;
  793. DecalInstance *dinst;
  794. DecalData *ddata;
  795. // Loop through DecalQueue once for preRendering work.
  796. // 1. Update DecalInstance fade (over time)
  797. // 2. Clip geometry if flagged to do so.
  798. // 3. Calculate lod - if decal is far enough away it will not render.
  799. for ( U32 i = 0; i < mDecalQueue.size(); i++ )
  800. {
  801. dinst = mDecalQueue[i];
  802. ddata = dinst->mDataBlock;
  803. // LOD calculation...
  804. pixelSize = dinst->calcPixelSize( state->getViewport().extent.y, state->getCameraPosition(), state->getWorldToScreenScale().y );
  805. if ( pixelSize != F32_MAX && pixelSize < ddata->fadeEndPixelSize )
  806. {
  807. mDecalQueue.erase_fast( i );
  808. i--;
  809. continue;
  810. }
  811. // We will try to render this decal... so do any
  812. // final adjustments to it before rendering.
  813. // Update fade and delete expired.
  814. if ( !( dinst->mFlags & PermanentDecal || dinst->mFlags & CustomDecal ) )
  815. {
  816. delta = ( curSimTime - dinst->mCreateTime );
  817. if ( delta > dinst->mDataBlock->lifeSpan )
  818. {
  819. diff = delta - dinst->mDataBlock->lifeSpan;
  820. dinst->mVisibility = 1.0f - (F32)diff / (F32)dinst->mDataBlock->fadeTime;
  821. if ( dinst->mVisibility <= 0.0f )
  822. {
  823. mDecalQueue.erase_fast( i );
  824. removeDecal( dinst );
  825. i--;
  826. continue;
  827. }
  828. }
  829. }
  830. // Build clipped geometry for this decal if needed.
  831. if ( dinst->mFlags & ClipDecal && !( dinst->mFlags & CustomDecal ) )
  832. {
  833. // Turn off the flag so we don't continually try to clip
  834. // if it fails.
  835. dinst->mFlags = dinst->mFlags & ~ClipDecal;
  836. if ( !(dinst->mFlags & CustomDecal) && !clipDecal( dinst ) )
  837. {
  838. // Clipping failed to get any geometry...
  839. // Remove it from the render queue.
  840. mDecalQueue.erase_fast( i );
  841. i--;
  842. // If the decal is one placed at run-time (not the editor)
  843. // then we should also permanently delete the decal instance.
  844. if ( !(dinst->mFlags & SaveDecal) )
  845. {
  846. removeDecal( dinst );
  847. }
  848. // If this is a decal placed by the editor it will be
  849. // flagged to attempt clipping again the next time it is
  850. // modified. For now we just skip rendering it.
  851. continue;
  852. }
  853. }
  854. // If we get here and the decal still does not have any geometry
  855. // skip rendering it. It must be an editor placed decal that failed
  856. // to clip any geometry but has not yet been flagged to try again.
  857. if ( !dinst->mVerts || dinst->mVertCount == 0 || dinst->mIndxCount == 0 )
  858. {
  859. mDecalQueue.erase_fast( i );
  860. i--;
  861. continue;
  862. }
  863. // Calculate the alpha value for this decal and apply it to the verts.
  864. {
  865. PROFILE_START( DecalManager_RenderDecals_Update_SetAlpha );
  866. F32 alpha = 1.0f;
  867. // Only necessary for decals which fade over time or distance.
  868. if ( !( dinst->mFlags & PermanentDecal ) || dinst->mDataBlock->fadeStartPixelSize >= 0.0f )
  869. {
  870. if ( pixelSize < ddata->fadeStartPixelSize )
  871. {
  872. const F32 range = ddata->fadeStartPixelSize - ddata->fadeEndPixelSize;
  873. alpha = 1.0f - mClampF( ( ddata->fadeStartPixelSize - pixelSize ) / range, 0.0f, 1.0f );
  874. }
  875. alpha *= dinst->mVisibility;
  876. }
  877. // If the alpha value has not changed since last render avoid
  878. // looping through all the verts!
  879. if ( alpha != dinst->mLastAlpha )
  880. {
  881. // calculate the swizzles color once, outside the loop.
  882. GFXVertexColor color;
  883. color.set( 255, 255, 255, (U8)(alpha * 255.0f) );
  884. for ( U32 v = 0; v < dinst->mVertCount; v++ )
  885. dinst->mVerts[v].color = color;
  886. dinst->mLastAlpha = alpha;
  887. }
  888. PROFILE_END();
  889. }
  890. }
  891. PROFILE_END();
  892. if ( mDecalQueue.empty() )
  893. return;
  894. // Sort queued decals...
  895. // 1. Editor decals - in render priority order first, creation time second, and material third.
  896. // 2. Dynamic decals - in render priority order first and creation time second.
  897. //
  898. // With the constraint that decals with different render priority cannot
  899. // be rendered together in the same draw call.
  900. PROFILE_START( DecalManager_RenderDecals_Sort );
  901. dQsort( mDecalQueue.address(), mDecalQueue.size(), sizeof(DecalInstance*), cmpDecalRenderOrder );
  902. PROFILE_END();
  903. PROFILE_SCOPE( DecalManager_RenderDecals_RenderBatch );
  904. RenderPassManager *renderPass = state->getRenderPass();
  905. // Base render instance we use for convenience.
  906. // Data shared by all instances we allocate below can be copied
  907. // from the base instance at the same time.
  908. MeshRenderInst baseRenderInst;
  909. baseRenderInst.clear();
  910. MatrixF *tempMat = renderPass->allocUniqueXform( MatrixF( true ) );
  911. MathUtils::getZBiasProjectionMatrix( gDecalBias, rootFrustum, tempMat );
  912. baseRenderInst.projection = tempMat;
  913. baseRenderInst.objectToWorld = &MatrixF::Identity;
  914. baseRenderInst.worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
  915. baseRenderInst.type = RenderPassManager::RIT_Decal;
  916. // Make it the sort distance the max distance so that
  917. // it renders after all the other opaque geometry in
  918. // the deferred bin.
  919. baseRenderInst.sortDistSq = F32_MAX;
  920. Vector<DecalBatch> batches;
  921. DecalBatch *currentBatch = NULL;
  922. // Loop through DecalQueue collecting them into render batches.
  923. for ( U32 i = 0; i < mDecalQueue.size(); i++ )
  924. {
  925. DecalInstance *decal = mDecalQueue[i];
  926. DecalData *data = decal->mDataBlock;
  927. Material *mat = data->getMaterialDefinition();
  928. if ( currentBatch == NULL )
  929. {
  930. // Start a new batch, beginning with this decal.
  931. batches.increment();
  932. currentBatch = &batches.last();
  933. currentBatch->startDecal = i;
  934. currentBatch->decalCount = 1;
  935. // Shrink and warning: preventing a potential crash.
  936. currentBatch->iCount =
  937. (decal->mIndxCount > smMaxIndices) ? smMaxIndices : decal->mIndxCount;
  938. currentBatch->vCount =
  939. (decal->mVertCount > smMaxVerts) ? smMaxVerts : decal->mVertCount;
  940. #ifdef TORQUE_DEBUG
  941. // we didn't mean send a spam to the console
  942. static U32 countMsgIndx = 0;
  943. if ( (decal->mIndxCount > smMaxIndices) && ((countMsgIndx++ % 1024) == 0) ) {
  944. Con::warnf(
  945. "DecalManager::prepRenderImage() - Shrinked indices of decal."
  946. " Lost %u.", (decal->mIndxCount - smMaxIndices)
  947. );
  948. }
  949. static U32 countMsgVert = 0;
  950. if ( (decal->mVertCount > smMaxVerts) && ((countMsgVert++ % 1024) == 0) ) {
  951. Con::warnf(
  952. "DecalManager::prepRenderImage() - Shrinked vertices of decal."
  953. " Lost %u.", (decal->mVertCount - smMaxVerts)
  954. );
  955. }
  956. #endif
  957. currentBatch->mat = mat;
  958. currentBatch->matInst = decal->mDataBlock->getMaterialInstance();
  959. currentBatch->priority = decal->getRenderPriority();
  960. currentBatch->dynamic = !(decal->mFlags & SaveDecal);
  961. continue;
  962. }
  963. if ( currentBatch->iCount + decal->mIndxCount >= smMaxIndices ||
  964. currentBatch->vCount + decal->mVertCount >= smMaxVerts ||
  965. currentBatch->mat != mat ||
  966. currentBatch->priority != decal->getRenderPriority() ||
  967. decal->mCustomTex )
  968. {
  969. // End batch.
  970. currentBatch = NULL;
  971. i--;
  972. continue;
  973. }
  974. // Add on to current batch.
  975. currentBatch->decalCount++;
  976. currentBatch->iCount += decal->mIndxCount;
  977. currentBatch->vCount += decal->mVertCount;
  978. }
  979. // Make sure our primitive and vertex buffer handle storage is
  980. // big enough to take all batches. Doing this now avoids reallocation
  981. // later on which would invalidate all the pointers we already had
  982. // passed into render instances.
  983. //mPBs.reserve( batches.size() );
  984. //mVBs.reserve( batches.size() );
  985. // System memory array of verts and indices so we can fill them incrementally
  986. // and then memcpy to the graphics device buffers in one call.
  987. static DecalVertex vertData[smMaxVerts];
  988. static U16 indexData[smMaxIndices];
  989. // Loop through batches allocating buffers and submitting render instances.
  990. for ( U32 i = 0; i < batches.size(); i++ )
  991. {
  992. currentBatch = &batches[i];
  993. // Copy data into the system memory arrays, from all decals in this batch...
  994. DecalVertex *vpPtr = vertData;
  995. U16 *pbPtr = indexData;
  996. U32 lastDecal = currentBatch->startDecal + currentBatch->decalCount;
  997. U32 voffset = 0;
  998. U32 ioffset = 0;
  999. // This is an ugly hack for ProjectedShadow!
  1000. GFXTextureObject *customTex = NULL;
  1001. for ( U32 j = currentBatch->startDecal; j < lastDecal; j++ )
  1002. {
  1003. dinst = mDecalQueue[j];
  1004. const U32 indxCount =
  1005. (dinst->mIndxCount > currentBatch->iCount) ?
  1006. currentBatch->iCount : dinst->mIndxCount;
  1007. for ( U32 k = 0; k < indxCount; k++ )
  1008. {
  1009. *( pbPtr + ioffset + k ) = dinst->mIndices[k] + voffset;
  1010. }
  1011. ioffset += indxCount;
  1012. const U32 vertCount =
  1013. (dinst->mVertCount > currentBatch->vCount) ?
  1014. currentBatch->vCount : dinst->mVertCount;
  1015. dMemcpy( vpPtr + voffset, dinst->mVerts, sizeof( DecalVertex ) * vertCount );
  1016. voffset += vertCount;
  1017. // Ugly hack for ProjectedShadow!
  1018. if ( (dinst->mFlags & CustomDecal) && dinst->mCustomTex != NULL )
  1019. customTex = *dinst->mCustomTex;
  1020. }
  1021. AssertFatal( ioffset == currentBatch->iCount, "bad" );
  1022. AssertFatal( voffset == currentBatch->vCount, "bad" );
  1023. // Get handles to video memory buffers we will be filling...
  1024. GFXVertexBufferHandle<DecalVertex> *vb = NULL;
  1025. if ( mVBPool.empty() )
  1026. {
  1027. // If the Pool is empty allocate a new one.
  1028. vb = new GFXVertexBufferHandle<DecalVertex>;
  1029. vb->set( GFX, smMaxVerts, GFXBufferTypeDynamic );
  1030. }
  1031. else
  1032. {
  1033. // Otherwise grab from the pool.
  1034. vb = mVBPool.last();
  1035. mVBPool.pop_back();
  1036. }
  1037. // Push into our vector of 'in use' buffers.
  1038. mVBs.push_back( vb );
  1039. // Ready to start filling.
  1040. vpPtr = vb->lock();
  1041. // Same deal as above...
  1042. GFXPrimitiveBufferHandle *pb = NULL;
  1043. if ( mPBPool.empty() )
  1044. {
  1045. pb = new GFXPrimitiveBufferHandle;
  1046. pb->set( GFX, smMaxIndices, 0, GFXBufferTypeDynamic );
  1047. }
  1048. else
  1049. {
  1050. pb = mPBPool.last();
  1051. mPBPool.pop_back();
  1052. }
  1053. mPBs.push_back( pb );
  1054. pb->lock( &pbPtr );
  1055. // Memcpy from system to video memory.
  1056. const U32 vpCount = sizeof( DecalVertex ) * currentBatch->vCount;
  1057. dMemcpy( vpPtr, vertData, vpCount );
  1058. const U32 pbCount = sizeof( U16 ) * currentBatch->iCount;
  1059. dMemcpy( pbPtr, indexData, pbCount );
  1060. pb->unlock();
  1061. vb->unlock();
  1062. // DecalManager must hold handles to these buffers so they remain valid,
  1063. // we don't actually use them elsewhere.
  1064. //mPBs.push_back( pb );
  1065. //mVBs.push_back( vb );
  1066. // Get the best lights for the current camera position
  1067. // if the materail is forward lit and we haven't got them yet.
  1068. if ( currentBatch->matInst->isForwardLit() && !baseRenderInst.lights[0] )
  1069. {
  1070. LightQuery query;
  1071. query.init( rootFrustum.getPosition(),
  1072. rootFrustum.getTransform().getForwardVector(),
  1073. rootFrustum.getFarDist() );
  1074. query.getLights( baseRenderInst.lights, 8 );
  1075. }
  1076. // Submit render inst...
  1077. MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
  1078. *ri = baseRenderInst;
  1079. ri->primBuff = pb;
  1080. ri->vertBuff = vb;
  1081. ri->matInst = currentBatch->matInst;
  1082. ri->prim = renderPass->allocPrim();
  1083. ri->prim->type = GFXTriangleList;
  1084. ri->prim->minIndex = 0;
  1085. ri->prim->startIndex = 0;
  1086. ri->prim->numPrimitives = currentBatch->iCount / 3;
  1087. ri->prim->startVertex = 0;
  1088. ri->prim->numVertices = currentBatch->vCount;
  1089. ri->translucentSort = !currentBatch->matInst->getMaterial()->isTranslucent();
  1090. // Ugly hack for ProjectedShadow!
  1091. if ( customTex )
  1092. ri->miscTex = customTex;
  1093. // The decal bin will contain render instances for both decals and decalRoad's.
  1094. // Dynamic decals render last, then editor decals and roads in priority order.
  1095. // DefaultKey is sorted in descending order.
  1096. ri->defaultKey = currentBatch->dynamic ? 0xFFFFFFFF : (U32)currentBatch->priority;
  1097. ri->defaultKey2 = 1;//(U32)lastDecal->mDataBlock;
  1098. renderPass->addInst( ri );
  1099. }
  1100. #ifdef TORQUE_GATHER_METRICS
  1101. Con::setIntVariable( "$Decal::Batches", batches.size() );
  1102. Con::setIntVariable( "$Decal::Buffers", mPBs.size() + mPBPool.size() );
  1103. Con::setIntVariable( "$Decal::DecalsRendered", mDecalQueue.size() );
  1104. #endif
  1105. if( smDebugRender && gEditingMission )
  1106. {
  1107. ObjectRenderInst* ri = state->getRenderPass()->allocInst< ObjectRenderInst >();
  1108. ri->renderDelegate.bind( this, &DecalManager::_renderDecalSpheres );
  1109. ri->type = RenderPassManager::RIT_Editor;
  1110. ri->defaultKey = 0;
  1111. ri->defaultKey2 = 0;
  1112. state->getRenderPass()->addInst( ri );
  1113. }
  1114. }
  1115. void DecalManager::_renderDecalSpheres( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat )
  1116. {
  1117. if( !mData )
  1118. return;
  1119. const Vector<DecalSphere*> &grid = mData->getSphereList();
  1120. GFXDrawUtil *drawUtil = GFX->getDrawUtil();
  1121. ColorI sphereColor( 0, 255, 0, 45 );
  1122. GFXStateBlockDesc desc;
  1123. desc.setBlend( true );
  1124. desc.setZReadWrite( true, false );
  1125. desc.setCullMode( GFXCullNone );
  1126. for ( U32 i = 0; i < grid.size(); i++ )
  1127. {
  1128. DecalSphere *decalSphere = grid[i];
  1129. const SphereF &worldSphere = decalSphere->mWorldSphere;
  1130. if( state->getCullingFrustum().isCulled( worldSphere ) )
  1131. continue;
  1132. drawUtil->drawSphere( desc, worldSphere.radius, worldSphere.center, sphereColor );
  1133. }
  1134. }
  1135. bool DecalManager::_createDataFile()
  1136. {
  1137. AssertFatal( !mData, "DecalManager::tried to create duplicate data file?" );
  1138. // We need to construct a default file name
  1139. char fileName[1024];
  1140. fileName[0] = 0;
  1141. // See if we know our current mission name
  1142. char missionName[1024];
  1143. dStrcpy( missionName, Con::getVariable( "$Client::MissionFile" ), 1024 );
  1144. char *dot = dStrstr((const char*)missionName, ".mis");
  1145. if(dot)
  1146. *dot = '\0';
  1147. dSprintf( fileName, sizeof(fileName), "%s.mis.decals", missionName );
  1148. mDataFileName = StringTable->insert( fileName );
  1149. // If the file doesn't exist, create an empty file.
  1150. if( !Torque::FS::IsFile( fileName ) )
  1151. {
  1152. FileStream stream;
  1153. if( stream.open( mDataFileName, Torque::FS::File::Write ) )
  1154. {
  1155. DecalDataFile dataFile;
  1156. dataFile.write( stream );
  1157. }
  1158. }
  1159. mData = ResourceManager::get().load( mDataFileName );
  1160. return (bool)mData;
  1161. }
  1162. void DecalManager::saveDecals( const UTF8* fileName )
  1163. {
  1164. if( !mData )
  1165. return;
  1166. // Create the file.
  1167. FileStream stream;
  1168. if ( !stream.open( fileName, Torque::FS::File::Write ) )
  1169. {
  1170. Con::errorf( "DecalManager::saveDecals - Could not open '%s' for writing!", fileName );
  1171. return;
  1172. }
  1173. // Write the data.
  1174. if( !mData->write( stream ) )
  1175. {
  1176. Con::errorf( "DecalManager::saveDecals - Failed to write '%s'", fileName );
  1177. return;
  1178. }
  1179. mDirty = false;
  1180. }
  1181. bool DecalManager::loadDecals( const UTF8 *fileName )
  1182. {
  1183. if( mData )
  1184. clearData();
  1185. mData = ResourceManager::get().load( fileName );
  1186. mDirty = false;
  1187. return mData != NULL;
  1188. }
  1189. void DecalManager::clearData()
  1190. {
  1191. mClearDataSignal.trigger();
  1192. // Free all geometry buffers.
  1193. if( mData )
  1194. {
  1195. const Vector< DecalSphere* > grid = mData->getSphereList();
  1196. for( U32 i = 0; i < grid.size(); ++ i )
  1197. {
  1198. DecalSphere* sphere = grid[ i ];
  1199. for( U32 n = 0; n < sphere->mItems.size(); ++ n )
  1200. _freeBuffers( sphere->mItems[ n ] );
  1201. }
  1202. }
  1203. mData = NULL;
  1204. mDecalInstanceVec.clear();
  1205. _freePools();
  1206. }
  1207. bool DecalManager::onSceneAdd()
  1208. {
  1209. if( !Parent::onSceneAdd() )
  1210. return false;
  1211. SceneZoneSpaceManager::getZoningChangedSignal().notify( this, &DecalManager::_handleZoningChangedEvent );
  1212. return true;
  1213. }
  1214. void DecalManager::onSceneRemove()
  1215. {
  1216. SceneZoneSpaceManager::getZoningChangedSignal().remove( this, &DecalManager::_handleZoningChangedEvent );
  1217. Parent::onSceneRemove();
  1218. }
  1219. void DecalManager::_handleZoningChangedEvent( SceneZoneSpaceManager* zoneManager )
  1220. {
  1221. if( zoneManager != getSceneManager()->getZoneManager() || !getDecalDataFile() )
  1222. return;
  1223. // Clear the zoning state of all DecalSpheres in the data file.
  1224. const Vector< DecalSphere* > grid = getDecalDataFile()->getSphereList();
  1225. const U32 numSpheres = grid.size();
  1226. for( U32 i = 0; i < numSpheres; ++ i )
  1227. grid[ i ]->mZones.clear();
  1228. }
  1229. DefineEngineFunction( decalManagerSave, void, ( String decalSaveFile ), ( "" ),
  1230. "Saves the decals for the active mission in the entered filename.\n"
  1231. "@param decalSaveFile Filename to save the decals to.\n"
  1232. "@tsexample\n"
  1233. "// Set the filename to save the decals in. If no filename is set, then the\n"
  1234. "// decals will default to <activeMissionName>.mis.decals\n"
  1235. "%fileName = \"./missionDecals.mis.decals\";\n"
  1236. "// Inform the decal manager to save the decals for the active mission.\n"
  1237. "decalManagerSave( %fileName );\n"
  1238. "@endtsexample\n"
  1239. "@ingroup Decals" )
  1240. {
  1241. // If not given a file name, synthesize one.
  1242. if( decalSaveFile.isEmpty() )
  1243. {
  1244. String fileName = String::ToString( "%s.decals", Con::getVariable( "$Client::MissionFile" ) );
  1245. char fullName[ 4096 ];
  1246. Platform::makeFullPathName( fileName, fullName, sizeof( fullName ) );
  1247. decalSaveFile = String( fullName );
  1248. }
  1249. // Write the data.
  1250. gDecalManager->saveDecals( decalSaveFile );
  1251. }
  1252. DefineEngineFunction( decalManagerLoad, bool, ( const char* fileName ),,
  1253. "Clears existing decals and replaces them with decals loaded from the specified file.\n"
  1254. "@param fileName Filename to load the decals from.\n"
  1255. "@return True if the decal manager was able to load the requested file, "
  1256. "false if it could not.\n"
  1257. "@tsexample\n"
  1258. "// Set the filename to load the decals from.\n"
  1259. "%fileName = \"./missionDecals.mis.decals\";\n"
  1260. "// Inform the decal manager to load the decals from the entered filename.\n"
  1261. "decalManagerLoad( %fileName );\n"
  1262. "@endtsexample\n"
  1263. "@ingroup Decals" )
  1264. {
  1265. return gDecalManager->loadDecals( fileName );
  1266. }
  1267. DefineEngineFunction( decalManagerDirty, bool, (),,
  1268. "Returns whether the decal manager has unsaved modifications.\n"
  1269. "@return True if the decal manager has unsaved modifications, false if "
  1270. "everything has been saved.\n"
  1271. "@tsexample\n"
  1272. "// Ask the decal manager if it has unsaved modifications.\n"
  1273. "%hasUnsavedModifications = decalManagerDirty();\n"
  1274. "@endtsexample\n"
  1275. "@ingroup Decals" )
  1276. {
  1277. return gDecalManager->isDirty();
  1278. }
  1279. DefineEngineFunction( decalManagerClear, void, (),,
  1280. "Removes all decals currently loaded in the decal manager.\n"
  1281. "@tsexample\n"
  1282. "// Tell the decal manager to remove all existing decals.\n"
  1283. "decalManagerClear();\n"
  1284. "@endtsexample\n"
  1285. "@ingroup Decals" )
  1286. {
  1287. gDecalManager->clearData();
  1288. }
  1289. DefineEngineFunction( decalManagerAddDecal, S32,
  1290. ( Point3F position, Point3F normal, F32 rot, F32 scale, DecalData* decalData, bool isImmortal), ( false ),
  1291. "Adds a new decal to the decal manager.\n"
  1292. "@param position World position for the decal.\n"
  1293. "@param normal Decal normal vector (if the decal was a tire lying flat on a "
  1294. "surface, this is the vector pointing in the direction of the axle).\n"
  1295. "@param rot Angle (in radians) to rotate this decal around its normal vector.\n"
  1296. "@param scale Scale factor applied to the decal.\n"
  1297. "@param decalData DecalData datablock to use for the new decal.\n"
  1298. "@param isImmortal Whether or not this decal is immortal. If immortal, it "
  1299. "does not expire automatically and must be removed explicitly.\n"
  1300. "@return Returns the ID of the new Decal object or -1 on failure.\n"
  1301. "@tsexample\n"
  1302. "// Specify the decal position\n"
  1303. "%position = \"1.0 1.0 1.0\";\n\n"
  1304. "// Specify the up vector\n"
  1305. "%normal = \"0.0 0.0 1.0\";\n\n"
  1306. "// Add the new decal.\n"
  1307. "%decalObj = decalManagerAddDecal( %position, %normal, 0.5, 0.35, ScorchBigDecal, false );\n"
  1308. "@endtsexample\n"
  1309. "@ingroup Decals" )
  1310. {
  1311. if( !decalData )
  1312. {
  1313. Con::errorf( "decalManagerAddDecal - Invalid Decal DataBlock" );
  1314. return -1;
  1315. }
  1316. U8 flags = 0;
  1317. if( isImmortal )
  1318. flags |= PermanentDecal;
  1319. DecalInstance* inst = gDecalManager->addDecal( position, normal, rot, decalData, scale, -1, flags );
  1320. if( !inst )
  1321. {
  1322. Con::errorf( "decalManagerAddDecal - Unable to create decal instance." );
  1323. return -1;
  1324. }
  1325. // Add the decal to the instance vector.
  1326. inst->mId = gDecalManager->mDecalInstanceVec.size();
  1327. gDecalManager->mDecalInstanceVec.push_back( inst );
  1328. return inst->mId;
  1329. }
  1330. DefineEngineFunction( decalManagerRemoveDecal, bool, ( S32 decalID ),,
  1331. "Remove specified decal from the scene.\n"
  1332. "@param decalID ID of the decal to remove.\n"
  1333. "@return Returns true if successful, false if decal ID not found.\n"
  1334. "@tsexample\n"
  1335. "// Specify a decal ID to be removed\n"
  1336. "%decalID = 1;\n\n"
  1337. "// Tell the decal manager to remove the specified decal ID.\n"
  1338. "decalManagerRemoveDecal( %decalId )\n"
  1339. "@endtsexample\n"
  1340. "@ingroup Decals" )
  1341. {
  1342. DecalInstance *inst = gDecalManager->getDecal( decalID );
  1343. if( !inst )
  1344. return false;
  1345. gDecalManager->removeDecal(inst);
  1346. return true;
  1347. }
  1348. DefineEngineFunction( decalManagerEditDecal, bool, ( S32 decalID, Point3F pos, Point3F normal, F32 rotAroundNormal, F32 decalScale ),,
  1349. "Edit specified decal of the decal manager.\n"
  1350. "@param decalID ID of the decal to edit.\n"
  1351. "@param pos World position for the decal.\n"
  1352. "@param normal Decal normal vector (if the decal was a tire lying flat on a "
  1353. "surface, this is the vector pointing in the direction of the axle).\n"
  1354. "@param rotAroundNormal Angle (in radians) to rotate this decal around its normal vector.\n"
  1355. "@param decalScale Scale factor applied to the decal.\n"
  1356. "@return Returns true if successful, false if decalID not found.\n"
  1357. "" )
  1358. {
  1359. DecalInstance *decalInstance = gDecalManager->getDecal( decalID );
  1360. if( !decalInstance )
  1361. return false;
  1362. //Internally we need Point3F tangent instead of the user friendly F32 rotAroundNormal
  1363. MatrixF mat( true );
  1364. MathUtils::getMatrixFromUpVector( normal, &mat );
  1365. AngAxisF rot( normal, rotAroundNormal );
  1366. MatrixF rotmat;
  1367. rot.setMatrix( &rotmat );
  1368. mat.mul( rotmat );
  1369. Point3F tangent;
  1370. mat.getColumn( 1, &tangent );
  1371. //if everything is unchanged just do nothing and return "everything is ok"
  1372. if ( pos.equal(decalInstance->mPosition) &&
  1373. normal.equal(decalInstance->mNormal) &&
  1374. tangent.equal(decalInstance->mTangent) &&
  1375. mFabs( decalInstance->mSize - (decalInstance->mDataBlock->size * decalScale) ) < POINT_EPSILON )
  1376. return true;
  1377. decalInstance->mPosition = pos;
  1378. decalInstance->mNormal = normal;
  1379. decalInstance->mTangent = tangent;
  1380. decalInstance->mSize = decalInstance->mDataBlock->size * decalScale;
  1381. gDecalManager->clipDecal( decalInstance, NULL, NULL);
  1382. gDecalManager->notifyDecalModified( decalInstance );
  1383. return true;
  1384. }