
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///																																  ///
///		FICHIER :	ZooTexture.cpp																								  ///
///																																  ///
///		NATURE	:	Defines the class to manipulate ans product opengl texture for the textured material of the scene    		  ///
///																																  ///
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




#include	"..\Datas\zootexture.h"
#include	"..\SCOL\winuser.h"

#include "..\Loaders\JPEG\LoaderJpeg.h"
#include "../scol/colors.h"

//$BLG
//I included this file to use gluScaleImage in M3blitTexture16 ... this resulted in a 15x performance loss ...
//#include <GL/GLU.H>
//#include <stdio.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ZTexture Class
///
///		- Classe des textures : Image, filtre, et taille
///		- Méthodes pour le set des composantes et pour le chargement d'un BMP ou JPG
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////
/// Constructor					 										///
///////////////////////////////////////////////////////////////////////////
ZTexture::ZTexture(bool accel) : ZData()
{
	type	= TEX_TYPE_ID;

	Image		= NULL;
	ImageModif	= NULL;
	bitmap24	= NULL;
	
	Width = Height = 0;

	C = X = Y = A = R = S = false;
	
	modified  = true;
	activated = false;
	renamed	  = true;

	transpR = 0;
	transpG = 0;
	transpB = 0;
	rate	= 0;
	value	= 0;

	ID_created	= false;
	
	filter	= -1;

	accelerated = accel;
}



///////////////////////////////////////////////////////////////////////////
///		Destructor				 										///
///////////////////////////////////////////////////////////////////////////
ZTexture::~ZTexture()
{
	if(Image!=NULL)				free(Image);
	if(ImageModif!=NULL)		free(ImageModif);
	Image = ImageModif = NULL;

	if(ID_created && accelerated)
	{
		glDeleteTextures(1, &texID);
		ID_created = false;
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		SetTextureFilter																	///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZTexture::SetTextureFilter(int newfilter)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::SetTextureFilter ");
#endif

  //$BLG Modif
	//if( (newfilter>=0) && (newfilter<=2) )
	if( (newfilter>=0) && (newfilter<=3) )
	{
		if(activated)
		{
			filter = newfilter;
			PutGLMultiparams0();
			if(ImageModif)		free(ImageModif);
			ImageModif = (unsigned char *) malloc(Width * Height * 4);
			glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, ImageModif);
			SetupTexture();
		}
		else
			filter = newfilter;
	}
}


//$BLG
//Same as SetTextureFilter but ImageModif isn't freed if it does exist.
//The purpose is to mix OpenGL linear filtering with Scol common bitmap filters.
///////////////////////////////////////////////////////////////////////////////////////////////
///		BLG_SetTextureFilter																	///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZTexture::BLG_SetTextureFilter(int newfilter)
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::BLG_SetTextureFilter ");
#endif

	if( (newfilter>=0) && (newfilter<=3) )
	{
		if(activated)
		{
			filter = newfilter;
			PutGLMultiparams0();
			if(ImageModif == NULL)		
			{
			  ImageModif = (unsigned char *) malloc(Width * Height * 4);
			  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, ImageModif);
			}
			BLG_SetupTexture();
		}
		else
			filter = newfilter;
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		LoadTexture																			///
///////////////////////////////////////////////////////////////////////////////////////////////
bool ZTexture::LoadTexture(char *filename)
{
/*
	int i=0;

	while(filename[i] != '.')	i++;

	if ( ((filename[i+1]=='b') || (filename[i+1]=='B')) && 
		 ((filename[i+2]=='m') || (filename[i+2]=='M')) &&
		 ((filename[i+3]=='p') || (filename[i+3]=='P'))		)
	{
		if (LoadBMPTexture(filename) == false)		{	activated = false;	return false;	}
	}
	else
	if ( ((filename[i+1]=='j') || (filename[i+1]=='J')) &&
		 ((filename[i+2]=='p') || (filename[i+2]=='P')) &&
		 ((filename[i+3]=='g') || (filename[i+3]=='G'))		)
	{
		if (LoadJPGTexture(filename) == false)		{	activated = false;	return false;	}
	}
	else
	if ( ((filename[i+1]=='p') || (filename[i+1]=='P')) &&
		 ((filename[i+2]=='n') || (filename[i+2]=='N')) &&
		 ((filename[i+3]=='g') || (filename[i+3]=='G'))		)
	{
		if (LoadPNGTexture(filename) == false)		{	activated = false;	return false;	}
	}
	else
		return false;

	// declare the texture as ACTIVATED
	activated = true;
*/
	if(LoadJPGTexture(filename)==true)
	{
		activated = true;
		return StretchImage();
	}

	if(LoadPNGTexture(filename)==true)
	{
		activated = true;
		return StretchImage();
	}

	if(LoadBMPTexture(filename)==true)
	{
		activated = true;
		return StretchImage();
	}

	activated = false;
	return false;
}



