#include <vdi.h>
#include <ext.h>
#include <tos.h>

#include "frame.h"
#include "povproto.h"

/* les prototypes des fonctions line_a utilis‚es*/	
void linea_init( void );
void put_pixel( int x, int y, int color );

/* les prototypes des fonctions internes	*/
void pallete_init(void);
void stpalcolor(unsigned int ,unsigned int ,unsigned int ,unsigned int );
void hsv_to_rgb(DBL, DBL, DBL,unsigned int *,unsigned int *,unsigned int *);
void rgb_to_hsv(unsigned , DBL *, DBL *, DBL *);


/* les macros internes	*/
/*----------------------*/
int max_int(int x,int y)
{
	return((x>y)?x:y);
}

int min_int(int x,int y)
{
	return((y>x)?x:y);
}

/* donnes internes */
/*-----------------*/
int fen_width; 		
int fen_height;		

int		x_deb,y_deb;	/* coin haut a gauche de la fenetre a afficher	*/
long	color[4096];		/* table des couleurs tries par nombre d'occurence decroissante	*/
int     old_indx[4096];	/* ancienne table des couleurs triees	*/				
int		indx[4096];			/* table des index des couleurs tries	*/			
int		index[4096];	/* table de conversion numero de couleur -> numero de palette	*/
int coul_div_4,coul_div_2,coul_mul_075;
unsigned int nb_coul=0;
int *ptr_raster;	/* pointeur sur le raster vdi correspondant a l'ecran	*/
unsigned int *ptr_ligne;
int nb_coul_pal;	/* nombre de couleur dans la palette			*/
int pal_in[256];	/* palette de sauvegarde des couleurs d'origine	*/
int res;			/* resolution courante	*/
int lim;			/* nombre de couleur utilisees */
/* donnees externes fournies par dkb	*/
/*--------------------------------------*/
extern int		dim_x,dim_y;		/* dimension en x et y de l'image totale 		*/
extern unsigned int *ptr_ecran;				/* adresse ou dkb range ses images en nb bits	*/
extern int tail_pal;				/* nombre de couleur de la palette		*/
extern long table_couleur[4096];	/* table dans laquelle est stock‚ le nombre d'occurence de chaque couleur	*/
extern char DisplayFormat;		/* format d'affichage		*/
extern unsigned int Options;
extern int c_y;				/* numero de ligne calcule par dkb	*/

/* donnees communes qu'il faudra rendre interne	*/
/*----------------------------------------------*/
extern int   work_out[57];   /* Output from GSX parameter array	*/
extern int vdi_handle;
extern int nb_plan;

/* prototype des fonctions assembleurs apelees	*/
/*----------------------------------------------*/
void aff_rend(void);
void aff_ligne(void);
void init_linea(void);
void chg_palette(void);
void calc_palette2(void);
void calc_corresp(void);

/* Conversion from Hue, Saturation, Value to Red, Green, and Blue and back */
/* From "Computer Graphics", Donald Hearn & M. Pauline Baker, p. 304 */

/*-------------------------------------------------------------------------*/
void hsv_to_rgb(hue, s, v, r, g, b)
   DBL hue, s, v;               /* hue (0.0-360.0) s and v from 0.0-1.0) */
   unsigned int *r, *g, *b;         /* values from 0 to 63 */
   {
    DBL i, f, p1, p2, p3;
    DBL xh;
    DBL nr = 0.0, ng = 0.0, nb = 0.0;	/* rgb values of 0.0 - 1.0 */

   if (hue == 360.0)
      hue = 0.0;                /* (THIS LOOKS BACKWARDS BUT OK) */

   xh = hue / 60.0;             /* convert hue to be in 0,6     */
   i = floor(xh);               /* i = greatest integer <= h    */
   f = xh - i;                  /* f = fractional part of h     */
   p1 = v * (1. - s);
   p2 = v * (1. - (s * f));
   p3 = v * (1. - (s * (1. - f)));

   switch ((int) i)
      {
      case 0:
         nr = v;
         ng = p3;
         nb = p1;
         break;
      case 1:
         nr = p2;
         ng = v;
         nb = p1;
         break;
      case 2:
         nr = p1;
         ng = v;
         nb = p3;
         break;
      case 3:
         nr = p1;
         ng = p2;
         nb = v;
         break;
      case 4:
         nr = p3;
         ng = p1;
         nb = v;
         break;
      case 5:
         nr = v;
         ng = p1;
         nb = p2;
         break;
        }

   *r = (unsigned int)(15.0*nr ); /* Normalize the values to 16 */
   *g = (unsigned int)(15.0*ng );
   *b = (unsigned int)(15.0*nb );
   
   return;
   }
   
   
