Generateur de fractal personnalise [vesa] [djgpp]

Description

Un generateur de fractal assez spécial, où l'utilisateur dessine a la souris plusieurs 'segments', puis une forme (la aussi avec des segments), et le programme va se charger de repeter les premiers segments sur chaques segments de la forme dessinee. Ça fonctionne avec des listes chainees et le mode graphique VESA 105h.

Source / Exemple :


#include			<assert.h>
#include			<conio.h>
#include			<dpmi.h>
#include			<go32.h>
#include			<math.h>
#include			<pc.h>
#include			<stdio.h>
#include			<stdlib.h>
#include			<string.h>
#include			<sys/farptr.h>
#include			<sys/movedata.h>
#include			<unistd.h>

#define				BLACK		0
#define				RED		1
#define				WHITE		2
#define				ENTER		13
#define				ESCAPE		27
#define				SPACE		32

////////////////////////////////////////////////////////////////////////////////////////////////////

typedef struct VERTEX
{
	double			x;
	double			y;
	struct VERTEX*		n;
} VERTEX;

////////////////////////////////////////////////////////////////////////////////////////////////////

char				ascii[2048];
char*				buffer;
double				SIN[360];
double				COS[360];
__dpmi_regs			regs;
VERTEX*				f;
VERTEX*				fh;
VERTEX*				m;
VERTEX*				mh;

////////////////////////////////////////////////////////////////////////////////////////////////////

int				mouse(int* cx,int* cy,int lx,int ly);
int				build(VERTEX* v);
void				display();
void				draw(VERTEX* v,char color);
void				erase();
void				free_fractal();
void				generation();
void				initVESA();
void				line(int fx,int fy,int lx,int ly,char color);
void				pcx();
void				stopVESA();
void				text(char* t,int c,int x,int y);

////////////////////////////////////////////////////////////////////////////////////////////////////

