private static void Convert(string pegName)
        {
            if (File.Exists(pegName) == false)
            {
                Console.WriteLine("{0} does not exist.", pegName);
                return;
            }

            string gpegName = Path.ChangeExtension(pegName, ".g_peg_pc");

            if (File.Exists(gpegName) == false)
            {
                Console.WriteLine("{0} does not exist.", gpegName);
                return;
            }

            Stream header = File.OpenRead(pegName);
            Stream data   = File.OpenRead(gpegName);

            FileFormats.PegFile peg = new FileFormats.PegFile();
            peg.Read(header);

            foreach (FileFormats.PegEntry entry in peg.Entries)
            {
                int index = 0;
                foreach (FileFormats.PegFrame frame in entry.Frames)
                {
                    data.Seek(frame.Offset, SeekOrigin.Begin);
                    byte[] compressed = new byte[frame.Size];
                    data.Read(compressed, 0, (int)frame.Size);

                    FileFormats.PegFormat format = (FileFormats.PegFormat)frame.Format;

                    Bitmap bitmap;

                    // DXT
                    if (format == FileFormats.PegFormat.DXT1 ||
                        format == FileFormats.PegFormat.DXT3 ||
                        format == FileFormats.PegFormat.DXT5)
                    {
                        Squish.Flags flags = 0;

                        if (format == FileFormats.PegFormat.DXT1)
                        {
                            flags |= Squish.Flags.DXT1;
                        }
                        else if (format == FileFormats.PegFormat.DXT3)
                        {
                            flags |= Squish.Flags.DXT3;
                        }
                        else if (format == FileFormats.PegFormat.DXT5)
                        {
                            flags |= Squish.Flags.DXT5;
                        }

                        byte[] decompressed = new byte[frame.Width * frame.Height * 4];
                        Squish.Decompress(decompressed, frame.Width, frame.Height, compressed, (int)flags);
                        bitmap = MakeBitmapFromDXT(frame.Width, frame.Height, decompressed, true);
                    }
                    // R5G6B5
                    else if (format == FileFormats.PegFormat.R5G6B5)
                    {
                        bitmap = MakeBitmapFromR5G6B5(frame.Width, frame.Height, compressed);
                    }
                    // A8R8G8B8
                    else if (format == FileFormats.PegFormat.A8R8G8B8)
                    {
                        bitmap = MakeBitmapFromA8R8G8B8(frame.Width, frame.Height, compressed);
                    }
                    else
                    {
                        throw new Exception("unhandled format " + frame.Format.ToString());
                    }

                    string prefix = Path.ChangeExtension(pegName, null) + "   ";

                    if (entry.Frames.Count == 1)
                    {
                        bitmap.Save(prefix + Path.ChangeExtension(entry.Name, ".png"), ImageFormat.Png);
                    }
                    else
                    {
                        string name = Path.GetFileNameWithoutExtension(entry.Name);
                        name += " (frame " + index.ToString() + ")";

                        bitmap.Save(prefix + Path.ChangeExtension(name, ".png"), ImageFormat.Png);
                    }

                    index++;
                }
            }
        }
