/*************************************************************************
 * FastSprite Example Code
 *
 * File: convimg.c
 *
 * This file contains a tool to convert "BMP" format images to C++ files
 * containing "Image" objects 
 *
 * Copyright (c) Digital Nemesis Pty Ltd, 1999. All Rights Reserved
 * Permission is granted to use and distribute this document and related
 * source code free of charge provided this and all
 * similar messages and copyrights in the related files remains intact.
 *************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

//------------------------------------------------------------------------
// IMPUT DESCRIPTION
//
// This program takes an image and an optional mask as Windows bitmap files
// (BMP). The image must be 24 bits per pixel, the mask monochrome (1 bit
// per pixel)
//
//
// OUTPUT DESCRIPTION
//
// This program outputs 2 files, a .cpp and a .h file.
//
// the .h file will define static varables which are instantiated in the .cpp
// file.
//
// The purpose of this is to be able to create a header file with a struct
// with the name of the given scope and then include the header files as the
// contents of the struct to define elements of the structure.
//
// The .cpp files are then added to the project and compiled and the values
// from them are then accessible from the given scoping structure.
//
//-------------------------------------------------------------------------


// Define the name of the type used for an image
#define IMG_TYPE_NAME "Image"
#define BITS_TYPE_NAME "ImageBits"
#define CODES_TYPE_NAME "ImageCodes"

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

// global variables 
char*	pszInImageFileName = NULL;	// name of the image input file
char*	pszInMaskFileName = NULL;	// name of the mask file
char*	pszVarName = NULL;		// name of the generated variable
char*	pszScopeName = NULL;		// name of the "scope" or class this is to belong to
int	nWidth = 0;			// width and height of image
int	nHeight = 0;				


int ParseArgs(int argc, char** argv);
void Usage(char *pszProgName);

int LoadBMP24(char* pszFileName, BITMAPINFO** pBmInfo, unsigned char** pBmBits);
int LoadBMP1(char* pszFileName, BITMAPINFO** pBmInfo, unsigned char** pBmBits);

void WriteHeaderFile(FILE* fout);
void WriteFileHeader(FILE* fout);
void WriteImage(FILE* fout);
void WriteBitsHeader(FILE* fout);
void WriteBitsFooter(FILE* fout);
void WriteCodesHeader(FILE* fout);
void WriteCodesFooter(FILE* fout);
void WriteColour(FILE* fout, unsigned char Red, unsigned char Green, unsigned char Blue);
void WriteCode(FILE* fout, short pixelCode);

int ProcessMask(BITMAPINFO* pBmInfo, unsigned char* pBmBits, short** Codes);
int ReadMonoBMP(int x, int y, BITMAPINFO* pBmInfo, unsigned char* pBmBits);
void InvertBMP(BITMAPINFO* pBmInfo, unsigned char* pBmBits);

int main(int argc, char** argv)
{
	FILE*	fout;
	long	count = 0;
	char	szName[200];
	BITMAPINFO		*ImgBMI = NULL, *MskBMI = NULL;
	unsigned char	*ImgBits = NULL, *MskBits = NULL;
	short			*Codes = NULL;
	int				code, Offset, Width, PadBytes;

	// parse the command line
	if( ! ParseArgs( argc, argv ) ) {
		Usage( "ConvImage" );
		return 1;
	}


	// print info
	if (pszInMaskFileName != NULL )
		printf( "Processing: %s & %s -> %s.cpp %s.h\n", pszInImageFileName, pszInMaskFileName, pszVarName, pszVarName );
	else
		printf( "Processing: %s  -> %s.cpp %s.h\n", pszInImageFileName, pszVarName, pszVarName );


	// load the image file
	if(! LoadBMP24(pszInImageFileName, &ImgBMI, &ImgBits) ) {
		printf("Failed to load Image file %s\n", pszInImageFileName);
		return 1;
	}

	// get the size of the image
	nWidth = ImgBMI->bmiHeader.biWidth;
	nHeight = ImgBMI->bmiHeader.biHeight;

	// load the mask file if there is one
	if (pszInMaskFileName != NULL ) {
		if(! LoadBMP1(pszInMaskFileName, &MskBMI, &MskBits) ) {
			printf("Failed to load Mask file %s\n", pszInImageFileName);
			return 1;
		}

		// check that the sizes match
		if(MskBMI->bmiHeader.biWidth != nWidth || MskBMI->bmiHeader.biHeight != nHeight) {
			printf("Image and Mask sizes differ\n");
			return 1;
		}

		// process the codes to make the "transparency" mask so we can then
		// take only the pixels we need
		if(! ProcessMask(MskBMI, MskBits, &Codes) ) {
			printf("Failed to build Codes from Mask\n");
			return 1;
		}
	}


	// Generate the .cpp file
	sprintf(szName, "%s.cpp", pszVarName);
	fout = fopen( szName, "w" );
	if( fout == NULL ) {
		printf("Failed to open %s\n", szName);
		return 3;
	}

	// write the includes
	WriteFileHeader(fout);

	// write the header for the codes (if any)
	if( pszInMaskFileName != NULL ) {
		WriteCodesHeader(fout);
	
		code = 0;
		while(! (Codes[code] == 0 && Codes[code+1] == 0) ) {
			WriteCode(fout, Codes[code]);
			code++;
		}
		
		// write the missed 0
		WriteCode(fout, 0);
		
		WriteCodesFooter(fout);
	}

	// write the header info into the output file
	WriteBitsHeader(fout);

	if( pszInMaskFileName != NULL ) {
		// calculate the width in Bytes for the image scanline
		// (padded to DWORD boundary)
		Width = ((ImgBMI->bmiHeader.biWidth*3) + 3) & ~3;

		// calculate the number of pad bytes at the end of a line
		PadBytes = Width - (ImgBMI->bmiHeader.biWidth * 3);

		// write the bits out by processing the codes
		code = 0;
		Offset = 0;
		while(! (Codes[code] == 0 && Codes[code+1] == 0) ) {
			// Is this a transparent code or a normal pixel
			// do nothing if it is an end of line
			if( Codes[code] < 0 ) {
				// transparent
				count = - Codes[code];
				
				// skip count pixels
				Offset += count * 3;
			} else if( Codes[code] > 0 ) {
				// normal
				count = Codes[code];

				// add count pixels to the data stream
				while(count > 0) {
					WriteColour(fout, ImgBits[Offset+2], ImgBits[Offset+1], ImgBits[Offset]);
					Offset += 3;
					count--;
				}
			} else if( Codes[code] == 0 ) {
				// skip over the pad bytes in the image
				Offset += PadBytes;
			}

			code++;
		}
	} else {
		// how many pixels are there
		count = nWidth * nHeight;
		Offset = 0;
		while(count > 0) {
			WriteColour(fout, ImgBits[Offset+2], ImgBits[Offset+1], ImgBits[Offset]);
			Offset += 3;
			count--;
		}
	}

	// write the footer to the output file
	WriteBitsFooter(fout);


	// write the image type
	WriteImage(fout);

	// close the files
	fclose( fout );
	

	// Generate the .h file
	sprintf(szName, "%s.h", pszVarName);
	fout = fopen( szName, "w" );
	if( fout == NULL ) {
		printf("Failed to open %s\n", szName);
		return 4;
	}

	WriteHeaderFile(fout);

	fclose( fout );

	// free the allocated memory
	if(ImgBMI != NULL)
		free(ImgBMI); 
	if(MskBMI != NULL)
		free(MskBMI);
	if(ImgBits != NULL)
		free(ImgBits);
	if(MskBits != NULL)
		free(MskBits);

	if(Codes != NULL)
		free(Codes);

	// exit cleanly
	return 0;
}

// write the contents of the .h file.
void WriteHeaderFile(FILE* fout)
{
	//fprintf(fout, "static %s %s::%s_bits[];\n", BITS_TYPE_NAME, pszScopeName, pszVarName);

	//if(pszInMaskFileName != NULL)
	//	fprintf(fout, "static %s %s::%s_codes[];\n", CODES_TYPE_NAME, pszScopeName, pszVarName);

	fprintf(fout, "static %s %s::%s;\n", IMG_TYPE_NAME, pszScopeName, pszVarName);
}

// write a file header. If bHeaderFile is true, write the header for the .h file
// otherwise write the header for the .cpp file.
void WriteFileHeader(FILE* fout)
{
	fprintf(fout, "#include \"%s.h\"\n\n", pszScopeName);

	// header comment
	fprintf(fout, "\n/* Autogenerated by ConvImage from %s ", pszInImageFileName);
	if(pszInMaskFileName != NULL)
		fprintf(fout, "and %s ", pszInMaskFileName);
	fprintf(fout, "*/\n");
}

