#define VIRGULE 16
#define MULT 65536.0
int _supportMasque=1;
#define SupportMasque(active)		(_supportMasque=active)

HDC hdcConsole, hdcImage;
HWND hConsole;
#if !defined(LARGEUR_FENETRE) || !defined(HAUTEUR_FENETRE)
	int LARG=640, HAUT=300;
#else
	int LARG=LARGEUR_FENETRE, HAUT=HAUTEUR_FENETRE;
#endif
int LARG_BUF=640, HAUT_BUF=300;

int CLIP_X0=0, CLIP_Y0=0, CLIP_X1=640, CLIP_Y1=300;
#define ASSERT(condition)	if (!(condition))	  MessageBox(GetFocus(),"Erreur: "#condition,"Deception",0);
unsigned char *Bits=NULL;
BITMAPINFOHEADER BIH;

typedef unsigned char * SPRITE;
HBITMAP hbm;

//Clippe un sprite
#define ClipSprite			{										\
							if (!Bits || !sprite)	return;			\
							if (y0<0)	{							\
								sprite+=l*(y0)*3;					\
								h-=0-y0;							\
								y0=0;								\
							}										\
							if (x0<0)	{							\
								l+=0+x0;							\
								a-=x0;								\
								sprite+=-x0*3;						\
								x0=0;								\
							}										\
							y0+=CLIP_Y0;							\
							x0+=CLIP_X0;							\
							if (y0+h>=CLIP_Y1)	{					\
								h+=CLIP_Y1-(y0+h);					\
							}										\
							if (x0+l>=CLIP_X1)	{					\
								a+=-(CLIP_X1-(x0+l));				\
								l+=CLIP_X1-(x0+l);					\
							}										\
							a*=3;									\
							if (h<0)	return;						\
							}

//Clippe un sprite 8 bits
#define ClipSprite8			{										\
							if (!Bits || !sprite)	return;			\
							if (y0<0)	{							\
								sprite+=l*(0-y0);					\
								h-=0-y0;							\
								y0=0;								\
							}										\
							if (x0<0)	{							\
								l+=0+x0;							\
								a=-x0;								\
								sprite+=-x0;						\
								x0=0;								\
							}										\
							y0+=CLIP_Y0;							\
							x0+=CLIP_X0;							\
							if (y0+h>=CLIP_Y1)	{					\
								h+=CLIP_Y1-(y0+h);					\
							}										\
							if (x0+l>=CLIP_X1)	{					\
								a+=-(CLIP_X1-(x0+l));				\
								l+=CLIP_X1-(x0+l);					\
							}										\
							if (h<0)	return;						\
							}

//Clippe un rectangle (sans blague!)
#define ClipRect			{										\
							if (!Bits)	return;						\
							if (y0<0)	{							\
								h-=0-y0;							\
								y0=0;								\
							}										\
							if (x0<0)	{							\
								l+=0+x0;							\
								x0=0;								\
							}										\
							y0+=CLIP_Y0;							\
							x0+=CLIP_X0;							\
							if (y0+h>=CLIP_Y1)	{					\
								h+=CLIP_Y1-(y0+h);					\
							}										\
							if (x0+l>=CLIP_X1)	{					\
								l+=CLIP_X1-(x0+l);					\
							}										\
							if (h<0)	return;						\
							}

void AffErreur()		{
	LPVOID lpMsgBuf;
	FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		FORMAT_MESSAGE_FROM_SYSTEM | 
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL 
	);
	// Process any inserts in lpMsgBuf.
	// ...
	// Display the string.
	MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
	// Free the buffer.
	LocalFree( lpMsgBuf );
}

//Crée une DIB de taille "cx" et "cy" pour pouvoir y dessiner en l'utilisant comme un
//bloc de mémoire de "ibitcount" bits par pixel. La sélectionne dans "hdc" et la stocke
//dans "hbm". Le pointeur sur les bits de cette bitmap sera écrit dans "bits".
int CreeDIB(HDC hdc, int cx, int cy, int ibitcount, HBITMAP *hbm, void **bits) 
{
   // Create a BITMAPINFOHEADER structure to describe the DIB.
   int iSize = sizeof(BITMAPINFOHEADER);

   ASSERT((ibitcount == 8) || (ibitcount == 16) || (ibitcount == 24) || (ibitcount == 32)) ;
   ASSERT(cx > 0);
   ASSERT(cy > 0);
   memset(&BIH, 0, iSize);

   // Fill in the header info. 
   BIH.biSize = iSize;
   BIH.biWidth = cx;
   BIH.biHeight = cy+1;
   BIH.biPlanes = 1;
   BIH.biBitCount = ibitcount;
   BIH.biCompression = BI_RGB;

   // Create a new device context.

   // Create the DIB section.
   *hbm = CreateDIBSection(hdc,
               (BITMAPINFO*) &BIH,
                             DIB_RGB_COLORS,
                             (void**)bits,
                             NULL,
                             0);
	
    ASSERT(*hbm);
    ASSERT(*bits);

    // Select the new bitmap into the buffer DC.
    if (*hbm && *bits)
    {
        SelectObject(hdc,*hbm);
		return 1;
    }
	else	{
		return 0;
	}
}

