예제 #1
0
        // Simple DDS loader ported from http://msdn.microsoft.com/en-us/library/windows/apps/jj651550.aspx
        static void FillInitData(
            int width,
            int height,
            int depth,
            int mipCount,
            int arraySize,
            Format format,
            int maxsize,
            int bitSize,
            IntPtr bitData,
            out int twidth,
            out int theight,
            out int tdepth,
            out int skipMip,
            DataBox[] initData
            )
        {
            if (bitData == IntPtr.Zero)
            {
                throw new ArgumentNullException("bitData");
            }

            skipMip = 0;
            twidth  = 0;
            theight = 0;
            tdepth  = 0;

            int    numBytes = 0;
            int    rowBytes = 0;
            int    numRows  = 0;
            IntPtr pSrcBits = bitData;
            IntPtr pEndBits = IntPtr.Add(bitData, bitSize);

            int index = 0;

            for (int j = 0; j < arraySize; j++)
            {
                int w = width;
                int h = height;
                int d = depth;
                for (int i = 0; i < mipCount; i++)
                {
                    //FormatHelper.
                    if (FormatHelper.IsCompressed(format))
                    {
                        int numBlocksWide = 0;
                        if (width > 0)
                        {
                            numBlocksWide = Math.Max(1, (width + 3) / 4);
                        }
                        int numBlocksHigh = 0;
                        if (height > 0)
                        {
                            numBlocksHigh = Math.Max(1, (height + 3) / 4);
                        }
                        int bytesPerBlock = 0;

                        switch (format)
                        {
                        case Format.BC1_Typeless:
                        case Format.BC1_UNorm:
                        case Format.BC1_UNorm_SRgb:
                        case Format.BC4_Typeless:
                        case Format.BC4_UNorm:
                        case Format.BC4_SNorm:
                            bytesPerBlock = 8;
                            break;

                        case Format.BC2_Typeless:
                        case Format.BC2_UNorm:
                        case Format.BC2_UNorm_SRgb:
                        case Format.BC3_Typeless:
                        case Format.BC3_UNorm:
                        case Format.BC3_UNorm_SRgb:
                        case Format.BC5_Typeless:
                        case Format.BC5_UNorm:
                        case Format.BC5_SNorm:
                        case Format.BC6H_Typeless:
                        case Format.BC6H_Uf16:
                        case Format.BC6H_Sf16:
                        case Format.BC7_Typeless:
                        case Format.BC7_UNorm:
                        case Format.BC7_UNorm_SRgb:
                            bytesPerBlock = 16;
                            break;

                        default:
                            break;
                        }
                        rowBytes = numBlocksWide * bytesPerBlock;
                        numRows  = numBlocksHigh;
                    }
                    else if (FormatHelper.IsPacked(format))
                    {
                        rowBytes = ((width + 1) >> 1) * 4;
                        numRows  = height;
                    }
                    else
                    {
                        int bpp = FormatHelper.SizeOfInBits(format); // BitsPerPixel(fmt);
                        rowBytes = (width * bpp + 7) / 8;            // round up to nearest byte
                        numRows  = height;
                    }

                    numBytes = rowBytes * numRows;
                    //GetSurfaceInfo(w, h, format, NumBytes, RowBytes, NumRows);

                    if ((mipCount <= 1) || maxsize <= 0 || (w <= maxsize && h <= maxsize && d <= maxsize))
                    {
                        if (twidth <= 0)
                        {
                            twidth  = w;
                            theight = h;
                            tdepth  = d;
                        }

                        initData[index].DataPointer = pSrcBits;
                        initData[index].RowPitch    = rowBytes;
                        initData[index].SlicePitch  = numBytes;
                        ++index;
                    }
                    else
                    {
                        ++skipMip;
                    }

                    if (pSrcBits.ToInt64() + (numBytes * d) > pEndBits.ToInt64())
                    {
                        throw new IndexOutOfRangeException("Gone past end of DDS");
                    }

                    IntPtr.Add(pSrcBits, numBytes * d);

                    w = w >> 1;
                    h = h >> 1;
                    d = d >> 1;
                    if (w == 0)
                    {
                        w = 1;
                    }
                    if (h == 0)
                    {
                        h = 1;
                    }
                    if (d == 0)
                    {
                        d = 1;
                    }
                }
            }

            if (index == 0)
            {
                throw new Exception("Failed to create DataBoxes");
            }
        }
