
#include "main.h"
#include <math.h>
#include "savehead.h"


void ol_error( const char *msg, ... ) {



	va_list arglist;
	char bla[256];

	va_start(arglist, msg);

	vsprintf(bla,msg,arglist);
	MessageBox(NULL,bla,"Jimmy Hendrix's dead",MB_OK|MB_ICONERROR);
	va_end(arglist);	

}

void ol_error_fnumber( float number ) {
	va_list arglist;
	char bla[256];

	sprintf(bla,"%f",number);
	MessageBox(NULL,bla,"Jim's dead",MB_ICONERROR);	

}

unsigned char charbuff[256*256*4];

unsigned char char2buff[256*256*4];
#define uchar unsigned char


unsigned long RND_seed=1000;
     
unsigned long RND_find(unsigned long RND_limit) 
    {
    if (RND_limit==0) {RND_limit++;}
    RND_seed=(RND_seed*31421)+6927;
    return((RND_seed%RND_limit));
    }
//===============================================

void NOISE_MAKE(int *framebuf, int noise_amount, int type_noise)
			{
				
			for (int n=0;n<256*256;n++)
			{
				int rdpix=RND_find(noise_amount);
				int tempr, tempg, tempb;

				tempb=framebuf[n]&255;
				tempg=(framebuf[n]>>8)&255;
				tempr=(framebuf[n]>>16)&255;

				if (type_noise==0)	//saturation ADD
					{
					tempr+=rdpix; if (tempr>255) tempr=255;
					tempg+=rdpix; if (tempg>255) tempg=255;
					tempb+=rdpix; if (tempb>255) tempb=255;
					}

				if (type_noise==1)	//saturation ADD
					{
					tempr-=rdpix; if (tempr<0) tempr=0;
					tempg-=rdpix; if (tempg<0) tempg=0;
					tempb-=rdpix; if (tempb<0) tempb=0;
					}

				if (type_noise==2)
				{
				tempr=tempg=tempb=rdpix;
				}

				framebuf[n]=RGB(tempb, 
							    tempg, 
							    tempr);
				}
		}


	 void PLASMA_MAKE(int *framebuf, int off_x, int off_y, int freq_x, 
					  int freq_y, int plasm_r, int plasm_g, int plasm_b,
					  int plasm_a, int plasm_blend)
	 {

			for (int y=0;y<256;y++)
			{
				for (int x=0;x<256;x++)
				{
				int spx, spxr,spxg,spxb;
				spx=30+sin((x+off_x)*3.14*freq_x/128.0)*30.0;
				spx+=30+sin((y+off_y)*3.14*freq_y/128.0)*30.0;
				spx*=(plasm_a);
				spx>>=6;

				if (spx<0) spx=0;
				if (spx>255) spx=255;

				spxr=(spx*plasm_r)>>8;
				spxg=(spx*plasm_g)>>8;
				spxb=(spx*plasm_b)>>8;

				int tempr, tempg, tempb;

				tempb=framebuf[x+(y<<8)]&255;
				tempg=(framebuf[x+(y<<8)]>>8)&255;
				tempr=(framebuf[x+(y<<8)]>>16)&255;


				if (plasm_blend==1)	//saturation ADD
					{
					tempr+=spxr; if (tempr>255) tempr=255;
					tempg+=spxg; if (tempg>255) tempg=255;
					tempb+=spxb; if (tempb>255) tempb=255;
					}

				if (plasm_blend==2)	//saturation SUB
					{
					tempr-=spxr; if (tempr<0) tempr=0;
					tempg-=spxg; if (tempg<0) tempg=0;
					tempb-=spxb; if (tempb<0) tempb=0;
					}

				if (plasm_blend==3)
					{
					tempr=spxr;
					tempg=spxg;
					tempb=spxb;
					}

				framebuf[x+(y<<8)]=RGB(tempb,
									   tempg,
									   tempr);
				}

			}
	 }

void CONVintochar(int *src, unsigned char *dest)
{
	for (int n=0;n<256*256;n++)
	{
		unsigned char r,g,b;
				b=src[n]&255;
				g=(src[n]>>8)&255;
				r=(src[n]>>16)&255;
	dest[n<<2]=b;
	dest[1+(n<<2)]=g;
	dest[2+(n<<2)]=r;
	}
}

void CONVintocharRGB(int *src, unsigned char *dest)
{
	for (int n=0;n<256*256;n++)
	{
		unsigned char r,g,b;
				b=src[n]&255;
				g=(src[n]>>8)&255;
				r=(src[n]>>16)&255;
	dest[2+(n*3)]=b;
	dest[1+(n*3)]=g;
	dest[(n*3)]=r;
	}
}

