/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> /// <remarks> /// Credits to enohka for this code. /// See more at: http://github.com/enohka/moddingSuite /// </remarks> public virtual TgvImage Read(String filePath) { var file = new TgvImage(); byte[] rawDDSData = File.ReadAllBytes(filePath); using (var ms = new MemoryStream(rawDDSData)) { var buffer = new byte[4]; ms.Read(buffer, 0, buffer.Length); if (BitConverter.ToUInt32(buffer, 0) != DDSFormat.MagicHeader) { throw new ArgumentException("Wrong DDS magic"); } buffer = new byte[Marshal.SizeOf(typeof(DDSFormat.Header))]; ms.Read(buffer, 0, buffer.Length); var header = MiscUtilities.ByteArrayToStructure <DDSFormat.Header>(buffer); header.MipMapCount = 1; DDSHelper.ConversionFlags conversionFlags; var format = DDSHelper.GetDXGIFormat(ref header.PixelFormat, out conversionFlags); //read only the main content mipmap uint minMipByteLength = DDSMipMapUilities.GetMinimumMipMapSizeForFormat(header.PixelFormat); uint mipByteLength = (uint)DDSMipMapUilities.GetMipMapBytesCount((int)header.Width, (int)header.Height, format); mipByteLength = Math.Max(minMipByteLength, mipByteLength); buffer = new byte[mipByteLength]; ms.Read(buffer, 0, buffer.Length); var mip = new TgvMipMap(); mip.Content = buffer; mip.Length = mipByteLength; mip.MipSize = header.Width * header.Height; mip.MipWidth = header.Width; mip.MipHeight = header.Height; file.MipMapCount = (ushort)header.MipMapCount; file.MipMaps.Add(mip); file.Height = header.Height; file.ImageHeight = header.Height; file.Width = header.Width; file.ImageWidth = header.Width; file.Format = format; file.PixelFormatString = TgvUtilities.GetTgvFromPixelFormat(format); } return(file); }
/// <summary> /// /// </summary> /// <param name="file"></param> /// <returns></returns> /// <remarks> /// Credits to enohka for this code. /// See more at: http://github.com/enohka/moddingSuite /// </remarks> public virtual byte[] Write(TgvImage file) { using (MemoryStream stream = new MemoryStream()) { file.PixelFormatString = TgvUtilities.GetTgvFromPixelFormat(file.Format); //"DXT5_SRGB" var buffer = BitConverter.GetBytes(VersionMagic); stream.Write(buffer, 0, buffer.Length); buffer = BitConverter.GetBytes(file.IsCompressed ? 1 : 0); stream.Write(buffer, 0, buffer.Length); buffer = BitConverter.GetBytes(file.Width); stream.Write(buffer, 0, buffer.Length); buffer = BitConverter.GetBytes(file.Height); stream.Write(buffer, 0, buffer.Length); buffer = BitConverter.GetBytes(file.Width); stream.Write(buffer, 0, buffer.Length); buffer = BitConverter.GetBytes(file.Height); stream.Write(buffer, 0, buffer.Length); buffer = BitConverter.GetBytes((short)file.MipMapCount); stream.Write(buffer, 0, buffer.Length); var fmtLen = (short)file.PixelFormatString.Length; buffer = BitConverter.GetBytes(fmtLen); stream.Write(buffer, 0, buffer.Length); buffer = Encoding.ASCII.GetBytes(file.PixelFormatString); stream.Write(buffer, 0, buffer.Length); stream.Seek(MathUtilities.RoundToNextDivBy4(fmtLen) - fmtLen, SeekOrigin.Current); stream.Write(file.SourceChecksum, 0, file.SourceChecksum.Length); var mipOffset = (uint)(stream.Position); stream.Seek(8 * file.MipMapCount, SeekOrigin.Current); var sortedMipMaps = file.MipMaps.OrderBy(x => x.MipSize).ToList(); // Create the content and write all MipMaps, // since we compress on this part its the first part where we know the size of a MipMap foreach (var sortedMipMap in sortedMipMaps) { sortedMipMap.Offset = (uint)stream.Position; if (file.IsCompressed) { var zipoMagic = Encoding.ASCII.GetBytes("ZIPO"); stream.Write(zipoMagic, 0, zipoMagic.Length); //buffer = BitConverter.GetBytes(mipImgsizes[sortedMipMaps.IndexOf(sortedMipMap)]); //To Ÿle dzia³a. W orygianlnym pliku bajty s¹ w innej kolejnoœci. Pozatym to zak³ada ze potêg¹ jest indeks, //a w przypadku ma³ej liczby bitmap to nie ma sensu uint mipSize = sortedMipMap.MipSize; //GetMipMapSize(file.Width, file.Height, sortedMipMaps.IndexOf(sortedMipMap), sortedMipMaps.Count); buffer = BitConverter.GetBytes(mipSize); stream.Write(buffer, 0, buffer.Length); ICompressor comp = new ZlibCompressor(); buffer = comp.Compress(sortedMipMap.Content); stream.Write(buffer, 0, buffer.Length); sortedMipMap.Length = (uint)buffer.Length; } else { stream.Write(sortedMipMap.Content, 0, sortedMipMap.Content.Length); sortedMipMap.Length = (uint)sortedMipMap.Content.Length; } //Wygl¹da na to ¿e mipMapy musza mieæ offset wzglêden pocz¹tku pliku podzielny przez 4. //Trzeba dope³niæ do liczby podzielnej przez 4 przed zapisem nastêpnego //To dope³nienie zak³ada ¿e nag³ówek ma d³ugoœæ podzielna przez 4, tak ¿e pierwsza MipMapa nie jest przesuniêta. //Plik Edata wie o tym poszerzeniu rozmiaru, bo odczytuje d³ugoœæ pliku z rozmiaru contentu. bool multiMipMaps = file.MipMaps.Count > 1; bool needSupplementTo4 = (stream.Position % 4) != 0; if (multiMipMaps && needSupplementTo4) { int supplementSize = (int)(MathUtilities.RoundToNextDivBy4(stream.Position) - stream.Position); byte[] supplementBuffer = new byte[supplementSize]; stream.Write(supplementBuffer, 0, supplementBuffer.Length); } } stream.Seek(mipOffset, SeekOrigin.Begin); // Write the offset collection in the header. for (int i = 0; i < file.MipMapCount; i++) { buffer = BitConverter.GetBytes(sortedMipMaps[i].Offset); stream.Write(buffer, 0, buffer.Length); } // Write the size collection into the header. for (int i = 0; i < file.MipMapCount; i++) { buffer = BitConverter.GetBytes(sortedMipMaps[i].Length + 8); //+ 4 magii i + 4 rozmiaru mapy stream.Write(buffer, 0, buffer.Length); } return(stream.ToArray()); } }
public virtual TgvImage Read(String filePath) { var file = new TgvImage(); byte[] rawDDSData = File.ReadAllBytes(filePath); using (var ms = new MemoryStream(rawDDSData)) { var buffer = new byte[4]; ms.Read(buffer, 0, buffer.Length); if (BitConverter.ToUInt32(buffer, 0) != DDSFormat.MagicHeader) { throw new ArgumentException("Wrong DDS magic"); } buffer = new byte[Marshal.SizeOf(typeof(DDSFormat.Header))]; ms.Read(buffer, 0, buffer.Length); var header = MiscUtilities.ByteArrayToStructure <DDSFormat.Header>(buffer); DDSHelper.ConversionFlags conversionFlags; var format = DDSHelper.GetDXGIFormat(ref header.PixelFormat, out conversionFlags); if (header.MipMapCount == 0) { header.MipMapCount = 1; } for (int i = 0; i < header.MipMapCount; i++) { uint mipScale = (uint)Math.Max(1, 2 << (i - 1)); uint mipWidth = Math.Max(1, header.Width / mipScale); uint mipHeight = Math.Max(1, header.Height / mipScale); if (mipWidth < MinMipMapWidth || mipHeight < MinMipMapHeight) { break; } uint minMipByteLength = DDSMipMapUilities.GetMinimumMipMapSizeForFormat(header.PixelFormat); uint mipByteLength = (uint)DDSMipMapUilities.GetMipMapBytesCount((int)mipWidth, (int)mipHeight, format); mipByteLength = Math.Max(minMipByteLength, mipByteLength); buffer = new byte[mipByteLength]; ms.Read(buffer, 0, buffer.Length); var mip = new TgvMipMap(); mip.Content = buffer; mip.Length = mipByteLength; mip.MipSize = mipWidth * mipHeight;//(int)mipSize; //spr. czy to jest równe size czy width * height; mip.MipWidth = mipWidth; mip.MipHeight = mipHeight; file.MipMaps.Add(mip); } file.Height = header.Height; file.ImageHeight = header.Height; file.Width = header.Width; file.ImageWidth = header.Width; file.MipMapCount = (ushort)file.MipMaps.Count; file.Format = format; file.PixelFormatString = TgvUtilities.GetTgvFromPixelFormat(format); } return(file); }