changeset 0:1b2fad719890

Initial commit of IBBoard libraries
author IBBoard <dev@ibboard.co.uk>
date Fri, 19 Dec 2008 11:13:48 +0000
parents
children 7f6c92b0e2e0
files AssemblyInfo.cs Converter.cs IBBoard.Graphics.OpenILPort.csproj IBBoard.Graphics.OpenILPort.csproj.user IBBoard.Graphics.OpenILPort.mdp IBBoard.Graphics.OpenILPort.pidb copying
diffstat 7 files changed, 2072 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AssemblyInfo.cs	Fri Dec 19 11:13:48 2008 +0000
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("IBBoard.Graphics.OpenILPort")]
+[assembly: AssemblyDescription("A partial port of the DDS creation code from the OpenIL project")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Converter.cs	Fri Dec 19 11:13:48 2008 +0000
@@ -0,0 +1,1327 @@
+using System;
+using System.Drawing;
+
+/* -----------------------------------------------------------------------------*
+ *
+ * IBBoard.Graphics.OpenILPort
+ * Partial OpenIL code port from C++ to C# by IBBoard
+ * Website: http://www.ibboard.co.uk, email: Webmaster@ibboard.co.uk
+ * Copyright (C) 2006 IBBoard
+ * Last modified: 15/07/2006
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * 
+ * Filename: Converter.cs
+ *
+ * Converts a 32-bit BRGA file (TGA) to a DXT1/3/5 DDS file.
+ * Conversion is currently incomplete, MipMapping isn't using the correct
+ *		filters and other file formats are not supported.
+ * This port was purposefully made as a partial port to allow IBBoard's .Net
+ *		apps for the Dawn of War computer game textures to convert TGAs to DDS
+ *		files without using an external app, and without using Managed DirectX.
+ *
+ *-----------------------------------------------------------------------------*/
+
+namespace IBBoard.Graphics.OpenILPort
+{
+	public class Converter
+	{
+		public enum DXTType { None, DXT1, DXT3, DXT5 }
+
+		public enum Filter {Triangle}
+
+		private const byte BLACK_PIXEL = 0;
+		private const byte WHITE_PIXEL = 255;
+
+		public static readonly byte[] DXT1_Header = new byte[]{0x44, 0x44, 0x53, 0x20,//"DDS "
+																  0x7C, 0x00, 0x00, 0x00,//size - fixed to 124
+																  //0x07, 0x10, 0x02, 0x00};//valid field flags - DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT
+																  0x07, 0x10, 0x0A, 0x00,//Use Photoshop's output as a guide rather than the OpenIL line above
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//leave space for width and height
+																  0x00, 0x00, 0x00, 0x00,//and data length
+																  0x00, 0x00, 0x00, 0x00,//zero the volume depths
+																  0x00, 0x00, 0x00, 0x00,//and leave space for the mip maps
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//11 DWords of unspecified 'reserved'
+																  0x20, 0x00, 0x00, 0x00, //size - apparently fixed to 32
+																  0x04, 0x00, 0x00, 0x00,//DDPF_FOURCC
+																  0x44, 0x58, 0x54, 0x31,//DTX1
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //RGB and Alpha bit masks - not used in DoW DDS files
+																  0x08, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, //DDS Caps - always the same in DoW
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//two more reserved DWords
+																  0x00, 0x00, 0x00, 0x00};//and a final reserved DWord for good measure!
+
+		public static readonly byte[] DXT5_Header = new byte[]{0x44, 0x44, 0x53, 0x20,//"DDS "
+																  0x7C, 0x00, 0x00, 0x00,//size - fixed to 124
+																  //0x07, 0x10, 0x02, 0x00};//valid field flags - DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT
+																  0x07, 0x10, 0x0A, 0x00,//Use Photoshop's output as a guide rather than the OpenIL line above
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//leave space for width and height
+																  0x00, 0x00, 0x00, 0x00,//and data length
+																  0x00, 0x00, 0x00, 0x00,//zero the volume depths
+																  0x00, 0x00, 0x00, 0x00,//and leave space for the mip maps
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//11 DWords of unspecified 'reserved'
+																  0x20, 0x00, 0x00, 0x00, //size - apparently fixed to 32
+																  0x04, 0x00, 0x00, 0x00,//DDPF_FOURCC
+																  0x44, 0x58, 0x54, 0x35,//DTX5
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //RGB and Alpha bit masks - not used in DoW DDS files
+																  0x08, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, //DDS Caps - always the same in DoW
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//two more reserved DWords
+																  0x00, 0x00, 0x00, 0x00};//and a final reserved DWord for good measure!
+
+		public static readonly byte[] DXT3_Header = new byte[]{0x44, 0x44, 0x53, 0x20,//"DDS "
+																  0x7C, 0x00, 0x00, 0x00,//size - fixed to 124
+																  //0x07, 0x10, 0x02, 0x00};//valid field flags - DDSD_CAPS, DDSD_PIXELFORMAT, DDSD_WIDTH, DDSD_HEIGHT
+																  0x07, 0x10, 0x0A, 0x00,//Use Photoshop's output as a guide rather than the OpenIL line above
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//leave space for width and height
+																  0x00, 0x00, 0x00, 0x00,//and data length
+																  0x00, 0x00, 0x00, 0x00,//zero the volume depths
+																  0x00, 0x00, 0x00, 0x00,//and leave space for the mip maps
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//11 DWords of unspecified 'reserved'
+																  0x20, 0x00, 0x00, 0x00, //size - apparently fixed to 32
+																  0x04, 0x00, 0x00, 0x00,//DDPF_FOURCC
+																  0x44, 0x58, 0x54, 0x33,//DTX5
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //RGB and Alpha bit masks - not used in DoW DDS files
+																  0x08, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, //DDS Caps - always the same in DoW
+																  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//two more reserved DWords
+																  0x00, 0x00, 0x00, 0x00};//and a final reserved DWord for good measure!
+
+		private static int NextPower2(int val)
+		{
+			return (int)Math.Pow(2, Math.Ceiling(Math.Log(val)/Math.Log(2.0)));
+		}
+
+		private static int CalcMips(int width, int height)
+		{
+			return (int)Math.Ceiling(Math.Log(Math.Max(width, height))/Math.Log(2))+1;
+		}
+
+		private static int CalcFileSize(DXTType type, int width, int height, int mipmaps)
+		{
+			int val = 0;
+			byte bytes = (byte)BlockSize(type);
+
+			width = width/4;
+			height = height/4;
+
+			for (int i = 0; i<mipmaps; i++)
+			{
+				val+= width*height*bytes;
+				width = (width>1)?width/2:1;
+				height = (height>1)?height/2:1;
+			}
+
+			return val;
+		}
+
+		private static int BlockSize(DXTType type)
+		{
+			if (type==DXTType.DXT1)
+			{
+				return 8;
+			}
+			else if (type == DXTType.DXT5 || type == DXTType.DXT3)
+			{
+				return 16;
+			}
+			else
+			{
+				return 32;
+			}
+		}
+
+		public static byte[] BGRAtoDDS(byte[] rawData, DXTType DXTCFormat, int width, int height)
+		{
+			ushort ex0 = 0, ex1 = 0;
+			ushort[] Data;
+			ushort[] Block = new ushort[16]; 
+			byte[] file = null;
+			int x, y, i, pos;
+			uint BitMask;
+			byte a0 = 0, a1 = 0;
+			byte[] Alpha;
+			byte[] AlphaBlock = new byte[16];
+			byte[] AlphaBitMask = new byte[6];
+			byte[] AlphaOut = new byte[16];
+			bool HasAlpha = false;
+			int blocksize = BlockSize(DXTCFormat);
+
+			if (NextPower2(width) != width ||
+				NextPower2(height) != height) 
+			{
+				throw new InvalidOperationException("Dimensions of the image must be a power of two");
+			}
+
+			int mips = CalcMips(width, height);
+			int size = CalcFileSize(DXTCFormat, width, height, mips);
+			int mainSize = width*height/(16/blocksize);
+
+			rawData = CreateMipMaps(rawData, width, height, mips);
+
+			Data = CompressTo565(rawData, width, height);
+			if (Data == null)
+				return null;
+
+			Alpha = GetAlpha(rawData);
+			if (Alpha == null) 
+			{
+				return null;
+			}
+
+			file = new byte[size+128];
+
+			switch(DXTCFormat)
+			{
+				case DXTType.DXT1: DXT1_Header.CopyTo(file, 0);
+					break;
+				case DXTType.DXT5: DXT5_Header.CopyTo(file, 0);
+					break;
+				case DXTType.DXT3: DXT3_Header.CopyTo(file, 0);
+					break;
+				default:
+					throw new InvalidOperationException("Unsupported DXT format");
+			}
+
+			file[12] = (byte)height;
+			file[13] = (byte)(height>>8);
+			file[14] = (byte)(height>>16);
+			file[15] = (byte)(height>>24);
+			file[16] = (byte)width;
+			file[17] = (byte)(width>>8);
+			file[18] = (byte)(width>>16);
+			file[19] = (byte)(width>>24);
+			file[20] = (byte)mainSize;
+			file[21] = (byte)(mainSize>>8);
+			file[22] = (byte)(mainSize>>16);
+			file[23] = (byte)(mainSize>>24);
+			file[28] = (byte)mips;
+			file[29] = (byte)(mips>>8);
+			file[30] = (byte)(mips>>16);
+			file[31] = (byte)(mips>>24);
+			pos = 128;
+
+			int start = 0;
+			int startAlpha = 0;
+
+			switch (DXTCFormat)
+			{
+				case DXTType.DXT1:			
+					for (int m = 0; m<mips; m++)
+					{
+						for (y = 0; y < height; y += 4) 
+						{
+							for (x = 0; x < width; x += 4) 
+							{
+								AlphaBlock = GetAlphaBlock(Alpha, width, x, y, startAlpha, ref HasAlpha);
+
+								//Remove the old 'has alpha' check and replace is with a Ref'd bool above
+								//HasAlpha = false;
+
+								//for (i = 0 ; i < 16; i++) 
+								//{
+								//if (AlphaBlock[i] < 128) 
+								//{
+								//HasAlpha = true;
+								//break;
+								//}
+								//}
+
+								Block = GetBlock(Data, width, x, y, start);
+								ChooseEndpoints(Block, ref ex0, ref ex1);
+								CorrectEndDXT1(ref ex0, ref ex1, HasAlpha);
+								file[pos] = (byte)ex0;
+								file[pos+1] = (byte)(ex0>>8);
+								pos+=2;
+								file[pos] = (byte)ex1;
+								file[pos+1] = (byte)(ex1>>8);
+								pos+=2;
+
+								if (HasAlpha)
+									BitMask = GenBitMask(ex0, ex1, 3, Block, AlphaBlock);
+								else
+									BitMask = GenBitMask(ex0, ex1, 4, Block, null);
+
+								file[pos] = (byte)BitMask;
+								file[pos+1] = (byte)(BitMask>>8);
+								file[pos+2] = (byte)(BitMask>>16);
+								file[pos+3] = (byte)(BitMask>>24);
+								pos+=4;
+							}		
+						}
+
+						start = start+(width*height);
+						startAlpha = startAlpha+(width*height/2);
+
+						width /=2;
+						if (width<1) width = 1;
+						height /=2;
+						if (height<1) height = 1;
+					}
+					break;
+				case DXTType.DXT3:					
+					for (int m = 0; m<mips; m++)
+					{
+						for (y = 0; y < height; y += 4) 
+						{
+							for (x = 0; x < width; x += 4) 
+							{
+								AlphaBlock = GetAlphaBlock(Alpha, width, x, y, startAlpha);
+								for (i = 0; i < 16; i += 2) 
+								{
+									file[pos++] = (byte)(((AlphaBlock[i+1] >> 4) << 4) | (AlphaBlock[i] >> 4));
+								}
+
+								Block = GetBlock(Data, width, x, y, start);
+								ChooseEndpoints(Block, ref ex0, ref ex1);
+								CorrectEndDXT1(ref ex0, ref ex1, HasAlpha);//correct DXT3 colour ordering, because otherwise Photoshop treats it as DXT1 and makes index 3 (0x11) black
+								file[pos] = (byte)ex0;
+								file[pos+1] = (byte)(ex0>>8);
+								pos+=2;
+								file[pos] = (byte)ex1;
+								file[pos+1] = (byte)(ex1>>8);
+								pos+=2;
+								BitMask = GenBitMask(ex0, ex1, 4, Block, null);
+								file[pos] = (byte)BitMask;
+								file[pos+1] = (byte)(BitMask>>8);
+								file[pos+2] = (byte)(BitMask>>16);
+								file[pos+3] = (byte)(BitMask>>24);
+								pos+=4;
+							}		
+						}
+
+						start = start+(width*height);
+						startAlpha = startAlpha+(width*height/2);
+
+						width /=2;
+						if (width<1) width = 1;
+						height /=2;
+						if (height<1) height = 1;
+					}
+					break;
+
+				case DXTType.DXT5:
+					for (int m = 0; m<mips; m++)
+					{
+						for (y = 0; y < height; y += 4) 
+						{
+							for (x = 0; x < width; x += 4) 
+							{
+								AlphaBlock = GetAlphaBlock(Alpha, width, x, y, startAlpha);
+								ChooseAlphaEndpoints(AlphaBlock, ref a0, ref a1);
+								AlphaOut = GenAlphaBitMask(a0, a1, 8, AlphaBlock, AlphaBitMask);
+								file[pos++] = a0;
+								file[pos++] = a1;
+								file[pos++] = (byte)AlphaBitMask[0];
+								file[pos++] = (byte)AlphaBitMask[1];
+								file[pos++] = (byte)AlphaBitMask[2];
+								file[pos++] = (byte)AlphaBitMask[3];
+								file[pos++] = (byte)AlphaBitMask[4];
+								file[pos++] = (byte)AlphaBitMask[5];
+
+								Block = GetBlock(Data, width, x, y, start);
+								ChooseEndpoints(Block, ref ex0, ref ex1);
+								CorrectEndDXT1(ref ex0, ref ex1, HasAlpha);//correct DXT5 colour ordering, because otherwise Photoshop treats it as DXT1 and makes index 3 (0x11) black
+								file[pos] = (byte)ex0;
+								file[pos+1] = (byte)(ex0>>8);
+								pos+=2;
+								file[pos] = (byte)ex1;
+								file[pos+1] = (byte)(ex1>>8);
+								pos+=2;
+								BitMask = GenBitMask(ex0, ex1, 4, Block, null);
+								file[pos] = (byte)BitMask;
+								file[pos+1] = (byte)(BitMask>>8);
+								file[pos+2] = (byte)(BitMask>>16);
+								file[pos+3] = (byte)(BitMask>>24);
+								pos+=4;
+							}
+						}
+
+						start = start+(width*height);
+						startAlpha = startAlpha+(width*height/2);
+
+						width /=2;
+						if (width<1) width = 1;
+						height /=2;
+						if (height<1) height = 1;
+					}
+					break;
+			}
+
+			return file;
+		}
+
+		/// <summary>
+		/// Gets a 4x4 pixel block of RGB565 colours from the image
+		/// </summary>
+		/// <param name="Data">The image (and its MipMaps) as an array of RGB565 ushorts</param>
+		/// <param name="width">Pixel width of the image</param>
+		/// <param name="XPos">Horizontal position at which to start</param>
+		/// <param name="YPos">Vertical position at which to start</param>
+		/// <param name="start">Start of the MipMaps layer within the array</param>
+		/// <returns>Array of RGB565 ushorts for each pixel in the block</returns>
+		static ushort[] GetBlock(ushort[] Data, int width, int XPos, int YPos, int start)
+		{
+			int x, y, i = 0, Offset;
+			ushort[] Block = new ushort[16];
+
+			for (y = 0; y < 4; y++) 
+			{
+				Offset = (YPos + y) * width + XPos + start;
+
+				for (x = 0; x < 4; x++) 
+				{
+					Block[i++] = Data[Offset+x];
+				}
+			}
+
+			return Block;
+		}
+
+		/// <summary>
+		/// Returns a block of Alpha Channel data, without information as to whether there is transparency or not
+		/// </summary>
+		/// <param name="Data">The 32-bit image (and its MipMaps) as an array of bytes</param>
+		/// <param name="width">Pixel width of the image</param>
+		/// <param name="XPos">Horizontal position at which to start</param>
+		/// <param name="YPos">Vertical position at which to start</param>
+		/// <param name="start">Start of the MipMaps layer within the array</param>
+		/// <returns>Array of alpha bytes at the specified position in the specified MipMap</returns>
+		static byte[] GetAlphaBlock(byte[] Data, int width, int XPos, int YPos, int start)
+		{
+			bool junk = false;
+			return GetAlphaBlock(Data, width, XPos, YPos, start, ref junk);
+		}
+
+		/// <summary>
+		/// Returns a block of Alpha Channel data, with information as to whether there is transparency or not within the block
+		/// </summary>
+		/// <param name="Data">The 32-bit image (and its MipMaps) as an array of bytes</param>
+		/// <param name="width">Pixel width of the image</param>
+		/// <param name="XPos">Horizontal position at which to start</param>
+		/// <param name="YPos">Vertical position at which to start</param>
+		/// <param name="start">Start of the MipMaps layer within the array</param>
+		/// <param name="HasAlpha">Referenced boolean to indicate whether the block contains transparency</param>
+		/// <returns>Array of alpha bytes at the specified position in the specified MipMap</returns>
+		static byte[] GetAlphaBlock(byte[] Data, int width, int XPos, int YPos, int start, ref bool HasAlpha)
+		{
+			int x, y, i = 0, Offset;
+			byte[] Block = new byte[16];
+			HasAlpha = false;
+
+			for (y = 0; y < 4; y++) 
+			{
+				Offset = (YPos + y) * width + XPos + start;
+
+				for (x = 0; x < 4; x++) 
+				{
+					Block[i++] = Data[Offset+x];
+
+					if (Data[Offset+x]<128)
+						HasAlpha = true;
+				}
+			}
+
+			return Block;
+		}
+
+
+		/// <summary>
+		/// Converts a ushort RGB565 colour back to an RGB888 colour in the form of a Color object
+		/// </summary>
+		/// <param name="Pixel">The RGB565 ushort colour of a pixel</param>
+		/// <returns>A Color object of the equivalent RGB888 colour</returns>
+		static Color ShortToColor888(ushort Pixel)
+		{
+			Color col = Color.Black;
+
+			//we could do it the fancy and balanced way, but that seems to give colour hue issues of greys turning green/purple!
+			/*red = ((int)(Pixel & 0xf800))>>11;
+				red = (red * 255) / 31;
+				green = ((int)(Pixel & 0x07e0))>>5;
+				green = (green * 255) / 63;
+				blue = ((int)(Pixel & 0x001f) * 255) / 31;*/
+			col = Color.FromArgb(((Pixel & 0xF800) >> 11) << 3,
+				((Pixel & 0x07E0) >> 5)  << 2,
+				((Pixel & 0x001F))       << 3);
+
+			return col;
+		}
+
+		/// <summary>
+		/// Converts an RGB888 Color object to a ushort RGB565 colour
+		/// </summary>
+		/// <param name="Colour">The Color object to convert</param>
+		/// <returns>The equivalent RGB565 colour as a ushort</returns>
+		static ushort Color888ToShort(Color Colour)
+		{
+			return (ushort)(((Colour.R >> 3) << 11) | ((Colour.G >> 2) << 5) | (Colour.B >> 3));
+		}
+
+		/// <summary>
+		/// Generates the appropriate colour bitmask for the 4px x 4px DDS block
+		/// </summary>
+		/// <param name="ex0">Colour 0 as a ushort RGB565</param>
+		/// <param name="ex1">Colour 1 as a ushort RGB565</param>
+		/// <param name="NumCols">Number of colours to compress to. Value 3 for using 1-bit transparency in DXT1 images, otherwise 4</param>
+		/// <param name="In">Array of ushort RGB565 values holding the colours of the pixels in the block</param>
+		/// <param name="Alpha">Byte array of the alpha channel bytes for the block</param>
+		/// <returns></returns>
+		static uint GenBitMask(ushort ex0, ushort ex1, uint NumCols, ushort[] In, byte[] Alpha)
+		{
+			uint i, j, Closest, Dist, BitMask = 0;
+			byte[] Mask = new byte[16];
+			Color c;
+			Color[] Colours = new Color[4];
+
+			Colours[0] = ShortToColor888(ex0);
+			Colours[1] = ShortToColor888(ex1);
+
+			if (NumCols == 3) 
+			{
+				Colours[2] = Color.FromArgb((Colours[0].R + Colours[1].R) / 2, 
+					(Colours[0].G + Colours[1].G) / 2,
+					(Colours[0].B + Colours[1].B) / 2);
+				Colours[3] = Color.Black;
+			}
+			else 
+			{  // NumCols == 4
+				Colours[2] = Color.FromArgb((2 * Colours[0].R + Colours[1].R + 1) / 3,
+					(2 * Colours[0].G + Colours[1].G + 1) / 3,
+					(2 * Colours[0].B + Colours[1].B + 1) / 3);
+				Colours[3] = Color.FromArgb((Colours[0].R + 2 * Colours[1].R + 1) / 3,
+					(Colours[0].G + 2 * Colours[1].G + 1) / 3,
+					(Colours[0].B + 2 * Colours[1].B + 1) / 3);
+			}
+
+			for (i = 0; i < 16; i++) 
+			{
+				if (Alpha!=null) 
+				{  // Test to see if we have 1-bit transparency
+					if (Alpha[i] < 128) 
+					{
+						Mask[i] = 3;  // Transparent
+						continue;
+					}
+				}
+
+				// If no transparency, try to find which colour is the closest.
+				Closest = UInt16.MaxValue;
+				c = ShortToColor888(In[i]);
+				for (j = 0; j < NumCols; j++) 
+				{
+					Dist = Distance(c, Colours[j]);
+					//Dist = HSLDistance(c, Colours[j]);
+					if (Dist < Closest) 
+					{
+						Closest = Dist;
+						Mask[i] = (byte)j;
+					}
+				}
+			}
+
+			for (i = 0; i < 16; i++) 
+			{
+				BitMask |= (uint)((int)Mask[i] << (int)(i*2));
+			}
+
+			return BitMask;
+		}
+
+		/// <summary>
+		/// Compresses an BGRA8888 image (32-bit TGA) to an RGB565 image with MipMaps
+		/// </summary>
+		/// <param name="rawData">Raw 32-bit BRGA8888 image data without headers as an array of bytes</param>
+		/// <param name="width">Width of the raw image</param>
+		/// <param name="height">Height of the raw image</param>
+		/// <returns>RGB565 image with MipMaps as an array of ushorts</returns>
+		static ushort[] CompressTo565(byte[] rawData, int width, int height)
+		{
+			int mips = CalcMips(width, height);
+			ushort[] data = new ushort[CalcFileSize(DXTType.None, width, height, mips)/2];
+			uint i, j = 0;
+
+			for (i = 0; i < rawData.Length; i += 4, j++) 
+			{
+				data[j]  = (ushort)((rawData[i+2]>> 3) << 11);
+				data[j] |= (ushort)((rawData[i+1] >> 2) << 5);
+				data[j] |=  (ushort)(rawData[i] >> 3);
+			}
+
+			return data;
+		}
+
+		/// <summary>
+		/// Adds the MipMaps to a BGRA8888 image
+		/// </summary>
+		/// <param name="data">Raw 32-bit BRGA8888 image data without headers as an array of bytes</param>
+		/// <param name="width">Width of the raw image</param>
+		/// <param name="height">Height of the raw image</param>
+		/// <returns>Raw 32-bit BRGA8888 image data with MipMaps as an array of bytes</returns>
+		public static byte[] CreateMipMaps(byte[] data, int width, int height)
+		{
+			return CreateMipMaps(data, width, height, CalcMips(width, height));
+		}
+
+		/// <summary>
+		/// Adds the MipMaps to a BGRA8888 image
+		/// </summary>
+		/// <param name="data">Raw 32-bit BRGA8888 image data without headers as an array of bytes</param>
+		/// <param name="width">Width of the raw image</param>
+		/// <param name="height">Height of the raw image</param>
+		/// <param name="mips">Number of MipMaps to create</param>
+		/// <returns>Raw 32-bit BRGA8888 image data with MipMaps as an array of bytes</returns>
+		public static byte[] CreateMipMaps(byte[] data, int width, int height, int mips)
+		{
+			byte[] image = new byte[CalcFileSize(DXTType.None, width, height, mips)*2];
+			byte[] temp;
+			byte[] prev = data;
+			int start = width*height*4;
+			int reduction;
+			int redWidth = width;
+			int redHeight = height;
+
+			data.CopyTo(image, 0);
+			
+			for (int m = 1; m<mips; m++)
+			{
+				reduction = (int)Math.Pow(2, m);
+				reduction*=reduction;
+				temp = HalveSize(prev, redWidth, redHeight);
+				redWidth = redWidth/2;
+				redHeight = redHeight/2;
+				prev = temp;
+				temp.CopyTo(image, start); 
+				start = start+width*height*4/reduction;
+			}
+
+			return image;
+		}
+
+		/// <summary>
+		/// Reduces the size of a given image by half to create the MipMap
+		/// </summary>
+		/// <param name="data">32-bit image to reduce in size</param>
+		/// <param name="width">Width of original image</param>
+		/// <param name="height">Height of original image</param>
+		/// <returns>Half-sized 32-bit image</returns>
+		public static byte[] HalveSize(byte[] data, int width, int height)
+		{
+			byte[] map = new byte[data.Length/4];
+			Zoom(map, data, width, height, width/2, height/2, Filter.Triangle, 1.0);
+			return map;
+
+			
+			/*
+			int reduction = 2;
+			int step = reduction*4;
+			int byteWidth = 4*width;
+			int pos = 0;
+			int oldPos = 0;
+			double divisor = reduction*reduction;
+			byte[] map = new byte[data.Length/(reduction*reduction)];
+			double[] tempMap = new double[map.Length];
+			int reducedByteWidth = (int)Math.Round((double)byteWidth/reduction);
+			int penultByteWidth = byteWidth-4;
+			int penultRow = height-1;
+			double fraction = 1.0/reduction;
+			double proportionBL = (divisor-1)/(divisor*divisor);
+			double proportionBR = 1.0/(divisor*divisor);
+			double proportionTL = ((divisor-1)*(divisor-1))/(divisor*divisor);
+			double proportionTR = (divisor-1)/(divisor*divisor);
+			double start = fraction/2 - 0.5;
+
+			for (int i = 0; i<height; i+=2)
+			{
+				for (int j = 0; j<byteWidth; j+=8)
+				{
+					oldPos = i*byteWidth+j;
+
+					pos = (i/2)*reducedByteWidth+j/2;
+					tempMap[pos]+=(byte)(data[oldPos]/divisor+data[oldPos+4]/divisor+data[oldPos+byteWidth]/divisor+data[oldPos+byteWidth+4]/divisor);
+					oldPos++;
+					tempMap[pos+1]+= (byte)(data[oldPos]/divisor+data[oldPos+4]/divisor+data[oldPos+byteWidth]/divisor+data[oldPos+byteWidth+4]/divisor);
+					oldPos++;
+					tempMap[pos+2]+= (byte)(data[oldPos]/divisor+data[oldPos+4]/divisor+data[oldPos+byteWidth]/divisor+data[oldPos+byteWidth+4]/divisor);
+					oldPos++;
+					tempMap[pos+3]+= (byte)(data[oldPos]/divisor+data[oldPos+4]/divisor+data[oldPos+byteWidth]/divisor+data[oldPos+byteWidth+4]/divisor);
+				}
+			}
+
+			for (int i = 0; i<map.Length; i++)
+			{
+				map[i] = (byte)tempMap[i];
+			}
+
+			return map;*/
+		}
+
+		/// <summary>
+		/// Extracts the alpha channel from a raw 32-bit image with no headers
+		/// </summary>
+		/// <param name="rawData">The raw 32-bit image as a byte array</param>
+		/// <returns>The alpha channel from the image as a byte array</returns>
+		static byte[] GetAlpha(byte[] rawData)
+		{
+			byte[] data = new byte[rawData.Length/4];
+
+			for (int i = 0; i<data.Length; i++)
+			{
+				data[i] = rawData[i*4 + 3];
+			}
+
+			return data;
+		}
+
+		/// <summary>
+		/// Generates an alpha bit mask for a block in a DDS image
+		/// </summary>
+		/// <param name="a0">Alpha level 0</param>
+		/// <param name="a1">Alpha level 1</param>
+		/// <param name="Num">Number of graded alpha levels between a0 and a1 inclusive - either 6 or 8</param>
+		/// <param name="In">Alpha channel levels for the block</param>
+		/// <param name="Mask">Alpha bit mask to be stored in DXT3/DXT5 images</param>
+		/// <returns>Alpha bitmask for DXT1 images</returns>
+		static byte[] GenAlphaBitMask(byte a0, byte a1, uint Num, byte[] In, byte[] Mask)
+		{
+			byte[] Alphas = new byte[8];
+			byte[] M = new byte[16];
+			byte[] Out = new byte[16];
+			uint	i, j, Closest, Dist;
+
+			Alphas[0] = a0;
+			Alphas[1] = a1;
+
+			// 8-alpha or 6-alpha block?    
+			if (Num == 8) 
+			{    
+				// 8-alpha block:  derive the other six alphas.    
+				// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
+				Alphas[2] = (byte)((6 * Alphas[0] + 1 * Alphas[1] + 3) / 7);	// bit code 010
+				Alphas[3] = (byte)((5 * Alphas[0] + 2 * Alphas[1] + 3) / 7);	// bit code 011
+				Alphas[4] = (byte)((4 * Alphas[0] + 3 * Alphas[1] + 3) / 7);	// bit code 100
+				Alphas[5] = (byte)((3 * Alphas[0] + 4 * Alphas[1] + 3) / 7);	// bit code 101
+				Alphas[6] = (byte)((2 * Alphas[0] + 5 * Alphas[1] + 3) / 7);	// bit code 110
+				Alphas[7] = (byte)((1 * Alphas[0] + 6 * Alphas[1] + 3) / 7);	// bit code 111  
+			}    
+			else 
+			{  
+				// 6-alpha block.    
+				// Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated.
+				Alphas[2] = (byte)((4 * Alphas[0] + 1 * Alphas[1] + 2) / 5);	// Bit code 010
+				Alphas[3] = (byte)((3 * Alphas[0] + 2 * Alphas[1] + 2) / 5);	// Bit code 011
+				Alphas[4] = (byte)((2 * Alphas[0] + 3 * Alphas[1] + 2) / 5);	// Bit code 100
+				Alphas[5] = (byte)((1 * Alphas[0] + 4 * Alphas[1] + 2) / 5);	// Bit code 101
+				Alphas[6] = 0x00;										// Bit code 110
+				Alphas[7] = 0xFF;										// Bit code 111
+			}
+
+			for (i = 0; i < 16; i++) 
+			{
+				Closest = uint.MaxValue;
+				for (j = 0; j < 8; j++) 
+				{
+					Dist = (uint)(In[i] - Alphas[j]);
+					if (Dist < Closest) 
+					{
+						Closest = Dist;
+						M[i] = (byte)j;
+					}
+				}
+			}
+
+			if (Out!=null) 
+			{
+				for (i = 0; i < 16; i++) 
+				{
+					Out[i] = Alphas[M[i]];
+				}
+			}
+
+			// First three bytes.
+			Mask[0] = (byte)((M[0]) | (M[1] << 3) | ((M[2] & 0x03) << 6));
+			Mask[1] = (byte)((M[2] & 0x04)>>2 | (M[3] << 1) | (M[4] << 4) | ((M[5] & 0x01) << 7));
+			Mask[2] = (byte)((M[5] & 0x06)>>1 | (M[6] << 2) | (M[7] << 5));
+
+			// Second three bytes.
+			Mask[3] = (byte)((M[8]) | (M[9] << 3) | ((M[10] & 0x03) << 6));
+			Mask[4] = (byte)((M[10] & 0x04)>>2 | (M[11] << 1) | (M[12] << 4) | ((M[13] & 0x01) << 7));
+			Mask[5] = (byte)((M[13] & 0x06)>>1 | (M[14] << 2) | (M[15] << 5));
+
+			return Out;
+		}
+
+		/// <summary>
+		/// Calculates the difference between two colours
+		/// </summary>
+		/// <param name="c1">First colour to difference</param>
+		/// <param name="c2">Colour to difference it from</param>
+		/// <returns>Distance between the two colours</returns>
+		static uint Distance(Color c1, Color c2)
+		{
+			return  (uint)((c1.R - c2.R) * (c1.R - c2.R)) +
+				(uint)((c1.G - c2.G) * (c1.G - c2.G)) +
+				(uint)((c1.B - c2.B) * (c1.B - c2.B));
+			/*return  (uint)Math.Abs(c1.R - c2.R) +
+				(uint)Math.Abs(c1.G - c2.G) +
+				(uint)Math.Abs(c1.B - c2.B);*/
+		}
+
+		static uint HSLDistance(Color c1, Color c2)
+		{
+			double hue1, hue2;
+			double delta;
+
+			hue1 = hue2 = 0;
+
+			if (c1.R>c1.G && c1.R>c1.B)
+			{
+				delta = (c1.R - Math.Min(c1.G, c1.B));
+
+				if (delta!=0)
+				{
+					hue1 = (c1.G - c1.B) / delta * 60;
+				}
+
+				if (hue1<0)
+				{
+					hue1+= 360;
+				}
+			}
+			else if (c1.G>c1.B)
+			{
+				delta = (c1.G - Math.Min(c1.R, c1.B));
+
+				if (delta!=0)
+				{
+					hue1 = (c1.B - c1.R) / delta * 60 + 120;
+				}
+			}
+			else
+			{
+				delta = (c1.B - Math.Min(c1.G, c1.R));
+
+				if (delta!=0)
+				{
+					hue1 = (c1.R - c1.G) / delta * 60 + 240;
+				}
+			}
+
+			if (c2.R>c2.G && c2.R>c2.B)
+			{
+				delta = (c2.R - Math.Min(c2.G, c2.B));
+
+				if (delta!=0)
+				{
+					hue2 = (c2.G - c2.B) / delta * 60;
+				}
+
+				if (hue2<0)
+				{
+					hue2+= 360;
+				}
+			}
+			else if (c1.G>c1.B)
+			{
+				delta = (c2.G - Math.Min(c2.R, c2.B));
+
+				if (delta!=0)
+				{
+					hue2 = (c2.B - c2.R) / delta * 60 + 120;
+				}
+			}
+			else
+			{
+				delta = (c2.B - Math.Min(c2.G, c2.R));
+				if (delta!=0)
+				{
+					hue2 = (c2.R - c2.G) / delta * 60 + 240;
+				}
+			}
+
+			return (uint)Math.Abs(hue1 - hue2);
+			/*return  (uint)Math.Abs(c1.R - c2.R) +
+				(uint)Math.Abs(c1.G - c2.G) +
+				(uint)Math.Abs(c1.B - c2.B);*/
+		}
+
+		/// <summary>
+		/// Finds two endpoint RGB565 colours that are the most different from each other within a DDS image block
+		/// </summary>
+		/// <param name="Block">The 4x4 pixel block of RGB565 colours</param>
+		/// <param name="ex0">Reference to the first endpoint colour</param>
+		/// <param name="ex1">Reference to the secont endpoint colour that is most different from the first</param>
+		static void ChooseEndpoints(ushort[] Block, ref ushort ex0, ref ushort ex1)
+		{
+			int i, j;
+			Color[] Colours = new Color[16];
+			int Farthest = -1;//, nextFarthest = -1;
+			uint d;
+			//short idx_i = -1, idx_j = -1;
+
+			for (i = 0; i < 16; i++) 
+			{
+				Colours[i] = ShortToColor888(Block[i]);
+			}
+
+			for (i = 0; i < 16; i++) 
+			{
+				for (j = i+1; j < 16; j++) 
+				{
+					d = Distance(Colours[i], Colours[j]);
+
+					if (d > Farthest) 
+					{
+						Farthest = (int)d;
+						ex0 = Block[i];
+						ex1 = Block[j];
+					}
+				}
+			}
+
+			/*
+			//IBBoard custom version follows:
+			//Find the two most distant colours and ignore them
+			for (i = 0; i < 16; i++) 
+			{
+				for (j = i+1; j < 16; j++) 
+				{
+					d = Distance(Colours[i], Colours[j]);
+					if (d > Farthest) 
+					{
+						nextFarthest = Farthest;
+						Farthest = (int)d;
+						//ex0_next = ex0;
+						//ex1_next = ex1;
+						//ex0 = Block[i];
+						//ex1 = Block[j];
+						idx_i = (short)i;
+						idx_j = (short)j;
+					}
+				}
+			}
+
+			//Then find the most distant of all the colours excluding the two most distant ones
+			Farthest = -1;
+			nextFarthest = -1;
+
+			for (i = 0; i < 16; i++) 
+			{
+				if (i!=idx_i)
+				{
+					for (j = i+1; j < 16; j++) 
+					{
+						if (idx_j != j)
+						{
+							d = Distance(Colours[i], Colours[j]);
+
+							if (d > Farthest) 
+							{
+								nextFarthest = Farthest;
+								Farthest = (int)d;
+								//ex0_next = ex0;
+								//ex1_next = ex1;
+								ex0 = Block[i];
+								ex1 = Block[j];
+							}
+						}
+					}
+				}
+			}*/
+
+			return;
+		}
+
+		/// <summary>
+		/// Finds two endpoints within the alpha channel of a DDS image block that are most different from each other
+		/// </summary>
+		/// <param name="Block">The 4x4 pixel block of alpha channel data</param>
+		/// <param name="a0">Reference to the first endpoint alpha value</param>
+		/// <param name="a1">Reference to the second endpoint alpha value that is most distant from the first</param>
+		static void ChooseAlphaEndpoints(byte[] Block, ref byte a0, ref byte a1)
+		{
+			uint	i;
+			uint	Lowest = 0xFF, Highest = 0;
+			a0 = (byte)Highest;
+			a1 = (byte)Lowest;
+
+			for (i = 0; i < 16; i++) 
+			{
+				if (Block[i] < Lowest) 
+				{
+					a1 = Block[i];  // a1 is the lower of the two.
+					Lowest = Block[i];
+				}
+				
+				if (Block[i] > Highest) 
+				{
+					a0 = Block[i];  // a0 is the higher of the two.
+					Highest = Block[i];
+				}
+			}
+
+			return;
+		}
+
+
+		/// <summary>
+		/// Corrects the colour endpoints in accordance with the DDS algorithm so that ex0 < ex1 
+		/// only when the block has a 1-bit alpha channel with transparency
+		/// </summary>
+		/// <param name="ex0">Colour endpoint 0 as an RGB565 ushort</param>
+		/// <param name="ex1">Colour endpoint 1 as an RGB565 ushort</param>
+		/// <param name="HasAlpha">Whether the block has transparent bits</param>
+		/// <remarks>This function should only be used with DXT1 textures, however tests with Photoshop's
+		/// DDS plugin show that DXT3 and DXT5 images will show black for pixels given the value 0x11 if
+		/// the colour endpoints are not also corrected.</remarks>
+		static void CorrectEndDXT1(ref ushort ex0, ref ushort ex1, bool HasAlpha)
+		{
+			ushort Temp;
+
+			if (HasAlpha) 
+			{
+				if (ex0 > ex1) 
+				{
+					Temp = ex0;
+					ex0 = ex1;
+					ex1 = Temp;
+				}
+			}
+			else 
+			{
+				if (ex0 < ex1) 
+				{
+					Temp = ex0;
+					ex0 = ex1;
+					ex1 = Temp;
+				}
+			}
+		}
+
+		#region New 'zoom' code for Triangular filter
+
+		struct Contribution
+		{
+			public int n;
+			public ContribPixel[] p;
+		}
+
+		struct ContribPixel
+		{
+			public int pixel;
+			public double weight;
+		}
+
+		/// <summary>
+		/// 'Zooms' the image to resize it, using a filter such as Triangular
+		/// </summary>
+		/// <param name="dest">Byte array to copy the newly resized 32-bit image to</param>
+		/// <param name="src">Byte array containing the existing 32-bit image</param>
+		/// <param name="width">Current image width</param>
+		/// <param name="height">Current image height</param>
+		/// <param name="newWidth">Width to make the new image</param>
+		/// <param name="newHeight">Height to make the new image</param>
+		/// <param name="filter">Filter to use on resizing</param>
+		/// <param name="fwidth">Filter width</param>
+		/// <remarks>Currently only Triangular filter will be supported</remarks>
+		public static void Zoom(byte[] dest, byte[] src, int width, int height, int newWidth, int newHeight, Filter filter, double fwidth)
+		{
+			double xscale, yscale;
+			int xx;
+			int i, j, k;
+			int n;
+			double center, left, right;
+			double calcWidth, fscale, weight;
+			byte pel = 0, pel2;
+			bool bPelDelta;
+			Contribution[] contribY = new Contribution[newHeight];
+			Contribution contribX = new Contribution();
+			int c = 0;
+
+
+			xscale = newWidth/(double)width;
+			yscale = newHeight/(double)height;
+
+			
+			/* create intermediate column to hold horizontal dst column zoom */
+			byte[] tmp = new byte[height];
+
+			for (c = 0; c<4; c++)
+			{
+				if(yscale < 1.0)
+				{
+					calcWidth = fwidth / yscale;
+					fscale = 1.0 / yscale;
+					for(i = 0; i < newHeight; ++i)
+					{
+						contribY[i].n = 0;
+						contribY[i].p = new ContribPixel[(int)calcWidth * 2 + 1];
+
+						center = (double) i / yscale;
+						left = Math.Ceiling(center - calcWidth);
+						right = Math.Floor(center + calcWidth);
+						for(j = (int)left; j <= right; ++j) 
+						{
+							weight = center - (double) j;
+							weight = triangle_filter(weight / fscale) / fscale;
+							if(j < 0) 
+							{
+								n = -j;
+							} 
+							else if(j >= height) 
+							{
+								n = (height - j) + height - 1;
+							} 
+							else 
+							{
+								n = j;
+							}
+							k = contribY[i].n++;
+							contribY[i].p[k].pixel = n;
+							contribY[i].p[k].weight = weight;
+						}
+					}
+				} 
+				else 
+				{
+					for(i = 0; i < newHeight; ++i) 
+					{
+						contribY[i].n = 0;
+						contribY[i].p = new ContribPixel[(int)(fwidth * 2 + 1)];
+						if (contribY[i].p.Length == 0) 
+						{
+							return;
+						}
+						center = (double) i / yscale;
+						left = Math.Ceiling(center - fwidth);
+						right = Math.Floor(center + fwidth);
+						for(j = (int)left; j <= right; ++j) 
+						{
+							weight = center - (double) j;
+							weight = triangle_filter(weight);
+							if(j < 0) 
+							{
+								n = -j;
+							} 
+							else if(j >= height) 
+							{
+								n = (height - j) + height - 1;
+							} 
+							else 
+							{
+								n = j;
+							}
+							k = contribY[i].n++;
+							contribY[i].p[k].pixel = n;
+							contribY[i].p[k].weight = weight;
+						}
+					}
+				}
+			
+				for(xx = 0; xx < newWidth; xx++)
+				{
+					calc_x_contrib(ref contribX, xscale, fwidth, 
+						newWidth, width, filter, xx);
+
+					/* Apply horz filter to make dst column in tmp. */
+					for(k = 0; k < height; ++k)
+					{
+						weight = 0.0;
+						bPelDelta = false;
+						// Denton:  Put get_pixel source here
+						//pel = get_pixel(src, contribX.p[0].pixel, k);
+						try
+						{
+							pel = src[k * 4 * width + contribX.p[0].pixel * 4 + c];
+						}
+						catch (IndexOutOfRangeException)
+						{
+							//FIXME: Exception when newWidth=1, k=width-1, contribX.p[0].pixel=width and c=0
+							string fibble = "";
+							pel = 0;
+						}
+
+						for(j = 0; j < contribX.n; ++j)
+						{
+							// Denton:  Put get_pixel source here
+							//pel2 = get_pixel(src, contribX.p[j].pixel, k);
+							try
+							{
+								pel2 = src[k * 4 * width + contribX.p[j].pixel * 4 + c];
+							}
+							catch(IndexOutOfRangeException)
+							{
+								//FIXME: As above
+								pel2 = 0;
+							}
+
+							if(pel2 != pel)
+								bPelDelta = true;
+							weight += pel2 * contribX.p[j].weight;
+						}
+						weight = bPelDelta ? roundcloser(weight) : pel;
+
+						tmp[k] = CLAMP((byte)weight, BLACK_PIXEL, WHITE_PIXEL);
+					} /* next row in temp column */
+
+					/* The temp column has been built. Now stretch it 
+						 vertically into dst column. */
+					for(i = 0; i < newHeight; i++)
+					{
+						weight = 0.0;
+						bPelDelta = false;
+
+						try
+						{
+							pel = tmp[contribY[i].p[0].pixel];
+						}
+						catch (IndexOutOfRangeException)
+						{
+							//FIXME: As above
+							string fibble = "";
+							pel = 0;
+						}
+
+						for(j = 0; j < contribY[i].n; ++j)
+						{
+							try
+							{
+								pel2 = tmp[contribY[i].p[j].pixel];
+							}
+							catch (IndexOutOfRangeException)
+							{
+								//FIXME: As above
+								string fibble = "";
+								pel2 = 0;
+							}							if(pel2 != pel)
+								bPelDelta = true;
+							weight += pel2 * contribY[i].p[j].weight;
+						}
+						weight = bPelDelta ? roundcloser(weight) : pel;
+
+						try
+						{
+							dest[i * 4 * newWidth + xx * 4 + c] = CLAMP((byte)weight, BLACK_PIXEL, WHITE_PIXEL);
+						}
+						catch (IndexOutOfRangeException)
+						{
+							//FIXME: As above
+							string fibble = "";
+						}
+					} /* next dst row */
+				} /* next dst column */
+			}
+		}
+
+		private static void calc_x_contrib(ref Contribution contribX, double xscale, double fwidth, int dstwidth, int srcwidth, Filter filter, int i)
+		{
+			double width;
+			double fscale;
+			double center, left, right;
+			double weight;
+			int j, k, n;
+
+			if(xscale < 1.0)
+			{
+				/* Shrinking image */
+				width = fwidth / xscale;
+				fscale = 1.0 / xscale;
+
+				contribX.n = 0;
+				contribX.p = new ContribPixel[(int)(width * 2 + 1)];
+
+				center = (double) i / xscale;
+				left = Math.Ceiling(center - width);
+				right = Math.Floor(center + width);
+				for(j = (int)left; j <= right; ++j)
+				{
+					weight = center - (double) j;
+					weight = triangle_filter(weight / fscale) / fscale;
+
+					if(j < 0)
+						n = -j;
+					else if(j >= srcwidth)
+						n = (srcwidth - j) + srcwidth - 1;
+					else
+						n = j;
+			
+					k = contribX.n++;
+					contribX.p[k].pixel = n;
+					contribX.p[k].weight = weight;
+				}
+	
+			}
+			else
+			{
+				/* Expanding image */
+				contribX.n = 0;
+				contribX.p = new ContribPixel[(int)(fwidth * 2 + 1)];
+
+				center = (double) i / xscale;
+				left = Math.Ceiling(center - fwidth);
+				right = Math.Floor(center + fwidth);
+
+				for(j = (int)left; j <= right; ++j)
+				{
+					weight = center - (double) j;
+					weight = triangle_filter(weight);
+					if(j < 0) 
+					{
+						n = -j;
+					} 
+					else if(j >= srcwidth) 
+					{
+						n = (srcwidth - j) + srcwidth - 1;
+					} 
+					else 
+					{
+						n = j;
+					}
+					k = contribX.n++;
+					contribX.p[k].pixel = n;
+					contribX.p[k].weight = weight;
+				}
+			}
+		}
+
+		private static int roundcloser(double val)
+		{
+			return (int)Math.Round(val, 0);
+		}
+
+		private static byte CLAMP(byte v, byte l, byte h)
+			//value, low, high
+		{
+			return (v<l) ? l : ((v>h) ? h : v);
+		}
+
+		private static double triangle_filter(double t)
+		{
+			if(t < 0.0) t = -t;
+			if(t < 1.0) return 1.0 - t;
+			return 0.0;
+		}
+
+		#endregion
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IBBoard.Graphics.OpenILPort.csproj	Fri Dec 19 11:13:48 2008 +0000
@@ -0,0 +1,99 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <ProjectType>Local</ProjectType>
+    <ProductVersion>8.0.50727</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{DC228FE8-B0D1-4CE8-869D-404B9173AA58}</ProjectGuid>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ApplicationIcon>
+    </ApplicationIcon>
+    <AssemblyKeyContainerName>
+    </AssemblyKeyContainerName>
+    <AssemblyName>IBBoard.Graphics.OpenILPort</AssemblyName>
+    <AssemblyOriginatorKeyFile>
+    </AssemblyOriginatorKeyFile>
+    <DefaultClientScript>JScript</DefaultClientScript>
+    <DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
+    <DefaultTargetSchema>IE50</DefaultTargetSchema>
+    <DelaySign>false</DelaySign>
+    <OutputType>Library</OutputType>
+    <RootNamespace>IBBoard.Graphics.OpenILPort</RootNamespace>
+    <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
+    <StartupObject>
+    </StartupObject>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <OutputPath>C:\Documents and Settings\ibboard\My Documents\Visual Studio 2005\Projects\IBBoardGraphicsOpenILPort\bin\Debug\</OutputPath>
+    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+    <BaseAddress>285212672</BaseAddress>
+    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+    <ConfigurationOverrideFile>
+    </ConfigurationOverrideFile>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DocumentationFile>
+    </DocumentationFile>
+    <DebugSymbols>true</DebugSymbols>
+    <FileAlignment>4096</FileAlignment>
+    <NoStdLib>false</NoStdLib>
+    <NoWarn>
+    </NoWarn>
+    <Optimize>false</Optimize>
+    <RegisterForComInterop>false</RegisterForComInterop>
+    <RemoveIntegerChecks>false</RemoveIntegerChecks>
+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+    <WarningLevel>4</WarningLevel>
+    <DebugType>full</DebugType>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <OutputPath>bin\Release\</OutputPath>
+    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
+    <BaseAddress>285212672</BaseAddress>
+    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
+    <ConfigurationOverrideFile>
+    </ConfigurationOverrideFile>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>
+    </DocumentationFile>
+    <DebugSymbols>false</DebugSymbols>
+    <FileAlignment>4096</FileAlignment>
+    <NoStdLib>false</NoStdLib>
+    <NoWarn>
+    </NoWarn>
+    <Optimize>true</Optimize>
+    <RegisterForComInterop>false</RegisterForComInterop>
+    <RemoveIntegerChecks>false</RemoveIntegerChecks>
+    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
+    <WarningLevel>4</WarningLevel>
+    <DebugType>none</DebugType>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System">
+      <Name>System</Name>
+    </Reference>
+    <Reference Include="System.Drawing">
+      <Name>System.Drawing</Name>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AssemblyInfo.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Converter.cs">
+      <SubType>Code</SubType>
+    </Compile>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>
+    </PreBuildEvent>
+    <PostBuildEvent>
+    </PostBuildEvent>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IBBoard.Graphics.OpenILPort.csproj.user	Fri Dec 19 11:13:48 2008 +0000
@@ -0,0 +1,58 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <LastOpenVersion>7.10.3077</LastOpenVersion>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ReferencePath>
+    </ReferencePath>
+    <CopyProjectDestinationFolder>
+    </CopyProjectDestinationFolder>
+    <CopyProjectUncPath>
+    </CopyProjectUncPath>
+    <CopyProjectOption>0</CopyProjectOption>
+    <ProjectView>ProjectFiles</ProjectView>
+    <ProjectTrust>0</ProjectTrust>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <EnableASPDebugging>false</EnableASPDebugging>
+    <EnableASPXDebugging>false</EnableASPXDebugging>
+    <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
+    <EnableSQLServerDebugging>false</EnableSQLServerDebugging>
+    <RemoteDebugEnabled>false</RemoteDebugEnabled>
+    <RemoteDebugMachine>
+    </RemoteDebugMachine>
+    <StartAction>Project</StartAction>
+    <StartArguments>
+    </StartArguments>
+    <StartPage>
+    </StartPage>
+    <StartProgram>
+    </StartProgram>
+    <StartURL>
+    </StartURL>
+    <StartWorkingDirectory>
+    </StartWorkingDirectory>
+    <StartWithIE>true</StartWithIE>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <EnableASPDebugging>false</EnableASPDebugging>
+    <EnableASPXDebugging>false</EnableASPXDebugging>
+    <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
+    <EnableSQLServerDebugging>false</EnableSQLServerDebugging>
+    <RemoteDebugEnabled>false</RemoteDebugEnabled>
+    <RemoteDebugMachine>
+    </RemoteDebugMachine>
+    <StartAction>Project</StartAction>
+    <StartArguments>
+    </StartArguments>
+    <StartPage>
+    </StartPage>
+    <StartProgram>
+    </StartProgram>
+    <StartURL>
+    </StartURL>
+    <StartWorkingDirectory>
+    </StartWorkingDirectory>
+    <StartWithIE>true</StartWithIE>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IBBoard.Graphics.OpenILPort.mdp	Fri Dec 19 11:13:48 2008 +0000
@@ -0,0 +1,24 @@
+<Project name="IBBoard.Graphics.OpenILPort" fileversion="2.0" DefaultNamespace="IBBoard.Graphics.OpenILPort" language="C#" clr-version="Net_1_1" ctype="DotNetProject">
+  <Configurations active="Debug">
+    <Configuration name="Debug" ctype="DotNetProjectConfiguration">
+      <Output directory="bin/Debug/" assembly="IBBoard.Graphics.OpenILPort" />
+      <Build debugmode="True" target="Library" />
+      <Execution runwithwarnings="False" consolepause="True" runtime="MsNet" clr-version="Net_1_1" />
+      <CodeGeneration compiler="Mcs" warninglevel="4" optimize="True" unsafecodeallowed="False" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
+    </Configuration>
+    <Configuration name="Release" ctype="DotNetProjectConfiguration">
+      <Output directory="bin/Release/" assembly="IBBoard.Graphics.OpenILPort" />
+      <Build debugmode="False" target="Library" />
+      <Execution runwithwarnings="False" consolepause="True" runtime="MsNet" clr-version="Net_1_1" />
+      <CodeGeneration compiler="Mcs" warninglevel="4" optimize="True" unsafecodeallowed="False" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
+    </Configuration>
+  </Configurations>
+  <Contents>
+    <File name="AssemblyInfo.cs" subtype="Code" buildaction="Compile" />
+    <File name="Converter.cs" subtype="Code" buildaction="Compile" />
+  </Contents>
+  <References>
+    <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+    <ProjectReference type="Gac" localcopy="True" refto="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  </References>
+</Project>
\ No newline at end of file
Binary file IBBoard.Graphics.OpenILPort.pidb has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/copying	Fri Dec 19 11:13:48 2008 +0000
@@ -0,0 +1,506 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+
+