#include "texmgr.h"

BYTE bPalSwizzle[256] = {
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,

	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,

	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,

	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
};

tTextureList_t* LoadTexChunk( FILE* pChunk ) {
	tTextureList_t* pTexInfo = (tTextureList_t*)malloc( sizeof(tTextureList_t) );
	tImagedata_s* pTexList = NULL;
	char szMessage[128];
	INT iCurrentTexture, iByte = 0;
	INT iLastBackslash = 0, iLastPos = 0, iHeaderSize = 0, iCurChar = 0;

	fseek( pChunk, 2, 0 );
	fread( &iByte, 2, 1, pChunk );

	switch( iByte ) {
		case 0x0E:
			iHeaderSize = FLAG_0E;
		break;
		case 0x06:
			iHeaderSize = FLAG_06;
		break;
		case 0x00:
			iHeaderSize = FLAG_00;
		break;
		default:
			sprintf( szMessage, "Unknown chunk-header flag 0x%02x!", iByte );
			MessageBoxA( NULL, szMessage, "ERROR", MB_ICONERROR );
			return FALSE;
		break;
	}

	fseek( pChunk, iHeaderSize, 0 );
	fread( &iByte, 4, 1, pChunk );
	pTexInfo->texturenum = iByte;

	pTexList = (tImagedata_s*)malloc( pTexInfo->texturenum*sizeof(tImagedata_s) );

	fseek( pChunk, 56+iHeaderSize, 0 );
	for( iCurrentTexture = 0; iCurrentTexture < pTexInfo->texturenum; iCurrentTexture++ ) {
		fread( &iByte, 1, 1, pChunk );
		if( iByte != 0x00 ) {
			pTexList[iCurrentTexture].mode = iByte;
			fseek( pChunk, 0xB, SEEK_CUR );
			iByte = 0;
			fread( &iByte, 4, 1, pChunk );
			pTexList[iCurrentTexture].offset = iByte+iHeaderSize;
			iByte = 0;
			fread( &iByte, 2, 1, pChunk );
			pTexList[iCurrentTexture].w = iByte;
			iByte = 0;
			fread( &iByte, 2, 1, pChunk );
			pTexList[iCurrentTexture].h = iByte;
			iByte = 0;
			if( pTexList[iCurrentTexture].mode != TEX_NORMAL &&
				pTexList[iCurrentTexture].mode != TEX_NP5BPP ) {
				fseek( pChunk, 0x8, SEEK_CUR ); // Get offset to the palette if it's a palettized texture
				fread( &iByte, 4, 1, pChunk );
				pTexList[iCurrentTexture].paloffs = iByte+iHeaderSize;
				fseek( pChunk, 0x8, SEEK_CUR );
				iByte = 0;
			}
			else {
				pTexList[iCurrentTexture].paloffs = -1;
				fseek( pChunk, 0x14, SEEK_CUR );
			}

			iByte = 1;
			while( iByte != 0x00 ) {
				fread( &iByte, 1, 1, pChunk );
				pTexList[iCurrentTexture].name[iCurChar] = iByte;
				iCurChar++;
				if( iByte == 0x5C ) {
					iLastBackslash = ftell(pChunk);
					memset( pTexList[iCurrentTexture].name, 0, 64 );
				}
			}
			if( iLastBackslash ) {
				iByte = 1;
				fseek( pChunk, iLastBackslash, 0 );
				for( INT i = 0; i < 64; i++ ) {
					fread( &iByte, 1, 1, pChunk );
					pTexList[iCurrentTexture].name[i] = iByte;
					if( iByte == 0x00 ) break;
				}
			}

			if( iCurChar < 31 ) fseek( pChunk, (31-iCurChar)+1, SEEK_CUR );

			iCurChar = 0;
			if( pTexList[iCurrentTexture].mode != TEX_NORMAL &&
				pTexList[iCurrentTexture].mode != TEX_NP5BPP ) { // Read the palette
				iLastPos = ftell( pChunk ); // Memorize our current position in the file so we can go back
				fseek( pChunk, pTexList[iCurrentTexture].paloffs, 0 );
				for( INT i = 0; i < 256; i++ ) { // TODO: Different size palettes, usually it depends on how many bits are used
					fread( &iByte, 1, 1, pChunk ); // to store/read the palette color index for a pixel, and I haven't encountered >256
					pTexList[iCurrentTexture].pal[i].r = iByte;
					iByte = 0;

					fread( &iByte, 1, 1, pChunk );
					pTexList[iCurrentTexture].pal[i].g = iByte;
					iByte = 0;

					fread( &iByte, 1, 1, pChunk );
					pTexList[iCurrentTexture].pal[i].b = iByte;

					fread( &iByte, 1, 1, pChunk );
					pTexList[iCurrentTexture].pal[i].a = iByte; // no alpha?
					iByte = 0;
				}
				fseek( pChunk, iLastPos, 0 ); // Go back to our previous position
			}
		}
	}
	pTexInfo->textures = pTexList;
	return pTexInfo;
}

