| 1 | // tImageDDS.cpp  |
| 2 | //  |
| 3 | // This class knows how to load Direct Draw Surface (.dds) files. It knows the details of the dds file format and loads  |
| 4 | // the data into tLayers, optionally decompressing them. Saving is not implemented yet. The layers may be 'stolen' from  |
| 5 | // a tImageDDS so that excessive memcpys are avoided. After they are stolen the tImageDDS is invalid.  |
| 6 | //  |
| 7 | // Copyright (c) 2006, 2017, 2019, 2020, 2022-2024 Tristan Grimmer.  |
| 8 | // Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby  |
| 9 | // granted, provided that the above copyright notice and this permission notice appear in all copies.  |
| 10 | //  |
| 11 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL  |
| 12 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,  |
| 13 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN  |
| 14 | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR  |
| 15 | // PERFORMANCE OF THIS SOFTWARE.  |
| 16 |   |
| 17 | #include <Foundation/tString.h>  |
| 18 | #include "Image/tImageDDS.h"  |
| 19 | #include "Image/tPixelUtil.h"  |
| 20 | #include "Image/tPicture.h"  |
| 21 | namespace tImage  |
| 22 | {  |
| 23 |   |
| 24 |   |
| 25 | // Helper functions, enums, and types for parsing DDS files.  |
| 26 | namespace tDDS  |
| 27 | {  |
| 28 | // Direct Draw pixel format flags. When the comment says legacy here, we really mean it. Not just legacy in that  |
| 29 | // there's no DX10 block, but legacy in that there won't be a DX10 block AND it's still a really old-style dds.  |
| 30 | enum DDFormatFlag : uint32  |
| 31 | {  |
| 32 | // Pixel has alpha. tDDS::Format's MaskAlpha will be valid. I believe ALPHAPIXELS is only ever used in  |
| 33 | // combination with RGB, YUV, or LUMINANCE. An alpha-only dds would use DDFormatFlag_A instead.  |
| 34 | DDFormatFlag_HASALPHA = 0x00000001,  |
| 35 |   |
| 36 | // Legacy. Some dds files use this if all they contain is an alpha channel. tDDS::Format's RGBBitCount is the  |
| 37 | // number of bits used for the alpha channel and MaskAlpha will be valid.  |
| 38 | DDFormatFlag_A = 0x00000002,  |
| 39 |   |
| 40 | // Use the Four-CC to determine format. That's another whole thing. tDDS::Format's FourCC will be valid. Modern  |
| 41 | // dds files have a Four-CC of 'DX10' and another whole header specifies the actual pixel format. Complex-much?  |
| 42 | DDFormatFlag_FOURCC = 0x00000004,  |
| 43 |   |
| 44 | // Palette indexed. 8-bit. Never seen a dds with this.  |
| 45 | DDFormatFlag_PAL8 = 0x00000020,  |
| 46 |   |
| 47 | // Pixels contain RGB data. tDDS::Format's RGBBitCount is the number of bits used for RGB. Also go ahead and  |
| 48 | // read MaskRed, MaskGreen, and MaskBlue to determine where the data is and how many bits for each component.  |
| 49 | DDFormatFlag_RGB = 0x00000040,  |
| 50 |   |
| 51 | // Legacy. Some dds files use this for YUV pixels. tDDS::Format's RGBBitCount will be the number of bits used  |
| 52 | // for YUV (not RGB). Similarly, MaskRed, MaskGreen, and MaskBlue will contain the masks for each YUV component.  |
| 53 | // Red for Y, green for U, and blue for V.  |
| 54 | DDFormatFlag_YUV = 0x00000200,  |
| 55 |   |
| 56 | // Legacy. Some dds files use this for single channel luminance-only data. tDDS::Format's RGBBitCount will be  |
| 57 | // the number of bits used for luminance and MaskRed will contain the mask for the luminance component. If the  |
| 58 | // tDDPF_ALPHAPIXELS bit is also set, it would be a luminance-alpha (LA) dds.  |
| 59 | DDFormatFlag_L = 0x00020000,  |
| 60 |   |
| 61 | // Now that the raw format flags are out of the way, here are some combinations representing what you can  |
| 62 | // expect to find in a real dds file. These are basically just convenience enumerants that contains some  |
| 63 | // bitwise-ORs of the above flags. You can check for full equality with these enums (no need to check bits).  |
| 64 | DDFormatFlags_FourCC = DDFormatFlag_FOURCC,  |
| 65 | DDFormatFlags_RGB = DDFormatFlag_RGB,  |
| 66 | DDFormatFlags_RGBA = DDFormatFlag_RGB | DDFormatFlag_HASALPHA,  |
| 67 | DDFormatFlags_L = DDFormatFlag_L,  |
| 68 | DDFormatFlags_LA = DDFormatFlag_L | DDFormatFlag_HASALPHA,  |
| 69 | DDFormatFlags_A = DDFormatFlag_A,  |
| 70 | DDFormatFlags_PAL8 = DDFormatFlag_PAL8  |
| 71 | };  |
| 72 |   |
| 73 | #pragma pack(push, 4)  |
| 74 | struct FormatData  |
| 75 | {  |
| 76 | // Must be 32.  |
| 77 | uint32 Size;  |
| 78 |   |
| 79 | // See tDDS::PixelFormatFlags. Flags to indicate valid fields. Uncompressed formats will usually use  |
| 80 | // tDDS::PixelFormatFlags_RGB to indicate an RGB format, while compressed formats will use tDDS::PixelFormatFlags_FourCC  |
| 81 | // with a four-character code.  |
| 82 | uint32 Flags;  |
| 83 |   |
| 84 | // "DXT1", "DXT3", and "DXT5" are examples. m_flags should have DDSPixelFormatFlag_FourCC.  |
| 85 | uint32 FourCC;  |
| 86 |   |
| 87 | // Valid if flags has DDSPixelFormatFlag_RGB. For RGB formats this is the total number of bits per pixel. This  |
| 88 | // value is usually 16, 24, or 32. For A8R8G8B8, this value would be 32.  |
| 89 | uint32 RGBBitCount;  |
| 90 |   |
| 91 | // For RGB formats these three fields contain the masks for the red, green, and blue channels. For A8R8G8B8 these  |
| 92 | // values would be 0x00FF0000, 0x0000FF00, and 0x000000FF respectively.  |
| 93 | uint32 MaskRed;  |
| 94 | uint32 MaskGreen;  |
| 95 | uint32 MaskBlue;  |
| 96 |   |
| 97 | // If the flags have DDSPixelFormatFlag_Alpha set, this is valid and contains tha alpha mask. Eg. For A8R8G8B8 this  |
| 98 | // value would be 0xFF000000.  |
| 99 | uint32 MaskAlpha;  |
| 100 | };  |
| 101 | #pragma pack(pop)  |
| 102 |   |
| 103 | enum CapsBasicFlag : uint32  |
| 104 | {  |
| 105 | CapsBasicFlag_Complex = 0x00000008,  |
| 106 | CapsBasicFlag_Texture = 0x00001000,  |
| 107 | CapsBasicFlag_Mipmap = 0x00400000  |
| 108 | };  |
| 109 |   |
| 110 | enum : uint32  |
| 111 | {  |
| 112 | = 0x00000200,  |
| 113 | = 0x00000400,  |
| 114 | = 0x00000800,  |
| 115 | = 0x00001000,  |
| 116 | = 0x00002000,  |
| 117 | = 0x00004000,  |
| 118 | = 0x00008000,  |
| 119 | = 0x00200000  |
| 120 | };  |
| 121 |   |
| 122 | #pragma pack(push, 4)  |
| 123 | struct Caps  |
| 124 | {  |
| 125 | // DDS files should always include CapsBasicFlag_Texture. If the file contains mipmaps CapsBasicFlag_Mipmap  |
| 126 | // should be set. For any dds file with more than one main surface, such as a mipmap, cubic environment map,  |
| 127 | // or volume texture, CapsBasicFlag_Complex should also be set.  |
| 128 | uint32 FlagsCapsBasic;  |
| 129 |   |
| 130 | // For cubic environment maps CapsExtraFlag_CubeMap should be included as well as one or more faces of the map  |
| 131 | // (CapsExtraFlag_CubeMapPosX, etc). For volume textures CapsExtraFlag_Volume should be set.  |
| 132 | uint32 ;  |
| 133 | uint32 Unused[2];  |
| 134 | };  |
| 135 | #pragma pack(pop)  |
| 136 |   |
| 137 | enum : uint32  |
| 138 | {  |
| 139 | = 0x00000001, // Always included.  |
| 140 | = 0x00000002, // Always included. Height of largest image if mipmaps included.  |
| 141 | = 0x00000004, // Always included. Width of largest image if mipmaps included.  |
| 142 | = 0x00000008,  |
| 143 | = 0x00001000, // Always included.  |
| 144 | = 0x00020000,  |
| 145 | = 0x00080000,  |
| 146 | = 0x00800000  |
| 147 | };  |
| 148 |   |
| 149 | // Default packing is 8 bytes but the header is 128 bytes (mult of 4), so we make it all work here.  |
| 150 | #pragma pack(push, 4)  |
| 151 | struct   |
| 152 | {  |
| 153 | uint32 ; // Must be set to 124.  |
| 154 | uint32 ; // See tDDSFlags.  |
| 155 | uint32 ; // Height of main image.  |
| 156 | uint32 ; // Width of main image.  |
| 157 |   |
| 158 | // For uncompressed formats, this is the number of bytes per scan line (32-bit aligned) for the main image. dwFlags  |
| 159 | // should include DDSD_PITCH in this case. For compressed formats, this is the total number of bytes for the main  |
| 160 | // image. m_flags should have tDDSFlag_LinearSize in this case.  |
| 161 | uint32 ;  |
| 162 | uint32 ; // For volume textures. tDDSFlag_Depth is set for this to be valid.  |
| 163 | uint32 ; // Valid if tDDSFlag_MipmapCount set. @todo Count includes main image?  |
| 164 | uint32 [11];  |
| 165 | FormatData ; // 32 Bytes.  |
| 166 | Caps ; // 16 Bytes.  |
| 167 | uint32 ;  |
| 168 | };  |
| 169 | #pragma pack(pop)  |
| 170 |   |
| 171 | // D3D formats that may appear in DDS files. Would normally not make them uint32s, but they are also used for FourCCs.  |
| 172 | enum D3DFMT : uint32  |
| 173 | {  |
| 174 | D3DFMT_UNKNOWN = 0,  |
| 175 |   |
| 176 | D3DFMT_R8G8B8 = 20,  |
| 177 | D3DFMT_A8R8G8B8 = 21,  |
| 178 | D3DFMT_X8R8G8B8 = 22,  |
| 179 | D3DFMT_R5G6B5 = 23,  |
| 180 | D3DFMT_X1R5G5B5 = 24,  |
| 181 | D3DFMT_A1R5G5B5 = 25,  |
| 182 | D3DFMT_A4R4G4B4 = 26,  |
| 183 | D3DFMT_R3G3B2 = 27,  |
| 184 | D3DFMT_A8 = 28,  |
| 185 | D3DFMT_A8R3G3B2 = 29,  |
| 186 | D3DFMT_X4R4G4B4 = 30,  |
| 187 | D3DFMT_A2B10G10R10 = 31,  |
| 188 | D3DFMT_A8B8G8R8 = 32,  |
| 189 | D3DFMT_X8B8G8R8 = 33,  |
| 190 | D3DFMT_G16R16 = 34,  |
| 191 | D3DFMT_A2R10G10B10 = 35,  |
| 192 | D3DFMT_A16B16G16R16 = 36,  |
| 193 |   |
| 194 | D3DFMT_A8P8 = 40,  |
| 195 | D3DFMT_P8 = 41,  |
| 196 |   |
| 197 | D3DFMT_L8 = 50,  |
| 198 | D3DFMT_A8L8 = 51,  |
| 199 | D3DFMT_A4L4 = 52,  |
| 200 |   |
| 201 | D3DFMT_V8U8 = 60,  |
| 202 | D3DFMT_L6V5U5 = 61,  |
| 203 | D3DFMT_X8L8V8U8 = 62,  |
| 204 | D3DFMT_Q8W8V8U8 = 63,  |
| 205 | D3DFMT_V16U16 = 64,  |
| 206 | D3DFMT_A2W10V10U10 = 67,  |
| 207 |   |
| 208 | D3DFMT_UYVY = FourCC(ch0: 'U', ch1: 'Y', ch2: 'V', ch3: 'Y'),  |
| 209 | D3DFMT_R8G8_B8G8 = FourCC(ch0: 'R', ch1: 'G', ch2: 'B', ch3: 'G'),  |
| 210 | D3DFMT_YUY2 = FourCC(ch0: 'Y', ch1: 'U', ch2: 'Y', ch3: '2'),  |
| 211 | D3DFMT_G8R8_G8B8 = FourCC(ch0: 'G', ch1: 'R', ch2: 'G', ch3: 'B'),  |
| 212 |   |
| 213 | D3DFMT_DXT1 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '1'),  |
| 214 | D3DFMT_DXT2 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '2'),  |
| 215 | D3DFMT_DXT3 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '3'),  |
| 216 | D3DFMT_DXT4 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '4'),  |
| 217 | D3DFMT_DXT5 = FourCC(ch0: 'D', ch1: 'X', ch2: 'T', ch3: '5'),  |
| 218 |   |
| 219 | D3DFMT_BC4U = FourCC(ch0: 'B', ch1: 'C', ch2: '4', ch3: 'U'),  |
| 220 | D3DFMT_BC4S = FourCC(ch0: 'B', ch1: 'C', ch2: '4', ch3: 'S'),  |
| 221 | D3DFMT_BC5U = FourCC(ch0: 'B', ch1: 'C', ch2: '5', ch3: 'U'),  |
| 222 | D3DFMT_BC5S = FourCC(ch0: 'B', ch1: 'C', ch2: '5', ch3: 'S'),  |
| 223 |   |
| 224 | D3DFMT_ATI1 = FourCC(ch0: 'A', ch1: 'T', ch2: 'I', ch3: '1'),  |
| 225 | D3DFMT_AT1N = FourCC(ch0: 'A', ch1: 'T', ch2: '1', ch3: 'N'),  |
| 226 | D3DFMT_ATI2 = FourCC(ch0: 'A', ch1: 'T', ch2: 'I', ch3: '2'),  |
| 227 | D3DFMT_AT2N = FourCC(ch0: 'A', ch1: 'T', ch2: '2', ch3: 'N'),  |
| 228 |   |
| 229 | D3DFMT_ETC = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: ' '), // ETC1 RGB.  |
| 230 | D3DFMT_ETC1 = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: '1'), // ETC1 RGB.  |
| 231 | D3DFMT_ETC2 = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: '2'), // This is the RGB ETC2.  |
| 232 | D3DFMT_ETCA = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: 'A'), // This is the RGBA ETC2.  |
| 233 | D3DFMT_ETCP = FourCC(ch0: 'E', ch1: 'T', ch2: 'C', ch3: 'P'), // This is the RGBA1 ETC2.  |
| 234 |   |
| 235 | D3DFMT_ATC = FourCC(ch0: 'A', ch1: 'T', ch2: 'C', ch3: ' '),  |
| 236 | D3DFMT_ATCA = FourCC(ch0: 'A', ch1: 'T', ch2: 'C', ch3: 'A'),  |
| 237 | D3DFMT_ATCI = FourCC(ch0: 'A', ch1: 'T', ch2: 'C', ch3: 'I'),  |
| 238 | D3DFMT_POWERVR_2BPP = FourCC(ch0: 'P', ch1: 'T', ch2: 'C', ch3: '2'),  |
| 239 | D3DFMT_POWERVR_4BPP = FourCC(ch0: 'P', ch1: 'T', ch2: 'C', ch3: '4'),  |
| 240 |   |
| 241 | D3DFMT_D16_LOCKABLE = 70,  |
| 242 | D3DFMT_D32 = 71,  |
| 243 | D3DFMT_D15S1 = 73,  |
| 244 | D3DFMT_D24S8 = 75,  |
| 245 | D3DFMT_D24X8 = 77,  |
| 246 | D3DFMT_D24X4S4 = 79,  |
| 247 | D3DFMT_D16 = 80,  |
| 248 |   |
| 249 | D3DFMT_D32F_LOCKABLE = 82,  |
| 250 | D3DFMT_D24FS8 = 83,  |
| 251 |   |
| 252 | D3DFMT_D32_LOCKABLE = 84,  |
| 253 | D3DFMT_S8_LOCKABLE = 85,  |
| 254 |   |
| 255 | D3DFMT_L16 = 81,  |
| 256 |   |
| 257 | D3DFMT_VERTEXDATA = 100,  |
| 258 | D3DFMT_INDEX16 = 101,  |
| 259 | D3DFMT_INDEX32 = 102,  |
| 260 |   |
| 261 | D3DFMT_Q16W16V16U16 = 110,  |
| 262 |   |
| 263 | D3DFMT_MULTI2_ARGB8 = FourCC(ch0: 'M',ch1: 'E',ch2: 'T',ch3: '1'),  |
| 264 |   |
| 265 | D3DFMT_R16F = 111,  |
| 266 | D3DFMT_G16R16F = 112,  |
| 267 | D3DFMT_A16B16G16R16F = 113,  |
| 268 |   |
| 269 | D3DFMT_R32F = 114,  |
| 270 | D3DFMT_G32R32F = 115,  |
| 271 | D3DFMT_A32B32G32R32F = 116,  |
| 272 |   |
| 273 | D3DFMT_CxV8U8 = 117,  |
| 274 | D3DFMT_DX10 = FourCC(ch0: 'D', ch1: 'X', ch2: '1', ch3: '0'),  |
| 275 |   |
| 276 | D3DFMT_FORCE_DWORD = 0x7fffffff  |
| 277 | };  |
| 278 |   |
| 279 |   |
| 280 | // More modern DX formats. Made unsigned due to the force-uint (last member).  |
| 281 | enum DXGIFMT : uint32   |
| 282 | {  |
| 283 | DXGIFMT_UNKNOWN, // 0  |
| 284 | DXGIFMT_R32G32B32A32_TYPELESS,  |
| 285 | DXGIFMT_R32G32B32A32_FLOAT,  |
| 286 | DXGIFMT_R32G32B32A32_UINT,  |
| 287 | DXGIFMT_R32G32B32A32_SINT,  |
| 288 | DXGIFMT_R32G32B32_TYPELESS,  |
| 289 | DXGIFMT_R32G32B32_FLOAT,  |
| 290 | DXGIFMT_R32G32B32_UINT,  |
| 291 | DXGIFMT_R32G32B32_SINT,  |
| 292 | DXGIFMT_R16G16B16A16_TYPELESS,  |
| 293 | DXGIFMT_R16G16B16A16_FLOAT, // 10  |
| 294 | DXGIFMT_R16G16B16A16_UNORM,  |
| 295 | DXGIFMT_R16G16B16A16_UINT,  |
| 296 | DXGIFMT_R16G16B16A16_SNORM,  |
| 297 | DXGIFMT_R16G16B16A16_SINT,  |
| 298 | DXGIFMT_R32G32_TYPELESS,  |
| 299 | DXGIFMT_R32G32_FLOAT,  |
| 300 | DXGIFMT_R32G32_UINT,  |
| 301 | DXGIFMT_R32G32_SINT,  |
| 302 | DXGIFMT_R32G8X24_TYPELESS,  |
| 303 | DXGIFMT_D32_FLOAT_S8X24_UINT, // 20  |
| 304 | DXGIFMT_R32_FLOAT_X8X24_TYPELESS,  |
| 305 | DXGIFMT_X32_TYPELESS_G8X24_UINT,  |
| 306 | DXGIFMT_R10G10B10A2_TYPELESS,  |
| 307 | DXGIFMT_R10G10B10A2_UNORM,  |
| 308 | DXGIFMT_R10G10B10A2_UINT,  |
| 309 | DXGIFMT_R11G11B10_FLOAT,  |
| 310 | DXGIFMT_R8G8B8A8_TYPELESS,  |
| 311 | DXGIFMT_R8G8B8A8_UNORM,  |
| 312 | DXGIFMT_R8G8B8A8_UNORM_SRGB,  |
| 313 | DXGIFMT_R8G8B8A8_UINT, // 30  |
| 314 | DXGIFMT_R8G8B8A8_SNORM,  |
| 315 | DXGIFMT_R8G8B8A8_SINT,  |
| 316 | DXGIFMT_R16G16_TYPELESS,  |
| 317 | DXGIFMT_R16G16_FLOAT,  |
| 318 | DXGIFMT_R16G16_UNORM,  |
| 319 | DXGIFMT_R16G16_UINT,  |
| 320 | DXGIFMT_R16G16_SNORM,  |
| 321 | DXGIFMT_R16G16_SINT,  |
| 322 | DXGIFMT_R32_TYPELESS,  |
| 323 | DXGIFMT_D32_FLOAT, // 40  |
| 324 | DXGIFMT_R32_FLOAT,  |
| 325 | DXGIFMT_R32_UINT,  |
| 326 | DXGIFMT_R32_SINT,  |
| 327 | DXGIFMT_R24G8_TYPELESS,  |
| 328 | DXGIFMT_D24_UNORM_S8_UINT,  |
| 329 | DXGIFMT_R24_UNORM_X8_TYPELESS,  |
| 330 | DXGIFMT_X24_TYPELESS_G8_UINT,  |
| 331 | DXGIFMT_R8G8_TYPELESS,  |
| 332 | DXGIFMT_R8G8_UNORM,  |
| 333 | DXGIFMT_R8G8_UINT, // 50  |
| 334 | DXGIFMT_R8G8_SNORM,  |
| 335 | DXGIFMT_R8G8_SINT,  |
| 336 | DXGIFMT_R16_TYPELESS,  |
| 337 | DXGIFMT_R16_FLOAT,  |
| 338 | DXGIFMT_D16_UNORM,  |
| 339 | DXGIFMT_R16_UNORM,  |
| 340 | DXGIFMT_R16_UINT,  |
| 341 | DXGIFMT_R16_SNORM,  |
| 342 | DXGIFMT_R16_SINT,  |
| 343 | DXGIFMT_R8_TYPELESS, // 60  |
| 344 | DXGIFMT_R8_UNORM,  |
| 345 | DXGIFMT_R8_UINT,  |
| 346 | DXGIFMT_R8_SNORM,  |
| 347 | DXGIFMT_R8_SINT,  |
| 348 | DXGIFMT_A8_UNORM,  |
| 349 | DXGIFMT_R1_UNORM,  |
| 350 | DXGIFMT_R9G9B9E5_SHAREDEXP,  |
| 351 | DXGIFMT_R8G8_B8G8_UNORM,  |
| 352 | DXGIFMT_G8R8_G8B8_UNORM,  |
| 353 | DXGIFMT_BC1_TYPELESS, // 70  |
| 354 | DXGIFMT_BC1_UNORM,  |
| 355 | DXGIFMT_BC1_UNORM_SRGB,  |
| 356 | DXGIFMT_BC2_TYPELESS,  |
| 357 | DXGIFMT_BC2_UNORM,  |
| 358 | DXGIFMT_BC2_UNORM_SRGB,  |
| 359 | DXGIFMT_BC3_TYPELESS,  |
| 360 | DXGIFMT_BC3_UNORM,  |
| 361 | DXGIFMT_BC3_UNORM_SRGB,  |
| 362 | DXGIFMT_BC4_TYPELESS,  |
| 363 | DXGIFMT_BC4_UNORM, // 80  |
| 364 | DXGIFMT_BC4_SNORM,  |
| 365 | DXGIFMT_BC5_TYPELESS,  |
| 366 | DXGIFMT_BC5_UNORM,  |
| 367 | DXGIFMT_BC5_SNORM,  |
| 368 | DXGIFMT_B5G6R5_UNORM,  |
| 369 | DXGIFMT_B5G5R5A1_UNORM,  |
| 370 | DXGIFMT_B8G8R8A8_UNORM,  |
| 371 | DXGIFMT_B8G8R8X8_UNORM,  |
| 372 | DXGIFMT_R10G10B10_XR_BIAS_A2_UNORM,  |
| 373 | DXGIFMT_B8G8R8A8_TYPELESS, // 90  |
| 374 | DXGIFMT_B8G8R8A8_UNORM_SRGB,  |
| 375 | DXGIFMT_B8G8R8X8_TYPELESS,  |
| 376 | DXGIFMT_B8G8R8X8_UNORM_SRGB,  |
| 377 | DXGIFMT_BC6H_TYPELESS,  |
| 378 | DXGIFMT_BC6H_UF16,  |
| 379 | DXGIFMT_BC6H_SF16,  |
| 380 | DXGIFMT_BC7_TYPELESS,  |
| 381 | DXGIFMT_BC7_UNORM,  |
| 382 | DXGIFMT_BC7_UNORM_SRGB,  |
| 383 | DXGIFMT_AYUV, // 100  |
| 384 | DXGIFMT_Y410,  |
| 385 | DXGIFMT_Y416,  |
| 386 | DXGIFMT_NV12,  |
| 387 | DXGIFMT_P010,  |
| 388 | DXGIFMT_P016,  |
| 389 | DXGIFMT_420_OPAQUE,  |
| 390 | DXGIFMT_YUY2,  |
| 391 | DXGIFMT_Y210,  |
| 392 | DXGIFMT_Y216,  |
| 393 | DXGIFMT_NV11, // 110  |
| 394 | DXGIFMT_AI44,  |
| 395 | DXGIFMT_IA44,  |
| 396 | DXGIFMT_P8,  |
| 397 | DXGIFMT_A8P8,  |
| 398 | DXGIFMT_B4G4R4A4_UNORM, // 115  |
| 399 |   |
| 400 | DXGIFMT_P208 = 130,  |
| 401 | DXGIFMT_V208,  |
| 402 | DXGIFMT_V408,  |
| 403 |   |
| 404 | // These ASTC formats are extended DXGI formats not (yet?) officially supported by microsoft.  |
| 405 | // The NVTT exporter uses the UNORM versions of these (dx10 header only) when exporting ASTC dds files.  |
| 406 | DXGIFMT_EXT_ASTC_4X4_TYPELESS = 133,  |
| 407 | DXGIFMT_EXT_ASTC_4X4_UNORM,  |
| 408 | DXGIFMT_EXT_ASTC_4X4_UNORM_SRGB,  |
| 409 |   |
| 410 | DXGIFMT_EXT_ASTC_5X4_TYPELESS = 137,  |
| 411 | DXGIFMT_EXT_ASTC_5X4_UNORM,  |
| 412 | DXGIFMT_EXT_ASTC_5X4_UNORM_SRGB,  |
| 413 |   |
| 414 | DXGIFMT_EXT_ASTC_5X5_TYPELESS = 141,  |
| 415 | DXGIFMT_EXT_ASTC_5X5_UNORM,  |
| 416 | DXGIFMT_EXT_ASTC_5X5_UNORM_SRGB,  |
| 417 |   |
| 418 | DXGIFMT_EXT_ASTC_6X5_TYPELESS = 145,  |
| 419 | DXGIFMT_EXT_ASTC_6X5_UNORM,  |
| 420 | DXGIFMT_EXT_ASTC_6X5_UNORM_SRGB,  |
| 421 |   |
| 422 | DXGIFMT_EXT_ASTC_6X6_TYPELESS = 149,  |
| 423 | DXGIFMT_EXT_ASTC_6X6_UNORM,  |
| 424 | DXGIFMT_EXT_ASTC_6X6_UNORM_SRGB,  |
| 425 |   |
| 426 | DXGIFMT_EXT_ASTC_8X5_TYPELESS = 153,  |
| 427 | DXGIFMT_EXT_ASTC_8X5_UNORM,  |
| 428 | DXGIFMT_EXT_ASTC_8X5_UNORM_SRGB,  |
| 429 |   |
| 430 | DXGIFMT_EXT_ASTC_8X6_TYPELESS = 157,  |
| 431 | DXGIFMT_EXT_ASTC_8X6_UNORM,  |
| 432 | DXGIFMT_EXT_ASTC_8X6_UNORM_SRGB,  |
| 433 |   |
| 434 | DXGIFMT_EXT_ASTC_8X8_TYPELESS = 161,  |
| 435 | DXGIFMT_EXT_ASTC_8X8_UNORM,  |
| 436 | DXGIFMT_EXT_ASTC_8X8_UNORM_SRGB,  |
| 437 |   |
| 438 | DXGIFMT_EXT_ASTC_10X5_TYPELESS = 165,  |
| 439 | DXGIFMT_EXT_ASTC_10X5_UNORM,  |
| 440 | DXGIFMT_EXT_ASTC_10X5_UNORM_SRGB,  |
| 441 |   |
| 442 | DXGIFMT_EXT_ASTC_10X6_TYPELESS = 169,  |
| 443 | DXGIFMT_EXT_ASTC_10X6_UNORM,  |
| 444 | DXGIFMT_EXT_ASTC_10X6_UNORM_SRGB,  |
| 445 |   |
| 446 | DXGIFMT_EXT_ASTC_10X8_TYPELESS = 173,  |
| 447 | DXGIFMT_EXT_ASTC_10X8_UNORM,  |
| 448 | DXGIFMT_EXT_ASTC_10X8_UNORM_SRGB,  |
| 449 |   |
| 450 | DXGIFMT_EXT_ASTC_10X10_TYPELESS = 177,  |
| 451 | DXGIFMT_EXT_ASTC_10X10_UNORM,  |
| 452 | DXGIFMT_EXT_ASTC_10X10_UNORM_SRGB,  |
| 453 |   |
| 454 | DXGIFMT_EXT_ASTC_12X10_TYPELESS = 181,  |
| 455 | DXGIFMT_EXT_ASTC_12X10_UNORM,  |
| 456 | DXGIFMT_EXT_ASTC_12X10_UNORM_SRGB,  |
| 457 |   |
| 458 | DXGIFMT_EXT_ASTC_12X12_TYPELESS = 185,  |
| 459 | DXGIFMT_EXT_ASTC_12X12_UNORM,  |
| 460 | DXGIFMT_EXT_ASTC_12X12_UNORM_SRGB,  |
| 461 |   |
| 462 | DXGIFMT_FORCE_UINT = 0xffffffff  |
| 463 | };  |
| 464 |   |
| 465 | enum D3D10_DIMENSION  |
| 466 | {  |
| 467 | D3D10_DIMENSION_UNKNOWN = 0,  |
| 468 | D3D10_DIMENSION_BUFFER = 1,  |
| 469 | D3D10_DIMENSION_TEXTURE1D = 2,  |
| 470 | D3D10_DIMENSION_TEXTURE2D = 3,  |
| 471 | D3D10_DIMENSION_TEXTURE3D = 4  |
| 472 | };  |
| 473 |   |
| 474 | enum D3D11_MISCFLAG : uint32  |
| 475 | {  |
| 476 | D3D11_MISCFLAG_GENERATE_MIPS = 0x00000001,  |
| 477 | D3D11_MISCFLAG_SHARED = 0x00000002,  |
| 478 | D3D11_MISCFLAG_TEXTURECUBE = 0x00000004,  |
| 479 | D3D11_MISCFLAG_DRAWINDIRECT_ARGS = 0x00000010,  |
| 480 | D3D11_MISCFLAG_BUFFER_ALLOW_RAW_VIEWS = 0x00000020,  |
| 481 | D3D11_MISCFLAG_BUFFER_STRUCTURED = 0x00000040,  |
| 482 | D3D11_MISCFLAG_RESOURCE_CLAMP = 0x00000080,  |
| 483 | D3D11_MISCFLAG_SHARED_KEYEDMUTEX = 0x00000100,  |
| 484 | D3D11_MISCFLAG_GDI_COMPATIBLE = 0x00000200,  |
| 485 | D3D11_MISCFLAG_SHARED_NTHANDLE = 0x00000800,  |
| 486 | D3D11_MISCFLAG_RESTRICTED_CONTENT = 0x00001000,  |
| 487 | D3D11_MISCFLAG_RESTRICT_SHARED_RESOURCE = 0x00002000,  |
| 488 | D3D11_MISCFLAG_RESTRICT_SHARED_RESOURCE_DRIVER = 0x00004000,  |
| 489 | D3D11_MISCFLAG_GUARDED = 0x00008000,  |
| 490 | D3D11_MISCFLAG_TILE_POOL = 0x00020000,  |
| 491 | D3D11_MISCFLAG_TILED = 0x00040000,  |
| 492 | D3D11_MISCFLAG_HW_PROTECTED = 0x00080000,  |
| 493 |   |
| 494 | // These are TBD. Don't use.  |
| 495 | D3D11_MISCFLAG_SHARED_DISPLAYABLE,  |
| 496 | D3D11_MISCFLAG_SHARED_EXCLUSIVE_WRITER  |
| 497 | };  |
| 498 |   |
| 499 | #pragma pack(push, 4)  |
| 500 | struct   |
| 501 | {  |
| 502 | DXGIFMT ;  |
| 503 | D3D10_DIMENSION ;  |
| 504 | uint32 ;  |
| 505 | uint32 ;  |
| 506 | uint32 ;  |
| 507 | };  |
| 508 | #pragma pack(pop)  |
| 509 |   |
| 510 | // These figure out the pixel-format, colour-profile, alpha-mode, and channel-type. tPixelFormat does not specify  |
| 511 | // ancilllary properties of the data -- it specified the encoding of the data. The extra information, like the  |
| 512 | // colour-profile it was authored in, is stored in tColourProfile, tAlphaMode, and tChannelType. In many cases this  |
| 513 | // satellite information cannot be determined, in which they will be set to their 'unspecified' enumerant.  |
| 514 | void GetFormatInfo_FromDXGIFormat (tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, uint32 dxgiFormat);  |
| 515 | void GetFormatInfo_FromFourCC (tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, uint32 fourCC);  |
| 516 | void GetFormatInfo_FromComponentMasks (tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, const FormatData&);  |
| 517 | }  |
| 518 |   |
| 519 |   |
| 520 | void tDDS::GetFormatInfo_FromDXGIFormat(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alphaMode, tChannelType& chanType, uint32 dxgiFormat)  |
| 521 | {  |
| 522 | // For colour profile (the space of the data) we try to make an educated guess. In general only the asset author knows the  |
| 523 | // colour space/profile. For most (non-HDR) pixel formats for colours, we assume the data is sRGB. If the pixel format has  |
| 524 | // a specific sRGB alternative, we _should_ assume that the space is the alternative (usually linear) -- however many dds  |
| 525 | // files in the wild set them as UNORM rather than UNORM_SRGB. NVTT for example uses the UNORM (non sRGB) format for all ASTC  |
| 526 | // compressed textures, when it probably should have gone with the sRGB variant (i.e. They 'usually' encode colours).  |
| 527 | // Floating-point formats are assumed to be in linear-space (and are usually used for HDR images). In addition when the data  |
| 528 | // is probably not colour data (like ATI1/2) we assume it's linear.  |
| 529 | //  |
| 530 | // To keep the loading code as clean as possible, we'll respect the dds file's encoded format even if some files are set  |
| 531 | // incorrectly. If the format is typeless, we'll assume sRGB, but set the chanType to Unspecified.  |
| 532 | format = tPixelFormat::Invalid;  |
| 533 | profile = tColourProfile::sRGB;  |
| 534 | alphaMode = tAlphaMode::None;  |
| 535 | chanType = tChannelType::NONE;  |
| 536 |   |
| 537 | #define C(c) case DXGIFMT_##c  |
| 538 | #define F(f) format = tPixelFormat::f;  |
| 539 | #define P(p) profile = tColourProfile::p;  |
| 540 | #define M(m) alphaMode = tAlphaMode::m;  |
| 541 | #define T(t) chanType = tChannelType::t;  |
| 542 |   |
| 543 | // DXGI formats do not specify premultiplied alpha mode like DXT4/5 so we leave it unspecified. As for sRGB,  |
| 544 | // if it says UNORM_SRGB, sure, it may not contain sRGB data, but it's as good as you can get in terms of knowing.  |
| 545 | // I mean if the DirectX loader 'treats' it as being sRGB (in that it will convert it to linear), then we should  |
| 546 | // treat it as being sRGB data in general. Of course it could just be a recipe for apple pie, and if it is, it is  |
| 547 | // a recipe the authors wanted interpreted as sRGB data, otherwise they wouldn't have chosen the _SRGB pixel format.  |
| 548 | // Additionally real files in the wild are mostly still sRGB even with the non _SRGB DXGIFMT. For these cases the  |
| 549 | // switch below still chooses sRGB, but to make it clear, we explicity tag it with a commented out lRGB. That is,  |
| 550 | // when there is a non-sRGB variant and an sRGB variant, it _should_ be that the non-sRGB is linear, but real files  |
| 551 | // are still sRGB, so we explicitly put a commented out lRGB tag. eg. DXGIFMT_BC1_UNORM.  |
| 552 | switch (dxgiFormat)  |
| 553 | {  |
| 554 | //  |
| 555 | // BC Formats.  |
| 556 | //  |
| 557 | C(BC1_TYPELESS): F(BC1DXT1) P(sRGB) M(None) T(NONE) break;  |
| 558 | C(BC1_UNORM): F(BC1DXT1) /*P(lRGB)*/ T(UNORM) break;  |
| 559 | C(BC1_UNORM_SRGB): F(BC1DXT1) T(UNORM) break;  |
| 560 |   |
| 561 | // DXGI formats do not specify premultiplied alpha mode like DXT2/3 so we leave it unspecified.  |
| 562 | C(BC2_TYPELESS): F(BC2DXT2DXT3) break;  |
| 563 | C(BC2_UNORM): F(BC2DXT2DXT3) /*P(lRGB)*/ T(UNORM) break;  |
| 564 | C(BC2_UNORM_SRGB): F(BC2DXT2DXT3) T(UNORM) break;  |
| 565 |   |
| 566 | C(BC3_TYPELESS): F(BC3DXT4DXT5) break;  |
| 567 | C(BC3_UNORM): F(BC3DXT4DXT5) /*P(lRGB)*/ T(UNORM) break;  |
| 568 | C(BC3_UNORM_SRGB): F(BC3DXT4DXT5) T(UNORM) break;  |
| 569 |   |
| 570 | // We don't decode signed properly yet.  |
| 571 | C(BC4_TYPELESS): F(BC4ATI1U) P(lRGB) break;  |
| 572 | C(BC4_UNORM): F(BC4ATI1U) P(lRGB) T(UNORM) break;  |
| 573 | C(BC4_SNORM): F(BC4ATI1S) P(lRGB) T(SNORM) break;  |
| 574 |   |
| 575 | // We don't decode signed properly yet.  |
| 576 | C(BC5_TYPELESS): F(BC5ATI2U) P(lRGB) break;  |
| 577 | C(BC5_UNORM): F(BC5ATI2U) P(lRGB) T(UNORM) break;  |
| 578 | C(BC5_SNORM): F(BC5ATI2S) P(lRGB) T(SNORM) break;  |
| 579 |   |
| 580 | // Alpha not used by BC6. Interpret typeless as BC6H_U16... we gotta choose something.  |
| 581 | C(BC6H_TYPELESS): F(BC6U) P(HDRa) break;  |
| 582 | C(BC6H_UF16): F(BC6U) P(HDRa) T(UFLOAT) break;  |
| 583 | C(BC6H_SF16): F(BC6S) P(HDRa) T(SFLOAT) break;  |
| 584 |   |
| 585 | // Interpret typeless as sRGB. UNORM without the SRGB must be linear.  |
| 586 | C(BC7_TYPELESS): F(BC7) break;  |
| 587 | C(BC7_UNORM): F(BC7) /*P(lRGB)*/ T(UNORM) break;  |
| 588 | C(BC7_UNORM_SRGB): F(BC7) T(UNORM) break;  |
| 589 |   |
| 590 | //  |
| 591 | // Packed Formats.  |
| 592 | //  |
| 593 | C(A8_UNORM): F(A8) P(lRGB) break;  |
| 594 |   |
| 595 | // We don't decode signed properly yet. We treat single R channel as if it's in sRGB.  |
| 596 | C(R8_TYPELESS): F(R8) break;  |
| 597 | C(R8_UNORM): F(R8) T(UNORM) break;  |
| 598 | C(R8_UINT): F(R8) T(UINT) break;  |
| 599 | //C(R8_SNORM): F(R8) T(SNORM) break;  |
| 600 | //C(R8_SINT): F(R8) T(SINT) break;  |
| 601 |   |
| 602 | // We don't decode signed properly yet.  |
| 603 | C(R8G8_TYPELESS): F(R8G8) break;  |
| 604 | C(R8G8_UNORM): F(R8G8) T(UNORM) break;  |
| 605 | C(R8G8_UINT): F(R8G8) T(UINT) break;  |
| 606 | //C(R8G8_SNORM): F(R8G8) T(SNORM) break;  |
| 607 | //C(R8G8_SINT): F(R8G8) T(SINT) break;  |
| 608 |   |
| 609 | // UINT is stored same as UNORM. Only diff is that UNORM ends up as a 'float' from 0.0 to 1.0.  |
| 610 | // We don't decode signed properly yet. Since there is UNORM and UNORM_SRGB, need to assume  |
| 611 | // the UNORM one is linear (otherwise why have sRGB variant).  |
| 612 | // Apparently real files in the wild are mostly still sRGB even with the non _SRGB DXGIFMT.  |
| 613 | C(R8G8B8A8_TYPELESS): F(R8G8B8A8) break;  |
| 614 | C(R8G8B8A8_UNORM): F(R8G8B8A8) /*P(lRGB)*/ T(UNORM) break;  |
| 615 | C(R8G8B8A8_UINT): F(R8G8B8A8) T(UINT) break;  |
| 616 | C(R8G8B8A8_UNORM_SRGB): F(R8G8B8A8) T(UNORM) break;  |
| 617 | //C(R8G8B8A8_SNORM): F(R8G8B8A8) T(SNORM) break;  |
| 618 | //C(R8G8B8A8_SINT): F(R8G8B8A8) T(SINT) break;  |
| 619 |   |
| 620 | C(B8G8R8A8_TYPELESS): F(B8G8R8A8) break;  |
| 621 | C(B8G8R8A8_UNORM): F(B8G8R8A8) /*P(lRGB)*/ T(UNORM) break;  |
| 622 | C(B8G8R8A8_UNORM_SRGB): F(B8G8R8A8) T(UNORM) break;  |
| 623 |   |
| 624 | // Formats without explicit sRGB variants are considered sRGB.  |
| 625 | C(B5G6R5_UNORM): F(G3B5R5G3) T(UNORM) break;  |
| 626 | C(B4G4R4A4_UNORM): F(G4B4A4R4) T(UNORM) break;  |
| 627 | C(B5G5R5A1_UNORM): F(G3B5A1R5G2) T(UNORM) break;  |
| 628 |   |
| 629 | C(R16_FLOAT): F(R16f) P(HDRa) T(SFLOAT) break;  |
| 630 | C(R16G16_FLOAT): F(R16G16f) P(HDRa) T(SFLOAT) break;  |
| 631 | C(R16G16B16A16_FLOAT): F(R16G16B16A16f) P(HDRa) T(SFLOAT) break;  |
| 632 |   |
| 633 | C(R32_FLOAT): F(R32f) P(HDRa) T(SFLOAT) break;  |
| 634 | C(R32G32_FLOAT): F(R32G32f) P(HDRa) T(SFLOAT) break;  |
| 635 | C(R32G32B32_FLOAT): F(R32G32B32f) P(HDRa) T(SFLOAT) break;  |
| 636 | C(R32G32B32A32_FLOAT): F(R32G32B32A32f) P(HDRa) T(SFLOAT) break;  |
| 637 |   |
| 638 | C(R11G11B10_FLOAT): F(B10G11R11uf) P(HDRa) T(UFLOAT) break;  |
| 639 | C(R9G9B9E5_SHAREDEXP): F(E5B9G9R9uf) P(HDRa) T(UFLOAT) break;  |
| 640 |   |
| 641 | //  |
| 642 | // ASTC Formats.  |
| 643 | //  |
| 644 | // We chose HDR as the default profile because it can load LDR blocks. The other way around doesn't work with  |
| 645 | // with the tests images -- the LDR profile doesn't appear capable of loading HDR blocks (they become magenta).  |
| 646 | // Apparently real files in the wild are mostly still sRGB even with the non _SRGB DXGIFMT.  |
| 647 | //  |
| 648 | C(EXT_ASTC_4X4_TYPELESS): F(ASTC4X4) /*P(HDRa)*/ break;  |
| 649 | C(EXT_ASTC_4X4_UNORM): F(ASTC4X4) /*P(HDRa)*/ T(UNORM) break;  |
| 650 | C(EXT_ASTC_4X4_UNORM_SRGB): F(ASTC4X4) T(UNORM) break;  |
| 651 |   |
| 652 | C(EXT_ASTC_5X4_TYPELESS): F(ASTC5X4) /*P(HDRa)*/ break;  |
| 653 | C(EXT_ASTC_5X4_UNORM): F(ASTC5X4) /*P(HDRa)*/ T(UNORM) break;  |
| 654 | C(EXT_ASTC_5X4_UNORM_SRGB): F(ASTC5X4) T(UNORM) break;  |
| 655 |   |
| 656 | C(EXT_ASTC_5X5_TYPELESS): F(ASTC5X5) /*P(HDRa)*/ break;  |
| 657 | C(EXT_ASTC_5X5_UNORM): F(ASTC5X5) /*P(HDRa)*/ T(UNORM) break;  |
| 658 | C(EXT_ASTC_5X5_UNORM_SRGB): F(ASTC5X5) T(UNORM) break;  |
| 659 |   |
| 660 | C(EXT_ASTC_6X5_TYPELESS): F(ASTC6X5) /*P(HDRa)*/ break;  |
| 661 | C(EXT_ASTC_6X5_UNORM): F(ASTC6X5) /*P(HDRa)*/ T(UNORM) break;  |
| 662 | C(EXT_ASTC_6X5_UNORM_SRGB): F(ASTC6X5) T(UNORM) break;  |
| 663 |   |
| 664 | C(EXT_ASTC_6X6_TYPELESS): F(ASTC6X6) /*P(HDRa)*/ break;  |
| 665 | C(EXT_ASTC_6X6_UNORM): F(ASTC6X6) /*P(HDRa)*/ T(UNORM) break;  |
| 666 | C(EXT_ASTC_6X6_UNORM_SRGB): F(ASTC6X6) T(UNORM) break;  |
| 667 |   |
| 668 | C(EXT_ASTC_8X5_TYPELESS): F(ASTC8X5) /*P(HDRa)*/ break;  |
| 669 | C(EXT_ASTC_8X5_UNORM): F(ASTC8X5) /*P(HDRa)*/ T(UNORM) break;  |
| 670 | C(EXT_ASTC_8X5_UNORM_SRGB): F(ASTC8X5) T(UNORM) break;  |
| 671 |   |
| 672 | C(EXT_ASTC_8X6_TYPELESS): F(ASTC8X6) /*P(HDRa)*/ break;  |
| 673 | C(EXT_ASTC_8X6_UNORM): F(ASTC8X6) /*P(HDRa)*/ T(UNORM) break;  |
| 674 | C(EXT_ASTC_8X6_UNORM_SRGB): F(ASTC8X6) T(UNORM) break;  |
| 675 |   |
| 676 | C(EXT_ASTC_8X8_TYPELESS): F(ASTC8X8) /*P(HDRa)*/ break;  |
| 677 | C(EXT_ASTC_8X8_UNORM): F(ASTC8X8) /*P(HDRa)*/ T(UNORM) break;  |
| 678 | C(EXT_ASTC_8X8_UNORM_SRGB): F(ASTC8X8) T(UNORM) break;  |
| 679 |   |
| 680 | C(EXT_ASTC_10X5_TYPELESS): F(ASTC10X5) /*P(HDRa)*/ break;  |
| 681 | C(EXT_ASTC_10X5_UNORM): F(ASTC10X5) /*P(HDRa)*/ T(UNORM) break;  |
| 682 | C(EXT_ASTC_10X5_UNORM_SRGB): F(ASTC10X5) T(UNORM) break;  |
| 683 |   |
| 684 | C(EXT_ASTC_10X6_TYPELESS): F(ASTC10X6) /*P(HDRa)*/ break;  |
| 685 | C(EXT_ASTC_10X6_UNORM): F(ASTC10X6) /*P(HDRa)*/ T(UNORM) break;  |
| 686 | C(EXT_ASTC_10X6_UNORM_SRGB): F(ASTC10X6) T(UNORM) break;  |
| 687 |   |
| 688 | C(EXT_ASTC_10X8_TYPELESS): F(ASTC10X8) /*P(HDRa)*/ break;  |
| 689 | C(EXT_ASTC_10X8_UNORM): F(ASTC10X8) /*P(HDRa)*/ T(UNORM) break;  |
| 690 | C(EXT_ASTC_10X8_UNORM_SRGB): F(ASTC10X8) T(UNORM) break;  |
| 691 |   |
| 692 | C(EXT_ASTC_10X10_TYPELESS): F(ASTC10X10) /*P(HDRa)*/ break;  |
| 693 | C(EXT_ASTC_10X10_UNORM): F(ASTC10X10) /*P(HDRa)*/ T(UNORM) break;  |
| 694 | C(EXT_ASTC_10X10_UNORM_SRGB): F(ASTC10X10) T(UNORM) break;  |
| 695 |   |
| 696 | C(EXT_ASTC_12X10_TYPELESS): F(ASTC12X10) /*P(HDRa)*/ break;  |
| 697 | C(EXT_ASTC_12X10_UNORM): F(ASTC12X10) /*P(HDRa)*/ T(UNORM) break;  |
| 698 | C(EXT_ASTC_12X10_UNORM_SRGB): F(ASTC12X10) T(UNORM) break;  |
| 699 |   |
| 700 | C(EXT_ASTC_12X12_TYPELESS): F(ASTC12X12) /*P(HDRa)*/ break;  |
| 701 | C(EXT_ASTC_12X12_UNORM): F(ASTC12X12) /*P(HDRa)*/ T(UNORM) break;  |
| 702 | C(EXT_ASTC_12X12_UNORM_SRGB): F(ASTC12X12) T(UNORM) break;  |
| 703 |   |
| 704 | default: P(None) break;  |
| 705 | }  |
| 706 | #undef C  |
| 707 | #undef F  |
| 708 | #undef P  |
| 709 | #undef M  |
| 710 | #undef T  |
| 711 | }  |
| 712 |   |
| 713 |   |
| 714 | void tDDS::GetFormatInfo_FromFourCC(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alphaMode, tChannelType& chanType, uint32 fourCC)  |
| 715 | {  |
| 716 | format = tPixelFormat::Invalid;  |
| 717 | profile = tColourProfile::sRGB;  |
| 718 | alphaMode = tAlphaMode::None;  |
| 719 | chanType = tChannelType::NONE;  |
| 720 |   |
| 721 | #define C(c) case D3DFMT_##c  |
| 722 | #define F(f) format = tPixelFormat::f;  |
| 723 | #define P(p) profile = tColourProfile::p;  |
| 724 | #define M(m) alphaMode = tAlphaMode::m;  |
| 725 | #define T(t) chanType = tChannelType::t;  |
| 726 | switch (fourCC)  |
| 727 | {  |
| 728 | // Note that during inspecition of the individual layer data, the DXT1 pixel format might be modified  |
| 729 | // to DXT1BA (binary alpha).  |
| 730 | C(DXT1): F(BC1DXT1) P(sRGB) M(None) T(NONE) break;  |
| 731 |   |
| 732 | // DXT2 and DXT3 are the same format. Only how you interpret the data is different. In tacent we treat them  |
| 733 | // as the same pixel-format. How contents are interpreted (the data) is not part of the format.   |
| 734 | C(DXT2): F(BC2DXT2DXT3) M(Mult) break;  |
| 735 | C(DXT3): F(BC2DXT2DXT3) M(Norm) break;  |
| 736 | C(DXT4): F(BC3DXT4DXT5) M(Mult) break;  |
| 737 | C(DXT5): F(BC3DXT4DXT5) M(Norm) break;  |
| 738 |   |
| 739 | C(ATI1): F(BC4ATI1U) P(lRGB) T(UNORM) break;  |
| 740 | C(BC4U): F(BC4ATI1U) P(lRGB) T(UNORM) break;  |
| 741 | C(BC4S): F(BC4ATI1S) P(lRGB) T(SNORM) break;  |
| 742 |   |
| 743 | C(ATI2): F(BC5ATI2U) P(lRGB) T(UNORM) break;  |
| 744 | C(BC5U): F(BC5ATI2U) P(lRGB) T(UNORM) break;  |
| 745 | C(BC5S): F(BC5ATI2S) P(lRGB) T(SNORM) break;  |
| 746 |   |
| 747 | // We don't yet support signed BC4S or BC5S.  |
| 748 | //C(BC4S): break;  |
| 749 | //C(BC5S): break;  |
| 750 |   |
| 751 | // We don't yet support D3DFMT_R8G8_B8G8 or D3DFMT_G8R8_G8B8 -- That's a lot of green precision.  |
| 752 | //C(R8G8_B8G8): break;  |
| 753 | //C(G8R8_G8B8): break;  |
| 754 |   |
| 755 | C(ETC): F(ETC1) break;  |
| 756 | C(ETC1): F(ETC1) break;  |
| 757 | C(ETC2): F(ETC2RGB) break;  |
| 758 | C(ETCA): F(ETC2RGBA) break;  |
| 759 | C(ETCP): F(ETC2RGBA1) break;  |
| 760 |   |
| 761 | // Sometimes these D3D formats may be stored in the FourCC slot.  |
| 762 | // We don't yet support D3DFMT_A16B16G16R16 or D3DFMT_Q16W16V16U16.  |
| 763 | //C(A16B16G16R16): break;  |
| 764 | //C(Q16W16V16U16): break;  |
| 765 |   |
| 766 | C(A8): F(A8) P(lRGB) break;  |
| 767 | C(L8): F(L8) break;  |
| 768 |   |
| 769 | // It's inconsistent calling the D3D format ABGR. The components are clearly in RGBA order, not ABGR.  |
| 770 | // Anyway, I only have control over the tPixelFormat names. In fairness, it looks like the format-name  |
| 771 | // was fixed in the DX10 header format type names. See  |
| 772 | // https://learn.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-legacy-formats  |
| 773 | C(A8B8G8R8): F(R8G8B8A8) break;  |
| 774 |   |
| 775 | C(R16F): F(R16f) P(HDRa) break;  |
| 776 | C(G16R16F): F(R16G16f) P(HDRa) break;  |
| 777 | C(A16B16G16R16F): F(R16G16B16A16f) P(HDRa) break;  |
| 778 |   |
| 779 | C(R32F): F(R32f) P(HDRa) break;  |
| 780 | C(G32R32F): F(R32G32f) P(HDRa) break;  |
| 781 | C(A32B32G32R32F): F(R32G32B32A32f) P(HDRa) break;  |
| 782 |   |
| 783 | default: P(None) break;  |
| 784 | }  |
| 785 | #undef C  |
| 786 | #undef F  |
| 787 | #undef P  |
| 788 | #undef M  |
| 789 | #undef T  |
| 790 | }  |
| 791 |   |
| 792 |   |
| 793 | void tDDS::GetFormatInfo_FromComponentMasks(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alpha, tChannelType& chanType, const FormatData& fmtData)  |
| 794 | {  |
| 795 | format = tPixelFormat::Invalid;  |
| 796 | profile = tColourProfile::sRGB;  |
| 797 | alpha = tAlphaMode::Unspecified;  |
| 798 | chanType = tChannelType::Unspecified;  |
| 799 |   |
| 800 | uint32 bitCount = fmtData.RGBBitCount;  |
| 801 | bool anyRGB = (fmtData.Flags & tDDS::DDFormatFlag_RGB);  |
| 802 | bool isRGB = (fmtData.Flags == tDDS::DDFormatFlags_RGB);  |
| 803 | bool isRGBA = (fmtData.Flags == tDDS::DDFormatFlags_RGBA);  |
| 804 | bool isA = (fmtData.Flags == tDDS::DDFormatFlags_A);  |
| 805 | bool isL = (fmtData.Flags == tDDS::DDFormatFlags_L);  |
| 806 | uint32 mskR = fmtData.MaskRed;  |
| 807 | uint32 mskG = fmtData.MaskGreen;  |
| 808 | uint32 mskB = fmtData.MaskBlue;  |
| 809 | uint32 mskA = fmtData.MaskAlpha;  |
| 810 |   |
| 811 | // Remember this is a little endian machine, so the masks are lying. Eg. 0x00FF0000 in memory is 00 00 FF 00 cuz it's encoded  |
| 812 | // as an int32 -- so the red comes after blue and green.  |
| 813 | switch (bitCount)  |
| 814 | {  |
| 815 | case 8: // Supports A8, L8.  |
| 816 | if ((isA || anyRGB) && (mskA == 0xFF))  |
| 817 | format = tPixelFormat::A8;  |
| 818 | else if ((isL || anyRGB) && (mskR == 0xFF))  |
| 819 | format = tPixelFormat::L8;  |
| 820 | break;  |
| 821 |   |
| 822 | case 16: // Supports G3B5R5G3, G4B4A4R4, and G3B5A1R5G2.  |
| 823 | if (isRGBA && (mskB == 0x001F) && (mskG == 0x03E0) && (mskR == 0x7C00) && (mskA == 0x8000))  |
| 824 | format = tPixelFormat::G3B5A1R5G2;  |
| 825 | else if (isRGBA && (mskB == 0x000F) && (mskG == 0x00F0) && (mskR == 0x0F00) && (mskA == 0xF000))  |
| 826 | format = tPixelFormat::G4B4A4R4;  |
| 827 | else if (isRGB && (mskB == 0x001F) && (mskG == 0x07E0) && (mskR == 0xF800))  |
| 828 | format = tPixelFormat::G3B5R5G3;  |
| 829 | break;  |
| 830 |   |
| 831 | case 24: // Supports B8G8R8 and R8G8B8.  |
| 832 | if (isRGB && (mskB == 0x0000FF) && (mskG == 0x00FF00) && (mskR == 0xFF0000))  |
| 833 | format = tPixelFormat::B8G8R8;  |
| 834 | else if (isRGB && (mskR == 0x0000FF) && (mskG == 0x00FF00) && (mskB == 0xFF0000))  |
| 835 | format = tPixelFormat::R8G8B8;  |
| 836 | break;  |
| 837 |   |
| 838 | case 32: // Supports B8G8R8A8 and R8G8B8A8.  |
| 839 | if (isRGBA && (mskB == 0x000000FF) && (mskG == 0x0000FF00) && (mskR == 0x00FF0000) && (mskA == 0xFF000000))  |
| 840 | format = tPixelFormat::B8G8R8A8;  |
| 841 | else if (isRGBA && (mskR == 0x000000FF) && (mskG == 0x0000FF00) && (mskB == 0x00FF0000) && (mskA == 0xFF000000))  |
| 842 | format = tPixelFormat::R8G8B8A8;  |
| 843 | break;  |
| 844 | }  |
| 845 |   |
| 846 | switch (format)  |
| 847 | {  |
| 848 | case tPixelFormat::A8:  |
| 849 | profile = tColourProfile::lRGB;  |
| 850 | break;  |
| 851 |   |
| 852 | case tPixelFormat::Invalid:  |
| 853 | profile = tColourProfile::None;  |
| 854 | break;  |
| 855 | }  |
| 856 | }  |
| 857 |   |
| 858 |   |
| 859 | tImageDDS::tImageDDS()  |
| 860 | {  |
| 861 | tStd::tMemset(dest: Layers, val: 0, numBytes: sizeof(Layers));  |
| 862 | }  |
| 863 |   |
| 864 |   |
| 865 | tImageDDS::tImageDDS(const tString& ddsFile, const LoadParams& loadParams) :  |
| 866 | Filename(ddsFile)  |
| 867 | {  |
| 868 | tStd::tMemset(dest: Layers, val: 0, numBytes: sizeof(Layers));  |
| 869 | Load(ddsFile, loadParams);  |
| 870 | }  |
| 871 |   |
| 872 |   |
| 873 | tImageDDS::tImageDDS(const uint8* ddsFileInMemory, int numBytes, const LoadParams& loadParams)  |
| 874 | {  |
| 875 | tStd::tMemset(dest: Layers, val: 0, numBytes: sizeof(Layers));  |
| 876 | Load(ddsFileInMemory, numBytes, loadParams);  |
| 877 | }  |
| 878 |   |
| 879 |   |
| 880 | void tImageDDS::Clear()  |
| 881 | {  |
| 882 | tBaseImage::Clear();  |
| 883 | for (int image = 0; image < NumImages; image++)  |
| 884 | {  |
| 885 | for (int layer = 0; layer < NumMipmapLayers; layer++)  |
| 886 | {  |
| 887 | delete Layers[layer][image];  |
| 888 | Layers[layer][image] = nullptr;  |
| 889 | }  |
| 890 | }  |
| 891 |   |
| 892 | States = 0; // Image will be invalid now since Valid state not set.  |
| 893 | AlphaMode = tAlphaMode::Unspecified;  |
| 894 | ChannelType = tChannelType::Unspecified;  |
| 895 | IsCubeMap = false;  |
| 896 | IsModernDX10 = false;  |
| 897 | RowReversalOperationPerformed = false;  |
| 898 | NumImages = 0;  |
| 899 | NumMipmapLayers = 0;  |
| 900 | }  |
| 901 |   |
| 902 |   |
| 903 | bool tImageDDS::Set(tPixel4b* pixels, int width, int height, bool steal)  |
| 904 | {  |
| 905 | Clear();  |
| 906 | if (!pixels || (width <= 0) || (height <= 0))  |
| 907 | return false;  |
| 908 |   |
| 909 | Layers[0][0] = new tLayer(tPixelFormat::R8G8B8A8, width, height, (uint8*)pixels, steal);  |
| 910 | AlphaMode = tAlphaMode::Normal;  |
| 911 | ChannelType = tChannelType::UNORM;  |
| 912 | IsCubeMap = false;  |
| 913 | IsModernDX10 = false;  |
| 914 | RowReversalOperationPerformed = false;  |
| 915 | NumImages = 1;  |
| 916 | NumMipmapLayers = 1;  |
| 917 |   |
| 918 | PixelFormatSrc = tPixelFormat::R8G8B8A8;  |
| 919 | PixelFormat = tPixelFormat::R8G8B8A8;  |
| 920 | ColourProfileSrc = tColourProfile::sRGB; // We assume pixels must be sRGB.  |
| 921 | ColourProfile = tColourProfile::sRGB;  |
| 922 |   |
| 923 | SetStateBit(StateBit::Valid);  |
| 924 | return true;  |
| 925 | }  |
| 926 |   |
| 927 |   |
| 928 | bool tImageDDS::Set(tFrame* frame, bool steal)  |
| 929 | {  |
| 930 | Clear();  |
| 931 | if (!frame || !frame->IsValid())  |
| 932 | return false;  |
| 933 |   |
| 934 | PixelFormatSrc = frame->PixelFormatSrc;  |
| 935 | PixelFormat = tPixelFormat::R8G8B8A8;  |
| 936 | ColourProfileSrc = tColourProfile::sRGB; // We assume frame must be sRGB.  |
| 937 | ColourProfile = tColourProfile::sRGB;  |
| 938 |   |
| 939 | tPixel4b* pixels = frame->GetPixels(steal);  |
| 940 | Set(pixels, width: frame->Width, height: frame->Height, steal);  |
| 941 | if (steal)  |
| 942 | delete frame;  |
| 943 |   |
| 944 | SetStateBit(StateBit::Valid);  |
| 945 | return true;  |
| 946 | }  |
| 947 |   |
| 948 |   |
| 949 | bool tImageDDS::Set(tPicture& picture, bool steal)  |
| 950 | {  |
| 951 | Clear();  |
| 952 | if (!picture.IsValid())  |
| 953 | return false;  |
| 954 |   |
| 955 | PixelFormatSrc = picture.PixelFormatSrc;  |
| 956 | PixelFormat = tPixelFormat::R8G8B8A8;  |
| 957 | // We don't know colour profile of tPicture.  |
| 958 |   |
| 959 | // This is worth some explanation. If steal is true the picture becomes invalid and the  |
| 960 | // 'set' call will steal the stolen pixels. If steal is false GetPixels is called and the  |
| 961 | // 'set' call will memcpy them out... which makes sure the picture is still valid after and  |
| 962 | // no-one is sharing the pixel buffer. We don't check the success of 'set' because it must  |
| 963 | // succeed if picture was valid.  |
| 964 | tPixel4b* pixels = steal ? picture.StealPixels() : picture.GetPixels();  |
| 965 | bool success = Set(pixels, width: picture.GetWidth(), height: picture.GetHeight(), steal);  |
| 966 | tAssert(success);  |
| 967 | return true;  |
| 968 | }  |
| 969 |   |
| 970 |   |
| 971 | tFrame* tImageDDS::GetFrame(bool steal)  |
| 972 | {  |
| 973 | // Data must be decoded for this to work.  |
| 974 | if (!IsValid() || (PixelFormat != tPixelFormat::R8G8B8A8) || (Layers[0][0] == nullptr))  |
| 975 | return nullptr;  |
| 976 |   |
| 977 | tFrame* frame = new tFrame();  |
| 978 | frame->Width = Layers[0][0]->Width;  |
| 979 | frame->Height = Layers[0][0]->Height;  |
| 980 | frame->PixelFormatSrc = PixelFormatSrc;  |
| 981 |   |
| 982 | if (steal)  |
| 983 | {  |
| 984 | frame->Pixels = (tPixel4b*)Layers[0][0]->StealData();  |
| 985 | delete Layers[0][0];  |
| 986 | Layers[0][0] = nullptr;  |
| 987 | }  |
| 988 | else  |
| 989 | {  |
| 990 | frame->Pixels = new tPixel4b[frame->Width * frame->Height];  |
| 991 | tStd::tMemcpy(dest: frame->Pixels, src: (tPixel4b*)Layers[0][0]->Data, numBytes: frame->Width * frame->Height * sizeof(tPixel4b));  |
| 992 | }  |
| 993 |   |
| 994 | return frame;  |
| 995 | }  |
| 996 |   |
| 997 |   |
| 998 | bool tImageDDS::IsOpaque() const  |
| 999 | {  |
| 1000 | return tImage::tIsOpaqueFormat(format: PixelFormat);  |
| 1001 | }  |
| 1002 |   |
| 1003 |   |
| 1004 | bool tImageDDS::StealLayers(tList<tLayer>& layers)  |
| 1005 | {  |
| 1006 | if (!IsValid() || IsCubemap() || (NumImages <= 0))  |
| 1007 | return false;  |
| 1008 |   |
| 1009 | for (int mip = 0; mip < NumMipmapLayers; mip++)  |
| 1010 | {  |
| 1011 | layers.Append(item: Layers[mip][0]);  |
| 1012 | Layers[mip][0] = nullptr;  |
| 1013 | }  |
| 1014 |   |
| 1015 | Clear();  |
| 1016 | return true;  |
| 1017 | }  |
| 1018 |   |
| 1019 |   |
| 1020 | int tImageDDS::GetLayers(tList<tLayer>& layers) const  |
| 1021 | {  |
| 1022 | if (!IsValid() || IsCubemap() || (NumImages <= 0))  |
| 1023 | return 0;  |
| 1024 |   |
| 1025 | for (int mip = 0; mip < NumMipmapLayers; mip++)  |
| 1026 | layers.Append(item: Layers[mip][0]);  |
| 1027 |   |
| 1028 | return NumMipmapLayers;  |
| 1029 | }  |
| 1030 |   |
| 1031 |   |
| 1032 | int tImageDDS::StealCubemapLayers(tList<tLayer> layerLists[tFaceIndex_NumFaces], uint32 faceFlags)  |
| 1033 | {  |
| 1034 | if (!IsValid() || !IsCubemap() || !faceFlags)  |
| 1035 | return 0;  |
| 1036 |   |
| 1037 | int faceCount = 0;  |
| 1038 | for (int face = 0; face < tFaceIndex_NumFaces; face++)  |
| 1039 | {  |
| 1040 | uint32 faceFlag = 1 << face;  |
| 1041 | if (!(faceFlag & faceFlags))  |
| 1042 | continue;  |
| 1043 |   |
| 1044 | tList<tLayer>& layers = layerLists[face];  |
| 1045 | for (int mip = 0; mip < NumMipmapLayers; mip++)  |
| 1046 | {  |
| 1047 | layers.Append( item: Layers[mip][face] );  |
| 1048 | Layers[mip][face] = nullptr;  |
| 1049 | }  |
| 1050 | faceCount++;  |
| 1051 | }  |
| 1052 |   |
| 1053 | Clear();  |
| 1054 | return faceCount;  |
| 1055 | }  |
| 1056 |   |
| 1057 |   |
| 1058 | int tImageDDS::GetCubemapLayers(tList<tLayer> layerLists[tFaceIndex_NumFaces], uint32 faceFlags) const  |
| 1059 | {  |
| 1060 | if (!IsValid() || !IsCubemap() || !faceFlags)  |
| 1061 | return 0;  |
| 1062 |   |
| 1063 | int sideCount = 0;  |
| 1064 | for (int face = 0; face < tFaceIndex_NumFaces; face++)  |
| 1065 | {  |
| 1066 | uint32 faceFlag = 1 << face;  |
| 1067 | if (!(faceFlag & faceFlags))  |
| 1068 | continue;  |
| 1069 |   |
| 1070 | tList<tLayer>& layers = layerLists[face];  |
| 1071 | for (int mip = 0; mip < NumMipmapLayers; mip++)  |
| 1072 | layers.Append( item: Layers[mip][face] );  |
| 1073 |   |
| 1074 | sideCount++;  |
| 1075 | }  |
| 1076 |   |
| 1077 | return sideCount;  |
| 1078 | }  |
| 1079 |   |
| 1080 |   |
| 1081 | bool tImageDDS::Load(const tString& ddsFile, const LoadParams& loadParams)  |
| 1082 | {  |
| 1083 | Clear();  |
| 1084 | Filename = ddsFile;  |
| 1085 | if (tSystem::tGetFileType(file: ddsFile) != tSystem::tFileType::DDS)  |
| 1086 | {  |
| 1087 | SetStateBit(StateBit::Fatal_IncorrectFileType);  |
| 1088 | return false;  |
| 1089 | }  |
| 1090 |   |
| 1091 | if (!tSystem::tFileExists(file: ddsFile))  |
| 1092 | {  |
| 1093 | SetStateBit(StateBit::Fatal_FileDoesNotExist);  |
| 1094 | return false;  |
| 1095 | }  |
| 1096 |   |
| 1097 | int ddsSizeBytes = 0;  |
| 1098 | uint8* ddsData = (uint8*)tSystem::tLoadFile(file: ddsFile, buffer: 0, fileSize: &ddsSizeBytes);  |
| 1099 | bool success = Load(ddsFileInMemory: ddsData, numBytes: ddsSizeBytes, loadParams);  |
| 1100 | delete[] ddsData;  |
| 1101 |   |
| 1102 | return success;  |
| 1103 | }  |
| 1104 |   |
| 1105 |   |
| 1106 | bool tImageDDS::Load(const uint8* ddsData, int ddsDataSize, const LoadParams& paramsIn)  |
| 1107 | {  |
| 1108 | Clear();  |
| 1109 | LoadParams params(paramsIn);  |
| 1110 |   |
| 1111 | // This will deal with zero-sized files properly as well.  |
| 1112 | if (ddsDataSize < int(sizeof(tDDS::Header)+sizeof(uint32)))  |
| 1113 | {  |
| 1114 | SetStateBit(StateBit::Fatal_IncorrectFileSize);  |
| 1115 | return false;  |
| 1116 | }  |
| 1117 |   |
| 1118 | uint32& magic = *((uint32*)ddsData);  |
| 1119 | ddsData += sizeof(uint32); ddsDataSize -= sizeof(uint32);  |
| 1120 | if (magic != FourCC(ch0: 'D',ch1: 'D',ch2: 'S',ch3: ' '))  |
| 1121 | {  |
| 1122 | SetStateBit(StateBit::Fatal_IncorrectMagicNumber);  |
| 1123 | return false;  |
| 1124 | }  |
| 1125 |   |
| 1126 | tDDS::Header& = *((tDDS::Header*)ddsData);  |
| 1127 | ddsData += sizeof(header); ddsDataSize -= sizeof(header);  |
| 1128 | tStaticAssert(sizeof(tDDS::Header) == 124);  |
| 1129 | if (header.Size != 124)  |
| 1130 | {  |
| 1131 | SetStateBit(StateBit::Fatal_IncorrectHeaderSize);  |
| 1132 | return false;  |
| 1133 | }  |
| 1134 |   |
| 1135 | uint32 flags = header.Flags;  |
| 1136 | int mainWidth = header.Width; // Main image.  |
| 1137 | int mainHeight = header.Height; // Main image.  |
| 1138 | if ((mainWidth <= 0) || (mainHeight <= 0))  |
| 1139 | {  |
| 1140 | SetStateBit(StateBit::Fatal_InvalidDimensions);  |
| 1141 | return false;  |
| 1142 | }  |
| 1143 |   |
| 1144 | // A strictly correct dds will have linear-size xor pitch set (one, not both).  |
| 1145 | // It seems ATI tools like GenCubeMap don't set the correct bits, but we still load  |
| 1146 | // with a conditional success if strict flag unset.  |
| 1147 | int pitch = 0; // Num bytes per line on main image (uncompressed images only).  |
| 1148 | int linearSize = 0; // Num bytes total main image (compressed images only).  |
| 1149 | if (flags & tDDS::HeaderFlag_Pitch)  |
| 1150 | pitch = header.PitchLinearSize;  |
| 1151 | if (flags & tDDS::HeaderFlag_LinearSize)  |
| 1152 | linearSize = header.PitchLinearSize;  |
| 1153 |   |
| 1154 | if ((!linearSize && !pitch) || (linearSize && pitch))  |
| 1155 | {  |
| 1156 | if (params.Flags & LoadFlag_StrictLoading)  |
| 1157 | {  |
| 1158 | SetStateBit(StateBit::Fatal_PitchXORLinearSize);  |
| 1159 | return false;  |
| 1160 | }  |
| 1161 | else  |
| 1162 | {  |
| 1163 | SetStateBit(StateBit::Conditional_PitchXORLinearSize);  |
| 1164 | }  |
| 1165 | }  |
| 1166 |   |
| 1167 | // Volume textures are not supported.  |
| 1168 | if (flags & tDDS::HeaderFlag_Depth)  |
| 1169 | {  |
| 1170 | SetStateBit(StateBit::Fatal_VolumeTexturesNotSupported);  |
| 1171 | return false;  |
| 1172 | }  |
| 1173 |   |
| 1174 | // Determine the expected number of layers by looking at the mipmap count if it is supplied. We assume a single layer  |
| 1175 | // if it is not specified.  |
| 1176 | NumMipmapLayers = 1;  |
| 1177 | bool hasMipmaps = (header.Capabilities.FlagsCapsBasic & tDDS::CapsBasicFlag_Mipmap) ? true : false;  |
| 1178 | if ((flags & tDDS::HeaderFlag_MipmapCount) && hasMipmaps)  |
| 1179 | NumMipmapLayers = header.MipmapCount;  |
| 1180 |   |
| 1181 | if (NumMipmapLayers > MaxMipmapLayers)  |
| 1182 | {  |
| 1183 | SetStateBit(StateBit::Fatal_MaxNumMipmapLevelsExceeded);  |
| 1184 | return false;  |
| 1185 | }  |
| 1186 |   |
| 1187 | tDDS::FormatData& format = header.Format;  |
| 1188 | if (format.Size != 32)  |
| 1189 | {  |
| 1190 | SetStateBit(StateBit::Fatal_IncorrectPixelFormatHeaderSize);  |
| 1191 | return false;  |
| 1192 | }  |
| 1193 |   |
| 1194 | // Determine if we support the pixel format and which one it is.  |
| 1195 | bool isRGB = (format.Flags == tDDS::DDFormatFlags_RGB);  |
| 1196 | bool isRGBA = (format.Flags == tDDS::DDFormatFlags_RGBA);  |
| 1197 | bool isA = (format.Flags == tDDS::DDFormatFlags_A);  |
| 1198 | bool isL = (format.Flags == tDDS::DDFormatFlags_L);  |
| 1199 | bool isFourCCFormat = (format.Flags == tDDS::DDFormatFlags_FourCC);  |
| 1200 | if (!isRGB && !isRGBA && !isA && !isL && !isFourCCFormat)  |
| 1201 | {  |
| 1202 | if (params.Flags & LoadFlag_StrictLoading)  |
| 1203 | {  |
| 1204 | SetStateBit(StateBit::Fatal_IncorrectPixelFormatSpec);  |
| 1205 | return false;  |
| 1206 | }  |
| 1207 | else  |
| 1208 | {  |
| 1209 | // If the flags completely fail to specify a format, we try to use the FourCC.  |
| 1210 | SetStateBit(StateBit::Conditional_IncorrectPixelFormatSpec);  |
| 1211 | isFourCCFormat = true;  |
| 1212 | }  |
| 1213 | }  |
| 1214 |   |
| 1215 | IsModernDX10 = isFourCCFormat && (format.FourCC == tDDS::D3DFMT_DX10);  |
| 1216 |   |
| 1217 | // Determine if this is a cubemap dds with 6 images. No need to check which images are present since they are  |
| 1218 | // required to be all there by the dds standard. All tools these days seem to write them all. If there are  |
| 1219 | // complaints when using legacy files we can fix this. We use FlagsCapsExtra in all cases where we are not using  |
| 1220 | // the DX10 extension header.  |
| 1221 | IsCubeMap = false;  |
| 1222 | NumImages = 1;  |
| 1223 | if (!IsModernDX10 && (header.Capabilities.FlagsCapsExtra & tDDS::CapsExtraFlag_CubeMap))  |
| 1224 | {  |
| 1225 | IsCubeMap = true;  |
| 1226 | NumImages = 6;  |
| 1227 | }  |
| 1228 |   |
| 1229 | if (IsModernDX10)  |
| 1230 | {  |
| 1231 | if (ddsDataSize < int(sizeof(tDDS::DX10Header)))  |
| 1232 | {  |
| 1233 | SetStateBit(StateBit::Fatal_IncorrectFileSize);  |
| 1234 | return false;  |
| 1235 | }  |
| 1236 |   |
| 1237 | tDDS::DX10Header& = *((tDDS::DX10Header*)ddsData);  |
| 1238 | ddsData += sizeof(tDDS::DX10Header); ddsDataSize -= sizeof(tDDS::DX10Header);  |
| 1239 | if (headerDX10.ArraySize == 0)  |
| 1240 | {  |
| 1241 | SetStateBit(StateBit::Fatal_DX10HeaderSizeIncorrect);  |
| 1242 | return false;  |
| 1243 | }  |
| 1244 |   |
| 1245 | // We only handle 2D textures for now.  |
| 1246 | if (headerDX10.Dimension != tDDS::D3D10_DIMENSION_TEXTURE2D)  |
| 1247 | {  |
| 1248 | SetStateBit(StateBit::Fatal_DX10DimensionNotSupported);  |
| 1249 | return false;  |
| 1250 | }  |
| 1251 |   |
| 1252 | if (headerDX10.MiscFlag & tDDS::D3D11_MISCFLAG_TEXTURECUBE)  |
| 1253 | {  |
| 1254 | IsCubeMap = true;  |
| 1255 | NumImages = 6;  |
| 1256 | }  |
| 1257 |   |
| 1258 | // If we found a dx10 chunk. It must be used to determine the pixel format and possibly any known colour-profile info.  |
| 1259 | tDDS::GetFormatInfo_FromDXGIFormat(format&: PixelFormat, profile&: ColourProfile, alphaMode&: AlphaMode, chanType&: ChannelType, dxgiFormat: headerDX10.DxgiFormat);  |
| 1260 | }  |
| 1261 | else if (isFourCCFormat)  |
| 1262 | {  |
| 1263 | tDDS::GetFormatInfo_FromFourCC(format&: PixelFormat, profile&: ColourProfile, alphaMode&: AlphaMode, chanType&: ChannelType, fourCC: format.FourCC);  |
| 1264 | }  |
| 1265 | // It must be a simple uncompressed format.  |
| 1266 | else  |
| 1267 | {  |
| 1268 | tDDS::GetFormatInfo_FromComponentMasks(format&: PixelFormat, profile&: ColourProfile, alpha&: AlphaMode, chanType&: ChannelType, fmtData: format);  |
| 1269 | }  |
| 1270 | PixelFormatSrc = PixelFormat;  |
| 1271 | ColourProfileSrc = ColourProfile;  |
| 1272 |   |
| 1273 | // From now on we should just be using the PixelFormat to decide what to do next.  |
| 1274 | if (PixelFormat == tPixelFormat::Invalid)  |
| 1275 | {  |
| 1276 | SetStateBit(StateBit::Fatal_PixelFormatNotSupported);  |
| 1277 | return false;  |
| 1278 | }  |
| 1279 |   |
| 1280 | if (tIsBCFormat(format: PixelFormat))  |
| 1281 | {  |
| 1282 | if ((params.Flags & LoadFlag_CondMultFourDim) && ((mainWidth%4) || (mainHeight%4)))  |
| 1283 | SetStateBit(StateBit::Conditional_DimNotMultFourBC);  |
| 1284 | if ((params.Flags & LoadFlag_CondPowerTwoDim) && (!tMath::tIsPower2(v: mainWidth) || !tMath::tIsPower2(v: mainHeight)))  |
| 1285 | SetStateBit(StateBit::Conditional_DimNotMultFourBC);  |
| 1286 | }  |
| 1287 |   |
| 1288 | bool reverseRowOrderRequested = params.Flags & LoadFlag_ReverseRowOrder;  |
| 1289 | RowReversalOperationPerformed = false;  |
| 1290 |   |
| 1291 | // For images whose height is not a multiple of the block size it makes it tricky when deoompressing to do  |
| 1292 | // the more efficient row reversal here, so we defer it. Packed formats have a block height of 1. Only BC  |
| 1293 | // and astc have non-unity block dimensins.  |
| 1294 | bool doRowReversalBeforeDecode = false;  |
| 1295 | if (reverseRowOrderRequested)  |
| 1296 | {  |
| 1297 | bool canDo = true;  |
| 1298 | for (int image = 0; image < NumImages; image++)  |
| 1299 | {  |
| 1300 | int height = mainHeight;  |
| 1301 | for (int layer = 0; layer < NumMipmapLayers; layer++)  |
| 1302 | {  |
| 1303 | if (!CanReverseRowData(PixelFormat, height))  |
| 1304 | {  |
| 1305 | canDo = false;  |
| 1306 | break;  |
| 1307 | }  |
| 1308 | height /= 2; if (height < 1) height = 1;  |
| 1309 | }  |
| 1310 | if (!canDo)  |
| 1311 | break;  |
| 1312 | }  |
| 1313 | doRowReversalBeforeDecode = canDo;  |
| 1314 | }  |
| 1315 |   |
| 1316 | for (int image = 0; image < NumImages; image++)  |
| 1317 | {  |
| 1318 | int width = mainWidth;  |
| 1319 | int height = mainHeight;  |
| 1320 | for (int layer = 0; layer < NumMipmapLayers; layer++)  |
| 1321 | {  |
| 1322 | int numBytes = 0;  |
| 1323 | if (tImage::tIsBCFormat(format: PixelFormat) || tImage::tIsASTCFormat(format: PixelFormat) || tImage::tIsPackedFormat(format: PixelFormat))  |
| 1324 | {  |
| 1325 | // It's a block format (BC/DXTn or ASTC). Each block encodes a 4x4 up to 12x12 square of pixels. DXT2,3,4,5 and BC 6,7 use 128  |
| 1326 | // bits per block. DXT1 and DXT1A (BC1) use 64bits per block. ASTC always uses 128 bits per block but it's not always 4x4.  |
| 1327 | // Packed formats are considered to have a block width and height of 1.  |
| 1328 | int blockW = tGetBlockWidth(PixelFormat);  |
| 1329 | int blockH = tGetBlockHeight(PixelFormat);  |
| 1330 | int bytesPerBlock = tImage::tGetBytesPerBlock(PixelFormat);  |
| 1331 | tAssert(bytesPerBlock > 0);  |
| 1332 | int numBlocksW = tGetNumBlocks(blockWH: blockW, imageWH: width);  |
| 1333 | int numBlocksH = tGetNumBlocks(blockWH: blockH, imageWH: height);  |
| 1334 | int numBlocks = numBlocksW*numBlocksH;  |
| 1335 | numBytes = numBlocks * bytesPerBlock;  |
| 1336 |   |
| 1337 | // Check that the amount of data left is enough to read in numBytes.  |
| 1338 | if (numBytes > ddsDataSize)  |
| 1339 | {  |
| 1340 | Clear();  |
| 1341 | SetStateBit(StateBit::Fatal_IncorrectFileSize);  |
| 1342 | return false;  |
| 1343 | }  |
| 1344 |   |
| 1345 | // Here's where we possibly modify the opaque DXT1 texture to be DXT1A if there are blocks with binary  |
| 1346 | // transparency. We only bother checking the main layer. If it's opaque we assume all the others are too.  |
| 1347 | if ((layer == 0) && (PixelFormat == tPixelFormat::BC1DXT1) && tImage::DoBC1BlocksHaveBinaryAlpha(blocks: (tImage::BC1Block*)ddsData, numBlocks))  |
| 1348 | PixelFormat = PixelFormatSrc = tPixelFormat::BC1DXT1A;  |
| 1349 |   |
| 1350 | // DDS files store textures upside down. In the OpenGL RH coord system, the lower left of the texture  |
| 1351 | // is the origin and consecutive rows go up. For this reason we need to read each row of blocks from  |
| 1352 | // the top to the bottom row. We also need to flip the rows within the 4x4 block by flipping the lookup  |
| 1353 | // tables. This should be fairly fast as there is no encoding or decoding going on. Width and height  |
| 1354 | // will go down to 1x1, which will still use a 4x4 DXT pixel-block.  |
| 1355 | if (doRowReversalBeforeDecode)  |
| 1356 | {  |
| 1357 | uint8* reversedPixelData = tImage::CreateReversedRowData(pixelData: ddsData, pixelDataFormat: PixelFormat, numBlocksW, numBlocksH);  |
| 1358 | tAssert(reversedPixelData);  |
| 1359 |   |
| 1360 | // We can simply get the layer to steal the memory (the last true arg).  |
| 1361 | Layers[layer][image] = new tLayer(PixelFormat, width, height, reversedPixelData, true);  |
| 1362 | }  |
| 1363 | else  |
| 1364 | {  |
| 1365 | // Not reversing. Use the current ddsData. Note that steal is false here so the data  |
| 1366 | // is both copied and owned by the new tLayer.  |
| 1367 | Layers[layer][image] = new tLayer(PixelFormat, width, height, (uint8*)ddsData);  |
| 1368 | }  |
| 1369 |   |
| 1370 | tAssert(Layers[layer][image]->GetDataSize() == numBytes);  |
| 1371 | }  |
| 1372 | else  |
| 1373 | {  |
| 1374 | // Unsupported pixel format.  |
| 1375 | Clear();  |
| 1376 | SetStateBit(StateBit::Fatal_PixelFormatNotSupported);  |
| 1377 | return false;  |
| 1378 | }  |
| 1379 |   |
| 1380 | ddsData += numBytes; ddsDataSize -= numBytes;  |
| 1381 | width /= 2; tMath::tiClampMin(val&: width, min: 1);  |
| 1382 | height /= 2; tMath::tiClampMin(val&: height, min: 1);  |
| 1383 | }  |
| 1384 | }  |
| 1385 |   |
| 1386 | if (doRowReversalBeforeDecode)  |
| 1387 | RowReversalOperationPerformed = true;  |
| 1388 |   |
| 1389 | // Not asked to decode. We're basically done.  |
| 1390 | if (!(params.Flags & LoadFlag_Decode))  |
| 1391 | {  |
| 1392 | if (reverseRowOrderRequested && !RowReversalOperationPerformed)  |
| 1393 | SetStateBit(StateBit::Conditional_CouldNotFlipRows);  |
| 1394 |   |
| 1395 | SetStateBit(StateBit::Valid);  |
| 1396 | tAssert(IsValid());  |
| 1397 | return true;  |
| 1398 | }  |
| 1399 |   |
| 1400 | // Spread only applies to single-channel (R-only or L-only) formats.  |
| 1401 | bool spread = params.Flags & LoadFlag_SpreadLuminance;  |
| 1402 |   |
| 1403 | // The gamma-compression load flags only apply when decoding. If the gamma mode is auto, we determine here  |
| 1404 | // whether to apply sRGB compression. If the space is linear and a format that often encodes colours, we apply it.  |
| 1405 | if (params.Flags & LoadFlag_AutoGamma)  |
| 1406 | {  |
| 1407 | // Clear all related flags.  |
| 1408 | params.Flags &= ~(LoadFlag_AutoGamma | LoadFlag_SRGBCompression | LoadFlag_GammaCompression);  |
| 1409 | if (tMath::tIsProfileLinearInRGB(profile: ColourProfileSrc))  |
| 1410 | {  |
| 1411 | // Just cuz it's linear doesn't mean we want to gamma transform. Some formats should be kept linear.  |
| 1412 | if  |
| 1413 | (  |
| 1414 | (PixelFormatSrc != tPixelFormat::A8) && (PixelFormatSrc != tPixelFormat::A8L8) &&  |
| 1415 | (PixelFormatSrc != tPixelFormat::BC4ATI1U) && (PixelFormatSrc != tPixelFormat::BC4ATI1S) &&  |
| 1416 | (PixelFormatSrc != tPixelFormat::BC5ATI2U) && (PixelFormatSrc != tPixelFormat::BC5ATI2S)  |
| 1417 | )  |
| 1418 | {  |
| 1419 | params.Flags |= LoadFlag_SRGBCompression;  |
| 1420 | }  |
| 1421 | }  |
| 1422 | }  |
| 1423 |   |
| 1424 | // Decode to 32-bit RGBA.  |
| 1425 | bool didRowReversalAfterDecode = false;  |
| 1426 | for (int image = 0; image < NumImages; image++)  |
| 1427 | {  |
| 1428 | for (int layerNum = 0; layerNum < NumMipmapLayers; layerNum++)  |
| 1429 | {  |
| 1430 | tLayer* layer = Layers[layerNum][image];  |
| 1431 | int w = layer->Width;  |
| 1432 | int h = layer->Height;  |
| 1433 |   |
| 1434 | // At the end of decoding _either_ decoded4b _or_ decoded4f will be valid, not both.  |
| 1435 | // The decoded4b format used for LDR images.  |
| 1436 | // The decoded4f format used for HDR images.  |
| 1437 | tColour4b* decoded4b = nullptr;  |
| 1438 | tColour4f* decoded4f = nullptr;  |
| 1439 | DecodeResult result = DecodePixelData  |
| 1440 | (  |
| 1441 | layer->PixelFormat, data: layer->Data, dataSize: layer->GetDataSize(),  |
| 1442 | width: w, height: h, dstLDR&: decoded4b, dstHDR&: decoded4f  |
| 1443 | );  |
| 1444 |   |
| 1445 | if (result != DecodeResult::Success)  |
| 1446 | {  |
| 1447 | Clear();  |
| 1448 | switch (result)  |
| 1449 | {  |
| 1450 | case DecodeResult::PackedDecodeError: SetStateBit(StateBit::Fatal_PackedDecodeError); break;  |
| 1451 | case DecodeResult::BlockDecodeError: SetStateBit(StateBit::Fatal_BCDecodeError); break;  |
| 1452 | case DecodeResult::ASTCDecodeError: SetStateBit(StateBit::Fatal_ASTCDecodeError); break;  |
| 1453 | default: SetStateBit(StateBit::Fatal_PixelFormatNotSupported); break;  |
| 1454 | }  |
| 1455 | return false;  |
| 1456 | }  |
| 1457 |   |
| 1458 | // Apply any decode flags.  |
| 1459 | tAssert(decoded4f || decoded4b);  |
| 1460 | bool flagTone = (params.Flags & tImageDDS::LoadFlag_ToneMapExposure) ? true : false;  |
| 1461 | bool flagSRGB = (params.Flags & tImageDDS::LoadFlag_SRGBCompression) ? true : false;  |
| 1462 | bool flagGama = (params.Flags & tImageDDS::LoadFlag_GammaCompression)? true : false;  |
| 1463 | if (decoded4f && (flagTone || flagSRGB || flagGama))  |
| 1464 | {  |
| 1465 | for (int p = 0; p < w*h; p++)  |
| 1466 | {  |
| 1467 | tColour4f& colour = decoded4f[p];  |
| 1468 | if (flagTone)  |
| 1469 | colour.TonemapExposure(exposure: params.Exposure, chans: tCompBit_RGB);  |
| 1470 | if (flagSRGB)  |
| 1471 | colour.LinearToSRGB(chans: tCompBit_RGB);  |
| 1472 | if (flagGama)  |
| 1473 | colour.LinearToGamma(gamma: params.Gamma, chans: tCompBit_RGB);  |
| 1474 | }  |
| 1475 | }  |
| 1476 | if (decoded4b && (flagSRGB || flagGama))  |
| 1477 | {  |
| 1478 | for (int p = 0; p < w*h; p++)  |
| 1479 | {  |
| 1480 | tColour4f colour(decoded4b[p]);  |
| 1481 | if (flagSRGB)  |
| 1482 | colour.LinearToSRGB(chans: tCompBit_RGB);  |
| 1483 | if (flagGama)  |
| 1484 | colour.LinearToGamma(gamma: params.Gamma, chans: tCompBit_RGB);  |
| 1485 | decoded4b[p].SetR(colour.R);  |
| 1486 | decoded4b[p].SetG(colour.G);  |
| 1487 | decoded4b[p].SetB(colour.B);  |
| 1488 | }  |
| 1489 | }  |
| 1490 |   |
| 1491 | // Update the layer with the 32-bit RGBA decoded data. If the data was HDR (float)  |
| 1492 | // convert it to 32 bit. Start by getting rid of the existing layer pixel data.  |
| 1493 | delete[] layer->Data;  |
| 1494 | if (decoded4f)  |
| 1495 | {  |
| 1496 | tAssert(!decoded4b);  |
| 1497 | decoded4b = new tColour4b[w*h];  |
| 1498 | for (int p = 0; p < w*h; p++)  |
| 1499 | decoded4b[p].Set(decoded4f[p]);  |
| 1500 | delete[] decoded4f;  |
| 1501 | }  |
| 1502 |   |
| 1503 | // Possibly spread the L/Red channel.  |
| 1504 | if (spread && tIsLuminanceFormat(format: layer->PixelFormat))  |
| 1505 | {  |
| 1506 | for (int p = 0; p < w*h; p++)  |
| 1507 | {  |
| 1508 | decoded4b[p].G = decoded4b[p].R;  |
| 1509 | decoded4b[p].B = decoded4b[p].R;  |
| 1510 | }  |
| 1511 | }  |
| 1512 |   |
| 1513 | layer->Data = (uint8*)decoded4b;  |
| 1514 | layer->PixelFormat = tPixelFormat::R8G8B8A8;  |
| 1515 |   |
| 1516 | // We've got one more chance to reverse the rows here (if we still need to) because we were asked to decode.  |
| 1517 | if (reverseRowOrderRequested && !RowReversalOperationPerformed && (layer->PixelFormat == tPixelFormat::R8G8B8A8))  |
| 1518 | {  |
| 1519 | // This shouldn't ever fail. Too easy to reverse RGBA 32-bit.  |
| 1520 | uint8* reversedRowData = tImage::CreateReversedRowData(pixelData: layer->Data, pixelDataFormat: layer->PixelFormat, numBlocksW: w, numBlocksH: h);  |
| 1521 | tAssert(reversedRowData);  |
| 1522 | delete[] layer->Data;  |
| 1523 | layer->Data = reversedRowData;  |
| 1524 | didRowReversalAfterDecode = true;  |
| 1525 | }  |
| 1526 |   |
| 1527 | if ((params.Flags & LoadFlag_SwizzleBGR2RGB) && (layer->PixelFormat == tPixelFormat::R8G8B8A8))  |
| 1528 | {  |
| 1529 | for (int xy = 0; xy < w*h; xy++)  |
| 1530 | {  |
| 1531 | tColour4b& col = ((tColour4b*)layer->Data)[xy];  |
| 1532 | tStd::tSwap(a&: col.R, b&: col.B);  |
| 1533 | }  |
| 1534 | }  |
| 1535 | }  |
| 1536 | }  |
| 1537 |   |
| 1538 | if (reverseRowOrderRequested && !RowReversalOperationPerformed && didRowReversalAfterDecode)  |
| 1539 | RowReversalOperationPerformed = true;  |
| 1540 |   |
| 1541 | // Maybe update the current colour profile.  |
| 1542 | if (params.Flags & LoadFlag_SRGBCompression) ColourProfile = tColourProfile::sRGB;  |
| 1543 | if (params.Flags & LoadFlag_GammaCompression) ColourProfile = tColourProfile::gRGB;  |
| 1544 |   |
| 1545 | // All images decoded. Can now set the object's pixel format. We do _not_ set the PixelFormatSrc here!  |
| 1546 | PixelFormat = tPixelFormat::R8G8B8A8;  |
| 1547 |   |
| 1548 | if (reverseRowOrderRequested && !RowReversalOperationPerformed)  |
| 1549 | SetStateBit(StateBit::Conditional_CouldNotFlipRows);  |
| 1550 |   |
| 1551 | SetStateBit(StateBit::Valid);  |
| 1552 | tAssert(IsValid());  |
| 1553 | return true;  |
| 1554 | }  |
| 1555 |   |
| 1556 |   |
| 1557 | const char* tImageDDS::GetStateDesc(StateBit state)  |
| 1558 | {  |
| 1559 | return StateDescriptions[int(state)];  |
| 1560 | }  |
| 1561 |   |
| 1562 |   |
| 1563 | const char* tImageDDS::StateDescriptions[] =  |
| 1564 | {  |
| 1565 | "Valid" ,  |
| 1566 | "Conditional Valid. Image rows could not be flipped." ,  |
| 1567 | "Conditional Valid. One of Pitch or LinearSize should be specified. Using dimensions instead." ,  |
| 1568 | "Conditional Valid. Pixel format specification ill-formed. Assuming FourCC." ,  |
| 1569 | "Conditional Valid. Image has dimension not multiple of four." ,  |
| 1570 | "Conditional Valid. Image has dimension not power of two." ,  |
| 1571 | "Fatal Error. File does not exist." ,  |
| 1572 | "Fatal Error. Incorrect file type. Must be a DDS file." ,  |
| 1573 | "Fatal Error. Filesize incorrect." ,  |
| 1574 | "Fatal Error. Magic FourCC Incorrect." ,  |
| 1575 | "Fatal Error. Incorrect DDS header size." ,  |
| 1576 | "Fatal Error. Incorrect Dimensions." ,  |
| 1577 | "Fatal Error. DDS volume textures not supported." ,  |
| 1578 | "Fatal Error. Pixel format header size incorrect." ,  |
| 1579 | "Fatal Error. One of Pitch or LinearSize must be specified when strict-loading set." ,  |
| 1580 | "Fatal Error. Pixel format specification incorrect." ,  |
| 1581 | "Fatal Error. Unsupported pixel format." ,  |
| 1582 | "Fatal Error. Maximum number of mipmap levels exceeded." ,  |
| 1583 | "Fatal Error. DX10 header size incorrect." ,  |
| 1584 | "Fatal Error. DX10 resource dimension not supported. 2D support only." ,  |
| 1585 | "Fatal Error. Unable to decode packed pixels." ,  |
| 1586 | "Fatal Error. Unable to decode BC pixels." ,  |
| 1587 | "Fatal Error. Unable to decode ASTC pixels."   |
| 1588 | };  |
| 1589 | tStaticAssert(tNumElements(tImageDDS::StateDescriptions) == int(tImageDDS::StateBit::NumStateBits));  |
| 1590 | tStaticAssert(int(tImageDDS::StateBit::NumStateBits) <= int(tImageDDS::StateBit::MaxStateBits));  |
| 1591 |   |
| 1592 |   |
| 1593 | }  |
| 1594 | |