#include <Graphlib/texte.h>

int SCALING=0, SCALING_BILINEAIRE=0;

void ModeScaling(int allume, int bilineaire)		{
	SCALING=allume;
	SCALING_BILINEAIRE=bilineaire;
}

//#define SCALING
//#define SCALING_BILINEAIRE

void AfficheEcran()		{
	if (SCALING)		{
		RECT rect;
		HDC hdcFenetre=hdcConsole;
		GetClientRect(hConsole,&rect);
		if (SCALING_BILINEAIRE)
			SetStretchBltMode(hdcFenetre,HALFTONE);
		else
			SetStretchBltMode(hdcFenetre,COLORONCOLOR);
		StretchBlt(hdcConsole,0,0,rect.right,rect.bottom,hdcImage,CLIP_X0,CLIP_Y0,CLIP_X1-CLIP_X0,CLIP_Y1-CLIP_Y0,SRCCOPY);
	}
	else
		BitBlt(hdcConsole,0,0,CLIP_X1-CLIP_X0,CLIP_Y1-CLIP_Y0,hdcImage,CLIP_X0,CLIP_Y0,SRCCOPY);
}

void AffichePleinEcran ()		{
	BitBlt(GetDC(NULL),0,0,LARG,HAUT,hdcImage,0,0,SRCCOPY);
}

//Colore un cadre sans transparence
void Cadre(int x0, int y0, int l, int h, int couleur)	{
	register unsigned char *bits=Bits+LARG_BUF*3*HAUT_BUF, *ptr;
	register int x, y;
	register unsigned char rouge=couleur&0x000000ff, vert=(couleur&0x0000ff00)>>8, bleu=(couleur&0x00ff0000)>>16;

	ClipRect;

	for (y=y0;y<y0+h;y++)	{
		ptr=bits-LARG_BUF*3*y+3*x0;
		for (x=0;x<l;x++)	{
			*(ptr++)=bleu;
			*(ptr++)=vert;
			*(ptr++)=rouge;
		}
	}
}

#include <Graphlib/pixels.h>

void Sprite(int x0, int y0, int l, int h, register unsigned char *sprite)		{
	int x, y, a=-(l*2);
	register unsigned char *bits=Bits+LARG_BUF*3*(HAUT_BUF), *ptr;

	sprite+=(h-1)*l*3;
	ClipSprite;

	for (y=y0;y<y0+h;y++)	{
		ptr=bits-LARG_BUF*3*y+3*x0;
		for (x=0;x<l;x++)	{
			if (*sprite==0xfe)		{
				sprite+=3;
				ptr+=3;
				continue;
			}
			*ptr=*sprite++;
			ptr++;
			*ptr=*sprite++;
			ptr++;
			*ptr=*sprite++;
			ptr++;
		}
		sprite+=a;
	}
}

//Mouais... rapide entre guillemets quoi! Elle élimine la fonction de pixels transparents et copie plus rapidement
void SpriteRapide(int x0, int y0, int l, int h, register unsigned char *sprite)		{
	int x, y, a=0;
	register unsigned char *bits=Bits+LARG_BUF*3*HAUT_BUF, *ptr, tmp;

	ClipSprite;

	for (y=y0;y<y0+h;y++)	{
		ptr=bits-LARG_BUF*3*y-3*(LARG_BUF-x0);
		for (x=0;x<l;x++)	{
			tmp=*(ptr+3);
			*(long*)ptr=*(long*)sprite;
			ptr+=3;
			sprite+=3;
		}
		*(ptr)=tmp;
		sprite+=a;
	}

}


