Example #1
0
        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;
                    }
                }
            }
        }