void CONVchartoint(unsigned char *src, int *dest)
{
	for (int n=0;n<256*256;n++)
	{
		unsigned char r,g,b;

		b=src[n<<2];
		g=src[1+(n<<2)];
		r=src[2+(n<<2)];
	dest[n]=(b<<16)|(g<<8)|r;
	}
}

void MAKEblur(int *source)
{

 CONVintochar(source, charbuff);
	
 unsigned int c[3],u;

 for (int i=0;i<256*256;i++)
 {
	 for (u=0;u<3;u++)
	 {
	 int left, right, up, down;

	 left=i-1;
	 right=i+1;
	 up=i-256;
	 down=i+256;

	 left&=65535;
	 right&=65535;
	 up&=65535;
	 down&=65535;

		 c[u]=charbuff[(left<<2)+u];
		 c[u]+=charbuff[(right<<2)+u];
		 c[u]+=charbuff[(up<<2)+u];
		 c[u]+=charbuff[(down<<2)+u];
		 c[u]>>=2;
		 charbuff[(i<<2)+u]=c[u];
	 }

 }

 CONVchartoint(charbuff, source);	
}

void MAKEsharp(int *source)
{

 CONVintochar(source, charbuff);
	
 int c[3],u;

 for (int i=0;i<256*256;i++)
 {
	 for (u=0;u<3;u++)
	 {
	 int left, right, up, down;

	 left=i-1;
	 right=i+1;
	 up=i-256;
	 down=i+256;

	 left&=65535;
	 right&=65535;
	 up&=65535;
	 down&=65535;

		 c[u]=-charbuff[(left<<2)+u];
		 c[u]-=charbuff[(right<<2)+u];
		 c[u]-=charbuff[(up<<2)+u];
		 c[u]-=charbuff[(down<<2)+u];
		 c[u]+=(charbuff[(i<<2)+u]<<3);
		 c[u]>>=2;
		 if (c[u]<0) c[u]=0;
		 if (c[u]>255) c[u]=255;

		 /* SPACE COMME FILTRE :)
		 c[u]=-charbuff[(left<<2)+u];
		 c[u]-=charbuff[(right<<2)+u];
		 c[u]-=charbuff[(up<<2)+u];
		 c[u]-=charbuff[(down<<2)+u];
		 c[u]+=(charbuff[i<<2]<<2);
		 c[u]>>=1;
		 if (c[u]<0) c[u]=0;
		 if (c[u]>255) c[u]=255;
		 */

		 char2buff[(i<<2)+u]=c[u];
	 }

 }

 CONVchartoint(char2buff, source);	
}



void MAKEcontour(int *source)
{

 CONVintochar(source, charbuff);
	
 int c[3],u;

 for (int i=0;i<256*256;i++)
 {
	 for (u=0;u<3;u++)
	 {
	 int left, right, up, down;
	 int p[10];

	 left=i-1;
	 right=i+1;
	 up=i-256;
	 down=i+256;

	 p[0]=charbuff[(((i-256-1)&65535)<<2)+u];
	 p[1]=charbuff[(((i-256)&65535)<<2)+u];
	 p[2]=charbuff[(((i-256+1)&65535)<<2)+u];
	 p[3]=charbuff[(((i-1)&65535)<<2)+u];
	 p[4]=charbuff[(((i)&65535)<<2)+u];
	 p[5]=charbuff[(((i+1)&65535)<<2)+u];
	 p[6]=charbuff[(((i+256-1)&65535)<<2)+u];
	 p[7]=charbuff[(((i+256)&65535)<<2)+u];
	 p[8]=charbuff[(((i+256+1)&65535)<<2)+u];

		 c[u]=-p[1];
		 c[u]-=p[3];
		 c[u]-=p[5];
		 c[u]-=p[7];
		 c[u]+=(p[4]<<2);

		c[u]<<=4;
		 

		 if (c[u]<0) c[u]=0;
		 if (c[u]>255) c[u]=255;

		 /* SPACE COMME FILTRE :)
		 c[u]=-charbuff[(left<<2)+u];
		 c[u]-=charbuff[(right<<2)+u];
		 c[u]-=charbuff[(up<<2)+u];
		 c[u]-=charbuff[(down<<2)+u];
		 c[u]+=(charbuff[i<<2]<<2);
		 c[u]>>=1;
		 if (c[u]<0) c[u]=0;
		 if (c[u]>255) c[u]=255;
		 */

		 char2buff[(i<<2)+u]=c[u];
	 }

 }

 CONVchartoint(char2buff, source);	
}



