#include<string.h>
#include"image.h"
#include<GameOS\GameOS.hpp>

int Image::IsTga()
{
	char *spos;
	spos=NULL;
	int i,slen=strlen(fname);
	for(i=slen-1;i>=0 && fname[i]!='.';i--);
	if(i<0) return 0;
	if(fname[i]=='.') spos=fname+i+1;
	return !strcmpi("tga",spos);
}

void Image::GetTgaInfo(Stuff::FileStream *stream)
{
	int i;
	int cm_index,cm_length,cm_esize,has_color_map,tgaid,xpos,ypos,sta,idlen,ttype;
	xpos=ypos=tgaid=has_color_map=cm_index=cm_length=cm_esize=sta=idlen=ttype=0;

	stream->ReadBytes(&idlen,1);
	stream->ReadBytes(&has_color_map,1);
	stream->ReadBytes(&tgaid,1);
	stream->ReadBytes(&cm_index,2);
	stream->ReadBytes(&cm_length,2);
	stream->ReadBytes(&cm_esize,1);

	cm_esize>>=3;

	if((tgaid!=1 && tgaid!=2 && tgaid!=10 && tgaid!=3) || (has_color_map && cm_esize!=3) )  
	{
		char msg[512];
		sprintf(msg,"Unsupported Tga Data Format %s",fname);
		GENNFERR(msg); //confirm uncompressed rgb
	}
	
	stream->ReadBytes(&xpos,2);
	stream->ReadBytes(&ypos,2);
	xlen=ylen=0;
	stream->ReadBytes(&xlen,2);
	stream->ReadBytes(&ylen,2);
	
	vxlen=xlen;
	vylen=ylen;
	
	stream->ReadBytes(&ttype,1);
	if(ttype==32) {itype=ITYPE_RGB; Bpp=32;}
	if(ttype==24) {itype=ITYPE_RGB; Bpp=24;}
	if(ttype==16) {itype=ITYPE_RGB; Bpp=16;}
	if(ttype==8) {itype=ITYPE_INDEXED; Bpp=8; MakeGrayscalePalette();}
	
	int byte_per_pix=Bpp>>3;
	
	stream->ReadBytes(&sta,1);
	
	
	if(has_color_map)
	{
		ImgRGBColor col;
		if(cm_esize==3) 
		for(i=cm_index;i<cm_index+cm_length;i++)
		{
			col.r=col.g=col.b=0;

			stream->ReadBytes(&col.r,1);
			stream->ReadBytes(&col.g,1);
			stream->ReadBytes(&col.b,1);
			if(i<256)
				pal[i]=col;
		}
	}
	if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0xff0000,0x00ff00,0x0000ff); 
		else
			if(Bpp==32)
				Mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000); 
	}
}


