ddsFile.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  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 = dds::getBitsPerPixel(dx10header.dxgiFormat) / 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. switch (header.ddspf.fourCC)
  255. {
  256. case 36: // D3DFMT_A16B16G16R16
  257. mBytesPerPixel = 8;
  258. break;
  259. case 110: // D3DFMT_Q16W16V16U16
  260. mBytesPerPixel = 8;
  261. break;
  262. case 111: // D3DFMT_R16F
  263. mBytesPerPixel = 2;
  264. break;
  265. case 112: // D3DFMT_G16R16F
  266. mBytesPerPixel = 4;
  267. break;
  268. case 113: // D3DFMT_A16B16G16R16F
  269. mBytesPerPixel = 8;
  270. break;
  271. case 114: // D3DFMT_R32F
  272. mBytesPerPixel = 4;
  273. break;
  274. case 115: // D3DFMT_G32R32F
  275. mBytesPerPixel = 8;
  276. break;
  277. case 116: // D3DFMT_A32B32G32R32F
  278. mBytesPerPixel = 16;
  279. break;
  280. }
  281. mFlags.set(RGBData);
  282. }
  283. }
  284. else
  285. {
  286. mFormat = dds::getGFXFormat(header.ddspf);
  287. //make sure getGFXFormat gave us a valid format
  288. if (mFormat == GFXFormat_FIRST)
  289. return false;
  290. mBytesPerPixel = header.ddspf.bpp / 8;
  291. mFlags.set(RGBData);
  292. }
  293. //mip map flag
  294. if (mMipMapCount > 1)
  295. mFlags.set(MipMapsFlag | ComplexFlag);
  296. //set transparency flag
  297. mHasTransparency = (header.ddspf.flags & DDS_ALPHAPIXELS);
  298. if (header.flags & DDS_HEADER_FLAGS_LINEARSIZE)
  299. mFlags.set(LinearSizeFlag);
  300. else if (header.flags & DDS_HEADER_FLAGS_PITCH)
  301. mFlags.set(PitchSizeFlag);
  302. //set cubemap flags
  303. if (header.cubemapFlags & DDS_CUBEMAP)
  304. {
  305. mFlags.set(CubeMapFlag | ComplexFlag);
  306. // Store the face flags too.
  307. if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEX) mFlags.set(CubeMap_PosX_Flag);
  308. if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEX) mFlags.set(CubeMap_NegX_Flag);
  309. if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEY) mFlags.set(CubeMap_PosY_Flag);
  310. if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEY) mFlags.set(CubeMap_NegY_Flag);
  311. if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEZ) mFlags.set(CubeMap_PosZ_Flag);
  312. if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEZ) mFlags.set(CubeMap_NegZ_Flag);
  313. }
  314. return true;
  315. }
  316. bool DDSFile::read(Stream &s, U32 dropMipCount)
  317. {
  318. if( !readHeader(s) )
  319. {
  320. Con::errorf("DDSFile::read - error reading header!");
  321. return false;
  322. }
  323. // If we're droping mips then make sure we have enough.
  324. dropMipCount = getMin( dropMipCount, mMipMapCount - 1 );
  325. // At this point we know what sort of image we contain. So we should
  326. // allocate some buffers, and read it in.
  327. // How many surfaces are we talking about?
  328. if(mFlags.test(CubeMapFlag))
  329. {
  330. mSurfaces.setSize( Cubemap_Surface_Count );
  331. for ( U32 i=0; i < Cubemap_Surface_Count; i++ )
  332. {
  333. // Does the cubemap contain this surface?
  334. if ( mFlags.test( CubeMap_PosX_Flag + ( i << 1 ) ) )
  335. mSurfaces[i] = new SurfaceData();
  336. else
  337. {
  338. mSurfaces[i] = NULL;
  339. continue;
  340. }
  341. // Load all the mips.
  342. for(S32 mip=0; mip<mMipMapCount; mip++)
  343. mSurfaces[i]->readNextMip(this, s, mHeight, mWidth, mip, mip < dropMipCount );
  344. }
  345. }
  346. else if (mFlags.test(VolumeFlag))
  347. {
  348. // Do something with volume
  349. }
  350. else
  351. {
  352. // It's a plain old texture.
  353. // First allocate a SurfaceData to stick this in.
  354. mSurfaces.push_back(new SurfaceData());
  355. // Load however many mips there are.
  356. for(S32 i=0; i<mMipMapCount; i++)
  357. mSurfaces.last()->readNextMip(this, s, mHeight, mWidth, i, i < dropMipCount);
  358. // Ok, we're done.
  359. }
  360. // If we're dropping mips then fix up the stats.
  361. if ( dropMipCount > 0 )
  362. {
  363. // Fix up the pitch and/or linear size.
  364. if( mFlags.test( LinearSizeFlag ) )
  365. mPitchOrLinearSize = getSurfaceSize( dropMipCount );
  366. else if ( mFlags.test( PitchSizeFlag ) )
  367. mPitchOrLinearSize = getSurfacePitch( dropMipCount );
  368. // Now fix up the rest of the
  369. mMipMapCount = getMax( (U32)1, mMipMapCount - dropMipCount );
  370. mHeight = getHeight( dropMipCount );
  371. mWidth = getWidth( dropMipCount );
  372. }
  373. return true;
  374. }
  375. bool DDSFile::writeHeader( Stream &s )
  376. {
  377. // write DDS magic
  378. U32 magic = DDS_MAGIC;
  379. s.write(magic);
  380. dds::DDS_HEADER header = {};
  381. dds::DDS_HEADER_DXT10 dx10header = {};
  382. bool hasDx10Header = false;
  383. //flags
  384. U32 surfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;
  385. U32 cubemapFlags = 0;
  386. U32 headerFlags = DDS_HEADER_FLAGS_TEXTURE;
  387. //pixel format
  388. const dds::DDS_PIXELFORMAT &format = dds::getDDSFormat(mFormat);
  389. // todo better dx10 support
  390. if (format.fourCC == dds::D3DFMT_DX10)
  391. {
  392. dx10header.dxgiFormat = dds::getDXGIFormat(mFormat);
  393. dx10header.arraySize = 1;
  394. dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE2D;
  395. dx10header.miscFlag = 0;
  396. dx10header.miscFlags2 = 0;
  397. hasDx10Header = true;
  398. }
  399. if (mFlags.test(CompressedData))
  400. headerFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
  401. else
  402. headerFlags |= DDS_HEADER_FLAGS_PITCH;
  403. if (mMipMapCount > 1)
  404. {
  405. surfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP;
  406. headerFlags |= DDS_HEADER_FLAGS_MIPMAP;
  407. }
  408. //cubemap flags
  409. if (mFlags.test(CubeMapFlag))
  410. {
  411. surfaceFlags |= DDS_SURFACE_FLAGS_CUBEMAP;
  412. cubemapFlags |= DDS_CUBEMAP_ALLFACES;
  413. if (hasDx10Header)
  414. dx10header.miscFlag = dds::D3D10_RESOURCE_MISC_TEXTURECUBE;
  415. }
  416. //volume texture
  417. if (mDepth > 0)
  418. {
  419. headerFlags |= DDS_HEADER_FLAGS_VOLUME;
  420. dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE3D;
  421. }
  422. //main dds header
  423. header.size = sizeof(dds::DDS_HEADER);
  424. header.flags = headerFlags;
  425. header.height = mHeight;
  426. header.width = mWidth;
  427. header.pitchOrLinearSize = mPitchOrLinearSize;
  428. header.depth = mDepth;
  429. header.ddspf = format;
  430. header.mipMapCount = mMipMapCount;
  431. header.surfaceFlags = surfaceFlags;
  432. header.cubemapFlags = cubemapFlags;
  433. memset(header.reserved1, 0, sizeof(header.reserved1));
  434. memset(header.reserved2, 0, sizeof(header.reserved2));
  435. //check our header is ok
  436. if (!dds::validateHeader(header))
  437. return false;
  438. //Write out the header
  439. s.write(DDS_HEADER_SIZE, &header);
  440. //Write out dx10 header
  441. if (hasDx10Header)
  442. s.write(DDS_HEADER_DX10_SIZE, &dx10header);
  443. return true;
  444. }
  445. bool DDSFile::write( Stream &s )
  446. {
  447. if(!writeHeader(s))
  448. {
  449. Con::errorf("DDSFile::write - error writing header!");
  450. return false;
  451. }
  452. // How many surfaces are we talking about?
  453. if(mFlags.test(CubeMapFlag))
  454. {
  455. // Do something with cubemaps.
  456. for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++)
  457. {
  458. // write the mips
  459. for (S32 i = 0; i < mMipMapCount; i++)
  460. mSurfaces[cubeFace]->writeNextMip(this, s, mHeight, mWidth, i);
  461. }
  462. }
  463. else if (mFlags.test(VolumeFlag))
  464. {
  465. // Do something with volume
  466. }
  467. else
  468. {
  469. // It's a plain old texture.
  470. // Load however many mips there are.
  471. for ( S32 i = 0; i < mMipMapCount; i++ )
  472. mSurfaces.last()->writeNextMip(this, s, mHeight, mWidth, i);
  473. // Ok, we're done.
  474. }
  475. return true;
  476. }
  477. void DDSFile::SurfaceData::dumpImage(DDSFile *dds, U32 mip, const char *file)
  478. {
  479. GBitmap *foo = new GBitmap(dds->mWidth >> mip, dds->mHeight >> mip, false, dds->mFormat);
  480. // Copy our data in.
  481. dMemcpy(foo->getWritableBits(), mMips[mip], dds->getSurfaceSize(dds->mHeight, dds->mWidth, mip) );
  482. FileStream stream;
  483. stream.open( file, Torque::FS::File::Write );
  484. if ( stream.getStatus() == Stream::Ok )
  485. {
  486. // Write it out.
  487. foo->writeBitmap("png", stream);
  488. }
  489. // Clean up.
  490. delete foo;
  491. }
  492. void DDSFile::SurfaceData::readNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel, bool skip)
  493. {
  494. U32 size = dds->getSurfaceSize(height, width, mipLevel);
  495. // If we're skipping this mip then seek forward.
  496. if ( skip )
  497. s.setPosition( s.getPosition() + size );
  498. else
  499. {
  500. mMips.push_back(new U8[size]);
  501. if(!s.read(size, mMips.last()))
  502. Con::errorf("DDSFile::SurfaceData::addNextMip - failed to read mip!");
  503. }
  504. }
  505. void DDSFile::SurfaceData::writeNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel)
  506. {
  507. U32 size = dds->getSurfaceSize(height, width, mipLevel);
  508. if(!s.write(size, mMips[mipLevel]))
  509. Con::errorf("DDSFile::SurfaceData::writeNextMip - failed to write mip!");
  510. }
  511. //------------------------------------------------------------------------------
  512. template<> void *Resource<DDSFile>::create( const Torque::Path &path )
  513. {
  514. #ifdef TORQUE_DEBUG_RES_MANAGER
  515. Con::printf( "Resource<DDSFile>::create - [%s]", path.getFullPath().c_str() );
  516. #endif
  517. FileStream stream;
  518. stream.open( path.getFullPath(), Torque::FS::File::Read );
  519. if ( stream.getStatus() != Stream::Ok )
  520. return NULL;
  521. DDSFile *retDDS = new DDSFile;
  522. if( !retDDS->read( stream, DDSFile::smDropMipCount ) )
  523. {
  524. delete retDDS;
  525. return NULL;
  526. }
  527. else
  528. {
  529. // Set source file name
  530. retDDS->mSourcePath = path;
  531. retDDS->mCacheString = Torque::Path::Join( path.getRoot(), ':', path.getPath() );
  532. retDDS->mCacheString = Torque::Path::Join( retDDS->mCacheString, '/', path.getFileName() );
  533. }
  534. return retDDS;
  535. }
  536. template<> ResourceBase::Signature Resource<DDSFile>::signature()
  537. {
  538. return MakeFourCC('D','D','S',' '); // Direct Draw Surface
  539. }
  540. Resource<DDSFile> DDSFile::load( const Torque::Path &path, U32 dropMipCount )
  541. {
  542. PROFILE_SCOPE( DDSFile_load );
  543. // HACK: It sucks that we cannot pass parameters into
  544. // the resource manager loading system.
  545. DDSFile::smDropMipCount = dropMipCount;
  546. Resource<DDSFile> ret = ResourceManager::get().load( path );
  547. DDSFile::smDropMipCount = 0;
  548. // Any kind of error checking or path stepping can happen here
  549. return ret;
  550. }
  551. //------------------------------------------------------------------------------
  552. DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp )
  553. {
  554. if( gbmp == NULL )
  555. return NULL;
  556. DDSFile *ret = new DDSFile;
  557. // Set up the DDSFile properties that matter. Since this is a GBitmap, there
  558. // are assumptions that can be made
  559. ret->mHeight = gbmp->getHeight();
  560. ret->mWidth = gbmp->getWidth();
  561. ret->mDepth = 0;
  562. ret->mFormat = gbmp->getFormat();
  563. ret->mFlags.set(RGBData);
  564. ret->mBytesPerPixel = gbmp->getBytesPerPixel();
  565. ret->mMipMapCount = gbmp->getNumMipLevels();
  566. ret->mHasTransparency = gbmp->getHasTransparency();
  567. // ASSUMPTION!!!
  568. // This _most likely_ does not belong here, but it is safe to assume that if
  569. // a GBitmap is 24-bit, and it's being converted to a DDS, it is most likely
  570. // going to be either:
  571. // a) Uploaded as a 32-bit texture, and just needs to be padded to RGBX
  572. // b) Uploaded as a compressed format, and needs to be padded to 32-bits anyway
  573. if( ret->mFormat == GFXFormatR8G8B8 )
  574. {
  575. ret->mFormat = GFXFormatR8G8B8X8;
  576. ret->mBytesPerPixel = 4;
  577. }
  578. if( ret->mMipMapCount > 1 )
  579. ret->mFlags.set(MipMapsFlag);
  580. // One surface per GBitmap
  581. ret->mSurfaces.push_back( new SurfaceData() );
  582. // Load the mips
  583. for( S32 i = 0; i < ret->mMipMapCount; i++ )
  584. {
  585. const U32 mipSz = ret->getSurfaceSize(i);
  586. ret->mSurfaces.last()->mMips.push_back( new U8[mipSz] );
  587. U8 *mipMem = ret->mSurfaces.last()->mMips.last();
  588. // If this is a straight copy, just do it, otherwise (ugh)
  589. if( ret->mFormat == gbmp->getFormat() )
  590. dMemcpy( mipMem, gbmp->getBits(i), mipSz );
  591. else
  592. {
  593. // Assumption:
  594. AssertFatal( gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert." );
  595. for( S32 pxl = 0; pxl < gbmp->getWidth(i) * gbmp->getHeight(i); pxl++ )
  596. {
  597. U8 *dst = &mipMem[pxl * ret->mBytesPerPixel];
  598. const U8 *src = &gbmp->getBits(i)[pxl * gbmp->getBytesPerPixel()];
  599. dMemcpy( dst, src, gbmp->getBytesPerPixel() * sizeof(U8) );
  600. dst[ret->mBytesPerPixel - 1] = 255;
  601. }
  602. }
  603. // Uncomment to debug-dump each mip level
  604. //ret->mSurfaces.last()->dumpImage( ret, i, avar( "%d_Gbmp_xmip%d", ret, i ) );
  605. }
  606. return ret;
  607. }
  608. DDSFile *DDSFile::createDDSCubemapFileFromGBitmaps(GBitmap **gbmps)
  609. {
  610. if (gbmps == NULL)
  611. return NULL;
  612. AssertFatal(gbmps[0], "createDDSCubemapFileFromGBitmaps bitmap 0 is null");
  613. AssertFatal(gbmps[1], "createDDSCubemapFileFromGBitmaps bitmap 1 is null");
  614. AssertFatal(gbmps[2], "createDDSCubemapFileFromGBitmaps bitmap 2 is null");
  615. AssertFatal(gbmps[3], "createDDSCubemapFileFromGBitmaps bitmap 3 is null");
  616. AssertFatal(gbmps[4], "createDDSCubemapFileFromGBitmaps bitmap 4 is null");
  617. AssertFatal(gbmps[5], "createDDSCubemapFileFromGBitmaps bitmap 5 is null");
  618. DDSFile *ret = new DDSFile;
  619. //all cubemaps have the same dimensions and formats
  620. GBitmap *pBitmap = gbmps[0];
  621. GFXFormat fmt = pBitmap->getFormat();
  622. if (fmt != GFXFormatR8G8B8A8 && fmt != GFXFormatR16G16B16A16F)
  623. {
  624. Con::errorf("createDDSCubemapFileFromGBitmaps: unsupported format");
  625. return NULL;
  626. }
  627. // Set up the DDSFile properties that matter. Since this is a GBitmap, there
  628. // are assumptions that can be made
  629. ret->mHeight = pBitmap->getHeight();
  630. ret->mWidth = pBitmap->getWidth();
  631. ret->mDepth = 0;
  632. ret->mFormat = pBitmap->getFormat();
  633. ret->mFlags.set( RGBData | CubeMapFlag | CubeMap_PosX_Flag | CubeMap_NegX_Flag | CubeMap_PosY_Flag |
  634. CubeMap_NegY_Flag | CubeMap_PosZ_Flag | CubeMap_NegZ_Flag);
  635. ret->mBytesPerPixel = pBitmap->getBytesPerPixel();
  636. //todo implement mip mapping
  637. ret->mMipMapCount = pBitmap->getNumMipLevels();
  638. ret->mHasTransparency = pBitmap->getHasTransparency();
  639. for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++)
  640. {
  641. ret->mSurfaces.push_back(new SurfaceData());
  642. // Load the mips
  643. for (S32 i = 0; i < ret->mMipMapCount; i++)
  644. {
  645. const U32 mipSz = ret->getSurfaceSize(i);
  646. ret->mSurfaces.last()->mMips.push_back(new U8[mipSz]);
  647. U8 *mipMem = ret->mSurfaces.last()->mMips.last();
  648. //straight copy
  649. dMemcpy(mipMem, gbmps[cubeFace]->getBits(i), mipSz);
  650. }
  651. }
  652. return ret;
  653. }
  654. bool DDSFile::decompressToGBitmap(GBitmap *dest)
  655. {
  656. // TBD: do we support other formats?
  657. if (mFormat != GFXFormatBC1 && mFormat != GFXFormatBC2 && mFormat != GFXFormatBC3)
  658. return false;
  659. dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), GFXFormatR8G8B8A8);
  660. // Decompress and copy mips...
  661. U32 numMips = getMipLevels();
  662. for (U32 i = 0; i < numMips; i++)
  663. {
  664. U8 *addr = dest->getAddress(0, 0, i);
  665. const U8 *mipBuffer = mSurfaces[0]->mMips[i];
  666. ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat);
  667. }
  668. return true;
  669. }
  670. DefineEngineFunction( getActiveDDSFiles, S32, (),,
  671. "Returns the count of active DDSs files in memory.\n"
  672. "@ingroup Rendering\n" )
  673. {
  674. return DDSFile::smActiveCopies;
  675. }