
asm(".code16gcc");

/* pour header.S */
const char kernel_version[] = "Mykernel";


/* modificationd'une entree de la palette */
void set_rgb(int idx, int r, int g, int b)
{
/* la technique d'origine pour modifier la palette vga */
/* on modifie directement des registres de la carte graphique */
	asm( "outb %%al,%%dx" : : "a" (idx), "d" (0x03c8) );
	asm( "outb %%al,%%dx" : : "a" (r), "d" (0x03c9) );
	asm( "outb %%al,%%dx" : : "a" (g), "d" (0x03c9) );
	asm( "outb %%al,%%dx" : : "a" (b), "d" (0x03c9) );
}

/* initialisation du mode vidéo */
void video_initialize(int mode)
{
	int i;
/* Je vous fais la version longue */
/* Le code assembleur paramétré (d'où les %%) */	asm ("pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
/* L'affectation des valeurs de retour  */              	: 
/* L'affectation des paramètres */              		: "a" (mode)
/* La liste des registres à sauvegarder */      		: "ebx", "ecx", "edx", "esi", "edi");

	/* on se fait une palette simple en niveaux de gris */
	for(i=0;i<64;i++) {
		/* attention au maximum de 64 (6 bits) */
		set_rgb(i,i,i,i);
	}
}

/* affichage d'un unique pixel */
void set_pix(int x, int y, int color)
{
/* calcul de la position du pixel en memoire vidéo */
	int pos = 320*y+x;
/* Technique à la mano car gas ne supporte pas l'adressage 16bits 
 * - on passe par ds qu'on doit sauvegarder
 * - la mémoire vidéo du mode vga 13h commence en A000:0000
 */
	asm ("push %%ds; movw %%ax,%%ds; movb %%cl,(%%bx); pop %%ds"
		: : "a" (0xA000), "b"(pos), "c" (color));
}

/* conversion en coordonnées flottantes */
void convert_i2d(int x, int y, double*ppx, double *ppy)
{
	/* on ne respecte pas l'aspect ratio pour remplir et on  centre a droite */
	*ppx = (double)(x-230) / 120.;
	*ppy = (double)(y-100) / 100.;
}

/* une itération du calcul fractal pour un pixel */
double iteration(double cx, double cy, double *ppx, double *ppy)
{
	double tx,ty;
	/* p = p^2 + C */
	tx = (*ppx)*(*ppx) - (*ppy)*(*ppy) + cx;
	ty = 2*(*ppx)*(*ppy) + cy;
	*ppx = tx;
	*ppy = ty;
	/* |p| */
	return (tx*tx+ty*ty);
}

/* affichage complet de la fractale */
void display()
{
	int x,y;
	int i,color;
	double cx,cy;
	double px,py;
	double radius;
	/* on parcourt l'écran */
	for(x=0;x<320;x++) {
		for(y=0;y<200;y++) {
			convert_i2d(x,y,&cx,&cy);
			px=0.;
			py=0.;
			/* on compte le nombre d'itération pour avoir la couleur */
			for(i=0;i<63;i++) {
				radius = iteration(cx,cy,&px,&py);
				if(radius > 2.)
					break;
			}
			/* on inverse pour avoir le noir a l'intérieur */
			color = (int)(63-i);
			set_pix(x,y,color);
		}
	}
}

/* devinez */
void cmain (unsigned long magic, unsigned long addr)
{
	video_initialize(0x0013);
	display();

	/* attente passive */
	while(1) {
		asm("hlt");
	}
}