void GetTexture( FILE* pChunk, tImagedata_s* texture ) {
	// The provided structure holds all info needed to get the pixels for this texture

	INT iByte = 0, iAlpha = 0;
	BYTE iPalId = 0;
	INT iCurrentPixel;
	BOOL halves = FALSE;
	tPixel_s* pPixels;

	pPixels = (tPixel_s*)malloc( (texture->w*texture->h)*sizeof(tPixel_s) );

	fseek( pChunk, texture->offset, 0 );
	for( iCurrentPixel = 0; iCurrentPixel < texture->w*texture->h; iCurrentPixel++ ) {
		switch( texture->mode ) {
			case TEX_PALET: {
				fread( &iByte, 1, 1, pChunk ); // bPalSwizzle is only needed for 8bpp
				pPixels[iCurrentPixel].r = texture->pal[ bPalSwizzle[iByte] ].r;
				pPixels[iCurrentPixel].g = texture->pal[ bPalSwizzle[iByte] ].g;
				pPixels[iCurrentPixel].b = texture->pal[ bPalSwizzle[iByte] ].b;
				pPixels[iCurrentPixel].a = texture->pal[ bPalSwizzle[iByte] ].a;
			} break;
			case TEX_PAL4BPP: {
				if( !halves ) { // We're reading the first half of the byte first
					fread( &iByte, 1, 1, pChunk );
					iPalId = iByte & 0x0F;
				} // Then read the second half
				else iPalId = (iByte & 0xF0) >> 4;

				pPixels[iCurrentPixel].r = texture->pal[ iPalId ].r;
				pPixels[iCurrentPixel].g = texture->pal[ iPalId ].g;
				pPixels[iCurrentPixel].b = texture->pal[ iPalId ].b;
				pPixels[iCurrentPixel].a = texture->pal[ iPalId ].a;

				halves = !halves; // Swap so we alternate between reading first & second byte halves
			} break;
			case TEX_NP5BPP: {
				fread( &iByte, 2, 1, pChunk );
				pPixels[iCurrentPixel].r = ( ((1 << 5)-1) & (iByte >> 0) )*8;
				pPixels[iCurrentPixel].g = ( ((1 << 5)-1) & (iByte >> 5) )*8;
				pPixels[iCurrentPixel].b = ( ((1 << 5)-1) & (iByte >> 10) )*8;
				iByte = ( ((1 << 1)-1) & (iByte >> 15) ); // 1 byte for alpha , 1-  fully opaque, 0 - fully transparent
				pPixels[iCurrentPixel].a = iByte ? 255 : 0;
			} break;
			case TEX_NORMAL: {
				fread( &iByte, 1, 1, pChunk );
				pPixels[iCurrentPixel].r = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pChunk );
				pPixels[iCurrentPixel].g = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pChunk );
				pPixels[iCurrentPixel].b = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pChunk );
				pPixels[iCurrentPixel].a = iByte;
				iByte = 0;
			} break;
		}
	}
	texture->pixels = pPixels;
	texture->pixelcount = iCurrentPixel;
}