Beispiel #2
0
        public static void Main(string[] args)
        {
            string decalId  = "12";
            bool   verbose  = false;
            bool   showHelp = false;

            var options = new OptionSet()
            {
                { "i|index=", "set decal index", v => decalId = v },
                { "v|verbose", "be verbose", v => verbose = v != null },
                { "h|help", "show this message and exit", v => showHelp = v != null },
            };

            List <string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 || extras.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_png [output_pak]", GetExecutableName());
                Console.WriteLine("Unpack specified archive.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            int decalIndex;

            if (int.TryParse(decalId, out decalIndex) == false)
            {
                Console.WriteLine($"Could not parse decal index '{decalId}'.");
                return;
            }

            if (decalIndex < 0 || decalIndex > 999)
            {
                Console.WriteLine($"Invalid decal index '{decalIndex}.");
                return;
            }

            var    inputPath = Path.GetFullPath(extras[0]);
            string outputPath;

            if (extras.Count > 1)
            {
                outputPath = extras[1];
            }
            else
            {
                var outputName       = Path.GetFileNameWithoutExtension(inputPath);
                var outputParentPath = Path.GetDirectoryName(inputPath);
                outputPath = Path.Combine(outputParentPath, $"DXM-WindowsNoEditor_Decal_{outputName}_P.pak");
            }

            const Squish.Flags squishFlags = Squish.Flags.DXT5 | Squish.Flags.SourceBGRA;

            int dxtTotalSize = 0;

            for (int mipIndex = 10; mipIndex >= 0; mipIndex--)
            {
                var mipSize = 1 << mipIndex;
                dxtTotalSize += Squish.GetStorageRequirements(mipSize, mipSize, squishFlags);
            }

            if (dxtTotalSize != 1398128)
            {
                throw new InvalidOperationException();
            }

            var dxtBytes = new byte[dxtTotalSize];

            using (var image = Image.FromFile(inputPath))
            {
                if (image.Width != 1024 || image.Height != 1024)
                {
                    Console.WriteLine("[Warning] Original image not 1024x1024, will resize (probably badly).");
                }

                int dxtOffset = 0;
                for (int mipIndex = 10; mipIndex >= 0; mipIndex--)
                {
                    var mipSize = 1 << mipIndex;

                    var rgbaStride = mipSize * 4;
                    var rgbaBytes  = new byte[rgbaStride * mipSize];
                    using (var bitmap = MaybeResize(image, mipSize, mipSize))
                    {
                        var area = new Rectangle(0, 0, mipSize, mipSize);
                        var data = bitmap.LockBits(area, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                        var scan = data.Scan0;
                        for (int y = 0, o = 0; y < mipSize; y++, scan += data.Stride, o += rgbaStride)
                        {
                            Marshal.Copy(scan, rgbaBytes, o, rgbaStride);
                        }
                        bitmap.UnlockBits(data);
                    }

                    var dxtSize = Squish.GetStorageRequirements(mipSize, mipSize, squishFlags);
                    Squish.CompressImage(rgbaBytes, 0, mipSize, mipSize, dxtBytes, dxtOffset, squishFlags);
                    dxtOffset += dxtSize;
                }
            }

            var decalIndexBytes = Encoding.ASCII.GetBytes($"{decalIndex:D3}");

            var filenameBytes = Encoding.UTF8.GetBytes(Path.GetFileNameWithoutExtension(outputPath));
            var filenameHash  = ComputeMD5(filenameBytes, 0, filenameBytes.Length);

            const int pakEntryHeaderSize       = 53;
            const int pakEntryHeaderHashOffset = 28;

            var outputLength = 0;
            var uassetOffset = outputLength;

            outputLength += Resources.UAsset.Length;
            var ubulkHeaderOffset = outputLength;

            outputLength += Resources.UBulkHeader.Length;
            var ubulkDataOffset = outputLength;

            outputLength += dxtBytes.Length;
            var uexpOffset = outputLength;

            outputLength += Resources.UExp.Length;
            var pakIndexOffset = outputLength;

            outputLength += Resources.PakIndex.Length;

            var outputBytes = new byte[outputLength];

            Array.Copy(Resources.UAsset, 0, outputBytes, uassetOffset, Resources.UAsset.Length);
            Array.Copy(Resources.UBulkHeader, 0, outputBytes, ubulkDataOffset, Resources.UBulkHeader.Length);
            Array.Copy(dxtBytes, 0, outputBytes, ubulkDataOffset, dxtBytes.Length);
            Array.Copy(Resources.UExp, 0, outputBytes, uexpOffset, Resources.UExp.Length);
            Array.Copy(Resources.PakIndex, 0, outputBytes, pakIndexOffset, Resources.PakIndex.Length);

            Array.Copy(filenameHash, 0, outputBytes, uassetOffset + pakEntryHeaderSize + 93, filenameHash.Length);
            Array.Copy(decalIndexBytes, 0, outputBytes, uassetOffset + pakEntryHeaderSize + 243, decalIndexBytes.Length);
            Array.Copy(decalIndexBytes, 0, outputBytes, uassetOffset + pakEntryHeaderSize + 349, decalIndexBytes.Length);

            var uassetHash = ComputeSHA1(outputBytes, uassetOffset + pakEntryHeaderSize, Resources.UAsset.Length - pakEntryHeaderSize);
            var ubulkHash  = ComputeSHA1(outputBytes, ubulkDataOffset, dxtBytes.Length);
            var uexpHash   = ComputeSHA1(outputBytes, uexpOffset + pakEntryHeaderSize, Resources.UExp.Length - pakEntryHeaderSize);

            Array.Copy(uassetHash, 0, outputBytes, uassetOffset + pakEntryHeaderHashOffset, uassetHash.Length);
            Array.Copy(ubulkHash, 0, outputBytes, ubulkHeaderOffset + pakEntryHeaderHashOffset, ubulkHash.Length);
            Array.Copy(uexpHash, 0, outputBytes, uexpOffset + pakEntryHeaderHashOffset, uexpHash.Length);

            Array.Copy(decalIndexBytes, 0, outputBytes, pakIndexOffset + 74, decalIndexBytes.Length);
            Array.Copy(uassetHash, 0, outputBytes, pakIndexOffset + 113, uassetHash.Length);
            Array.Copy(decalIndexBytes, 0, outputBytes, pakIndexOffset + 151, decalIndexBytes.Length);
            Array.Copy(ubulkHash, 0, outputBytes, pakIndexOffset + 189, ubulkHash.Length);
            Array.Copy(decalIndexBytes, 0, outputBytes, pakIndexOffset + 227, decalIndexBytes.Length);
            Array.Copy(uexpHash, 0, outputBytes, pakIndexOffset + 264, uexpHash.Length);

            var pakIndexHash = ComputeSHA1(outputBytes, pakIndexOffset, 289);

            Array.Copy(pakIndexHash, 0, outputBytes, pakIndexOffset + 314, pakIndexHash.Length);

            File.WriteAllBytes(outputPath, outputBytes);
        }