//$BLG: v4.6a4
//This was the partial first code translation called from StretchImageModif().
//$BLg: v4.6a5
// Note: The function was first created for StretchImageModify, it is now used
// for StretchImage() too.
/*
void BLG_Copy32Bits(unsigned char *src, unsigned char *dst)
{
	_asm
	{
		//Saving registries
		push eax
		push ebx
		//Copying data
		mov eax, src
		mov eax, [eax]
		mov ebx, dst
		mov [ebx], eax
		//Restoring registries
		pop ebx
		pop eax
	}
}
*/
// C Code translation
/*
void BLG_Stretch32BitsTexture(unsigned char *src, int i_i, int i_in, int i_x, int i_blg_ySrc, unsigned char *dst, int i_j, int i_jn, int i_y, int i_ybase, int i_yl, int i_blg_yDst)
{
	_asm
	{
		//Saving useful registries
		push eax
		push ebx
		push ecx
		push edx
		//Initializing Y loop
		mov i_y, 0
		NEWYL:
		  //i_ybase = i_y*i_in;
		  mov ebx, i_y
		  mov eax, i_in
		  mul ebx
		  mov i_ybase, eax
		  //i_yl = i_y*i_j/i_jn;
		  //i_yl *= i_i;
		  mov ebx, i_y   //This one can be deleted, i_y already i_in ebx
		  mov eax, i_j
		  mul ebx
		  mov ebx, i_jn
		  div ebx
		  mov ebx, i_i
		  mul ebx
		  mov i_yl, eax
		  //Initializing X loop
		  mov i_x, 0
		  NEWXL:
		    //i_blg_ySrc = (i_yl+i_x*i_i/i_in)*4;
		    mov ebx, i_x
		    mov eax, i_i
		    mul ebx
		    mov ebx, i_in
		    div ebx
		    add eax, i_yl
		    mov ebx, 4
		    mul ebx
		    mov i_blg_ySrc, eax
		    //i_blg_yDst = (i_ybase+i_x)*4;
		    mov ebx, i_ybase
		    add ebx, i_x
		    mov eax, 4
		    mul ebx
		    mov i_blg_yDst, eax
					//Copying data
					mov eax, src
					add eax, i_blg_ySrc
					mov eax, [eax]
					mov ebx, dst
					add ebx, i_blg_yDst
					mov [ebx], eax
				//Incrementing X counter and testing end of X loop
				inc i_x
				mov edx, i_in
				cmp edx, i_x
				jz  NXTYL
				jmp NEWXL
		  //Incrementing Y counter and testing end of Y loop
		  NXTYL:
		  inc i_y
		  mov edx, i_jn
		  cmp edx, i_y
		  jz  RSTOR
		  jmp NEWYL		
		//Restoring used registries
		RSTOR:
		pop edx
		pop ecx
		pop ebx
		pop eax
	}
}
*/
// C Code - Optimization 1
void BLG_Stretch32BitsTexture(unsigned char *src, int i_i, int i_in, int i_x, int i_blg_ySrc, unsigned char *dst, int i_j, int i_jn, int i_y, int i_ybase, int i_yl, int i_blg_yDst)
{
	_asm
	{
		//Saving useful registries
		push eax
		push ebx
		push ecx
		push edx
		//Initializing Y loop
		mov i_y, 0
		mov i_ybase, 0 //ybase is now a in++ counter
		mov ecx, i_jn
		NEWYL:
		  //Storing y loop counter to avoid conflict with x loop counter
		  push ecx
		  //ybase = y*in;
  		  //cf the above note regarding ybase
		  //yl = y*j/jn;
		  //yl *= i;
		  mov eax, i_y
		   inc eax     //We increment y right now, as it is stored in registry, this is faster than below inc in loop
		   mov i_y, eax
		   dec eax
		  mov ebx, i_j
		  mul ebx
		  mov ebx, i_jn
		  div ebx
		  mov ebx, i_i
		  mul ebx
		  mov i_yl, eax
		  //Initializing X loop
		  mov i_x, 0
		  mov ecx, i_in
		  NEWXL:
		    //blg_ySrc = (yl+x*i/in)*4;
		    mov ebx, i_x
		    mov eax, i_i
		    mul ebx
		    mov ebx, i_in   //in variable is kept in ebx till we increase ybase below (1 line gain)
		    div ebx
		    add eax, i_yl
		    shl eax, 2      //blg_ySrc is now in eax
		    //blg_yDst = (ybase+x)*4;
		    //inc i_ybase   //This is not an improvment ??? Although it replaces nxadd+1xadd by nxinc+0xadd ... Variable access probably ?
		    mov edx, i_x
		     inc edx        //We increment x right now, as it is stored in registry, this is faster than below inc in loop
		     mov i_x, edx
		     dec edx
		    add edx, i_ybase
		    shl edx, 2      //blg_yDst is now in edx
					//Copying data
					add eax, src
					mov eax, [eax]
					add edx, dst
					mov [edx], eax
				//Incrementing X counter and testing end of X loop
			  //inc i_x  //Moved above
				loop NEWXL
		  //Incrementing Y counter and testing end of Y loop
		  //inc i_y    //Moved above
		  add i_ybase, ebx
		  pop ecx
		  loop NEWYL	
		//Restoring used registries
		pop edx
		pop ecx
		pop ebx
		pop eax
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		StretchImage																		///
///////////////////////////////////////////////////////////////////////////////////////////////
bool ZTexture::StretchImage()
{
	// ------ Stretch de la texture ------
	//$BLG - v4.6a5 - set all variables in next line to 0
	int		i=0, j=0, in=0, jn=0, x=0, y=0, ybase=0, yl=0;
	unsigned char *bufn;
	//$BLG - v4.6a5 - Add
	int blg_ySrc=0, blg_yDst=0;


#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::StretchImage ");
#endif

	if(!Image)		{	activated = false;	return false;	}

	i = Width;
	j = Height;

	if(accelerated)
	{
		//$BLG: v4.6a5
		//Note: Dimensions below 64 have been removed to ensure OpenGL 1.4 specifications		
		if (  ( (i==512)||(i==256)||(i==128)||(i==64)/*||(i==32)*/ )
			&&  ( (j==512)||(j==256)||(j==128)||(j==64)/*||(j==32)*/ )	)		return true;
	}
	else //$BLG: Note - some coordinates mixes are missing ???
	{
		if(    
		     ((i==256) && (j==256) )
			|| ((i==512) && (j==256) )
			|| ((i==256) && (j==512) )
			|| ((i==512) && (j==512) )
			|| ((i==1024)&& (j==512) )
			|| ((i==512) && (j==1024))
			|| ((i==1024)&& (j==1024))
			|| ((i==256) && (j==128) )
			|| ((i==128) && (j==256) )
			|| ((i==128) && (j==128) )
			|| ((i==128) && (j==64)  )
			|| ((i==64)  && (j==128) )
			|| ((i==64)  && (j==64)  )
			|| ((i==64)  && (j==32)  )
			|| ((i==32)  && (j==64)  )
			|| ((i==32)  && (j==32)  ) 
			)	return true;
	}

	if(i > j)
	{
		//$BLG
		//Removed dimension 32 - OpenGL 1.4 ensures only 64 and above		
		/*if (i<=32)				in = 32;
		else */
		if (i<=64)				in = 64;
		else if (i<=128)	in = 128;
		else if (i<=256)	in = 256;
		//$BLG
		//Added dimension 1024
		//else				in = 512;		
		else if (i<=512)	in = 512;
		else				      in = 1024;

		if (i > j+j)			jn = in>>1;
		else							jn = in;
	}
	else
	{
		//$BLG
		//Removed dimension 32 - OpenGL 1.4 ensures only 64 and above
		/*if(j<=32)		jn = 32;
		else */
		if (j<=64)				jn = 64;
		else if(j<=128)		jn = 128;
		else if(j<=256)		jn = 256;
		//$BLG
		//Added dimension 1024
		//else				    jn = 512;
		else if(j<=512)   jn = 512;
		else				      jn = 1024;

		if (j > i+i)			in = jn>>1;
		else							in = jn;
	}

	bufn = (unsigned char *) malloc(in*jn*4);
	if(bufn==NULL)								{	activated = false;	return false;	}

	for(y=0; y<jn; y++)
	{
		ybase = y*in;
		yl	  = y*j/jn;
		yl	 *= i;

		for(x=0; x<in; x++)
		{
			//$BLG: v4.6a5 - Optimized
			/*
			bufn[ (ybase+x)*4+0 ] = Image[ (yl+x*i/in)*4+0 ];
			bufn[ (ybase+x)*4+1 ] = Image[ (yl+x*i/in)*4+1 ];
			bufn[ (ybase+x)*4+2 ] = Image[ (yl+x*i/in)*4+2 ];
			bufn[ (ybase+x)*4+3 ] = Image[ (yl+x*i/in)*4+3 ];			
			*/
			
			blg_ySrc = (yl+x*i/in)*4;
			blg_yDst = (ybase+x)*4;
			
			bufn[ blg_yDst+0 ] = Image[ blg_ySrc+0 ];
			bufn[ blg_yDst+1 ] = Image[ blg_ySrc+1 ];
			bufn[ blg_yDst+2 ] = Image[ blg_ySrc+2 ];
			bufn[ blg_yDst+3 ] = Image[ blg_ySrc+3 ];			
			
			//BLG_Stretch32BitsTexture(Image, i, in, x, blg_ySrc, bufn, j, jn, y, ybase, yl, blg_yDst);
		}
	}


	free(Image);
	Image	= (unsigned char *)bufn;
	Width	= in;
	Height	= jn;

	return true;
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		StretchImageModif																	///
///////////////////////////////////////////////////////////////////////////////////////////////
bool ZTexture::StretchImageModif()
{
	// ------ Stretch de la texture ------
	//$BLG - v4.6a4 - set all variables in next line to 0
	int		i=0, j=0, in=0, jn=0, x=0, y=0, ybase=0, yl=0;
	unsigned char *bufn;
	//$BLG Start - v4.6a2
	int blg_ySrc=0, blg_yDst=0;
	//$BLG End

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::StretchImageModif ");
#endif

	if(!ImageModif)		{	activated = false;	return false;	}

	i = Width;
	j = Height;

  //$BLG
  //Removed next part as dimensions have already been checked before entering this function
  //cf ZM3blitTexture() in ZooScol.cpp
  //Powers of 2 (OpenGL limitation), from 64 to 1024 are accepted - 64 is an OpenGL 1.4 minimal specification
  //Note that using high dimension values has a huge framerate cost
  /*
	if(    ((i==256) && (j==256) )
		|| ((i==512) && (j==256) )
		|| ((i==256) && (j==512) )
		|| ((i==512) && (j==512) )
		|| ((i==1024)&& (j==512) )
		|| ((i==512) && (j==1024))
		|| ((i==1024)&& (j==1024))
		|| ((i==256) && (j==128) )
		|| ((i==128) && (j==256) )
		|| ((i==128) && (j==128) )
		|| ((i==128) && (j==64)  )
		|| ((i==64)  && (j==128) )
		|| ((i==64)  && (j==64)  )
		|| ((i==64)  && (j==32)  )
		|| ((i==32)  && (j==64)  )
		|| ((i==32)  && (j==32)  ) )	return true;
  */
  
	if(i > j)
	{
		//$BLG
		//Removed dimension 32 - OpenGL 1.4 ensures only 64 and above
		/*
		if (i<=32)		in = 32;
		else 
		*/
		if (i<=64)		in = 64;
		else if (i<=128)	in = 128;
		else if (i<=256)	in = 256;
		//$BLG
		//Added dimension 1024 - this one is included in ZM3blitTexture(), but not here
		//else				in = 512;
		else if (i<=512)	in = 512;
		else				      in = 1024;

		if(i > j+j)			  jn = in>>1;
		else				      jn = in;
	}
	else
	{
		//$BLG
		//Removed dimension 32 - OpenGL 1.4 ensures only 64 and above
		/*
		if(j<=32)		jn = 32;
		else 
		*/
		if (j<=64)		    jn = 64;
		else if(j<=128)		jn = 128;
		else if(j<=256)		jn = 256;
		//$BLG
		//Added dimension 1024 - this one is included in ZM3blitTexture(), but not here
		//else				    jn = 512;
		else if(j<=512)   jn = 512;
		else				      jn = 1024;

		if(j > i+i)			  in = jn>>1;
		else				      in = jn;
	}

	bufn = (unsigned char *) malloc(in*jn*4);
	if(bufn==NULL)								{	activated = false;	return false;	}
  
  //$BLG - v4.6a4
  //Removed the whole next part - replaced it with assembler code: BLG_Stretch32BitsTexture()
  BLG_Stretch32BitsTexture(ImageModif, i, in, x, blg_ySrc, bufn, j, jn, y, ybase, yl, blg_yDst);
  /*
  //$BLG - v4.6a4
  //Former code, already optimized by me - trying to use hardware performance...
  //Optimization forgotten: use of gluScaleImage() induced a 15x performance down !!!
  //Back to originally optimized code
	for(y=0; y<jn; y++)
	{
		ybase = y*in;
		yl	  = y*j/jn;
		yl	 *= i;

		for(x=0; x<in; x++)
		{
			//$BLG Modif - v4.6a2
			//bufn[ (ybase+x)*4+0 ] = ImageModif[ (yl+x*i/in)*4+0 ];
			//bufn[ (ybase+x)*4+1 ] = ImageModif[ (yl+x*i/in)*4+1 ];
			//bufn[ (ybase+x)*4+2 ] = ImageModif[ (yl+x*i/in)*4+2 ];
			//bufn[ (ybase+x)*4+3 ] = ImageModif[ (yl+x*i/in)*4+3 ];
			blg_ySrc = (yl+x*i/in)*4;
			blg_yDst = (ybase+x)*4;
			//$BLG - v4.6a4
			//Removed the next part of my original optimization (v4.6a2) - replaced it with assembler code: BLG_Copy32Bits().
			// -> 5% performance enhancement.
			//bufn[ blg_yDst+0 ] = ImageModif[ blg_ySrc+0 ];
			//bufn[ blg_yDst+1 ] = ImageModif[ blg_ySrc+1 ];
			//bufn[ blg_yDst+2 ] = ImageModif[ blg_ySrc+2 ];
			//bufn[ blg_yDst+3 ] = ImageModif[ blg_ySrc+3 ];
			BLG_Copy32Bits(ImageModif + blg_ySrc, bufn + blg_yDst);
		}
	}
  //$BLG - v4.6a4
  //Above forgotten "optimization" - former optimized code has been restored/modified.
	//gluScaleImage(GL_RGBA, i, j, GL_UNSIGNED_BYTE, ImageModif, in, jn, GL_UNSIGNED_BYTE, bufn);
	*/

	free(ImageModif);
	ImageModif	= (unsigned char *)bufn;
	Width	= in;
	Height	= jn;

	return true;
}




///////////////////////////////////////////////////////////////////////////////////////////////
///		LoadBitmapTexture																	///
///////////////////////////////////////////////////////////////////////////////////////////////
bool ZTexture::LoadBMPTexture(char *filename)//, bool transpColor, unsigned char Red, unsigned char Green, unsigned char Blue, unsigned char tolerance)
{
	FILE				* File;
	BITMAPFILEHEADER	FileHeader;
	BITMAPINFOHEADER	InfoHeader;
	DWORD				Type;
	int					i, j, off=0;

//	_asm{int 3};

	if ((File = fopen(filename, "rb"))==NULL)		return false;
	
	// test de validité du fichier
	char test[1200];
	fread(test,1,0x36,File);
	if(test[0]!='B' || test[1]!='M')
	{
		fclose(File);
		return false;
	}
	fseek(File, 0, SEEK_SET);

	// read the header and type, then seek to the next position
	fread(&FileHeader, sizeof(FileHeader), 1, File);
	fread(&Type, sizeof(Type), 1, File);
	fseek(File, sizeof(FileHeader), SEEK_SET);

	// read the infoheader
	fread(&InfoHeader, sizeof(InfoHeader), 1, File);


	// set our texture width and height from what is read in the file
	Width	= InfoHeader.biWidth;
	Height	= InfoHeader.biHeight;

	if(InfoHeader.biBitCount == 16)
	{
		if(Image!=NULL)		free(Image);
		Image	= (unsigned char *) malloc(Width * Height * 4);
		memset(Image, 0, Width * Height * 4);

		int k;
		int testX = (Width*2)%4;
		if(testX!=0)		testX = 4-testX;
		
		if(InfoHeader.biCompression==BI_RGB)
		{
			unsigned short	maskB=0x001F, maskG=0x03E0, maskR=0x7C00;
			unsigned short	coul;

			for (j=0; j < InfoHeader.biHeight; j++)
			{
				for (i=0; i < InfoHeader.biWidth; i++)
				{
					fread(&coul, sizeof(coul), 1, File);

					Image[off+0] = (coul&maskR)>>7;
					Image[off+1] = (coul&maskG)>>2;
					Image[off+2] = (coul&maskB)<<3;
					Image[off+3] = 255;

					off += 4;
				}
				for(k=0; k<testX; k++)		fgetc(File);
			}
		}
		else
		{
			fclose(File);
			return false;
		}
	}
	else
	if(InfoHeader.biBitCount == 24)
	{
		if(Image!=NULL)		free(Image);
		Image	= (unsigned char *) malloc(Width * Height * 4);
		memset(Image, 0, Width * Height * 4);
		RGBTRIPLE			rgb;

		int testX = (Width*3)%4;
		if(testX!=0)		testX = 4-testX;

		int k;

		for (j=0; j < Height; j++)
		{
			for (i=0; i < Width; i++)
			{
				// load the r g and b values from the file into an RGBTRIPLE structure
				fread(&rgb, sizeof(rgb), 1, File);

				Image[off+0] = rgb.rgbtRed;
				Image[off+1] = rgb.rgbtGreen;
				Image[off+2] = rgb.rgbtBlue;
				Image[off+3] = 255;
				off += 4;
			}

			for(k=0; k<testX; k++)		fgetc(File);
		}
	}
	else
	if(InfoHeader.biBitCount == 32)
	{
		if(Image!=NULL)		free(Image);
		Image	= (unsigned char *) malloc(Width * Height * 4);
		memset(Image, 0, Width * Height * 4);
		RGBQUAD			rgba;

		for (j=0; j < InfoHeader.biHeight; j++)
		{
			for (i=0; i < InfoHeader.biWidth; i++)
			{
				// load the r g and b values from the file into an RGBTRIPLE structure
				fread(&rgba, sizeof(rgba), 1, File);

				Image[off+0] = rgba.rgbRed;
				Image[off+1] = rgba.rgbGreen;
				Image[off+2] = rgba.rgbBlue;
				Image[off+3] = rgba.rgbReserved;

				off += 4;
			}
		}
	}
	else
	if(InfoHeader.biBitCount == 8)
	{
		if(Image!=NULL)		free(Image);
		Image	= (unsigned char *) malloc(Width * Height * 4);
		memset(Image, 0, Width * Height * 4);

		fseek(File, 54, SEEK_SET);

		RGBQUAD			rgb[256];
		for (i=0; i < 256; i++)			fread(&(rgb[i]), sizeof(rgb[i]), 1, File);

		fseek(File, 1078, SEEK_SET);
		unsigned char	coul;

		transpR = rgb[0].rgbRed;
		transpG = rgb[0].rgbGreen;
		transpB = rgb[0].rgbBlue;

		int k;
		int testX = (Width)%4;
		if(testX!=0)		testX = 4-testX;

		for (j=0; j < InfoHeader.biHeight; j++)
		{
			for (i=0; i < InfoHeader.biWidth; i++)
			{
				// load the r g and b values from the file into an RGBTRIPLE structure
				fread(&coul, 1, 1, File);

				Image[off+0] = rgb[coul].rgbRed;
				Image[off+1] = rgb[coul].rgbGreen;
				Image[off+2] = rgb[coul].rgbBlue;

				if(coul)		Image[off+3] = 255;
				else			Image[off+3] = 0;

				off += 4;
			}
			for(k=0; k<testX; k++)		fgetc(File);
		}
	}

	fclose(File);

	return true;
}



int GetHEXA(const string &c, int pos, int size)
{
	int	a,k,i,n;
	k=0;
	for(i=pos; i<pos+size; i++)
	{
		a = c[i];
		if ((a>='0')&&(a<='9'))			n = a-'0';
		else if ((a>='A')&&(a<='F'))	n = 10+a-'A';
		else if ((a>='a')&&(a<='f'))	n = 10+a-'a';
		else							n = 0;
		k = (k<<4) + n;
	}
	
	return k;
}


int RGB2HSV(unsigned char R, unsigned char G, unsigned char B, float *rh, float *rs, float *rv)
{
	int		max, min;
	float	h, s, v, delta;

	if(R>G)			max = R;
	else			max = G;
	if(B>max)		max = B;

	if(R<G)			min = R; 
	else			min = G;
	if(B<min)		min = B;
	
	v = max;
	v/= 255;

	if(max)
	{
		s = max-min;
		s/= max;
	}
	else s=0;

	if(s==0)	h=0;
	else
	{
		delta = max-min;
		if(R==max)			h = (G-B)/delta;
		else if(G==max)		h = 2+(B-R)/delta;
		else				h = 4+(R-G)/delta;
		h *= 60;
		if(h<0)				h += 360;
	}
	
	*rh=h; 
	*rs=s; 
	*rv=v;

	return 0;
}


void HSV2RGB(float h, float s, float v, unsigned char *R, unsigned char *G, unsigned char *B)
{
	int		i;
	float	f,p,q,t;
		
	v *= 255.0f;
	if(s==0.0f)		*R = *G = *B = v;
	else
	{
		while(h>=360.0f)		h -= 360.0f;
		while(h<0.0f)			h += 360.0f;
		h/=60.0f;
		i = floor(h);
		f = h-(float)i;
		p = v*(1.-s);
		q = v*(1.-s*f);
		t = v*(1.-s*(1.-f));
		
		switch(i)	
		{
			case 0:
					*R=v; *G=t; *B=p;
					break;
			case 1:
					*R=q; *G=v; *B=p;
					break;
			case 2:
					*R=p; *G=v; *B=t;
					break;
			case 3:
					*R=p; *G=q; *B=v;
					break;
			case 4:
					*R=t; *G=p; *B=v;
					break;
			case 5:
					*R=v; *G=p; *B=q;
					break;
		}
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///		CreateModifiedImg																	///
///////////////////////////////////////////////////////////////////////////////////////////////
bool ZTexture::CreateModifiedImg()
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::CreateModifiedImg ");
#endif

	if(Image==NULL)		return false;

	if(ImageModif==NULL)	ImageModif	= (unsigned char *) malloc(Width * Height * 4);
	memcpy(ImageModif, Image, Width*Height*4);

	int i=0, size=name.size();
	int	colR, colG, colB, coef;

	C = X = Y = A = R = S = false;

	if(size && name[i]=='%')
	{
		i++;

		while(i<size && name[i]!='%')
		{
			if(name[i]=='C' && (size-i>8) )
			{
				colB = GetHEXA(name, i+1, 2);		colG = GetHEXA(name, i+3, 2);
				colR = GetHEXA(name, i+5, 2);		coef = GetHEXA(name, i+7, 2);

				for(int off=0; off<Width*Height*4; off+=4)
				{
					ImageModif[off+0] = ((ImageModif[off+0]*(256-coef))>>8) + ((colR*coef)>>8);
					ImageModif[off+1] = ((ImageModif[off+1]*(256-coef))>>8) + ((colG*coef)>>8);
					ImageModif[off+2] = ((ImageModif[off+2]*(256-coef))>>8) + ((colB*coef)>>8);
				}
				i += 9;
			}
			else if(name[i]=='A' && (size-i>8) )
			{
				colB = GetHEXA(name, i+1, 2);		colG = GetHEXA(name, i+3, 2);
				colR = GetHEXA(name, i+5, 2);		coef = GetHEXA(name, i+7, 2);

				transpR = colR;		
				transpG = colG;		
				transpB = colB;		
				rate	= coef;
				
				A = true;

				coef *= 3;

				for(int off=0; off<Width*Height*4; off+=4)
				{
					if( abs(ImageModif[off+0]-colR)+abs(colG-ImageModif[off+1])+abs(ImageModif[off+2]-colB) < coef )
					{
						//$BLG: Modified like M3filter(): this is an attraction filter, not a black attraction filter
						//if(accelerated)	ImageModif[off+0] = ImageModif[off+1] = ImageModif[off+2] = 0;
						//else
						//{
							ImageModif[off+0] = colR;
							ImageModif[off+1] = colG;
							ImageModif[off+2] = colB;
						//}
						ImageModif[off+3] = 0;
					}
				}
				i+=9;
			}
			else if(name[i]=='X')
			{
				char tmpCol;

				for(int off=0; off<Width*Height*4; off+=4)
				{
					tmpCol = ImageModif[off+0];
					ImageModif[off+0] = ImageModif[off+1];
					ImageModif[off+1] = ImageModif[off+2];
					ImageModif[off+2] = tmpCol;
				}
				i++;
			}
			else if(name[i]=='Y')
			{
				char tmpCol;

				for(int off=0; off<Width*Height*4; off+=4)
				{
					tmpCol = ImageModif[off+2];
					ImageModif[off+2] = ImageModif[off+1];
					ImageModif[off+1] = ImageModif[off+0];
					ImageModif[off+0] = tmpCol;
				}
				i++;
			}
			else if(name[i]=='R' && (size-i>4) )
			{

				int		ang = (GetHEXA(name, i+1, 4)*360)>>16;
				float	rh, rs, rv;
				for(int off=0; off<Width*Height*4; off+=4)
				{
					RGB2HSV(ImageModif[off+0], ImageModif[off+1], ImageModif[off+2], &rh,&rs,&rv);
					HSV2RGB(rh+ang, rs, rv, &ImageModif[off+0], &ImageModif[off+1], &ImageModif[off+2]);
				}
				i+=5;
			}
			else if(name[i]=='S' && (size-i>6) )
			{

				int		sat16 = GetHEXA(name, i+1, 4);
				float	sat = sat16;
				float	rh, rs, rv;

				sat /= 65536.0f;
				coef = GetHEXA(name, i+5, 2);

				for(int off=0; off<Width*Height*4; off+=4)
				{
					RGB2HSV(ImageModif[off+0], ImageModif[off+1], ImageModif[off+2], &rh,&rs,&rv);
					HSV2RGB(rh, (rs*(256-coef)+sat*coef)/256, rv, &ImageModif[off+0], &ImageModif[off+1], &ImageModif[off+2]);
				}
				i+=7;
			}
      //$BLG Start: Opengl filters: TF_NONE, TF_LINEAR, TF_BILINEAR, TF_TRILINEAR
			else if(name[i]=='O' && (size-i>1) )
			{
				int		blg_ogl = GetHEXA(name, i+1, 1);
        BLG_SetTextureFilter(blg_ogl);
				i+=2;
			}			
      //$BLG End
			else i++;
		}
	}

	renamed = false;			// becoz we have used the NEW flags of rendering
	free(Image);
	Image = NULL;

	return true;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		CreateModifiedImg																	///
///////////////////////////////////////////////////////////////////////////////////////////////
bool ZTexture::CreateModifiedImg_WithoutLoading_A()
{
#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::CreateModifiedImg_WithoutLoading_A ");
#endif

	if(Image==NULL)		return false;

	if(ImageModif==NULL)	ImageModif	= (unsigned char *) malloc(Width * Height * 4);
	memcpy(ImageModif, Image, Width*Height*4);

	int i=0, size=name.size();
	int	colR, colG, colB, coef;

	C = X = Y = R = S = false;

	if(size && name[i]=='%')
	{
		i++;

		while(i<size && name[i]!='%')
		{
			if(name[i]=='C' && (size-i>8) )
			{
				colB = GetHEXA(name, i+1, 2);		colG = GetHEXA(name, i+3, 2);
				colR = GetHEXA(name, i+5, 2);		coef = GetHEXA(name, i+7, 2);

				for(int off=0; off<Width*Height*4; off+=4)
				{
					ImageModif[off+0] = ((ImageModif[off+0]*(256-coef))>>8) + ((colR*coef)>>8);
					ImageModif[off+1] = ((ImageModif[off+1]*(256-coef))>>8) + ((colG*coef)>>8);
					ImageModif[off+2] = ((ImageModif[off+2]*(256-coef))>>8) + ((colB*coef)>>8);
				}
				i += 9;
			}
			else if(name[i]=='A' && (size-i>8) )
			{
				i+=9;
			}
			else if(name[i]=='X')
			{
				char tmpCol;
				for(int off=0; off<Width*Height*4; off+=4)
				{
					tmpCol = ImageModif[off+0];
					ImageModif[off+0] = ImageModif[off+1];
					ImageModif[off+1] = ImageModif[off+2];
					ImageModif[off+2] = tmpCol;
				}
				i++;
			}
			else if(name[i]=='Y')
			{
				char tmpCol;
				for(int off=0; off<Width*Height*4; off+=4)
				{
					tmpCol = ImageModif[off+2];
					ImageModif[off+2] = ImageModif[off+1];
					ImageModif[off+1] = ImageModif[off+0];
					ImageModif[off+0] = tmpCol;
				}
				i++;
			}
			else if(name[i]=='R' && (size-i>4) )
			{
				int		ang = (GetHEXA(name, i+1, 4)*360)>>16;
				float	rh, rs, rv;
				for(int off=0; off<Width*Height*4; off+=4)
				{
					RGB2HSV(ImageModif[off+0], ImageModif[off+1], ImageModif[off+2], &rh,&rs,&rv);
					HSV2RGB(rh+ang, rs, rv, &ImageModif[off+0], &ImageModif[off+1], &ImageModif[off+2]);
				}
				i+=5;
			}
			else if(name[i]=='S' && (size-i>6) )
			{
				int		sat16 = GetHEXA(name, i+1, 4);
				float	sat = sat16;
				float	rh, rs, rv;

				sat /= 65536.0f;
				coef = GetHEXA(name, i+5, 2);

				for(int off=0; off<Width*Height*4; off+=4)
				{
					RGB2HSV(ImageModif[off+0], ImageModif[off+1], ImageModif[off+2], &rh,&rs,&rv);
					HSV2RGB(rh, (rs*(256-coef)+sat*coef)/256, rv, &ImageModif[off+0], &ImageModif[off+1], &ImageModif[off+2]);
				}
				i+=7;
			}
			else i++;
		}
	}

	if(A)
	{
		coef = rate*3;

		for(int off=0; off<Width*Height*4; off+=4)
		{
			if( abs(ImageModif[off+0]-transpR)+abs(transpG-ImageModif[off+1])+abs(ImageModif[off+2]-transpB) < coef )
			{
				if(accelerated)	ImageModif[off+0] = ImageModif[off+1] = ImageModif[off+2] = 0;
				else
				{
					ImageModif[off+0] = transpR;
					ImageModif[off+1] = transpG;
					ImageModif[off+2] = transpB;
				}
				ImageModif[off+3] = 0;
			}
		}
	}


	renamed = false;			// becoz we have used the NEW flags of rendering
	free(Image);
	Image = NULL;

	return true;
}



///////////////////////////////////////////////////////////////////////////////////////////////
///		SetupTexture																		///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZTexture::SetupTexture()
{

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::SetupTexture ");
#endif

	if(accelerated)
	{
		if(ID_created)
		{
			glDeleteTextures(1, &texID);
			ID_created = false;
		}

		if(ImageModif==NULL)		return;

		// tell OpenGL we want to use this texture's Id
		glGenTextures(1, &texID);
		ID_created = true;
		glBindTexture(GL_TEXTURE_2D, texID);

/* MS Modification sur les paramètres de textures */

		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, /*GL_CLAMP_TO_EDGE*/GL_REPEAT);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, /*GL_CLAMP_TO_EDGE*/GL_REPEAT);


		if( (filter==TF_NONE)  )
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		else if(filter == TF_LINEAR)
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		}
		else if(filter == TF_BILINEAR)
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		}
		else if(filter == TF_TRILINEAR)
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		}

		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

		glTexImage2D(GL_TEXTURE_2D, 0, 4, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ImageModif );

		if(filter!=TF_NONE)			gluBuild2DMipmaps( GL_TEXTURE_2D, 4, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, ImageModif );

		free(ImageModif);
		ImageModif = NULL;
	}
	else
	{
	int i, im;

		//$LB
		if(bitmap24)	free(bitmap24);

		bitmap24 = (OBJBITMAP_BUFFER) malloc(Width * Height * 3);

		OBJBITMAP_BUFFER bitm = (OBJBITMAP_BUFFER)bitmap24;

		for(i=0, im=0; i< Width * Height * 3;)
		{
			bitm[i++] = ImageModif[im++];
			bitm[i++] = ImageModif[im++];
			bitm[i++] = ImageModif[im++];
			im++;
		}

		free(ImageModif);
		ImageModif = NULL;
	}
}