System::Drawing::Bitmap^ DrawTextureIntoABMP( FILE* pChunk, tTextureList_s* pTex, INT iTexNum ) {
	System::Drawing::Bitmap^ bmp;
	INT x, y;
	INT16 stride; //! wrong type here may be causing crashes/undef' behavior
	BYTE* dataptr;

	x = y = 0;
	GetTexture( pChunk, &pTex->textures[iTexNum] );

	bmp = gcnew System::Drawing::Bitmap( pTex->textures[iTexNum].w, pTex->textures[iTexNum].h );
	System::Drawing::Imaging::BitmapData^ bmpdata = bmp->LockBits( System::Drawing::Rectangle(0, 0, bmp->Width, bmp->Height),
		System::Drawing::Imaging::ImageLockMode::WriteOnly, System::Drawing::Imaging::PixelFormat::Format32bppArgb );

	dataptr = (BYTE*)(INT)bmpdata->Scan0;
	stride = bmpdata->Stride;
	// Faster than SetPixel()
	for( INT i = 0; i < pTex->textures[iTexNum].pixelcount; i++ ) {
		if( y > pTex->textures[iTexNum].h ) break;
		dataptr[(x*4)+y*stride] = pTex->textures[iTexNum].pixels[i].b;
		dataptr[(x*4)+y*stride+1] = pTex->textures[iTexNum].pixels[i].g;
		dataptr[(x*4)+y*stride+2] = pTex->textures[iTexNum].pixels[i].r;
		dataptr[(x*4)+y*stride+3] = pTex->textures[iTexNum].pixels[i].a;
		x++; if( x >= pTex->textures[iTexNum].w ) { x = 0; y++; }
	}
	bmp->UnlockBits( bmpdata );
	delete[] bmpdata;
	return bmp;
}

void ExportPalettized( FILE* pal, FILE* pChunk, tTextureList_s* pTex, INT iTexNum, BYTE bNumForName ) {
	char texfname[128];
	//char num[3];
	tImagedata_s* pTexture;
	FILE* texfile;
	INT iByte = 0;

	pTexture = &pTex->textures[iTexNum];
	//if( bNumForName ) sprintf( num, "%03i", iTexNum );
	sprintf( texfname, bNumForName ? "%03i.tex" : "%s.tex", bNumForName ? (char*)iTexNum : pTexture->name );
	texfile = fopen( texfname, "wb" ); // ^^^^^^ HACK because %03i part will only be used when bNumForName is true

	fseek( pChunk, pTexture->paloffs, 0 );
	for( INT i = 0; i < 1024; i++ ) { // 256*4 = 1024, we have 4 bytes for a color in the palette, and there are 256 colors
		fread( &iByte, 1, 1, pChunk );
		fwrite( &iByte, 1, 1, pal );
		iByte = 0;
	}

	fseek( pChunk, pTexture->offset, 0 );
	fwrite( &pTexture->w, 2, 1, texfile );
	fwrite( &pTexture->h, 2, 1, texfile );
	for( INT i = 0; i < pTexture->pixelcount; i++ ) { // Each byte in the palettized texture itself is a reference to the color in the palette
		fread( &iByte, 1, 1, pChunk );
		fwrite( &iByte, 1, 1, texfile );
		iByte = 0;
	}
	fclose( texfile );
}

