public void Load(System.IO.Stream input) { BinaryReader Utility = new BinaryReader(input); // Read the DDS tag. If it's not right, then bail.. uint ddsTag = Utility.ReadUInt32( ); if (ddsTag != 0x20534444) { throw new FormatException("File does not appear to be a DDS image"); } // Read everything in.. for now assume it worked like a charm.. m_header.Read(input); if ((m_header.m_pixelFormat.m_flags & ( int )DdsPixelFormat.PixelFormatFlags.FourCC) != 0) { int squishFlags = 0; switch (m_header.m_pixelFormat.m_fourCC) { case 0x31545844: squishFlags = ( int )Native.SquishFlags.DXT1; break; case 0x33545844: squishFlags = ( int )Native.SquishFlags.DXT3; break; case 0x35545844: squishFlags = ( int )Native.SquishFlags.DXT5; break; default: throw new FormatException("File is not a supported DDS format"); } // Compute size of compressed block area int blockCount = ((GetWidth() + 3) / 4) * ((GetHeight() + 3) / 4); int blockSize = ((squishFlags & ( int )Native.SquishFlags.DXT1) != 0) ? 8 : 16; // Allocate room for compressed blocks, and read data into it. byte[] compressedBlocks = new byte[blockCount * blockSize]; input.Read(compressedBlocks, 0, compressedBlocks.GetLength(0)); // Now decompress.. m_pixelData = Native.DecompressImage(compressedBlocks, GetWidth(), GetHeight(), squishFlags); } else { // We can only deal with the non-DXT formats we know about.. this is a bit of a mess.. // Sorry.. DdsFileFormat fileFormat = DdsFileFormat.INVALID; if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGBA) && (m_header.m_pixelFormat.m_rgbBitCount == 32) && (m_header.m_pixelFormat.m_rBitMask == 0x00ff0000) && (m_header.m_pixelFormat.m_gBitMask == 0x0000ff00) && (m_header.m_pixelFormat.m_bBitMask == 0x000000ff) && (m_header.m_pixelFormat.m_aBitMask == 0xff000000)) { fileFormat = DdsFileFormat.A8R8G8B8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGB) && (m_header.m_pixelFormat.m_rgbBitCount == 32) && (m_header.m_pixelFormat.m_rBitMask == 0x00ff0000) && (m_header.m_pixelFormat.m_gBitMask == 0x0000ff00) && (m_header.m_pixelFormat.m_bBitMask == 0x000000ff) && (m_header.m_pixelFormat.m_aBitMask == 0x00000000)) { fileFormat = DdsFileFormat.X8R8G8B8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGBA) && (m_header.m_pixelFormat.m_rgbBitCount == 32) && (m_header.m_pixelFormat.m_rBitMask == 0x000000ff) && (m_header.m_pixelFormat.m_gBitMask == 0x0000ff00) && (m_header.m_pixelFormat.m_bBitMask == 0x00ff0000) && (m_header.m_pixelFormat.m_aBitMask == 0xff000000)) { fileFormat = DdsFileFormat.A8B8G8R8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGB) && (m_header.m_pixelFormat.m_rgbBitCount == 32) && (m_header.m_pixelFormat.m_rBitMask == 0x000000ff) && (m_header.m_pixelFormat.m_gBitMask == 0x0000ff00) && (m_header.m_pixelFormat.m_bBitMask == 0x00ff0000) && (m_header.m_pixelFormat.m_aBitMask == 0x00000000)) { fileFormat = DdsFileFormat.X8B8G8R8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGBA) && (m_header.m_pixelFormat.m_rgbBitCount == 16) && (m_header.m_pixelFormat.m_rBitMask == 0x00007c00) && (m_header.m_pixelFormat.m_gBitMask == 0x000003e0) && (m_header.m_pixelFormat.m_bBitMask == 0x0000001f) && (m_header.m_pixelFormat.m_aBitMask == 0x00008000)) { fileFormat = DdsFileFormat.A1R5G5B5; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGBA) && (m_header.m_pixelFormat.m_rgbBitCount == 16) && (m_header.m_pixelFormat.m_rBitMask == 0x00000f00) && (m_header.m_pixelFormat.m_gBitMask == 0x000000f0) && (m_header.m_pixelFormat.m_bBitMask == 0x0000000f) && (m_header.m_pixelFormat.m_aBitMask == 0x0000f000)) { fileFormat = DdsFileFormat.A4R4G4B4; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGB) && (m_header.m_pixelFormat.m_rgbBitCount == 24) && (m_header.m_pixelFormat.m_rBitMask == 0x00ff0000) && (m_header.m_pixelFormat.m_gBitMask == 0x0000ff00) && (m_header.m_pixelFormat.m_bBitMask == 0x000000ff) && (m_header.m_pixelFormat.m_aBitMask == 0x00000000)) { fileFormat = DdsFileFormat.R8G8B8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.RGB) && (m_header.m_pixelFormat.m_rgbBitCount == 16) && (m_header.m_pixelFormat.m_rBitMask == 0x0000f800) && (m_header.m_pixelFormat.m_gBitMask == 0x000007e0) && (m_header.m_pixelFormat.m_bBitMask == 0x0000001f) && (m_header.m_pixelFormat.m_aBitMask == 0x00000000)) { fileFormat = DdsFileFormat.R5G6B5; } // If fileFormat is still invalid, then it's an unsupported format. if (fileFormat == DdsFileFormat.INVALID) { throw new FormatException("File is not a supported DDS format"); } // Size of a source pixel, in bytes int srcPixelSize = (( int )m_header.m_pixelFormat.m_rgbBitCount / 8); // We need the pitch for a row, so we can allocate enough memory for the load. int rowPitch = 0; if ((m_header.m_headerFlags & ( int )DdsHeader.HeaderFlags.Pitch) != 0) { // Pitch specified.. so we can use directly rowPitch = ( int )m_header.m_pitchOrLinearSize; } else if ((m_header.m_headerFlags & ( int )DdsHeader.HeaderFlags.LinerSize) != 0) { // Linear size specified.. compute row pitch. Of course, this should never happen // as linear size is *supposed* to be for compressed textures. But Microsoft don't // always play by the rules when it comes to DDS output. rowPitch = ( int )m_header.m_pitchOrLinearSize / ( int )m_header.m_height; } else { // Another case of Microsoft not obeying their standard is the 'Convert to..' shell extension // that ships in the DirectX SDK. Seems to always leave flags empty..so no indication of pitch // or linear size. And - to cap it all off - they leave pitchOrLinearSize as *zero*. Zero??? If // we get this bizarre set of inputs, we just go 'screw it' and compute row pitch ourselves, // making sure we DWORD align it (if that code path is enabled). rowPitch = (( int )m_header.m_width * srcPixelSize); #if APPLY_PITCH_ALIGNMENT rowPitch = ((( int )rowPitch + 3) & (~3)); #endif // APPLY_PITCH_ALIGNMENT } // System.Diagnostics.Debug.WriteLine( "Image width : " + m_header.m_width + ", rowPitch = " + rowPitch ); // Ok.. now, we need to allocate room for the bytes to read in from.. it's rowPitch bytes * height byte[] readPixelData = new byte[rowPitch * m_header.m_height]; input.Read(readPixelData, 0, readPixelData.GetLength(0)); // We now need space for the real pixel data.. that's width * height * 4.. m_pixelData = new byte[m_header.m_width * m_header.m_height * 4]; // And now we have the arduous task of filling that up with stuff.. for (int destY = 0; destY < ( int )m_header.m_height; destY++) { for (int destX = 0; destX < ( int )m_header.m_width; destX++) { // Compute source pixel offset int srcPixelOffset = (destY * rowPitch) + (destX * srcPixelSize); // Read our pixel uint pixelColour = 0; uint pixelRed = 0; uint pixelGreen = 0; uint pixelBlue = 0; uint pixelAlpha = 0; // Build our pixel colour as a DWORD for (int loop = 0; loop < srcPixelSize; loop++) { pixelColour |= ( uint )(readPixelData[srcPixelOffset + loop] << (8 * loop)); } if (fileFormat == DdsFileFormat.A8R8G8B8) { pixelAlpha = (pixelColour >> 24) & 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.X8R8G8B8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.A8B8G8R8) { pixelAlpha = (pixelColour >> 24) & 0xff; pixelRed = (pixelColour >> 0) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 16) & 0xff; } else if (fileFormat == DdsFileFormat.X8B8G8R8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 0) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 16) & 0xff; } else if (fileFormat == DdsFileFormat.A1R5G5B5) { pixelAlpha = (pixelColour >> 15) * 0xff; pixelRed = (pixelColour >> 10) & 0x1f; pixelGreen = (pixelColour >> 5) & 0x1f; pixelBlue = (pixelColour >> 0) & 0x1f; pixelRed = (pixelRed << 3) | (pixelRed >> 2); pixelGreen = (pixelGreen << 3) | (pixelGreen >> 2); pixelBlue = (pixelBlue << 3) | (pixelBlue >> 2); } else if (fileFormat == DdsFileFormat.A4R4G4B4) { pixelAlpha = (pixelColour >> 12) & 0xff; pixelRed = (pixelColour >> 8) & 0x0f; pixelGreen = (pixelColour >> 4) & 0x0f; pixelBlue = (pixelColour >> 0) & 0x0f; pixelAlpha = (pixelAlpha << 4) | (pixelAlpha >> 0); pixelRed = (pixelRed << 4) | (pixelRed >> 0); pixelGreen = (pixelGreen << 4) | (pixelGreen >> 0); pixelBlue = (pixelBlue << 4) | (pixelBlue >> 0); } else if (fileFormat == DdsFileFormat.R8G8B8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.R5G6B5) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 11) & 0x1f; pixelGreen = (pixelColour >> 5) & 0x3f; pixelBlue = (pixelColour >> 0) & 0x1f; pixelRed = (pixelRed << 3) | (pixelRed >> 2); pixelGreen = (pixelGreen << 2) | (pixelGreen >> 4); pixelBlue = (pixelBlue << 3) | (pixelBlue >> 2); } // Write the colours away.. int destPixelOffset = (destY * ( int )m_header.m_width * 4) + (destX * 4); m_pixelData[destPixelOffset + 0] = ( byte )pixelRed; m_pixelData[destPixelOffset + 1] = ( byte )pixelGreen; m_pixelData[destPixelOffset + 2] = ( byte )pixelBlue; m_pixelData[destPixelOffset + 3] = ( byte )pixelAlpha; } } } }