/*-------------------------------------------------------------------------*/
void rgb_to_hsv(coul, h, s, v)
unsigned int coul;
DBL *h, *s, *v;
{
	int r,g,b;
   	DBL m, r1, g1, b1;
   	DBL nr, ng, nb;		/* rgb values of 0.0 - 1.0      */
   	DBL nh = 0.0, ns, nv;	/* hsv local values */
	/* ici, il faut redecomposer l'image en r,g,b chacun de 0 a 1 */
	nr=coul;
	ng=coul;
	nb=coul;

   nv = max_int (nr, max_int (ng, nb));
   m = min_int (nr, min_int (ng, nb));

   if (nv != 0.0)                /* if no value, it's black! */
      ns = (nv - m) / nv;
   else
      ns = 0.0;                 /* black = no colour saturation */

   if (ns == 0.0)                /* hue undefined if no saturation */
   {
      *h = 0.0;                  /* return black level (?) */
      *s = 0.0;
      *v = nv;
      return;
   }

   r1 = (nv - nr) / (nv - m);    /* distance of color from red   */
   g1 = (nv - ng) / (nv - m);    /* distance of color from green   */
   b1 = (nv - nb) / (nv - m);    /* distance of color from blue   */

   if (nv == nr)
   {
      if (m == ng)
         nh = 5. + b1;
      else
         nh = 1. - g1;
   } 

   if (nv == ng)
      {
      if (m == nb)
         nh = 1. + r1;
      else
         nh = 3. - b1;
      }

   if (nv == nb)
      {
      if (m == nr)
         nh = 3. + g1;
      else
         nh = 5. - r1;
      }

   *h = nh * 60.0;      /* return h converted to degrees */
   *s = ns;
   *v = nv;
   return;
}


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

long recup_palette(void)
{
	int i;
	const int *ptr_palette=(int *)0xff8240;
	for (i=0;i<16;i++)
		pal_in[i]=ptr_palette[i];
	return(0);
}

/*-------------------------------------------------------------------------*/
void open_vwork2(void)
{ 
     int i;
     int nb_plan;
	unsigned long taille;

	res=Getrez();
    nb_coul=work_out[13];			/* nombre de couleur presentes	*/
	nb_coul_pal=work_out[39];
	nb_plan=log(nb_coul_pal)/log(2);	/* calcul du nombre de plan de bits	*/
	 coul_div_4=nb_coul/4;
	 coul_div_2=nb_coul/2;
	 coul_mul_075=nb_coul*3/4;

	/* recuperer la palette originale	*/
  if (res>2)		/* si on est sur un tt*/
   {
		EgetPalette(0,256,pal_in);	/* recuperer la palette initiale	*/
   }
   else
   {
		Supexec(recup_palette);
   }

	/* le pointeur de ligne pointe sur la ligne courante	*/		
	ptr_ligne=ptr_ecran;

     switch (DisplayFormat)
   {
  	/* d0: tracage dans la resolution courante en palette fixe	*/
  	/* d1: pas de tracage durant le calcul. Affichage final en palette optimis‚e dans la resolution courante*/
	/* d2=d0+d1: tracage dans la resolution courante en palette fixe +Affichage final en palette optimis‚e */
	/* d3: tracage dans la resolution courante avec palette optimis‚e chaque fin de ligne		*/

  	case '0':		
   		pallete_init();
   		linea_init();
		break;
	case '2':
   		linea_init();
	case '1':	
	case '3':
		init_linea();
	   	for (i=0;i<4096;i++)
	   		table_couleur[i]=0;
		break;
	}
	if (DisplayFormat!=0)	/* si affichage optimise	*/			
		if (nb_coul!=0)	/* si il y a moins de 32768 couleurs	*/
		   	for (i=0;i<nb_coul_pal;i++)
   				table_couleur[i]=0;

	for (i=0;i<4096;i++)
		index[i]=-1;
	lim=-1;
}			  



/*-------------------------------------------------------------------------*/
void stpalcolor(unsigned int a,unsigned int r,unsigned int g,unsigned int b)
{
	int la_coul;
	la_coul= r*256+
			 g*16+b;
	EsetColor(a,la_coul);
}

