ddsFile.cpp
Engine/source/gfx/bitmap/ddsFile.cpp
Public Functions
DefineEngineFunction(getActiveDDSFiles , S32 , () , "Returns the <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1ad43c3812e6d13e0518d9f8b8f463ffcf">count</a> of active DDSs files in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">memory.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n</a>" )
Detailed Description
Public Functions
DefineEngineFunction(getActiveDDSFiles , S32 , () , "Returns the <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1ad43c3812e6d13e0518d9f8b8f463ffcf">count</a> of active DDSs files in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">memory.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Rendering\n</a>" )
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "gfx/bitmap/ddsFile.h" 26#include "gfx/bitmap/ddsData.h" 27#include "gfx/bitmap/bitmapUtils.h" 28#include "gfx/bitmap/imageUtils.h" 29#include "gfx/gfxDevice.h" 30#include "core/util/fourcc.h" 31#include "console/console.h" 32#include "core/resourceManager.h" 33#include "core/stream/fileStream.h" 34#include "gfx/bitmap/gBitmap.h" 35#include "console/engineAPI.h" 36 37#include <squish.h> 38 39S32 DDSFile::smActiveCopies = 0; 40U32 DDSFile::smDropMipCount = 0; 41 42DDSFile::DDSFile( const DDSFile &dds ) 43 : mFlags( dds.mFlags ), 44 mHeight( dds.mHeight ), 45 mWidth( dds.mWidth ), 46 mDepth( dds.mDepth ), 47 mPitchOrLinearSize( dds.mPitchOrLinearSize ), 48 mMipMapCount( dds.mMipMapCount ), 49 mFormat( dds.mFormat ), 50 mBytesPerPixel( dds.mBytesPerPixel ), 51 mFourCC( dds.mFourCC ), 52 mCacheString( dds.mCacheString ), 53 mSourcePath( dds.mSourcePath ), 54 mHasTransparency( dds.mHasTransparency ) 55{ 56 VECTOR_SET_ASSOCIATION( mSurfaces ); 57 smActiveCopies++; 58 59 for ( U32 i=0; i < dds.mSurfaces.size(); i++ ) 60 { 61 SurfaceData *surface = NULL; 62 if ( dds.mSurfaces[i] ) 63 surface = new SurfaceData; 64 65 mSurfaces.push_back( surface ); 66 67 if ( !surface ) 68 continue; 69 70 for ( U32 m=0; m < dds.mSurfaces[i]->mMips.size(); m++ ) 71 { 72 U32 size = dds.getSurfaceSize( m ); 73 surface->mMips.push_back(new U8[size]); 74 dMemcpy( surface->mMips.last(), dds.mSurfaces[i]->mMips[m], size ); 75 } 76 } 77} 78 79void DDSFile::clear() 80{ 81 mFlags = 0; 82 mHeight = mWidth = mDepth = mPitchOrLinearSize = mMipMapCount = 0; 83 mFormat = GFXFormatR8G8B8; 84} 85 86U32 DDSFile::getSurfacePitch( U32 mipLevel ) const 87{ 88 if(mFlags.test(CompressedData)) 89 { 90 U32 sizeMultiple = 0; 91 92 switch(mFormat) 93 { 94 case GFXFormatBC1: 95 case GFXFormatBC4: 96 sizeMultiple = 8; 97 break; 98 case GFXFormatBC2: 99 case GFXFormatBC3: 100 case GFXFormatBC5: 101 sizeMultiple = 16; 102 break; 103 default: 104 AssertISV(false, "DDSFile::getPitch - invalid compressed texture format, we only support DXT1-5 right now."); 105 break; 106 } 107 108 // Maybe need to be DWORD aligned? 109 U32 align = getMax(U32(1), getWidth(mipLevel)/4) * sizeMultiple; 110 align += 3; align >>=2; align <<=2; 111 return align; 112 113 } 114 else 115 return getWidth(mipLevel) * mBytesPerPixel; 116} 117 118U32 DDSFile::getSurfaceSize( U32 height, U32 width, U32 mipLevel ) const 119{ 120 // Bump by the mip level. 121 height = getMax(U32(1), height >> mipLevel); 122 width = getMax(U32(1), width >> mipLevel); 123 124 if(mFlags.test(CompressedData)) 125 { 126 // From the directX docs: 127 // max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5) 128 129 U32 sizeMultiple = 0; 130 131 switch(mFormat) 132 { 133 case GFXFormatBC1: 134 case GFXFormatBC4: 135 sizeMultiple = 8; 136 break; 137 case GFXFormatBC2: 138 case GFXFormatBC3: 139 case GFXFormatBC5: 140 sizeMultiple = 16; 141 break; 142 default: 143 AssertISV(false, "DDSFile::getSurfaceSize - invalid compressed texture format, we only support DXT1-5 right now."); 144 break; 145 } 146 147 return getMax(U32(1), width/4) * getMax(U32(1), height/4) * sizeMultiple; 148 } 149 else 150 { 151 return height * width* mBytesPerPixel; 152 } 153} 154 155U32 DDSFile::getSizeInBytes() const 156{ 157 // TODO: This doesn't take mDepth into account, so 158 // it doesn't work right for volume textures! 159 160 U32 bytes = 0; 161 if (mFlags.test(CubeMapFlag)) 162 { 163 for(U32 cubeFace=0;cubeFace < Cubemap_Surface_Count;cubeFace++) 164 for (U32 i = 0; i < mMipMapCount; i++) 165 bytes += getSurfaceSize(mHeight, mWidth, i); 166 } 167 else 168 { 169 for (U32 i = 0; i < mMipMapCount; i++) 170 bytes += getSurfaceSize(mHeight, mWidth, i); 171 } 172 173 return bytes; 174} 175 176U32 DDSFile::getSizeInBytes( GFXFormat format, U32 height, U32 width, U32 mipLevels ) 177{ 178 AssertFatal( ImageUtil::isCompressedFormat(format), 179 "DDSFile::getSizeInBytes - Must be a Block Compression format!" ); 180 181 // From the directX docs: 182 // max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5) 183 184 U32 sizeMultiple = 0; 185 if ( format == GFXFormatBC1 || format == GFXFormatBC1_SRGB || format == GFXFormatBC4) 186 sizeMultiple = 8; 187 else 188 sizeMultiple = 16; 189 190 U32 mipHeight, mipWidth; 191 U32 bytes = 0; 192 for ( U32 m=0; m < mipLevels; m++ ) 193 { 194 mipHeight = getMax( U32(1), height >> m ); 195 mipWidth = getMax( U32(1), width >> m ); 196 197 bytes += getMax( U32(1), mipWidth / 4 ) * 198 getMax( U32(1), mipHeight / 4 ) * sizeMultiple; 199 } 200 201 return bytes; 202} 203 204bool DDSFile::readHeader(Stream &s) 205{ 206 U32 fourcc; 207 // Read the FOURCC 208 s.read(&fourcc); 209 210 if(fourcc != DDS_MAGIC) 211 { 212 Con::errorf("DDSFile::readHeader - unexpected magic number, wanted 'DDS '!"); 213 return false; 214 } 215 216 //dds headers 217 dds::DDS_HEADER header = {}; 218 dds::DDS_HEADER_DXT10 dx10header = {}; 219 //todo DX10 formats 220 bool hasDx10Header = false; 221 222 //read in header 223 s.read(DDS_HEADER_SIZE, &header); 224 //check for dx10 header support 225 if ((header.ddspf.flags & DDS_FOURCC) && (header.ddspf.fourCC == dds::D3DFMT_DX10)) 226 { 227 //read in dx10 header 228 s.read(DDS_HEADER_DX10_SIZE, &dx10header); 229 if (!dds::validateHeaderDx10(dx10header)) 230 return false; 231 232 hasDx10Header = true; 233 } 234 235 //make sure our dds header is valid 236 if (!dds::validateHeader(header)) 237 return false; 238 239 // store details 240 mPitchOrLinearSize = header.pitchOrLinearSize; 241 mMipMapCount = header.mipMapCount ? header.mipMapCount : 1; 242 mHeight = header.height; 243 mWidth = header.width; 244 mDepth = header.depth; 245 mFourCC = header.ddspf.fourCC; 246 247 //process dx10 header 248 if (hasDx10Header) 249 { 250 if (dx10header.arraySize > 1) 251 { 252 Con::errorf("DDSFile::readHeader - DX10 arrays not supported"); 253 return false; 254 } 255 256 mFormat = dds::getGFXFormat(dx10header.dxgiFormat); 257 //make sure getGFXFormat gave us a valid format 258 if (mFormat == GFXFormat_FIRST) 259 return false; 260 //cubemap 261 if (dx10header.miscFlag & dds::D3D10_RESOURCE_MISC_TEXTURECUBE) 262 { 263 mFlags.set(CubeMap_All_Flags | ComplexFlag); 264 } 265 266 mHasTransparency = ImageUtil::isAlphaFormat(mFormat); 267 268 //mip map flag 269 if (mMipMapCount > 1) 270 mFlags.set(MipMapsFlag | ComplexFlag); 271 272 if (ImageUtil::isCompressedFormat(mFormat)) 273 mFlags.set(CompressedData); 274 else 275 { 276 mBytesPerPixel = dds::getBitsPerPixel(dx10header.dxgiFormat) / 8; 277 mFlags.set(RGBData); 278 } 279 280 // we finished now 281 return true; 282 } 283 284 //process regular header 285 286 //D3DFMT_DX10 is caught above, no need to check now 287 if (header.ddspf.flags & DDS_FOURCC) 288 { 289 mFormat = dds::getGFXFormat(mFourCC); 290 //make sure getGFXFormat gave us a valid format 291 if (mFormat == GFXFormat_FIRST) 292 return false; 293 294 if (ImageUtil::isCompressedFormat(mFormat)) 295 mFlags.set(CompressedData); 296 else 297 { 298 switch (header.ddspf.fourCC) 299 { 300 case 36: // D3DFMT_A16B16G16R16 301 mBytesPerPixel = 8; 302 break; 303 case 110: // D3DFMT_Q16W16V16U16 304 mBytesPerPixel = 8; 305 break; 306 case 111: // D3DFMT_R16F 307 mBytesPerPixel = 2; 308 break; 309 case 112: // D3DFMT_G16R16F 310 mBytesPerPixel = 4; 311 break; 312 case 113: // D3DFMT_A16B16G16R16F 313 mBytesPerPixel = 8; 314 break; 315 case 114: // D3DFMT_R32F 316 mBytesPerPixel = 4; 317 break; 318 case 115: // D3DFMT_G32R32F 319 mBytesPerPixel = 8; 320 break; 321 case 116: // D3DFMT_A32B32G32R32F 322 mBytesPerPixel = 16; 323 break; 324 } 325 326 mFlags.set(RGBData); 327 } 328 } 329 else 330 { 331 mFormat = dds::getGFXFormat(header.ddspf); 332 //make sure getGFXFormat gave us a valid format 333 if (mFormat == GFXFormat_FIRST) 334 return false; 335 336 mBytesPerPixel = header.ddspf.bpp / 8; 337 mFlags.set(RGBData); 338 } 339 340 //mip map flag 341 if (mMipMapCount > 1) 342 mFlags.set(MipMapsFlag | ComplexFlag); 343 344 //set transparency flag 345 mHasTransparency = (header.ddspf.flags & DDS_ALPHAPIXELS); 346 347 if (header.flags & DDS_HEADER_FLAGS_LINEARSIZE) 348 mFlags.set(LinearSizeFlag); 349 else if (header.flags & DDS_HEADER_FLAGS_PITCH) 350 mFlags.set(PitchSizeFlag); 351 352 //set cubemap flags 353 if (header.cubemapFlags & DDS_CUBEMAP) 354 { 355 mFlags.set(CubeMapFlag | ComplexFlag); 356 // Store the face flags too. 357 if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEX) mFlags.set(CubeMap_PosX_Flag); 358 if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEX) mFlags.set(CubeMap_NegX_Flag); 359 if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEY) mFlags.set(CubeMap_PosY_Flag); 360 if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEY) mFlags.set(CubeMap_NegY_Flag); 361 if (header.cubemapFlags & DDS_CUBEMAP_POSITIVEZ) mFlags.set(CubeMap_PosZ_Flag); 362 if (header.cubemapFlags & DDS_CUBEMAP_NEGATIVEZ) mFlags.set(CubeMap_NegZ_Flag); 363 } 364 365 366 367 return true; 368} 369 370bool DDSFile::read(Stream &s, U32 dropMipCount) 371{ 372 if( !readHeader(s) ) 373 { 374 Con::errorf("DDSFile::read - error reading header!"); 375 return false; 376 } 377 378 // If we're droping mips then make sure we have enough. 379 dropMipCount = getMin( dropMipCount, mMipMapCount - 1 ); 380 381 // At this point we know what sort of image we contain. So we should 382 // allocate some buffers, and read it in. 383 384 // How many surfaces are we talking about? 385 if(mFlags.test(CubeMapFlag)) 386 { 387 mSurfaces.setSize( Cubemap_Surface_Count ); 388 389 for ( U32 i=0; i < Cubemap_Surface_Count; i++ ) 390 { 391 // Does the cubemap contain this surface? 392 if ( mFlags.test( CubeMap_PosX_Flag + ( i << 1 ) ) ) 393 mSurfaces[i] = new SurfaceData(); 394 else 395 { 396 mSurfaces[i] = NULL; 397 continue; 398 } 399 400 // Load all the mips. 401 for(S32 mip=0; mip<mMipMapCount; mip++) 402 mSurfaces[i]->readNextMip(this, s, mHeight, mWidth, mip, mip < dropMipCount ); 403 } 404 405 } 406 else if (mFlags.test(VolumeFlag)) 407 { 408 // Do something with volume 409 } 410 else 411 { 412 // It's a plain old texture. 413 414 // First allocate a SurfaceData to stick this in. 415 mSurfaces.push_back(new SurfaceData()); 416 417 // Load however many mips there are. 418 for(S32 i=0; i<mMipMapCount; i++) 419 mSurfaces.last()->readNextMip(this, s, mHeight, mWidth, i, i < dropMipCount); 420 421 // Ok, we're done. 422 } 423 424 // If we're dropping mips then fix up the stats. 425 if ( dropMipCount > 0 ) 426 { 427 // Fix up the pitch and/or linear size. 428 if( mFlags.test( LinearSizeFlag ) ) 429 mPitchOrLinearSize = getSurfaceSize( dropMipCount ); 430 else if ( mFlags.test( PitchSizeFlag ) ) 431 mPitchOrLinearSize = getSurfacePitch( dropMipCount ); 432 433 // Now fix up the rest of the 434 mMipMapCount = getMax( (U32)1, mMipMapCount - dropMipCount ); 435 mHeight = getHeight( dropMipCount ); 436 mWidth = getWidth( dropMipCount ); 437 } 438 439 return true; 440} 441 442bool DDSFile::writeHeader( Stream &s ) 443{ 444 // write DDS magic 445 U32 magic = DDS_MAGIC; 446 s.write(magic); 447 448 dds::DDS_HEADER header = {}; 449 dds::DDS_HEADER_DXT10 dx10header = {}; 450 451 bool hasDx10Header = false; 452 //flags 453 U32 surfaceFlags = DDS_SURFACE_FLAGS_TEXTURE; 454 U32 cubemapFlags = 0; 455 U32 headerFlags = DDS_HEADER_FLAGS_TEXTURE; 456 457 //pixel format 458 const dds::DDS_PIXELFORMAT &format = dds::getDDSFormat(mFormat); 459 460 // todo better dx10 support 461 if (format.fourCC == dds::D3DFMT_DX10) 462 { 463 dx10header.dxgiFormat = dds::getDXGIFormat(mFormat); 464 dx10header.arraySize = 1; 465 dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE2D; 466 dx10header.miscFlag = 0; 467 dx10header.miscFlags2 = 0; 468 hasDx10Header = true; 469 } 470 471 if (mFlags.test(CompressedData)) 472 headerFlags |= DDS_HEADER_FLAGS_LINEARSIZE; 473 else 474 headerFlags |= DDS_HEADER_FLAGS_PITCH; 475 476 if (mMipMapCount > 1) 477 { 478 surfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP; 479 headerFlags |= DDS_HEADER_FLAGS_MIPMAP; 480 } 481 482 //cubemap flags 483 if (mFlags.test(CubeMapFlag)) 484 { 485 surfaceFlags |= DDS_SURFACE_FLAGS_CUBEMAP; 486 cubemapFlags |= DDS_CUBEMAP_ALLFACES; 487 if (hasDx10Header) 488 dx10header.miscFlag = dds::D3D10_RESOURCE_MISC_TEXTURECUBE; 489 } 490 491 //volume texture 492 if (mDepth > 0) 493 { 494 headerFlags |= DDS_HEADER_FLAGS_VOLUME; 495 dx10header.resourceDimension = dds::D3D10_RESOURCE_DIMENSION_TEXTURE3D; 496 } 497 498 //main dds header 499 header.size = sizeof(dds::DDS_HEADER); 500 header.flags = headerFlags; 501 header.height = mHeight; 502 header.width = mWidth; 503 header.pitchOrLinearSize = mPitchOrLinearSize; 504 header.depth = mDepth; 505 header.ddspf = format; 506 header.mipMapCount = mMipMapCount; 507 header.surfaceFlags = surfaceFlags; 508 header.cubemapFlags = cubemapFlags; 509 memset(header.reserved1, 0, sizeof(header.reserved1)); 510 memset(header.reserved2, 0, sizeof(header.reserved2)); 511 512 //check our header is ok 513 if (!dds::validateHeader(header)) 514 return false; 515 516 //Write out the header 517 s.write(DDS_HEADER_SIZE, &header); 518 519 //Write out dx10 header 520 if (hasDx10Header) 521 s.write(DDS_HEADER_DX10_SIZE, &dx10header); 522 523 return true; 524} 525 526bool DDSFile::write( Stream &s ) 527{ 528 if(!writeHeader(s)) 529 { 530 Con::errorf("DDSFile::write - error writing header!"); 531 return false; 532 } 533 534 // How many surfaces are we talking about? 535 if(mFlags.test(CubeMapFlag)) 536 { 537 // Do something with cubemaps. 538 for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++) 539 { 540 // write the mips 541 for (S32 i = 0; i < mMipMapCount; i++) 542 mSurfaces[cubeFace]->writeNextMip(this, s, mHeight, mWidth, i); 543 } 544 } 545 else if (mFlags.test(VolumeFlag)) 546 { 547 // Do something with volume 548 } 549 else 550 { 551 // It's a plain old texture. 552 553 // Load however many mips there are. 554 for ( S32 i = 0; i < mMipMapCount; i++ ) 555 mSurfaces.last()->writeNextMip(this, s, mHeight, mWidth, i); 556 557 // Ok, we're done. 558 } 559 560 return true; 561} 562 563void DDSFile::SurfaceData::dumpImage(DDSFile *dds, U32 mip, const char *file) 564{ 565 GBitmap *foo = new GBitmap(dds->mWidth >> mip, dds->mHeight >> mip, false, dds->mFormat); 566 567 // Copy our data in. 568 dMemcpy(foo->getWritableBits(), mMips[mip], dds->getSurfaceSize(dds->mHeight, dds->mWidth, mip) ); 569 570 FileStream stream; 571 572 stream.open( file, Torque::FS::File::Write ); 573 574 if ( stream.getStatus() == Stream::Ok ) 575 { 576 // Write it out. 577 foo->writeBitmap("png", stream); 578 } 579 580 // Clean up. 581 delete foo; 582} 583 584void DDSFile::SurfaceData::readNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel, bool skip) 585{ 586 U32 size = dds->getSurfaceSize(height, width, mipLevel); 587 588 // If we're skipping this mip then seek forward. 589 if ( skip ) 590 s.setPosition( s.getPosition() + size ); 591 else 592 { 593 mMips.push_back(new U8[size]); 594 if(!s.read(size, mMips.last())) 595 Con::errorf("DDSFile::SurfaceData::addNextMip - failed to read mip!"); 596 } 597} 598 599void DDSFile::SurfaceData::writeNextMip(DDSFile *dds, Stream &s, U32 height, U32 width, U32 mipLevel) 600{ 601 U32 size = dds->getSurfaceSize(height, width, mipLevel); 602 if(!s.write(size, mMips[mipLevel])) 603 Con::errorf("DDSFile::SurfaceData::writeNextMip - failed to write mip!"); 604} 605 606//------------------------------------------------------------------------------ 607 608template<> void *Resource<DDSFile>::create( const Torque::Path &path ) 609{ 610#ifdef TORQUE_DEBUG_RES_MANAGER 611 Con::printf( "Resource<DDSFile>::create - [%s]", path.getFullPath().c_str() ); 612#endif 613 614 FileStream stream; 615 616 stream.open( path.getFullPath(), Torque::FS::File::Read ); 617 618 if ( stream.getStatus() != Stream::Ok ) 619 return NULL; 620 621 DDSFile *retDDS = new DDSFile; 622 623 if( !retDDS->read( stream, DDSFile::smDropMipCount ) ) 624 { 625 delete retDDS; 626 return NULL; 627 } 628 else 629 { 630 // Set source file name 631 retDDS->mSourcePath = path; 632 retDDS->mCacheString = Torque::Path::Join( path.getRoot(), ':', path.getPath() ); 633 retDDS->mCacheString = Torque::Path::Join( retDDS->mCacheString, '/', path.getFileName() ); 634 } 635 636 return retDDS; 637} 638 639template<> ResourceBase::Signature Resource<DDSFile>::signature() 640{ 641 return MakeFourCC('D','D','S',' '); // Direct Draw Surface 642} 643 644Resource<DDSFile> DDSFile::load( const Torque::Path &path, U32 dropMipCount ) 645{ 646 PROFILE_SCOPE( DDSFile_load ); 647 648 // HACK: It sucks that we cannot pass parameters into 649 // the resource manager loading system. 650 DDSFile::smDropMipCount = dropMipCount; 651 Resource<DDSFile> ret = ResourceManager::get().load( path ); 652 DDSFile::smDropMipCount = 0; 653 654 // Any kind of error checking or path stepping can happen here 655 656 return ret; 657} 658 659//------------------------------------------------------------------------------ 660 661DDSFile *DDSFile::createDDSFileFromGBitmap( const GBitmap *gbmp ) 662{ 663 if( gbmp == NULL ) 664 return NULL; 665 666 DDSFile *ret = new DDSFile; 667 668 // Set up the DDSFile properties that matter. Since this is a GBitmap, there 669 // are assumptions that can be made 670 ret->mHeight = gbmp->getHeight(); 671 ret->mWidth = gbmp->getWidth(); 672 ret->mDepth = 0; 673 ret->mFormat = gbmp->getFormat(); 674 ret->mFlags.set(RGBData); 675 ret->mBytesPerPixel = gbmp->getBytesPerPixel(); 676 ret->mMipMapCount = gbmp->getNumMipLevels(); 677 ret->mHasTransparency = gbmp->getHasTransparency(); 678 679 // ASSUMPTION!!! 680 // This _most likely_ does not belong here, but it is safe to assume that if 681 // a GBitmap is 24-bit, and it's being converted to a DDS, it is most likely 682 // going to be either: 683 // a) Uploaded as a 32-bit texture, and just needs to be padded to RGBX 684 // b) Uploaded as a compressed format, and needs to be padded to 32-bits anyway 685 if( ret->mFormat == GFXFormatR8G8B8 ) 686 { 687 ret->mFormat = GFXFormatR8G8B8X8; 688 ret->mBytesPerPixel = 4; 689 } 690 691 if( ret->mMipMapCount > 1 ) 692 ret->mFlags.set(MipMapsFlag); 693 694 // One surface per GBitmap 695 ret->mSurfaces.push_back( new SurfaceData() ); 696 697 // Load the mips 698 for( S32 i = 0; i < ret->mMipMapCount; i++ ) 699 { 700 const U32 mipSz = ret->getSurfaceSize(i); 701 ret->mSurfaces.last()->mMips.push_back( new U8[mipSz] ); 702 703 U8 *mipMem = ret->mSurfaces.last()->mMips.last(); 704 705 // If this is a straight copy, just do it, otherwise (ugh) 706 if( ret->mFormat == gbmp->getFormat() ) 707 dMemcpy( mipMem, gbmp->getBits(i), mipSz ); 708 else 709 { 710 // Assumption: 711 AssertFatal( gbmp->getBytesPerPixel() + 1 == ret->mBytesPerPixel, "Assumption failed, not 24->32 bit straight convert." ); 712 713 for( S32 pxl = 0; pxl < gbmp->getWidth(i) * gbmp->getHeight(i); pxl++ ) 714 { 715 U8 *dst = &mipMem[pxl * ret->mBytesPerPixel]; 716 const U8 *src = &gbmp->getBits(i)[pxl * gbmp->getBytesPerPixel()]; 717 dMemcpy( dst, src, gbmp->getBytesPerPixel() * sizeof(U8) ); 718 dst[ret->mBytesPerPixel - 1] = 255; 719 } 720 } 721 722 // Uncomment to debug-dump each mip level 723 //ret->mSurfaces.last()->dumpImage( ret, i, avar( "%d_Gbmp_xmip%d", ret, i ) ); 724 } 725 726 return ret; 727} 728 729DDSFile *DDSFile::createDDSCubemapFileFromGBitmaps(GBitmap **gbmps) 730{ 731 if (gbmps == NULL) 732 return NULL; 733 734 AssertFatal(gbmps[0], "createDDSCubemapFileFromGBitmaps bitmap 0 is null"); 735 AssertFatal(gbmps[1], "createDDSCubemapFileFromGBitmaps bitmap 1 is null"); 736 AssertFatal(gbmps[2], "createDDSCubemapFileFromGBitmaps bitmap 2 is null"); 737 AssertFatal(gbmps[3], "createDDSCubemapFileFromGBitmaps bitmap 3 is null"); 738 AssertFatal(gbmps[4], "createDDSCubemapFileFromGBitmaps bitmap 4 is null"); 739 AssertFatal(gbmps[5], "createDDSCubemapFileFromGBitmaps bitmap 5 is null"); 740 741 DDSFile *ret = new DDSFile; 742 //all cubemaps have the same dimensions and formats 743 GBitmap *pBitmap = gbmps[0]; 744 745 GFXFormat fmt = pBitmap->getFormat(); 746 if (fmt != GFXFormatR8G8B8A8 && fmt != GFXFormatR16G16B16A16F) 747 { 748 Con::errorf("createDDSCubemapFileFromGBitmaps: unsupported format"); 749 return NULL; 750 } 751 752 // Set up the DDSFile properties that matter. Since this is a GBitmap, there 753 // are assumptions that can be made 754 ret->mHeight = pBitmap->getHeight(); 755 ret->mWidth = pBitmap->getWidth(); 756 ret->mDepth = 0; 757 ret->mFormat = pBitmap->getFormat(); 758 ret->mFlags.set( RGBData | CubeMapFlag | CubeMap_PosX_Flag | CubeMap_NegX_Flag | CubeMap_PosY_Flag | 759 CubeMap_NegY_Flag | CubeMap_PosZ_Flag | CubeMap_NegZ_Flag); 760 ret->mBytesPerPixel = pBitmap->getBytesPerPixel(); 761 //todo implement mip mapping 762 ret->mMipMapCount = pBitmap->getNumMipLevels(); 763 ret->mHasTransparency = pBitmap->getHasTransparency(); 764 765 for (U32 cubeFace = 0; cubeFace < Cubemap_Surface_Count; cubeFace++) 766 { 767 ret->mSurfaces.push_back(new SurfaceData()); 768 // Load the mips 769 for (S32 i = 0; i < ret->mMipMapCount; i++) 770 { 771 const U32 mipSz = ret->getSurfaceSize(i); 772 ret->mSurfaces.last()->mMips.push_back(new U8[mipSz]); 773 774 U8 *mipMem = ret->mSurfaces.last()->mMips.last(); 775 //straight copy 776 dMemcpy(mipMem, gbmps[cubeFace]->getBits(i), mipSz); 777 } 778 } 779 780 return ret; 781} 782 783bool DDSFile::decompressToGBitmap(GBitmap *dest) 784{ 785 // TBD: do we support other formats? 786 if (mFormat != GFXFormatBC1 && mFormat != GFXFormatBC2 && mFormat != GFXFormatBC3) 787 return false; 788 789 dest->allocateBitmapWithMips(getWidth(), getHeight(), getMipLevels(), GFXFormatR8G8B8A8); 790 791 // Decompress and copy mips... 792 793 U32 numMips = getMipLevels(); 794 795 for (U32 i = 0; i < numMips; i++) 796 { 797 U8 *addr = dest->getAddress(0, 0, i); 798 const U8 *mipBuffer = mSurfaces[0]->mMips[i]; 799 ImageUtil::decompress(mipBuffer, addr, getWidth(i), getHeight(i), mFormat); 800 801 } 802 803 return true; 804} 805 806DefineEngineFunction( getActiveDDSFiles, S32, (),, 807 "Returns the count of active DDSs files in memory.\n" 808 "@ingroup Rendering\n" ) 809{ 810 return DDSFile::smActiveCopies; 811} 812