public static void Save( Document input, Stream output, DdsFileFormat format, DdsErrorMetric errorMetric, BC7CompressionMode compressionMode, bool cubeMap, bool generateMipmaps, MipMapSampling sampling, Surface scratchSurface, ProgressEventHandler progressCallback) { using (RenderArgs args = new RenderArgs(scratchSurface)) { input.Render(args, true); } DdsProgressCallback ddsProgress = null; if (progressCallback != null) { ddsProgress = (UIntPtr done, UIntPtr total) => { double progress = (double)done.ToUInt64() / (double)total.ToUInt64(); progressCallback(null, new ProgressEventArgs(progress * 100.0, true)); }; } SaveDdsFile(scratchSurface, format, errorMetric, compressionMode, cubeMap, generateMipmaps, sampling, output, ddsProgress); }
public static void PNG_To_DDS(string From_PNG_File, string To_DDS_File, DdsFileFormat Format) { //こっちのコードもメモリリークしていますが、GCで解放されるため放置 System.IO.FileStream fileStream = new System.IO.FileStream(To_DDS_File, System.IO.FileMode.Create); DdsFile.Save(fileStream, Format, DdsErrorMetric.Perceptual, BC7CompressionMode.Slow, false, false, ResamplingAlgorithm.Bilinear, Surface.CopyFromBitmap(new Bitmap(From_PNG_File)), null); fileStream.Close(); }
internal DdsPixelFormat(DdsFileFormat format) { this.size = SizeOf; switch (format) { case DdsFileFormat.R8G8B8X8: this.flags = PixelFormatFlags.Rgb; this.fourCC = 0; this.RGBBitCount = 32; this.RBitMask = 0x000000ff; this.GBitMask = 0x0000ff00; this.BBitMask = 0x00ff0000; this.ABitMask = 0x00000000; break; case DdsFileFormat.B8G8R8: this.flags = PixelFormatFlags.Rgb; this.fourCC = 0; this.RGBBitCount = 24; this.RBitMask = 0x00ff0000; this.GBitMask = 0x0000ff00; this.BBitMask = 0x000000ff; this.ABitMask = 0x00000000; break; default: throw new InvalidOperationException(GetUnsupportedFormatMessage(format)); } }
public DdsSaveConfigToken( DdsFileFormat fileFormat, int compressorType, int errorMetric, bool weightColourByAlpha, bool generateMipMaps ) { m_fileFormat = fileFormat; m_compressorType = compressorType; m_errorMetric = errorMetric; m_weightColourByAlpha = weightColourByAlpha; m_generateMipMaps = generateMipMaps; }
public DdsSaveConfigToken(DdsFileFormat fileFormat, int compressorType, int errorMetric, bool weightColourByAlpha, bool generateMipMaps) { m_fileFormat = fileFormat; m_compressorType = compressorType; m_errorMetric = errorMetric; m_weightColourByAlpha = weightColourByAlpha; m_generateMipMaps = generateMipMaps; }
protected override void OnSaveT(Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler progressCallback) { DdsFileFormat fileFormat = (DdsFileFormat)token.GetProperty(PropertyNames.FileFormat).Value; BC7CompressionMode compressionMode = (BC7CompressionMode)token.GetProperty(PropertyNames.BC7CompressionMode).Value; DdsErrorMetric errorMetric = (DdsErrorMetric)token.GetProperty(PropertyNames.ErrorMetric).Value; bool generateMipmaps = token.GetProperty <BooleanProperty>(PropertyNames.GenerateMipMaps).Value; MipMapSampling mipSampling = (MipMapSampling)token.GetProperty(PropertyNames.MipMapResamplingAlgorithm).Value; DdsFile.Save(input, output, fileFormat, errorMetric, compressionMode, generateMipmaps, mipSampling, scratchSurface, progressCallback); }
protected override bool IsReflexive(PropertyBasedSaveConfigToken token) { if (token.GetProperty <BooleanProperty>(PropertyNames.CubeMap).Value) { return(false); } DdsFileFormat format = (DdsFileFormat)token.GetProperty(PropertyNames.FileFormat).Value; return(format == DdsFileFormat.B8G8R8A8 || format == DdsFileFormat.R8G8B8A8); }
private static void SaveDdsFile( Surface surface, DdsFileFormat format, DdsErrorMetric errorMetric, BC7CompressionMode compressionMode, bool cubeMap, bool generateMipmaps, MipMapSampling mipMapSampling, Stream output, DdsProgressCallback progressCallback) { DDSSaveInfo info = new DDSSaveInfo { scan0 = surface.Scan0.Pointer, width = surface.Width, height = surface.Height, stride = surface.Stride, format = format, errorMetric = errorMetric, compressionMode = compressionMode, cubeMap = cubeMap && IsCrossedCubeMapSize(surface), generateMipmaps = generateMipmaps, mipmapSampling = mipMapSampling }; StreamIOCallbacks streamIO = new StreamIOCallbacks(output); IOCallbacks callbacks = new IOCallbacks { Read = streamIO.Read, Write = streamIO.Write, Seek = streamIO.Seek, GetSize = streamIO.GetSize }; int hr; if (IntPtr.Size == 8) { hr = DdsIO_x64.Save(ref info, callbacks, progressCallback); } else { hr = DdsIO_x86.Save(ref info, callbacks, progressCallback); } GC.KeepAlive(streamIO); GC.KeepAlive(callbacks); GC.KeepAlive(progressCallback); if (FAILED(hr)) { Marshal.ThrowExceptionForHR(hr); } }
protected override void OnSaveT(Document input, Stream output, PropertyBasedSaveConfigToken token, Surface scratchSurface, ProgressEventHandler callback) { scratchSurface.Clear(ColorBgra.Zero); using (RenderArgs args = new RenderArgs(scratchSurface)) { input.Render(args, true); } DdsFileFormat fileFormat = (DdsFileFormat)token.GetProperty <StaticListChoiceProperty>(PropertyNames.FileFormat).Value; DdsCompressorType compressorType = (DdsCompressorType)token.GetProperty <StaticListChoiceProperty>(PropertyNames.CompressorType).Value; DdsErrorMetric errorMetric = (DdsErrorMetric)token.GetProperty <StaticListChoiceProperty>(PropertyNames.ErrorMetric).Value; bool weightColorByAlpha = token.GetProperty <BooleanProperty>(PropertyNames.WeightColorByAlpha).Value; bool generateMipMaps = token.GetProperty <BooleanProperty>(PropertyNames.GenerateMipMaps).Value; ResamplingAlgorithm mipMapResamplingAlgorithm = (ResamplingAlgorithm)token.GetProperty <StaticListChoiceProperty>(PropertyNames.MipMapResamplingAlgorithm).Value; new DdsFile().Save(output, scratchSurface, fileFormat, compressorType, errorMetric, generateMipMaps, mipMapResamplingAlgorithm, weightColorByAlpha, callback); }
private int GetSquishFlags(DdsFileFormat fileFormat, DdsCompressorType compressorType, DdsErrorMetric errorMetric, bool weightColorByAlpha) { int num = 0; if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) { num |= 1; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT3) { num |= 2; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT5) { num |= 4; } if (num != 0) { if (compressorType == DdsCompressorType.ClusterFit) { num |= 8; } else if (compressorType == DdsCompressorType.RangeFit) { num |= 0x10; } else { num |= 0x100; } if (errorMetric == DdsErrorMetric.Perceptual) { num |= 0x20; } else { num |= 0x40; } if ((compressorType == DdsCompressorType.ClusterFit) & weightColorByAlpha) { num |= 0x80; } } return(num); }
internal DdsHeader(int width, int height, int arraySize, int mipCount, DdsFileFormat format) { this.size = SizeOf; this.flags = HeaderFlags.Texture; this.height = (uint)height; this.width = (uint)width; switch (format) { case DdsFileFormat.R8G8B8X8: this.flags |= HeaderFlags.Pitch; this.pitchOrLinearSize = (((uint)width * 32) + 7) / 8; break; case DdsFileFormat.B8G8R8: this.flags |= HeaderFlags.Pitch; this.pitchOrLinearSize = (((uint)width * 24) + 7) / 8; break; default: throw new InvalidOperationException(GetUnsupportedFormatMessage(format)); } this.depth = 1; if (mipCount > 1) { this.flags |= HeaderFlags.Mipmap; this.mipMapCount = (uint)mipCount; this.caps |= SurfaceFlags.Mipmap; } else { this.mipMapCount = 1; } this.reserved1 = new uint[11]; this.ddspf = new DdsPixelFormat(format); this.caps |= SurfaceFlags.Texture; if (arraySize == 6) { this.caps |= SurfaceFlags.Cubemap; this.caps2 |= CubemapFaces.All; } this.caps3 = 0; this.caps4 = 0; this.reserved2 = 0; }
private const uint DdsMagic = 0x20534444; // "DDS " internal DX9DdsWriter(int width, int height, int arraySize, int mipLevels, DdsFileFormat format) { this.width = width; this.height = height; this.arraySize = arraySize; this.mipLevels = mipLevels; this.format = format; switch (format) { case DdsFileFormat.R8G8B8X8: this.pixelBuffer = new byte[4]; break; case DdsFileFormat.B8G8R8: this.pixelBuffer = new byte[3]; break; default: throw new InvalidOperationException(GetUnsupportedFormatMessage(format)); } }
private static unsafe void SaveDdsFile( Surface surface, DdsFileFormat format, DdsErrorMetric errorMetric, BC7CompressionMode compressionMode, bool generateMipmaps, MipMapSampling mipMapSampling, DdsWriteImageCallback writeImageCallback, DdsProgressCallback progressCallback) { DDSSaveInfo info = new DDSSaveInfo { width = surface.Width, height = surface.Height, stride = surface.Stride, format = format, errorMetric = errorMetric, compressionMode = compressionMode, generateMipmaps = generateMipmaps, mipmapSampling = mipMapSampling, scan0 = surface.Scan0.Pointer }; int hr; if (IntPtr.Size == 8) { hr = DdsIO_x64.Save(ref info, writeImageCallback, progressCallback); } else { hr = DdsIO_x86.Save(ref info, writeImageCallback, progressCallback); } if (FAILED(hr)) { Marshal.ThrowExceptionForHR(hr); } }
public void Initialize(DdsFileFormat fileFormat) { switch (fileFormat) { case DdsFileFormat.DDS_FORMAT_DXT1: case DdsFileFormat.DDS_FORMAT_DXT3: case DdsFileFormat.DDS_FORMAT_DXT5: this.Flags = (UInt32)PixelFormatFlags.DDS_FOURCC; this.RgbBitCount = 0x00000000; this.BitMaskA = 0x00000000; this.BitMaskR = 0x00000000; this.BitMaskG = 0x00000000; this.BitMaskB = 0x00000000; if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) { this.FourCC = 0x31545844; //"DXT1" } if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT3) { this.FourCC = 0x33545844; //"DXT3" } if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT5) { this.FourCC = 0x35545844; //"DXT5" } break; case DdsFileFormat.DDS_FORMAT_A8R8G8B8: this.Flags = (UInt32)PixelFormatFlags.DDS_RGBA; this.RgbBitCount = 0x000000020; this.FourCC = 0; this.BitMaskA = 0xff000000; this.BitMaskR = 0x00ff0000; this.BitMaskG = 0x0000ff00; this.BitMaskB = 0x000000ff; break; case DdsFileFormat.DDS_FORMAT_X8R8G8B8: this.Flags = (UInt32)PixelFormatFlags.DDS_RGB; this.RgbBitCount = 0x00000020; this.FourCC = 0x00000000; this.BitMaskA = 0x00000000; this.BitMaskR = 0x00ff0000; this.BitMaskG = 0x0000ff00; this.BitMaskB = 0x000000ff; break; case DdsFileFormat.DDS_FORMAT_A8B8G8R8: this.Flags = (UInt32)PixelFormatFlags.DDS_RGBA; this.RgbBitCount = 0x00000020; this.FourCC = 0x00000000; this.BitMaskA = 0xff000000; this.BitMaskR = 0x000000ff; this.BitMaskG = 0x0000ff00; this.BitMaskB = 0x00ff0000; break; case DdsFileFormat.DDS_FORMAT_X8B8G8R8: this.Flags = (UInt32)PixelFormatFlags.DDS_RGB; this.RgbBitCount = 0x00000020; this.FourCC = 0x00000000; this.BitMaskA = 0x00000000; this.BitMaskR = 0x000000ff; this.BitMaskG = 0x0000ff00; this.BitMaskB = 0x00ff0000; break; case DdsFileFormat.DDS_FORMAT_A1R5G5B5: this.Flags = (UInt32)PixelFormatFlags.DDS_RGBA; this.RgbBitCount = 0x00000010; this.FourCC = 0x00000000; this.BitMaskA = 0x00008000; this.BitMaskR = 0x00007c00; this.BitMaskG = 0x000003e0; this.BitMaskB = 0x0000001f; break; case DdsFileFormat.DDS_FORMAT_A4R4G4B4: this.Flags = (UInt32)PixelFormatFlags.DDS_RGBA; this.RgbBitCount = 16; this.FourCC = 0; this.BitMaskA = 0x0000f000; this.BitMaskR = 0x00000f00; this.BitMaskG = 0x000000f0; this.BitMaskB = 0x0000000f; break; case DdsFileFormat.DDS_FORMAT_R8G8B8: this.Flags = (UInt32)PixelFormatFlags.DDS_RGB; this.RgbBitCount = 0x00000018; this.FourCC = 0x00000000; this.BitMaskA = 0x00000000; this.BitMaskR = 0x00ff0000; this.BitMaskG = 0x0000ff00; this.BitMaskB = 0x000000ff; break; case DdsFileFormat.DDS_FORMAT_R5G6B5: this.Flags = (UInt32)PixelFormatFlags.DDS_RGB; this.RgbBitCount = 0x00000010; this.FourCC = 0x00000000; this.BitMaskA = 0x00000000; this.BitMaskR = 0x0000f800; this.BitMaskG = 0x000007e0; this.BitMaskB = 0x0000001f; break; default: break; } }
public void Initialise( DdsFileFormat fileFormat ) { m_size = Size(); switch( fileFormat ) { case DdsFileFormat.DXT1: case DdsFileFormat.DXT3: case DdsFileFormat.DXT5: { // DXT1/DXT3/DXT5 m_flags = ( int )PixelFormatFlags.FourCC; m_rgbBitCount = 0; m_rBitMask = 0; m_gBitMask = 0; m_bBitMask = 0; m_aBitMask = 0; if ( fileFormat == DdsFileFormat.DXT1 ) m_fourCC = 0x31545844; //"DXT1" if ( fileFormat == DdsFileFormat.DXT3 ) m_fourCC = 0x33545844; //"DXT1" if ( fileFormat == DdsFileFormat.DXT5 ) m_fourCC = 0x35545844; //"DXT1" break; } case DdsFileFormat.A8R8G8B8: { m_flags = ( int )PixelFormatFlags.RGBA; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0xff000000; break; } case DdsFileFormat.X8R8G8B8: { m_flags = ( int )PixelFormatFlags.RGB; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0x00000000; break; } case DdsFileFormat.A8B8G8R8: { m_flags = ( int )PixelFormatFlags.RGBA; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x000000ff; m_gBitMask = 0x0000ff00; m_bBitMask = 0x00ff0000; m_aBitMask = 0xff000000; break; } case DdsFileFormat.X8B8G8R8: { m_flags = ( int )PixelFormatFlags.RGB; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x000000ff; m_gBitMask = 0x0000ff00; m_bBitMask = 0x00ff0000; m_aBitMask = 0x00000000; break; } case DdsFileFormat.A1R5G5B5: { m_flags = ( int )PixelFormatFlags.RGBA; m_rgbBitCount = 16; m_fourCC = 0; m_rBitMask = 0x00007c00; m_gBitMask = 0x000003e0; m_bBitMask = 0x0000001f; m_aBitMask = 0x00008000; break; } case DdsFileFormat.A4R4G4B4: { m_flags = ( int )PixelFormatFlags.RGBA; m_rgbBitCount = 16; m_fourCC = 0; m_rBitMask = 0x00000f00; m_gBitMask = 0x000000f0; m_bBitMask = 0x0000000f; m_aBitMask = 0x0000f000; break; } case DdsFileFormat.R8G8B8: { m_flags = ( int )PixelFormatFlags.RGB; m_fourCC = 0; m_rgbBitCount = 24; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0x00000000; break; } case DdsFileFormat.R5G6B5: { m_flags = ( int )PixelFormatFlags.RGB; m_fourCC = 0; m_rgbBitCount = 16; m_rBitMask = 0x0000f800; m_gBitMask = 0x000007e0; m_bBitMask = 0x0000001f; m_aBitMask = 0x00000000; break; } default: break; } }
protected override bool IsReflexive(PropertyBasedSaveConfigToken token) { DdsFileFormat format = (DdsFileFormat)token.GetProperty(PropertyNames.FileFormat).Value; return(format == DdsFileFormat.B8G8R8A8 || format == DdsFileFormat.R8G8B8A8); }
public void Initialise(DdsFileFormat fileFormat) { m_size = Size(); switch (fileFormat) { case DdsFileFormat.DDS_FORMAT_DXT1: case DdsFileFormat.DDS_FORMAT_DXT3: case DdsFileFormat.DDS_FORMAT_DXT5: { // DXT1/DXT3/DXT5 m_flags = ( int )PixelFormatFlags.DDS_FOURCC; m_rgbBitCount = 0; m_rBitMask = 0; m_gBitMask = 0; m_bBitMask = 0; m_aBitMask = 0; if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) { m_fourCC = 0x31545844; //"DXT1" } if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT3) { m_fourCC = 0x33545844; //"DXT1" } if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT5) { m_fourCC = 0x35545844; //"DXT1" } break; } case DdsFileFormat.DDS_FORMAT_A8R8G8B8: { m_flags = ( int )PixelFormatFlags.DDS_RGBA; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0xff000000; break; } case DdsFileFormat.DDS_FORMAT_X8R8G8B8: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_A8B8G8R8: { m_flags = ( int )PixelFormatFlags.DDS_RGBA; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x000000ff; m_gBitMask = 0x0000ff00; m_bBitMask = 0x00ff0000; m_aBitMask = 0xff000000; break; } case DdsFileFormat.DDS_FORMAT_X8B8G8R8: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x000000ff; m_gBitMask = 0x0000ff00; m_bBitMask = 0x00ff0000; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_A1R5G5B5: { m_flags = ( int )PixelFormatFlags.DDS_RGBA; m_rgbBitCount = 16; m_fourCC = 0; m_rBitMask = 0x00007c00; m_gBitMask = 0x000003e0; m_bBitMask = 0x0000001f; m_aBitMask = 0x00008000; break; } case DdsFileFormat.DDS_FORMAT_A4R4G4B4: { m_flags = ( int )PixelFormatFlags.DDS_RGBA; m_rgbBitCount = 16; m_fourCC = 0; m_rBitMask = 0x00000f00; m_gBitMask = 0x000000f0; m_bBitMask = 0x0000000f; m_aBitMask = 0x0000f000; break; } case DdsFileFormat.DDS_FORMAT_R8G8B8: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_fourCC = 0; m_rgbBitCount = 24; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_R5G6B5: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_fourCC = 0; m_rgbBitCount = 16; m_rBitMask = 0x0000f800; m_gBitMask = 0x000007e0; m_bBitMask = 0x0000001f; m_aBitMask = 0x00000000; break; } default: break; } }
public void Load(System.IO.Stream input) { // Read the DDS tag. If it's not right, then bail.. uint ddsTag = ( uint )Utility.ReadUInt32(input); 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.DDS_FOURCC) != 0) { int squishFlags = 0; switch (m_header.m_pixelFormat.m_fourCC) { case 0x31545844: squishFlags = ( int )DdsSquish.SquishFlags.kDxt1; break; case 0x33545844: squishFlags = ( int )DdsSquish.SquishFlags.kDxt3; break; case 0x35545844: squishFlags = ( int )DdsSquish.SquishFlags.kDxt5; 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 )DdsSquish.SquishFlags.kDxt1) != 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 = DdsSquish.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.DDS_FORMAT_INVALID; if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_A8R8G8B8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_X8R8G8B8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_A8B8G8R8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_X8B8G8R8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_A1R5G5B5; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_A4R4G4B4; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_R8G8B8; } else if ((m_header.m_pixelFormat.m_flags == ( int )DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_R5G6B5; } // If fileFormat is still invalid, then it's an unsupported format. if (fileFormat == DdsFileFormat.DDS_FORMAT_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.DDS_HEADER_FLAGS_PITCH) != 0) { // Pitch specified.. so we can use directly rowPitch = ( int )m_header.m_pitchOrLinearSize; } else if ((m_header.m_headerFlags & ( int )DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_LINEARSIZE) != 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.DDS_FORMAT_A8R8G8B8) { pixelAlpha = (pixelColour >> 24) & 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_X8R8G8B8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_A8B8G8R8) { pixelAlpha = (pixelColour >> 24) & 0xff; pixelRed = (pixelColour >> 0) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 16) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_X8B8G8R8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 0) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 16) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_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.DDS_FORMAT_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.DDS_FORMAT_R8G8B8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_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; } } } }
public static unsafe void Save( Document input, Stream output, DdsFileFormat format, DdsErrorMetric errorMetric, BC7CompressionMode compressionMode, bool generateMipmaps, MipMapSampling sampling, Surface scratchSurface, ProgressEventHandler progressCallback) { using (RenderArgs args = new RenderArgs(scratchSurface)) { input.Render(args, true); } DdsWriteImageCallback ddsWriteImage = delegate(IntPtr image, UIntPtr imageSize) { ulong size = imageSize.ToUInt64(); if (image != IntPtr.Zero && size > 0) { const int MaxBufferSize = 65536; ulong streamBufferSize = Math.Min(MaxBufferSize, size); byte[] streamBuffer = new byte[streamBufferSize]; output.SetLength(checked ((long)size)); ulong offset = 0; ulong remaining = size; fixed(byte *destPtr = streamBuffer) { byte *srcPtr = (byte *)image.ToPointer(); while (remaining > 0) { ulong copySize = Math.Min(MaxBufferSize, remaining); Buffer.MemoryCopy(srcPtr + offset, destPtr, streamBufferSize, copySize); output.Write(streamBuffer, 0, (int)copySize); offset += copySize; remaining -= copySize; } } } }; DdsProgressCallback ddsProgress = delegate(UIntPtr done, UIntPtr total) { double progress = (double)done.ToUInt64() / (double)total.ToUInt64(); progressCallback(null, new ProgressEventArgs(progress * 100.0, true)); }; SaveDdsFile(scratchSurface, format, errorMetric, compressionMode, generateMipmaps, sampling, ddsWriteImage, ddsProgress); GC.KeepAlive(ddsWriteImage); }
public void Initialise(DdsFileFormat fileFormat) { this.m_size = this.Size(); switch (fileFormat) { case DdsFileFormat.DDS_FORMAT_DXT1: case DdsFileFormat.DDS_FORMAT_DXT3: case DdsFileFormat.DDS_FORMAT_DXT5: this.m_flags = 4; this.m_rgbBitCount = 0; this.m_rBitMask = 0; this.m_gBitMask = 0; this.m_bBitMask = 0; this.m_aBitMask = 0; if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) { this.m_fourCC = 0x31545844; } if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT3) { this.m_fourCC = 0x33545844; } if (fileFormat != DdsFileFormat.DDS_FORMAT_DXT5) { break; } this.m_fourCC = 0x35545844; return; case DdsFileFormat.DDS_FORMAT_A8R8G8B8: this.m_flags = 0x41; this.m_rgbBitCount = 0x20; this.m_fourCC = 0; this.m_rBitMask = 0xff0000; this.m_gBitMask = 0xff00; this.m_bBitMask = 0xff; this.m_aBitMask = 0xff000000; return; case DdsFileFormat.DDS_FORMAT_X8R8G8B8: this.m_flags = 0x40; this.m_rgbBitCount = 0x20; this.m_fourCC = 0; this.m_rBitMask = 0xff0000; this.m_gBitMask = 0xff00; this.m_bBitMask = 0xff; this.m_aBitMask = 0; return; case DdsFileFormat.DDS_FORMAT_A8B8G8R8: this.m_flags = 0x41; this.m_rgbBitCount = 0x20; this.m_fourCC = 0; this.m_rBitMask = 0xff; this.m_gBitMask = 0xff00; this.m_bBitMask = 0xff0000; this.m_aBitMask = 0xff000000; return; case DdsFileFormat.DDS_FORMAT_X8B8G8R8: this.m_flags = 0x40; this.m_rgbBitCount = 0x20; this.m_fourCC = 0; this.m_rBitMask = 0xff; this.m_gBitMask = 0xff00; this.m_bBitMask = 0xff0000; this.m_aBitMask = 0; return; case DdsFileFormat.DDS_FORMAT_A1R5G5B5: this.m_flags = 0x41; this.m_rgbBitCount = 0x10; this.m_fourCC = 0; this.m_rBitMask = 0x7c00; this.m_gBitMask = 0x3e0; this.m_bBitMask = 0x1f; this.m_aBitMask = 0x8000; return; case DdsFileFormat.DDS_FORMAT_A4R4G4B4: this.m_flags = 0x41; this.m_rgbBitCount = 0x10; this.m_fourCC = 0; this.m_rBitMask = 0xf00; this.m_gBitMask = 240; this.m_bBitMask = 15; this.m_aBitMask = 0xf000; return; case DdsFileFormat.DDS_FORMAT_R8G8B8: this.m_flags = 0x40; this.m_fourCC = 0; this.m_rgbBitCount = 0x18; this.m_rBitMask = 0xff0000; this.m_gBitMask = 0xff00; this.m_bBitMask = 0xff; this.m_aBitMask = 0; return; case DdsFileFormat.DDS_FORMAT_R5G6B5: this.m_flags = 0x40; this.m_fourCC = 0; this.m_rgbBitCount = 0x10; this.m_rBitMask = 0xf800; this.m_gBitMask = 0x7e0; this.m_bBitMask = 0x1f; this.m_aBitMask = 0; break; default: return; } }
public void Load( System.IO.Stream input ) { if (input == null) return; if (input.Length == 0) return; ReadWriteStream(input, this._rawDDS); input.Seek(0, SeekOrigin.Begin); 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.DDS_FOURCC) != 0) { //int squishFlags = 0; DdsFileFormat ddsFormat = new DdsFileFormat(); switch (m_header.m_pixelFormat.m_fourCC) { case 0x31545844: //squishFlags = ( int )DdsSquish.SquishFlags.kDxt1; ddsFormat = DdsFileFormat.DDS_FORMAT_DXT1; m_header.fileFormat = "DXT1"; break; case 0x33545844: //squishFlags = ( int )DdsSquish.SquishFlags.kDxt3; ddsFormat = DdsFileFormat.DDS_FORMAT_DXT3; m_header.fileFormat = "DXT3"; break; case 0x35545844: //squishFlags = ( int )DdsSquish.SquishFlags.kDxt5; ddsFormat = DdsFileFormat.DDS_FORMAT_DXT5; m_header.fileFormat = "DXT5"; break; case 0x31495441: ddsFormat = DdsFileFormat.DDS_FORMAT_ATI1; m_header.fileFormat = "ATI1"; break; case 0x32495441: ddsFormat = DdsFileFormat.DDS_FORMAT_ATI2; m_header.fileFormat = "ATI2"; 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 = 0; //((squishFlags & (int)DdsSquish.SquishFlags.kDxt1) != 0) ? 8 : 16; //if ((squishFlags & (int)DdsFileFormat.DDS_FORMAT_DXT1) != 0) //{ //blockSize = 8; //} //else //{ //blockSize = 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 = DdsSquish.DecompressImage( input, GetWidth(), GetHeight(), squishFlags ); this.m_pixelData = DecodeTextureData(input, ddsFormat, GetWidth(), GetHeight(), 0, 0, false); } else { // We can only deal with the non-DXT formats we know about.. this is a bit of a mess.. // Sorry.. DdsFileFormat fileFormat = DdsFileFormat.DDS_FORMAT_INVALID; if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_RGB + (int)DdsPixelFormat.PixelFormatFlags.DDS_ALPHAPIXELS) && (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.DDS_FORMAT_A8R8G8B8; m_header.fileFormat = "ARGB8"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_X8R8G8B8; m_header.fileFormat = "X8RGB8"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_RGB + (int)DdsPixelFormat.PixelFormatFlags.DDS_ALPHAPIXELS) && (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.DDS_FORMAT_A8B8G8R8; m_header.fileFormat = "ABGR8"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_X8B8G8R8; m_header.fileFormat = "XBGR8"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_RGB + (int)DdsPixelFormat.PixelFormatFlags.DDS_ALPHAPIXELS) && (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.DDS_FORMAT_A1R5G5B5; m_header.fileFormat = "ARGB"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_RGB + (int)DdsPixelFormat.PixelFormatFlags.DDS_ALPHAPIXELS) && (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.DDS_FORMAT_A4R4G4B4; m_header.fileFormat = "ARGB4"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_R8G8B8; m_header.fileFormat = "RGB8"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_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.DDS_FORMAT_R5G6B5; m_header.fileFormat = "RGB5"; } else if ((m_header.m_pixelFormat.m_flags == (int)DdsPixelFormat.PixelFormatFlags.DDS_LUMINANCE + (int)DdsPixelFormat.PixelFormatFlags.DDS_ALPHAPIXELS) && (m_header.m_pixelFormat.m_rgbBitCount == 16) && (m_header.m_pixelFormat.m_rBitMask == 0x000000ff) && (m_header.m_pixelFormat.m_gBitMask == 0x00000000) && (m_header.m_pixelFormat.m_bBitMask == 0x00000000) && (m_header.m_pixelFormat.m_aBitMask == 0x0000ff00)) { fileFormat = DdsFileFormat.DDS_FORMAT_A8L8; m_header.fileFormat = "A8L8"; } // If fileFormat is still invalid, then it's an unsupported format. if (fileFormat == DdsFileFormat.DDS_FORMAT_INVALID) { System.Windows.Forms.MessageBox.Show("File is not a supported DDS format"); return; } // 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.DDS_HEADER_FLAGS_PITCH) != 0) { // Pitch specified.. so we can use directly rowPitch = (int)m_header.m_pitchOrLinearSize; } else if ((m_header.m_headerFlags & (int)DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_LINEARSIZE) != 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.DDS_FORMAT_A8R8G8B8) { pixelAlpha = (pixelColour >> 24) & 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_X8R8G8B8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_A8B8G8R8) { pixelAlpha = (pixelColour >> 24) & 0xff; pixelRed = (pixelColour >> 0) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 16) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_X8B8G8R8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 0) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 16) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_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.DDS_FORMAT_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.DDS_FORMAT_R8G8B8) { pixelAlpha = 0xff; pixelRed = (pixelColour >> 16) & 0xff; pixelGreen = (pixelColour >> 8) & 0xff; pixelBlue = (pixelColour >> 0) & 0xff; } else if (fileFormat == DdsFileFormat.DDS_FORMAT_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; } } } }
public void Save(Stream output, Surface surface, DdsFileFormat fileFormat, DdsCompressorType compressorType, DdsErrorMetric errorMetric, bool generateMipMaps, ResamplingAlgorithm mipMapResamplingAlgorithm, bool weightColorByAlpha, ProgressEventHandler progressCallback) { int num21; int num = 0; bool flag = ((fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) || (fileFormat == DdsFileFormat.DDS_FORMAT_DXT3)) || (fileFormat == DdsFileFormat.DDS_FORMAT_DXT5); int num2 = 1; int mipWidth = surface.Width; int height = surface.Height; if (generateMipMaps) { while ((mipWidth > 1) || (height > 1)) { num2++; mipWidth /= 2; height /= 2; } } this.m_header.m_size = this.m_header.Size(); this.m_header.m_headerFlags = 0x1007; if (flag) { this.m_header.m_headerFlags |= 0x80000; } else { this.m_header.m_headerFlags |= 8; } if (num2 > 1) { this.m_header.m_headerFlags |= 0x20000; } this.m_header.m_height = (uint)surface.Height; this.m_header.m_width = (uint)surface.Width; if (flag) { int num5 = ((surface.Width + 3) / 4) * ((surface.Height + 3) / 4); int num6 = (fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) ? 8 : 0x10; this.m_header.m_pitchOrLinearSize = (uint)(num5 * num6); } else { switch (fileFormat) { case DdsFileFormat.DDS_FORMAT_A8R8G8B8: case DdsFileFormat.DDS_FORMAT_X8R8G8B8: case DdsFileFormat.DDS_FORMAT_A8B8G8R8: case DdsFileFormat.DDS_FORMAT_X8B8G8R8: num = 4; break; case DdsFileFormat.DDS_FORMAT_A1R5G5B5: case DdsFileFormat.DDS_FORMAT_A4R4G4B4: case DdsFileFormat.DDS_FORMAT_R5G6B5: num = 2; break; case DdsFileFormat.DDS_FORMAT_R8G8B8: num = 3; break; } this.m_header.m_pitchOrLinearSize = (uint)(this.m_header.m_width * num); } this.m_header.m_depth = 0; this.m_header.m_mipMapCount = (num2 == 1) ? 0 : ((uint)num2); this.m_header.m_reserved1_0 = 0; this.m_header.m_reserved1_1 = 0; this.m_header.m_reserved1_2 = 0; this.m_header.m_reserved1_3 = 0; this.m_header.m_reserved1_4 = 0; this.m_header.m_reserved1_5 = 0; this.m_header.m_reserved1_6 = 0; this.m_header.m_reserved1_7 = 0; this.m_header.m_reserved1_8 = 0; this.m_header.m_reserved1_9 = 0; this.m_header.m_reserved1_10 = 0; this.m_header.m_pixelFormat.Initialise(fileFormat); this.m_header.m_surfaceFlags = 0x1000; if (num2 > 1) { this.m_header.m_surfaceFlags |= 0x400008; } this.m_header.m_cubemapFlags = 0; this.m_header.m_reserved2_0 = 0; this.m_header.m_reserved2_1 = 0; this.m_header.m_reserved2_2 = 0; output.WriteUInt32(0x20534444); this.m_header.Write(output); int squishFlags = this.GetSquishFlags(fileFormat, compressorType, errorMetric, weightColorByAlpha); mipWidth = surface.Width; height = surface.Height; SizeInt32[] numArray = new SizeInt32[num2]; int[] numArray2 = new int[num2]; int[] pixelsCompleted = new int[num2]; long totalPixels = 0L; for (int i = 0; i < num2; i++) { SizeInt32 num8 = new SizeInt32((mipWidth > 0) ? mipWidth : 1, (height > 0) ? height : 1); numArray[i] = num8; int num9 = num8.Width * num8.Height; numArray2[i] = num9; if (i == 0) { pixelsCompleted[i] = 0; } else { pixelsCompleted[i] = pixelsCompleted[i - 1] + numArray2[i - 1]; } totalPixels += num9; mipWidth /= 2; height /= 2; } mipWidth = surface.Width; height = surface.Height; for (int mipLoop = 0; mipLoop < num2; mipLoop = num21 + 1) { byte[] buffer; SizeInt32 size = numArray[mipLoop]; Surface surface2 = new Surface(size); if (mipLoop == 0) { surface2 = surface; } else { IRenderer <ColorBgra> renderer; SizeInt32 newSize = surface2.Size <ColorBgra>(); switch (mipMapResamplingAlgorithm) { case ResamplingAlgorithm.NearestNeighbor: renderer = surface.ResizeNearestNeighbor(newSize); break; case ResamplingAlgorithm.Bilinear: renderer = surface.ResizeBilinear(newSize); break; case ResamplingAlgorithm.Bicubic: renderer = surface.ResizeBicubic(newSize); break; case ResamplingAlgorithm.SuperSampling: renderer = surface.ResizeSuperSampling(newSize); break; case ResamplingAlgorithm.Fant: renderer = surface.ResizeFant(newSize); break; default: throw ExceptionUtil.InvalidEnumArgumentException <ResamplingAlgorithm>(mipMapResamplingAlgorithm, "mipMapResamplingAlgorithm"); } renderer.Render <ColorBgra>(surface2); } DdsSquish.ProgressFn fn = delegate(int workDone, int workTotal) { long num = workDone * mipWidth; long num2 = pixelsCompleted[mipLoop]; double num3 = (num + num2) / ((double)totalPixels); progressCallback(this, new ProgressEventArgs(DoubleUtil.Clamp(100.0 * num3, 0.0, 100.0))); }; if ((fileFormat >= DdsFileFormat.DDS_FORMAT_DXT1) && (fileFormat <= DdsFileFormat.DDS_FORMAT_DXT5)) { buffer = DdsSquish.CompressImage(surface2, squishFlags, (progressCallback == null) ? null : fn); } else { int num12 = num * surface2.Width; buffer = new byte[num12 * surface2.Height]; buffer.Initialize(); for (int j = 0; j < surface2.Height; j++) { for (int k = 0; k < surface2.Width; k++) { ColorBgra point = surface2.GetPoint(k, j); uint num15 = 0; switch (fileFormat) { case DdsFileFormat.DDS_FORMAT_A8R8G8B8: num15 = (uint)((((point.A << 0x18) | (point.R << 0x10)) | (point.G << 8)) | point.B); break; case DdsFileFormat.DDS_FORMAT_X8R8G8B8: num15 = (uint)(((point.R << 0x10) | (point.G << 8)) | point.B); break; case DdsFileFormat.DDS_FORMAT_A8B8G8R8: num15 = (uint)((((point.A << 0x18) | (point.B << 0x10)) | (point.G << 8)) | point.R); break; case DdsFileFormat.DDS_FORMAT_X8B8G8R8: num15 = (uint)(((point.B << 0x10) | (point.G << 8)) | point.R); break; case DdsFileFormat.DDS_FORMAT_A1R5G5B5: num15 = (uint)((((((point.A != null) ? 1 : 0) << 15) | ((point.R >> 3) << 10)) | ((point.G >> 3) << 5)) | (point.B >> 3)); break; case DdsFileFormat.DDS_FORMAT_A4R4G4B4: num15 = (uint)(((((point.A >> 4) << 12) | ((point.R >> 4) << 8)) | ((point.G >> 4) << 4)) | (point.B >> 4)); break; case DdsFileFormat.DDS_FORMAT_R8G8B8: num15 = (uint)(((point.R << 0x10) | (point.G << 8)) | point.B); break; case DdsFileFormat.DDS_FORMAT_R5G6B5: num15 = (uint)((((point.R >> 3) << 11) | ((point.G >> 2) << 5)) | (point.B >> 3)); break; } int num16 = (j * num12) + (k * num); for (int m = 0; m < num; m++) { buffer[num16 + m] = (byte)((num15 >> (8 * m)) & 0xff); } } if (progressCallback != null) { long num18 = (j + 1) * mipWidth; long num19 = pixelsCompleted[mipLoop]; double num20 = (num18 + num19) / ((double)totalPixels); progressCallback(this, new ProgressEventArgs(100.0 * num20)); } } } output.Write(buffer, 0, buffer.GetLength(0)); mipWidth /= 2; height /= 2; num21 = mipLoop; } }
private static UInt32 GetMipMapOffset(DdsFileFormat fourcc, int width, int height, int mipmaps, int mipmapno, bool mipmapreversed) { UInt32 offset = 0; if (mipmapreversed) { for (int loop = mipmaps - 1; loop > mipmapno; loop--) { offset += GetMipMapSize(fourcc, width, height, mipmaps, loop); } } else { for (int loop = mipmapno; loop > 0; loop--) { offset += GetMipMapSize(fourcc, width, height, mipmaps, loop - 1); } } return offset; }
private static byte[] DecodeTextureData(Stream file, DdsFileFormat fourcc, int width, int height, int mipmaps, int mipmapno, bool mipmapreversed) { UInt32 start = GetMipMapOffset(fourcc, width, height, mipmaps, mipmapno, mipmapreversed); UInt32 size = GetMipMapSize(fourcc, width, height, mipmaps, mipmapno); //if (input.Length == 0) return null; if (size == 0 || size + start + file.Position > file.Length) return null; width = (width + (1 << mipmapno) - 1) >> mipmapno; height = (height + (1 << mipmapno) - 1) >> mipmapno; file.Seek(start, System.IO.SeekOrigin.Current); byte[] data = new byte[size]; file.Read(data, 0, (int)size); byte[] pixeldata = new byte[width * height * 4]; //pixeldata[0] = 0x42; //pixeldata[1] = 0x4d; //BitConverter.GetBytes(pixeldata.Length).CopyTo(pixeldata, 2); //pixeldata[10] = 0x36; //pixeldata[14] = 0x28; //BitConverter.GetBytes(width).CopyTo(pixeldata, 18); //BitConverter.GetBytes(height).CopyTo(pixeldata, 22); //pixeldata[26] = 1; //pixeldata[28] = 32; //BitConverter.GetBytes(width * height * 4).CopyTo(pixeldata, 0); switch (fourcc) { case DdsFileFormat.DDS_FORMAT_ATI1: DecodeATI1Texture(pixeldata, 0, width, height, data); break; case DdsFileFormat.DDS_FORMAT_ATI2: DecodeATI2Texture(pixeldata, 0, width, height, data); break; case DdsFileFormat.DDS_FORMAT_DXT1: DecodeDXT1Texture(pixeldata, 0, width, height, data); break; case DdsFileFormat.DDS_FORMAT_DXT5: DecodeDXT5Texture(pixeldata, 0, width, height, data); break; } //System.IO.MemoryStream ms = new System.IO.MemoryStream(pixeldata); //using (ms) //{ // return new Bitmap(Image.FromStream(ms)); //} return pixeldata; }
public DdsFileFormatSetting(string name, DdsFileFormat fileFormat) { Name = name; DdsFileFormat = fileFormat; }
private static string GetUnsupportedFormatMessage(DdsFileFormat format) { return(format.ToString() + " is not a supported pixel format."); }
public static void DDS_To_DDS(string From_DDS_File, string To_DDS_File, DdsFileFormat Format) { System.IO.FileStream fileStream = new System.IO.FileStream(To_DDS_File, System.IO.FileMode.Create); DdsFile.Save(fileStream, Format, DdsErrorMetric.Perceptual, BC7CompressionMode.Slow, false, false, ResamplingAlgorithm.Bilinear, Load(From_DDS_File), null); fileStream.Close(); }
private static UInt32 GetMipMapSize(DdsFileFormat fourcc, int width, int height, int mipmaps, int mipmapno) { width = (width + (1 << mipmapno) - 1) >> mipmapno; height = (height + (1 << mipmapno) - 1) >> mipmapno; switch (fourcc) { case DdsFileFormat.DDS_FORMAT_DXT1: return (UInt32)(((width + 3) / 4) * ((height + 3) / 4)) * 8; case DdsFileFormat.DDS_FORMAT_DXT5: return (UInt32)(((width + 3) / 4) * ((height + 3) / 4)) * 16; case DdsFileFormat.DDS_FORMAT_ATI1: return (UInt32)(((width + 3) / 4) * ((height + 3) / 4)) * 8; case DdsFileFormat.DDS_FORMAT_ATI2: return (UInt32)(((width + 3) / 4) * ((height + 3) / 4)) * 16; default: return 0; } }
/* * public void Save(System.IO.Stream output, Surface surface, DdsSaveConfigToken ddsToken, ProgressEventHandler progressCallback) { * // For non-compressed textures, we need pixel width. * int pixelWidth = 0; * * // Identify if we're a compressed image * bool isCompressed = ((ddsToken.m_fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) || * (ddsToken.m_fileFormat == DdsFileFormat.DDS_FORMAT_DXT3) || * (ddsToken.m_fileFormat == DdsFileFormat.DDS_FORMAT_DXT5)); * * // Compute mip map count.. * int mipCount = 1; * int mipWidth = surface.Width; * int mipHeight = surface.Height; * * if (ddsToken.m_generateMipMaps) { * // This breaks! * * while ((mipWidth > 1) || (mipHeight > 1)) { * mipCount++; * mipWidth /= 2; * mipHeight /= 2; * } * } * * // Populate bulk of our DdsHeader * m_header.m_size = m_header.Size(); * m_header.m_headerFlags = (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_TEXTURE); * * if (isCompressed) * m_header.m_headerFlags |= (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_LINEARSIZE); * else * m_header.m_headerFlags |= (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_PITCH); * * if (mipCount > 1) * m_header.m_headerFlags |= (uint)(DdsHeader.HeaderFlags.DDS_HEADER_FLAGS_MIPMAP); * * m_header.m_height = (uint)surface.Height; * m_header.m_width = (uint)surface.Width; * * if (isCompressed) { * // Compresssed textures have the linear flag set.So pitchOrLinearSize * // needs to contain the entire size of the DXT block. * int blockCount = ((surface.Width + 3) / 4) * ((surface.Height + 3) / 4); * int blockSize = (ddsToken.m_fileFormat == 0) ? 8 : 16; * m_header.m_pitchOrLinearSize = (uint)(blockCount * blockSize); * } * else { * // Non-compressed textures have the pitch flag set. So pitchOrLinearSize * // needs to contain the row pitch of the main image. DWORD aligned too. * switch (ddsToken.m_fileFormat) { * case DdsFileFormat.DDS_FORMAT_A8R8G8B8: * case DdsFileFormat.DDS_FORMAT_X8R8G8B8: * case DdsFileFormat.DDS_FORMAT_A8B8G8R8: * case DdsFileFormat.DDS_FORMAT_X8B8G8R8: * pixelWidth = 4; // 32bpp * break; * * case DdsFileFormat.DDS_FORMAT_A1R5G5B5: * case DdsFileFormat.DDS_FORMAT_A4R4G4B4: * case DdsFileFormat.DDS_FORMAT_R5G6B5: * pixelWidth = 2; // 16bpp * break; * * case DdsFileFormat.DDS_FORMAT_R8G8B8: * pixelWidth = 3; // 24bpp * break; * } * * // Compute row pitch * m_header.m_pitchOrLinearSize = (uint)((int)m_header.m_width * pixelWidth); * #if APPLY_PITCH_ALIGNMENT * // Align to DWORD, if we need to.. (see notes about pitch alignment all over this code) * m_header.m_pitchOrLinearSize = ( uint )( ( ( int )m_header.m_pitchOrLinearSize + 3 ) & ( ~3 ) ); #endif //APPLY_PITCH_ALIGNMENT * } * * m_header.m_depth = 0; * m_header.m_mipMapCount = (mipCount == 1) ? 0 : (uint)mipCount; * m_header.m_reserved1_0 = 0; * m_header.m_reserved1_1 = 0; * m_header.m_reserved1_2 = 0; * m_header.m_reserved1_3 = 0; * m_header.m_reserved1_4 = 0; * m_header.m_reserved1_5 = 0; * m_header.m_reserved1_6 = 0; * m_header.m_reserved1_7 = 0; * m_header.m_reserved1_8 = 0; * m_header.m_reserved1_9 = 0; * m_header.m_reserved1_10 = 0; * * // Populate our DdsPixelFormat object * m_header.m_pixelFormat.Initialise(ddsToken.m_fileFormat); * * // Populate miscellanous header flags * m_header.m_surfaceFlags = (uint)DdsHeader.SurfaceFlags.DDS_SURFACE_FLAGS_TEXTURE; * * if (mipCount > 1) * m_header.m_surfaceFlags |= (uint)DdsHeader.SurfaceFlags.DDS_SURFACE_FLAGS_MIPMAP; * * m_header.m_cubemapFlags = 0; * m_header.m_reserved2_0 = 0; * m_header.m_reserved2_1 = 0; * m_header.m_reserved2_2 = 0; * * // Write out our DDS tag * Utility.WriteUInt32(output, 0x20534444); // 'DDS ' * * // Write out the header * m_header.Write(output); * * int squishFlags = ddsToken.GetSquishFlags(); * * // Our output data array will be sized as necessary * byte[] outputData; * * // Reset our mip width & height variables... * mipWidth = surface.Width; * mipHeight = surface.Height; * * // Figure out how much total work each mip map is * Size[] writeSizes = new Size[mipCount]; * int[] mipPixels = new int[mipCount]; * int[] pixelsCompleted = new int[mipCount]; // # pixels completed once we have reached this mip * long totalPixels = 0; * for (int mipLoop = 0; mipLoop < mipCount; mipLoop++) { * Size writeSize = new Size((mipWidth > 0) ? mipWidth : 1, (mipHeight > 0) ? mipHeight : 1); * writeSizes[mipLoop] = writeSize; * * int thisMipPixels = writeSize.Width * writeSize.Height; * mipPixels[mipLoop] = thisMipPixels; * * if (mipLoop == 0) { * pixelsCompleted[mipLoop] = 0; * } * else { * pixelsCompleted[mipLoop] = pixelsCompleted[mipLoop - 1] + mipPixels[mipLoop - 1]; * } * * totalPixels += thisMipPixels; * mipWidth /= 2; * mipHeight /= 2; * } * * mipWidth = surface.Width; * mipHeight = surface.Height; * * for (int mipLoop = 0; mipLoop < mipCount; mipLoop++) { * Size writeSize = writeSizes[mipLoop]; * Surface writeSurface = new Surface(writeSize); * * if (mipLoop == 0) { * // No point resampling the first level.. it's got exactly what we want. * writeSurface = surface; * } * else { * // I'd love to have a UI component to select what kind of resampling, but * // there's hardly any space for custom UI stuff in the Save Dialog. And I'm * // not having any scrollbars in there..! * // Also, note that each mip level is formed from the main level, to reduce * // compounded errors when generating mips. * writeSurface.SuperSamplingFitSurface(surface); * } * * DdsSquish.ProgressFn progressFn = * delegate(int workDone, int workTotal) { * long thisMipPixelsDone = workDone * (long)mipWidth; * long previousMipsPixelsDone = pixelsCompleted[mipLoop]; * double progress = (double)((double)thisMipPixelsDone + * (double)previousMipsPixelsDone) / (double)totalPixels; * progressCallback(this, new ProgressEventArgs(100.0 * progress)); * }; * * if ((ddsToken.m_fileFormat >= DdsFileFormat.DDS_FORMAT_DXT1) && * (ddsToken.m_fileFormat <= DdsFileFormat.DDS_FORMAT_DXT5)) * outputData = DdsSquish.CompressImage(writeSurface, squishFlags, * (progressCallback == null) ? null : progressFn); * else { * int mipPitch = pixelWidth * writeSurface.Width; * * // From the DDS documents I read, I'd expected the pitch of each mip level to be * // DWORD aligned. As it happens, that's not the case. Re-aligning the pitch of * // each level results in later mips getting sheared as the pitch is incorrect. * // So, the following line is intentionally optional. Maybe the documentation * // is referring to the pitch when accessing the mip directly.. who knows. * // * // Infact, all the talk of non-compressed textures having DWORD alignment of pitch * // seems to be bollocks.. If I apply alignment, then they fail to load in 3rd Party * // or Microsoft DDS viewing applications. * // * #if APPLY_PITCH_ALIGNMENT * mipPitch = ( mipPitch + 3 ) & ( ~3 ); #endif // APPLY_PITCH_ALIGNMENT * * outputData = new byte[mipPitch * writeSurface.Height]; * outputData.Initialize(); * * for (int y = 0; y < writeSurface.Height; y++) { * for (int x = 0; x < writeSurface.Width; x++) { * // Get colour from surface * ColorBgra pixelColour = writeSurface.GetPoint(x, y); * uint pixelData = 0; * * switch (ddsToken.m_fileFormat) { * case DdsFileFormat.DDS_FORMAT_A8R8G8B8: { * pixelData = ((uint)pixelColour.A << 24) | * ((uint)pixelColour.R << 16) | * ((uint)pixelColour.G << 8) | * ((uint)pixelColour.B << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_X8R8G8B8: { * pixelData = ((uint)pixelColour.R << 16) | * ((uint)pixelColour.G << 8) | * ((uint)pixelColour.B << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_A8B8G8R8: { * pixelData = ((uint)pixelColour.A << 24) | * ((uint)pixelColour.B << 16) | * ((uint)pixelColour.G << 8) | * ((uint)pixelColour.R << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_X8B8G8R8: { * pixelData = ((uint)pixelColour.B << 16) | * ((uint)pixelColour.G << 8) | * ((uint)pixelColour.R << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_A1R5G5B5: { * pixelData = ((uint)((pixelColour.A != 0) ? 1 : 0) << 15) | * ((uint)(pixelColour.R >> 3) << 10) | * ((uint)(pixelColour.G >> 3) << 5) | * ((uint)(pixelColour.B >> 3) << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_A4R4G4B4: { * pixelData = ((uint)(pixelColour.A >> 4) << 12) | * ((uint)(pixelColour.R >> 4) << 8) | * ((uint)(pixelColour.G >> 4) << 4) | * ((uint)(pixelColour.B >> 4) << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_R8G8B8: { * pixelData = ((uint)pixelColour.R << 16) | * ((uint)pixelColour.G << 8) | * ((uint)pixelColour.B << 0); * break; * } * * case DdsFileFormat.DDS_FORMAT_R5G6B5: { * pixelData = ((uint)(pixelColour.R >> 3) << 11) | * ((uint)(pixelColour.G >> 2) << 5) | * ((uint)(pixelColour.B >> 3) << 0); * break; * } * } * * // pixelData contains our target data.. so now set the pixel bytes * int pixelOffset = (y * mipPitch) + (x * pixelWidth); * for (int loop = 0; loop < pixelWidth; loop++) { * outputData[pixelOffset + loop] = (byte)((pixelData >> (8 * loop)) & 0xff); * } * } * * if (progressCallback != null) { * long thisMipPixelsDone = (y + 1) * (long)mipWidth; * long previousMipsPixelsDone = pixelsCompleted[mipLoop]; * double progress = (double)((double)thisMipPixelsDone + * (double)previousMipsPixelsDone) / (double)totalPixels; * progressCallback(this, new ProgressEventArgs(100.0 * progress)); * } * } * } * * // Write the data for this mip level out.. * output.Write(outputData, 0, outputData.GetLength(0)); * * mipWidth = mipWidth / 2; * mipHeight = mipHeight / 2; * } * }*/ public Bitmap Load(BinaryReader input) { // Read the DDS tag. If it's not right, then bail.. UInt32 ddsTag = input.ReadUInt32(); if (ddsTag != 0x20534444) { throw new FormatException("File does not appear to be a DDS image"); } m_header.Read(input); if ((Header.PixelFormat.Flags & (UInt32)PixelFormatFlags.DDS_FOURCC) != 0) { UInt32 squishFlags = 0; switch (Header.PixelFormat.FourCC) { case 0x31545844: squishFlags = (UInt32)SquishFlags.Dxt1; break; case 0x33545844: squishFlags = (UInt32)SquishFlags.Dxt3; break; case 0x35545844: squishFlags = (UInt32)SquishFlags.Dxt5; break; default: throw new FormatException("File is not a supported DDS format"); } // Compute size of compressed block area int blockCount = ((this.Width + 3) / 4) * ((this.Height + 3) / 4); int blockSize = ((squishFlags & (UInt32)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.. return(DdsSquish.DecompressImage(compressedBlocks, this.Width, this.Height, (int)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.DDS_FORMAT_INVALID; if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGBA) && (this.Header.PixelFormat.RgbBitCount == 0x20) && (this.Header.PixelFormat.BitMaskA == 0xff000000) && (this.Header.PixelFormat.BitMaskR == 0x00ff0000) && (this.Header.PixelFormat.BitMaskG == 0x0000ff00) && (this.Header.PixelFormat.BitMaskB == 0x000000ff)) { fileFormat = DdsFileFormat.DDS_FORMAT_A8R8G8B8; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGB) && (this.Header.PixelFormat.RgbBitCount == 0x20) && (this.Header.PixelFormat.BitMaskA == 0x00000000) && (this.Header.PixelFormat.BitMaskR == 0x00ff0000) && (this.Header.PixelFormat.BitMaskG == 0x0000ff00) && (this.Header.PixelFormat.BitMaskB == 0x000000ff)) { fileFormat = DdsFileFormat.DDS_FORMAT_X8R8G8B8; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGBA) && (this.Header.PixelFormat.RgbBitCount == 0x20) && (this.Header.PixelFormat.BitMaskA == 0xff000000) && (this.Header.PixelFormat.BitMaskR == 0x000000ff) && (this.Header.PixelFormat.BitMaskG == 0x0000ff00) && (this.Header.PixelFormat.BitMaskB == 0x00ff0000)) { fileFormat = DdsFileFormat.DDS_FORMAT_A8B8G8R8; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGB) && (this.Header.PixelFormat.RgbBitCount == 0x20) && (this.Header.PixelFormat.BitMaskA == 0x00000000) && (this.Header.PixelFormat.BitMaskR == 0x000000ff) && (this.Header.PixelFormat.BitMaskG == 0x0000ff00) && (this.Header.PixelFormat.BitMaskB == 0x00ff0000)) { fileFormat = DdsFileFormat.DDS_FORMAT_X8B8G8R8; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGBA) && (this.Header.PixelFormat.RgbBitCount == 0x10) && (this.Header.PixelFormat.BitMaskA == 0x00008000) && (this.Header.PixelFormat.BitMaskR == 0x00007c00) && (this.Header.PixelFormat.BitMaskG == 0x000003e0) && (this.Header.PixelFormat.BitMaskB == 0x0000001f)) { fileFormat = DdsFileFormat.DDS_FORMAT_A1R5G5B5; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGBA) && (this.Header.PixelFormat.RgbBitCount == 0x10) && (this.Header.PixelFormat.BitMaskA == 0x0000f000) && (this.Header.PixelFormat.BitMaskR == 0x00000f00) && (this.Header.PixelFormat.BitMaskG == 0x000000f0) && (this.Header.PixelFormat.BitMaskB == 0x0000000f)) { fileFormat = DdsFileFormat.DDS_FORMAT_A4R4G4B4; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGB) && (this.Header.PixelFormat.RgbBitCount == 0x18) && (this.Header.PixelFormat.BitMaskA == 0x00000000) && (this.Header.PixelFormat.BitMaskR == 0x00ff0000) && (this.Header.PixelFormat.BitMaskG == 0x0000ff00) && (this.Header.PixelFormat.BitMaskB == 0x000000ff)) { fileFormat = DdsFileFormat.DDS_FORMAT_R8G8B8; } else if ( (this.Header.PixelFormat.Flags == (UInt32)PixelFormatFlags.DDS_RGB) && (this.Header.PixelFormat.RgbBitCount == 0x10) && (this.Header.PixelFormat.BitMaskA == 0x00000000) && (this.Header.PixelFormat.BitMaskR == 0x0000f800) && (this.Header.PixelFormat.BitMaskG == 0x000007e0) && (this.Header.PixelFormat.BitMaskB == 0x0000001f)) { fileFormat = DdsFileFormat.DDS_FORMAT_R5G6B5; } // If fileFormat is still invalid, then it's an unsupported format. if (fileFormat == DdsFileFormat.DDS_FORMAT_INVALID) { throw new FormatException("File is not a supported DDS format"); } // Size of a source pixel, in bytes UInt32 srcPixelSize = ((UInt32)this.Header.PixelFormat.RgbBitCount / 8); // We need the pitch for a row, so we can allocate enough memory for the load. UInt32 rowPitch = 0; if ((this.Header.Flags & (UInt32)HeaderFlags.DDS_HEADER_FLAGS_PITCH) != 0) { // Pitch specified.. so we can use directly rowPitch = (UInt32)this.Header.PitchOrLinearSize; } else if ((this.Header.Flags & (int)HeaderFlags.DDS_HEADER_FLAGS_LINEARSIZE) != 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 = (UInt32)this.Header.PitchOrLinearSize / this.Header.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 = (this.Header.Width * srcPixelSize); #if APPLY_PITCH_ALIGNMENT rowPitch = ((( int )rowPitch + 3) & (~3)); #endif } // Ok.. now, we need to allocate room for the bytes to read in from. // It's rowPitch bytes * height byte[] readPixelData = new byte[rowPitch * this.Header.Height]; input.Read(readPixelData, 0, readPixelData.GetLength(0)); // We now need space for the real pixel data. byte[] pixelData = new byte[this.Header.Width * this.Header.Height * 4]; // And now we have the arduous task of filling that up with stuff.. for (UInt32 destY = 0; destY < this.Header.Height; destY++) { for (UInt32 destX = 0; destX < this.Header.Width; destX++) { // Compute source pixel offset UInt32 srcPixelOffset = (destY * rowPitch) + (destX * srcPixelSize); // Read our pixel UInt32 pixelColor = 0; UInt32 pixelR = 0; UInt32 pixelG = 0; UInt32 pixelB = 0; UInt32 pixelA = 0; // Build our pixel colour as a DWORD for (int loop = 0; loop < srcPixelSize; loop++) { pixelColor |= (uint)(readPixelData[srcPixelOffset + loop] << (8 * loop)); } switch (fileFormat) { case DdsFileFormat.DDS_FORMAT_A8R8G8B8: pixelA = (pixelColor >> 0x18) & 0xff; pixelR = (pixelColor >> 0x10) & 0xff; pixelG = (pixelColor >> 0x08) & 0xff; pixelB = pixelColor & 0xff; break; case DdsFileFormat.DDS_FORMAT_X8R8G8B8: pixelA = 0xff; pixelR = (pixelColor >> 0x10) & 0xff; pixelG = (pixelColor >> 0x08) & 0xff; pixelB = pixelColor & 0xff; break; case DdsFileFormat.DDS_FORMAT_A8B8G8R8: pixelA = (pixelColor >> 0x18) & 0xff; pixelR = pixelColor & 0xff; pixelG = (pixelColor >> 0x08) & 0xff; pixelB = (pixelColor >> 0x10) & 0xff; break; case DdsFileFormat.DDS_FORMAT_X8B8G8R8: pixelA = 0xff; pixelR = pixelColor & 0xff; pixelG = (pixelColor >> 0x08) & 0xff; pixelB = (pixelColor >> 0x10) & 0xff; break; case DdsFileFormat.DDS_FORMAT_A1R5G5B5: pixelA = (pixelColor >> 15) * 0xff; pixelR = (pixelColor >> 10) & 0x1f; pixelR = (pixelR << 3) | (pixelR >> 2); pixelG = (pixelColor >> 5) & 0x1f; pixelG = (pixelG << 3) | (pixelG >> 2); pixelB = (pixelColor >> 0) & 0x1f; pixelB = (pixelB << 3) | (pixelB >> 2); break; case DdsFileFormat.DDS_FORMAT_A4R4G4B4: pixelA = (pixelColor >> 12) & 0xff; pixelA = (pixelA << 4) | (pixelA >> 0); pixelR = (pixelColor >> 8) & 0x0f; pixelR = (pixelR << 4) | (pixelR >> 0); pixelG = (pixelColor >> 4) & 0x0f; pixelG = (pixelG << 4) | (pixelG >> 0); pixelB = (pixelColor >> 0) & 0x0f; pixelB = (pixelB << 4) | (pixelB >> 0); break; case DdsFileFormat.DDS_FORMAT_R8G8B8: pixelA = 0xff; pixelR = (pixelColor >> 0x10) & 0xff; pixelG = (pixelColor >> 0x08) & 0xff; pixelB = pixelColor & 0xff; break; case DdsFileFormat.DDS_FORMAT_R5G6B5: pixelA = 0xff; pixelR = (pixelColor >> 0x0b) & 0x1f; pixelR = (pixelR << 0x03) | (pixelR >> 0x02); pixelG = (pixelColor >> 0x05) & 0x3f; pixelG = (pixelG << 0x02) | (pixelG >> 0x04); pixelB = pixelColor & 0x1f; pixelB = (pixelB << 0x03) | (pixelB >> 0x02); break; } UInt32 destPixelOffset = (destY * this.Header.Width * 4) + (destX * 4); pixelData[destPixelOffset + 0] = (byte)pixelB; pixelData[destPixelOffset + 1] = (byte)pixelG; pixelData[destPixelOffset + 2] = (byte)pixelR; pixelData[destPixelOffset + 3] = (byte)pixelA; } } // Copy the pixel data to a new bitmap Bitmap bmp = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb); Rectangle rect = new Rectangle(0, 0, this.Width, this.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat); System.Runtime.InteropServices.Marshal.Copy(pixelData, 0, bmpData.Scan0, this.Stride * this.Height); bmp.UnlockBits(bmpData); return(bmp); } }
public static void Save( IServiceProvider services, Document input, Stream output, DdsFileFormat format, DdsErrorMetric errorMetric, BC7CompressionMode compressionMode, bool cubeMap, bool generateMipmaps, ResamplingAlgorithm sampling, Surface scratchSurface, ProgressEventHandler progressCallback) { using (RenderArgs args = new RenderArgs(scratchSurface)) { input.Render(args, true); } DdsNative.DdsProgressCallback ddsProgress = null; if (progressCallback != null) { ddsProgress = (UIntPtr done, UIntPtr total) => { double progress = (double)done.ToUInt64() / (double)total.ToUInt64(); try { progressCallback(null, new ProgressEventArgs(progress * 100.0, true)); return(true); } catch (OperationCanceledException) { return(false); } }; } int width = scratchSurface.Width; int height = scratchSurface.Height; int arraySize = 1; Size?cubeMapFaceSize = null; if (cubeMap && IsCrossedCubeMapSize(scratchSurface)) { if (width > height) { width /= 4; height /= 3; } else { width /= 3; height /= 4; } arraySize = 6; cubeMapFaceSize = new Size(width, height); } int mipLevels = generateMipmaps ? GetMipCount(width, height) : 1; bool enableHardwareAcceleration = (bool)services.GetService <ISettingsService>().GetSetting(AppSettingPaths.UI.EnableHardwareAcceleration).Value; DdsNative.DDSSaveInfo info = new DdsNative.DDSSaveInfo { width = width, height = height, arraySize = arraySize, mipLevels = mipLevels, format = format, errorMetric = errorMetric, compressionMode = compressionMode, cubeMap = cubeMapFaceSize.HasValue, enableHardwareAcceleration = enableHardwareAcceleration }; using (TextureCollection textures = GetTextures(scratchSurface, cubeMapFaceSize, mipLevels, sampling)) { DdsNative.Save(info, textures, output, ddsProgress); } }
public void Initialise( DdsFileFormat fileFormat ) { m_size = Size(); switch( fileFormat ) { case DdsFileFormat.DDS_FORMAT_DXT1: case DdsFileFormat.DDS_FORMAT_DXT3: case DdsFileFormat.DDS_FORMAT_DXT5: { // DXT1/DXT3/DXT5 m_flags = ( int )PixelFormatFlags.DDS_FOURCC; m_rgbBitCount = 0; m_rBitMask = 0; m_gBitMask = 0; m_bBitMask = 0; m_aBitMask = 0; if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT1) { m_fourCC = 0x31545844; }//"DXT1" if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT3) { m_fourCC = 0x33545844; } //"DXT1" if (fileFormat == DdsFileFormat.DDS_FORMAT_DXT5) { m_fourCC = 0x35545844; } //"DXT1" break; } case DdsFileFormat.DDS_FORMAT_A8R8G8B8: { m_flags = ( int )PixelFormatFlags.DDS_RGB + (int)PixelFormatFlags.DDS_ALPHAPIXELS; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0xff000000; break; } case DdsFileFormat.DDS_FORMAT_X8R8G8B8: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_A8B8G8R8: { m_flags = ( int )PixelFormatFlags.DDS_RGB + (int)PixelFormatFlags.DDS_ALPHAPIXELS; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x000000ff; m_gBitMask = 0x0000ff00; m_bBitMask = 0x00ff0000; m_aBitMask = 0xff000000; break; } case DdsFileFormat.DDS_FORMAT_X8B8G8R8: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_rgbBitCount = 32; m_fourCC = 0; m_rBitMask = 0x000000ff; m_gBitMask = 0x0000ff00; m_bBitMask = 0x00ff0000; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_A1R5G5B5: { m_flags = ( int )PixelFormatFlags.DDS_RGB + (int)PixelFormatFlags.DDS_ALPHAPIXELS; m_rgbBitCount = 16; m_fourCC = 0; m_rBitMask = 0x00007c00; m_gBitMask = 0x000003e0; m_bBitMask = 0x0000001f; m_aBitMask = 0x00008000; break; } case DdsFileFormat.DDS_FORMAT_A4R4G4B4: { m_flags = ( int )PixelFormatFlags.DDS_RGB + (int)PixelFormatFlags.DDS_ALPHAPIXELS; m_rgbBitCount = 16; m_fourCC = 0; m_rBitMask = 0x00000f00; m_gBitMask = 0x000000f0; m_bBitMask = 0x0000000f; m_aBitMask = 0x0000f000; break; } case DdsFileFormat.DDS_FORMAT_R8G8B8: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_fourCC = 0; m_rgbBitCount = 24; m_rBitMask = 0x00ff0000; m_gBitMask = 0x0000ff00; m_bBitMask = 0x000000ff; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_R5G6B5: { m_flags = ( int )PixelFormatFlags.DDS_RGB; m_fourCC = 0; m_rgbBitCount = 16; m_rBitMask = 0x0000f800; m_gBitMask = 0x000007e0; m_bBitMask = 0x0000001f; m_aBitMask = 0x00000000; break; } case DdsFileFormat.DDS_FORMAT_A8L8: { m_flags = (int)PixelFormatFlags.DDS_RGB + (int)PixelFormatFlags.DDS_ALPHAPIXELS; m_fourCC = 0; m_rgbBitCount = 16; m_rBitMask = 0x000000ff; m_gBitMask = 0x00000000; m_bBitMask = 0x00000000; m_aBitMask = 0x0000ff00; break; } default: break; } }