protected override void ExecuteCommandsLogic(CmdsExecutionData data) { var contentFile = data.ContainerFile.GetContentFileByPath(data.ContentPath); if (contentFile.FileType != ContentFileType.Image) { throw new CmdExecutionFailedException( String.Format("Invalid targetContentPath: \"{0}\". It doesn't target an image content file.", data.ContentPath), DefaultExecutionErrorMsg); } TgvImage oldTgv = BytesToTgv(contentFile.Content); TgvImage newtgv = DDSFileToTgv(data.ModificationSourcePath, !Command.UseMipMaps); ImageComposerService.ReplaceImageTile( oldTgv, newtgv, (uint)Command.TileSize.Value, (uint)Command.Column.Value, (uint)Command.Row.Value); var newContet = TgvToBytes(oldTgv, !Command.UseMipMaps); contentFile.LoadCustomContent(newContet); }
protected TgvImage BytesToTgv(byte[] rawTgv, bool readMipMaps = true) { ITgvBinReader rawReader = new TgvBinReader(); TgvImage oldTgv = rawReader.Read(rawTgv, readMipMaps); return(oldTgv); }
protected override void ExecuteCommandsLogic(CmdsExecutionData data) { var contentFile = data.ContainerFile.GetContentFileByPath(data.ContentPath); //To nie będzie potrzebne tutaj jeśli nie bedzie trzeba ładować i wykorzystywać starego obrazka. if (contentFile.FileType != ContentFileType.Image) { throw new CmdExecutionFailedException( String.Format("Invalid targetContentPath: \"{0}\". It doesn't target an image content file.", data.ContentPath), DefaultExecutionErrorMsg); } //Ładowanie starego obrazka nie będzie potrzebne jeśli bedzie pewnośc ze recznie wygenerowana checkusma jest ok. //Ale co z info o kompresji? Trudno żeby użytkownik je znał poprawnie... TgvImage oldTgv = BytesToTgv(contentFile.Content, false); TgvImage newtgv = DDSFileToTgv(data.ModificationSourcePath, !Command.UseMipMaps); //newtgv.SourceChecksum = newtgv.ComputeContentChecksum(); //newtgv.IsCompressed = Command.UseCompression; newtgv.SourceChecksum = oldTgv.SourceChecksum; newtgv.IsCompressed = oldTgv.IsCompressed; var newContent = TgvToBytes(newtgv, !Command.UseMipMaps); contentFile.LoadCustomContent(newContent); }
protected TgvImage BytesToTgv(byte[] rawTgv) { ITgvBinReader rawReader = new TgvBinReader(); TgvImage oldTgv = rawReader.Read(rawTgv); return(oldTgv); }
/// <summary> /// /// </summary> /// <param name="destination"></param> /// <param name="source"></param> /// <param name="tileSize"></param> /// <param name="column"></param> /// <param name="row"></param> public void ReplaceImageTile(TgvImage destination, TgvImage source, uint tileSize, uint column, uint row) { uint xPos = tileSize * column; uint yPos = tileSize * row; ReplaceImagePart(destination, source, xPos, yPos); }
protected byte[] TgvToBytes(TgvImage tgv, bool discardMipMaps = true) { ITgvBinWriter tgvRawWriter = discardMipMaps ? new TgvBinNoMipMapsWriter() : new TgvBinWriter(); var bytes = tgvRawWriter.Write(tgv); return(bytes); }
protected TgvImage DDSFileToTgv(String sourceFullPath, bool discardMipMaps = true) { ITgvFileReader tgvReader = discardMipMaps ? (ITgvFileReader)(new TgvDDSMoMipMapsReader()) : (ITgvFileReader)(new TgvDDSReader()); TgvImage newtgv = tgvReader.Read(sourceFullPath); return(newtgv); }
/// <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> public override byte[] Write(TgvImage file) { TgvImage noMipMapsFile = new TgvImage(); noMipMapsFile.PixelFormatString = file.PixelFormatString; noMipMapsFile.Format = file.Format; noMipMapsFile.Height = file.Height; noMipMapsFile.Width = file.Width; noMipMapsFile.ImageHeight = file.ImageHeight; noMipMapsFile.ImageWidth = file.ImageWidth; noMipMapsFile.IsCompressed = file.IsCompressed; noMipMapsFile.SourceChecksum = file.SourceChecksum; noMipMapsFile.Version = file.Version; noMipMapsFile.MipMaps.Add(file.MipMaps.OrderBy(x => x.Length).Last()); noMipMapsFile.MipMapCount = 1; return(base.Write(noMipMapsFile)); }
protected override void ExecuteCommandsLogic(CmdsExecutionData data) { if (!data.ContainerFile.ContainsContentFileWithPath(data.ContentPath)) { TgvImage image = DDSFileToTgv(data.ModificationSourcePath, !Command.UseMipMaps); //Trzeba mieć na to oko, czy nie powoduje problemów, bo przy replace była używana checksuma starego obrazka. image.SourceChecksum = !String.IsNullOrEmpty(Command.Checksum) ? MiscUtilities.HexByteStringToByteArray(Command.Checksum) : image.ComputeContentChecksum(); image.IsCompressed = Command.UseCompression; var newContentFile = new EdataContentFile(); newContentFile.Path = data.ContentPath; newContentFile.LoadCustomContent(TgvToBytes(image, !Command.UseMipMaps)); data.ContainerFile.AddContentFile(newContentFile); } else if (Command.OverwriteIfExist) { var contentFile = data.ContainerFile.GetContentFileByPath(data.ContentPath); //To nie będzie potrzebne tutaj jeśli nie bedzie trzeba ładować i wykorzystywać starego obrazka. if (contentFile.FileType != ContentFileType.Image) { throw new CmdExecutionFailedException( String.Format("Invalid targetContentPath: \"{0}\". It doesn't target an image content file.", data.ContentPath), DefaultExecutionErrorMsg); } //Ładowanie starego obrazka nie będzie potrzebne jeśli bedzie pewnośc ze recznie wygenerowana checkusma jest ok. //Ok, tu kiedyś było odczytywanie starych danych z starego obrazka, teraz checksuma jest generowana na nowo, //żeby uniknac konieczności ładowania tych starych danych, bo nie sa potrzeben przy dodawaniu, a tutaj były by potrzebne //i trudno to rozwiązać przy założeniu ze dane są ładowane na zewnątrz. //TgvImage oldTgv = BytesToTgv(contentFile.Content); TgvImage image = DDSFileToTgv(data.ModificationSourcePath, !Command.UseMipMaps); image.SourceChecksum = !String.IsNullOrEmpty(Command.Checksum) ? MiscUtilities.HexByteStringToByteArray(Command.Checksum) : image.ComputeContentChecksum(); image.IsCompressed = Command.UseCompression; contentFile.LoadCustomContent(TgvToBytes(image, !Command.UseMipMaps)); } }
/// <summary> /// /// </summary> /// <param name="target"></param> /// <param name="source"></param> /// <param name="xPos"></param> /// <param name="yPos"></param> public void ReplaceImagePart(TgvImage target, TgvImage source, uint xPos, uint yPos) { //Jeśli chodzi o podmienianie częśći obrazka w mipMapach, warunkiem było by że użytkownik zapewnia obrazek źródłowy posiadający mipMapy //W takiej sytuacji trzeba było by obliczać dla którego nr mipmapy obrazka z siatką (lods orygianlny) możliwa była by podmiania z wykorzystaniem //mipmap obrazka źródłowego od użytkownika... if (target.MipMaps.Count == 0 || source.MipMaps.Count == 0) { return; } if (xPos >= target.Width || xPos < 0 || yPos >= target.Height || yPos < 0) { return; } var sortedSourceMips = source.MipMaps.OrderByDescending(x => x.MipSize).ToArray(); var sortedTargettMips = target.MipMaps.OrderByDescending(x => x.MipSize).ToArray(); for (int i = 0; (i < sortedSourceMips.Length) && (i < sortedTargettMips.Length); ++i) { var sourceMip = sortedSourceMips[i]; var targetMip = sortedTargettMips[i]; //1. Przeskalować pozycje umieszczenia //2. Spr czy pozycje umieszczenia są poprawne //3. ocenić kiedy nie można / staję sie niebezpieczne dalsze przepisywnia mipmap przy jednoczesnym znikomym rezultacie. uint mipScale = (uint)Math.Max(1, 2 << (i - 1));//Przenieśc to do jakiego utilies uint targetMipXPos = xPos / mipScale; uint targetMipYPos = yPos / mipScale; if (targetMipXPos >= 0 && targetMipXPos < targetMip.MipWidth && targetMipYPos >= 0 && targetMipYPos < targetMip.MipHeight) { ReplaceMipMapPart(targetMip, sourceMip, targetMipXPos, targetMipYPos); } } }
/// <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); }
/// <summary> /// /// </summary> /// <param name="rawTgvData"></param> /// <returns></returns> /// <remarks> /// Credits to enohka for this code. /// See more at: http://github.com/enohka/moddingSuite /// </remarks> public virtual TgvImage Read(byte[] rawTgvData, bool loadMipMaps = true) { var tgv = new TgvImage(); using (var ms = new MemoryStream(rawTgvData)) { var buffer = new byte[4]; ms.Read(buffer, 0, buffer.Length); tgv.Version = BitConverter.ToUInt32(buffer, 0); ms.Read(buffer, 0, buffer.Length); tgv.IsCompressed = BitConverter.ToInt32(buffer, 0) > 0; ms.Read(buffer, 0, buffer.Length); tgv.Width = BitConverter.ToUInt32(buffer, 0); ms.Read(buffer, 0, buffer.Length); tgv.Height = BitConverter.ToUInt32(buffer, 0); ms.Read(buffer, 0, buffer.Length); tgv.ImageHeight = BitConverter.ToUInt32(buffer, 0); ms.Read(buffer, 0, buffer.Length); tgv.ImageWidth = BitConverter.ToUInt32(buffer, 0); buffer = new byte[2]; ms.Read(buffer, 0, buffer.Length); tgv.MipMapCount = BitConverter.ToUInt16(buffer, 0); ms.Read(buffer, 0, buffer.Length); ushort pixelFormatLen = BitConverter.ToUInt16(buffer, 0); buffer = new byte[pixelFormatLen]; ms.Read(buffer, 0, buffer.Length); tgv.PixelFormatString = Encoding.ASCII.GetString(buffer); ms.Seek(MathUtilities.RoundToNextDivBy4(pixelFormatLen) - pixelFormatLen, SeekOrigin.Current); buffer = new byte[16]; ms.Read(buffer, 0, buffer.Length); tgv.SourceChecksum = (byte[])buffer.Clone(); //Read MipMaps var mipMaps = CreateEmptyMipMaps(tgv.MipMapCount); ReadMipMapsOffsets(ms, mipMaps); ReadMipMapsLengths(ms, mipMaps); if (loadMipMaps) { ReadMipMapsContent(ms, mipMaps, tgv.IsCompressed); } SetMipMapsDimensions(mipMaps, tgv.Width, tgv.Height); tgv.MipMaps = mipMaps; } tgv.Format = TgvUtilities.GetPixelFormatFromTgv(tgv.PixelFormatString); return(tgv); }