void MAKEDiffuse(int *source)
{

 CONVintochar(source, charbuff);

 for (int i=0;i<256*256;i++)
 {
	 int tempi, x,y;

	 x=RND_find(256)-128;
	 x>>=4;
	 y=RND_find(256)-128;
	 y>>=4;
	 y*=256;

	 tempi=(x+i+y)&65535;
	 tempi<<=2;


	 char2buff[(i<<2)]=charbuff[tempi];
	 char2buff[(i<<2)+1]=charbuff[tempi+1];
	 char2buff[(i<<2)+2]=charbuff[tempi+2];
	 }


 CONVchartoint(char2buff, source);	
}





void COLOR_invert(int *source)
{
 int i=0;

 CONVintochar(source, charbuff);

 for (int x=0;x<256*256;x++)
 {
	 for (int c=0;c<3;c++)
	 {
	 charbuff[i+c]=255-charbuff[i+c];	
	 }
  i+=4;
 }

 CONVchartoint(charbuff, source);	
}


void COLOR_greyscale(int *source)
{
 int i=0;

 CONVintochar(source, charbuff);

 for (int x=0;x<256*256;x++)
 {
  int col=charbuff[i]+charbuff[i+1]+charbuff[i+2]+charbuff[i+2];
  col>>=2;

  for (int c=0;c<3;c++)
  {
	  charbuff[i+c]=col;
  }

  i+=4;
 }

 CONVchartoint(charbuff, source);	
}


void COLOR_contrast(int *source, float bright, float contrast)
{
 int i, c, col[3], mf[3];

 CONVintochar(source, charbuff);

 i=0;			/* trouve d'abord la valeur moyenne du bitmap */
 
 col[0]=col[1]=col[2]=0;

	for (int x=0;x<256*256;x++)
		{
		for (c=0;c<3;c++)
			{
			col[c]+=charbuff[c+i];
			}
		i+=4;
		}

 col[0]>>=16;
 col[1]>>=16;
 col[2]>>=16;	//couleur moyenne

  i=0;
  	for (x=0;x<256*256;x++)
	{ 
		for (c=0;c<3;c++)
			{
			//mf[c]=(charbuff[c+i]-128) * contrast + 128;
			mf[c]=(int) (charbuff[c+i]);
			mf[c]+=(int) (col[c]*bright);

			if (mf[c]<col[c]) {mf[c]-=(int) (col[c]-mf[c])*contrast;}
			else {mf[c]+=(int) (mf[c]-col[c])*contrast;}

			if (mf[c] < 0) mf[c]=0;
	    	if (mf[c] > 255) mf[c]=255;
		
			charbuff[c+i]=mf[c];
			}
		i+=4;
		}


 CONVchartoint(charbuff, source);	
}



void COLOR_rgb(int *source, float rp, float gp, float bp)
{
int i;

 CONVintochar(source, charbuff);

 for (i=0;i<256*256*4;i+=4)
 {
 charbuff[i]=(charbuff[i]*bp)/256.0;
 charbuff[i+1]=(charbuff[i+1]*gp)/256.0;
 charbuff[i+2]=(charbuff[i+2]*rp)/256.0;

 }
 CONVchartoint(charbuff, source);	
}



void FX_SinusDeformation(int *source, float xamp, float xfreq, float yamp, float yfreq)
{

 CONVintochar(source, charbuff);
	
 float xn,yn;
 int    xf, yf;

 for (int x=0;x<256;x++)
 {
	for (int y=0;y<256;y++)
	{
		xn=sin(y*xfreq*3.14/128.0)*xamp;
		yn=cos(x*yfreq*3.14/128.0)*yamp;
		xn+=(float) x;	
		yn+=(float) y;  
		xf=(int) xn;	xf&=255;
		yf=(int) yn;	yf&=255;

		int off=xf+(yf<<8); off<<=2;
		*((long*) &char2buff[(x+(y<<8))<<2])=*((long*) &charbuff[off]);
	}
 }

 CONVchartoint(char2buff, source);	
}


void FX_Dilate(int *source, float dilatepower)
{
 int i=0;

 CONVintochar(source, charbuff);

 for (int x=0;x<256;x++)
 {
	for (int y=0;y<256;y++)
	{
	int n=(x+(y<<8))<<2;	//offset
	int nx,ny;

	for (int i=0;i<3;i++)
		{
		int i1, i2, i3, i4;

		i1=i-4+n;	i1&=262143;
		i2=i+4+n;		i2&=262143;
		i3=i-1024+n;	i3&=262143;
		i4=i+1024+n;	i4&=262143;

		nx=charbuff[i1]-charbuff[i2];
		ny=charbuff[i3]-charbuff[i4];
		int dist=(int) sqrt(nx*nx+ny*ny)*dilatepower;
		dist+=charbuff[n+i];
		if (dist>255) dist=255;
		char2buff[n+i]=dist;
		}
	}
 }

 CONVchartoint(char2buff, source);	
}