void Image::LoadTga(Stuff::FileStream *stream)
{
	int i;
	BYTE *dpt;

	int cm_index,cm_length,cm_esize,has_color_map,tgaid,xpos,ypos,sta,idlen,ttype;
	xpos=ypos=tgaid=has_color_map=cm_index=cm_length=cm_esize=sta=idlen=ttype=0;

	stream->ReadBytes(&idlen,1);
	stream->ReadBytes(&has_color_map,1);
	stream->ReadBytes(&tgaid,1);
	stream->ReadBytes(&cm_index,2);
	stream->ReadBytes(&cm_length,2);
	stream->ReadBytes(&cm_esize,1);

	cm_esize>>=3;


	if((tgaid!=1 && tgaid!=2 && tgaid!=10 && tgaid!=3) || (has_color_map && cm_esize!=3) )  
	{
		char msg[512];
		sprintf(msg,"Unsupported Tga Data Format %s",fname);
		GENNFERR(msg); //confirm uncompressed rgb
	}
	
	stream->ReadBytes(&xpos,2);
	stream->ReadBytes(&ypos,2);
	xlen=ylen=0;
	stream->ReadBytes(&xlen,2);
	stream->ReadBytes(&ylen,2);
	
	vxlen=xlen;
	vylen=ylen;
	
	stream->ReadBytes(&ttype,1);
	if(ttype==32) {itype=ITYPE_RGB; Bpp=32;}
	if(ttype==24) {itype=ITYPE_RGB; Bpp=24;}
	if(ttype==16) {itype=ITYPE_RGB; Bpp=16;}
	if(ttype==8) {itype=ITYPE_INDEXED; Bpp=8; MakeGrayscalePalette();}
	
	int byte_per_pix=Bpp>>3;
	
	stream->ReadBytes(&sta,1);

	
	
	if(has_color_map)
	{
		ImgRGBColor col;
		if(cm_esize==3) 
		for(i=cm_index;i<cm_index+cm_length;i++)
		{
			col.r=col.g=col.b=0;

			stream->ReadBytes(&col.r,1);
			stream->ReadBytes(&col.g,1);
			stream->ReadBytes(&col.b,1);
			if(i<256)
				pal[i]=col;
		}
	}
	
	IAlloc();
	dpt=Lock();
	BYTE *dat=dpt;
	
		int x,y,j;
		//get data
		switch(tgaid) 
		{
		case 1:		//Raw ColorMap
		case 2:		//Raw Image
		case 3:		//UnCompressed BW Image
			if(sta&0x20)
			{
/*
				for(y=0;y<ylen;y++,dpt+=Pitch-byte_per_pix*xlen)
					for(x=0;x<xlen;x++,dpt+=byte_per_pix)
						for(j=byte_per_pix-1;j>=0;j--)
							dpt[j]=(BYTE)getc(fl);
*/
		
					stream->ReadBytes(dpt,Pitch*ylen);
					dpt+=Pitch*ylen;
		  }
			else                         //inverted image
			{

				dpt=dat+((ylen-1)*Pitch);
				for(y=0;y<ylen;y++,dpt-=Pitch)
					stream->ReadBytes(dpt,Pitch);

 /*
				for(x=0;x<xlen;x++)
					{
						dpt=dat+y*Pitch+x*byte_per_pix;
						for(j=0;j<byte_per_pix;j++)
							dpt[j]=(BYTE)getc(fl);
   }
*/
			}
			break;
			
		
		case 10: //RLEImage
			{	
				int PixelSum=xlen*ylen,Pixs,tag;
				BYTE tmpval[4];
				
				if(sta&0x20)
				{
					while(PixelSum>0)
					{
						tag=0;
						stream->ReadBytes(&tag,1);
						Pixs=(tag&0x7F)+1;
						if(tag&0x80) 
						{
								stream->ReadBytes(tmpval,byte_per_pix);
							
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
								for(j=0;j<byte_per_pix;j++)
									dpt[j]=tmpval[j];
								
						}
						else
						{
								int bread=byte_per_pix*Pixs;
								stream->ReadBytes(dpt,bread);
								dpt+=bread;
				
						}
						PixelSum-=Pixs;
					}
				}
				else                         //inverted image
				{
					y=x=0; 
					while(PixelSum>0)
					{
						tag=0;
						stream->ReadBytes(&tag,1);
						Pixs=(tag&0x7F)+1;
						if(tag&0x80) 
						{
								stream->ReadBytes(tmpval,byte_per_pix);
							
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
							{
								dpt=dat+(ylen-y)*Pitch+x*(Bpp>>3);
									stream->ReadBytes(dpt,byte_per_pix);
								x++;
								if(x>=xlen) {x=0; y++;}
							}
							
						}
						else
						{
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
							{
								dpt=dat+(ylen-y)*Pitch+x*(Bpp>>3);
									stream->ReadBytes(dpt,byte_per_pix);
								x++;
								if(x>=xlen) {x=0; y++;}
							}
							
						}
						PixelSum-=Pixs;
					}
					
				}
			}
			break;
	}
	
	UnLock();
	if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0xff0000,0x00ff00,0x0000ff); 
		else
			if(Bpp==32)
				Mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000); 
	}
}


void Image::SaveTga(Stuff::FileStream *stream)
{
	int i;
	WORD tmpint;
	BYTE tbte;
	BYTE *cdata;
	
	tbte=0;       	stream->WriteBytes(&tbte,1); //Size of Header
	tbte=0;       	stream->WriteBytes(&tbte,1); //ColorMap Flag
	tbte=0x02;    	stream->WriteBytes(&tbte,1);  //Image Type
	
	for(i=3;i<=7;i++) //ColorMap
	{	tbte=0;       	stream->WriteBytes(&tbte,1);  }
	
	tmpint=0;	   	stream->WriteBytes(&tmpint,2);    //Xorg
	tmpint=0;		stream->WriteBytes(&tmpint,2);				//YOrg
	
	
	stream->WriteBytes(&xlen,2);
	stream->WriteBytes(&ylen,2);
	tbte=(BYTE)Bpp;    stream->WriteBytes(&tbte,1);		
	tbte=0x20;    stream->WriteBytes(&tbte,1);		//Flag
	
	if(Bpp==24)
		MaskTo(RGBMask(0xff0000,0x00ff00,0x0000ff));
	else
		if(Bpp==32)
			MaskTo(RGBMask(0x00ff0000,0x0000ff00,0x000000ff,0xff000000));
		
		cdata=Lock();
		stream->WriteBytes(cdata,(int)xlen*ylen*(Bpp>>3));
		
		UnLock();
}