//$BLG
//Same as SetupTexture (simplified), but used with BLG_SetTextureFilter, not SetTextureFilter.
//Note that this last function (SetTextureFilter) is called elsewhere in the code of the VM.
//This function is used only to apply OpenGL filters in hardware rendering mode, without 
//conflict with Scol texture filters.
///////////////////////////////////////////////////////////////////////////////////////////////
///		BLG_SetupTexture																		///
///////////////////////////////////////////////////////////////////////////////////////////////
void ZTexture::BLG_SetupTexture()
{

#ifdef	_SCOL_DEBUG_
	MMechostr(0,"ZTexture::BLG_SetupTexture ");
#endif

	if(accelerated)
	{
		if(ID_created)
		{
			glDeleteTextures(1, &texID);
			ID_created = false;
		}

		if(ImageModif==NULL)		return;

		// tell OpenGL we want to use this texture's Id
		glGenTextures(1, &texID);
		ID_created = true;
		glBindTexture(GL_TEXTURE_2D, texID);

		if( (filter==TF_NONE)  )
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		}
		else if(filter == TF_LINEAR)
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		}
		else if(filter == TF_BILINEAR)
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		}
		else if(filter == TF_TRILINEAR)
		{
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		}
	}
}





///////////////////////////////////////////////////////////////////////////
/// Load JPEG image														///
///////////////////////////////////////////////////////////////////////////
bool ZTexture::LoadJPGTexture(char *filename)
{
	Image = (unsigned char*) LoadJpgFromFile(filename, &Width, &Height);

	if(Image==NULL)		return false;
	else				return true;

}