void FX_Bump(int *source, float bump_powaX, float bump_powaY, float bumplight)
{
 int i=0;

 CONVintochar(source, charbuff);

 for (int x=0;x<256;x++)
 {
	for (int y=0;y<256;y++)
	{
	int n=(x+(y<<8))<<2;	//offset
	int nx,ny;

	for (int i=0;i<3;i++)
		{
		int i1, i2, i3, i4;

		i1=i-4+n;		i1&=262143;
		i2=i+4+n;		i2&=262143;
		i3=i-1024+n;	i3&=262143;
		i4=i+1024+n;	i4&=262143;

		nx=charbuff[i2]-charbuff[i1];
		ny=charbuff[i4]-charbuff[i3];

		nx*=bump_powaX;
		ny*=bump_powaY;

		int col=abs((x-128)-nx);	//merci fred pour ce code limpide =)
		if (col>127) col=127;		 
		int difx=127-col;
		if (difx<0) difx=1;

		col=abs((y-128)-ny);
		if (col>127) col=127;
		int dify=127-col;
		if (dify<0) dify=1;

		col=(difx+dify)*charbuff[n+i]*bumplight;
		col>>=8;
		if (col>255) col=255;
		char2buff[n+i]=col;
		}
	}
 }

 CONVchartoint(char2buff, source);	
}


void FX_Displace(int *source, int dx, int dy)
{
 int i=0;

 CONVintochar(source, charbuff);

 for (int x=0;x<256;x++)
 {
	for (int y=0;y<256;y++)
	{
	int n=(x+(y<<8))<<2;	//offset

	int nx=x+dx; nx&=255;
	int ny=y+dy; ny&=255;

	*((long*) &char2buff[n])=*((long*) &charbuff[(nx+(ny<<8))<<2]);

	}
 }

 CONVchartoint(char2buff, source);	
}



	void GenColor_Do(int *framebuf, int bb, int bg, int br)
			{
			for (int n=0;n<256*256;n++)
			{framebuf[n]=RGB(bb, 
							 bg, 
							 br);}
			}




/******************************************************************************************/


void PROCESS_CHUNK_GEN_PLASMA(uchar *filebuffer, int *pixbuffer, int pos)
{
 uchar a[10];
 for (int n=0;n<9;n++) { a[n]=filebuffer[pos+1+n]; }	//skip the chunk
 PLASMA_MAKE(pixbuffer, a[2], a[3], a[0],  a[1], a[4], a[5], a[6], a[7], a[8]);
}

void PROCESS_CHUNK_GEN_NOISE(uchar *filebuffer, int *pixbuffer, int pos)
{
 uchar a1; short b2; uchar a3;
 a1=filebuffer[pos+1];
 b2=*((short*) &filebuffer[pos+2]);
 a3=filebuffer[pos+4];
 ///SEED_RANDOM=b2;			//<<------ a rajouter !!!!! selon le code..
 NOISE_MAKE(pixbuffer, a3, a1);
}

void PROCESS_CHUNK_GEN_FILL(uchar *filebuffer, int *pixbuffer, int pos)
{
 uchar a1,a2,a3;
 a1=filebuffer[pos+1];
 a2=filebuffer[pos+2];
 a3=filebuffer[pos+3];
 GenColor_Do(pixbuffer, a3, a2, a1);
}

void PROCESS_CHUNK_FX_SINUS(uchar *filebuffer, int *pixbuffer, int pos)
{
 uchar a1,a2,a3,a4;
 a1=filebuffer[pos+1];
 a2=filebuffer[pos+2];
 a3=filebuffer[pos+3];
 a4=filebuffer[pos+4];
 FX_SinusDeformation(pixbuffer, (float) a1, (float) a3, (float) a2, (float) a4);
}

void PROCESS_CHUNK_FX_BUMP(uchar *filebuffer, int *pixbuffer, int pos)
{
 float a1, a2, a3;
 a1=*((float*) &filebuffer[pos+1]);
 a2=*((float*) &filebuffer[pos+1+4]);
 a3=*((float*) &filebuffer[pos+1+8]);
 FX_Bump(pixbuffer, a1, a2, a3);
}

void PROCESS_CHUNK_FX_DILATE(uchar *filebuffer, int *pixbuffer, int pos)
{
 FX_Dilate(pixbuffer, *((float*) &filebuffer[pos+1]));
}

