// =============================================================================
// -----------------------------------------------------------------------------
// Program
// -----------------------------------------------------------------------------

#include <stdio.h>
#include <windows.h>
#include "_bitmap.h"

	// This defines if the rendering method is double pixeled, 
	// i.e. 01 12 23 34 instead of 01 23 45 67, this allows precise pixels
	// to be selected when scaling, but comes at the cost of twice the amount
	// of memory.

#define QUALITY FALSE

#define DEBUG FALSE

#define DirSize 0x1000
char Direct [DirSize], *FileName, *ExtName;

struct MAP

{
	int Y;
	int S;
	int P;
	int X;
};

struct MAPSPRITE

{
	int Size;
	MAP *Map;
};

struct PIXLIST

{
	int Size;
	int PixCount;
	int *Data;
};

struct PIXMASTER

{
	int Pieces;
	PIXLIST *List;
};

// =============================================================================
// -----------------------------------------------------------------------------
// Processing a film texture map image
// -----------------------------------------------------------------------------

int ProcessFilm (IMG &Image, MAPSPRITE *MapSlot, PIXMASTER *Pix)

{
	MapSlot->Map = NULL;
	MapSlot->Size = 0;

	struct BOX { int ShiftX; int ShiftY; int L; int U; int R; int D; };
	BOX Box = { 0, 0, 0x7FFFFFFF, 0x7FFFFFFF, -1, -1 };

		// --- finding the texture ---

	PIX_BGRA PadColour = Image.Data [0];
	for (int Y = 0; Y < Image.SizeY; Y++)
	{
		for (int X = 0; X < Image.SizeX; X++)
		{
			Image.Data [X + (Y * Image.SizeX)].Alpha = 0xFF;
			if (	PadColour.Red   != Image.Data [X + (Y * Image.SizeX)].Red	||
				PadColour.Green != Image.Data [X + (Y * Image.SizeX)].Green	||
				PadColour.Blue  != Image.Data [X + (Y * Image.SizeX)].Blue	)
			{
				if (X < Box.L) { Box.L = X; }
				if (Y < Box.U) { Box.U = Y; }
				if ((X + 1) > Box.R) { Box.R = X + 1; }
				if ((Y + 1) > Box.D) { Box.D = Y + 1; }
				Image.Data [X + (Y * Image.SizeX)].Alpha = 0x00;
			}
		}
	}
	if (Box.R == -1)
	{
		return (-1);
	}

		// --- Working out the best alignment for reducing tiles ---

	int BestWidth = -1, BestHeight = -1;
	int BestCount = 0x7FFFFFFF;
	for (int SY = 0; SY < 8; SY++)
	{
		for (int SX = 0; SX < 8; SX++)
		{
			int Count = 0, CurWidth = 8, CurHeight = 8;
			for (int YT = Box.U - SY, Height = 8; YT < Box.D + 8; YT += 8, Height += 8)
			{
				for (int XT = Box.L - SX, Width = 8; XT < Box.R + 8; XT += 8, Width += 8)
				{
					for (int YP = 0; YP < 8; YP++)
					{
						int XP;
						for (XP = 0; XP < 8; XP++)
						{
							if ((XT + XP) < 0 || (XT + XP) >= Image.SizeX) { continue; }
							if ((YT + YP) < 0 || (YT + YP) >= Image.SizeY) { continue; }
							if (Image.Data [(XT + XP) + ((YT + YP) * Image.SizeX)].Alpha == 0x00)
							{
								if (Width > CurWidth) { CurWidth = Width; }
								if (Height > CurHeight) { CurHeight = Height; }
								Count++;
								break;
							}
						}
						if (XP < 8) { break; }
					}
		
				}
			}
			if (Count < BestCount)
			{
				BestCount = Count;
				Box.ShiftX = SX;
				Box.ShiftY = SY;
				BestWidth = CurWidth;
				BestHeight = CurHeight;
			}
		}
	}

		// --- aligning, truncating, and mapping out valid tiles ---

	int CentreX = (Image.SizeX / 2) - (Box.L - Box.ShiftX);
	int CentreY = (Image.SizeY / 2) - (Box.U - Box.ShiftY);
	TruncateImage (&Image,		Box.L - Box.ShiftX,
					Box.U - Box.ShiftY,
					BestWidth + (Box.L - Box.ShiftX),
					BestHeight + (Box.U - Box.ShiftY),
					PadColour);

#if DEBUG==TRUE
	FlipImage (&Image);
	SaveBMP (&Image, "Test.bmp", 24);
	FlipImage (&Image);
	printf ("Dumped truncated image\n");
#endif

	u_char MapByte [Image.SizeX / 8] [Image.SizeY / 8];
	for (int YT = 0; YT < Image.SizeY; YT += 8)
	{
		for (int XT = 0; XT < Image.SizeX; XT += 8)
		{
			MapByte [XT / 8] [YT / 8] = 0xFF;
			for (int YP = 0; YP < 8; YP++)
			{
				int XP;
				for (XP = 0; XP < 8; XP++)
				{
					if (Image.Data [(XT + XP) + ((YT + YP) * Image.SizeX)].Alpha == 0x00)
					{
						MapByte [XT / 8] [YT / 8] = 0x80;
						break;
					}
				}
				if (XP < 8) { break; }
			}
		}
	}

		// --- Finding sprite pieces ---

	int SizeOrder [] = { //	X, Y
				4, 4,
				3, 4,
				4, 3,
				3, 3,
				2, 4,
				4, 2,
				2, 3,
				3, 2,
				2, 2,
				1, 4,
				4, 1,
				1, 3,
				3, 1,
				1, 2,
				2, 1,
				1, 1	};

	int MapPos = 0;
	int Pattern = 0;
	for (int SizeLoc = 0; SizeLoc < 0x10*2; SizeLoc += 2)
	{
		for (int Y = 0; Y < Image.SizeY / 8; Y++)
		{
			for (int X = 0; X < Image.SizeX / 8; X++)
			{
				int YT, XT;
				for (YT = 0; YT < SizeOrder [SizeLoc+1]; YT++)
				{
					for (XT = 0; XT < SizeOrder [SizeLoc]; XT++)
					{
						if ((X + XT) >= Image.SizeX / 8) { break; }
						if ((Y + YT) >= Image.SizeY / 8) { break; }
						if (MapByte [X + XT] [Y + YT] != 0x80) { break; }
					}
					if (XT < SizeOrder [SizeLoc]) { break; }
				}
				if (YT < SizeOrder [SizeLoc+1]) { continue; }
				int Shape = ((SizeOrder [SizeLoc] - 1) << 2) | (SizeOrder [SizeLoc+1] - 1);
				for (YT = 0; YT < SizeOrder [SizeLoc+1]; YT++)
				{
					for (XT = 0; XT < SizeOrder [SizeLoc]; XT++)
					{
						MapByte [X + XT] [Y + YT] = Shape;
					}
				}
				if (MapPos >= MapSlot->Size)
				{
					MapSlot->Size <<= 1;
					if (MapSlot->Size == 0) { MapSlot->Size = 0x10; }
					MAP *MapNew = (MAP*) realloc (MapSlot->Map, MapSlot->Size * sizeof (MAP));
					if (MapNew == NULL)
					{
						free (MapSlot->Map); MapSlot->Map = NULL;
						printf ("    Error, could not reallocate mapping list...\n");
						return (0);
					}
					MapSlot->Map = MapNew;
				}
				MapSlot->Map [MapPos].Y = (Y * 8) + -CentreY;
				MapSlot->Map [MapPos].S = Shape;
				MapSlot->Map [MapPos].P = Pattern;
				MapSlot->Map [MapPos++].X = (X * 8) + -CentreX;
				Pattern += SizeOrder [SizeLoc] * SizeOrder [SizeLoc+1];
			}
		}
	}
	MapSlot->Size = MapPos;

#if DEBUG==TRUE
	FILE *File = fopen ("Test MapByte.bin", "wb");
	for (int Y = 0; Y < Image.SizeY / 8; Y++)
	{
		for (int X = 0; X < Image.SizeX / 8; X++)
		{
			fputc (MapByte [X] [Y], File);
		}
	}
	fclose (File);

	File = fopen ("Test Map.bin", "wb");
	for (int MapLoc = 0; MapLoc < MapSlot->Size; MapLoc++)
	{
		fputc (MapSlot->Map [MapLoc].Y >> 0x08, File);
		fputc (MapSlot->Map [MapLoc].Y, File);
		fputc (MapSlot->Map [MapLoc].S, File);
		fputc (0x00, File);
		fputc (MapSlot->Map [MapLoc].P >> 0x08, File);
		fputc (MapSlot->Map [MapLoc].P, File);
		fputc (MapSlot->Map [MapLoc].X >> 0x08, File);
		fputc (MapSlot->Map [MapLoc].X, File);
	}
	fclose (File);
	printf ("Dumped mappings...\n");
#endif

		// --- Generating coordinates ---

	Pix->Pieces = MapSlot->Size;
	Pix->List = (PIXLIST*) calloc (Pix->Pieces, sizeof (PIXLIST));
	if (Pix->List == NULL)
	{
		free (MapSlot->Map); MapSlot->Map = NULL;
		printf ("    Error, could not allocate pixel frame lists...\n");
		return (0);
	}

	int *Data = (int*) (Image.Data);
	for (int MapLoc = 0; MapLoc < MapSlot->Size; MapLoc++)
	{
		int Y = MapSlot->Map [MapLoc].Y + CentreY;
		int X = MapSlot->Map [MapLoc].X + CentreX;
		int HC = (MapSlot->Map [MapLoc].S & 3) + 1;
		int WC = ((MapSlot->Map [MapLoc].S >> 2) & 3) + 1;
		Pix->List [MapLoc].Size = (HC * 8) * (WC * 4) + ((WC * 2) + 2);
		Pix->List [MapLoc].Data = (int*) malloc (Pix->List [MapLoc].Size * sizeof (int));
		if (Pix->List [MapLoc].Data == NULL)
		{
			while (MapLoc-- > 0)
			{
				free (Pix->List [MapLoc].Data); Pix->List [MapLoc].Data = NULL;
			}
			free (Pix->List); Pix->List = NULL;
			free (MapSlot->Map); MapSlot->Map = NULL;
			printf ("    Error, could not allocate pixel list...\n");
			return (0);
		}
		Pix->List [MapLoc].PixCount = 0;
		int PixLoc = 0;
		for (int W = 0; W < WC; W++)
		{
			int StartLoc = PixLoc++;
			for (int H = 0; H < HC; H++)
			{
				for (int YP = Y + (H * 8), YC = 8; YC > 0; YC--, YP++)
				{
					for (int XP = X + (W * 8), XC = 8; XC > 0; XC -= 2, XP += 2)
					{
						int Pixel = Data [XP + (YP * Image.SizeX)];
						if (Pixel < 0)
						{
							Pixel = Data [(XP+1) + (YP * Image.SizeX)];
							if (Data [(XP+1) + (YP * Image.SizeX)] < 0)
							{
								Pixel = -1;
							}
						}
						if (Pixel != -1)
						{
#if QUALITY==FALSE
							Pixel /= 2;
#endif
							if (StartLoc != -1)
							{
								Pix->List [MapLoc].Data [StartLoc] = Pixel;
								StartLoc = -1;
							}
						}
						Pix->List [MapLoc].Data [PixLoc++] = Pixel;
						Pix->List [MapLoc].PixCount++;
					}
				}
			}
			Pix->List [MapLoc].Data [PixLoc++] = -2;
		}
		Pix->List [MapLoc].Data [PixLoc++] = -2;	// for overflow...
	}
}

