#include <stdio.h>
#include <math.h>
#include <string.h>
#include "graphic3d.h"
#include "es.h"
#include "util.h"

/* Liste des coordonnees des triangles finale                         */
extern static triangle_t *ListTri;

extern static double rayon=1.;
extern static double rmin;
extern static char   outf[80]="";
extern static int    depth;

/***************************************************************/
/* Allocation et initialisation d'un tableau de triangle       */
/* La taille finale = nb * echelle, nb etant le nombre de      */
/* triangles initiales et echelle le multiplicateur de la      */
/* subdivision                                                 */ 
/***************************************************************/
triangle_t * Initialisation( triangle_t *list_init, int nb, int echelle)
{
  triangle_t *list_tri;  /* Tableau de triangles */
  int         i;         /* indice d'iterations  */

  list_tri = (triangle_t *) malloc( nb*echelle*sizeof(triangle_t) );

  if ( !list_tri ) {
    fprintf( stdout, "Erreur d'allocation de memoire : %d octets\n",
	     nb*echelle*sizeof(triangle_t) );
    exit(-2);
  }

  for ( i=0; i<nb; i++ ) {
    CopyTriangle( list_tri[i*echelle], list_init[i] );
  }

  return list_tri;
}


/***************************************************************/
/* Subdivision d'un seul triangle                              */
/***************************************************************/
void  SubdivisionSingle( triangle_t t0, 
			 triangle_t t1, triangle_t t2,
			 triangle_t t3, triangle_t t4 )
{
  triangle_t tmp;
  point3d_t  p01, p12, p30;

  CopyTriangle( tmp, t0 );

  /* Calcul des points de milieu */
  p01.x = t0[0].x + t0[1].x;
  p01.y = t0[0].y + t0[1].y;
  p01.z = t0[0].z + t0[1].z;

  p12.x = t0[1].x + t0[2].x;
  p12.y = t0[1].y + t0[2].y;
  p12.z = t0[1].z + t0[2].z;

  p30.x = t0[0].x + t0[2].x;
  p30.y = t0[0].y + t0[2].y;
  p30.z = t0[0].z + t0[2].z;

  Normaliser( &p01 );
  Normaliser( &p12 );
  Normaliser( &p30 );

  /* Creation de nouveaux triangles */
  CopyPoint3d( t1+0, tmp+0 );
  CopyPoint3d( t1+1, &p01 );
  CopyPoint3d( t1+2, &p30 );

  CopyPoint3d( t2+0, &p01 );
  CopyPoint3d( t2+1, tmp+1 );
  CopyPoint3d( t2+2, &p12 );

  CopyPoint3d( t3+0, &p01 );
  CopyPoint3d( t3+1, &p12 );
  CopyPoint3d( t3+2, &p30 );

  CopyPoint3d( t4+0, &p30 );
  CopyPoint3d( t4+1, &p12 );
  CopyPoint3d( t4+2, tmp+2 );
}



/************************************************************* */
/* Affinement du maillage d'une spere unitaire par une         */
/* subdivision recursive des triangles                         */
/************************************************************* */
void SubdivisionGlobale( triangle_t *list_tri, int nb, int prof )
{
  int p;           /* indice d'iteration de la profondeur */
  int i;           /* indice des triagnles a subdiviser   */
  int nb_total=nb; /* nb * 4^prof                         */
  int pas_cur=1, pas_suiv=1;

  for ( i=0; i<prof; i++ ) pas_suiv *= 4;

  nb_total = nb * pas_suiv;

  for ( p=prof; p>0; p-- ) {
    pas_cur = pas_suiv;
    pas_suiv /= 4;

    for ( i=0; i<nb_total; i+=pas_cur )
      SubdivisionSingle( list_tri[i], 
			 list_tri[i], list_tri[i+pas_suiv], 
			 list_tri[i+2*pas_suiv], list_tri[i+3*pas_suiv] );
  }
}


/************************************************************* */
/* Calcul de la profondeur de la subdivision                   */
/* a partir du rayon de la sphere R et rmin                    */
/************************************************************* */
int calculDepth( double R, double r, int nb_dep )
{
  double   surf_s;     /* surface de la sphere  */
  double   surf_t;     /* surface d'un triangle */
  int      nb_tri;
  int      depth = 1;

  surf_s = 4.0 * M_PI * rayon * rayon;
  surf_t = sqrt( (double)3.0 ) * M_PI * rmin * rmin / 4.0;
  nb_tri =  (int)(surf_s / surf_t + 0.5);

printf("Nb de triangles minimum : %d\n", nb_tri);
  nb_tri = (int)( (double)nb_tri/nb_dep + 0.5);

  while ( nb_tri>4 ) {
    nb_tri = (int) ( (double)nb_tri/4.0 + 0.5 );
    depth++;
  }

  return depth;
}


/************************************************************* */
/* Analyse des options du programme                            */
/************************************************************* */
void analyzeParams(int argc, char **argv)
{
  int ind_p=0, ind_o=0;   /* indicateurs des options -p et -o */ 
  int ind_R=0, ind_r=0;   /* indicateurs des options -R et -r */ 
  int i=0;

  while ( ++i<argc ) {
    if ( strcmp( argv[i], "-d" ) == 0 ) { 
      depth = atoi( argv[++i] );
      ind_p = 1;
    }

    if ( strcmp( argv[i], "-o" ) == 0 ) {
      strcpy( outf, argv[++i] );
      ind_o = 1;
    }

    if ( strcmp( argv[i], "-R" ) == 0 ) {
      rayon = atof( argv[++i] );
      ind_R = 1;
    }

    if ( strcmp( argv[i], "-r" ) == 0 ) {
      rmin = atof( argv[++i] );
      ind_r = 1;
    }
  }

  if ( !ind_p ) {
    if ( !ind_R || !ind_r ) {
      fprintf( stderr, "Usage : %s -d profondeur[-R rayon -r rmin] -c [-i] -cart [-spher] -o fichier\n", argv[0] );
      fprintf( stderr, "Les options -R et -r doivent etre utilisees ensemble\n" );
      exit( -1 );
    } 
    else {
      printf( "R = %f, r=%f\n", rayon, rmin );
      depth = calculDepth( rayon, rmin, NB );
    }
  }

  if ( !ind_o ) {
      fprintf( stderr, "Manque -o fichier\n" );
      exit( -1 );
  }
}