BOOL ReplaceTexture( const char* chunkfname, System::String^ texturefile, tTextureList_s* pTex, INT iTexNum ) {
	System::Drawing::Bitmap^ pTexBitmap;
	System::Drawing::Imaging::BitmapData^ bmpdata;
	FILE* pChunk;
	INT x, y, stride;
	BYTE* dataptr;

	x = y = 0;
	pChunk = fopen( chunkfname, "rb+" );
	pTexBitmap = gcnew System::Drawing::Bitmap( texturefile ); // Gcnew or direct Bitmap::FromFile?

	if( pTexBitmap->Width != pTex->textures[iTexNum].w || pTexBitmap->Height != pTex->textures[iTexNum].h ) {
		delete[] pTexBitmap;
		fclose( pChunk );
		MessageBoxA( NULL, "The input texture has different dimensions from the source texture", "ERROR", MB_ICONERROR );
		return FALSE;
	}

	bmpdata = pTexBitmap->LockBits( System::Drawing::Rectangle(0, 0, pTexBitmap->Width, pTexBitmap->Height),
		System::Drawing::Imaging::ImageLockMode::ReadOnly, System::Drawing::Imaging::PixelFormat::Format32bppArgb );

	dataptr = (BYTE*)(INT)bmpdata->Scan0;
	stride = bmpdata->Stride;
	for( INT i = 0; i < pTex->textures[iTexNum].pixelcount; i++ ) {
		if( y > pTexBitmap->Height ) break;
		pTex->textures[iTexNum].pixels[i].a = dataptr[(x*4)+y*stride+3];
		pTex->textures[iTexNum].pixels[i].r = dataptr[(x*4)+y*stride+2];
		pTex->textures[iTexNum].pixels[i].g = dataptr[(x*4)+y*stride+1];
		pTex->textures[iTexNum].pixels[i].b = dataptr[(x*4)+y*stride];
		x++; if( x >= pTexBitmap->Width ) { x = 0; y++; } // Moved from top to bottom of the for loop
	}

	fseek( pChunk, pTex->textures[iTexNum].offset, 0 );
	for( INT i = 0; i < pTex->textures[iTexNum].pixelcount; i++ ) {
		fwrite( &pTex->textures[iTexNum].pixels[i].r, 1, 1, pChunk );
		fwrite( &pTex->textures[iTexNum].pixels[i].g, 1, 1, pChunk );
		fwrite( &pTex->textures[iTexNum].pixels[i].b, 1, 1, pChunk );
		pTex->textures[iTexNum].pixels[i].a = 128; // FOR NOW
		fwrite( &pTex->textures[iTexNum].pixels[i].a, 1, 1, pChunk );
	}

	delete[] pTexBitmap;
	delete[] bmpdata;
	fclose( pChunk );

	return TRUE;
}