int				main()
{
	char			key;
	char			segs[30];
	int			i;
	int			fi;
	int			mi;

	initVESA();

	mi=build(m);
	if (mi==-1) { stopVESA(); return 0; }
	fi=build(f);
	if (fi==-1) { stopVESA(); return 0; }
	draw(f,BLACK);
	i=0;
	while (1)
	{
		sprintf(segs,"%d segments    ",(int)(fi*pow(mi,i++)));
		text(segs,WHITE,1,10);
		display();
		do key=getch(); while ((key!=ENTER)&&(key!='P')&&(key!=ESCAPE));
		if (key==ESCAPE) break;
		else if (key=='P') pcx();
		erase();
		generation();
	};

	stopVESA();
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int				mouse(int* cx,int* cy,int lx,int ly)
{
	int			button=0;

	do
	{
		regs.x.ax=0x03;		// MOV AX,00h
		__dpmi_int(0x33,&regs);	// INT 33h
		button=(button&2)|(regs.x.bx&1);
		if (button==1)
		{
			(*cx)+=regs.x.cx-lx;	// augmente cx du nombre de pixel dont la souris a bouge
			(*cy)-=regs.x.dx-ly;	// diminue cy du nombre de pixel dont la souris a bouge
			button|=2;
		}
	} while (button&1);	// continue tant qu'un bouton est presse

	if (!button)
	{
		(*cx)+=regs.x.cx-lx;	// augmente cx du nombre de pixel dont la souris a bouge
		(*cy)-=regs.x.dx-ly;	// diminue cy du nombre de pixel dont la souris a bouge
	}
	if ((*cx)>350) (*cx)=350;	// pour eviter les debordements
	else if ((*cx)<-349) (*cx)=-349;
	if ((*cy)>350) (*cy)=350;	// pour eviter les debordements
	else if ((*cy)<-349) (*cy)=-349;

	regs.x.ax=0x04;		// MOV AX,00h
	regs.x.cx=lx;		// MOV CX,[lx]
	regs.x.dx=ly;		// MOV DX,[ly]
	__dpmi_int(0x33,&regs);	// INT 33h

	return button;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int				build(VERTEX* v)
{
	int			cx=0;
	int			cy=0;
	int			lx;
	int			ly;
	int			i=1;
	char			key;
	char			pos[5];
	double			deg;
	VERTEX*			p;
	VERTEX*			h;

	text("X : ",WHITE,1,10);
	text("Y : ",WHITE,1,11);
	text("angle : ",WHITE,1,12);

	regs.x.ax=0x03;		// MOV AX,00h
	__dpmi_int(0x33,&regs);	// INT 33h
	lx=regs.x.cx;	// position X actuelle de la souris
	ly=regs.x.dx;	// position Y actuelle de la souris

	h=v;	// sauve l'adresse du debut de la liste
	if (v->n==NULL)	// si l'utilisateur doit choisir le premier et le dernier vertex
	{
		while (1)	// boucle infinie
		{
			// efface l'ancien curseur
			if (cy==350)	buffer[cx+510+((382-cy)<<10)]=BLACK; else buffer[cx+510+((382-cy)<<10)]=WHITE;
			if (cx==350)	buffer[cx+511+((383-cy)<<10)]=BLACK; else buffer[cx+511+((383-cy)<<10)]=WHITE;
			if (cy==-349)	buffer[cx+510+((384-cy)<<10)]=BLACK; else buffer[cx+510+((384-cy)<<10)]=WHITE;
			if (cx==-349)	buffer[cx+509+((383-cy)<<10)]=BLACK; else buffer[cx+509+((383-cy)<<10)]=WHITE;
			buffer[cx+510+((383-cy)<<10)]=WHITE;

			if (mouse(&cx,&cy,lx,ly))
			{
				v->x=(double)cx;
				v->y=(double)cy;
				if (v->n==NULL) // si l'utilisateur a choisi le premier vertex
				{
					v->n=(VERTEX*)malloc(sizeof(VERTEX));
					v=v->n;
					v->n=(VERTEX*)1;	// flag
				}
				else break;	// quitte la boucle infinie si le dernier vertex a ete choisi
			}

			// gestion du clavier
			if (kbhit())
			{
				key=getch();
				if (key==ESCAPE)
				{
					v->n=NULL;
					return -1;
				}
			}

			// affiche la position du curseur
			sprintf(pos,"%4d",cx);
			text(pos,WHITE,5,10);
			sprintf(pos,"%4d",cy);
			text(pos,WHITE,5,11);

			// dessine le nouveau curseur
			buffer[cx+510+((382-cy)<<10)]=RED;
			buffer[cx+511+((383-cy)<<10)]=RED;
			buffer[cx+510+((384-cy)<<10)]=RED;
			buffer[cx+509+((383-cy)<<10)]=RED;
			buffer[cx+510+((383-cy)<<10)]=RED;

			// si le premier vertex est deja choisi
			if (v->n)
			{
				line(h->x,h->y,cx,cy,BLACK);
				buffer[(int)h->x+510+((int)(382-h->y)<<10)]=BLACK;
				buffer[(int)h->x+511+((int)(383-h->y)<<10)]=BLACK;
				buffer[(int)h->x+510+((int)(384-h->y)<<10)]=BLACK;
				buffer[(int)h->x+509+((int)(383-h->y)<<10)]=BLACK;
				buffer[(int)h->x+510+((int)(383-h->y)<<10)]=BLACK;

				// affiche l'amplitude
				if ((cx-h->x==0.0)&&(cy-h->y>=0.0)) deg=90.0;
				else if ((cx-h->x==0.0)&&(cy-h->y<=0.0)) deg=270.0;
				else if ((cx-h->x>=0.0)&&(cy-h->y>=0.0)) deg=180.0/PI*atan((cy-h->y)/(cx-h->x));
				else if ((cx-h->x<=0.0)&&(cy-h->y>=0.0)) deg=180.0-180.0/PI*atan(-(cy-h->y)/(cx-h->x));
				else if ((cx-h->x<=0.0)&&(cy-h->y<=0.0)) deg=180.0+180.0/PI*atan((cy-h->y)/(cx-h->x));
				else deg=360.0-180.0/PI*atan(-(cy-h->y)/(cx-h->x));
				sprintf(pos,"%3.0f",deg);
				text(pos,WHITE,9,12);
			}
			display();
			line(h->x,h->y,cx,cy,WHITE);
		}
		v->n=NULL;	// ferme la liste chainee
		v=h;		// revient au debut de la liste chainee

		// efface le premier vertex
		if (h->y==350)	buffer[(int)h->x+510+((int)(382-h->y)<<10)]=BLACK; else buffer[(int)h->x+510+((int)(382-h->y)<<10)]=WHITE;
		if (cx==350)	buffer[(int)h->x+511+((int)(383-h->y)<<10)]=BLACK; else buffer[(int)h->x+511+((int)(383-h->y)<<10)]=WHITE;
		if (h->y==-349)	buffer[(int)h->x+510+((int)(384-h->y)<<10)]=BLACK; else buffer[(int)h->x+510+((int)(384-h->y)<<10)]=WHITE;
		if (cx==-349)	buffer[(int)h->x+509+((int)(383-h->y)<<10)]=BLACK; else buffer[(int)h->x+509+((int)(383-h->y)<<10)]=WHITE;
		buffer[(int)h->x+510+((int)(383-h->y)<<10)]=WHITE;
	}
	p=v->n;		// sauve l'adresse de l'element suivant
	v->n=(VERTEX*)malloc(sizeof(VERTEX));	// nouvel element suivant
	v->n->n=p;	// positionne le nouvel element juste avant l'ancien element
	p=v;		// sauve l'adresse de l'element actuel
	v=v->n;
	do
	{
		while (!kbhit())	// tant qu'aucune touche n'est pressee
		{
			// efface l'ancien curseur
			if (cy==350)	buffer[cx+510+((382-cy)<<10)]=BLACK; else buffer[cx+510+((382-cy)<<10)]=WHITE;
			if (cx==350)	buffer[cx+511+((383-cy)<<10)]=BLACK; else buffer[cx+511+((383-cy)<<10)]=WHITE;
			if (cy==-349)	buffer[cx+510+((384-cy)<<10)]=BLACK; else buffer[cx+510+((384-cy)<<10)]=WHITE;
			if (cx==-349)	buffer[cx+509+((383-cy)<<10)]=BLACK; else buffer[cx+509+((383-cy)<<10)]=WHITE;
			buffer[cx+510+((383-cy)<<10)]=WHITE;

			if (mouse(&cx,&cy,lx,ly))
			{
				i++;	// augmente le nombre de segments
				erase();
				v->x=(double)cx;
				v->y=(double)cy;
				p=v->n;
				v->n=(VERTEX*)malloc(sizeof(VERTEX));
				v->n->n=p;
				p=v;
				v=v->n;
				// le nouveau vertex est maintenant enregistre
				// et on passe au vertex suivant
			}
			else erase();		// efface l'ancien fractal

			v->x=(double)cx;	// nouvelle position X du point
			v->y=(double)cy;	// nouvelle position Y du point
			draw(h,RED);		// dessine le nouveau fractal

			// affiche la position du curseur
			sprintf(pos,"%4d",cx);
			text(pos,WHITE,5,10);
			sprintf(pos,"%4d",cy);
			text(pos,WHITE,5,11);

			// affiche l'amplitude
			if ((cx-p->x==0.0)&&(cy-p->y>=0.0)) deg=90.0;
			else if ((cx-p->x==0.0)&&(cy-p->y<=0.0)) deg=270.0;
			else if ((cx-p->x>=0.0)&&(cy-p->y>=0.0)) deg=180.0/PI*atan((cy-p->y)/(cx-p->x));
			else if ((cx-p->x<=0.0)&&(cy-p->y>=0.0)) deg=180.0-180.0/PI*atan(-(cy-p->y)/(cx-p->x));
			else if ((cx-p->x<=0.0)&&(cy-p->y<=0.0)) deg=180.0+180.0/PI*atan((cy-p->y)/(cx-p->x));
			else deg=360.0-180.0/PI*atan(-(cy-p->y)/(cx-p->x));
			sprintf(pos,"%3.0f",deg);
			text(pos,WHITE,9,12);

			// dessine le nouveau curseur
			buffer[cx+510+((382-cy)<<10)]=BLACK;
			buffer[cx+511+((383-cy)<<10)]=BLACK;
			buffer[cx+510+((384-cy)<<10)]=BLACK;
			buffer[cx+509+((383-cy)<<10)]=BLACK;
			buffer[cx+510+((383-cy)<<10)]=BLACK;

			display();		// affichage
		}

		// gestion du clavier
		key=getch();
		if (key==ESCAPE)
		{
			v->n=NULL;
			return -1;
		}

	} while (key!=ENTER);	// recommence si ENTER n'a pas ete presse
	erase();				// efface le fractal
	text("              ",WHITE,1,10);
	text("              ",WHITE,1,11);
	text("              ",WHITE,1,12);
	display();
	v=h;
	while (v->n->n) // cherche l'avant-dernier vertex
	{
		p=v;	// sauve l'adresse de l'element actuel
		v=v->n;	// et passe a l'element suivant
	}
	p->n=v->n;	// efface l'element actuel
	free(v);	// libere la memoire

	return i;	// renvoie le nombre de segments
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				display()
{
	int			bank;

	while (!(inportw(0x03DA)&8));	// synchronisation avec l'ecran
	while (inportw(0x03DA)&8);
	for (bank=0 ; bank<12 ; bank++)	// 12 banques
	{
		regs.x.ax=0x4F05;	// fonction 4F05h
		regs.x.bx=0;		// fenetre A
		regs.x.dx=bank;	// numero de la banque
		__dpmi_int(0x10,&regs);	// INT 10h
		dosmemput(buffer+(bank<<16),65536L,0xA0000);	// affichage
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				draw(VERTEX* v,char color)
{
	while (v->n)
	{
		line(v->x,v->y,v->n->x,v->n->y,color);
		v=v->n;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				erase()
{
	unsigned long		i;

	i=161+33*1024;	// position 161:33
	while (i<=860+732*1024)	// tant qu'on est pas a la position 860:732
	{
		buffer[i]=WHITE;		// pixel blanc
		i++;				// augmente i
		if ((i%1024)>860) i+=163+161;	// si X > 860
	}	// on vient d'effacer le carre blanc de 700x700 pixels

}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				free_fractal()
{
	f=fh;			// revient au debut de la liste
	while (f->n)		// on efface chaque element jusqu'a ce
	{			// qu'on soit arrive au dernier element
		fh=f;		// on retient l'adresse de l'element actuel
		f=f->n;		// on va a l'element suivant
		free(fh);	// et on efface l'element de l'adresse retenue
	}			// on recommence tant qu'il reste des elements
	free(f);		// et on efface le tout dernier element
	m=mh;		// on fait exactement la meme chose pour l'autre liste chainee
	while (m->n)
	{
		mh=m;
		m=m->n;
		free(mh);
	}
	free(m);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				generation()
{
	double			deg;
	double			fl;
	double			fx;
	double			fy;
	double			fdeg;
	double			ml;
	double			mx;
	double			my;
	double			mdeg;
	VERTEX*			p;

	
	f=fh;
	draw(f,BLACK);
	display();
	while (f->n)
	{
		// calcule l'amplitude et la longueur du segment
		fx=f->n->x-f->x;
		fy=f->n->y-f->y;
		fl=sqrt(fx*fx+fy*fy);
		if ((fx==0.0)&&(fy>=0.0)) fdeg=90.0;
		else if ((fx==0.0)&&(fy<=0.0)) fdeg=270.0;
		else if ((fx>=0.0)&&(fy>=0.0)) fdeg=180.0/PI*atan(fy/fx);
		else if ((fx<=0.0)&&(fy>=0.0)) fdeg=180.0-180.0/PI*atan(-fy/fx);
		else if ((fx<=0.0)&&(fy<=0.0)) fdeg=180.0+180.0/PI*atan(fy/fx);
		else fdeg=360.0-180.0/PI*atan(-fy/fx);
		m=mh;
		while (m->n->n)
		{
			// efface l'ancien segment
			line(f->x,f->y,f->n->x,f->n->y,WHITE);

			// calcule l'amplitude et la longueur du segment
			mx=m->n->x-m->x;
			my=m->n->y-m->y;
			ml=sqrt(mx*mx+my*my);
			if ((mx==0.0)&&(my>=0.0)) mdeg=90.0;
			else if ((mx==0.0)&&(my<=0.0)) mdeg=270.0;
			else if ((mx>=0.0)&&(my>=0.0)) mdeg=180.0/PI*atan(my/mx);
			else if ((mx<=0.0)&&(my>=0.0)) mdeg=180.0-180.0/PI*atan(-my/mx);
			else if ((mx<=0.0)&&(my<=0.0)) mdeg=180.0+180.0/PI*atan(my/mx);
			else mdeg=360.0-180.0/PI*atan(-my/mx);

			// insere un nouveau vertex
			p=f->n;
			f->n=(VERTEX*)malloc(sizeof(VERTEX));
			f->n->n=p;
			p=f;
			f=f->n;

			// positionne le nouveau vertex
			deg=fdeg+mdeg;
			if (deg>=360.0) deg-=360.0;
			ml=fl*ml/700.0;
			f->x=p->x+COS[(int)deg]*ml;
			f->y=p->y+SIN[(int)deg]*ml;

			// affiche le nouveau segment en rouge
			line(p->x,p->y,f->x,f->y,RED);
			display();

			m=m->n;
		}
		line(f->x,f->y,f->n->x,f->n->y,RED);
		f=f->n;
	}
	m=mh;
	f=fh;
	erase();
	draw(f,BLACK);
	display();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				initVESA()
{
	unsigned long		i;

	regs.x.ax=0x4F02;		// fonction 4F02h
	regs.x.bx=0x105;		// mode 105h - 1024x768 256 couleurs
	__dpmi_int(0x10,&regs);		// INT 10h
	buffer=(char*)malloc(1024*768);	// alloue de la memoire pour le buffer

	outportb(0x03C8,BLACK);		// noir
	outportb(0x03C9,0);
	outportb(0x03C9,0);
	outportb(0x03C9,0);
	outportb(0x03C8,RED);		// rouge
	outportb(0x03C9,63);
	outportb(0x03C9,0);
	outportb(0x03C9,0);
	outportb(0x03C8,WHITE);		// blanc
	outportb(0x03C9,63);
	outportb(0x03C9,63);
	outportb(0x03C9,63);

	for (i=0 ; i<1024*768 ; i++) buffer[i]=BLACK;	// ecran noir
	erase();	// dessine un carre blanc de 700x700 pixels

	f=(VERTEX*)malloc(sizeof(VERTEX));	// creation du premier element
	fh=f;					// sauve l'adresse du debut
	f->n=NULL;				// on ferme la liste chainee

	m=(VERTEX*)malloc(sizeof(VERTEX));	// creation des deux premiers vertex
	mh=m;					// sauve l'adresse du debut
	m->x=-349.0;	// premier vertex au centre
	m->y=0.0;	// et tout a gauche
	m->n=(VERTEX*)malloc(sizeof(VERTEX));	// vertex suivant
	m=m->n;
	m->x=350.0;	// second vertex au centre
	m->y=0.0;	// et tout a droite
	m->n=NULL;	// on ferme la liste chainee
	m=mh;		// on revient au debut de la liste chainee

	// initialisation de la souris
	regs.x.ax=0x00;		// MOV AX,00h
	__dpmi_int(0x33,&regs);	// INT 33h
	regs.x.ax=0x02;		// MOV AX,02h
	__dpmi_int(0x33,&regs);	// INT 33h

	// precalcul des nombres trigonometriques
	for (i=0 ; i<360 ; i++)
	{
		SIN[i]=sin(i*PI/180.0);
		COS[i]=cos(i*PI/180.0);
	}

	// initialisation texte
	dosmemget(0x000FFA6E,2048L,ascii);
	text("GENERATEUR DE FRACTAL - par Boes Olivier\r\n",RED,41,1);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				line(int fx,int fy,int lx,int ly,char color)
{
	int			x1;
	int			y1;
	int			x2;
	int			y2;
	int			dx;
	int			dy;
	int			sub;
	int			remain;
	int			error;
	int			inc1;
	int			inc2;

	fx+=510;
	fy=383-fy;
	lx+=510;
	ly=383-ly;
	if (fx>lx)
	{
		x1=lx;
		x2=fx;
		y1=ly;
		y2=fy;
	}
	else
	{
		x1=fx;
		x2=lx;
		y1=fy;
		y2=ly;
	}
	dx=x2-x1;
	dy=y2-y1;
	if ((!dx)&&(!dy)) return;
	if (dy<0) 
	{
		dy=-dy;
		inc1=-1;
		inc2=1;
	}
	else 
	{
		inc1=1;
		inc2=1;
	}
	if (dx>dy)
	{	
		sub=dx-dy;
		error=dy-(dx>>1);
		remain=(dx+1)>>1;

		do
		{
			if ((x1>160)&&(x1<861)&&(y1>32)&&(y1<733)) buffer[x1+(y1<<10)]=color;
			if ((x2>160)&&(x2<861)&&(y2>32)&&(y2<733)) buffer[x2+(y2<<10)]=color;
			x1+=inc2;
			x2-=inc2;
			if (error>=0)
			{
				y1+=inc1;
				y2-=inc1;
				error-=sub;
			}
			else error+=dy;
		} while (--remain>0);
		if ((!(dx&1))&&((x1>160)&&(x1<861)&&(y1>32)&&(y1<733))) buffer[x1+(y1<<10)]=color;
	}
	else
	{	
		sub=dy-dx;
		error=dx-(dy>>1);
		remain=(dy+1)>>1;

		do
		{
			if ((x1>160)&&(x1<861)&&(y1>32)&&(y1<733)) buffer[x1+(y1<<10)]=color;
			if ((x2>160)&&(x2<861)&&(y2>32)&&(y2<733)) buffer[x2+(y2<<10)]=color;
			y1+=inc1;
			y2-=inc1;
			if (error>=0)
			{
				x1+=inc2;
				x2-=inc2;
				error-=sub;
			}
			else error+=dx;
		} while (--remain>0);
		if ((!(dy&1))&&((x1>160)&&(x1<861)&&(y1>32)&&(y1<733))) buffer[x1+(y1<<10)]=color;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void					pcx()
{
	char				header[128];
	char				c;
	char				n;
	char				name[11];
	char*				img;
	FILE*				file;
	unsigned char			pal[768];
	unsigned int			width=(700+(700&1));
	unsigned long			max=700*700;
	unsigned long			i;
	unsigned long			i2;

	/* --- CREATION DU PCX --- */
	strcpy(name,"ecran0.pcx");
	while ((__file_exists(name))&&(name[5]<='9')) name[5]++;
	if (name[5]>'9') return;
	file=fopen(name,"wb");
	img=(char*)malloc(700*700*sizeof(char));
	i=161+33*1024;	// position 161:33
	i2=0;
	while (i<=860+732*1024)	// tant qu'on est pas a la position 860:732
	{
		img[i2++]=buffer[i];
		i++;				// augmente i
		if ((i%1024)>860) i+=163+161;	// si X > 860
	}

	/* --- EN-TETE --- */
	header[0]=10;				/* octet PCX */
	header[1]=5;				/* version de PCX */
	header[2]=1;				/* RLE active */
	header[3]=8;				/* 8 bits pour un pixel */
	header[4]=0;				/* Xmin */
	header[5]=0;				/* Xmin */
	header[6]=0;				/* Ymin */
	header[7]=0;				/* Ymin */
	header[8]=(700-1)&0x00FF;			/* Xmax */
	header[9]=((700-1)&0xFF00)>>8;		/* Xmax */
	header[10]=(700-1)&0x00FF;		/* Ymax */
	header[11]=((700-1)&0xFF00)>>8;		/* Ymax */
	header[12]=72;				/* resolution horizontale */
	header[13]=0;				/* resolution horizontale */
	header[14]=72;				/* resolution verticale */
	header[15]=0;				/* resolution verticale */
	for (i=0 ; i<16 ; i++)			/* palette 16 couleurs */
	{
		header[i*3+16]=15-i;
		header[i*3+17]=15-i;
		header[i*3+18]=15-i;
	}
	header[64]=0;				/* toujours 0 */
	header[65]=1;				/* toujours 1 */
	header[66]=width&0x00FF;		/* largeur, doit etre un nombre pair */
	header[67]=(width&0xFF00)>>8;		/* largeur, doit etre un nombre pair */
	header[68]=1;				/* 1 = couleurs, 2 = noir et blanc */
	for (i=69 ; i<128 ; i++) header[i]=0;	/* tout le reste c'est 0 */

	fwrite(header,sizeof(char),128,file);	/* on ecrit l'en-tete */

	/* --- IMAGE --- */
	i=0;
	do
	{
		c=img[i];
		i++;
		n=1;
		if (i!=max) while (img[i]==c)
		{
			if ((n<63)&&(i%700)) n++;
			else break;
			i++;
			if (i==max) break;
		}
		if ((n==1)&&((c&0xC0)!=0xC0)) fwrite(&c,sizeof(char),1,file);
		else
		{
			if ((i%700==0)&&(700!=width)&&(c==(char)(255)))
			{
				n++;
				width=0;
			}
			n|=0xC0;
			fwrite(&n,sizeof(char),1,file);
			fwrite(&c,sizeof(char),1,file);
		}
		if (!width) width=700+1;
		else if ((i%700==0)&&(700!=width)) fwrite("\xC1\xFF",sizeof(char),2,file);
	} while (i!=max);
	
	/* --- PALETTE --- */
	c=12;
	fwrite(&c,sizeof(char),1,file);
	pal[0]=0;	pal[1]=0;	pal[2]=0;
	pal[3]=255;	pal[4]=0;	pal[5]=0;
	pal[6]=255;	pal[7]=255;	pal[8]=255;
	for (i=9 ; i<768 ; i++) pal[i]=0;
	fwrite(pal,sizeof(char),768,file);
	fclose(file);
	free(img);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				stopVESA()
{
	regs.h.ah=0x00;		// fonction 00h
	regs.h.al=0x03;		// mode 03h - mode texte normal
	__dpmi_int(0x10,&regs);	// INT 10h
	free(buffer);		// on libere la memoire du buffer
	free_fractal();		// on libere la memoire des listes chainees
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				text(char* t,int c,int x,int y)
{
	unsigned int		i;
	unsigned int		i2;
	unsigned int		pos1;
	unsigned int		pos2;

	pos1=(x<<3)+(y<<13);	// convertit les positions
	for (i=0 ; t[i] ; i++)	// tant que le texte n'est pas fini
	{
		if (t[i]=='\n')	// passe une ligne
		{
			pos1+=1024*8;
			continue;
		}
		if (t[i]=='\r')	// retour a gauche
		{
			pos1=(pos1&0xFFC00)+(x<<3);
			continue;
		}
		pos2=t[i]<<3;	// va au caractere demande
		for (i2=0 ; i2<8 ; i2++)	// 8 lignes par caracteres
		{
			if (ascii[pos2]&0x80) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x40) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x20) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x10) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x08) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x04) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x02) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x01) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			pos1+=1024-8;
			pos2++;
		}
		pos1-=1024*8-8;
	}
}
#include			<assert.h>
#include			<conio.h>
#include			<dpmi.h>
#include			<go32.h>
#include			<math.h>
#include			<pc.h>
#include			<stdio.h>
#include			<stdlib.h>
#include			<string.h>
#include			<sys/farptr.h>
#include			<sys/movedata.h>
#include			<unistd.h>

#define				BLACK		0
#define				RED		1
#define				WHITE		2
#define				ENTER		13
#define				ESCAPE		27
#define				SPACE		32

////////////////////////////////////////////////////////////////////////////////////////////////////

typedef struct VERTEX
{
	double			x;
	double			y;
	struct VERTEX*		n;
} VERTEX;

////////////////////////////////////////////////////////////////////////////////////////////////////

char				ascii[2048];
char*				buffer;
double				SIN[360];
double				COS[360];
__dpmi_regs			regs;
VERTEX*				f;
VERTEX*				fh;
VERTEX*				m;
VERTEX*				mh;

////////////////////////////////////////////////////////////////////////////////////////////////////

int				mouse(int* cx,int* cy,int lx,int ly);
int				build(VERTEX* v);
void				display();
void				draw(VERTEX* v,char color);
void				erase();
void				free_fractal();
void				generation();
void				initVESA();
void				line(int fx,int fy,int lx,int ly,char color);
void				pcx();
void				stopVESA();
void				text(char* t,int c,int x,int y);

////////////////////////////////////////////////////////////////////////////////////////////////////

int				main()
{
	char			key;
	char			segs[30];
	int			i;
	int			fi;
	int			mi;

	initVESA();

	mi=build(m);
	if (mi==-1) { stopVESA(); return 0; }
	fi=build(f);
	if (fi==-1) { stopVESA(); return 0; }
	draw(f,BLACK);
	i=0;
	while (1)
	{
		sprintf(segs,"%d segments    ",(int)(fi*pow(mi,i++)));
		text(segs,WHITE,1,10);
		display();
		do key=getch(); while ((key!=ENTER)&&(key!='P')&&(key!=ESCAPE));
		if (key==ESCAPE) break;
		else if (key=='P') pcx();
		erase();
		generation();
	};

	stopVESA();
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int				mouse(int* cx,int* cy,int lx,int ly)
{
	int			button=0;

	do
	{
		regs.x.ax=0x03;		// MOV AX,00h
		__dpmi_int(0x33,&regs);	// INT 33h
		button=(button&2)|(regs.x.bx&1);
		if (button==1)
		{
			(*cx)+=regs.x.cx-lx;	// augmente cx du nombre de pixel dont la souris a bouge
			(*cy)-=regs.x.dx-ly;	// diminue cy du nombre de pixel dont la souris a bouge
			button|=2;
		}
	} while (button&1);	// continue tant qu'un bouton est presse

	if (!button)
	{
		(*cx)+=regs.x.cx-lx;	// augmente cx du nombre de pixel dont la souris a bouge
		(*cy)-=regs.x.dx-ly;	// diminue cy du nombre de pixel dont la souris a bouge
	}
	if ((*cx)>350) (*cx)=350;	// pour eviter les debordements
	else if ((*cx)<-349) (*cx)=-349;
	if ((*cy)>350) (*cy)=350;	// pour eviter les debordements
	else if ((*cy)<-349) (*cy)=-349;

	regs.x.ax=0x04;		// MOV AX,00h
	regs.x.cx=lx;		// MOV CX,[lx]
	regs.x.dx=ly;		// MOV DX,[ly]
	__dpmi_int(0x33,&regs);	// INT 33h

	return button;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int				build(VERTEX* v)
{
	int			cx=0;
	int			cy=0;
	int			lx;
	int			ly;
	int			i=1;
	char			key;
	char			pos[5];
	double			deg;
	VERTEX*			p;
	VERTEX*			h;

	text("X : ",WHITE,1,10);
	text("Y : ",WHITE,1,11);
	text("angle : ",WHITE,1,12);

	regs.x.ax=0x03;		// MOV AX,00h
	__dpmi_int(0x33,&regs);	// INT 33h
	lx=regs.x.cx;	// position X actuelle de la souris
	ly=regs.x.dx;	// position Y actuelle de la souris

	h=v;	// sauve l'adresse du debut de la liste
	if (v->n==NULL)	// si l'utilisateur doit choisir le premier et le dernier vertex
	{
		while (1)	// boucle infinie
		{
			// efface l'ancien curseur
			if (cy==350)	buffer[cx+510+((382-cy)<<10)]=BLACK; else buffer[cx+510+((382-cy)<<10)]=WHITE;
			if (cx==350)	buffer[cx+511+((383-cy)<<10)]=BLACK; else buffer[cx+511+((383-cy)<<10)]=WHITE;
			if (cy==-349)	buffer[cx+510+((384-cy)<<10)]=BLACK; else buffer[cx+510+((384-cy)<<10)]=WHITE;
			if (cx==-349)	buffer[cx+509+((383-cy)<<10)]=BLACK; else buffer[cx+509+((383-cy)<<10)]=WHITE;
			buffer[cx+510+((383-cy)<<10)]=WHITE;

			if (mouse(&cx,&cy,lx,ly))
			{
				v->x=(double)cx;
				v->y=(double)cy;
				if (v->n==NULL) // si l'utilisateur a choisi le premier vertex
				{
					v->n=(VERTEX*)malloc(sizeof(VERTEX));
					v=v->n;
					v->n=(VERTEX*)1;	// flag
				}
				else break;	// quitte la boucle infinie si le dernier vertex a ete choisi
			}

			// gestion du clavier
			if (kbhit())
			{
				key=getch();
				if (key==ESCAPE)
				{
					v->n=NULL;
					return -1;
				}
			}

			// affiche la position du curseur
			sprintf(pos,"%4d",cx);
			text(pos,WHITE,5,10);
			sprintf(pos,"%4d",cy);
			text(pos,WHITE,5,11);

			// dessine le nouveau curseur
			buffer[cx+510+((382-cy)<<10)]=RED;
			buffer[cx+511+((383-cy)<<10)]=RED;
			buffer[cx+510+((384-cy)<<10)]=RED;
			buffer[cx+509+((383-cy)<<10)]=RED;
			buffer[cx+510+((383-cy)<<10)]=RED;

			// si le premier vertex est deja choisi
			if (v->n)
			{
				line(h->x,h->y,cx,cy,BLACK);
				buffer[(int)h->x+510+((int)(382-h->y)<<10)]=BLACK;
				buffer[(int)h->x+511+((int)(383-h->y)<<10)]=BLACK;
				buffer[(int)h->x+510+((int)(384-h->y)<<10)]=BLACK;
				buffer[(int)h->x+509+((int)(383-h->y)<<10)]=BLACK;
				buffer[(int)h->x+510+((int)(383-h->y)<<10)]=BLACK;

				// affiche l'amplitude
				if ((cx-h->x==0.0)&&(cy-h->y>=0.0)) deg=90.0;
				else if ((cx-h->x==0.0)&&(cy-h->y<=0.0)) deg=270.0;
				else if ((cx-h->x>=0.0)&&(cy-h->y>=0.0)) deg=180.0/PI*atan((cy-h->y)/(cx-h->x));
				else if ((cx-h->x<=0.0)&&(cy-h->y>=0.0)) deg=180.0-180.0/PI*atan(-(cy-h->y)/(cx-h->x));
				else if ((cx-h->x<=0.0)&&(cy-h->y<=0.0)) deg=180.0+180.0/PI*atan((cy-h->y)/(cx-h->x));
				else deg=360.0-180.0/PI*atan(-(cy-h->y)/(cx-h->x));
				sprintf(pos,"%3.0f",deg);
				text(pos,WHITE,9,12);
			}
			display();
			line(h->x,h->y,cx,cy,WHITE);
		}
		v->n=NULL;	// ferme la liste chainee
		v=h;		// revient au debut de la liste chainee

		// efface le premier vertex
		if (h->y==350)	buffer[(int)h->x+510+((int)(382-h->y)<<10)]=BLACK; else buffer[(int)h->x+510+((int)(382-h->y)<<10)]=WHITE;
		if (cx==350)	buffer[(int)h->x+511+((int)(383-h->y)<<10)]=BLACK; else buffer[(int)h->x+511+((int)(383-h->y)<<10)]=WHITE;
		if (h->y==-349)	buffer[(int)h->x+510+((int)(384-h->y)<<10)]=BLACK; else buffer[(int)h->x+510+((int)(384-h->y)<<10)]=WHITE;
		if (cx==-349)	buffer[(int)h->x+509+((int)(383-h->y)<<10)]=BLACK; else buffer[(int)h->x+509+((int)(383-h->y)<<10)]=WHITE;
		buffer[(int)h->x+510+((int)(383-h->y)<<10)]=WHITE;
	}
	p=v->n;		// sauve l'adresse de l'element suivant
	v->n=(VERTEX*)malloc(sizeof(VERTEX));	// nouvel element suivant
	v->n->n=p;	// positionne le nouvel element juste avant l'ancien element
	p=v;		// sauve l'adresse de l'element actuel
	v=v->n;
	do
	{
		while (!kbhit())	// tant qu'aucune touche n'est pressee
		{
			// efface l'ancien curseur
			if (cy==350)	buffer[cx+510+((382-cy)<<10)]=BLACK; else buffer[cx+510+((382-cy)<<10)]=WHITE;
			if (cx==350)	buffer[cx+511+((383-cy)<<10)]=BLACK; else buffer[cx+511+((383-cy)<<10)]=WHITE;
			if (cy==-349)	buffer[cx+510+((384-cy)<<10)]=BLACK; else buffer[cx+510+((384-cy)<<10)]=WHITE;
			if (cx==-349)	buffer[cx+509+((383-cy)<<10)]=BLACK; else buffer[cx+509+((383-cy)<<10)]=WHITE;
			buffer[cx+510+((383-cy)<<10)]=WHITE;

			if (mouse(&cx,&cy,lx,ly))
			{
				i++;	// augmente le nombre de segments
				erase();
				v->x=(double)cx;
				v->y=(double)cy;
				p=v->n;
				v->n=(VERTEX*)malloc(sizeof(VERTEX));
				v->n->n=p;
				p=v;
				v=v->n;
				// le nouveau vertex est maintenant enregistre
				// et on passe au vertex suivant
			}
			else erase();		// efface l'ancien fractal

			v->x=(double)cx;	// nouvelle position X du point
			v->y=(double)cy;	// nouvelle position Y du point
			draw(h,RED);		// dessine le nouveau fractal

			// affiche la position du curseur
			sprintf(pos,"%4d",cx);
			text(pos,WHITE,5,10);
			sprintf(pos,"%4d",cy);
			text(pos,WHITE,5,11);

			// affiche l'amplitude
			if ((cx-p->x==0.0)&&(cy-p->y>=0.0)) deg=90.0;
			else if ((cx-p->x==0.0)&&(cy-p->y<=0.0)) deg=270.0;
			else if ((cx-p->x>=0.0)&&(cy-p->y>=0.0)) deg=180.0/PI*atan((cy-p->y)/(cx-p->x));
			else if ((cx-p->x<=0.0)&&(cy-p->y>=0.0)) deg=180.0-180.0/PI*atan(-(cy-p->y)/(cx-p->x));
			else if ((cx-p->x<=0.0)&&(cy-p->y<=0.0)) deg=180.0+180.0/PI*atan((cy-p->y)/(cx-p->x));
			else deg=360.0-180.0/PI*atan(-(cy-p->y)/(cx-p->x));
			sprintf(pos,"%3.0f",deg);
			text(pos,WHITE,9,12);

			// dessine le nouveau curseur
			buffer[cx+510+((382-cy)<<10)]=BLACK;
			buffer[cx+511+((383-cy)<<10)]=BLACK;
			buffer[cx+510+((384-cy)<<10)]=BLACK;
			buffer[cx+509+((383-cy)<<10)]=BLACK;
			buffer[cx+510+((383-cy)<<10)]=BLACK;

			display();		// affichage
		}

		// gestion du clavier
		key=getch();
		if (key==ESCAPE)
		{
			v->n=NULL;
			return -1;
		}

	} while (key!=ENTER);	// recommence si ENTER n'a pas ete presse
	erase();				// efface le fractal
	text("              ",WHITE,1,10);
	text("              ",WHITE,1,11);
	text("              ",WHITE,1,12);
	display();
	v=h;
	while (v->n->n) // cherche l'avant-dernier vertex
	{
		p=v;	// sauve l'adresse de l'element actuel
		v=v->n;	// et passe a l'element suivant
	}
	p->n=v->n;	// efface l'element actuel
	free(v);	// libere la memoire

	return i;	// renvoie le nombre de segments
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				display()
{
	int			bank;

	while (!(inportw(0x03DA)&8));	// synchronisation avec l'ecran
	while (inportw(0x03DA)&8);
	for (bank=0 ; bank<12 ; bank++)	// 12 banques
	{
		regs.x.ax=0x4F05;	// fonction 4F05h
		regs.x.bx=0;		// fenetre A
		regs.x.dx=bank;	// numero de la banque
		__dpmi_int(0x10,&regs);	// INT 10h
		dosmemput(buffer+(bank<<16),65536L,0xA0000);	// affichage
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				draw(VERTEX* v,char color)
{
	while (v->n)
	{
		line(v->x,v->y,v->n->x,v->n->y,color);
		v=v->n;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				erase()
{
	unsigned long		i;

	i=161+33*1024;	// position 161:33
	while (i<=860+732*1024)	// tant qu'on est pas a la position 860:732
	{
		buffer[i]=WHITE;		// pixel blanc
		i++;				// augmente i
		if ((i%1024)>860) i+=163+161;	// si X > 860
	}	// on vient d'effacer le carre blanc de 700x700 pixels

}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				free_fractal()
{
	f=fh;			// revient au debut de la liste
	while (f->n)		// on efface chaque element jusqu'a ce
	{			// qu'on soit arrive au dernier element
		fh=f;		// on retient l'adresse de l'element actuel
		f=f->n;		// on va a l'element suivant
		free(fh);	// et on efface l'element de l'adresse retenue
	}			// on recommence tant qu'il reste des elements
	free(f);		// et on efface le tout dernier element
	m=mh;		// on fait exactement la meme chose pour l'autre liste chainee
	while (m->n)
	{
		mh=m;
		m=m->n;
		free(mh);
	}
	free(m);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				generation()
{
	double			deg;
	double			fl;
	double			fx;
	double			fy;
	double			fdeg;
	double			ml;
	double			mx;
	double			my;
	double			mdeg;
	VERTEX*			p;

	
	f=fh;
	draw(f,BLACK);
	display();
	while (f->n)
	{
		// calcule l'amplitude et la longueur du segment
		fx=f->n->x-f->x;
		fy=f->n->y-f->y;
		fl=sqrt(fx*fx+fy*fy);
		if ((fx==0.0)&&(fy>=0.0)) fdeg=90.0;
		else if ((fx==0.0)&&(fy<=0.0)) fdeg=270.0;
		else if ((fx>=0.0)&&(fy>=0.0)) fdeg=180.0/PI*atan(fy/fx);
		else if ((fx<=0.0)&&(fy>=0.0)) fdeg=180.0-180.0/PI*atan(-fy/fx);
		else if ((fx<=0.0)&&(fy<=0.0)) fdeg=180.0+180.0/PI*atan(fy/fx);
		else fdeg=360.0-180.0/PI*atan(-fy/fx);
		m=mh;
		while (m->n->n)
		{
			// efface l'ancien segment
			line(f->x,f->y,f->n->x,f->n->y,WHITE);

			// calcule l'amplitude et la longueur du segment
			mx=m->n->x-m->x;
			my=m->n->y-m->y;
			ml=sqrt(mx*mx+my*my);
			if ((mx==0.0)&&(my>=0.0)) mdeg=90.0;
			else if ((mx==0.0)&&(my<=0.0)) mdeg=270.0;
			else if ((mx>=0.0)&&(my>=0.0)) mdeg=180.0/PI*atan(my/mx);
			else if ((mx<=0.0)&&(my>=0.0)) mdeg=180.0-180.0/PI*atan(-my/mx);
			else if ((mx<=0.0)&&(my<=0.0)) mdeg=180.0+180.0/PI*atan(my/mx);
			else mdeg=360.0-180.0/PI*atan(-my/mx);

			// insere un nouveau vertex
			p=f->n;
			f->n=(VERTEX*)malloc(sizeof(VERTEX));
			f->n->n=p;
			p=f;
			f=f->n;

			// positionne le nouveau vertex
			deg=fdeg+mdeg;
			if (deg>=360.0) deg-=360.0;
			ml=fl*ml/700.0;
			f->x=p->x+COS[(int)deg]*ml;
			f->y=p->y+SIN[(int)deg]*ml;

			// affiche le nouveau segment en rouge
			line(p->x,p->y,f->x,f->y,RED);
			display();

			m=m->n;
		}
		line(f->x,f->y,f->n->x,f->n->y,RED);
		f=f->n;
	}
	m=mh;
	f=fh;
	erase();
	draw(f,BLACK);
	display();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				initVESA()
{
	unsigned long		i;

	regs.x.ax=0x4F02;		// fonction 4F02h
	regs.x.bx=0x105;		// mode 105h - 1024x768 256 couleurs
	__dpmi_int(0x10,&regs);		// INT 10h
	buffer=(char*)malloc(1024*768);	// alloue de la memoire pour le buffer

	outportb(0x03C8,BLACK);		// noir
	outportb(0x03C9,0);
	outportb(0x03C9,0);
	outportb(0x03C9,0);
	outportb(0x03C8,RED);		// rouge
	outportb(0x03C9,63);
	outportb(0x03C9,0);
	outportb(0x03C9,0);
	outportb(0x03C8,WHITE);		// blanc
	outportb(0x03C9,63);
	outportb(0x03C9,63);
	outportb(0x03C9,63);

	for (i=0 ; i<1024*768 ; i++) buffer[i]=BLACK;	// ecran noir
	erase();	// dessine un carre blanc de 700x700 pixels

	f=(VERTEX*)malloc(sizeof(VERTEX));	// creation du premier element
	fh=f;					// sauve l'adresse du debut
	f->n=NULL;				// on ferme la liste chainee

	m=(VERTEX*)malloc(sizeof(VERTEX));	// creation des deux premiers vertex
	mh=m;					// sauve l'adresse du debut
	m->x=-349.0;	// premier vertex au centre
	m->y=0.0;	// et tout a gauche
	m->n=(VERTEX*)malloc(sizeof(VERTEX));	// vertex suivant
	m=m->n;
	m->x=350.0;	// second vertex au centre
	m->y=0.0;	// et tout a droite
	m->n=NULL;	// on ferme la liste chainee
	m=mh;		// on revient au debut de la liste chainee

	// initialisation de la souris
	regs.x.ax=0x00;		// MOV AX,00h
	__dpmi_int(0x33,&regs);	// INT 33h
	regs.x.ax=0x02;		// MOV AX,02h
	__dpmi_int(0x33,&regs);	// INT 33h

	// precalcul des nombres trigonometriques
	for (i=0 ; i<360 ; i++)
	{
		SIN[i]=sin(i*PI/180.0);
		COS[i]=cos(i*PI/180.0);
	}

	// initialisation texte
	dosmemget(0x000FFA6E,2048L,ascii);
	text("GENERATEUR DE FRACTAL - par Boes Olivier\r\n",RED,41,1);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				line(int fx,int fy,int lx,int ly,char color)
{
	int			x1;
	int			y1;
	int			x2;
	int			y2;
	int			dx;
	int			dy;
	int			sub;
	int			remain;
	int			error;
	int			inc1;
	int			inc2;

	fx+=510;
	fy=383-fy;
	lx+=510;
	ly=383-ly;
	if (fx>lx)
	{
		x1=lx;
		x2=fx;
		y1=ly;
		y2=fy;
	}
	else
	{
		x1=fx;
		x2=lx;
		y1=fy;
		y2=ly;
	}
	dx=x2-x1;
	dy=y2-y1;
	if ((!dx)&&(!dy)) return;
	if (dy<0) 
	{
		dy=-dy;
		inc1=-1;
		inc2=1;
	}
	else 
	{
		inc1=1;
		inc2=1;
	}
	if (dx>dy)
	{	
		sub=dx-dy;
		error=dy-(dx>>1);
		remain=(dx+1)>>1;

		do
		{
			if ((x1>160)&&(x1<861)&&(y1>32)&&(y1<733)) buffer[x1+(y1<<10)]=color;
			if ((x2>160)&&(x2<861)&&(y2>32)&&(y2<733)) buffer[x2+(y2<<10)]=color;
			x1+=inc2;
			x2-=inc2;
			if (error>=0)
			{
				y1+=inc1;
				y2-=inc1;
				error-=sub;
			}
			else error+=dy;
		} while (--remain>0);
		if ((!(dx&1))&&((x1>160)&&(x1<861)&&(y1>32)&&(y1<733))) buffer[x1+(y1<<10)]=color;
	}
	else
	{	
		sub=dy-dx;
		error=dx-(dy>>1);
		remain=(dy+1)>>1;

		do
		{
			if ((x1>160)&&(x1<861)&&(y1>32)&&(y1<733)) buffer[x1+(y1<<10)]=color;
			if ((x2>160)&&(x2<861)&&(y2>32)&&(y2<733)) buffer[x2+(y2<<10)]=color;
			y1+=inc1;
			y2-=inc1;
			if (error>=0)
			{
				x1+=inc2;
				x2-=inc2;
				error-=sub;
			}
			else error+=dx;
		} while (--remain>0);
		if ((!(dy&1))&&((x1>160)&&(x1<861)&&(y1>32)&&(y1<733))) buffer[x1+(y1<<10)]=color;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void					pcx()
{
	char				header[128];
	char				c;
	char				n;
	char				name[11];
	char*				img;
	FILE*				file;
	unsigned char			pal[768];
	unsigned int			width=(700+(700&1));
	unsigned long			max=700*700;
	unsigned long			i;
	unsigned long			i2;

	/* --- CREATION DU PCX --- */
	strcpy(name,"ecran0.pcx");
	while ((__file_exists(name))&&(name[5]<='9')) name[5]++;
	if (name[5]>'9') return;
	file=fopen(name,"wb");
	img=(char*)malloc(700*700*sizeof(char));
	i=161+33*1024;	// position 161:33
	i2=0;
	while (i<=860+732*1024)	// tant qu'on est pas a la position 860:732
	{
		img[i2++]=buffer[i];
		i++;				// augmente i
		if ((i%1024)>860) i+=163+161;	// si X > 860
	}

	/* --- EN-TETE --- */
	header[0]=10;				/* octet PCX */
	header[1]=5;				/* version de PCX */
	header[2]=1;				/* RLE active */
	header[3]=8;				/* 8 bits pour un pixel */
	header[4]=0;				/* Xmin */
	header[5]=0;				/* Xmin */
	header[6]=0;				/* Ymin */
	header[7]=0;				/* Ymin */
	header[8]=(700-1)&0x00FF;			/* Xmax */
	header[9]=((700-1)&0xFF00)>>8;		/* Xmax */
	header[10]=(700-1)&0x00FF;		/* Ymax */
	header[11]=((700-1)&0xFF00)>>8;		/* Ymax */
	header[12]=72;				/* resolution horizontale */
	header[13]=0;				/* resolution horizontale */
	header[14]=72;				/* resolution verticale */
	header[15]=0;				/* resolution verticale */
	for (i=0 ; i<16 ; i++)			/* palette 16 couleurs */
	{
		header[i*3+16]=15-i;
		header[i*3+17]=15-i;
		header[i*3+18]=15-i;
	}
	header[64]=0;				/* toujours 0 */
	header[65]=1;				/* toujours 1 */
	header[66]=width&0x00FF;		/* largeur, doit etre un nombre pair */
	header[67]=(width&0xFF00)>>8;		/* largeur, doit etre un nombre pair */
	header[68]=1;				/* 1 = couleurs, 2 = noir et blanc */
	for (i=69 ; i<128 ; i++) header[i]=0;	/* tout le reste c'est 0 */

	fwrite(header,sizeof(char),128,file);	/* on ecrit l'en-tete */

	/* --- IMAGE --- */
	i=0;
	do
	{
		c=img[i];
		i++;
		n=1;
		if (i!=max) while (img[i]==c)
		{
			if ((n<63)&&(i%700)) n++;
			else break;
			i++;
			if (i==max) break;
		}
		if ((n==1)&&((c&0xC0)!=0xC0)) fwrite(&c,sizeof(char),1,file);
		else
		{
			if ((i%700==0)&&(700!=width)&&(c==(char)(255)))
			{
				n++;
				width=0;
			}
			n|=0xC0;
			fwrite(&n,sizeof(char),1,file);
			fwrite(&c,sizeof(char),1,file);
		}
		if (!width) width=700+1;
		else if ((i%700==0)&&(700!=width)) fwrite("\xC1\xFF",sizeof(char),2,file);
	} while (i!=max);
	
	/* --- PALETTE --- */
	c=12;
	fwrite(&c,sizeof(char),1,file);
	pal[0]=0;	pal[1]=0;	pal[2]=0;
	pal[3]=255;	pal[4]=0;	pal[5]=0;
	pal[6]=255;	pal[7]=255;	pal[8]=255;
	for (i=9 ; i<768 ; i++) pal[i]=0;
	fwrite(pal,sizeof(char),768,file);
	fclose(file);
	free(img);
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				stopVESA()
{
	regs.h.ah=0x00;		// fonction 00h
	regs.h.al=0x03;		// mode 03h - mode texte normal
	__dpmi_int(0x10,&regs);	// INT 10h
	free(buffer);		// on libere la memoire du buffer
	free_fractal();		// on libere la memoire des listes chainees
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void				text(char* t,int c,int x,int y)
{
	unsigned int		i;
	unsigned int		i2;
	unsigned int		pos1;
	unsigned int		pos2;

	pos1=(x<<3)+(y<<13);	// convertit les positions
	for (i=0 ; t[i] ; i++)	// tant que le texte n'est pas fini
	{
		if (t[i]=='\n')	// passe une ligne
		{
			pos1+=1024*8;
			continue;
		}
		if (t[i]=='\r')	// retour a gauche
		{
			pos1=(pos1&0xFFC00)+(x<<3);
			continue;
		}
		pos2=t[i]<<3;	// va au caractere demande
		for (i2=0 ; i2<8 ; i2++)	// 8 lignes par caracteres
		{
			if (ascii[pos2]&0x80) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x40) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x20) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x10) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x08) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x04) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x02) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			if (ascii[pos2]&0x01) buffer[pos1++]=c&0x00FF;
			else buffer[pos1++]=(c&0xFF00)>>8;
			pos1+=1024-8;
			pos2++;
		}
		pos1-=1024*8-8;
	}
}

Conclusion :


J'ai hésité à mettre la source dans 'Algorythme' ou 'Graphique', finalement c'est ce dernier que j'ai choisi.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.