void Image::LoadTga(char *str)
{
	Stuff::FileStream stream;
	stream.Open(str,Stuff::FileStream::ReadOnly);
	LoadTga(&stream);
//	stream.Close();
	strcpy(fname,str);
}

void Image::GetTgaInfo(FILE *fl)
{
	int i,idlen,sta,pos;
	int xpos,ypos;
	int tgaid;
	int has_color_map;
	pos=ftell(fl);
	idlen=getc(fl);           //get idlenght
	has_color_map=getc(fl);
	tgaid=getc(fl);
	int cm_index,cm_length,cm_esize;
	cm_index=getc(fl); cm_index|=getc(fl)<<8;
	cm_length=getc(fl); cm_length|=getc(fl)<<8;
	cm_esize=getc(fl)>>3;

	if((tgaid!=1 && tgaid!=2 && tgaid!=10 && tgaid!=3) || (has_color_map && cm_esize!=3) )  
	{
		char msg[512];
		sprintf(msg,"Unsupported Tga Data Format %s",fname);
		GENNFERR(msg); //confirm uncompressed rgb
	}
	
	xpos=getc(fl); xpos|=getc(fl)<<8;
	ypos=getc(fl); ypos|=getc(fl)<<8;
	xlen=getc(fl); xlen|=getc(fl)<<8;
	ylen=getc(fl); ylen|=getc(fl)<<8;
	
	vxlen=xlen;
	vylen=ylen;
	
	int ttype=getc(fl);
	if(ttype==32) {itype=ITYPE_RGB; Bpp=32;}
	if(ttype==24) {itype=ITYPE_RGB; Bpp=24;}
	if(ttype==16) {itype=ITYPE_RGB; Bpp=16;}
	if(ttype==8) {itype=ITYPE_INDEXED; Bpp=8; MakeGrayscalePalette();}
	
	int byte_per_pix=Bpp>>3;
	
	sta=getc(fl);
	
	
	if(has_color_map)
	{
		ImgRGBColor col;
		if(cm_esize==3) 
		for(i=cm_index;i<cm_index+cm_length;i++)
		{
			col.r=getc(fl);
			col.g=getc(fl);
			col.b=getc(fl);
			if(i<256)
				pal[i]=col;
		}
	}
	if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0xff0000,0x00ff00,0x0000ff); 
		else
			if(Bpp==32)
				Mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000); 
	}
}

void Image::GetTgaInfo(char *str)
{
	Stuff::FileStream stream;
	stream.Open(str,Stuff::FileStream::ReadOnly);
	GetTgaInfo(&stream);
	strcpy(fname,str);
}