void PROCESS_CHUNK_FX_DISPLACE(uchar *filebuffer, int *pixbuffer, int pos)
{
 int a1,a2;
 a1=filebuffer[pos+1];
 a2=filebuffer[pos+2];
 FX_Displace(pixbuffer, a1, a2);
}

void PROCESS_CHUNK_FILT_GAUSSIAN(uchar *filebuffer, int *pixbuffer, int pos)
{

	for (int n=0;n<filebuffer[pos+1];n++)
	{
	MAKEblur(pixbuffer);
	}
}


void PROCESS_CHUNK_COL_BRIGHTCONT(uchar *filebuffer, int *pixbuffer, int pos)
{
 float a1,a2;

 a1=*((float*) &filebuffer[pos+1]);
 a2=*((float*) &filebuffer[pos+1+4]);
 COLOR_contrast(pixbuffer, a1, a2);
}




void PROCESS_CHUNK_COL_RGB(uchar *filebuffer, int *pixbuffer, int pos)
{
 uchar a1,a2,a3;
 a1=filebuffer[pos+1];
 a2=filebuffer[pos+2];
 a3=filebuffer[pos+3];
 COLOR_rgb(pixbuffer, a1, a2, a3);
}

int pixbuffer[256*256];
unsigned char gainsbarre[256*256*4];


void PROCESS_NML_FILE(unsigned char *filebuffer, unsigned char *dest)
{
int n=3;
unsigned char chunk;

//	unsigned char *gainsbarre;
	//gainsbarre=(unsigned char*) malloc(256*256*4);	

	for (int u=0;u<256*256;u++)
	{
		pixbuffer[u]=0;
	}


	//check if the header is correct

	reprocess:;

	chunk=filebuffer[n];

	if (chunk==CHUNK_EOF) {
		//ol_error("EOT"); 
		CONVintocharRGB(pixbuffer, dest); 
		return;
	}

	switch(chunk)
	{
		case CHUNK_GEN_PLASMA:
			
		PROCESS_CHUNK_GEN_PLASMA(filebuffer, pixbuffer, n);
		n+=10;
		break;

		case CHUNK_GEN_NOISE:
	
		PROCESS_CHUNK_GEN_NOISE(filebuffer, pixbuffer, n);
		n+=5;
		break;
		
		case CHUNK_GEN_FILL:
			
		PROCESS_CHUNK_GEN_FILL(filebuffer, pixbuffer, n);
		n+=4;
		break;

		case CHUNK_FX_SINUS:
			
		PROCESS_CHUNK_FX_SINUS(filebuffer, pixbuffer, n);
		n+=5;
		break;

		case CHUNK_FX_BUMP:
		
		PROCESS_CHUNK_FX_BUMP(filebuffer, pixbuffer, n);
		n+=13;
		break;

		case CHUNK_FX_DILATE:
			
		PROCESS_CHUNK_FX_DILATE(filebuffer, pixbuffer, n);
		n+=5;
		break;

		case CHUNK_FX_DISPLACE:
		
		PROCESS_CHUNK_FX_DISPLACE(filebuffer, pixbuffer, n);
		n+=3;
		break;

		case CHUNK_FILT_GAUSSIAN:
			
		PROCESS_CHUNK_FILT_GAUSSIAN(filebuffer, pixbuffer, n);
		n+=2;
		break;

		case CHUNK_FILT_SHARPEN:
		
		MAKEsharp(pixbuffer);
		n+=1;
		break;

		case CHUNK_FILT_STRIPES:
		
		MAKEDiffuse(pixbuffer);
		n+=1;
		break;

	//	case CHUNK_FILT_EMBOSS:
		
	//	MAKEemboss(pixbuffer);
		//n+=1;
		//break;
	
		//case CHUNK_FILT_CONTOUR:
		
		//MAKEcontour(pixbuffer);
	//	n+=1;
		//break;

		case CHUNK_COL_INVERT:
		
		COLOR_invert(pixbuffer);
		n+=1;
		break;

		case CHUNK_COL_GREYSCALE:
		
		COLOR_greyscale(pixbuffer);
		n+=1;
		break;

		case CHUNK_COL_BRIGHTCONT:
		
		PROCESS_CHUNK_COL_BRIGHTCONT(filebuffer, pixbuffer, n);
		n+=9;
		break;

		case CHUNK_COL_RGB:
		
		PROCESS_CHUNK_COL_RGB(filebuffer, pixbuffer, n);
		n+=4;
		break;

	//	case CHUNK_FILE_KWI:
	//	n+=1;
	//	break;
	}

	goto reprocess;

	
}