// write the image class declaration with all the members initialised
void WriteImage(FILE* fout)
{ 
	// actual image structure
	fprintf(fout, "%s %s::%s (\n", IMG_TYPE_NAME, pszScopeName, pszVarName);
	fprintf(fout, "\t%d,\t\t/* Width */\n", nWidth);
	fprintf(fout, "\t%d,\t\t/* Height */\n", nHeight);
	fprintf(fout, "\t%d,\t\t/* Bits Per Pixel */\n", 16);
	//fprintf(fout, "\t%s::%s_bits,\t\t/* bits */\n", pszScopeName, pszVarName);
	fprintf(fout, "\t%s_bits,\t\t/* bits */\n", pszVarName);

	// codes
	if(pszInMaskFileName != NULL)
		//fprintf(fout, "\t%s::%s_codes\t\t/* codes */\n", pszScopeName, pszVarName);
		fprintf(fout, "\t%s_codes\t\t/* codes */\n", pszVarName);
	else
		fprintf(fout, "\t0L\t\t/* no codes */\n");

	fprintf(fout, ");\n");
}

// begin the bits data
void WriteBitsHeader(FILE* fout)
{ 
	//fprintf(fout, "%s %s::%s_bits[] = {\n\t", BITS_TYPE_NAME, pszScopeName, pszVarName);
	fprintf(fout, "static %s %s_bits[] = {\n\t", BITS_TYPE_NAME, pszVarName);

}