///////////////////////////////////
///	The loader					///
///////////////////////////////////
bool ZTexture::LoadPNGTexture(char *filename)
{
	long	image_width, image_height;
	uch		bg_red=0, bg_green=0, bg_blue=0;
	uch		trn_red=0, trn_green=0, trn_blue=0;
	ulg		image_rowbytes;
	int		image_channels;
	uch		*image_data;

	FILE *infile = NULL;
	if ((infile=fopen(filename,"rb")) == NULL)		return false;

	if (readpng_init(infile, &image_width, &image_height) != 0)
	{
		fclose(infile);
    readpng_cleanup(true);
		return false;
	}

	if (readpng_get_bgcolor(&bg_red, &bg_green, &bg_blue) > 1)
	{
		fclose( infile );
    readpng_cleanup( TRUE );
		return false;
	}

//	MMechostr(0,"$BLG: readpng_get_image - sta\n");
	image_data = readpng_get_image(&image_channels, &image_rowbytes );
//	MMechostr(0,"$BLG: readpng_get_image - end\n");
  fclose(infile);

  if (!image_data)
	{
		readpng_cleanup(TRUE);
		return false;
	}

	Width  = image_width;
	Height = image_height;

	Image  = (unsigned char *) malloc(Width * Height * 4);
	memset(Image, 0, Width * Height * 4);


  ulg i, row, lastrow;
	uch *src;

	for(lastrow = row = 0; row < Height; ++row) 
	{
    src = image_data + row * image_rowbytes;

		if(image_channels == 3) 
		{ 
      for(i=0; i<image_width; i++) 
			{
        Image[((Height-row-1)*Width+i)*4+0] = *src++;
        Image[((Height-row-1)*Width+i)*4+1] = *src++;
        Image[((Height-row-1)*Width+i)*4+2] = *src++;
        Image[((Height-row-1)*Width+i)*4+3] = 255;
      }
    }
		else /* if ( image_channels == 4 ) */ 
		{
      for(i=0; i<image_width; i++) 
			{
        Image[((Height-row-1)*Width+i)*4+0] = *src++;
        Image[((Height-row-1)*Width+i)*4+1] = *src++;
        Image[((Height-row-1)*Width+i)*4+2] = *src++;
        Image[((Height-row-1)*Width+i)*4+3] = *src++;
      }
		}
	}
	
	readpng_cleanup(TRUE);

	return true;
}







