tsLastDetail.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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 "ts/tsLastDetail.h"
  24. #include "renderInstance/renderPassManager.h"
  25. #include "ts/tsShapeInstance.h"
  26. #include "scene/sceneManager.h"
  27. #include "scene/sceneRenderState.h"
  28. #include "lighting/lightInfo.h"
  29. #include "renderInstance/renderImposterMgr.h"
  30. #include "gfx/gfxTransformSaver.h"
  31. #include "gfx/bitmap/ddsFile.h"
  32. #include "gfx/bitmap/imageUtils.h"
  33. #include "gfx/gfxTextureManager.h"
  34. #include "math/mRandom.h"
  35. #include "core/stream/fileStream.h"
  36. #include "util/imposterCapture.h"
  37. #include "materials/materialManager.h"
  38. #include "materials/materialFeatureTypes.h"
  39. #include "console/consoleTypes.h"
  40. #include "console/engineAPI.h"
  41. GFXImplementVertexFormat( ImposterState )
  42. {
  43. addElement( "POSITION", GFXDeclType_Float4 );
  44. addElement( "ImposterParams", GFXDeclType_Float2, 0 );
  45. addElement( "ImposterUpVec", GFXDeclType_Float3, 1 );
  46. addElement( "ImposterRightVec", GFXDeclType_Float3, 2 );
  47. };
  48. Vector<TSLastDetail*> TSLastDetail::smLastDetails;
  49. bool TSLastDetail::smCanShadow = true;
  50. AFTER_MODULE_INIT( Sim )
  51. {
  52. Con::addVariable( "$pref::imposter::canShadow", TypeBool, &TSLastDetail::smCanShadow,
  53. "User preference which toggles shadows from imposters. Defaults to true.\n"
  54. "@ingroup Rendering\n" );
  55. }
  56. TSLastDetail::TSLastDetail( TSShape *shape,
  57. const String &cachePath,
  58. U32 numEquatorSteps,
  59. U32 numPolarSteps,
  60. F32 polarAngle,
  61. bool includePoles,
  62. S32 dl, S32 dim )
  63. {
  64. mNumEquatorSteps = getMax( numEquatorSteps, (U32)1 );
  65. mNumPolarSteps = numPolarSteps;
  66. mPolarAngle = polarAngle;
  67. mIncludePoles = includePoles;
  68. mShape = shape;
  69. mDl = dl;
  70. mDim = getMax( dim, (S32)32 );
  71. mRadius = mShape->mRadius;
  72. mCenter = mShape->center;
  73. mCachePath = cachePath;
  74. mDiffusePath = mCachePath + "_imposter.dds";
  75. mNormalPath = mCachePath + "_imposter_normals.dds";
  76. mMaterial = NULL;
  77. mMatInstance = NULL;
  78. // Store this in the static list.
  79. smLastDetails.push_back( this );
  80. }
  81. TSLastDetail::TSLastDetail(TSShape* shape,
  82. const String& cachePath,
  83. const String& diffusePath,
  84. const String& normalPath,
  85. U32 numEquatorSteps,
  86. U32 numPolarSteps,
  87. F32 polarAngle,
  88. bool includePoles,
  89. S32 dl, S32 dim)
  90. {
  91. mNumEquatorSteps = getMax(numEquatorSteps, (U32)1);
  92. mNumPolarSteps = numPolarSteps;
  93. mPolarAngle = polarAngle;
  94. mIncludePoles = includePoles;
  95. mShape = shape;
  96. mDl = dl;
  97. mDim = getMax(dim, (S32)32);
  98. mRadius = mShape->mRadius;
  99. mCenter = mShape->center;
  100. mCachePath = cachePath;
  101. mDiffusePath = diffusePath;
  102. mNormalPath = normalPath;
  103. mMaterial = NULL;
  104. mMatInstance = NULL;
  105. // Store this in the static list.
  106. smLastDetails.push_back(this);
  107. }
  108. TSLastDetail::~TSLastDetail()
  109. {
  110. SAFE_DELETE( mMatInstance );
  111. if ( mMaterial )
  112. mMaterial->deleteObject();
  113. // Remove ourselves from the list.
  114. Vector<TSLastDetail*>::iterator iter = T3D::find( smLastDetails.begin(), smLastDetails.end(), this );
  115. smLastDetails.erase( iter );
  116. }
  117. void TSLastDetail::render( const TSRenderState &rdata, F32 alpha )
  118. {
  119. // Early out if we have nothing to render.
  120. if ( alpha < 0.01f ||
  121. !mMatInstance ||
  122. mMaterial->mImposterUVs.size() == 0 )
  123. return;
  124. const MatrixF &mat = GFX->getWorldMatrix();
  125. // Post a render instance for this imposter... the special
  126. // imposter render manager will do the magic!
  127. RenderPassManager *renderPass = rdata.getSceneState()->getRenderPass();
  128. ImposterRenderInst *ri = renderPass->allocInst<ImposterRenderInst>();
  129. ri->mat = rdata.getSceneState()->getOverrideMaterial( mMatInstance );
  130. ri->state.alpha = alpha;
  131. // Store the up and right vectors of the rotation
  132. // and we'll generate the up vector in the shader.
  133. //
  134. // This is faster than building a quat on the
  135. // CPU and then rebuilding the matrix on the GPU.
  136. //
  137. // NOTE: These vector include scale.
  138. //
  139. mat.getColumn( 2, &ri->state.upVec );
  140. mat.getColumn( 0, &ri->state.rightVec );
  141. // We send the unscaled size and the vertex shader
  142. // will use the orientation vectors above to scale it.
  143. ri->state.halfSize = mRadius;
  144. // We use the center of the object bounds for
  145. // the center of the billboard quad.
  146. mat.mulP( mCenter, &ri->state.center );
  147. // We sort by the imposter type first so that RIT_Imposter and s
  148. // RIT_ImposterBatches do not get mixed together.
  149. //
  150. // We then sort by material.
  151. //
  152. ri->defaultKey = 1;
  153. ri->defaultKey2 = ri->mat->getStateHint();
  154. renderPass->addInst( ri );
  155. }
  156. void TSLastDetail::update( bool forceUpdate )
  157. {
  158. // This should never be called on a dedicated server or
  159. // anywhere else where we don't have a GFX device!
  160. AssertFatal( GFXDevice::devicePresent(), "TSLastDetail::update() - Cannot update without a GFX device!" );
  161. // Clear the materialfirst.
  162. SAFE_DELETE( mMatInstance );
  163. if ( mMaterial )
  164. {
  165. mMaterial->deleteObject();
  166. mMaterial = NULL;
  167. }
  168. // Make sure imposter textures have been flushed (and not just queued for deletion)
  169. TEXMGR->cleanupCache();
  170. // Get the real path to the source shape for doing modified time
  171. // comparisons... this might be different if the DAEs have been
  172. // deleted from the install.
  173. String shapeFile( mCachePath );
  174. if ( !Torque::FS::IsFile( shapeFile ) )
  175. {
  176. Torque::Path path(shapeFile);
  177. path.setExtension("cached.dts");
  178. shapeFile = path.getFullPath();
  179. if ( !Torque::FS::IsFile( shapeFile ) )
  180. {
  181. Con::errorf( "TSLastDetail::update - '%s' could not be found!", mCachePath.c_str() );
  182. return;
  183. }
  184. }
  185. // Do we need to update the imposter?
  186. const String diffuseMapPath = _getDiffuseMapPath();
  187. bool isFile = Platform::isFile(diffuseMapPath.c_str());
  188. if ( forceUpdate || !Platform::isFile(diffuseMapPath.c_str()) ||
  189. Platform::compareModifiedTimes( diffuseMapPath, shapeFile ) <= 0 )
  190. _update();
  191. // If the time check fails now then the update must have not worked.
  192. if ( Platform::compareModifiedTimes( diffuseMapPath, shapeFile ) < 0 )
  193. {
  194. Con::errorf( "TSLastDetail::update - Failed to create imposters for '%s'!", mCachePath.c_str() );
  195. return;
  196. }
  197. // Figure out what our vertex format will be.
  198. //
  199. // If we're on SM 3.0 we can do multiple vertex streams
  200. // and the performance win is big as we send 3x less data
  201. // on each imposter instance.
  202. //
  203. // The problem is SM 2.0 won't do this, so we need to
  204. // support fallback to regular single stream imposters.
  205. //
  206. //mImposterVertDecl.copy( *getGFXVertexFormat<ImposterCorner>() );
  207. //mImposterVertDecl.append( *getGFXVertexFormat<ImposterState>(), 1 );
  208. //mImposterVertDecl.getDecl();
  209. mImposterVertDecl.clear();
  210. mImposterVertDecl.copy( *getGFXVertexFormat<ImposterState>() );
  211. // Setup the material for this imposter.
  212. mMaterial = MATMGR->allocateAndRegister( String::EmptyString );
  213. mMaterial->mAutoGenerated = true;
  214. mMaterial->setDiffuseMapFile(diffuseMapPath, 0);
  215. mMaterial->setNormalMapFile(_getNormalMapPath(), 0);
  216. mMaterial->mImposterLimits.set( (mNumPolarSteps * 2) + 1, mNumEquatorSteps, mPolarAngle, mIncludePoles );
  217. mMaterial->mTranslucent = true;
  218. mMaterial->mTranslucentBlendOp = Material::None;
  219. mMaterial->mTranslucentZWrite = true;
  220. mMaterial->mDoubleSided = true;
  221. mMaterial->mAlphaTest = true;
  222. mMaterial->mAlphaRef = 84;
  223. // Create the material instance.
  224. FeatureSet features = MATMGR->getDefaultFeatures();
  225. features.addFeature( MFT_ImposterVert );
  226. mMatInstance = mMaterial->createMatInstance();
  227. if ( !mMatInstance->init( features, &mImposterVertDecl ) )
  228. {
  229. delete mMatInstance;
  230. mMatInstance = NULL;
  231. }
  232. // Get the diffuse texture and from its size and
  233. // the imposter dimensions we can generate the UVs.
  234. GFXTexHandle diffuseTex( diffuseMapPath, &GFXStaticTextureSRGBProfile, String::EmptyString );
  235. Point2I texSize( diffuseTex->getWidth(), diffuseTex->getHeight() );
  236. _validateDim();
  237. S32 downscaledDim = mDim >> GFXTextureManager::getTextureDownscalePower(&GFXStaticTextureSRGBProfile);
  238. // Ok... pack in bitmaps till we run out.
  239. Vector<RectF> imposterUVs;
  240. for ( S32 y=0; y+downscaledDim <= texSize.y; )
  241. {
  242. for ( S32 x=0; x+downscaledDim <= texSize.x; )
  243. {
  244. // Store the uv for later lookup.
  245. RectF info;
  246. info.point.set( (F32)x / (F32)texSize.x, (F32)y / (F32)texSize.y );
  247. info.extent.set( (F32)downscaledDim / (F32)texSize.x, (F32)downscaledDim / (F32)texSize.y );
  248. imposterUVs.push_back( info );
  249. x += downscaledDim;
  250. }
  251. y += downscaledDim;
  252. }
  253. AssertFatal( imposterUVs.size() != 0, "hey" );
  254. mMaterial->mImposterUVs = imposterUVs;
  255. }
  256. void TSLastDetail::_validateDim()
  257. {
  258. // Loop till they fit.
  259. S32 newDim = mDim;
  260. while ( true )
  261. {
  262. S32 maxImposters = ( smMaxTexSize / newDim ) * ( smMaxTexSize / newDim );
  263. S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 );
  264. if ( imposterCount <= maxImposters )
  265. break;
  266. // There are too many imposters to fit a single
  267. // texture, so we fail. These imposters are for
  268. // rendering small distant objects. If you need
  269. // a really high resolution imposter or many images
  270. // around the equator and poles, maybe you need a
  271. // custom solution.
  272. newDim /= 2;
  273. }
  274. if ( newDim != mDim )
  275. {
  276. Con::printf( "TSLastDetail::_validateDim - '%s' detail dimensions too big! Reduced from %d to %d.",
  277. mCachePath.c_str(),
  278. mDim, newDim );
  279. mDim = newDim;
  280. }
  281. }
  282. void TSLastDetail::_update()
  283. {
  284. // We're gonna render... make sure we can.
  285. bool sceneBegun = GFX->canCurrentlyRender();
  286. if ( !sceneBegun )
  287. GFX->beginScene();
  288. _validateDim();
  289. Vector<GBitmap*> bitmaps;
  290. Vector<GBitmap*> normalmaps;
  291. // We need to create our own instance to render with.
  292. TSShapeInstance *shape = new TSShapeInstance( mShape, true );
  293. // Animate the shape once.
  294. shape->animate( mDl );
  295. // So we don't have to change it everywhere.
  296. const GFXFormat format = GFXFormatR8G8B8A8;
  297. S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 );
  298. // Figure out the optimal texture size.
  299. Point2I texSize( smMaxTexSize, smMaxTexSize );
  300. while ( true )
  301. {
  302. Point2I halfSize( texSize.x / 2, texSize.y / 2 );
  303. U32 count = ( halfSize.x / mDim ) * ( halfSize.y / mDim );
  304. if ( count < imposterCount )
  305. {
  306. // Try half of the height.
  307. count = ( texSize.x / mDim ) * ( halfSize.y / mDim );
  308. if ( count >= imposterCount )
  309. texSize.y = halfSize.y;
  310. break;
  311. }
  312. texSize = halfSize;
  313. }
  314. GBitmap *imposter = NULL;
  315. GBitmap *normalmap = NULL;
  316. GBitmap destBmp( texSize.x, texSize.y, true, format );
  317. GBitmap destNormal( texSize.x, texSize.y, true, format );
  318. U32 mipLevels = destBmp.getNumMipLevels();
  319. ImposterCapture *imposterCap = new ImposterCapture();
  320. F32 equatorStepSize = M_2PI_F / (F32)mNumEquatorSteps;
  321. static const MatrixF topXfm( EulerF( -M_PI_F / 2.0f, 0, 0 ) );
  322. static const MatrixF bottomXfm( EulerF( M_PI_F / 2.0f, 0, 0 ) );
  323. MatrixF angMat;
  324. F32 polarStepSize = 0.0f;
  325. if ( mNumPolarSteps > 0 )
  326. polarStepSize = -( 0.5f * M_PI_F - mDegToRad( mPolarAngle ) ) / (F32)mNumPolarSteps;
  327. PROFILE_START(TSLastDetail_snapshots);
  328. S32 currDim = mDim;
  329. for ( S32 mip = 0; mip < mipLevels; mip++ )
  330. {
  331. if ( currDim < 1 )
  332. currDim = 1;
  333. dMemset( destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize( format ) );
  334. dMemset( destNormal.getWritableBits(mip), 0, destNormal.getWidth(mip) * destNormal.getHeight(mip) * GFXFormat_getByteSize( format ) );
  335. bitmaps.clear();
  336. normalmaps.clear();
  337. F32 rotX = 0.0f;
  338. if ( mNumPolarSteps > 0 )
  339. rotX = -( mDegToRad( mPolarAngle ) - 0.5f * M_PI_F );
  340. // We capture the images in a particular order which must
  341. // match the order expected by the imposter renderer.
  342. imposterCap->begin( shape, mDl, currDim, mRadius, mCenter );
  343. for ( U32 j=0; j < (2 * mNumPolarSteps + 1); j++ )
  344. {
  345. F32 rotZ = -M_PI_F / 2.0f;
  346. for ( U32 k=0; k < mNumEquatorSteps; k++ )
  347. {
  348. angMat.mul( MatrixF( EulerF( rotX, 0, 0 ) ),
  349. MatrixF( EulerF( 0, 0, rotZ ) ) );
  350. imposterCap->capture( angMat, &imposter, &normalmap );
  351. bitmaps.push_back( imposter );
  352. normalmaps.push_back( normalmap );
  353. rotZ += equatorStepSize;
  354. }
  355. rotX += polarStepSize;
  356. if ( mIncludePoles )
  357. {
  358. imposterCap->capture( topXfm, &imposter, &normalmap );
  359. bitmaps.push_back(imposter);
  360. normalmaps.push_back( normalmap );
  361. imposterCap->capture( bottomXfm, &imposter, &normalmap );
  362. bitmaps.push_back( imposter );
  363. normalmaps.push_back( normalmap );
  364. }
  365. }
  366. imposterCap->end();
  367. Point2I atlasSize( destBmp.getWidth(mip), destBmp.getHeight(mip) );
  368. // Ok... pack in bitmaps till we run out.
  369. for ( S32 y=0; y+currDim <= atlasSize.y; )
  370. {
  371. for ( S32 x=0; x+currDim <= atlasSize.x; )
  372. {
  373. // Copy the next bitmap to the dest texture.
  374. GBitmap* cell = bitmaps.first();
  375. bitmaps.pop_front();
  376. destBmp.copyRect(cell, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip );
  377. delete cell;
  378. // Copy the next normal to the dest texture.
  379. GBitmap* cellNormalmap = normalmaps.first();
  380. normalmaps.pop_front();
  381. destNormal.copyRect(cellNormalmap, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip );
  382. delete cellNormalmap;
  383. // Did we finish?
  384. if ( bitmaps.empty() )
  385. break;
  386. x += currDim;
  387. }
  388. // Did we finish?
  389. if ( bitmaps.empty() )
  390. break;
  391. y += currDim;
  392. }
  393. // Next mip...
  394. currDim /= 2;
  395. }
  396. PROFILE_END(); // TSLastDetail_snapshots
  397. delete imposterCap;
  398. delete shape;
  399. // Should we dump the images?
  400. if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) )
  401. {
  402. String imposterPath = _getDiffuseMapPath();
  403. String normalsPath = _getNormalMapPath();
  404. FileStream stream;
  405. if ( stream.open( imposterPath, Torque::FS::File::Write ) )
  406. destBmp.writeBitmap( "png", stream );
  407. stream.close();
  408. if ( stream.open( normalsPath, Torque::FS::File::Write ) )
  409. destNormal.writeBitmap( "png", stream );
  410. stream.close();
  411. }
  412. // DEBUG: Some code to force usage of a test image.
  413. //GBitmap* tempMap = GBitmap::load( "./forest/data/test1234.png" );
  414. //tempMap->extrudeMipLevels();
  415. //mTexture.set( tempMap, &GFXStaticTextureSRGBProfile, false );
  416. //delete tempMap;
  417. DDSFile *ddsDest = DDSFile::createDDSFileFromGBitmap( &destBmp );
  418. ImageUtil::ddsCompress( ddsDest, GFXFormatBC2 );
  419. DDSFile *ddsNormals = DDSFile::createDDSFileFromGBitmap( &destNormal );
  420. ImageUtil::ddsCompress( ddsNormals, GFXFormatBC3 );
  421. // Finally save the imposters to disk.
  422. FileStream fs;
  423. if ( fs.open( _getDiffuseMapPath(), Torque::FS::File::Write ) )
  424. {
  425. ddsDest->write( fs );
  426. fs.close();
  427. }
  428. if ( fs.open( _getNormalMapPath(), Torque::FS::File::Write ) )
  429. {
  430. ddsNormals->write( fs );
  431. fs.close();
  432. }
  433. delete ddsDest;
  434. delete ddsNormals;
  435. // If we did a begin then end it now.
  436. if ( !sceneBegun )
  437. GFX->endScene();
  438. }
  439. void TSLastDetail::deleteImposterCacheTextures()
  440. {
  441. const String diffuseMap = _getDiffuseMapPath();
  442. if ( diffuseMap.length() )
  443. dFileDelete( diffuseMap );
  444. const String normalMap = _getNormalMapPath();
  445. if ( normalMap.length() )
  446. dFileDelete( normalMap );
  447. }
  448. void TSLastDetail::updateImposterImages( bool forceUpdate )
  449. {
  450. // Can't do it without GFX!
  451. if ( !GFXDevice::devicePresent() )
  452. return;
  453. //D3DPERF_SetMarker( D3DCOLOR_RGBA( 0, 255, 0, 255 ), L"TSLastDetail::makeImposter" );
  454. bool sceneBegun = GFX->canCurrentlyRender();
  455. if ( !sceneBegun )
  456. GFX->beginScene();
  457. Vector<TSLastDetail*>::iterator iter = smLastDetails.begin();
  458. for ( ; iter != smLastDetails.end(); iter++ )
  459. (*iter)->update( forceUpdate );
  460. if ( !sceneBegun )
  461. GFX->endScene();
  462. }
  463. DefineEngineFunction( tsUpdateImposterImages, void, (bool forceUpdate), (false), "tsUpdateImposterImages( bool forceupdate )")
  464. {
  465. TSLastDetail::updateImposterImages(forceUpdate);
  466. }