예제 #2
0
        /// <summary>
        /// Decodes DDS header including optional DX10 extended header
        /// </summary>
        /// <param name="headerPtr">Pointer to the DDS header.</param>
        /// <param name="size">Size of the DDS content.</param>
        /// <param name="flags">Flags used for decoding the DDS header.</param>
        /// <param name="description">Output texture description.</param>
        /// <param name="convFlags">Output conversion flags.</param>
        /// <exception cref="ArgumentException">If the argument headerPtr is null</exception>
        /// <exception cref="InvalidOperationException">If the DDS header contains invalid datas.</exception>
        /// <returns>True if the decoding is successfull, false if this is not a DDS header.</returns>
        private static unsafe bool DecodeDDSHeader(IntPtr headerPtr, int size, DDSFlags flags, out ImageDescription description, out ConversionFlags convFlags)
        {
            description = new ImageDescription();
            convFlags   = ConversionFlags.None;

            if (headerPtr == IntPtr.Zero)
            {
                throw new ArgumentException("Pointer to DDS header cannot be null", "headerPtr");
            }

            if (size < (Utilities.SizeOf <DDS.Header>() + sizeof(uint)))
            {
                return(false);
            }

            // DDS files always start with the same magic number ("DDS ")
            if (*(uint *)(headerPtr) != DDS.MagicHeader)
            {
                return(false);
            }

            var header = *(DDS.Header *)((byte *)headerPtr + sizeof(int));

            // Verify header to validate DDS file
            if (header.Size != Utilities.SizeOf <DDS.Header>() || header.PixelFormat.Size != Utilities.SizeOf <DDS.PixelFormat>())
            {
                return(false);
            }

            // Setup MipLevels
            description.MipLevels = header.MipMapCount;
            if (description.MipLevels == 0)
            {
                description.MipLevels = 1;
            }

            // Check for DX10 extension
            if ((header.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0 && (new FourCC('D', 'X', '1', '0') == header.PixelFormat.FourCC))
            {
                // Buffer must be big enough for both headers and magic value
                if (size < (Utilities.SizeOf <DDS.Header>() + sizeof(uint) + Utilities.SizeOf <DDS.HeaderDXT10>()))
                {
                    return(false);
                }

                var headerDX10 = *(DDS.HeaderDXT10 *)((byte *)headerPtr + sizeof(int) + Utilities.SizeOf <DDS.Header>());
                convFlags |= ConversionFlags.DX10;

                description.ArraySize = headerDX10.ArraySize;
                if (description.ArraySize == 0)
                {
                    throw new InvalidOperationException("Unexpected ArraySize == 0 from DDS HeaderDX10 ");
                }

                description.Format = headerDX10.DXGIFormat;
                if (!FormatHelper.IsValid(description.Format))
                {
                    throw new InvalidOperationException("Invalid Format from DDS HeaderDX10 ");
                }

                switch (headerDX10.ResourceDimension)
                {
                case ResourceDimension.Texture1D:

                    // D3DX writes 1D textures with a fixed Height of 1
                    if ((header.Flags & DDS.HeaderFlags.Height) != 0 && header.Height != 1)
                    {
                        throw new InvalidOperationException("Unexpected Height != 1 from DDS HeaderDX10 ");
                    }

                    description.Width     = header.Width;
                    description.Height    = 1;
                    description.Depth     = 1;
                    description.Dimension = TextureDimension.Texture1D;
                    break;

                case ResourceDimension.Texture2D:
                    if ((headerDX10.MiscFlags & ResourceOptionFlags.TextureCube) != 0)
                    {
                        description.ArraySize *= 6;
                        description.Dimension  = TextureDimension.TextureCube;
                    }
                    else
                    {
                        description.Dimension = TextureDimension.Texture2D;
                    }

                    description.Width  = header.Width;
                    description.Height = header.Height;
                    description.Depth  = 1;
                    break;

                case ResourceDimension.Texture3D:
                    if ((header.Flags & DDS.HeaderFlags.Volume) == 0)
                    {
                        throw new InvalidOperationException("Texture3D missing HeaderFlags.Volume from DDS HeaderDX10");
                    }

                    if (description.ArraySize > 1)
                    {
                        throw new InvalidOperationException("Unexpected ArraySize > 1 for Texture3D from DDS HeaderDX10");
                    }

                    description.Width     = header.Width;
                    description.Height    = header.Height;
                    description.Depth     = header.Depth;
                    description.Dimension = TextureDimension.Texture3D;
                    break;

                default:
                    throw new InvalidOperationException(string.Format("Unexpected dimension [{0}] from DDS HeaderDX10", headerDX10.ResourceDimension));
                }
            }
            else
            {
                description.ArraySize = 1;

                if ((header.Flags & DDS.HeaderFlags.Volume) != 0)
                {
                    description.Width     = header.Width;
                    description.Height    = header.Height;
                    description.Depth     = header.Depth;
                    description.Dimension = TextureDimension.Texture3D;
                }
                else
                {
                    if ((header.CubemapFlags & DDS.CubemapFlags.CubeMap) != 0)
                    {
                        // We require all six faces to be defined
                        if ((header.CubemapFlags & DDS.CubemapFlags.AllFaces) != DDS.CubemapFlags.AllFaces)
                        {
                            throw new InvalidOperationException("Unexpected CubeMap, expecting all faces from DDS Header");
                        }

                        description.ArraySize = 6;
                        description.Dimension = TextureDimension.TextureCube;
                    }
                    else
                    {
                        description.Dimension = TextureDimension.Texture2D;
                    }

                    description.Width  = header.Width;
                    description.Height = header.Height;
                    description.Depth  = 1;
                    // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
                }

                description.Format = GetDXGIFormat(ref header.PixelFormat, flags, out convFlags);

                if (description.Format == Format.Unknown)
                {
                    throw new InvalidOperationException("Unsupported PixelFormat from DDS Header");
                }
            }

            // Special flag for handling BGR DXGI 1.1 formats
            if ((flags & DDSFlags.ForceRgb) != 0)
            {
                switch ((Format)description.Format)
                {
                case Format.B8G8R8A8_UNorm:
                    description.Format = Format.R8G8B8A8_UNorm;
                    convFlags         |= ConversionFlags.Swizzle;
                    break;

                case Format.B8G8R8X8_UNorm:
                    description.Format = Format.R8G8B8A8_UNorm;
                    convFlags         |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
                    break;

                case Format.B8G8R8A8_Typeless:
                    description.Format = Format.R8G8B8A8_Typeless;
                    convFlags         |= ConversionFlags.Swizzle;
                    break;

                case Format.B8G8R8A8_UNorm_SRgb:
                    description.Format = Format.R8G8B8A8_UNorm_SRgb;
                    convFlags         |= ConversionFlags.Swizzle;
                    break;

                case Format.B8G8R8X8_Typeless:
                    description.Format = Format.R8G8B8A8_Typeless;
                    convFlags         |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
                    break;

                case Format.B8G8R8X8_UNorm_SRgb:
                    description.Format = Format.R8G8B8A8_UNorm_SRgb;
                    convFlags         |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
                    break;
                }
            }

            // Pass DDSFlags copy memory to the conversion flags
            if ((flags & DDSFlags.CopyMemory) != 0)
            {
                convFlags |= ConversionFlags.CopyMemory;
            }

            // Special flag for handling 16bpp formats
            if ((flags & DDSFlags.No16Bpp) != 0)
            {
                switch ((Format)description.Format)
                {
                case Format.B5G6R5_UNorm:
                case Format.B5G5R5A1_UNorm:
                case Format.B4G4R4A4_UNorm:
                    description.Format = Format.R8G8B8A8_UNorm;
                    convFlags         |= ConversionFlags.Expand;
                    if (description.Format == Format.B5G6R5_UNorm)
                    {
                        convFlags |= ConversionFlags.NoAlpha;
                    }
                    break;
                }
            }
            return(true);
        }