// =============================================================================
// -----------------------------------------------------------------------------
// Converting a pixel list into 68k instructions
// -----------------------------------------------------------------------------

#define G68K(STR,...)\
{\
	CodeLoc += snprintf (&Code [CodeLoc], CodeSize-CodeLoc, STR, ##__VA_ARGS__);\
}

#define ODD(REG) ((REG)&1)

bool Generate68k (PIXLIST Pix, char *&Code, int Slot, int &StartLoc, int &FinishLoc, bool ThoroughCode)

{
	int *a1 = Pix.Data;
	while (Slot > 0)
	{
		while (*a1 != -2)	// finding the end of the routine
		{
			a1++;
		}
		a1++;
		Slot--;
	}

	Code = NULL;
	int CodeSize = 0;
	int CodeLoc = 0;

	int *a2 = a1;
	int a0 = *a2++;
	if (*a2 != -2)
	{
		int Size = 0;
		StartLoc = a0;
		FinishLoc = a0;
		while (*a2 != -2)
		{
			if (*a2 != a0++)
			{
				break;
			}
			a2++;
			Size++;
		}
		if (*a2 == -2)
		{
			FinishLoc = a0;
			if ((CodeLoc + 0x100) > CodeSize)
			{
				CodeSize <<= 1;
				if (CodeSize == 0) { CodeSize = 0x200; }
				char *New = (char*) realloc (Code, CodeSize);
				if (New == NULL)
				{
					free (Code); Code = NULL;
					printf ("    Error, could not allocate memory for 68k code string...\n");
					return (TRUE);
				}
				Code = New;
			}
			int Longs = Size / 4;
			int Words = (Size - ((Size / 4) * 4)) / 2;
			while (Longs-- > 0)
			{
				if ((CodeLoc + 0x100) > CodeSize)
				{
					CodeSize <<= 1;
					if (CodeSize == 0) { CodeSize = 0x200; }
					char *New = (char*) realloc (Code, CodeSize);
					if (New == NULL)
					{
						free (Code); Code = NULL;
						printf ("    Error, could not allocate memory for 68k code string...\n");
						return (TRUE);
					}
					Code = New;
				}
				G68K (	"		move.l	(a0)+,(a5)\r\n");
			}
			while (Words-- > 0)
			{
				if ((CodeLoc + 0x100) > CodeSize)
				{
					CodeSize <<= 1;
					if (CodeSize == 0) { CodeSize = 0x200; }
					char *New = (char*) realloc (Code, CodeSize);
					if (New == NULL)
					{
						free (Code); Code = NULL;
						printf ("    Error, could not allocate memory for 68k code string...\n");
						return (TRUE);
					}
					Code = New;
				}
				G68K (	"		move.w	(a0)+,(a5)\r\n");
			}
			G68K (	"		rts\r\n");
			a2 += 1;
			if (*a2 == -2)
			{
				return (TRUE);
			}
			return (FALSE);
		}
	}





	int d3 = 0;
	int d0 [3] = { 0 };
	a0 = *a1++;
	StartLoc = a0;
	FinishLoc = a0;
	while (a1 [0] != -2)	// && a1 [2] != -2)
	{
		if ((CodeLoc + 0x100) > CodeSize)
		{
			CodeSize <<= 1;
			if (CodeSize == 0) { CodeSize = 0x200; }
			char *New = (char*) realloc (Code, CodeSize);
			if (New == NULL)
			{
				free (Code); Code = NULL;
				printf ("    Error, could not allocate memory for 68k code string...\n");
				return (TRUE);
			}
			Code = New;
		}

		if (ThoroughCode == TRUE)
		{
			if ((a1 [0] != -1 && a1 [1] != -1) && a1 [0] == a1 [1])
			{
				if (	d0 [2] != -1	)
				{
					G68K (	"		moveq	#$00,d0\r\n");
					d0 [0] = -1;
					d0 [1] = -1;
					d0 [2] = -1;
					d0 [3] = -1;
				}
				G68K (	"		move.b	%.0d(a0),d0\r\n"
					"		move.w	d0,d3\r\n"
					"		lsl.w	#$04,d0\r\n"
					"		rol.b	#$04,d3\r\n"
					"		ror.w	#$04,d3\r\n"
					"		or.w	d3,d0\r\n", a1 [0] - a0);
				d3 = 0;
				d0 [2] = 0;
				d0 [3] = 0;
				G68K (	"		move.w	d0,(a5)\r\n");
				a1 += 2;
				continue;
			}
			if ((a1 [1] != -1 && a1 [2] != -1) && a1 [1] == a1 [2])
			{
				if (	d0 [0] != -1	&&
					d0 [1] != -1	&&
					d0 [2] != -1	&&
					d0 [3] != -1	)
				{
					G68K (	"		moveq	#$00,d0\r\n");
					d0 [0] = -1;
					d0 [1] = -1;
					d0 [2] = -1;
					d0 [3] = -1;
				}
				if (a1 [0] != -1)
				{
					G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [0] - a0);
					G68K (	"		swap	d0\r\n");
					d0 [0] = 0;
				}
				G68K (	"		move.b	%.0d(a0),d0\r\n"
					"		move.w	d0,d3\r\n"
					"		lsl.w	#$04,d0\r\n"
					"		rol.b	#$04,d3\r\n"
					"		ror.w	#$04,d3\r\n"
					"		or.w	d3,d0\r\n", a1 [1] - a0);
				d3 = 0;
				G68K (	"		lsl.l	#$08,d0\r\n");
				if (a1 [3] != -1)
				{
					G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [3] - a0);
					d0 [3] = 0;
				}
				d0 [1] = 0;
				d0 [2] = 0;
				G68K (	"		move.l	d0,(a5)\r\n");
				a1 += 4;
				continue;
			}
		}

		if (a1 [0] == -1)
		{
			if (a1 [1] == -1)
			{
				if (a1 [2] == -1)
				{
					if (a1 [3] == -1)
					{
						G68K (	"		move.l	d2,(a5)\r\n");
						a1 += 4;
					}
					else
					{
						if (	d0 [0] != -1	||
							d0 [1] != -1	||
							d0 [2] != -1	)
						{
							G68K (	"		moveq	#$00,d0\r\n");
							d0 [0] = -1;
							d0 [1] = -1;
							d0 [2] = -1;
							d0 [3] = -1;
						}
						G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [3] - a0);
						d0 [3] = 0;
						G68K (	"		move.l	d0,(a5)\r\n");
						a1 += 4;
					}
				}
				else
				{
					if (a1 [3] == -1 && a1 [2] != -2)
					{
						if (	d0 [0] != -1	||
							d0 [1] != -1	)
						{
							G68K (	"		moveq	#$00,d0\r\n");
							d0 [0] = -1;
							d0 [1] = -1;
							d0 [2] = -1;
							d0 [3] = -1;
						}
						if (ODD (a1 [2]) == 0)
						{
							G68K (	"		move.w	%.0d(a0),d0\r\n", a1 [2] - a0);
						}
						else
						{
							G68K (	"		movep.w	%d(a0),d0\r\n", a1 [2] - a0);
						}
						d0 [2] = 0;
						G68K (	"		sf.b	d0\r\n");
						d0 [3] = -1;
						G68K (	"		move.l	d0,(a5)\r\n");
						a1 += 4;
					}
					else
					{
						G68K (	"		move.w	d2,(a5)\r\n");
						a1 += 2;
					}
				}
			}
			else
			{
				if (a1 [2] == -1)
				{
					if (	d0 [2] != -1	)
					{
						G68K (	"		moveq	#$00,d0\r\n");
						d0 [0] = -1;
						d0 [1] = -1;
						d0 [2] = -1;
						d0 [3] = -1;
					}
					G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [1] - a0);
					d0 [3] = 0;
					G68K (	"		move.w	d0,(a5)\r\n");
					a1 += 2;
				}
				else
				{
					if (a1 [3] == -1 && a1 [2] != -2)
					{
						if (a1 [1] + 1 == a1 [2] && ODD (a1 [1] - 1) == 0)
						{
							G68K (	"		move.l	%.0d(a0),d0\r\n", (a1 [1] - a0) - 1);
							d0 [0] = 0;
							d0 [1] = 0;
							d0 [2] = 0;
							d0 [3] = 0;
							if (d3 != -1)
							{
								G68K (	"		move.l	d1,d3\r\n"
									"		sf.b	d3\r\n");
								d3 = -1;
							}
							G68K (	"		and.l	d3,d0\r\n");
							d0 [0] = -1;
							d0 [3] = -1;
							G68K (	"		move.l	d0,(a5)\r\n");
							a1 += 4;
						}
						else if (a1 [1] + 2 == a1 [2])
						{
							G68K (	"		movep.l	%d(a0),d0\r\n", (a1 [1] - a0) - 2);
							d0 [0] = 0;
							d0 [1] = 0;
							d0 [2] = 0;
							d0 [3] = 0;
							if (d3 != -1)
							{
								G68K (	"		move.l	d1,d3\r\n"
									"		sf.b	d3\r\n");
								d3 = -1;
							}
							G68K (	"		and.l	d3,d0\r\n");
							d0 [0] = -1;
							d0 [3] = -1;
							G68K (	"		move.l	d0,(a5)\r\n");
							a1 += 4;
						}
						else
						{
							if (	d0 [2] != -1	)
							{
								G68K (	"		moveq	#$00,d0\r\n");
								d0 [0] = -1;
								d0 [1] = -1;
								d0 [2] = -1;
								d0 [3] = -1;
							}
							G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [1] - a0);
							d0 [3] = 0;
							G68K (	"		move.w	d0,(a5)\r\n");
							a1 += 2;
						}
					}
					else
					{
						if (a1 [1] + 1 == a1 [2] && ODD (a1 [1] - 1) == 0)
						{
							G68K (	"		move.l	%.0d(a0),d0\r\n", (a1 [1] - a0) - 1);
							d0 [0] = 0;
							d0 [1] = 0;
							d0 [2] = 0;
							d0 [3] = 0;
							G68K (	"		and.l	d1,d0\r\n");
							d0 [0] = -1;
							if (a1 [1] + 2 != a1 [3])
							{
								G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [3] - a0);
							}
							G68K (	"		move.l	d0,(a5)\r\n");
							a1 += 4;
						}
						else if (a1 [1] + 2 == a1 [2])
						{
							G68K (	"		movep.l	%d(a0),d0\r\n", (a1 [1] - a0) - 2);
							d0 [0] = 0;
							d0 [1] = 0;
							d0 [2] = 0;
							d0 [3] = 0;
							G68K (	"		and.l	d1,d0\r\n");
							d0 [0] = -1;
							if (a1 [1] + 4 != a1 [3])
							{
								G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [3] - a0);
							}
							G68K (	"		move.l	d0,(a5)\r\n");
							a1 += 4;
						}
						else
						{
							if (	d0 [2] != -1	)
							{
								G68K (	"		moveq	#$00,d0\r\n");
								d0 [0] = -1;
								d0 [1] = -1;
								d0 [2] = -1;
								d0 [3] = -1;
							}
							G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [1] - a0);
							d0 [3] = 0;
							G68K (	"		move.w	d0,(a5)\r\n");
							a1 += 2;
						}
					}
				}
			}
		}
		else
		{
			if (a1 [1] == -1)
			{
				if (ODD (a1 [0]) == 0)
				{
					G68K (	"		move.w	%.0d(a0),d0\r\n", a1 [0] - a0);
				}
				else
				{
					G68K (	"		movep.w	%d(a0),d0\r\n", a1 [0] - a0);
				}
				d0 [2] = 0;
				G68K (	"		sf.b	d0\r\n");
				d0 [3] = -1;
				G68K (	"		move.w	d0,(a5)\r\n");
				a1 += 2;
			}
			else
			{
				if (a1 [2] == -1 || a1 [3] == -1 || a1 [2] == -2)
				{
					if (a1 [0] + 1 == a1 [1] && ODD (a1 [0]) == 0)
					{
						G68K (	"		move.w	%.0d(a0),(a5)\r\n", a1 [0] - a0);
						a1 += 2;
					}
					else if (a1 [0] + 2 == a1 [1])
					{
						G68K (	"		movep.w	%d(a0),d0\r\n", a1 [0] - a0);
						d0 [2] = 0;
						d0 [3] = 0;
						G68K (	"		move.w	d0,(a5)\r\n");
						a1 += 2;
					}
					else
					{
						if (ODD (a1 [0]) == 0)
						{
							G68K (	"		move.w	%.0d(a0),d0\r\n", a1 [0] - a0);
						}
						else
						{
							G68K (	"		movep.w	%d(a0),d0\r\n", a1 [0] - a0);
						}
						d0 [2] = 0;
						G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [1] - a0);
						d0 [3] = 0;
						G68K (	"		move.w	d0,(a5)\r\n");
						a1 += 2;
					}
				}
				else
				{
					if (a1 [0] + 1 == a1 [1] && a1 [0] + 2 == a1 [2] && a1 [0] + 3 == a1 [3] && ODD (a1 [0]) == 0)
					{
						G68K (	"		move.l	%.0d(a0),(a5)\r\n", a1 [0] - a0);
						a1 += 4;
					}
					else if (a1 [0] + 2 == a1 [1] && a1 [0] + 4 == a1 [2] && a1 [0] + 6 == a1 [3])
					{
						G68K (	"		movep.l	%d(a0),d0\r\n", a1 [0] - a0);
						d0 [0] = 0;
						d0 [1] = 0;
						d0 [2] = 0;
						d0 [3] = 0;
						G68K (	"		move.l	d0,(a5)\r\n");
						a1 += 4;
					}
					else if (a1 [0] + 1 == a1 [1] && ODD (a1 [0]) == 0)
					{
						G68K (	"		move.w	%.0d(a0),(a5)\r\n", a1 [0] - a0);
						a1 += 2;
					}
					else if (a1 [0] + 2 == a1 [1] && ODD (a1 [0]) == 0)
					{
						G68K (	"		movep.w	%d(a0),d0\r\n", a1 [0] - a0);
						d0 [2] = 0;
						d0 [3] = 0;
						G68K (	"		move.w	d0,(a5)\r\n");
						a1 += 2;
					}
					else
					{
						if (ODD (a1 [0]) == 0)
						{
							G68K (	"		move.w	%.0d(a0),d0\r\n", a1 [0] - a0);
						}
						else
						{
							G68K (	"		movep.w	%d(a0),d0\r\n", a1 [0] - a0);
						}
						d0 [2] = 0;
						G68K (	"		move.b	%.0d(a0),d0\r\n", a1 [1] - a0);
						d0 [3] = 0;
						G68K (	"		move.w	d0,(a5)\r\n");
						a1 += 2;
					}
				}
			}
		}
	}
	G68K (	"		rts\r\n");
	a1 += 1;
	if (*a1 == -2)
	{
		return (TRUE);
	}
	return (FALSE);
}

