home *** CD-ROM | disk | FTP | other *** search
- // a greatly modified parser , originaly based on the targa reader by David Polomis (paloma_sw@cox.net)
- // now modified to extract image files from the ps2 version of LucasArts gladius.
-
- using System;
- using System.Collections.Generic;
- using System.Collections;
- using System.Text;
- using System.IO;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Runtime.InteropServices;
-
- namespace xexuxjy
- {
- public class GladiusHeader
- {
- private short sColorMapFirstEntryIndex = 0;
- private short sColorMapLength = 0;
- private byte bColorMapEntrySize = 0;
- public int Width = 0;
- public int Height = 0;
- private byte bPixelDepth = 0;
- private byte bImageDescriptor = 0;
- public byte[] RawColourMap;
- public byte[] SwizzledColourMap;
- public PixelFormat PixelFormat;
-
- public static char[] PTTPHeader = new char[] { 'P', 'T', 'T', 'P' };
- public static char[] NMPTHeader = new char[] { 'N', 'M', 'P', 'T' };
- public static char[] r2d2Header = new char[] { 'R', '2', 'D', '2', 'p', 's', 'x', '2' };
- public static char[] tmapHeader = new char[] { 't', 'm', 'a', 'p' };
-
-
- public static void TestGladius()
- {
- GladiusImage targaImage = new GladiusImage();
-
- String targetDirectory = @"C:/gladius-extracted/test-extract/";
- //String filepath = @"D:\gladius-extracted\ps2-decompressed\converted1\";
- //String filepath = @"D:\gladius-extracted\ps2-decompressed\PTTP\";
- //String errorFile = @"D:\gladius-extracted\ps2-decompressed-errors";
-
- String filepath = @"C:\gladius-extracted\ps2-decompressed\PTTP\";
- String errorFile = @"C:\gladius-extracted\ps2-decompressed-errors";
-
- System.IO.DirectoryInfo targetInfo = new DirectoryInfo(targetDirectory);
- if (!targetInfo.Exists)
- {
- targetInfo.Create();
- }
-
- bool doDelete = true;
- if (doDelete)
- {
- foreach (FileInfo file in targetInfo.GetFiles())
- {
- file.Delete();
- }
- }
-
- string[] filePaths = Directory.GetFiles(filepath);
-
- DirectoryInfo d = new DirectoryInfo(filepath);
- FileInfo[] files = d.GetFiles(); //Getting Text files
- using (StreamWriter errorStream = new StreamWriter(new FileStream(errorFile, FileMode.OpenOrCreate)))
- {
- GladiusImage image = null;
- foreach (FileInfo file in files)
- {
- //if (file.Name != "File_000957")
- //if (file.Name != "File_000230")
- if (file.Name != "File_000024")
- {
- //continue;
- }
- using (FileStream fs = new FileStream(filepath + file.Name, FileMode.Open))
- using (BinaryReader binReader = new BinaryReader(fs))
- {
- int headerPadding = 0;
-
- int subImageCounter = 0;
-
- List<String> textureNameList = BuildImageList(binReader);
-
- // if there were no texture names then reset the position of the stream to find the data.
- if (textureNameList.Count == 0)
- {
- binReader.BaseStream.Position = 0;
- }
-
- while (ReadToNextTMapBlock(binReader, ref subImageCounter))
- {
- int adjustedCounter = subImageCounter-1;
-
- image = new GladiusImage();
-
- image.Header.LoadHeaderInfo(binReader, errorStream, file.Name);
-
- bool saveImage = true;
- String outputFileName = null;
- if (textureNameList.Count > 0 && adjustedCounter < textureNameList.Count)
- {
- //outputFileName = file.Name + "-" + textureNameList[adjustedCounter];
- outputFileName = textureNameList[adjustedCounter];
- }
- else
- {
- outputFileName = file.Name + "-" + (adjustedCounter);
- }
-
- //outputFileName = file.Name + "-" + (subImageCounter);
-
- errorStream.WriteLine(String.Format("Extracting [{0}][{1}][{2}]", file.Name, adjustedCounter, outputFileName));
-
- int imagePadding = 0x13;// 0x24;
-
- if (image.Header.PixelFormat == PixelFormat.Format8bppIndexed)
- {
- //image.Header.Se
- image.Header.ColorMapLength = 256;
- image.Header.ColorMapEntrySize = 32;
-
- if (binReader.BaseStream.Position + 1024 > binReader.BaseStream.Length)
- {
- // not enough room for a colour map?
- break;
- }
- image.Header.PixelDepth = 8;
- image.LoadColourMapInfo(binReader);
-
- }
- else if (image.Header.PixelFormat == PixelFormat.Format32bppArgb)
- {
- image.Header.PixelDepth = 32;
- }
- else
- {
- int ibreak = 0;
- }
-
- if (image.Header.ValidSize() && image.Header.KnownFormat())
- {
-
-
- binReader.BaseStream.Seek(imagePadding, SeekOrigin.Current);
- try
- {
- image.LoadGladiusImage(binReader);
- if (saveImage)
- {
- image.Image.Save(targetDirectory + outputFileName + ".png", ImageFormat.Png);
- }
- }
- catch (AccessViolationException e)
- {
- // bleugh.
- }
-
- bool writePalette = false;
- if (writePalette)
- {
- using (var fs2 = new FileStream(targetDirectory + file.Name + "-pal.bin", FileMode.CreateNew))
- {
- using (var bw = new BinaryWriter(fs2))
- {
- bw.Write(image.Header.RawColourMap);
- }
- }
-
- using (var fs2 = new FileStream(targetDirectory + file.Name + "-cpal.bin", FileMode.CreateNew))
- {
- using (var bw = new BinaryWriter(fs2))
- {
- bw.Write(image.Header.SwizzledColourMap);
- }
- }
- }
- }
- }
- }
- }
- }
-
- }
-
- //readpfhd!
-
-
- /// <summary>
- /// Gets total number of color map entries included.
- /// </summary>
- public short ColorMapLength
- {
- get;set;
- }
-
- /// <summary>
- /// Gets the number of bits per entry in the Color Map. Typically 15, 16, 24 or 32-bit values are used.
- /// </summary>
- public byte ColorMapEntrySize
- {
- get;set;
- }
-
-
- /// <summary>
- /// Gets the number of bits per pixel. This number includes
- /// the Attribute or Alpha channel bits. Common values are 8, 16, 24 and 32.
- /// </summary>
- public byte PixelDepth
- {
- get;set;
- }
-
-
- /// <summary>
- /// Gets the number of bytes per pixel.
- /// </summary>
- public int BytesPerPixel
- {
- get
- {
- return (int)this.PixelDepth / 8;
- }
- }
-
- public static bool FindCharsInStream(BinaryReader binReader, char[] charsToFind)
- {
- bool found = false;
- char c = ' ';
- int lastFoundIndex = 0;
- try
- {
- while (true)
- {
- c = (char)binReader.ReadByte();
- if (c == charsToFind[lastFoundIndex])
- {
- lastFoundIndex++;
- if (lastFoundIndex == charsToFind.Length)
- {
- found = true;
- break;
- }
- }
- else
- {
- lastFoundIndex = 0;
- }
- }
- }
- catch (Exception e)
- {
- int ibreak = 0;
- }
- return found;
-
- }
-
-
- public static bool ReadToNextTMapBlock(BinaryReader binReader, ref int imageCount)
- {
- bool foundR2D2 = FindCharsInStream(binReader, GladiusHeader.r2d2Header);
- bool foundTmap = false;
- byte[] extra = new byte[8];
-
- while (foundR2D2)
- {
- imageCount++;
-
- binReader.Read(extra, 0, extra.Length);
- bool shouldHaveTmap = (extra[5] != 0x00);
- if (shouldHaveTmap)
- {
- foundTmap = FindCharsInStream(binReader, GladiusHeader.tmapHeader);
- //if (foundTmap)
- //{
- // imageCount++;
- //}
- break;
- }
- foundR2D2 = FindCharsInStream(binReader, GladiusHeader.r2d2Header);
- }
-
- return foundTmap;
- }
-
-
- public static List<String> BuildImageList(BinaryReader binReader)
- {
- List<String> textureNameList = new List<string>();
-
- List<String> ignoreList = new List<string>();
-
- // for some reason these seem to be referenced but not included in all(?) the files so ignore them.
- //ignoreList.Add("teeth.tga");
- //ignoreList.Add("skygold_R.rm.tga");
-
- // load header and map of image names.
- if (FindCharsInStream(binReader, GladiusHeader.PTTPHeader))
- {
- if (FindCharsInStream(binReader, GladiusHeader.NMPTHeader))
- {
- int unknown1 = binReader.ReadInt32();
- int unknown2 = binReader.ReadInt32();
- int numTextures = binReader.ReadInt32();
-
- for (int i = 0; i < numTextures; ++i)
- {
- StringBuilder sb = new StringBuilder();
- char b = (char)binReader.ReadByte();
- while (b != 0x00)
- {
- if (b != 0x00)
- {
- sb.Append(b);
- }
- b = (char)binReader.ReadByte();
- }
- String n = sb.ToString();
- if (!ignoreList.Contains(n))
- {
- textureNameList.Add(n);
- }
- }
- }
-
- }
- return textureNameList;
- }
-
-
-
-
- public bool KnownFormat()
- {
- return PixelFormat == PixelFormat.Format8bppIndexed || PixelFormat == PixelFormat.Format32bppArgb;
- }
-
- public bool ValidSize()
- {
- return !(Width <= 0 || Height <= 0 || Width > 1024 || Height > 1024);
- }
-
-
- public void LoadHeaderInfo(BinaryReader binReader, StreamWriter errorStream, String file)
- {
- int headerPadding = 0;
-
- byte[] extraHeader = new byte[24];
- binReader.Read(extraHeader, 0, extraHeader.Length);
-
- //19th extra byte should determine image format (8bppIndexed,32rgba)
- //20th extra byte should be FF
- int imageSize = extraHeader[2];
- int imageFormat = extraHeader[22];
-
- if (imageFormat == 0xB0)
- {
- if (imageSize == 0x10)
- {
- Width = Height = 256;
- }
- else if (imageSize == 0x08)
- {
- Width = Height = 0x20;
- }
- else if (imageSize == 0x04)
- {
- Width = Height = 64;
- }
- else
- {
- errorStream.WriteLine(String.Format("Unknown size [{0}] File [{1}]", imageSize, file));
- }
-
- PixelFormat = PixelFormat.Format32bppArgb;
- headerPadding = 101;
- }
- else if (imageFormat == 0xD8 || imageFormat == 0x60)
- {
- PixelFormat = PixelFormat.Format8bppIndexed;
- headerPadding = 0x78 - 20;
- }
- else
- {
- errorStream.WriteLine(String.Format("Unknown Output Format [{0}] File [{1}] Position[{2}]", imageFormat, file, binReader.BaseStream.Position));
- }
-
- {
- binReader.BaseStream.Seek(headerPadding, SeekOrigin.Current);
- //return binReader.BaseStream.Position;
-
- }
- }
-
- public static bool PositionReaderAtNextImage(BinaryReader binReader, StreamWriter errorStream, String file)
- {
- return FindCharsInStream(binReader, GladiusHeader.r2d2Header) && FindCharsInStream(binReader, GladiusHeader.tmapHeader);
- }
-
- static int Main(string[] args)
- {
- GladiusHeader.TestGladius();
- return 0;
- }
-
- }
-
-
-
- public class GladiusImage : IDisposable
- {
- private GladiusHeader gladiusHeader = null;
- private Bitmap bitmapImage = null;
- private string strFileName = string.Empty;
- private int intStride = 0;
- private GCHandle ImageByteHandle;
- private System.Collections.Generic.List<System.Collections.Generic.List<byte>> rows = new System.Collections.Generic.List<System.Collections.Generic.List<byte>>();
- private System.Collections.Generic.List<byte> row = new System.Collections.Generic.List<byte>();
-
- /// <summary>
- /// Creates a new instance of the TargaImage object.
- /// </summary>
- public GladiusImage()
- {
- this.gladiusHeader = new GladiusHeader();
- this.bitmapImage = null;
- }
-
-
- /// <summary>
- /// Gets a TargaHeader object that holds the Targa Header information of the loaded file.
- /// </summary>
- public GladiusHeader Header
- {
- get { return this.gladiusHeader; }
- set { this.gladiusHeader = value; }
- }
-
- /// <summary>
- /// Gets a Bitmap representation of the loaded file.
- /// </summary>
- public Bitmap Image
- {
- get { return this.bitmapImage; }
- }
-
- /// <summary>
- /// Gets the full path and filename of the loaded file.
- /// </summary>
- public string FileName
- {
- get { return this.strFileName; }
- }
-
-
- /// <summary>
- /// Gets the byte offset between the beginning of one scan line and the next. Used when loading the image into the Image Bitmap.
- /// </summary>
- /// <remarks>
- /// The memory allocated for Microsoft Bitmaps must be aligned on a 32bit boundary.
- /// The stride refers to the number of bytes allocated for one scanline of the bitmap.
- /// </remarks>
- public int Stride
- {
- get { return this.intStride; }
- }
-
- ~GladiusImage()
- {
- Dispose(false);
- }
-
- public void LoadColourMapInfo(BinaryReader binReader)
- {
- int paletteSize = 1024;
-
- this.gladiusHeader.RawColourMap = new byte[paletteSize];
- this.gladiusHeader.SwizzledColourMap = new byte[paletteSize];
-
- int rawCounter = 0;
-
- while (rawCounter < paletteSize)
- {
- int a = 0;
- int r = 0;
- int g = 0;
- int b = 0;
-
- byte rbyte = binReader.ReadByte();
- byte gbyte = binReader.ReadByte();
- byte bbyte = binReader.ReadByte();
- byte abyte = binReader.ReadByte();
-
- this.gladiusHeader.RawColourMap[rawCounter++] = rbyte;
- this.gladiusHeader.RawColourMap[rawCounter++] = gbyte;
- this.gladiusHeader.RawColourMap[rawCounter++] = bbyte;
- this.gladiusHeader.RawColourMap[rawCounter++] = abyte;
- }
-
- byte[] src = this.gladiusHeader.RawColourMap;
- byte[] tgt = this.gladiusHeader.SwizzledColourMap;
-
- int blockSize = 8;
- int blockIncrement = blockSize * 4;
- int offset = 0;
- while (offset < src.Length)
- {
-
- for (int j = 0; j < blockSize; ++j)
- {
- tgt[offset + 0] = src[offset + 2];
- tgt[offset + 1] = src[offset + 1];
- tgt[offset + 2] = src[offset + 0];
- tgt[offset + 3] = src[offset + 3];
- offset += 4;
- }
-
- for (int j = 0; j < blockSize; ++j)
- {
- tgt[offset + 0] = src[blockIncrement + offset + 2];
- tgt[offset + 1] = src[blockIncrement + offset + 1];
- tgt[offset + 2] = src[blockIncrement + offset + 0];
- tgt[offset + 3] = src[blockIncrement + offset + 3];
- offset += 4;
- }
-
- for (int j = 0; j < blockSize; ++j)
- {
- tgt[offset + 0] = src[offset + 2 - (blockIncrement * 1)];
- tgt[offset + 1] = src[offset + 1 - (blockIncrement * 1)];
- tgt[offset + 2] = src[offset + 0 - (blockIncrement * 1)];
- tgt[offset + 3] = src[offset + 3 - (blockIncrement * 1)];
- offset += 4;
- }
-
- for (int j = 0; j < blockSize; ++j)
- {
- tgt[offset + 0] = src[offset + 2];
- tgt[offset + 1] = src[offset + 1];
- tgt[offset + 2] = src[offset + 0];
- tgt[offset + 3] = src[offset + 3];
- offset += 4;
- }
-
- }
-
- // skip 12?
- int a1 = binReader.ReadInt32();
- int a2 = binReader.ReadInt32();
-
- this.gladiusHeader.Width = binReader.ReadInt16();
- this.gladiusHeader.Height = binReader.ReadInt16();
- }
-
- // assumes we've position the stream.
- private byte[] LoadImageBytes(BinaryReader binReader)
- {
- byte[] data = null;
- int intImageRowByteSize = (int)this.gladiusHeader.Width * ((int)this.gladiusHeader.BytesPerPixel);
-
- // get the size in bytes of the whole image
- int intImageByteSize = intImageRowByteSize * (int)this.gladiusHeader.Height;
- data = new byte[intImageByteSize];
-
- try
- {
- if(Header.PixelFormat == PixelFormat.Format8bppIndexed)
- {
- for (int i = 0; i < data.Length; ++i)
- {
-
- data[i] = binReader.ReadByte();
- }
- }
- else if (Header.PixelFormat == PixelFormat.Format32bppArgb)
- {
- byte[] subBytes = new byte[4];
- int adjustedLength = data.Length / 4;
- int counter = 0;
- for (int i = 0; i < adjustedLength; ++i)
- {
- subBytes[0] = binReader.ReadByte ();
- subBytes[1] = binReader.ReadByte ();
- subBytes[2] = binReader.ReadByte ();
- subBytes[3] = binReader.ReadByte ();
-
- //bgr
- //Array.Reverse(subBytes);
- subBytes[3] = 0xff;
- data[counter++] = subBytes[2];
- data[counter++] = subBytes[1];
- data[counter++] = subBytes[0];
- data[counter++] = subBytes[3];
- }
-
- }
-
-
-
-
- }
- catch (Exception e)
- {
- // if we read past the end, somethings wrong, but try and return as much data as we could get..
- }
- // return the image byte array
- return data;
-
- }
-
- public void LoadGladiusImage(BinaryReader binReader)
- {
- this.intStride = (((int)this.gladiusHeader.Width * (int)this.gladiusHeader.PixelDepth + 31) & ~31) >> 3; // width in bytes
-
- byte[] bimagedata = this.LoadImageBytes(binReader);
-
- this.ImageByteHandle = GCHandle.Alloc(bimagedata, GCHandleType.Pinned);
-
- PixelFormat pf = this.Header.PixelFormat;
-
-
- this.bitmapImage = new Bitmap((int)this.gladiusHeader.Width,
- (int)this.gladiusHeader.Height,
- this.intStride,
- pf,
- this.ImageByteHandle.AddrOfPinnedObject());
-
- if (pf == PixelFormat.Format8bppIndexed)
- {
- int numColourEntries = gladiusHeader.RawColourMap.Length / 4;
- if (numColourEntries > 0)
- {
- ColorPalette pal = this.bitmapImage.Palette;
-
- byte[] map = gladiusHeader.RawColourMap;
- map = gladiusHeader.SwizzledColourMap;
- for (int i = 0; i < numColourEntries; i++)
- {
- Color c = Color.FromArgb(255, map[i * 4], map[(i * 4) + 1], map[(i * 4) + 2]);
- Color c2 = Color.FromArgb(c.A, c.B, c.G, c.R);
- pal.Entries[i] = c2;
- }
- this.bitmapImage.Palette = pal;
- }
- }
- }
-
- #region IDisposable Members
-
- public void Dispose()
- {
- Dispose(true);
- // Take yourself off the Finalization queue
- // to prevent finalization code for this object
- // from executing a second time.
- //GC.SuppressFinalize(this);
-
- }
-
-
- protected virtual void Dispose(bool disposing)
- {
- // Check to see if Dispose has already been called.
- // If disposing equals true, dispose all managed
- // and unmanaged resources.
- if (disposing)
- {
- // Dispose managed resources.
- if (this.bitmapImage != null)
- {
- this.bitmapImage.Dispose();
- }
-
- if (this.ImageByteHandle != null)
- {
- if (this.ImageByteHandle.IsAllocated)
- {
- this.ImageByteHandle.Free();
- }
-
- }
- }
- }
-
-
- #endregion
- }
-
-
-
-
- }
-