/*-------------------------------------------------------------------------*/
void pallete_init()		/* Fill VGA 256 color palette with colors! */
{
      unsigned int m;
    unsigned int r, g, b;
     DBL hue, sat, val;

  /* make pallette  0 black */
  stpalcolor(0,0,0,0);
   /* make pallette  1/4 nb de couleur white */
  stpalcolor(coul_div_4,15,15,15);
  if (nb_coul==2)
  	return; 
  /* make pallette  1/2 nb couleur dark grey */
 stpalcolor(coul_div_2,7,7,7);

  /* make pallette  3/4 nb couleur lite grey */
   stpalcolor(coul_mul_075,11,11,11);
    for (m = 1; m <coul_div_4; m++)     /* for the 1st 64 colors... */
	{
	sat = 0.5;	/* start with the saturation and intensity low */
	val = 0.5;
	hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
	hsv_to_rgb (hue, sat, val, &r, &g, &b);
	stpalcolor (m, r, g, b); /* set m to rgb value */
	sat = 1.0;	/* high saturation and half intensity (shades) */
	val = 0.50;
	hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
	hsv_to_rgb (hue, sat, val, &r, &g, &b);
	stpalcolor (m + coul_div_4, r, g, b);  /* set m + nb_coul/4 */

	sat = 0.5;	/* half saturation and high intensity (pastels) */
	val = 1.0;

	hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
	hsv_to_rgb (hue, sat, val, &r, &g, &b);
	stpalcolor (m + coul_div_2, r, g, b); /* set m + 128 */

	sat = 1.0;            /* normal full HSV set at full intensity */
	val = 1.0;
   
	hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
	hsv_to_rgb (hue, sat, val, &r, &g, &b);
	stpalcolor (m + coul_mul_075, r, g, b); /* set m + 192 */
	}
    return;
}


void affi_image(void)
{
	int x;
	int nb_used;
	static int last_nb_coul=0;
	DBL h,s,v;
	float coulor;
	if (DisplayFormat=='3')		/* si on trace en palette optimisee	*/
	if (nb_plan!=15)		/* si on n'est pas en mode true color	*/
	{
		memcpy(color,table_couleur,sizeof(color));	/* copier dans color la table des couleurs non tries	*/
		calc_palette2();
		nb_used=lim+1;
		if (nb_used<nb_coul)	/* si on utilise moins de couleur
								qu'il y en as dans la palette	*/
		{
				if (nb_used>last_nb_coul)	/* si on a plus de couleur qu'avant	*/
				{
					last_nb_coul=nb_used;
					chg_palette();
				}
				aff_ligne();
		} else								
		if (memcmp(old_indx,indx,sizeof(int)*nb_coul*.75))	/* si la palette visible n'est pas la meme	*/
		{
			memcpy(old_indx,
					indx,
					sizeof(int)*nb_coul*.75);
			chg_palette();
			calc_corresp();
			aff_rend();
		}
		else
		{
			aff_ligne();					/* si elle est la meme, afficher la ligne	*/
		}
		ptr_ligne=ptr_ecran;
	}
	else						/* cas du mode 32768 couleurs	*/
		aff_ligne();	
	if (DisplayFormat!='2') return;	/*d2 :tracage en cours de calcul en palette fixe	*/
	for (x=0;x<dim_x;x++)
	{
	   rgb_to_hsv(ptr_ligne[x], &h, &s, &v);

	   if (s < 0.20)   /* black or white if no saturation of color... */
	   {
	   	   if (v < 0.25)
   		      coulor = 0;        /* black */
   		   else if (v > 0.8)
   		      coulor = coul_div_4;       /* white */
   		   else if (v > 0.5)
   		      coulor = coul_mul_075;      /* lite grey */
   		   else
   		      coulor = coul_div_2;      /* dark grey */
   		}
   		else
   		{
   	 	  coulor =  (64.0 * ((DBL)(h)) / 360.0);	

	      if (!coulor)
   	      coulor = 1;        /* avoid black, white or grey */
   	   
    	  if (coulor >coul_div_4)
	       	  coulor = coul_div_4-1;       /* avoid same */	

    	  if (v > 0.50)
	       	  coulor += coul_div_2;    /* colors 128-255 for high inten. */	

    	  if (s > 0.50)        /* more than half saturated? */
        	 coulor += coul_div_4;    /* color range 64-128 or 192-255 */
	    }
  		put_pixel(x,c_y,(int)coulor);	
  	}
	return;
}

void affi_final(void)
{
	/* affichage final effectue  pour d1 et d2*/
	if ((DisplayFormat=='2')	/* affichage final en palette optimis‚	*/
		|| (DisplayFormat=='1'))
	{
			memcpy(color,table_couleur,sizeof(color));
			calc_palette2();
			calc_corresp();
			chg_palette();
			aff_rend();
	}		
 
}


void display_finished2(void)
{
	if (Options & DISPLAY)
	{
		if (res>2)	
			EsetPalette(0,256,pal_in);		/* restorer la palette	*/
		else 
			Setpalette(pal_in);		/* restorer la palette	*/
		v_clsvwk(vdi_handle);
	}
}