public static void ParseEntries(XmlNode entriesNode, PegFile pegFile) { foreach (XmlNode entryNode in entriesNode.ChildNodes) { switch (entryNode.Name) { case "Entry": PegEntry entry = new PegEntry(); foreach (XmlNode node in entryNode.ChildNodes) { switch (node.Name) { case "Name": entry.Name = node.InnerText; break; case "Frames": ParseFrames(node, entry); break; //default: //throw new Exception(String.Format("Encountered unknown XML element: {0}", node.Name)); } } pegFile.Entries.Add(entry); break; //default: //throw new Exception(String.Format("Encountered unknown XML element: {0}", entryNode.Name)); } } }
public static Bitmap EntryDataToBitmap(PegEntry entry) { if (entry.bitmap_format == PegFormat.PC_DXT1) { var decompressBuffer = Squish.Decompress(entry.RawData, entry.width, entry.height, Squish.Flags.DXT1); return(MakeBitmapFromDXT(entry.width, entry.height, decompressBuffer, true)); } else if (entry.bitmap_format == PegFormat.PC_DXT3) { var decompressBuffer = Squish.Decompress(entry.RawData, entry.width, entry.height, Squish.Flags.DXT3); return(MakeBitmapFromDXT(entry.width, entry.height, decompressBuffer, true)); } else if (entry.bitmap_format == PegFormat.PC_DXT5) { var decompressBuffer = Squish.Decompress(entry.RawData, entry.width, entry.height, Squish.Flags.DXT5); return(MakeBitmapFromDXT(entry.width, entry.height, decompressBuffer, true)); } else { throw new Exception($"Unsupported PEG data format detected! {entry.bitmap_format.ToString()} is not yet supported."); } }
public static void ParseFrames(XmlNode framesNode, PegEntry entry) { foreach (XmlNode frameNode in framesNode.ChildNodes) { switch (frameNode.Name) { case "Frame": PegFrame frame = new PegFrame(); foreach (XmlNode node in frameNode.ChildNodes) { switch (node.Name) { case "Width": ushort.TryParse(node.InnerText, out frame.Width); break; case "Height": ushort.TryParse(node.InnerText, out frame.Height); break; case "Format": PegFormat format = (PegFormat)Enum.Parse(typeof(PegFormat), node.InnerText, true); frame.Format = (ushort)format; break; case "Unknown0A": ushort.TryParse(node.InnerText, out frame.Unknown0A); break; case "Unknown0C": uint.TryParse(node.InnerText, out frame.Unknown0C); break; case "Unknown12": uint.TryParse(node.InnerText, out frame.Unknown12); break; case "Unknown16": uint.TryParse(node.InnerText, out frame.Unknown16); break; case "UnknownFlags1A": ushort.TryParse(node.InnerText, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out frame.UnknownFlags1A); break; case "Size": uint.TryParse(node.InnerText, out frame.Size); break; case "Unknown20": uint.TryParse(node.InnerText, out frame.Unknown20); break; case "Unknown24": uint.TryParse(node.InnerText, out frame.Unknown24); break; case "Unknown28": uint.TryParse(node.InnerText, out frame.Unknown28); break; case "Unknown2C": uint.TryParse(node.InnerText, out frame.Unknown2C); break; //default: //throw new Exception(String.Format("Encountered unknown XML element: {0}", node.Name)); } } entry.Frames.Add(frame); break; default: throw new Exception(String.Format("Encountered unknown XML element: {0}", frameNode.Name)); } } }
static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse <Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); #if DEBUG Console.ReadLine(); #endif return; } if (options.Output == null) { options.Output = "output"; } if (!Directory.Exists(options.Output)) { Directory.CreateDirectory(options.Output); } FontFile font = null; using (Stream s = File.OpenRead(options.Source)) { font = new FontFile(s); } Dictionary <char, char> charMap = new Dictionary <char, char>(); using (Stream s = File.OpenRead(options.Charmap)) { charMap = LanguageUtility.GetDecodeCharMapFromStream(s); } string indicatedPegPath = Path.Combine(Path.GetDirectoryName(options.Source), font.Header.BitmapName); string[] pegExtensions = new string[] { ".cpeg_pc", ".cvbm_pc" }; string[] gpegExtensions = new string[] { ".gpeg_pc", ".gvbm_pc" }; bool foundPeg = false; string pegPath = null; string gpegPath = null; for (int i = 0; i < pegExtensions.Length; i++) { string pegExtension = pegExtensions[i]; string gpegExtension = gpegExtensions[i]; string candidatePath = Path.ChangeExtension(indicatedPegPath, pegExtension); if (File.Exists(candidatePath)) { foundPeg = true; pegPath = candidatePath; gpegPath = Path.ChangeExtension(pegPath, gpegExtension); break; } } if (!foundPeg) { Console.WriteLine("Couldn't find {0}! Extension may be \".cpeg_pc\" or \".cvbm_pc\".", indicatedPegPath); return; } Bitmap fontBitmap = null; using (Stream pegStream = File.OpenRead(pegPath)) { PegFile peg = new PegFile(pegStream); PegEntry entry = null; foreach (PegEntry e in peg.Entries) { if (e.Filename == font.Header.BitmapName) { entry = e; break; } } if (entry == null) { Console.WriteLine("Couldn't find bitmap {0} in font peg!", font.Header.BitmapName); return; } byte[] bitmapData = null; using (Stream gpegStream = File.OpenRead(gpegPath)) { bitmapData = entry.GetData(gpegStream); } byte[] uncompressed = null; switch (entry.Data.BitmapFormat) { case PegBitmapFormat.D3DFMT_DXT3: uncompressed = ManagedSquish.Squish.DecompressImage(bitmapData, entry.Data.Width, entry.Data.Height, ManagedSquish.SquishFlags.Dxt3); break; case PegBitmapFormat.D3DFMT_DXT5: uncompressed = ManagedSquish.Squish.DecompressImage(bitmapData, entry.Data.Width, entry.Data.Height, ManagedSquish.SquishFlags.Dxt5); break; default: throw new Exception(); } fontBitmap = new Bitmap(entry.Data.Width, entry.Data.Height, PixelFormat.Format32bppArgb); BitmapData data = fontBitmap.LockBits(new Rectangle(0, 0, fontBitmap.Width, fontBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); Marshal.Copy(uncompressed, 0, data.Scan0, uncompressed.Length); fontBitmap.UnlockBits(data); } using (StreamWriter sw = new StreamWriter(Path.Combine(options.Output, "out.txt"))) { for (int i = 0; i < font.Characters.Count; i++) { FontCharacter c = font.Characters[i]; int u = font.U[i]; int v = font.V[i]; int charValue = font.Header.FirstAscii + i; if (c.ByteWidth == 0) { continue; } char actualChar = '\0'; char rawChar = (char)charValue; if (charMap.ContainsKey(rawChar)) { actualChar = charMap[rawChar]; sw.WriteLine("{0} \"{1}\"", charValue, actualChar); } else { sw.WriteLine("{0} \"\"", charValue); } using (Bitmap bm = new Bitmap(c.ByteWidth, font.Header.RenderHeight)) { using (Graphics g = Graphics.FromImage(bm)) { g.Clear(Color.Black); g.DrawImage(fontBitmap, 0, 0, new Rectangle(u, v, c.ByteWidth, font.Header.RenderHeight), GraphicsUnit.Pixel); g.Flush(); } string bmName = String.Format("{0}.png", charValue); string bmPath = Path.Combine(options.Output, bmName); bm.Save(bmPath, ImageFormat.Png); } } } }
public bool Init(CacheFile target, int selectedIndex, string replacementFilePath) { //Todo: Make some reuseable helper functions to shorten this up. Ex: //Todo: - Copy file, parent, asm, and cpu/gpu sister file between caches //Todo: - Repack parent with edited file //Todo: - Update asm file with new values PegEntry selectedEntry = target.PegData.Entries[selectedIndex]; PegName = target.PegData.cpuFileName; SubTextureName = selectedEntry.Name; //Set TrackedByAsm and find asm name CacheFile asmFile = null; AsmContainer targetContainer = null; AsmPrimitive targetPrimitive = null; if (target.Parent.PackfileData.ContainsAsmFiles) { TrackedByAsm = true; foreach (var asm in target.Parent.PackfileData.AsmFiles) { foreach (var container in asm.Containers) { foreach (var primitive in container.Primitives) { if (primitive.Name != target.Filename) { continue; } AsmName = primitive.Name; targetContainer = container; targetPrimitive = primitive; } } } if (AsmName == null || targetContainer == null || targetPrimitive == null) { return(false); } } //Copy edited files to project cache if (!ProjectManager.CopyFileToProjectCache(target.PegData.cpuFileName, target.Parent, out CacheFile cpuFile)) { return(false); } if (!ProjectManager.CopyFileToProjectCache(target.PegData.gpuFileName, target.Parent, out CacheFile gpuFile)) { return(false); } if (TrackedByAsm && !ProjectManager.CopyFileToProjectCache(AsmName, target.Parent, out asmFile) || asmFile == null) { return(false); } //Update entry data selectedEntry = cpuFile.PegData.Entries[selectedIndex]; selectedEntry.Bitmap = new Bitmap(replacementFilePath); selectedEntry.Edited = true; selectedEntry.RawData = Utility.Helpers.ImageHelpers.ConvertBitmapToByteArray(selectedEntry.Bitmap); selectedEntry.width = (ushort)selectedEntry.Bitmap.Width; selectedEntry.height = (ushort)selectedEntry.Bitmap.Height; selectedEntry.source_height = (ushort)selectedEntry.Bitmap.Height; //source_width sometimes equals width and sometimes equals 36352. This is a quick hack for now until that behavior is understood. //Not properly setting this causes the game to improperly scale the texture selectedEntry.source_width = selectedEntry.source_width == selectedEntry.width ? (ushort)selectedEntry.Bitmap.Width : (ushort)36352; cpuFile.PegData.Write(cpuFile.FilePath, gpuFile.FilePath); //Update asm data if applicable if (TrackedByAsm) { var cpuFileInfo = new FileInfo(cpuFile.FilePath); var gpuFileInfo = new FileInfo(gpuFile.FilePath); int sizeDifference = (int)cpuFileInfo.Length - (int)targetPrimitive.HeaderSize; sizeDifference += (int)gpuFileInfo.Length - (int)targetPrimitive.DataSize; targetPrimitive.HeaderSize = (uint)cpuFileInfo.Length; targetPrimitive.DataSize = (uint)gpuFileInfo.Length; //Todo: Finish packfile writing code //Todo: Pack str2 and update CompressedSize var parentPackfile = cpuFile.Parent.PackfileData; parentPackfile.WriteToBinary(Path.GetDirectoryName(asmFile.FilePath), asmFile.Parent.FilePath, true, true, true); if (!cpuFile.Parent.PackfileData.TryGetSubfileEntry(cpuFile.Filename, out var cpuFileEntry)) { return(false); } if (!cpuFile.Parent.PackfileData.TryGetSubfileEntry(gpuFile.Filename, out var gpuFileEntry)) { return(false); } targetContainer.CompressedSize = parentPackfile.Header.CompressedDataSize; targetContainer.DataOffset = parentPackfile.DataStartOffset; targetPrimitive.HeaderSize = cpuFileEntry.DataSize; targetPrimitive.DataSize = gpuFileEntry.DataSize; //Todo: Update primitive sizes //Todo: Update DataOffset //Todo: Make sure to update other primitives in the same str2 if their offsets/values have changed asmFile.AsmData.WriteToBinary(); } //Todo: Generate modinfo.xml data for this UpdateDescription(); return(true); }