// end the bits data
void WriteBitsFooter(FILE* fout)
{ 
	fprintf(fout, "0 };\t /* 0 is a fake colour */\n");
}

// begin the codes data
void WriteCodesHeader(FILE* fout)
{ 
	//fprintf(fout, "%s %s::%s_codes[] = {\n\t", CODES_TYPE_NAME, pszScopeName, pszVarName);
	fprintf(fout, "static %s %s_codes[] = {\n\t", CODES_TYPE_NAME, pszVarName);
}

// end the codes data
void WriteCodesFooter(FILE* fout)
{ 
	fprintf(fout, "0 };\t /* 0 is the end of codes mark */\n");
}

// write a single colour to the given output file
void WriteColour(FILE* fout, unsigned char Red, unsigned char Green, unsigned char Blue)
{
	static int count = 0;
	double r, g, b;
	unsigned short R, G, B, col;

	// calculate the normalised colours
	r = ((double)Red) / 255.0;
	g = ((double)Green) / 255.0;
	b = ((double)Blue) / 255.0;

	// form the 16 bit colour value (r = 5 bits, g = 6 bits, b = 5 bits
	R = (unsigned short)(r*(double)0x1F);
	G = (unsigned short)(g*(double)0x3F);
	B = (unsigned short)(b*(double)0x1F);

	col = R << 11 | G << 5 | B;
	
	// print it
	if(count >= 5) {
		fprintf(fout, "\n\t");
		count = 0;
	} 

	count++;

	fprintf(fout, "0x%04X, ", col);
}

// write a single pixel code to the given output file
void WriteCode(FILE* fout, short pixelCode)
{

	// print it
	fprintf(fout, "%d, ", pixelCode);

	// add a new line if this is an end of line code (0)
	if(pixelCode == 0) 
		fprintf(fout, "\n\t");
}

// parse the command line argumnets into global variables
int ParseArgs(int argc, char** argv)
{
	// chech the number of args
	if(argc == 5) {
		// we have a mask as well as an image 

		// get the in file name
		pszInImageFileName = argv[1];
	
		// get the mask file name
		pszInMaskFileName = argv[2];

		// get the scope name
		pszScopeName = argv[3];

		// get the out variable name
		pszVarName = argv[4];

	} else if( argc == 4 ) {
		// we don't have a mask

		// get the in file name
		pszInImageFileName = argv[1];

		// get the scope name
		pszScopeName = argv[2];

		// get the out variable name
		pszVarName = argv[3];
	} else {
		return FALSE;
	}

	return TRUE;
}

