예제 #1
0
        private static SurfaceInfo GetSurfaceInfo(uint width, uint height, DdsImageFormat format, DdsHeader header)
        {
            uint rowBytes = 0;

            switch (format)
            {
            case DdsImageFormat.Rg8SNorm:
                rowBytes = (width * 16 + 7) / 8;     // round up to nearest byte
                break;

            case DdsImageFormat.Rgba8:
                rowBytes = width * (header.PixelFormat.RgbBitCount / 8);
                break;

            case DdsImageFormat.Rgba16Float:
                rowBytes = width * 4;
                break;
            }

            if (rowBytes > 0)
            {
                return(new SurfaceInfo
                {
                    RowBytes = rowBytes,
                    NumRows = height,
                    NumBytes = rowBytes * height
                });
            }

            uint blockSize;

            switch (format)
            {
            case DdsImageFormat.Bc1:
                blockSize = 8;
                break;

            case DdsImageFormat.Bc2:
            case DdsImageFormat.Bc3:
                blockSize = 16;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            var numBlocksWide = width / 4;
            var numBlocksHigh = height / 4;

            return(new SurfaceInfo
            {
                RowBytes = numBlocksWide * blockSize,
                NumRows = numBlocksHigh,
                NumBytes = numBlocksWide * blockSize * numBlocksHigh
            });
        }
예제 #2
0
        public static DdsFile FromStream(Stream stream)
        {
            using (var reader = new BinaryReader(stream, Encoding.ASCII, true))
            {
                var magic = reader.ReadFourCc();
                if (magic != "DDS ")
                {
                    throw new InvalidDataException();
                }

                var header = DdsHeader.Parse(reader);

                DdsImageFormat imageFormat;
                if (header.PixelFormat.Flags.HasFlag(DdsPixelFormatFlags.FourCc))
                {
                    imageFormat = GetImageFormat(header.PixelFormat.FourCc);
                }
                else if (header.PixelFormat.Flags.HasFlag(DdsPixelFormatFlags.BumpDuDv))
                {
                    imageFormat = DdsImageFormat.Rg8SNorm;
                }
                else if (header.PixelFormat.Flags.HasFlag(DdsPixelFormatFlags.Rgb))
                {
                    imageFormat = DdsImageFormat.Rgba8;
                }
                else
                {
                    throw new InvalidDataException();
                }

                var dimension = DdsTextureDimension.Texture2D;
                var arraySize = 1u;
                if (header.Flags.HasFlag(DdsHeaderFlags.Depth) && header.Caps2.HasFlag(DdsCaps2.Volume))
                {
                    dimension = DdsTextureDimension.Texture3D;
                }
                else if (header.Caps2.HasFlag(DdsCaps2.CubeMap))
                {
                    dimension = DdsTextureDimension.TextureCube;
                    if (!header.Caps2.HasFlag(DdsCaps2.AllCubeMapFaces))
                    {
                        throw new InvalidDataException();
                    }
                    arraySize = 6;
                }

                var isCompressed = imageFormat == DdsImageFormat.Bc1 ||
                                   imageFormat == DdsImageFormat.Bc2 ||
                                   imageFormat == DdsImageFormat.Bc3;

                var mipMapCount = header.MipMapCount;
                if (mipMapCount == 0)
                {
                    mipMapCount = 1;
                }

                var mipMaps = new TextureMipMapData[mipMapCount * arraySize];

                for (var arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
                {
                    var width  = header.Width;
                    var height = header.Height;
                    var depth  = Math.Max(header.Depth, 1);
                    for (var i = 0; i < mipMapCount; i++)
                    {
                        var surfaceInfo = GetSurfaceInfo(width, height, imageFormat, header);

                        var numSurfaceBytes = surfaceInfo.NumBytes * depth;
                        var mipMapData      = reader.ReadBytes((int)numSurfaceBytes);

                        // Set alpha bytes for 32-bit rgb images that don't include alpha data.
                        if (imageFormat == DdsImageFormat.Rgba8 && !header.PixelFormat.Flags.HasFlag(DdsPixelFormatFlags.AlphaPixels))
                        {
                            for (var j = 0; j < mipMapData.Length; j += 4)
                            {
                                mipMapData[j + 3] = 255;
                            }
                        }

                        mipMaps[(arrayIndex * mipMapCount) + i] = new TextureMipMapData(
                            mipMapData,
                            surfaceInfo.RowBytes,
                            surfaceInfo.NumBytes,
                            width,
                            height);

                        width  >>= 1;
                        height >>= 1;
                        depth  >>= 1;

                        if (isCompressed)
                        {
                            // Align width and height to multiple of 4.
                            width  = (width + 3) / 4 * 4;
                            height = (height + 3) / 4 * 4;
                        }
                        else
                        {
                            width  = Math.Max(width, 1);
                            height = Math.Max(height, 1);
                        }

                        depth = Math.Max(depth, 1);
                    }
                }

                return(new DdsFile
                {
                    Header = header,
                    Dimension = dimension,
                    ImageFormat = imageFormat,
                    ArraySize = arraySize,
                    MipMapCount = mipMapCount,
                    MipMaps = mipMaps
                });
            }
        }
예제 #3
0
        public static DdsFile FromFileSystemEntry(FileSystemEntry entry)
        {
            using (var stream = entry.Open())
                using (var reader = new BinaryReader(stream, Encoding.ASCII, true))
                {
                    var magic = reader.ReadFourCc();
                    if (magic != "DDS ")
                    {
                        throw new InvalidDataException();
                    }

                    var header = DdsHeader.Parse(reader);

                    DdsImageFormat imageFormat;
                    if (header.PixelFormat.Flags.HasFlag(DdsPixelFormatFlags.FourCc))
                    {
                        imageFormat = GetImageFormat(header.PixelFormat.FourCc);
                    }
                    else if (header.PixelFormat.Flags.HasFlag(DdsPixelFormatFlags.BumpDuDv))
                    {
                        imageFormat = DdsImageFormat.Rg8SNorm;
                    }
                    else
                    {
                        throw new InvalidDataException();
                    }

                    if (header.Flags.HasFlag(DdsHeaderFlags.Depth) ||
                        header.Caps2.HasFlag(DdsCaps2.CubeMap) ||
                        header.Caps2.HasFlag(DdsCaps2.Volume))
                    {
                        throw new NotSupportedException();
                    }

                    var mipMapCount = header.MipMapCount;
                    if (mipMapCount == 0)
                    {
                        mipMapCount = 1;
                    }

                    var mipMaps = new DdsMipMap[mipMapCount];

                    var width  = header.Width;
                    var height = header.Height;
                    for (var i = 0; i < mipMapCount; i++)
                    {
                        var surfaceInfo = GetSurfaceInfo(width, height, imageFormat);

                        var mipMapData = reader.ReadBytes((int)surfaceInfo.NumBytes);

                        mipMaps[i] = new DdsMipMap(mipMapData, surfaceInfo.RowBytes);

                        width  >>= 1;
                        height >>= 1;

                        width  = Math.Max(width, 1);
                        height = Math.Max(height, 1);
                    }

                    return(new DdsFile
                    {
                        Header = header,
                        ImageFormat = imageFormat,
                        MipMaps = mipMaps
                    });
                }
        }