public static byte[] Compress(byte[] decompressed, uint width, uint height, PegFormat format) { uint compressedSize = 0; Flags flags = 0; if (format == PegFormat.DXT1) { compressedSize = (uint)(decompressed.Length / 8); flags |= Flags.DXT1; } else if (format == PegFormat.DXT3) { compressedSize = (uint)(decompressed.Length / 4); flags |= Flags.DXT3; } else if (format == PegFormat.DXT5) { compressedSize = (uint)(decompressed.Length / 4); flags |= Flags.DXT5; } flags |= Flags.ColourMetricUniform | Flags.ColourIterativeClusterFit; byte[] compressed = new byte[compressedSize]; NativeMethods.CompressImage(decompressed, width, height, compressed, (int)flags); return(compressed); }
public static Bitmap RawDataToBitmap(byte[] rawData, PegFormat format, ushort width, ushort height) { if (format == PegFormat.PC_DXT1) { var decompressBuffer = Squish.Decompress(rawData, width, height, Squish.Flags.DXT1); return(MakeBitmapFromDXT(width, height, decompressBuffer, true)); } else if (format == PegFormat.PC_DXT3) { var decompressBuffer = Squish.Decompress(rawData, width, height, Squish.Flags.DXT3); return(MakeBitmapFromDXT(width, height, decompressBuffer, true)); } else if (format == PegFormat.PC_DXT5) { var decompressBuffer = Squish.Decompress(rawData, width, height, Squish.Flags.DXT5); return(MakeBitmapFromDXT(width, height, decompressBuffer, true)); } else if (format == PegFormat.PC_8888) { return(MakeBitmapFromPc8888(width, height, rawData)); } else { throw new Exception($"Unsupported PEG data format detected! {format.ToString()} is not yet supported."); } }
public static byte[] ByteSwap(byte[] data, PegFormat format) { byte[] output = new byte[data.Length]; switch (format) { case PegFormat.DXT1: for (int i = 0; i < data.Length; i += 8) { output[i] = data[i + 1]; output[i + 1] = data[i]; output[i + 2] = data[i + 3]; output[i + 3] = data[i + 2]; output[i + 4] = data[i + 4]; output[i + 5] = data[i + 5]; output[i + 6] = data[i + 6]; output[i + 7] = data[i + 7]; } break; case PegFormat.A8R8G8B8: for (int i = 0; i < data.Length; i += 4) { output[i] = data[i + 3]; output[i + 1] = data[i + 2]; output[i + 2] = data[i + 1]; output[i + 3] = data[i]; } break; default: throw new Exception("Unhandled format: " + format.ToString()); } return(output); }
public void Read(BinaryReader header) { data = header.ReadUInt32(); width = header.ReadUInt16(); height = header.ReadUInt16(); bitmap_format = (PegFormat)header.ReadUInt16(); source_width = header.ReadUInt16(); anim_tiles_width = header.ReadUInt16(); anim_tiles_height = header.ReadUInt16(); num_frames = header.ReadUInt16(); flags = header.ReadUInt16(); filename = header.ReadUInt32(); source_height = header.ReadUInt16(); fps = header.ReadByte(); mip_levels = header.ReadByte(); frame_size = header.ReadUInt32(); next = header.ReadUInt32(); previous = header.ReadUInt32(); cache0 = header.ReadUInt32(); cache1 = header.ReadUInt32(); }
public static byte[] Decompress(byte[] compressed, uint width, uint height, PegFormat format) { byte[] decompressed = new byte[width * height * 4]; Flags flags = 0; if (format == PegFormat.DXT1) { flags |= Flags.DXT1; } else if (format == PegFormat.DXT3) { flags |= Flags.DXT3; } else if (format == PegFormat.DXT5) { flags |= Flags.DXT5; } NativeMethods.DecompressImage(decompressed, width, height, compressed, (int)flags); return(decompressed); }
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)); } } }
public static void Repack(string descFilePath) { Console.WriteLine("Repacking {0}:", descFilePath); if (!File.Exists(descFilePath)) { Console.WriteLine("peg_desc file does not exist: {0}", descFilePath); return; } string extension = Path.GetExtension(descFilePath); if (!(extension == ".peg_desc")) { Console.WriteLine("File is not a peg_desc file: {0}", descFilePath); return; } string descFolder = Path.GetDirectoryName(descFilePath); Console.Write("Loading Peg Description... "); PegFile pegFile = XmlParser.ParseFile(descFilePath); if (pegFile == null) { Console.WriteLine("An error occurred while loading the peg_desc file."); return; } Console.WriteLine("done."); Console.WriteLine("Loading texture data, performing colour space conversions and compressing data:"); Dictionary <PegFrame, byte[]> rawFrameData = new Dictionary <PegFrame, byte[]>(); uint totalSize = 0; ushort totalFrames = 0; foreach (PegEntry entry in pegFile.Entries) { for (int i = 0; i < entry.Frames.Count; i++) { PegFrame frame = entry.Frames[i]; Console.Write(" - {0} (frame {1})... ", entry.Name, i); frame.Frames = (ushort)((i == 0) ? entry.Frames.Count : 1); frame.Offset = totalSize; PegFormat format = (PegFormat)frame.Format; byte[] rawData = null; string rawFilePath = Path.Combine(descFolder, String.Format("{0}_{1}.raw", entry.Name, i)); string filePath = Path.Combine(descFolder, String.Format("{0}_{1}.png", entry.Name, i)); if (File.Exists(rawFilePath)) { Console.Write("loading from {0}... ", rawFilePath); FileStream rawFileStream = new FileStream(rawFilePath, FileMode.Open, FileAccess.Read, FileShare.None); rawData = new byte[rawFileStream.Length]; rawFileStream.Read(rawData, 0, rawData.Length); rawFileStream.Close(); Console.WriteLine("done."); } else { Console.Write("importing from {0}... ", filePath); if (!File.Exists(filePath)) { Console.WriteLine("Unable to find file: {0}", filePath); Console.WriteLine("Make sure all your texture files are in the correct location and correctly named."); return; } Bitmap srcBitmap = new Bitmap(filePath); switch (format) { case PegFormat.DXT1: case PegFormat.DXT3: case PegFormat.DXT5: rawData = GetRawA8R8G8B8DataFromBitmap(srcBitmap); ImageFormats.SwapRedAndBlue((uint)srcBitmap.Width, (uint)srcBitmap.Height, ref rawData); rawData = ImageFormats.Compress(rawData, (uint)srcBitmap.Width, (uint)srcBitmap.Height, format); break; case PegFormat.A8R8G8B8: rawData = GetRawA8R8G8B8DataFromBitmap(srcBitmap); break; case PegFormat.R5G6B5: Bitmap outBitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format16bppRgb565); srcBitmap.SetResolution(96, 96); Graphics g = Graphics.FromImage(outBitmap); g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.DrawImage(srcBitmap, 0, 0, srcBitmap.Width, srcBitmap.Height); g.Dispose(); Rectangle lockArea = new Rectangle(0, 0, outBitmap.Width, outBitmap.Height); BitmapData bitmapData = outBitmap.LockBits(lockArea, ImageLockMode.ReadOnly, outBitmap.PixelFormat); rawData = new byte[srcBitmap.Width * srcBitmap.Height * 2]; Marshal.Copy(bitmapData.Scan0, rawData, 0, rawData.Length); outBitmap.UnlockBits(bitmapData); outBitmap.Dispose(); break; default: throw new Exception("Unhandled format: " + format.ToString()); } srcBitmap.Dispose(); Console.WriteLine("done."); } frame.Size = (uint)rawData.Length; totalSize += frame.Size; if (totalSize % 16 != 0) { uint difference = (uint)(Math.Ceiling((float)totalSize / 16f) * 16) - totalSize; totalSize += difference; } totalFrames++; entry.Frames[i] = frame; rawFrameData.Add(frame, rawData); } } pegFile.DataFileSize = totalSize; Console.WriteLine("Finished loading texture data."); Console.Write("Writing peg_pc and g_peg_pc files..."); string pegFilePath = Path.ChangeExtension(descFilePath, "peg_pc"); string pegDataFilePath = Path.ChangeExtension(descFilePath, "g_peg_pc"); FileStream pegFileStream = new FileStream(pegFilePath, FileMode.Create, FileAccess.Write, FileShare.None); FileStream pegDataFileStream = new FileStream(pegDataFilePath, FileMode.Create, FileAccess.Write, FileShare.None); pegFileStream.WriteU32(0x564B4547); // GEKV pegFileStream.WriteU16(10); // Version pegFileStream.WriteU16(pegFile.Unknown06); pegFileStream.WriteU32(pegFile.FileSize); // Length - we come back and fill this in later pegFileStream.WriteU32(pegFile.DataFileSize); pegFileStream.WriteU16((ushort)pegFile.Entries.Count); pegFileStream.WriteU16(pegFile.Unknown12); pegFileStream.WriteU16(totalFrames); pegFileStream.WriteU16(pegFile.Unknown16); // Write entries pegFileStream.Seek(0x18, SeekOrigin.Begin); foreach (PegEntry entry in pegFile.Entries) { for (int i = 0; i < entry.Frames.Count; i++) { PegFrame frame = entry.Frames[i]; byte[] frameData = StructureToByteArray(frame); pegFileStream.Write(frameData, 0, frameData.Length); } } // Write names pegFileStream.Seek(0x18 + (0x30 * totalFrames), SeekOrigin.Begin); foreach (PegEntry entry in pegFile.Entries) { pegFileStream.WriteASCIIZ(entry.Name); } pegFileStream.Seek(0x08, SeekOrigin.Begin); pegFileStream.WriteU32((uint)pegFileStream.Length); pegFileStream.Flush(); pegFileStream.Close(); pegDataFileStream.SetLength(pegFile.DataFileSize); foreach (PegEntry entry in pegFile.Entries) { foreach (PegFrame frame in entry.Frames) { pegDataFileStream.Seek(frame.Offset, SeekOrigin.Begin); pegDataFileStream.Write(rawFrameData[frame], 0, (int)frame.Size); } } pegDataFileStream.Flush(); pegDataFileStream.Close(); Console.WriteLine("done."); Console.WriteLine(); Console.WriteLine("Finished repacking."); }
public static void UnpackImages(PegFile pegFile, string path, Stream pegDataFileStream) { foreach (PegEntry entry in pegFile.Entries) { Console.WriteLine("Extracting {0} ({1} frame{2}):", entry.Name, entry.Frames.Count, (entry.Frames.Count == 1 ? "" : "s")); for (int i = 0; i < entry.Frames.Count; i++) { string filePath = Path.Combine(path, String.Format("{0}_{1}.png", entry.Name, i)); string rawFilePath = Path.Combine(path, String.Format("{0}_{1}.raw", entry.Name, i)); Console.Write(" - Extracting {0}... ", filePath); PegFrame frame = entry.Frames[i]; pegDataFileStream.Seek(frame.Offset, SeekOrigin.Begin); byte[] rawData = new byte[frame.Size]; pegDataFileStream.Read(rawData, 0, (int)frame.Size); PegFormat format = (PegFormat)frame.Format; FileStream rawFileStream = new FileStream(rawFilePath, FileMode.Create, FileAccess.Write, FileShare.None); rawFileStream.Write(rawData, 0, rawData.Length); rawFileStream.Flush(); rawFileStream.Close(); Bitmap bitmap = null; switch (format) { case PegFormat.A8R8G8B8: if (pegFile.BigEndian) { rawData = ImageFormats.ByteSwap(rawData, format); } bitmap = ImageFormats.MakeBitmapFromA8R8G8B8(frame.Width, frame.Height, rawData); break; case PegFormat.R5G6B5: if (pegFile.BigEndian) { rawData = ImageFormats.ByteSwap(rawData, format); } bitmap = ImageFormats.MakeBitmapFromR5G6B5(frame.Width, frame.Height, rawData); break; case PegFormat.DXT1: if (pegFile.BigEndian) { rawData = ImageFormats.ByteSwap(rawData, format); } byte[] decompressedDXT1 = ImageFormats.Decompress(rawData, frame.Width, frame.Height, format); bitmap = ImageFormats.MakeBitmapFromDXT(frame.Width, frame.Height, decompressedDXT1, false); break; case PegFormat.DXT3: case PegFormat.DXT5: byte[] decompressed = ImageFormats.Decompress(rawData, frame.Width, frame.Height, format); bitmap = ImageFormats.MakeBitmapFromDXT(frame.Width, frame.Height, decompressed, true); break; default: throw new Exception("Unhandled format: " + format.ToString()); } bitmap.Save(filePath, ImageFormat.Png); bitmap.Dispose(); Console.WriteLine("done."); } } }
public static void WritePegDescription(PegFile pegFile, string pegDescFilePath) { XmlTextWriter writer = new XmlTextWriter(pegDescFilePath, Encoding.UTF8); writer.Formatting = Formatting.Indented; writer.IndentChar = '\t'; writer.Indentation = 1; writer.WriteStartDocument(); writer.WriteStartElement("PegDescription"); // Header data writer.WriteElementString("BigEndian", pegFile.BigEndian.ToString()); writer.WriteElementString("Magic", "GEKV"); writer.WriteElementString("Version", "10"); writer.WriteElementString("Unknown06", pegFile.Unknown06.ToString()); writer.WriteElementString("FileSize", pegFile.FileSize.ToString()); writer.WriteElementString("DataFileSize", pegFile.DataFileSize.ToString()); writer.WriteElementString("EntryCount", pegFile.Entries.Count.ToString()); writer.WriteElementString("Unknown12", pegFile.Unknown12.ToString()); int frameCount = 0; foreach (PegEntry entry in pegFile.Entries) { frameCount += entry.Frames.Count; } writer.WriteElementString("FrameCount", frameCount.ToString()); writer.WriteElementString("Unknown16", pegFile.Unknown16.ToString()); writer.WriteStartElement("Entries"); foreach (PegEntry entry in pegFile.Entries) { writer.WriteStartElement("Entry"); writer.WriteElementString("Name", entry.Name); writer.WriteStartElement("Frames"); foreach (PegFrame frame in entry.Frames) { writer.WriteStartElement("Frame"); writer.WriteElementString("Offset", frame.Offset.ToString()); writer.WriteElementString("Width", frame.Width.ToString()); writer.WriteElementString("Height", frame.Height.ToString()); PegFormat frameFormat = (PegFormat)frame.Format; writer.WriteElementString("Format", frameFormat.ToString()); writer.WriteElementString("Unknown0A", frame.Unknown0A.ToString()); writer.WriteElementString("Unknown0C", frame.Unknown0C.ToString()); writer.WriteElementString("Frames", frame.Frames.ToString()); writer.WriteElementString("Unknown12", frame.Unknown12.ToString()); writer.WriteElementString("Unknown16", frame.Unknown16.ToString()); writer.WriteElementString("UnknownFlags1A", frame.UnknownFlags1A.ToString("X4")); writer.WriteElementString("Size", frame.Size.ToString()); writer.WriteElementString("Unknown20", frame.Unknown20.ToString()); writer.WriteElementString("Unknown24", frame.Unknown24.ToString()); writer.WriteElementString("Unknown28", frame.Unknown28.ToString()); writer.WriteElementString("Unknown2C", frame.Unknown2C.ToString()); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndDocument(); writer.Close(); }