BOOL CreateTexChunk( tTextureList_s* textures, dbl_chunk_header_s* pChunkHeader, const char* output,
					INT chunkN, System::Windows::Forms::RichTextBox^ logbox, System::Windows::Forms::ProgressBar^ pbar ) {
	FILE* pChunk, * pPalFile;
	System::Drawing::Bitmap^ pTexBitmap;
	System::Drawing::Imaging::BitmapData^ bmpdata;
	char szFilename[256];
	INT iHeaderSize = 0; // The size of the header + garbage, it's determined by the chunk's iFlag
	INT iByte = 0, x, y, stride, namelen, fill_in, iLastPos, iTotalTextures, iProgressAddition = 0;
	INT16* iFSTexOffsets; // Offset for fseek's to get back to the place where we should put
	INT16* iPALTexOffsets;
	BYTE* dataptr;
	char* fileext;

	fill_in = 0;
	iFSTexOffsets = (INT16*)malloc( textures->texturenum*2 );
	iPALTexOffsets = (INT16*)malloc( textures->texturenum*2 );
	sprintf( szFilename, (chunkN < 10) ? "%s\\Chunk0%i.chk" : "%s\\Chunk%i.chk", output, chunkN );
	pChunk = fopen( szFilename, "wb" );
	if( !pChunk ) {
		MessageBoxA( NULL, "Couldn't create the chunk-file", "ERROR", MB_ICONERROR );
		return FALSE;
	}

	fwrite( &pChunkHeader->iDataChunkType, 2, 1, pChunk );
	fwrite( &pChunkHeader->iFlag, 2, 1, pChunk );
	fseek( pChunk, 4, SEEK_CUR );
	fwrite( &pChunkHeader->iDataChunkVer, 2, 1, pChunk );
	if( pChunkHeader->iFlag != 0x00 ) {
		fwrite( "1000", 4, 1, pChunk ); //iHeaderSize += 4; // It's 4 more bytes because of the 1000
	}

	switch( pChunkHeader->iFlag ) {
		case 0x0E:
			iHeaderSize = FLAG_0E;
		break;
		case 0x06:
			iHeaderSize = FLAG_06;
		break;
		case 0x00:
			iHeaderSize = FLAG_00;
		break;
	}

	iByte = 0;

	fseek( pChunk, iHeaderSize, 0 );
	fwrite( &textures->texturenum, 2, 1, pChunk );
	fseek( pChunk, 22, SEEK_CUR );
	fwrite( "TEXTUREBLOCK_START", 1, 0x12, pChunk );
	fseek( pChunk, 0xD, SEEK_CUR );
	iTotalTextures = 0;
	for( INT i = 0; i < textures->texturenum; i++ ) {
		iProgressAddition = (INT)(((float)i/(float)textures->texturenum)*100.0);
		if( iProgressAddition > 100 ) iProgressAddition = 100;
		pbar->Value = iProgressAddition;

		fileext = (char*)((&textures->textures[i].name[0]+strlen(textures->textures[i].name))-3);
		if( stricmp(fileext, "tex") && stricmp(fileext, "png") ) continue; // See if it's a texture
		iTotalTextures++;
		if( !stricmp(fileext, "tex") ) { // Handle the palettized texture
			logbox->Text += "\n=============================";
			logbox->Text += "\nAdding a palettized texture "+MakeString(textures->textures[i].name)+":";
			fileext = (char*)malloc( 64*4 );
			strcpy( fileext, textures->textures[i].name );
			fileext[ strlen(fileext)-3 ] = '\0';
			sprintf( szFilename, "%s\\%spal", textures->textures[i].basepath, fileext );
			free( fileext );
			pPalFile = fopen( szFilename, "rb" ); // Read the palette file first (.pal)
			if( !pPalFile ) {
				sprintf( szFilename, "Couldn't open the palette file for %s texture", textures->textures[i].name );
				MessageBoxA( NULL, szFilename, "ERROR", MB_ICONERROR );
				return FALSE;
			}
			logbox->Text += "\n\nReading the palette file for "+MakeString(textures->textures[i].name);
			for( INT p = 0; p < 256; p++ ) {
				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pal[p].r = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pal[p].g = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pal[p].b = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pal[p].a = iByte;
				iByte = 0;
			}
			fclose( pPalFile );

			logbox->Text += "\nReading the texture file for "+MakeString(textures->textures[i].name);
			sprintf( szFilename, "%s\\%s", textures->textures[i].basepath, textures->textures[i].name );
			pPalFile = fopen( szFilename, "rb" ); // Read the texture file , it contains raw bytes which are
			fseek( pPalFile, 0, SEEK_END ); // indexes of colors in the palette
			textures->textures[i].pixelcount = ftell(pPalFile);
			fseek( pPalFile, 0, 0 );
			fread( &textures->textures[i].w, 2, 1, pPalFile );
			fread( &textures->textures[i].h, 2, 1, pPalFile );
			textures->textures[i].pixels = (tPixel_s*)malloc( (textures->textures[i].pixelcount)*sizeof(tPixel_s) );

			for( INT f = 0; f < textures->textures[i].pixelcount; f++ ) {
				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pixels[f].r = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pixels[f].g = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pixels[f].b = iByte;
				iByte = 0;

				fread( &iByte, 1, 1, pPalFile );
				textures->textures[i].pixels[f].a = iByte;
				iByte = 0;
			}

			textures->textures[i].mode = TEX_PALET; // Signify that the texture is palettized
			continue; // And skip the rest of the action
		}
		// This part below handles a 'normal' 0x1C texture that's not palettized nor fucked with in any other way
		logbox->Text += "\n=============================";
		logbox->Text += "\nAdding a normal texture "+MakeString(textures->textures[i].name)+":";

		pTexBitmap = gcnew System::Drawing::Bitmap( MakeString(textures->textures[i].basepath)+"\\"+MakeString(textures->textures[i].name) );

		textures->textures[i].w = pTexBitmap->Width; // Dimensions are easy
		textures->textures[i].h = pTexBitmap->Height;
		textures->textures[i].mode = TEX_NORMAL;
		textures->textures[i].pixelcount = (pTexBitmap->Width*pTexBitmap->Height);
		textures->textures[i].pixels = (tPixel_s*)malloc( (textures->textures[i].pixelcount)*sizeof(tPixel_s) );

		logbox->Text += "\nPixelcount: "+textures->textures[i].pixelcount.ToString();

		bmpdata = pTexBitmap->LockBits( System::Drawing::Rectangle(0, 0, pTexBitmap->Width, pTexBitmap->Height),
			System::Drawing::Imaging::ImageLockMode::ReadOnly, System::Drawing::Imaging::PixelFormat::Format32bppArgb );
		dataptr = (BYTE*)bmpdata->Scan0.ToPointer();
		stride = bmpdata->Stride;

		logbox->Text += "\nReading pixels...";

		x = 0; y = 0;
		for( INT p = 0; p < textures->textures[i].pixelcount; p++ ) {
			if( y > pTexBitmap->Height ) break;
			textures->textures[i].pixels[p].a = dataptr[(x*4)+y*stride+3];
			textures->textures[i].pixels[p].r = dataptr[(x*4)+y*stride+2];
			textures->textures[i].pixels[p].g = dataptr[(x*4)+y*stride+1];
			textures->textures[i].pixels[p].b = dataptr[(x*4)+y*stride];
			x++; if( x >= pTexBitmap->Width ) { x = 0; y++; }
		}

		pTexBitmap->UnlockBits( bmpdata );

		delete[] bmpdata; // Free this up I guess
		delete[] pTexBitmap;
	}

	logbox->Text += "\n\n\n\n=============================";
	logbox->Text += "\nWriting the header";
	// Texture names, offsets, dimensions & related
	for( INT i = 0; i < textures->texturenum; i++ ) {
		fileext = (char*)((&textures->textures[i].name[0]+strlen(textures->textures[i].name))-3);
		if( stricmp(fileext, "tex") && stricmp(fileext, "png") ) continue; // If it's not a recognized tex' fmt
		 // we don't write down the junk, eg .pal files and such
		sprintf( szFilename, "%s\\%s", textures->textures[i].basepath, textures->textures[i].name );
		namelen = strlen(szFilename);

		iByte = 0; // !
		fwrite( &iByte, 1, 1, pChunk ); // Write the zero before the texture mode
		fwrite( &textures->textures[i].mode, 1, 1, pChunk );
		fseek( pChunk, 0xB, SEEK_CUR );
		iFSTexOffsets[i] = ftell( pChunk ); // Save the position so we can get back later to fill in the offset
		fseek( pChunk, 4, SEEK_CUR );
		fwrite( &textures->textures[i].w, 2, 1, pChunk ); // Dimensions
		fwrite( &textures->textures[i].h, 2, 1, pChunk );
		if( textures->textures[i].mode == TEX_PALET ) {
			fseek( pChunk, 0x8, SEEK_CUR );
			iPALTexOffsets[i] = ftell( pChunk ); // Save the offset for us to know where to go later
			fseek( pChunk, 0xC, SEEK_CUR ); // to write the actual offset to the palette
		}
		else fseek( pChunk, 0x14, SEEK_CUR );
		if( namelen <= 31 ) { // If the filename is too short fill it with the zeroes
			fill_in = 31-namelen;
			for( INT c = 0; c < fill_in; c++ ) {
				fwrite( &iByte, 1, 1, pChunk );
			}
			namelen = 0;
		}
		else {
			namelen -= 31; // Otherwise subtract 31 (the max' filename length)
		}
		fwrite( szFilename+namelen, 1, strlen(szFilename)-namelen, pChunk ); // Write the name till its too long
	}

	fseek( pChunk, iHeaderSize*2, SEEK_CUR );

	logbox->Text += "\nWriting the pixels for each texture...";

	for( INT i = 0; i < textures->texturenum; i++ ) {
		iLastPos = ftell( pChunk )-iHeaderSize; // Get the offset to the texture that we're writing
		fseek( pChunk, iFSTexOffsets[i], 0 ); // Go to the place where were supposed to put the offset
		fwrite( &iLastPos, 4, 1, pChunk ); // ..
		fseek( pChunk, iLastPos+iHeaderSize, 0 ); // Come back
		iLastPos = 0;
		// Write the pixels
		for( INT p = 0; p < textures->textures[i].pixelcount; p++ ) {
			fwrite( &textures->textures[i].pixels[p].r, 1, 1, pChunk );
			fwrite( &textures->textures[i].pixels[p].g, 1, 1, pChunk );
			fwrite( &textures->textures[i].pixels[p].b, 1, 1, pChunk );
			fwrite( &textures->textures[i].pixels[p].a, 1, 1, pChunk );
		}
	}

	// Come back to fill in the other offsets & append the palettes

	logbox->Text += "\nWriting the palettes and/or writing offsets for each texture...";

	fseek( pChunk, 64, SEEK_CUR );
	iByte = 0x10; // We're saying that the palette size is 256, we probably shouldn't?
	for( INT i = 0; i < textures->texturenum; i++ ) {
		if( textures->textures[i].mode != TEX_PALET ) continue;
		iLastPos = ftell( pChunk )-iHeaderSize;
		fseek( pChunk, iPALTexOffsets[i], 0 );
		fwrite( &iLastPos, 4, 1, pChunk );
		fwrite( &iByte, 2, 1, pChunk );
		fwrite( &iByte, 2, 1, pChunk );
		fseek( pChunk, iLastPos+iHeaderSize, 0 );
		iLastPos = 0;

		for( INT p = 0; p < 256; p++ ) {
			fwrite( &textures->textures[i].pal[p].r, 1, 1, pChunk );
			fwrite( &textures->textures[i].pal[p].g, 1, 1, pChunk );
			fwrite( &textures->textures[i].pal[p].b, 1, 1, pChunk );
			fwrite( &textures->textures[i].pal[p].a, 1, 1, pChunk );
		}
	}

	logbox->Text += "\nCalculating the chunksize & misc...";

	// Calculate the chunksize
	iLastPos = 0;
	fseek( pChunk, 0, SEEK_END );
	iLastPos = ftell( pChunk )-iHeaderSize;
	fseek( pChunk, 4, 0 );
	fwrite( &iLastPos, 4, 1, pChunk );
	fwrite( &pChunkHeader->iDataChunkVer, 2, 1, pChunk );

	fseek( pChunk, iHeaderSize, 0 );
	fwrite( &iTotalTextures, 2, 1, pChunk );

	fclose( pChunk );

	free( iFSTexOffsets ); free( iPALTexOffsets );

	pbar->Value = 100;
	MessageBoxA( NULL, "The chunk has been assembled successfully!", "SUCKCESS", MB_ICONINFORMATION );

	return TRUE;
}