// display usage info
void Usage(char *pszProgName)
{
	printf("Usage:\n\t%s <in file> [<mask file>] <scope name> <var name> \n\n", pszProgName);
	printf("This will generate <varname>.cpp and <varname>.h\n");
}


// Load a 24 bpp bitmap from the file pszFileName. 
// Allocate and fill a BITMAPINFO and the bits.
int LoadBMP24(char* pszFileName, BITMAPINFO** pBmInfo, unsigned char** pBmBits)
{
	BITMAPFILEHEADER	bmfh;
	BITMAPINFOHEADER	bmih;
	DWORD				dwRead;
	DWORD				nSizeOfBits;
	FILE*				fIn;

	// open the bitmap file
	fIn = fopen(pszFileName, "rb");

	if( fIn == NULL) {
		printf("\nCould not open %s\n", pszFileName);
		return FALSE;
	}

	// read the BITMAPFILEHEADER
	dwRead = fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, fIn );

	if (dwRead != 1 ) {
		fclose(fIn); 
		printf("\nRead bitmap file header failed\n");
		return FALSE;
	}


	// Retrieve the BITMAPFILEHEADER structure.
	dwRead = fread(&bmih, sizeof(BITMAPINFOHEADER), 1, fIn );

	if (dwRead != 1 ) {
		fclose(fIn); 
		printf("\nRead bitmap info header failed\n");
		return FALSE;
	}

	// make sure this is a 24 bpp bitmap
	if(bmih.biBitCount != 24) {
		fclose(fIn); 
		printf("\n%s: Not a 24 bit BMP\n", pszFileName);
		return FALSE;
	}

	// make shure this is a bottom up DIB
	if(bmih.biHeight < 0) {
		fclose(fIn); 
		printf("\n%s: Not a Bottom Up BMP\n", pszFileName);
		return FALSE;
	}

	// Allocate memory for the BITMAPINFO structure. Note there are no colour entries in this
	// file because it is 24 bit
	*pBmInfo = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER));

	// Load BITMAPINFOHEADER into the BITMAPINFO structure.
	(*pBmInfo)->bmiHeader.biSize = bmih.biSize; 
	(*pBmInfo)->bmiHeader.biWidth = bmih.biWidth; 
	(*pBmInfo)->bmiHeader.biHeight = bmih.biHeight; 
	(*pBmInfo)->bmiHeader.biPlanes = bmih.biPlanes; 
	(*pBmInfo)->bmiHeader.biBitCount = bmih.biBitCount; 
	(*pBmInfo)->bmiHeader.biCompression = bmih.biCompression; 
	(*pBmInfo)->bmiHeader.biSizeImage = bmih.biSizeImage; 
	(*pBmInfo)->bmiHeader.biXPelsPerMeter = bmih.biXPelsPerMeter; 
	(*pBmInfo)->bmiHeader.biYPelsPerMeter = bmih.biYPelsPerMeter; 
	(*pBmInfo)->bmiHeader.biClrUsed = bmih.biClrUsed; 
	(*pBmInfo)->bmiHeader.biClrImportant = bmih.biClrImportant;

	// Allocate memory for the required number of bytes.
	nSizeOfBits = bmfh.bfSize - bmfh.bfOffBits;
	*pBmBits = (unsigned char*)malloc(nSizeOfBits);  
	
	// seek to the begining of the bitmap data
	fseek(fIn, bmfh.bfOffBits, SEEK_SET);

	// read the bitmap data
	dwRead = 0;
	while(dwRead < nSizeOfBits ) {
		dwRead = dwRead + fread((*pBmBits)+dwRead, 1, nSizeOfBits-dwRead, fIn );
	}

	// close the file
	fclose(fIn);

	InvertBMP( *pBmInfo, *pBmBits );

	return TRUE;
}