///////////////////////////////////////////////////////////////////////////
/// Set the texture as the current texture in the current unit			///
///////////////////////////////////////////////////////////////////////////
void ZTexture::PutGLparams()
{
	if(ID_created)	glBindTexture(GL_TEXTURE_2D, texID);
}

//////////////////////////////////////////////////////////////////////////////
////////////// Multitexturing ////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
/// Set the texture as the current texture in the current unit			///
///////////////////////////////////////////////////////////////////////////
void ZTexture::PutGLMultiparams0()
{
	if(ID_created)	
	{
		glActiveTextureARB( GL_TEXTURE0_ARB );
		glEnable( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, texID );
	}
}


///////////////////////////////////////////////////////////////////////////
/// Set the texture as the current texture in the current unit			///
///////////////////////////////////////////////////////////////////////////
void ZTexture::PutGLMultiparams1()
{
	if(ID_created)	
	{
		glActiveTextureARB( GL_TEXTURE1_ARB );
		glEnable( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, texID );
	}
}

///////////////////////////////////////////////////////////////////////////
/// Set the texture as the current texture in the current unit			///
///////////////////////////////////////////////////////////////////////////
void ZTexture::PutGLMultiparams2()
{
	if(ID_created)	
	{
		glActiveTextureARB( GL_TEXTURE2_ARB );
		glEnable( GL_TEXTURE_2D );
		glBindTexture( GL_TEXTURE_2D, texID );
	}
}




///////////////////////////////////////////////////////////////////////////
/// Set the name of the node											///
///////////////////////////////////////////////////////////////////////////
/// Input	: 
///		- the new name of the node
/// Output	: 
///		- set the new name of the node
/// Return	: NONE
void ZTexture::SetFileName(char * newName)
{
	filename = string(newName);
	renamed = true;
}

void ZTexture::SetFileName(string newName)
{
	filename = string((char*)newName.c_str());
	renamed = true;
}


























