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 }); }
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 }); } }
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 }); } }