view ChunkyDataPTBD.cs @ 0:82db9430c2e4 default tip

Initial commit under GPLv3
author IBBoard <dev@ibboard.co.uk>
date Sat, 06 Oct 2018 19:49:25 +0100
parents
children
line wrap: on
line source

// This file is a part of the Relic Tools and is copyright 2006-2018 IBBoard.
//
// The file and the library/program it is in are licensed under the GNU GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license.
using System;
using System.IO;
using IBBoard.Graphics;
using IBBoard.Relic.RelicTools.Exceptions;

namespace IBBoard.Relic.RelicTools
{
	/// <summary>
	/// Summary description for ChunkyDataPTBD.
	/// </summary>
	public class ChunkyDataPTBD : ChunkyDataLayer
	{
		const float size_x = 64;
		const float size_y = 64;
		float x;
		float y;

		public ChunkyDataPTBD(int version_in, string name_in, byte[] innerData):base("PTBD", version_in, name_in)
		{
			x = BitConverter.ToSingle(innerData,0);
			y = BitConverter.ToSingle(innerData,4);
		}

		public float Pos_x
		{
			get{ return x; }
		}

		public float Pos_y
		{
			get{ return y; }
		}

		public float Height
		{
			get{ return size_y; }
		}

		public float Width
		{
			get{ return size_x; }
		}

		public override void Save(DirectoryInfo dir, string fileBaseName)
		{
			int width = Info.Width;
			int height = Info.Height;

			float right = x+size_x;
			float top = y+size_y;

			if (((int)right)>width || ((int)top)>height)
			{
				throw new InvalidChunkException("Badge layer contains an invalid badge position");
			}

			//create the TGA
			int fileLength = width*height;
			byte [] file = new byte[fileLength];

			int pos = 0;

			for (int i = 0; i<height; i++)
			{
				for (int j = 0; j<width; j++)
				{
					if (x<=j && j<right && y<=i && i<top)
					{
						file[pos] = byte.MaxValue;
					}
					else
					{
						file[pos] = byte.MinValue;
					}

					pos++;
				}
			}

			//save the TGA
			FileStream str = new FileStream(dir.FullName.TrimEnd(Path.DirectorySeparatorChar)+Path.DirectorySeparatorChar+fileBaseName+"_Badge.tga", FileMode.Create);
			BinaryWriter bw = new BinaryWriter(str);
			bw.Write(TGA_Greyscale_Header_a);				
			bw.Write((ushort)width);
			bw.Write((ushort)height);
			bw.Write(TGA_Greyscale_Header_b);
			bw.Write(file);
			bw.Flush();
			bw.Close();
		}

		public static ChunkyDataPTBD CreateFromTGA(int version, string name, byte[] tgaData)
		{
			//check image type code
			if (tgaData[2]!=0x03)
			{
				bool worked = false;

				if (tgaData[1] == 0x01 && tgaData[2] == 0x01)
				{
					tgaData = ImageConverter.ColourMapToGreyscale(tgaData);
					worked = true;
				}


				if (!worked)
				{
					ImageConverter.MapEncStruct format = ImageConverter.getMapEncStruct(tgaData[2]);
					throw new InvalidFileException("_badge.tga must be an unencoded unmapped monochrome Targa image.\r\n"+
						"  Image type: "+format.formatType+"\r\n"+
						"  Image encoded: "+((format.isEncoded)?"yes":"no")+"\r\n"+
						"  Colour mapped: "+((format.isMapped)?"yes":"no"));
				}
			}

			//check colour depth
			if (tgaData[16]!=0x08)
			{
				throw new InvalidFileException("_badge.tga must be an 8-bit Targa image. Image was "+tgaData[16]+"-bit.");
			}

			float pos_x = float.MinValue;
			float pos_y = float.MinValue;
			int width = (int)tgaData[12]+(((int)tgaData[13])<<8);
			int height = (int)tgaData[14]+(((int)tgaData[15])<<8);
			int currPos = 0;
			int size_x_int = (int)size_x;

			for (currPos = 18; currPos<tgaData.Length; currPos+=size_x_int)
			{
				//try to find our badge;
				if (tgaData[currPos]==byte.MaxValue)
				{
					pos_y = (float)((currPos-18)/width);
					pos_x = (float)(currPos-18-(pos_y*width));
					break;
				}
			}

			if (pos_y!=float.MinValue)
			{
				int maxPossibleEnd = currPos+width;
				int extra = 0;

				while (currPos<maxPossibleEnd && tgaData[currPos]==byte.MaxValue)
				{
					currPos++;
					extra++;
				}

				//check where the left hand side should start
				if (pos_x>0 && (tgaData[currPos-size_x_int]!=byte.MaxValue || tgaData[currPos-size_x_int-1]!=byte.MinValue))
				{
					throw new InvalidFileException("Badge is is not the correct width or is not a solid white square");
				}
				else
				{
					pos_x = pos_x+extra-size_x;
				}

				//and check for the top - not all of the block, just assume a left and bottom side are OK
				int aboveTop = currPos-size_x_int+(width*(int)size_y);
				for (int i = currPos-size_x_int; i<=aboveTop && i<tgaData.Length; i+= width)
				{
					if (tgaData[i]!=byte.MaxValue && i!=aboveTop)
					{
						throw new InvalidFileException("Badge area is too small. Badge must be 64px by 64px");
					}
				}

				//if we got here, it's all OK

				byte[] data = new byte[16];
			
				BitConverter.GetBytes(pos_x).CopyTo(data, 0);
				BitConverter.GetBytes(pos_y).CopyTo(data, 4);
				BitConverter.GetBytes(size_x).CopyTo(data, 8);
				BitConverter.GetBytes(size_y).CopyTo(data, 12);
			
				return new ChunkyDataPTBD(version, name, data);
			}
			else
			{
				return null;
			}
		}

		public override bool Savable
		{
			get
			{
				return true;
			}
		}

		public override int DataLength
		{
			get
			{
				return 16;
			}
		}

		public override byte[] GetDataBytes()
		{
			byte[] data = new byte[16];
			BitConverter.GetBytes(x).CopyTo(data, 0);
			BitConverter.GetBytes(y).CopyTo(data, 4);
			BitConverter.GetBytes(size_x).CopyTo(data, 8);
			BitConverter.GetBytes(size_y).CopyTo(data, 12);
			return data;
		}

		public override string GetDisplayDetails()
		{
			return base.GetBaseDisplayDetails()+Environment.NewLine+
				"------------"+Environment.NewLine+
				"X:\t\t"+x+Environment.NewLine+
				"Y:\t\t"+y+Environment.NewLine+
				"Width:\t\t"+size_x+Environment.NewLine+
				"Height:\t\t"+size_y;
		}
	}
}