// =============================================================================
// -----------------------------------------------------------------------------
// Main routine
// -----------------------------------------------------------------------------

int main (int ArgNumber, char **ArgList, char **EnvList)

{
	printf ("Film Generator - by MarkeyJester\n\n");
	if (ArgNumber <= 1)
	{
		printf (" -> Pass one or more \"film texture map\" image files to this program to\n"
			"    generate draw code and sprite mappings.\n"
			"\n"
			"    \"film texture map\" images are just bitmaps with pixel colours in BGR\n"
			"    order 000000 upwards to specify where the pixels are to be drawn to the\n"
			"    shape.\n"
			"\nPress enter key to exit...\n");
		fflush (stdin); getchar ( ); return (0x00);
	}

// -----------------------------------------------------------------------------
// File loading/processing loop
// -----------------------------------------------------------------------------

	IMG Image;
	MAPSPRITE MapList [ArgNumber - 1] = { 0 };
	PIXMASTER PixMaster [ArgNumber - 1] = { 0 };
	int TotalSprites = 0;
	int TotalPixels = 0;
	bool Fail = FALSE;
	int MapLoc = 0;
	for (int ArgCount = 1; ArgCount < ArgNumber; ArgCount++)
	{
		FileName = Direct;
		ExtName = NULL;
		for (int Loc = 0; ; )
		{
			char Byte = ArgList [ArgCount] [Loc];
			if (Byte == '.') { ExtName = &Direct [Loc]; }
			Direct [Loc++] = Byte;
			if (Byte == '/' || Byte == '\\') { FileName = &Direct [Loc]; }
			if (Byte == 0x00)
			{
				if (ExtName == NULL) { ExtName = &Direct [--Loc]; }
				break;
			}
		}
		printf (" -> %s\n", FileName);
		int Return = ImageLoad (&Image, Direct);
		if (Return != 0)
		{
			switch (Return)
			{
				case 1: printf ("    Error; bitmap file cannot be opened\n"); break;
				case 2: printf ("    Error; bitmap allocation error\n"); break;
				case 3: printf ("    Error; bitmap fread didn't copy full size\n"); break;
				case 4: printf ("    Error; bitmap pixel format not supported\n"); break;
				case 5: printf ("    Error; bitmap image is not a valid \"BM\" format\n"); break;
				case 6: printf ("    Error; bitmap compression not supported\n"); break;
			}
			printf ("    Skipping file...\n");
		//	printf ("    Press enter to continue..."); fflush (stdin); getchar ( );
			continue;
		}
		FlipImage (&Image);
		ProcessFilm (Image, &MapList [MapLoc], &PixMaster [MapLoc]);
		if (MapList [MapLoc].Map == NULL)
		{
			free (Image.Data); Image.Data = NULL;
			printf ("    Skipping file...\n");
		//	printf ("    Press enter to continue..."); fflush (stdin); getchar ( );
			continue;
		}
		int PixelCount = 0;
		for (int PixLoc = 0; PixLoc < PixMaster [MapLoc].Pieces; PixLoc++)
		{
			PixelCount += PixMaster [MapLoc].List [PixLoc].Size;
		}
		printf ("    Sprites:  %d ($%X)\n", MapList [MapLoc].Size, MapList [MapLoc].Size);
		printf ("    Pixels:   $%X\n", PixelCount);
		TotalSprites += MapList [MapLoc].Size;
		TotalPixels += PixelCount;
		MapLoc++;

		free (Image.Data); Image.Data = NULL;
	}
	int MapSize = MapLoc;
	printf ("\n"
		"  Total sprite pieces = %d ($%X)\n"
		"  Total pixels        = $%X\n", TotalSprites, TotalSprites, TotalPixels);

// -----------------------------------------------------------------------------
// Creating render subroutines
// -----------------------------------------------------------------------------

	int RoutSize = 0;
	for (int MapLoc = 0; MapLoc < MapSize; MapLoc++)
	{
		RoutSize += (PixMaster [MapLoc].Pieces * 4) + 1;
	}
	char *Routines [RoutSize] = { 0 };
	RoutSize = 0;

	char Text [0x1000];
	FILE *File = fopen ("RenderFilm.asm", "wb");

	fputs ( "; ===========================================================================\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"; Film rendering subroutines (Generated by \"Film Gen.exe\")\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"\r\n"
		"RenderFilm:\r\n", File);
	for (int MapLoc = MapSize-1; MapLoc >= 0; MapLoc--) // DOING IN REVERSE AS THE ANIMATION IS BACKWARDS!
	{
		snprintf (Text, 0x1000, "		dc.l	RendFrame%0.3d-RenderFilm\r\n", MapLoc);
		fputs (Text, File);
	}
	fputs ( "\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"; Frames...\r\n"
		"; ---------------------------------------------------------------------------\r\n", File);

	for (int MapLoc = 0; MapLoc < MapSize; MapLoc++)
	{
		snprintf (Text, 0x1000, "\r\nRendFrame%0.3d:\r\n", MapLoc);
		fputs (Text, File);
		if (MapLoc == 0)
		{
			fputs (	"		move.l	a0,d0\r\n"
				"		and.l	d1,d0\r\n"
				"		lsr.l	#$01,d0\r\n"
#if QUALITY==FALSE
				"		lea	$280(a0),a0\r\n"
				"		move.l	#$94019340,(a6)		; $280 size\r\n"
#else
				"		lea	$500(a0),a0\r\n"
				"		move.l	#$94029380,(a6)		; $280 size\r\n"
				"		move.w	#$8F01,(a6)		; keep only even bytes\r\n"
#endif
				"		move.l	#$96009500,-(sp)\r\n"
				"		move.w	#$9700,-(sp)\r\n"
				"		movep.l	d0,-$01(sp)\r\n"
				"		move.l	(sp)+,(a6)\r\n"
				"		move.w	(sp),(a6)\r\n"
				"		move.l	d4,d0\r\n"
				"		swap	d0\r\n"
				"		move.w	d0,(a6)\r\n"
				"		swap	d0\r\n"
				"		tas.b	d0\r\n"
				"		move.w	d0,(sp)\r\n"
				"		move.w	(sp)+,(a6)\r\n"
#if QUALITY==TRUE
				"		move.w	#$8F02,(a6)		; restore auto-increment\r\n"
#endif
				"		addi.l	#$02800000,d4\r\n"
				"		rts\r\n", File);
			continue;
		}
		int PrevLoc = 0;
		int TransSize = 0;
		for (int PixLoc = 0; PixLoc < PixMaster [MapLoc].Pieces; PixLoc++)
		{
			PIXLIST Pix = PixMaster [MapLoc].List [PixLoc];
			TransSize += Pix.PixCount;
			int Slot = 0;
			bool Finish = FALSE;
			while (Finish == FALSE)
			{
				int StartLoc, FinishLoc;
				bool ThoroughCode = FALSE;
				if (MapLoc == 12)
				{
					ThoroughCode = TRUE;
				}
				Finish = Generate68k (Pix, Routines [RoutSize], Slot++, StartLoc, FinishLoc, ThoroughCode);
				if (PrevLoc != StartLoc)
				{
					if ((StartLoc - PrevLoc) > 8 || (StartLoc - PrevLoc) < -8)
					{
						snprintf (Text, 0x1000, "		lea	%.0d(a0),a0\r\n", StartLoc - PrevLoc);
					}
					else if (StartLoc < PrevLoc)
					{
						snprintf (Text, 0x1000, "		subq.w	#%.0d,a0\r\n", PrevLoc - StartLoc);
					}
					else
					{
						snprintf (Text, 0x1000, "		addq.w	#%.0d,a0\r\n", StartLoc - PrevLoc);
					}
					fputs (Text, File);
				}
				PrevLoc = FinishLoc;
				int RoutLoc = -1;
				while (++RoutLoc < RoutSize)
				{
					if (Routines [RoutLoc] [0] & 0xFF == 0x80) { continue; }
					if (Routines [RoutLoc] [0] & 0xFF == 0xC0) { continue; }
					int Loc = 0;
					for ( ; Routines [RoutLoc] [Loc] != 0 && Routines [RoutSize] [Loc] != 0; Loc++)
					{
						if (Routines [RoutLoc] [Loc] != Routines [RoutSize] [Loc]) { break; }
					}
					if (Routines [RoutLoc] [Loc] == Routines [RoutSize] [Loc])
					{
						Routines [RoutSize] [0] = 0x80;
						Routines [RoutSize] [1] = RoutLoc >> 0x18;
						Routines [RoutSize] [2] = RoutLoc >> 0x10;
						Routines [RoutSize] [3] = RoutLoc >> 0x08;
						Routines [RoutSize] [4] = RoutLoc >> 0x00;
						break;
					}
				}
				snprintf (Text, 0x1000, "		jsrl	RendFilm%0.3d,d3\r\n", RoutLoc);
				fputs (Text, File);
				if (Finish == TRUE && (PixLoc + 1) >= PixMaster [MapLoc].Pieces)
				{
#if QUALITY==FALSE
					StartLoc = 0x280;
					FinishLoc = 0x280;
#else
					StartLoc = 0x500;
					FinishLoc = 0x500;
#endif
					if (PrevLoc != StartLoc)
					{
						if ((StartLoc - PrevLoc) > 8 || (StartLoc - PrevLoc) < -8)
						{
							snprintf (Text, 0x1000, "		lea	%.0d(a0),a0\r\n", StartLoc - PrevLoc);
						}
						else if (StartLoc < PrevLoc)
						{
							snprintf (Text, 0x1000, "		subq.w	#%.0d,a0\r\n", PrevLoc - StartLoc);
						}
						else
						{
							snprintf (Text, 0x1000, "		addq.w	#%.0d,a0\r\n", StartLoc - PrevLoc);
						}
						fputs (Text, File);
					}
					PrevLoc = FinishLoc;

					snprintf (Text, 0x1000, "		addi.l	#$%0.8X,d4\r\n"
								"		rts\r\n", TransSize << 0x10);
					fputs (Text, File);
			//		snprintf (Text, 0x1000, "		jmpl	RendFilm%0.3d,d3\r\n", RoutLoc);
				}
				else
				{
			//		snprintf (Text, 0x1000, "		jsrl	RendFilm%0.3d,d3\r\n", RoutLoc);
				}
			//	fputs (Text, File);
				RoutSize++;
			}
		}
		Routines [RoutSize] = (char*) malloc (100);
		Routines [RoutSize++] [0] = 0xC0;

	/*	printf ("%X sprites\n", MapList [MapLoc].Size);
		for (int Loc = 0; Loc < MapList [MapLoc].Size; Loc++)
		{
			printf ("Y %0.4X S %0.2X00 P %0.4X X %0.4X\n",
				MapList [MapLoc].Map [Loc].Y & 0xFFFF,
				(MapList [MapLoc].Map [Loc].S & 0x0F) << 0x08,
				MapList [MapLoc].Map [Loc].P & 0xFFFF,
				MapList [MapLoc].Map [Loc].X & 0xFFFF);
		}	*/
	}

	fputs ( "\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"; Routines...\r\n"
		"; ---------------------------------------------------------------------------\r\n", File);

	bool New = TRUE;
	for (int RoutLoc = 0; RoutLoc < RoutSize; RoutLoc++)
	{
		if ((Routines [RoutLoc] [0] & 0xFF) == 0xC0)
		{
			New = TRUE;
			continue;
		}
		if (New == TRUE)
		{
		//	snprintf (Text, 0x1000, "\r\n; New frame\r\n\r\n");
		//	fputs (Text, File);
			New = FALSE;
		}
		if ((Routines [RoutLoc] [0] & 0xFF) == 0x80)
		{
			int AltLoc = Routines [RoutLoc] [1] << 0x18;
			AltLoc |= (Routines [RoutLoc] [2] & 0xFF) << 0x10;
			AltLoc |= (Routines [RoutLoc] [3] & 0xFF) << 0x08;
			AltLoc |= (Routines [RoutLoc] [4] & 0xFF) << 0x00;
		//	snprintf (Text, 0x1000, "\r\n	; Copy of %d\r\n\r\n", AltLoc);
		//	fputs (Text, File);
		}
		else
		{
			snprintf (Text, 0x1000, "\r\nRendFilm%0.3d:\r\n", RoutLoc);
			fputs (Text, File);
			fputs (Routines [RoutLoc], File);
		}
		free (Routines [RoutLoc]); Routines [RoutLoc] = NULL;
	}
	fputs ( "\r\n; ===========================================================================\r\n", File);
	fclose (File);






		// --- Now the mappings ---



	File = fopen ("MapFilm.asm", "wb");
	fputs ( "; ===========================================================================\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"; Film mappings (Generated by \"Film Gen.exe\")\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"\r\n"
		"MapFilm:\r\n", File);
	for (int MapLoc = MapSize-1; MapLoc >= 0; MapLoc--) // DOING IT IN REVERSE AS ANIMATION IS BACKWARDS!!
	{
		int MapPos;
		for (MapPos = 0; MapPos < MapLoc; MapPos++)
		{
			if (MapList [MapLoc].Size == MapList [MapPos].Size)
			{
				int Loc;
				for (Loc = 0; Loc < MapList [MapLoc].Size; Loc++)
				{
					if (	(MapList [MapPos].Map [Loc].Y & 0xFFFF) != (MapList [MapLoc].Map [Loc].Y & 0xFFFF)	||
						(MapList [MapPos].Map [Loc].S & 0xFFFF) != (MapList [MapLoc].Map [Loc].S & 0xFFFF)	||
						(MapList [MapPos].Map [Loc].P & 0xFFFF) != (MapList [MapLoc].Map [Loc].P & 0xFFFF)	||
						(MapList [MapPos].Map [Loc].X & 0xFFFF) != (MapList [MapLoc].Map [Loc].X & 0xFFFF)	)
					{
						break;
					}
				}
				if (Loc >= MapList [MapLoc].Size)
				{
					MapList [MapLoc].Size = -MapPos;
					break;
				}
			}
		}
		snprintf (Text, 0x1000, "		dc.l	MapFilm%0.3d-MapFilm\r\n", MapPos);
		fputs (Text, File);
	}
	fputs ( "MapFilm_End:\r\n"
		"\r\n"
		"; ---------------------------------------------------------------------------\r\n"
		"; Mapping data\r\n"
		"; ---------------------------------------------------------------------------\r\n", File);

	for (int MapLoc = 0; MapLoc < MapSize; MapLoc++)
	{
		if (MapList [MapLoc].Size >= 0)
		{
			snprintf (Text, 0x1000, "\r\nMapFilm%0.3d:	dc.w	$%0.4X\r\n", MapLoc, MapList [MapLoc].Size & 0xFFFF);
			fputs (Text, File);
			for (int Loc = 0; Loc < MapList [MapLoc].Size; Loc++)
			{
				snprintf (Text, 0x1000, "		dc.w	$%0.4X,$%0.4X,$%0.4X,$%0.4X\r\n",
					MapList [MapLoc].Map [Loc].Y & 0xFFFF,
					(MapList [MapLoc].Map [Loc].S & 0x0F) << 0x08,
					MapList [MapLoc].Map [Loc].X & 0xFFFF,
					MapList [MapLoc].Map [Loc].P & 0xFFFF);
				fputs (Text, File);
			}
		}
	}
	fputs ( "\r\n; ===========================================================================\r\n", File);
	fclose (File);

// -----------------------------------------------------------------------------
// Finish/clean-up
// -----------------------------------------------------------------------------

	for (int MapLoc = 0; MapLoc < MapSize; MapLoc++)
	{
		free (MapList [MapLoc].Map); MapList [MapLoc].Map = NULL;
		if (PixMaster [MapLoc].List != NULL)
		{
			for (int PixLoc = 0; PixLoc < PixMaster [MapLoc].Pieces; PixLoc++)
			{
 				free (PixMaster [MapLoc].List [PixLoc].Data); PixMaster [MapLoc].List [PixLoc].Data = NULL;
			}
			free (PixMaster [MapLoc].List); PixMaster [MapLoc].List = NULL;
		}


	}
	printf ("\nPress enter key to exit...\n");
	fflush (stdin); getchar ( ); return (0x00);
}

// =============================================================================
