
//=============================================
// 
// Mercredi 12 decembre 2001
//  
// Arash Habibi
// 
// Scene.c
//
/*typedef struct
{
  int largeur, hauteur; 
  float dist_obs_ecran; 
  int nb_objets; 
  objet_t objet[SC_NBMAX_OBJET]; 
} scene_t; */
//
//
//============================================

#include <Scene.h>

//-------------------------------------------
//-------------------------------------------

void SC_Check(scene_t *scene, char *commentaire)
{
  int i; 

  fprintf(stderr,"\n\n ||||||||||||||||| %s : CHECK SCENE |||||||||||||\n", commentaire); 

  fprintf(stderr,"largeur,hauteur =%d x %d pixels\n", scene->largeur, scene->hauteur);
  fprintf(stderr,"distnace observateur - ecran = %f\n", scene->dist_obs_ecran);
  fprintf(stderr,"Dans cette scene il y a %d objets.\n", scene->nb_objets);

  for(i=0; i<scene->nb_sources; i++)
    SR_Check(scene->source[i],"");

  for(i=0; i<scene->nb_objets; i++)
    O_Check(scene->objet[i],"");
}


//-------------------------------------------
//-------------------------------------------

static void _Init(scene_t *scene, int largeur, int hauteur)
{
  float distance_obs_ecran = 1.0; 
  float taille_pixel = 0.001; 
  couleur_t couleur_fond; 

  scene->largeur = largeur; 
  scene->hauteur = hauteur; 
  PM_InitBuffer(largeur, hauteur);

  scene->taille_pixel = taille_pixel; 
  scene->largeurF = taille_pixel * scene->largeur; 
  scene->hauteurF = taille_pixel * scene->hauteur; 

  scene->dist_obs_ecran = distance_obs_ecran; 

  V_Set(&(scene->pixel_inf_gauche),
	-scene->largeurF/2.0 + taille_pixel/2.0, 
	-scene->hauteurF/2.0 + taille_pixel/2.0, 
	scene->dist_obs_ecran);

  V_Set(&(scene->observateur), 0.0, 0.0, 0.0);
  V_Set(&(scene->regard),      0.0, 0.0, 1.0);
  V_Set(&(scene->haut),        0.0, 1.0, 0.0);
  V_Set(&(scene->gauche),     -1.0, 0.0, 0.0);

  C_SetFL(&couleur_fond, 0.0, 0.0, 0.0);
  // C_SetUB(&couleur_fond, 51, 127, 178);
  scene->couleur_fond   = couleur_fond; 

  scene->nb_objets = 0; 
}


//-------------------------------------------
//-------------------------------------------

static void _AdditionObjet(scene_t *scene, objet_t objet)
{
  if(scene->nb_objets>=SC_NBMAX_OBJET)
    {
      fprintf(stderr,"_AdditionObjet : \n");
      fprintf(stderr,"Nous avons deja %d objets et on ne peut pas en prendre davantage.\n", 
	      scene->nb_objets);
      exit(1);
    }
  else
    {
      scene->objet[scene->nb_objets] = objet; 
      scene->nb_objets ++; 
    }
}

//-------------------------------------------
//-------------------------------------------

static void _AdditonSource(scene_t *scene, source_t s)
{
  if(scene->nb_sources>=SC_NBMAX_SOURCE)
    {
      fprintf(stderr,"_AdditionSource : \n");
      fprintf(stderr,"Nous avons deja %d sources et on ne peut pas en prendre davantage.\n", 
	      scene->nb_sources); 
      exit(1);
    }
  else
    {
      scene->source[scene->nb_sources] = s; 
      scene->nb_sources++; 
    }
}

//-------------------------------------------
//-------------------------------------------