// Load a Monochrome bitmap from the file pszFileName. 
// Allocate and fill a BITMAPINFO and the bits.
int LoadBMP1(char* pszFileName, BITMAPINFO** pBmInfo, unsigned char** pBmBits)
{
	BITMAPFILEHEADER	bmfh;
	BITMAPINFOHEADER	bmih;
	DWORD				dwRead;
	DWORD				nSizeOfBits;
	FILE*				fIn;

	// open the bitmap file
	fIn = fopen(pszFileName, "rb");

	if( fIn == NULL) {
		printf("\nCould not open %s\n", pszFileName);
		return FALSE;
	}

	// read the BITMAPFILEHEADER
	dwRead = fread(&bmfh, sizeof(BITMAPFILEHEADER), 1, fIn );

	if (dwRead != 1 ) {
		fclose(fIn); 
		printf("\nRead bitmap file header failed\n");
		return FALSE;
	}


	// Retrieve the BITMAPFILEHEADER structure.
	dwRead = fread(&bmih, sizeof(BITMAPINFOHEADER), 1, fIn );

	if (dwRead != 1 ) {
		fclose(fIn); 
		printf("\nRead bitmap info header failed\n");
		return FALSE;
	}

	// make shure this is a bottom up DIB
	if(bmih.biHeight < 0) {
		fclose(fIn); 
		printf("\n%s: Not a Bottom Up BMP\n", pszFileName);
		return FALSE;
	}

	// make sure this is a monochrome bitmap
	if(bmih.biBitCount != 1) {
		fclose(fIn); 
		printf("\n%s: Not a Monochrome BMP\n", pszFileName);
		return FALSE;
	}

	// Allocate memory for the BITMAPINFO structure. Note there will be 2 colours
	// and they may not equate to 0 = black, 1 = white
	*pBmInfo = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) * 2));

	// Load BITMAPINFOHEADER into the BITMAPINFO structure.
	(*pBmInfo)->bmiHeader.biSize = bmih.biSize; 
	(*pBmInfo)->bmiHeader.biWidth = bmih.biWidth; 
	(*pBmInfo)->bmiHeader.biHeight = bmih.biHeight; 
	(*pBmInfo)->bmiHeader.biPlanes = bmih.biPlanes; 
	(*pBmInfo)->bmiHeader.biBitCount = bmih.biBitCount; 
	(*pBmInfo)->bmiHeader.biCompression = bmih.biCompression; 
	(*pBmInfo)->bmiHeader.biSizeImage = bmih.biSizeImage; 
	(*pBmInfo)->bmiHeader.biXPelsPerMeter = bmih.biXPelsPerMeter; 
	(*pBmInfo)->bmiHeader.biYPelsPerMeter = bmih.biYPelsPerMeter; 
	(*pBmInfo)->bmiHeader.biClrUsed = bmih.biClrUsed; 
	(*pBmInfo)->bmiHeader.biClrImportant = bmih.biClrImportant;

	// read the colour table
	dwRead = fread(&((*pBmInfo)->bmiColors[0]), sizeof(RGBQUAD), 2, fIn );

	if (dwRead != 2 ) {
		fclose(fIn); 
		printf("\nRead Colour Table Failed!\n");
		return FALSE;
	}

	// Allocate memory for the required number of bytes.
	nSizeOfBits = bmfh.bfSize - bmfh.bfOffBits;
	*pBmBits = (unsigned char*)malloc(nSizeOfBits);  
	
	// seek to the begining of the bitmap data
	fseek(fIn, bmfh.bfOffBits, SEEK_SET);

	// read the bitmap data
	// read the bitmap data
	dwRead = 0;
	while(dwRead < nSizeOfBits ) {
		dwRead = dwRead + fread((*pBmBits)+dwRead, 1, nSizeOfBits-dwRead, fIn );
	}

	// close the file
	fclose(fIn);

	InvertBMP( *pBmInfo, *pBmBits );

	return TRUE;
}

