decalManager.cpp 55 KB

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