DDS.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. #define DDSCAPS2_CUBEMAP 0x200
  6. #define DDSCAPS2_CUBEMAP_POSITIVEX 0x400
  7. #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x800
  8. #define DDSCAPS2_CUBEMAP_POSITIVEY 0x1000
  9. #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x2000
  10. #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x4000
  11. #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x8000
  12. #define DDSCAPS2_VOLUME 0x200000
  13. #define DDPF_FOURCC 0x4
  14. #define DDPF_LUMINANCE 0x20000
  15. /******************************************************************************/
  16. #pragma pack(push, 4)
  17. struct DDS_PIXELFORMAT
  18. {
  19. UInt Size, Flags, FourCC, RGBBitCount, RBitMask, GBitMask, BBitMask, ABitMask;
  20. IMAGE_TYPE type()
  21. {
  22. if(!(Flags&DDPF_FOURCC))FourCC=0;
  23. if(FourCC==CC4('D', 'X', '1', '0'))return IMAGE_NONE; // special DX10+ format
  24. if(FourCC==CC4('D', 'X', 'T', '1'))return IMAGE_DXT1;
  25. if(FourCC==CC4('D', 'X', 'T', '2'))return IMAGE_DXT3;
  26. if(FourCC==CC4('D', 'X', 'T', '3'))return IMAGE_DXT3;
  27. if(FourCC==CC4('D', 'X', 'T', '4'))return IMAGE_DXT5;
  28. if(FourCC==CC4('D', 'X', 'T', '5'))return IMAGE_DXT5;
  29. // fix 'RGBBitCount' for these formats, because it may be 0
  30. if(FourCC==111){RGBBitCount=16 ; return IMAGE_F16 ;}
  31. if(FourCC==112){RGBBitCount=16*2; return IMAGE_F16_2;}
  32. if(FourCC==113){RGBBitCount=16*4; return IMAGE_F16_4;}
  33. if(FourCC==114){RGBBitCount=32 ; return IMAGE_F32 ;}
  34. if(FourCC==115){RGBBitCount=32*2; return IMAGE_F32_2;}
  35. if(FourCC==116){RGBBitCount=32*4; return IMAGE_F32_4;}
  36. if(Flags&DDPF_LUMINANCE)
  37. {
  38. if(RGBBitCount== 8 && RBitMask==0x000000FF && GBitMask==0x00000000 && BBitMask==0x00000000 && ABitMask==0x00000000)return IMAGE_L8;
  39. if(RGBBitCount==16 && RBitMask==0x000000FF && GBitMask==0x00000000 && BBitMask==0x00000000 && ABitMask==0x0000FF00)return IMAGE_L8A8;
  40. if(RGBBitCount==16 && RBitMask==0x0000FFFF && GBitMask==0x00000000 && BBitMask==0x00000000 && ABitMask==0x00000000)return IMAGE_I16;
  41. }
  42. if(RGBBitCount==32 && RBitMask==0x00FF0000 && GBitMask==0x0000FF00 && BBitMask==0x000000FF && ABitMask==0xFF000000)return IMAGE_B8G8R8A8;
  43. if(RGBBitCount==32 && RBitMask==0x000000FF && GBitMask==0x0000FF00 && BBitMask==0x00FF0000 && ABitMask==0xFF000000)return IMAGE_R8G8B8A8;
  44. if(RGBBitCount==24 && RBitMask==0x000000FF && GBitMask==0x0000FF00 && BBitMask==0x00FF0000 && ABitMask==0x00000000)return IMAGE_R8G8B8;
  45. if(RGBBitCount==16 && RBitMask==0x000000FF && GBitMask==0x0000FF00 && BBitMask==0x00000000 && ABitMask==0x00000000)return IMAGE_R8G8;
  46. if(RGBBitCount== 8 && RBitMask==0x000000FF && GBitMask==0x00000000 && BBitMask==0x00000000 && ABitMask==0x00000000)return IMAGE_R8;
  47. if(RGBBitCount== 8 && RBitMask==0x00000000 && GBitMask==0x00000000 && BBitMask==0x00000000 && ABitMask==0x000000FF)return IMAGE_A8;
  48. if(RGBBitCount==16 && RBitMask==0x00000F00 && GBitMask==0x000000F0 && BBitMask==0x0000000F && ABitMask==0x00000000)return IMAGE_B4G4R4X4;
  49. if(RGBBitCount==16 && RBitMask==0x00000F00 && GBitMask==0x000000F0 && BBitMask==0x0000000F && ABitMask==0x0000F000)return IMAGE_B4G4R4A4;
  50. if(RGBBitCount==16 && RBitMask==0x00007C00 && GBitMask==0x000003E0 && BBitMask==0x0000001F && ABitMask==0x00000000)return IMAGE_B5G5R5X1;
  51. if(RGBBitCount==16 && RBitMask==0x00007C00 && GBitMask==0x000003E0 && BBitMask==0x0000001F && ABitMask==0x00008000)return IMAGE_B5G5R5A1;
  52. if(RGBBitCount==16 && RBitMask==0x0000F800 && GBitMask==0x000007E0 && BBitMask==0x0000001F && ABitMask==0x00000000)return IMAGE_B5G6R5;
  53. if(RGBBitCount==24 && RBitMask==0x00FF0000 && GBitMask==0x0000FF00 && BBitMask==0x000000FF && ABitMask==0x00000000)return IMAGE_B8G8R8;
  54. if(RGBBitCount==32 && RBitMask==0x00FF0000 && GBitMask==0x0000FF00 && BBitMask==0x000000FF && ABitMask==0x00000000)return IMAGE_B8G8R8X8;
  55. if(RGBBitCount==32 && RBitMask==0x000000FF && GBitMask==0x0000FF00 && BBitMask==0x00FF0000 && ABitMask==0x00000000)return IMAGE_R8G8B8X8;
  56. if(RGBBitCount==32 && RBitMask==0x000003FF && GBitMask==0x000FFC00 && BBitMask==0x3FF00000 && ABitMask==0xC0000000)return IMAGE_R10G10B10A2;
  57. return IMAGE_NONE;
  58. }
  59. };
  60. struct DDS_HEADER
  61. {
  62. UInt Size, Flags, Height, Width, PitchOrLinearSize, Depth, MipMapCount, Reserved1[11];
  63. DDS_PIXELFORMAT pf;
  64. UInt Caps, Caps2, Caps3, Caps4, Reserved2;
  65. IMAGE_TYPE load(File &f)
  66. {
  67. ASSERT(SIZE(DDS_HEADER)==124 && SIZE(DDS_PIXELFORMAT)==32);
  68. if(f.getFast(T))
  69. if(Size==SIZE(DDS_HEADER) && pf.Size==SIZE(DDS_PIXELFORMAT))
  70. if(!(Caps2&DDSCAPS2_CUBEMAP) && !(Caps2&DDSCAPS2_VOLUME)) // Cube and Volume textures are not currently supported
  71. if(IMAGE_TYPE type=pf.type())
  72. {
  73. switch(type) // many DDS writers incorrectly setup 'PitchOrLinearSize', so we have to adjust it manually, according to https://docs.microsoft.com/en-us/windows/desktop/direct3ddds/dx-graphics-dds-pguide#dds-file-layout
  74. {
  75. case IMAGE_BC1: PitchOrLinearSize=DivCeil4(Width)* 8; break;
  76. case IMAGE_BC2: case IMAGE_BC3: case IMAGE_BC7: PitchOrLinearSize=DivCeil4(Width)*16; break;
  77. default: PitchOrLinearSize=DivCeil8(Width*pf.RGBBitCount); break;
  78. }
  79. return type;
  80. }
  81. return IMAGE_NONE;
  82. }
  83. };
  84. #pragma pack(pop)
  85. /******************************************************************************/
  86. Bool Image::ImportDDS(File &f, Int type, Int mode, Int mip_maps)
  87. {
  88. if(mode>=0 && mode!=IMAGE_2D && mode!=IMAGE_SOFT)return false; // if mode is specified, and not SOFT/2D then fail
  89. if(f.getUInt()==CC4('D','D','S',' '))
  90. {
  91. DDS_HEADER header; if(IMAGE_TYPE t=header.load(f))
  92. {
  93. if(type <=0)type =t; if(type>=IMAGE_TYPES)type=IMAGE_R8G8B8A8;
  94. if(mode < 0)mode =IMAGE_SOFT; // always default to SOFT like all other file formats
  95. if(mip_maps< 0)mip_maps=((header.MipMapCount>1 && mode==IMAGE_2D) ? 0 : 1);
  96. if(t==type && createTry(header.Width, header.Height, 1, t, IMAGE_MODE(mode), mip_maps, false) // if conversion is not required, then try desired values
  97. || createTry(header.Width, header.Height, 1, t, IMAGE_SOFT , 1, false)) // otherwise import as soft
  98. if(lock(LOCK_WRITE))
  99. {
  100. Int pitch =ImagePitch (w(), h(), 0, hwType()), // use "w(), h()" instead of "hwW(), hwH()" because we want to read only valid pixels and zero others
  101. blocks_y=ImageBlocksY(w(), h(), 0, hwType()); // use "w(), h()" instead of "hwW(), hwH()" because we want to read only valid pixels and zero others
  102. if(header.PitchOrLinearSize>=pitch)
  103. {
  104. Int skip=header.PitchOrLinearSize-pitch, zero=T.pitch()-pitch;
  105. Byte *data=T.data();
  106. FREPD(y, blocks_y)
  107. {
  108. f.getFast(data, pitch);
  109. f.skip(skip);
  110. Zero(data+pitch, zero);
  111. data+=T.pitch();
  112. }
  113. Zero(data, T.pitch2()-blocks_y*T.pitch());
  114. unlock();
  115. if(f.ok())
  116. {
  117. if(type!=T.type() || mode!=T.mode())
  118. {
  119. if(!copyTry(T, -1, -1, -1, type, mode, mip_maps))goto error;
  120. }else updateMipMaps();
  121. return true;
  122. }
  123. }
  124. }
  125. }
  126. }
  127. error:
  128. del(); return false;
  129. }
  130. Bool Image::ImportDDS(C Str &name, Int type, Int mode, Int mip_maps)
  131. {
  132. File f; if(f.readTry(name))return ImportDDS(f, type, mode, mip_maps);
  133. del(); return false;
  134. }
  135. Bool Image::ImportDDS(C Str &name) {return ImportDDS(name, -1);}
  136. Bool Image::ImportDDS( File &f ) {return ImportDDS(f , -1);}
  137. /******************************************************************************/
  138. //Bool ExportDX (C Str &name, GPU_API(D3DXIMAGE_FILEFORMAT, D3DX11_IMAGE_FILE_FORMAT, UInt) format)C; // export using DirectX
  139. //Bool Image::ExportDDS(C Str &name)C {return ExportDX(name, GPU_API(D3DXIFF_DDS, D3DX11_IFF_DDS, 0));}
  140. Bool Image::ExportDDS(C Str &name)C {return false;}
  141. /******************************************************************************/
  142. }
  143. /******************************************************************************/