// process the mask image into a list of drawing codes. Allocate an
// array to put the codes into.
// refer to Image.h for an explaination of how the codes work
int ProcessMask(BITMAPINFO* pBmInfo, unsigned char* pBmBits, short** Codes)
{
	int		w, h;	// current location in the image
	int		code;	// current code
	
	// allocate an approximate size of buffer to hold the codes.
	// we will assume the absolute worst case that each alternate pixel is
	// transparent, so we will need as many codes as pixels.
	*Codes = (short*)malloc(sizeof(short)*(nWidth * nHeight));

	// initialise the first code
	code = 0;
	(*Codes)[code] = 0;

	// start at the first pixel on the first line
	for(h = 0; h < pBmInfo->bmiHeader.biHeight; h++) {
		for(w = 0; w < pBmInfo->bmiHeader.biWidth; w++) {
			if((*Codes)[code] == 0) {	// new code
				if( ReadMonoBMP(w, h, pBmInfo, pBmBits) != 0 ) {	
					// normal
					(*Codes)[code] = 1; 
				} else {					
					// transparent
					(*Codes)[code] = -1;
				} 
			} else if((*Codes)[code] < 0) {	// currently transparent
				// is this a transparent or normal pixel
				if( ReadMonoBMP(w, h, pBmInfo, pBmBits) != 0 ) {	
					// normal - end of the code
					code++;
					(*Codes)[code] = 1; // start at 1 to include this pixel
				} else {					
					// transparent - include this pixel in the current code
					(*Codes)[code]--;
				}
			} else {						// currently drawing
				// is this a transparent or normal pixel
				if( ReadMonoBMP(w, h, pBmInfo, pBmBits) != 0 ) {	
					// normal - include this pixel in the current code
					(*Codes)[code]++;
				} else {					
					//  transparent- end of the code
					code++;
					(*Codes)[code] = -1; // start at -1 to include this pixel
				}
			}
		}
		// add the end of line code
		code++;
		(*Codes)[code] = 0;

		// prepare the next code as a blank one
		code++;
		(*Codes)[code] = 0;
	}

	// add the end of image code
	(*Codes)[code] = 0;

	return TRUE;
}

// read a given pixel from the MonoBitmap bits.
int ReadMonoBMP(int x, int y, BITMAPINFO* pBmInfo, unsigned char* pBmBits)
{
	// calculate the offset of the byte we need. Note that BMPs are based on
	// bmWidthBytes being even and having some unused pixels on the end of a line
	// if needed. All rows are DWORD aligned meaning they are evenly divisible by 32
	int Width;
	int Offset;
	int	Bit;
	int Val;
	
	// calculate the width in Bytes for the image
	Width = pBmInfo->bmiHeader.biWidth / 32;

	// add an extra byte for any left over bits
	if(pBmInfo->bmiHeader.biWidth % 32 != 0)
		Width = Width + 1;

	// get to the scan line we need
	Offset = Width * y * 4;	

	// get to the actual byte we need
	Offset = Offset + (x / 8);

	// calculate the bit we need. MSB = left most pixel
	Bit = 7 - (x % 8);

	Val = (pBmBits[Offset] & (1<<Bit)) >> Bit;

	// get the correct colour (sometimes sneaky programs make 1 = black)
	if( pBmInfo->bmiColors[Val].rgbRed == 0 )
		return 0;
	else
		return 1;
}

// invert the Bitmap bits so it becomes a top down image 
// normally BMP files are bottom up.
void InvertBMP(BITMAPINFO* pBmInfo, unsigned char* pBmBits)
{
	int Width, w;
	int	numRowsToSwap;
	int	TopRow, BottomRow;

	// calculate the actual width of the row in bytes
	if(pBmInfo->bmiHeader.biBitCount == 24) {
		// calculate the width in Bytes for the image scanline
		// (padded to DWORD boundary)
		Width = ((pBmInfo->bmiHeader.biWidth*3) + 3) & ~3;
	} else {
		Width = pBmInfo->bmiHeader.biWidth / 32;
		if(pBmInfo->bmiHeader.biWidth % 32 != 0)
			Width = Width + 1;
		
		Width *= 4;
	}

	// calculate the number of rows to swap
	numRowsToSwap = pBmInfo->bmiHeader.biHeight / 2;

	while(numRowsToSwap > 0) {
		// calculate the top and bottom row being worked on
		TopRow = numRowsToSwap - 1;
		BottomRow = pBmInfo->bmiHeader.biHeight - numRowsToSwap;

		// iterate accross the rows and swap the pixels
		for(w = 0; w < Width; w++) {
			unsigned char t;

			t = pBmBits[(TopRow*Width) + w];
			pBmBits[(TopRow*Width) + w] = pBmBits[(BottomRow*Width) + w];
			pBmBits[(BottomRow*Width) + w] = t;
		}

		// new rows
		numRowsToSwap--;
	}
}