void SC_Build(scene_t *scene, int largeur, int hauteur)
{
  couleur_t rouge, vert, bleu, blanc, tresblanc, noir; 
  surface_t rouge_brillant, vert_mat, blanc_mat, bleu_brillant; 
  objet_t sphere_rouge, sphere_bleue, sol, confetti; 
  sphere_t *sphere_centre, *sphere_decal;  
  plan_t *plan; 
  triangle_t *triangle; 
  vecteur_t centre, P, j; 
  vecteur_t A, B, C, D, E; 
  source_t source1;

  _Init(scene, largeur, hauteur); 

  C_SetFL(&noir,  0.0, 0.0, 0.0); 
  C_SetFL(&rouge, 1.0, 0.0, 0.0);
  C_SetFL(&vert,  0.0, 2.0, 0.4);
  C_SetFL(&bleu,  12,  20,  40);
  C_SetFL(&blanc, 2.0, 2.0, 2.0);
  C_SetFL(&tresblanc, 5.0, 5.0, 5.0);

  PH_Set(&rouge_brillant, noir,  rouge, noir, 10, 0, 0, 0); 
  PH_Set(&vert_mat,       vert,  noir,  noir, 0,  0, 0, 0); 
  PH_Set(&blanc_mat,      blanc, noir,  noir, 0,  0, 0, 0); 
  PH_Set(&bleu_brillant,  noir,  tresblanc, noir, 100, 0, 0, 0); 

  V_Set(&D, 0.0, 3.0, 6.0); 
  V_Set(&E, 1.0, 2.5, 6.0); 
  SR_Set(&source1, blanc, D); 
  _AdditonSource(scene, source1); 
  // SR_Set(&source2, blanc, E);
  // _AdditonSource(scene, source2);  

  V_Set(&P, 0.0,-2.0, 0.0); 
  V_Set(&j, 0.0, 1.0, 0.0); 

  //----------

  NEW(sphere_centre,1,sphere_t);

  O_SetNom(&sphere_rouge, "la_rouge");
  O_SetCouleur(&sphere_rouge, rouge);
  O_SetSurface(&sphere_rouge, blanc_mat); 

  V_Set(&centre, 0.0, -1.0, 10.0);
  S_Set(sphere_centre, centre, 1.0);
  O_SetShape(&sphere_rouge, O_SPHERE, (void*)(sphere_centre));

  _AdditionObjet(scene, sphere_rouge); 

  //----------

  NEW(sphere_decal,1,sphere_t);

  O_SetNom(&sphere_bleue, "la_bleue");
  O_SetCouleur(&sphere_bleue, bleu);
  O_SetSurface(&sphere_bleue, bleu_brillant); 

  V_Set(&centre, 1.0, 0.0, 13.0);
  S_Set(sphere_decal, centre, 1.0);
  O_SetShape(&sphere_bleue, O_SPHERE, (void*)(sphere_decal));

  _AdditionObjet(scene, sphere_bleue); 

  //----------

  NEW(plan,1,plan_t); 

  O_SetNom(&sol, "le_sol");
  O_SetCouleur(&sol, vert);
  O_SetSurface(&sol, vert_mat);

  P_Set1(plan, P, j); 
  O_SetShape(&sol, O_PLAN, (void*)(plan));

  _AdditionObjet(scene, sol); 

  //----------

  NEW(triangle,1,triangle_t); 

  O_SetNom(&confetti, "confetti");
  O_SetCouleur(&confetti, blanc);
  O_SetSurface(&confetti, blanc_mat);

  V_Set(&A, 0.5, 0.5, 5.0); 
  V_Set(&B,-0.1, 0.6, 5.0); 
  V_Set(&C, 0.0, 0.5, 6.0); 

  TR_Set(triangle, A, B, C); 
  O_SetShape(&confetti, O_TRIANGLE, (void*)(triangle));

  _AdditionObjet(scene, confetti); 

  //----------

  SC_Check(scene, "apres build");
}


//-------------------------------------------
// retourne la position du pixel dans 
// l'espace. 
//-------------------------------------------

vecteur_t _PositionPixel(scene_t *scene, int i, int j)
{
  vecteur_t resultat; 

  V_Set(&resultat, 
	(scene->pixel_inf_gauche).x + i*scene->taille_pixel, 
	(scene->pixel_inf_gauche).y + j*scene->taille_pixel, 
	scene->dist_obs_ecran);

  return(resultat);
}

//-------------------------------------------
//-------------------------------------------

void SC_Visualize(scene_t *scene, char *nomprog, char *nomppm)
{
  int colonne, ligne, objet_cpt, source_cpt, nb_intersections, leplusproche=-1; 
  rayon_t rayon; 
  double dist, dist_min=SC_TRESLOIN; 
  vecteur_t pos_pixel, direction_rayon; 
  couleur_t couleur; 

  for(colonne=0; colonne<scene->largeur; colonne++)
    for(ligne=0; ligne<scene->hauteur; ligne++)
      {
	pos_pixel = _PositionPixel(scene, colonne, ligne);
	// V_Set(&pos_pixel, 0.0, 0.0, scene->dist_obs_ecran); 
	direction_rayon = V_Difference(pos_pixel, scene->observateur);
	R_Set(&rayon, scene->observateur, direction_rayon);

	leplusproche = -1; 
	dist_min = SC_TRESLOIN; 

	for(objet_cpt=0; objet_cpt<scene->nb_objets; objet_cpt++)
	  {
	    O_IntersectRayon(scene->objet[objet_cpt], 
			     rayon, &nb_intersections, 
			     &(scene->intersection[objet_cpt]),
			     &(scene->normal[objet_cpt]));
	    
	    if(nb_intersections!=0)
	      {
		dist = V_Distance(scene->observateur, scene->intersection[objet_cpt]); 
		if(dist < dist_min)
		  {
		    dist_min = dist; 
		    leplusproche = objet_cpt; 
		  }
	      }
	  }

	// V_Check(scene->intersection[0], "intersection"); 
	// V_Check(scene->normal[0], "normal"); 

	if(leplusproche==-1)
	  PM_Color(scene->couleur_fond.r, scene->couleur_fond.v, scene->couleur_fond.b);

	else 
	  {
	    C_SetFL(&couleur, 0.0, 0.0, 0.0); 
	    for(source_cpt=0; source_cpt<scene->nb_sources; source_cpt++)
	      couleur = C_Addition(couleur, PH_CouleurReflechie(scene->objet[leplusproche].surface, 
								scene->normal[leplusproche], 
								scene->intersection[leplusproche], 
								scene->source[source_cpt].position, 
								scene->observateur, 
								scene->source[source_cpt].couleur, 
								scene->lumiere_ambiante)); 
	    PM_Color(couleur.r, couleur.v, couleur.b); 
	  }

	PM_Vertex(colonne, ligne);
      }
  PM_SaveImagePPM(nomppm, nomprog);
  
  PM_Close();
}