int tx, ty;
unsigned char *ChargeBmpDansSprite24(const char *nomFichier)		{
	FILE *f;
	unsigned char *ptr, *bloc, *ptrbloc, *blocCharge;
	int i, x, y, offset;
	WORD v;

	f=fopen(nomFichier,"rb");

	if (!f)		{
//		erreurFatale("Impossible de charger un des fichiers bitmap.");
		return NULL;
	}

	for (i=0;i<=26;i++)	{
		fread(&v,sizeof(WORD),1,f);		//Un mot, c'est deux octets

		if (i==9)  tx=v;
		if (i==11) ty=v;
	}

	offset=tx%4;

	bloc=(unsigned char *)malloc(tx*(ty+1)*3);
	blocCharge=(unsigned char *)malloc(tx*(ty+1)*3);

	if ((signed)fread(blocCharge,3,tx*(ty+1),f)!=tx*ty)		{
//		fclose(f);
//		MessageBox(NULL,"Erreur de chargement de fichier bitmap.\nLe format est probablement faux...\nVérifiez qu'il s'agit d'une bitmap 24 bits...","Erreur",MB_ICONERROR);
	}
	fclose(f);

	ptrbloc=blocCharge;
	for (y=0;y<ty;y++)		{
		ptr=bloc+y*tx*3;
		for (x=0;x<tx*3;x++)		{
			if (!_supportMasque)		{
				if (*ptrbloc==0xfe)
					if (x%3==0)
						*ptrbloc=0xff;
			}
			*ptr++=*ptrbloc++;
		}
		ptrbloc+=offset;
	}

	return bloc;
}

unsigned char *ChargeBmpDansSprite24Rapide(const char *nomFichier)		{
	FILE *f;
	unsigned char *ptr, *bloc, *ptrbloc;
	int i, x, y;
	WORD v;

	f=fopen(nomFichier,"rb");

	if (!f)		{
//		erreurFatale("Impossible de charger un des fichiers bitmap.");
		return NULL;
	}

	for (i=0;i<=26;i++)	{
		fread(&v,sizeof(WORD),1,f);		//Un mot, c'est deux octets

		if (i==9)  tx=v;
		if (i==11) ty=v;
	}

/*	txi=tx;
	if (tx%4>0)
		tx+=4-tx%4;*/

/*	if (tx>LARG || ty>HAUT)		{
		MessageBox(NULL,"L'en-tête de la bitmap est faux ou trop gros.","Oups...",MB_ICONERROR);
		return NULL;
	}*/

	if (tx%4!=0)		{
		fclose(f);
		MessageBox(NULL,"La largeur de la bitmap n'est pas un multiple de 4.\nIl sera impossible de l'utiliser sinon...","Erreur",MB_ICONERROR);
		return NULL;
	}
	bloc=(unsigned char *)malloc(tx*(ty+1)*3);
	if ((signed)fread(bloc,3,tx*(ty+1),f)!=tx*ty)		{
		fclose(f);
		MessageBox(NULL,"Erreur de chargement de fichier bitmap.\nLe format est probablement faux...\nVérifiez qu'il s'agit d'une bitmap 24 bits...","Erreur",MB_ICONERROR);
		return NULL;
	}
	fclose(f);

	ptrbloc=bloc;

	for (y=0;y<ty;y++)		{
		ptr=bloc+y*tx*3;
		for (x=0;x<tx*3;x++)		{
			*ptr++=*ptrbloc++;
		}
	}

	return bloc;
}


//Dessine un pixel inversé avec la possibilité d'utiliser une couleur de masque
__inline void DessPixInvMasque(register int x,register int y,register int c)		{
	register unsigned char *ptr;
	x+=CLIP_X0;
	y+=CLIP_Y0;
	ptr=Bits+LARG_BUF*3*(HAUT_BUF-y)+3*x;
	if ((c&0x0000ff)==0xfe)
		return;
	*(ptr++)=(unsigned char)(c&0x000000ff);
	*(ptr++)=(unsigned char)((c&0x0000ff00)>>8);
	*(ptr++)=(unsigned char)((c&0x00ff0000)>>16);
}

#define SpriteGetPix(sprite,x,y,l)		\
	((*(unsigned long *)((unsigned char*)sprite-l*3*y+3*x)))


HRGN hrgn=0;

void ZoneEcran(int x0,int y0,int x1,int y1)		{
	RECT rect;
	CLIP_X0=x0, CLIP_Y0=y0, CLIP_X1=x1, CLIP_Y1=y1;
	rect.left=x0;
	rect.top=y0;
	rect.right=x1;
	rect.bottom=y1;
	if (hrgn)
		DeleteObject(hrgn);
	hrgn=CreateRectRgnIndirect(&rect);
	SelectClipRgn(hdcImage,hrgn);
}


#include <Graphlib/timer.h>


void EffaceEcran(int gris=0)		{
	memset(Bits,gris,LARG_BUF*(HAUT_BUF+1)*3);
}

