ddsFile.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  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 "gfx/bitmap/ddsFile.h"
  24. #include "gfx/bitmap/ddsData.h"
  25. #include "gfx/bitmap/bitmapUtils.h"
  26. #include "gfx/bitmap/imageUtils.h"
  27. #include "gfx/gfxDevice.h"
  28. #include "core/util/fourcc.h"
  29. #include "console/console.h"
  30. #include "core/resourceManager.h"
  31. #include "core/stream/fileStream.h"
  32. #include "gfx/bitmap/gBitmap.h"
  33. #include "console/engineAPI.h"
  34. #include <squish.h>
  35. S32 DDSFile::smActiveCopies = 0;
  36. U32 DDSFile::smDropMipCount = 0;
  37. DDSFile::DDSFile( const DDSFile &dds )
  38. : mFlags( dds.mFlags ),
  39. mHeight( dds.mHeight ),
  40. mWidth( dds.mWidth ),
  41. mDepth( dds.mDepth ),
  42. mPitchOrLinearSize( dds.mPitchOrLinearSize ),
  43. mMipMapCount( dds.mMipMapCount ),
  44. mFormat( dds.mFormat ),
  45. mBytesPerPixel( dds.mBytesPerPixel ),
  46. mFourCC( dds.mFourCC ),
  47. mCacheString( dds.mCacheString ),
  48. mSourcePath( dds.mSourcePath ),
  49. mHasTransparency( dds.mHasTransparency )
  50. {
  51. VECTOR_SET_ASSOCIATION( mSurfaces );
  52. smActiveCopies++;
  53. for ( U32 i=0; i < dds.mSurfaces.size(); i++ )
  54. {
  55. SurfaceData *surface = NULL;
  56. if ( dds.mSurfaces[i] )
  57. surface = new SurfaceData;
  58. mSurfaces.push_back( surface );
  59. if ( !surface )
  60. continue;
  61. for ( U32 m=0; m < dds.mSurfaces[i]->mMips.size(); m++ )
  62. {
  63. U32 size = dds.getSurfaceSize( m );
  64. surface->mMips.push_back(new U8[size]);
  65. dMemcpy( surface->mMips.last(), dds.mSurfaces[i]->mMips[m], size );
  66. }
  67. }
  68. }
  69. void DDSFile::clear()
  70. {
  71. mFlags = 0;
  72. mHeight = mWidth = mDepth = mPitchOrLinearSize = mMipMapCount = 0;
  73. mFormat = GFXFormatR8G8B8;
  74. }
  75. U32 DDSFile::getSurfacePitch( U32 mipLevel ) const
  76. {
  77. if(mFlags.test(CompressedData))
  78. {
  79. U32 sizeMultiple = 0;
  80. switch(mFormat)
  81. {
  82. case GFXFormatBC1:
  83. case GFXFormatBC4:
  84. sizeMultiple = 8;
  85. break;
  86. case GFXFormatBC2:
  87. case GFXFormatBC3:
  88. case GFXFormatBC5:
  89. sizeMultiple = 16;
  90. break;
  91. default:
  92. AssertISV(false, "DDSFile::getPitch - invalid compressed texture format, we only support DXT1-5 right now.");
  93. break;
  94. }
  95. // Maybe need to be DWORD aligned?
  96. U32 align = getMax(U32(1), getWidth(mipLevel)/4) * sizeMultiple;
  97. align += 3; align >>=2; align <<=2;
  98. return align;
  99. }
  100. else
  101. return getWidth(mipLevel) * mBytesPerPixel;
  102. }
  103. U32 DDSFile::getSurfaceSize( U32 height, U32 width, U32 mipLevel ) const
  104. {
  105. // Bump by the mip level.
  106. height = getMax(U32(1), height >> mipLevel);
  107. width = getMax(U32(1), width >> mipLevel);
  108. if(mFlags.test(CompressedData))
  109. {
  110. // From the directX docs:
  111. // max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5)
  112. U32 sizeMultiple = 0;
  113. switch(mFormat)
  114. {
  115. case GFXFormatBC1:
  116. case GFXFormatBC4:
  117. sizeMultiple = 8;
  118. break;
  119. case GFXFormatBC2:
  120. case GFXFormatBC3:
  121. case GFXFormatBC5:
  122. sizeMultiple = 16;
  123. break;
  124. default:
  125. AssertISV(false, "DDSFile::getSurfaceSize - invalid compressed texture format, we only support DXT1-5 right now.");
  126. break;
  127. }
  128. return getMax(U32(1), width/4) * getMax(U32(1), height/4) * sizeMultiple;
  129. }
  130. else
  131. {
  132. return height * width* mBytesPerPixel;
  133. }
  134. }
  135. U32 DDSFile::getSizeInBytes() const
  136. {
  137. // TODO: This doesn't take mDepth into account, so
  138. // it doesn't work right for volume textures!
  139. U32 bytes = 0;
  140. if (mFlags.test(CubeMapFlag))
  141. {
  142. for(U32 cubeFace=0;cubeFace < Cubemap_Surface_Count;cubeFace++)
  143. for (U32 i = 0; i < mMipMapCount; i++)
  144. bytes += getSurfaceSize(mHeight, mWidth, i);
  145. }
  146. else
  147. {
  148. for (U32 i = 0; i < mMipMapCount; i++)
  149. bytes += getSurfaceSize(mHeight, mWidth, i);
  150. }
  151. return bytes;
  152. }
  153. U32 DDSFile::getSizeInBytes( GFXFormat format, U32 height, U32 width, U32 mipLevels )
  154. {
  155. AssertFatal( ImageUtil::isCompressedFormat(format),
  156. "DDSFile::getSizeInBytes - Must be a Block Compression format!" );
  157. // From the directX docs:
  158. // max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5)
  159. U32 sizeMultiple = 0;
  160. if ( format == GFXFormatBC1 || format == GFXFormatBC1_SRGB || format == GFXFormatBC4)
  161. sizeMultiple = 8;
  162. else
  163. sizeMultiple = 16;
  164. U32 mipHeight, mipWidth;
  165. U32 bytes = 0;
  166. for ( U32 m=0; m < mipLevels; m++ )
  167. {
  168. mipHeight = getMax( U32(1), height >> m );
  169. mipWidth = getMax( U32(1), width >> m );
  170. bytes += getMax( U32(1), mipWidth / 4 ) *
  171. getMax( U32(1), mipHeight / 4 ) * sizeMultiple;
  172. }
  173. return bytes;
  174. }
  175. bool DDSFile::readHeader(Stream &s)
  176. {
  177. U32 fourcc;
  178. // Read the FOURCC
  179. s.read(&fourcc);
  180. if(fourcc != DDS_MAGIC)
  181. {
  182. Con::errorf("DDSFile::readHeader - unexpected magic number, wanted 'DDS '!");
  183. return false;
  184. }
  185. //dds headers
  186. dds::DDS_HEADER header = {};
  187. dds::DDS_HEADER_DXT10 dx10header = {};
  188. //todo DX10 formats
  189. bool hasDx10Header = false;
  190. //read in header
  191. s.read(DDS_HEADER_SIZE, &header);
  192. //check for dx10 header support
  193. if ((header.ddspf.flags & DDS_FOURCC) && (header.ddspf.fourCC == dds::D3DFMT_DX10))
  194. {
  195. //read in dx10 header
  196. s.read(DDS_HEADER_DX10_SIZE, &dx10header);
  197. if (!dds::validateHeaderDx10(dx10header))
  198. return false;
  199. hasDx10Header = true;
  200. }
  201. //make sure our dds header is valid
  202. if (!dds::validateHeader(header))
  203. return false;
  204. // store details
  205. mPitchOrLinearSize = header.pitchOrLinearSize;
  206. mMipMapCount = header.mipMapCount ? header.mipMapCount : 1;
  207. mHeight = header.height;
  208. mWidth = header.width;
  209. mDepth = header.depth;
  210. mFourCC = header.ddspf.fourCC;
  211. //process dx10 header
  212. if (hasDx10Header)
  213. {
  214. if (dx10header.arraySize > 1)
  215. {
  216. Con::errorf("DDSFile::readHeader - DX10 arrays not supported");
  217. return false;
  218. }
  219. mFormat = dds::getGFXFormat(dx10header.dxgiFormat);
  220. //make sure getGFXFormat gave us a valid format
  221. if (mFormat == GFXFormat_FIRST)
  222. return false;
  223. //cubemap
  224. if (dx10header.miscFlag & dds::D3D10_RESOURCE_MISC_TEXTURECUBE)
  225. {
  226. mFlags.set(CubeMap_All_Flags | ComplexFlag);
  227. }
  228. mHasTransparency = ImageUtil::isAlphaFormat(mFormat);
  229. //mip map flag
  230. if (mMipMapCount > 1)
  231. mFlags.set(MipMapsFlag | ComplexFlag);
  232. if (ImageUtil::isCompressedFormat(mFormat))
  233. mFlags.set(CompressedData);
  234. else
  235. {
  236. mBytesPerPixel = header.ddspf.bpp / 8;
  237. mFlags.set(RGBData);
  238. }
  239. // we finished now
  240. return true;
  241. }
  242. //process regular header
  243. //D3DFMT_DX10 is caught above, no need to check now
  244. if (header.ddspf.flags & DDS_FOURCC)
  245. {
  246. mFormat = dds::getGFXFormat(mFourCC);
  247. //make sure getGFXFormat gave us a valid format
  248. if (mFormat == GFXFormat_FIRST)
  249. return false;
  250. if (ImageUtil::isCompressedFormat(mFormat))
  251. mFlags.set(CompressedData);
  252. else
  253. {
  254. mBytesPerPixel = header.ddspf.bpp / 8;
  255. mFlags.set(RGBData);
  256. }
  257. }
  258. else
  259. {
  260. mFormat = dds::getGFXFormat(header.ddspf);
  261. //make sure getGFXFormat gave us a valid format
  262. if (mFormat == GFXFormat_FIRST)
  263. return false;
  264. mBytesPerPixel = header.ddspf.bpp / 8;
  265. mFlags.set(RGBData);
  266. }
  267. //mip map flag
  268. if (mMipMapCount > 1)
  269. mFlags.set(MipMapsFlag | ComplexFlag);
  270. //set transparency flag
  271. mHasTransparency = (header.ddspf.flags & DDS_ALPHAPIXELS);
  272. if (header.flags & DDS_HEADER_FLAGS_LINEARSIZE)
  273. mFlags.set(LinearSizeFlag);
  274. else if (header.flags & DDS_HEADER_FLAGS_PITCH)
  275. mFlags.set(PitchSizeFlag);
  276. //set cubemap flags
  277. if (header.cubemapFlags & DDS_CUBEMAP)
  278. {
  279. mFlags.set(CubeMapFlag | ComplexFlag);
  280. // Store the face flags too.
  281. if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEX) mFlags.set(CubeMap_PosX_Flag);
  282. if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEX) mFlags.set(CubeMap_NegX_Flag);
  283. if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEY) mFlags.set(CubeMap_PosY_Flag);
  284. if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEY) mFlags.set(CubeMap_NegY_Flag);
  285. if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEZ) mFlags.set(CubeMap_PosZ_Flag);
  286. if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEZ) mFlags.set(CubeMap_NegZ_Flag);
  287. }
  288. return true;
  289. }
  290. bool DDSFile::read(Stream &s, U32 dropMipCount)
  291. {
  292. if( !readHeader(s) )
  293. {
  294. Con::errorf("DDSFile::read - error reading header!");
  295. return false;
  296. }
  297. // If we're droping mips then make sure we have enough.
  298. dropMipCount = getMin( dropMipCount, mMipMapCount - 1 );
  299. // At this point we know what sort of image we contain. So we should
  300. // allocate some buffers, and read it in.
  301. // How many surfaces are we talking about?
  302. if(mFlags.test(CubeMapFlag))
  303. {
  304. mSurfaces.setSize( Cubemap_Surface_Count );
  305. for ( U32 i=0; i < Cubemap_Surface_Count; i++ )
  306. {
  307. // Does the cubemap contain this surface?
  308. if ( mFlags.test( CubeMap_PosX_Flag + ( i << 1 ) ) )
  309. mSurfaces[i] = new SurfaceData();
  310. else
  311. {
  312. mSurfaces[i] = NULL;
  313. continue;
  314. }
  315. // Load all the mips.
  316. for(S32 l=0; l<mMipMapCount; l++)
  317. mSurfaces[i]->readNextMip(this, s, mHeight, mWidth, l, l < dropMipCount );
  318. }
  319. }
  320. else if (mFlags.test(VolumeFlag))
  321. {
  322. // Do something with volume
  323. }
  324. else
  325. {
  326. // It's a plain old texture.
  327. // First allocate a SurfaceData to stick this in.
  328. mSurfaces.push_back(new SurfaceData());
  329. // Load however many mips there are.
  330. for(S32 i=0; i<mMipMapCount; i++)
  331. mSurfaces.last()->readNextMip(this, s, mHeight, mWidth, i, i < dropMipCount);
  332. // Ok, we're done.
  333. }
  334. // If we're dropping mips then fix up the stats.
  335. if ( dropMipCount > 0 )
  336. {
  337. // Fix up the pitch and/or linear size.
  338. if( mFlags.test( LinearSizeFlag ) )
  339. mPitchOrLinearSize = getSurfaceSize( dropMipCount );
  340. else if ( mFlags.test( PitchSizeFlag ) )
  341. mPitchOrLinearSize = getSurfacePitch( dropMipCount );
  342. // Now fix up the rest of the
  343. mMipMapCount = getMax( (U32)1, mMipMapCount - dropMipCount );
  344. mHeight = getHeight( dropMipCount );
  345. mWidth = getWidth( dropMipCount );
  346. }
  347. return true;
  348. }
  349. bool DDSFile::writeHeader( Stream &s )
  350. {
  351. // write DDS magic
  352. U32 magic = DDS_MAGIC;
  353. s.write(magic);
  354. dds::DDS_HEADER header = {};
  355. dds::DDS_HEADER_DXT10 dx10header = {};
  356. bool hasDx10Header = false;
  357. //flags
  358. U32 surfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;
  359. U32 cubemapFlags = 0;
  360. U32 headerFlags = DDS_HEADER_FLAGS_TEXTURE;
  361. //pixel format
  362. const dds::DDS_PIXELFORMAT &format = dds::getDDSFormat(mFormat);
  363. // todo better dx10 support
  364. if (format.fourCC == dds::D3DFMT_DX10)
  365. {
  366. dx10header.dxgiFormat = dds::getDXGIFormat(mFormat);
  367. dx10header.arraySize = 1;
  368. dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE2D;
  369. dx10header.miscFlag = 0;
  370. dx10header.miscFlags2 = 0;
  371. hasDx10Header = true;
  372. }
  373. if (mFlags.test(CompressedData))
  374. headerFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
  375. else
  376. headerFlags |= DDS_HEADER_FLAGS_PITCH;
  377. if (mMipMapCount > 1)
  378. {
  379. surfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP;
  380. headerFlags |= DDS_HEADER_FLAGS_MIPMAP;
  381. }
  382. //cubemap flags
  383. if (mFlags.test(CubeMapFlag))
  384. {
  385. surfaceFlags |= DDS_SURFACE_FLAGS_CUBEMAP;
  386. cubemapFlags |= DDS_CUBEMAP_ALLFACES;
  387. }
  388. //volume texture
  389. if (mDepth > 0)
  390. {
  391. headerFlags |= DDS_HEADER_FLAGS_VOLUME;
  392. dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE3D;
  393. }
  394. //main dds header
  395. header.size = sizeof(dds::DDS_HEADER);
  396. header.flags = headerFlags;
  397. header.height = mHeight;
  398. header.width = mWidth;
  399. header.pitchOrLinearSize = mPitchOrLinearSize;
  400. header.depth = mDepth;
  401. header.ddspf = format;
  402. header.mipMapCount = mMipMapCount;
  403. header.surfaceFlags = surfaceFlags;
  404. header.cubemapFlags = cubemapFlags;
  405. memset(header.reserved1, 0, sizeof(header.reserved1));
  406. memset(header.reserved2, 0, sizeof(header.reserved2));
  407. //check our header is ok
  408. if (!dds::validateHeader(header))
  409. return false;
  410. //Write out the header
  411. s.write(DDS_HEADER_SIZE, &header);
  412. //Write out dx10 header
  413. if (hasDx10Header)
  414. s.write(DDS_HEADER_DX10_SIZE, &dx10header);
  415. return true;
  416. }
  417. bool DDSFile::write( Stream &s )
  418. {
  419. if(!writeHeader(s))
  420. {
  421. Con::errorf("DDSFile::write - error writing header!");
  422. return false;
  423. }
  424. // How many surfaces are we talking about?
  425. if(mFlags.test(CubeMapFlag))
  426. {
  427. // Do something with cubemaps.
  428. for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++)
  429. {
  430. // write the mips
  431. for (S32 i = 0; i < mMipMapCount; i++)
  432. mSurfaces[cubeFace]->writeNextMip(this, s, mHeight, mWidth, i);
  433. }
  434. }
  435. else if (mFlags.test(VolumeFlag))
  436. {
  437. // Do something with volume
  438. }
  439. else
  440. {
  441. // It's a plain old texture.
  442. // Load however many mips there are.
  443. for ( S32 i = 0; i < mMipMapCount; i++ )
  444. mSurfaces.last()->writeNextMip(this, s, mHeight, mWidth, i);
  445. // Ok, we're done.
  446. }
  447. return true;
  448. }
  449. void DDSFile::SurfaceData::dumpImage(DDSFile *dds, U32 mip, const char *file)
  450. {
  451. GBitmap *foo = new GBitmap(dds->mWidth >> mip, dds->mHeight >> mip, false, dds->mFormat);
  452. // Copy our data in.
  453. dMemcpy(foo->getWritableBits(), mMips[mip], dds->getSurfaceSize(dds->mHeight, dds->mWidth, mip) );
  454. FileStream stream;
  455. stream.open( file, Torque::FS::File::Write );
  456. if ( stream.getStatus() == Stream::Ok )
  457. {
  458. // Write it out.
  459. foo->writeBitmap("png", stream);
  460. }
  461. // Clean up.
  462. delete foo;
  463. }
  464. void DDSFile::SurfaceData::readNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel, bool skip)
  465. {
  466. U32 size = dds->getSurfaceSize(height, width, mipLevel);
  467. // If we're skipping this mip then seek forward.
  468. if ( skip )
  469. s.setPosition( s.getPosition() + size );
  470. else
  471. {
  472. mMips.push_back(new U8[size]);
  473. if(!s.read(size, mMips.last()))
  474. Con::errorf("DDSFile::SurfaceData::addNextMip - failed to read mip!");
  475. }
  476. }
  477. void DDSFile::SurfaceData::writeNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel)
  478. {
  479. U32 size = dds->getSurfaceSize(height, width, mipLevel);
  480. if(!s.write(size, mMips[mipLevel]))
  481. Con::errorf("DDSFile::SurfaceData::writeNextMip - failed to write mip!");
  482. }
  483. //------------------------------------------------------------------------------
  484. template<> void *Resource<DDSFile>::create( const Torque::Path &path )
  485. {
  486. #ifdef TORQUE_DEBUG_RES_MANAGER
  487. Con::printf( "Resource<DDSFile>::create - [%s]", path.getFullPath().c_str() );
  488. #endif
  489. FileStream stream;
  490. stream.open( path.getFullPath(), Torque::FS::File::Read );
  491. if ( stream.getStatus() != Stream::Ok )
  492. return NULL;
  493. DDSFile *retDDS = new DDSFile;
  494. if( !retDDS->read( stream, DDSFile::smDropMipCount ) )
  495. {
  496. delete retDDS;
  497. return NULL;
  498. }
  499. else
  500. {
  501. // Set source file name
  502. retDDS->mSourcePath = path;
  503. retDDS->mCacheString = Torque::Path::Join( path.getRoot(), ':', path.getPath() );
  504. retDDS->mCacheString = Torque::Path::Join( retDDS->mCacheString, '/', path.getFileName() );
  505. }
  506. return retDDS;
  507. }
  508. template<> ResourceBase::Signature Resource<DDSFile>::signature()
  509. {
  510. return MakeFourCC('D','D','S',' '); // Direct Draw Surface
  511. }
  512. Resource<DDSFile> DDSFile::load( const Torque::Path &path, U32 dropMipCount )
  513. {
  514. PROFILE_SCOPE( DDSFile_load );
  515. // HACK: It sucks that we cannot pass parameters into
  516. // the resource manager loading system.
  517. DDSFile::smDropMipCount = dropMipCount;
  518. Resource<DDSFile> ret = ResourceManager::get().load( path );
  519. DDSFile::smDropMipCount = 0;
  520. // Any kind of error checking or path stepping can happen here
  521. return ret;
  522. }
  523. //------------------------------------------------------------------------------
  524. DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
  525. {
  526. if( gbmp == NULL )
  527. return NULL;
  528. DDSFile *ret = new DDSFile;
  529. // Set up the DDSFile properties that matter. Since this is a GBitmap, there
  530. // are assumptions that can be made
  531. ret->mHeight = gbmp->getHeight();
  532. ret->mWidth = gbmp->getWidth();
  533. ret->mDepth = 0;
  534. ret->mFormat = gbmp->getFormat();
  535. ret->mFlags.set(RGBData);
  536. ret->mBytesPerPixel = gbmp->getBytesPerPixel();
  537. ret->mMipMapCount = gbmp->getNumMipLevels();
  538. ret->mHasTransparency = gbmp->getHasTransparency();
  539. // ASSUMPTION!!!
  540. // This _most likely_ does not belong here, but it is safe to assume that if
  541. // a GBitmap is 24-bit, and it's being converted to a DDS, it is most likely
  542. // going to be either:
  543. // a) Uploaded as a 32-bit texture, and just needs to be padded to RGBX
  544. // b) Uploaded as a compressed format, and needs to be padded to 32-bits anyway
  545. if( ret->mFormat == GFXFormatR8G8B8 )
  546. {
  547. ret->mFormat = GFXFormatR8G8B8X8;
  548. ret->mBytesPerPixel = 4;
  549. }
  550. if( ret->mMipMapCount > 1 )
  551. ret->mFlags.set(MipMapsFlag);
  552. // One surface per GBitmap
  553. ret->mSurfaces.push_back( new SurfaceData() );
  554. // Load the mips
  555. for( S32 i = 0; i < ret->mMipMapCount; i++ )
  556. {
  557. const U32 mipSz = ret->getSurfaceSize(i);
  558. ret->mSurfaces.last()->mMips.push_back( new U8[mipSz] );
  559. U8 *mipMem = ret->mSurfaces.last()->mMips.last();
  560. // If this is a straight copy, just do it, otherwise (ugh)
  561. if( ret->mFormat == gbmp->getFormat() )
  562. dMemcpy( mipMem, gbmp->getBits(i), mipSz );
  563. else
  564. {
  565. // Assumption:
  566. AssertFatal( gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert." );
  567. for( S32 pxl = 0; pxl < gbmp->getWidth(i) * gbmp->getHeight(i); pxl++ )
  568. {
  569. U8 *dst = &mipMem[pxl * ret->mBytesPerPixel];
  570. const U8 *src = &gbmp->getBits(i)[pxl * gbmp->getBytesPerPixel()];
  571. dMemcpy( dst, src, gbmp->getBytesPerPixel() * sizeof(U8) );
  572. dst[ret->mBytesPerPixel - 1] = 255;
  573. }
  574. }
  575. // Uncomment to debug-dump each mip level
  576. //ret->mSurfaces.last()->dumpImage( ret, i, avar( "%d_Gbmp_xmip%d", ret, i ) );
  577. }
  578. return ret;
  579. }
  580. DDSFile *DDSFile::createDDSCubemapFileFromGBitmaps(GBitmap **gbmps)
  581. {
  582. if (gbmps == NULL)
  583. return NULL;
  584. AssertFatal(gbmps[0], "createDDSCubemapFileFromGBitmaps bitmap 0 is null");
  585. AssertFatal(gbmps[1], "createDDSCubemapFileFromGBitmaps bitmap 1 is null");
  586. AssertFatal(gbmps[2], "createDDSCubemapFileFromGBitmaps bitmap 2 is null");
  587. AssertFatal(gbmps[3], "createDDSCubemapFileFromGBitmaps bitmap 3 is null");
  588. AssertFatal(gbmps[4], "createDDSCubemapFileFromGBitmaps bitmap 4 is null");
  589. AssertFatal(gbmps[5], "createDDSCubemapFileFromGBitmaps bitmap 5 is null");
  590. DDSFile *ret = new DDSFile;
  591. //all cubemaps have the same dimensions and formats
  592. GBitmap *pBitmap = gbmps[0];
  593. if (pBitmap->getFormat() != GFXFormatR8G8B8A8)
  594. {
  595. Con::errorf("createDDSCubemapFileFromGBitmaps: Only GFXFormatR8G8B8A8 supported for now");
  596. return NULL;
  597. }
  598. // Set up the DDSFile properties that matter. Since this is a GBitmap, there
  599. // are assumptions that can be made
  600. ret->mHeight = pBitmap->getHeight();
  601. ret->mWidth = pBitmap->getWidth();
  602. ret->mDepth = 0;
  603. ret->mFormat = pBitmap->getFormat();
  604. ret->mFlags.set( RGBData | CubeMapFlag | CubeMap_PosX_Flag | CubeMap_NegX_Flag | CubeMap_PosY_Flag |
  605. CubeMap_NegY_Flag | CubeMap_PosZ_Flag | CubeMap_NegZ_Flag);
  606. ret->mBytesPerPixel = pBitmap->getBytesPerPixel();
  607. //todo implement mip mapping
  608. ret->mMipMapCount = pBitmap->getNumMipLevels();
  609. ret->mHasTransparency = pBitmap->getHasTransparency();
  610. for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++)
  611. {
  612. ret->mSurfaces.push_back(new SurfaceData());
  613. // Load the mips
  614. for (S32 i = 0; i < ret->mMipMapCount; i++)
  615. {
  616. const U32 mipSz = ret->getSurfaceSize(i);
  617. ret->mSurfaces.last()->mMips.push_back(new U8[mipSz]);
  618. U8 *mipMem = ret->mSurfaces.last()->mMips.last();
  619. //straight copy
  620. dMemcpy(mipMem, gbmps[cubeFace]->getBits(i), mipSz);
  621. }
  622. }
  623. return ret;
  624. }
  625. bool DDSFile::decompressToGBitmap(GBitmap *dest)
  626. {
  627. // TBD: do we support other formats?
  628. if (mFormat != GFXFormatBC1 && mFormat != GFXFormatBC2 && mFormat != GFXFormatBC3)
  629. return false;
  630. dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), GFXFormatR8G8B8A8);
  631. // Decompress and copy mips...
  632. U32 numMips = getMipLevels();
  633. for (U32 i = 0; i < numMips; i++)
  634. {
  635. U8 *addr = dest->getAddress(0, 0, i);
  636. const U8 *mipBuffer = mSurfaces[0]->mMips[i];
  637. ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat);
  638. }
  639. return true;
  640. }
  641. DefineEngineFunction( getActiveDDSFiles, S32, (),,
  642. "Returns the count of active DDSs files in memory.\n"
  643. "@ingroup Rendering\n" )
  644. {
  645. return DDSFile::smActiveCopies;
  646. }