void Image::LoadTga(FILE *fl)
{
	int i,idlen,sta,pos;
	int xpos,ypos;
	int tgaid;
	int has_color_map;
	BYTE *dpt;
	pos=ftell(fl);
	idlen=getc(fl);           //get idlenght
	has_color_map=getc(fl);
	tgaid=getc(fl);
	int cm_index,cm_length,cm_esize;
	cm_index=getc(fl); cm_index|=getc(fl)<<8;
	cm_length=getc(fl); cm_length|=getc(fl)<<8;
	cm_esize=getc(fl)>>3;

	if((tgaid!=1 && tgaid!=2 && tgaid!=10 && tgaid!=3) || (has_color_map && cm_esize!=3) )  
	{
		char msg[512];
		sprintf(msg,"Unsupported Tga Data Format %s",fname);
		GENNFERR(msg); //confirm uncompressed rgb
	}
	
	xpos=getc(fl); xpos|=getc(fl)<<8;
	ypos=getc(fl); ypos|=getc(fl)<<8;
	xlen=getc(fl); xlen|=getc(fl)<<8;
	ylen=getc(fl); ylen|=getc(fl)<<8;
	
	vxlen=xlen;
	vylen=ylen;
	
	int ttype=getc(fl);
	if(ttype==32) {itype=ITYPE_RGB; Bpp=32;}
	if(ttype==24) {itype=ITYPE_RGB; Bpp=24;}
	if(ttype==16) {itype=ITYPE_RGB; Bpp=16;}
	if(ttype==8) {itype=ITYPE_INDEXED; Bpp=8; MakeGrayscalePalette();}
	
	int byte_per_pix=Bpp>>3;
	
	sta=getc(fl);
	
	IAlloc();
	dpt=Lock();
	BYTE *dat=dpt;
	
	if(has_color_map)
	{
		ImgRGBColor col;
		if(cm_esize==3) 
		for(i=cm_index;i<cm_index+cm_length;i++)
		{
			col.r=getc(fl);
			col.g=getc(fl);
			col.b=getc(fl);
			if(i<256)
				pal[i]=col;
		}
	}
		int x,y,j;
		//get data
		switch(tgaid) 
		{
		case 1:		//Raw ColorMap
		case 2:		//Raw Image
		case 3:		//UnCompressed BW Image
			if(sta&0x20)
			{
/*
				for(y=0;y<ylen;y++,dpt+=Pitch-byte_per_pix*xlen)
					for(x=0;x<xlen;x++,dpt+=byte_per_pix)
						for(j=byte_per_pix-1;j>=0;j--)
							dpt[j]=(BYTE)getc(fl);
*/
		
				for(y=0;y<ylen;y++,dpt+=Pitch)
					fread(dpt,Pitch,1,fl);

		  }
			else                         //inverted image
			{

				dpt=dat+((ylen-1)*Pitch);
				for(y=0;y<ylen;y++,dpt-=Pitch)
					fread(dpt,Pitch,1,fl);

 /*
				for(x=0;x<xlen;x++)
					{
						dpt=dat+y*Pitch+x*byte_per_pix;
						for(j=0;j<byte_per_pix;j++)
							dpt[j]=(BYTE)getc(fl);
   }
*/
			}
			break;
			
		
		case 10: //RLEImage
			{	
				int PixelSum=xlen*ylen,Pixs,tag;
				BYTE tmpval[4];
				
				if(sta&0x20)
				{
					while(PixelSum>0)
					{
						tag=getc(fl);
						Pixs=(tag&0x7F)+1;
						if(tag&0x80) 
						{
							for(j=0;j<byte_per_pix;j++)
								tmpval[j]=getc(fl);
							
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
								for(j=0;j<byte_per_pix;j++)
									dpt[j]=tmpval[j];
								
						}
						else
						{
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
								for(j=0;j<byte_per_pix;j++)
									dpt[j]=(BYTE)getc(fl);
								
						}
						PixelSum-=Pixs;
					}
				}
				else                         //inverted image
				{
					y=x=0; 
					while(PixelSum>0)
					{
						tag=getc(fl);
						Pixs=(tag&0x7F)+1;
						if(tag&0x80) 
						{
							for(j=0;j<byte_per_pix;j++)
								tmpval[j]=getc(fl);
							
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
							{
								dpt=dat+(ylen-y)*Pitch+x*(Bpp>>3);
								for(j=0;j<byte_per_pix;j++)
									dpt[j]=tmpval[j];
								x++;
								if(x>=xlen) {x=0; y++;}
							}
							
						}
						else
						{
							for(i=0;i<Pixs;i++,dpt+=byte_per_pix)
							{
								dpt=dat+(ylen-y)*Pitch+x*(Bpp>>3);
								for(j=0;j<byte_per_pix;j++)
									dpt[j]=(BYTE)getc(fl);
								x++;
								if(x>=xlen) {x=0; y++;}
							}
							
						}
						PixelSum-=Pixs;
					}
					
				}
			}
			break;
	}
	
	UnLock();
	if(itype!=ITYPE_INDEXED)	
	{
		if(Bpp==24)
			Mask.Set(0xff0000,0x00ff00,0x0000ff); 
		else
			if(Bpp==32)
				Mask.Set(0x00ff0000,0x0000ff00,0x000000ff,0xff000000); 
	}
}

void Image::SaveTga(char *str)
{
	Stuff::FileStream stream;
	stream.Open(str,Stuff::FileStream::WriteOnly);
	SaveTga(&stream);
	strcpy(fname,str);
}

void Image::SaveTga(FILE *fl)
{
	int i;
	WORD tmpint;
	BYTE tbte;
	BYTE *cdata;
	
	tbte=0;    fwrite(&tbte,1,1,fl);		//Size of Header
	tbte=0;    fwrite(&tbte,1,1,fl);		//ColorMap Flag
	tbte=0x02; fwrite(&tbte,1,1,fl);	//Image Type
	
	for(i=3;i<=7;i++) //ColorMap
	{	tbte=0;    fwrite(&tbte,1,1,fl); }
	
	tmpint=0;	fwrite(&tmpint,1,2,fl);				//Xorg
	tmpint=0;	fwrite(&tmpint,1,2,fl);				//YOrg
	
	
	fwrite(&xlen,1,2,fl);
	fwrite(&ylen,1,2,fl);
	tbte=(BYTE)Bpp;    fwrite(&tbte,1,1,fl);		
	tbte=0x20;    fwrite(&tbte,1,1,fl);		//Flag
	
	if(Bpp==24)
		MaskTo(RGBMask(0xff0000,0x00ff00,0x0000ff));
	else
		if(Bpp==32)
			MaskTo(RGBMask(0x00ff0000,0x0000ff00,0x000000ff,0xff000000));
		
		cdata=Lock();
		fwrite(cdata,1,(int)xlen*ylen*(Bpp>>3),fl);					//Image Data
		
		UnLock();
}