void Rotation(register unsigned char *sprite, int x1, int y1, int l, int h, double t)		{
	int x, y, centrex,centrey,dmax, min_x,max_x,min_y,max_y;
	double cosT,sinT, xp, yp, x1p=l/2, y1p=h/2;
	
	if (!sprite)	return;

    cosT = cos(t);
    sinT = sin(t);

	centrex=x1;
	centrey=y1;
	dmax=max(l+h-2,0)/2;
	min_x=max(centrex-dmax,0);
	max_x=min(centrex+dmax,LARG);
	min_y=max(centrey-dmax,0);
	max_y=min(centrey+dmax,HAUT);

	for (y=min_y;y<max_y;y++)		{
			xp = (min_x-x1) * cosT + (y-y1) * sinT + x1p + 0.25;
			yp = (y-y1) * cosT - (min_x-x1) * sinT + y1p + 0.25;
			for (x = min_x; x <= max_x; x++)
            {
//				printf("%f %f ",xp,yp);
//				Getch();
				if (xp>=0 && xp<l && yp>=0 && yp<h)
					DessPixInvMasque(x,y,SpriteGetPix(sprite,(int)xp,(int)yp,l));
				xp += cosT;
				yp -= sinT;
            }
	}
}

void Redimensionne(register unsigned char *spr, int x0, int y0, int lb, int hb, int l, int h)		{
	int x, y, a=0;
	register unsigned char *bits=Bits+LARG_BUF*3*HAUT_BUF, *ptr, *spr2, *sprite;
	int y_min, x_min, y_max, x_max;
	int x1=x0+l, y1=y0+h;

//	ClipSprite;
	if (!spr)		return;

	if (x0>=0)			x_min=x0;
	else				x_min=0;
	if (y0>=0)			y_min=y0;
	else				y_min=0;
	if (x1<LARG)		x_max=x1;
	else				x_max=LARG-1;
	if (y1<HAUT)		y_max=y1;
	else				y_max=HAUT-1;
	spr+=3*(hb-1)*lb;

	for (y=y_min;y<y_max;y++)	{
		ptr=bits-LARG_BUF*3*(y)-3*(LARG_BUF-x_min);
		spr2=spr-lb*3*((hb*(y-y0))/h);
		for (x=x_min;x<x_max;x++)	{
			sprite=spr2+3*((lb*(x-x0))/l);
			if (*sprite==0xfe)		{
				sprite+=3;
				ptr+=3;
				continue;
			}
			*ptr=*sprite++;
			ptr++;
			*ptr=*sprite++;
			ptr++;
			*ptr=*sprite++;
			ptr++;
		}
		sprite+=a;
	}

}

void Rotozoom(register unsigned char *sprite, int x1, int y1, int l, int h, double facteur, double t)		{
	int x, y, centrex,centrey,dmax, min_x,max_x,min_y,max_y;
	long cosT, sinT;
	long xp, yp, x1p=(l<<VIRGULE)/2, y1p=(h<<VIRGULE)/2;
	register short xpentier, ypentier;

	if (!sprite)	return;

    cosT = (long)((cos(t)*MULT)/facteur);
    sinT = (long)((sin(t)*MULT)/facteur);

	centrex=x1;
	centrey=y1;
	dmax=(int)((float)(max(l+h-2,0)/2)*(float)facteur);
	min_x=max(centrex-dmax,0);
	max_x=min(centrex+dmax,CLIP_X1-CLIP_X0-1);
	min_y=max(centrey-dmax,0);
	max_y=min(centrey+dmax,CLIP_Y1-CLIP_Y0-1);
	sprite+=3*(h-1)*l;

	for (y=min_y;y<max_y;y++)		{
			xp = (min_x-x1) * cosT + (y-y1) * sinT + x1p + (1>>VIRGULE)/4;
			yp = (y-y1) * cosT - (min_x-x1) * sinT + y1p + (1>>VIRGULE)/4;

			for (x = min_x; x <= max_x; x++)
			{
				xpentier=(short)(xp>>VIRGULE), ypentier=(short)(yp>>VIRGULE);
				if (xpentier>=0 && xpentier<l && ypentier>=0 && ypentier<h)
					DessPixInvMasque(x,y,SpriteGetPix(sprite,(int)xpentier,(int)ypentier,l));
				xp += cosT;
				yp -= sinT;
			}
	}
}


void SauveBmpPressePapiers()		{
	HDC hdcTemp;
	HBITMAP hbmTemp;
	hdcTemp=CreateCompatibleDC(GetDC(NULL));
	hbmTemp=CreateCompatibleBitmap(GetDC(NULL),LARG,HAUT);
	SelectObject(hdcTemp,hbmTemp);
	BitBlt(hdcTemp,0,0,LARG,HAUT,hdcImage,0,0,SRCCOPY);
	OpenClipboard(GetFocus());
	EmptyClipboard();
	SetClipboardData(CF_BITMAP,hbmTemp);
	CloseClipboard();
}

