/***********************************************************************************/
/*   Objects.c : library of basic objects for OpenGL                               */
/*                                                                                 */
/*   Author : Christophe Morel, Jian-jin LI                                        */
/*                                                                                 */
/***********************************************************************************/
#include <stdlib.h> 
#include "objects.h"

#ifndef M_PI
#define M_PI 3.14159265
#endif

#define RADIUS 1

extern int     displayStyle;
extern double *ListTri;     /* Liste des coordonnees des triangles du maillage */
extern int     NBTri;       /* Nombre de triangles du maillage                 */
extern double *ListCoordX;
extern double *ListCoordY;
extern double *ListCoordZ;
extern double *ListCoordX_E;
extern double *ListCoordY_E;
extern double *ListCoordZ_E;
extern double *texture_E;
extern double *ListCoordX_tore;
extern double *ListCoordY_tore;
extern double *ListCoordZ_tore;
extern double *texture_tore;
extern double *texture_E_Affiche;
extern double *ListTheta;
extern double *ListPhi;
extern int NbLat;
extern int NbPts;

extern double *texture;
extern int     useTexture;
extern float cam_x;
extern float cam_y;

static double  dpi = 2.0*M_PI;

/***********************************************************************************/
/*                                                                                 */
/* Transformation of the Cartesian coordinates to polar coordinates                */
/*                                                                                 */
/* Inputs  :                                                                       */
/*           s : 3D Cartesian coordinates                                          */
/* Outputs :                                                                       */
/*           u : 2D texture coordinates                                            */
/*                                                                                 */
/***********************************************************************************/
void cart2Pol(double  s[3], double u[2])
{
    u[0] = atan2(s[1], -s[0]) / dpi + 0.5;
    u[1] = acos(s[2]/RADIUS) / M_PI;
}



/***********************************************************************************/
/*                                                                                 */
/* Draw a triangle with normal and texture coordinates                             */
/*                                                                                 */
/* Inputs  :                                                                       */
/*           t   : Cartesian coordinates of 3 vertex                               */
/* Outputs :                                                                       */
/*           tex : texture coordinates of 3 vertex                                 */
/*                                                                                 */
/***********************************************************************************/
void drawTriangle( double *t,  double *col )
{
  //double u[2]; /* coordonnees de texture */

  glBegin( displayStyle );
  
    glNormal3d( t[0], t[1], t[2] ); 
    if ( useTexture ) glColor3f( col[0], col[0], col[0] );
    else glColor3f( 1.0, 0.5, 0.0 );
    glVertex3d( t[0], t[1], t[2] );

    glNormal3d( t[3], t[4], t[5] ); 
    if ( useTexture ) glColor3f( col[1], col[1], col[1] );
    else glColor3f( 1.0, 0.5, 0.0 );
    glVertex3d( t[3], t[4], t[5] );

    glNormal3d( t[6], t[7], t[8] ); 
    if ( useTexture ) glColor3f( col[2], col[2], col[2] );
    else glColor3f( 1.0, 0.5, 0.0 );
    glVertex3d( t[6], t[7], t[8] );

  glEnd();
}


/***********************************************************************************/
/*                                                                                 */
/* Draw a object formed by a list of triangles                                     */
/*                                                                                 */
/* Inputs  :                                                                       */
/*           ListTri : list of triangle's vertex coordinates                       */
/*           ListTex : list of texture coordinates of triangle's vertex            */
/*                                                                                 */
/***********************************************************************************/
void drawListTriangles()
{
  int i;

  for (i = 0; i < NBTri; i++) 
  {
    drawTriangle( ListTri+i*9, texture+3*i );
  }
}


/***********************************************************************************/
/*                                                                                 */
/* Draw a rectangle                                                                */
/*    If orientation = 1 , normal vectors are oriented like z axis                 */
/*    If orientation = -1, normal vectors are oriented like -z axis                */
/*                                                                                 */
/***********************************************************************************/
void drawRectangle(
      int numWidth,   /* Resolution for Width                                      */
      int numDepth,   /* Resolution for Depth                                      */
      float Width,    /* Width of the rectangle                                    */
      float Depth,    /* Depth of the rectangle                                    */
      int orientation /* Indicate the orientation of the normal vectors            */
)
{

  float xStep = (float)Width/numWidth;
  float yStep = (float)Depth/numDepth;

  float x0, x1;
  float y0, y1;
  float u0, u1;
  float v0, v1;

  int    i, j;

  x0 = -Width/2.0; u0 = 0.0;
  for (i=0;i<numWidth;++i)
  {
    x1 = x0 + xStep;
    u1 = (float)(i+1)/(float)numWidth;

    y0 = -Depth/2.0; v0 = 0.0;
         
    for (j=0;j<numDepth;++j)
    {
      y1 = y0 + yStep;
      v1 = (float)(j+1)/(float)numDepth;

    glBegin(displayStyle);
      glNormal3f(0.0,0.0,orientation);
      glVertex3f(x0, y0, 0.0);

      glNormal3f(0.0,0.0,orientation);
      glVertex3f(x1, y0, 0.0);
      
      glNormal3f(0.0,0.0,orientation);
      glVertex3f(x1, y1, 0.0);

      glNormal3f(0.0,0.0,orientation);
      glVertex3f(x0, y1, 0.0);
    glEnd();

      y0 = y1;
      v0 = v1;
    }
    
    x0 = x1;
    u0 = u1;
  }
}


/***********************************************************************************/
/*                                                                                 */
/* Draw a rectangle                                                                */
/*    If orientation = 1 , normal vectors are oriented like z axis                 */
/*    If orientation = -1, normal vectors are oriented like -z axis                */
/*                                                                                 */
/***********************************************************************************/
void drawRectangle2(
      int orientation /* Indicate the orientation of the normal vectors            */
)
{

    glBegin(displayStyle);
      glColor3f(1.0, 1.0, 1.0);
      glNormal3f(0.0,0.0,orientation);
      glVertex3f(-1.0, -1.0, 0.0);

      glColor3f(1.0, 0.0, 0.0);
      glNormal3f(0.0,0.0,orientation);
      glVertex3f(1.0, -1.0, 0.0);
      
      glColor3f(0.0, 1.0, 0.0);
      glNormal3f(0.0,0.0,orientation);
      glVertex3f(1.0, 1.0, 0.0);

      glColor3f(0.0, 0.0, 1.0);
      glNormal3f(0.0,0.0,orientation);
      glVertex3f(-1.0, 1.0, 0.0);
    glEnd();

}


/***********************************************************************************/
/*                                                                                 */
/* Draw a sphere                                                                   */
/*                                                                                 */
/***********************************************************************************/
void drawSphere(
      int numAngle, /* Resolution for Angle                                        */
      float radius, /* Radius of the sphere                                        */
      int half      /* Do we draw an entire or half a sphere ?                     */
)
{
  float majorStep = (M_PI /numAngle);
  float minorStep = ((half?1.0:2.0) * M_PI / numAngle);
  int i, j;
  float a0, a1;
  float r0, r1;
  float z0, z1;
  float c0, c1;
  float x0, x1;
  float y0, y1;

  a0 = 0.0;
  r0  = radius * sin(a0);
  z0 = radius * cos(a0);
   for (i = 0; i < numAngle; ++i) 
  {
    a1 = a0 + majorStep;
    r1 = radius * sin(a1);
    z1 = radius * cos(a1);
    
    c0 = 0.0;
    x0 = (float)cos(c0);
    y0 = (float)sin(c0);
    for (j = 0; j <= numAngle; ++j) {
      c1 = c0 + minorStep;
      x1 = (float)cos(c1);
      y1 = (float)sin(c1);
      
    glBegin(displayStyle);
      glNormal3f((x0 * r0) / radius, (y0 * r0) / radius, z0 / radius);
      glVertex3f(x0 * r0, y0 * r0, z0);

      glNormal3f((x0 * r1) / radius, (y0 * r1) / radius, z1 / radius);
      glVertex3f(x0 * r1, y0 * r1, z1);

      glNormal3f((x1 * r1) / radius, (y1 * r1) / radius, z1 / radius);
      glVertex3f(x1 * r1, y1 * r1, z1);

      glNormal3f((x1 * r0) / radius, (y1 * r0) / radius, z0 / radius);
      glVertex3f(x1 * r0, y1 * r0, z0);
    glEnd();
      
      c0 = c1;
      x0 = x1;
      y0 = y1;
    }

    a0 = a1;
    r0 = r1;
    z0 = z1;
  }
}


/***********************************************************************************/
/*                                                                                 */
/* Draw an equiangular sphere                                                      */
/*                                                                                 */
/***********************************************************************************/

void drawSphereEqui(void)
{
	int i, j;
	double rouge, vert, bleu;
	
	rouge = 1;
	vert = 1;
	bleu = 1;
	
	glBegin(displayStyle);
		for (j=0; j<NbLat+1; j++)
		{
			if (j==0)
			{
				glNormal3d(0.0,0.0,1.0);
				glColor3f(texture[0]*rouge, texture[0]*vert, texture[0]*bleu);
				glVertex3d(0.0,0.0,1.0);
			}

			glNormal3d(ListCoordX[j-1],ListCoordY[j-1],ListCoordZ[j-1]);
			glColor3f(texture[j-1]*rouge, texture[j-1]*vert, texture[j-1]*bleu);
			glVertex3d(ListCoordX[j-1],ListCoordY[j-1],ListCoordZ[j-1]);
		}
	glEnd();
	
	for (j=0; j<(NbLat*(NbLat-1)-1); j++)
	{
		glBegin(displayStyle);

			glNormal3d(ListCoordX[j],ListCoordY[j],ListCoordZ[j]);
			glColor3f(texture[j]*rouge, texture[j]*vert, texture[j]*bleu);
			glVertex3d(ListCoordX[j],ListCoordY[j],ListCoordZ[j]);
	
			glNormal3d(ListCoordX[j+1],ListCoordY[j+1],ListCoordZ[j+1]);
			glColor3f(texture[j+1]*rouge, texture[j+1]*vert, texture[j+1]*bleu);
			glVertex3d(ListCoordX[j+1],ListCoordY[j+1],ListCoordZ[j+1]);

			glNormal3d(ListCoordX[j+NbLat+1],ListCoordY[j+NbLat+1],ListCoordZ[j+NbLat+1]);
			glColor3f(texture[j+NbLat+1]*rouge, texture[j+NbLat+1]*vert, texture[j+NbLat+1]*bleu);
			glVertex3d(ListCoordX[j+NbLat+1],ListCoordY[j+NbLat+1],ListCoordZ[j+NbLat+1]);

			glNormal3d(ListCoordX[j+NbLat],ListCoordY[j+NbLat],ListCoordZ[j+NbLat]);
			glColor3f(texture[j+NbLat]*rouge, texture[j+NbLat]*vert, texture[j+NbLat]*bleu);
			glVertex3d(ListCoordX[j+NbLat],ListCoordY[j+NbLat],ListCoordZ[j+NbLat]);
			
		glEnd();
	}
	
	glBegin(displayStyle);
		for (j=(NbLat*(NbLat-1)); j<(NbLat*NbLat+1); j++)
		{
			if (j==(NbLat*(NbLat-1)))
			{
				glNormal3d(0.0,0.0,-1.0);
				glColor3f(texture[NbLat*(NbLat-1)]*rouge, texture[NbLat*(NbLat-1)]*vert, texture[NbLat*(NbLat-1)]*bleu);
				glVertex3d(0.0,0.0,-1.0);
			}
			glNormal3d(ListCoordX[j-1],ListCoordY[j-1],ListCoordZ[j-1]);
			glColor3f(texture[j-1]*rouge, texture[j-1]*vert, texture[j-1]*bleu);
			glVertex3d(ListCoordX[j-1],ListCoordY[j-1],ListCoordZ[j-1]);
		}
	glEnd();

}


/***********************************************************************************/
/*                                                                                 */
/* Draw an equiangular sphere in elevation                                         */
/*                                                                                 */
/***********************************************************************************/

void drawSphereEqui_Elevation(void)
{
	int i, j;
	double rouge, vert, bleu;
	
	rouge = 1;
	vert = 1;
	bleu = 1;
	
	glBegin(displayStyle);
		for (j=0; j<NbLat+1; j++)
		{
			if (j==0)
			{
				glNormal3d(ListCoordX_E[0],ListCoordY_E[0],ListCoordZ_E[0]);
				glColor3f(texture_E_Affiche[0]*rouge, texture_E_Affiche[0]*vert, texture_E_Affiche[0]*bleu);
				glVertex3d(ListCoordX_E[0],ListCoordY_E[0],ListCoordZ_E[0]);
			}

			glNormal3d(ListCoordX_E[j-1],ListCoordY_E[j-1],ListCoordZ_E[j-1]);
			glColor3f(texture_E_Affiche[j-1]*rouge, texture_E_Affiche[j-1]*vert, texture_E_Affiche[j-1]*bleu);
			glVertex3d(ListCoordX_E[j-1],ListCoordY_E[j-1],ListCoordZ_E[j-1]);
		}
	glEnd();
	
	for (j=0; j<(NbLat*(NbLat-1)-1); j++)
	{
		glBegin(displayStyle);

			glNormal3d(ListCoordX_E[j],ListCoordY_E[j],ListCoordZ_E[j]);
			glColor3f(texture_E_Affiche[j]*rouge, texture_E_Affiche[j]*vert, texture_E_Affiche[j]*bleu);
			glVertex3d(ListCoordX_E[j],ListCoordY_E[j],ListCoordZ_E[j]);
	
			glNormal3d(ListCoordX_E[j+1],ListCoordY_E[j+1],ListCoordZ_E[j+1]);
			glColor3f(texture_E_Affiche[j+1]*rouge, texture_E_Affiche[j+1]*vert, texture_E_Affiche[j+1]*bleu);
			glVertex3d(ListCoordX_E[j+1],ListCoordY_E[j+1],ListCoordZ_E[j+1]);

			glNormal3d(ListCoordX_E[j+NbLat+1],ListCoordY_E[j+NbLat+1],ListCoordZ_E[j+NbLat+1]);
			glColor3f(texture_E_Affiche[j+NbLat+1]*rouge, texture_E_Affiche[j+NbLat+1]*vert, texture_E_Affiche[j+NbLat+1]*bleu);
			glVertex3d(ListCoordX_E[j+NbLat+1],ListCoordY_E[j+NbLat+1],ListCoordZ_E[j+NbLat+1]);

			glNormal3d(ListCoordX_E[j+NbLat],ListCoordY_E[j+NbLat],ListCoordZ_E[j+NbLat]);
			glColor3f(texture_E_Affiche[j+NbLat]*rouge, texture_E_Affiche[j+NbLat]*vert, texture_E_Affiche[j+NbLat]*bleu);
			glVertex3d(ListCoordX_E[j+NbLat],ListCoordY_E[j+NbLat],ListCoordZ_E[j+NbLat]);
			
		glEnd();
	}
	
	glBegin(displayStyle);
		for (j=(NbLat*(NbLat-1)); j<(NbLat*NbLat+1); j++)
		{
			if (j==(NbLat*(NbLat-1)))
			{
				glNormal3d(ListCoordX_E[NbLat*(NbLat-1)],ListCoordY_E[NbLat*(NbLat-1)],ListCoordZ_E[NbLat*(NbLat-1)]);
				glColor3f(texture_E_Affiche[NbLat*(NbLat-1)]*rouge, texture_E_Affiche[NbLat*(NbLat-1)]*vert, texture_E_Affiche[NbLat*(NbLat-1)]*bleu);
				glVertex3d(ListCoordX_E[NbLat*(NbLat-1)],ListCoordY_E[NbLat*(NbLat-1)],ListCoordZ_E[NbLat*(NbLat-1)]);
			}
			glNormal3d(ListCoordX_E[j-1],ListCoordY_E[j-1],ListCoordZ_E[j-1]);
			glColor3f(texture_E_Affiche[j-1]*rouge, texture_E_Affiche[j-1]*vert, texture_E_Affiche[j-1]*bleu);
			glVertex3d(ListCoordX_E[j-1],ListCoordY_E[j-1],ListCoordZ_E[j-1]);
		}
	glEnd();

}



/***********************************************************************************/
/*                                                                                 */
/* Draw a HEALPix sphere                                                           */
/*                                                                                 */
/***********************************************************************************/

void drawSphereHEALPix(void)
{
	double delta_theta, delta_phi, x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
	double theta, phi, theta_ref, sin_theta;
	double phi0, delta_phi0, phi_theta, theta_phi, theta0;
	int i, NSide, NCap, count = 0;
	
	NSide = sqrt(NbPts/12.0);
	NCap = 2*((NSide*NSide)-NSide);
	
	delta_theta = ListTheta[0];
	theta_ref = 0.0;
	
	for (i=0; i<NbPts/2.0; i++)
	{
		theta = ListTheta[i];
		sin_theta = sin(theta);
		if(theta!=theta_ref)
		{
			theta_ref = theta;
			sin_theta = sin(theta);
			delta_phi = (ListPhi[i+1]-ListPhi[i])/2.0;
			texture[i] = 1.0;
			if (i!=0)
			{
				delta_theta = (ListTheta[i]-ListTheta[i-1]);
				phi0 = ListPhi[i-count];
				theta0 = ListTheta[i-count];
				delta_phi0 = (ListPhi[i-count+1]-ListPhi[i-count])/2.0;
				count = 0;
			}
		}

		phi = ListPhi[i];
		
		if ((i>=0 && i<4) || (i>=(NbPts-4) && i<NbPts) || (i>=NCap && i<(NbPts-NCap)))
		{
			x1 = sin(theta-delta_theta)*cos(phi);
			y1 = sin(theta-delta_theta)*sin(phi);
			z1 = cos(theta-delta_theta);
		
			x2 = sin(theta)*cos(phi-delta_phi);
			y2 = sin(theta)*sin(phi-delta_phi);
			z2 = cos(theta);
		
			x3 = sin(theta+delta_theta)*cos(phi);
			y3 = sin(theta+delta_theta)*sin(phi);
			z3 = cos(theta+delta_theta);
		
			x4 = sin(theta)*cos(phi+delta_phi);
			y4 = sin(theta)*sin(phi+delta_phi);
			z4 = cos(theta);
			
			//if (i>=0 && i<4)
			//{
			//	phi_theta[i] = phi-delta_phi;
			//}
		}
		
		if (i>=4 && i<NCap)
		{
			if (count == 0)
			{
				phi_theta = phi0 - delta_phi0;
			}
			else if (count%2 != 0)
			{
				phi_theta = phi_theta + 2*delta_phi0;
			}
				
			x1 = sin(theta-delta_theta)*cos(phi_theta);
			y1 = sin(theta-delta_theta)*sin(phi_theta);
			z1 = cos(theta-delta_theta);
		
			x2 = sin(theta)*cos(phi-delta_phi);
			y2 = sin(theta)*sin(phi-delta_phi);
			z2 = cos(theta);
		
			x3 = sin(theta+delta_theta)*cos(phi);
			y3 = sin(theta+delta_theta)*sin(phi);
			z3 = cos(theta+delta_theta);
		
			x4 = sin(theta)*cos(phi+delta_phi);
			y4 = sin(theta)*sin(phi+delta_phi);
			z4 = cos(theta);
		}
		count ++;
		
		/*x1 = sin(theta-delta_theta)*cos(phi);
		y1 = sin(theta-delta_theta)*sin(phi);
		z1 = cos(theta-delta_theta);
		
		x2 = sin(theta)*cos(phi-delta_phi);
		y2 = sin(theta)*sin(phi-delta_phi);
		z2 = cos(theta);
		
		x3 = sin(theta+delta_theta)*cos(phi);
		y3 = sin(theta+delta_theta)*sin(phi);
		z3 = cos(theta+delta_theta);
		
		x4 = sin(theta)*cos(phi+delta_phi);
		y4 = sin(theta)*sin(phi+delta_phi);
		z4 = cos(theta);*/
		
		glBegin(displayStyle);
			glNormal3d(x1,y1,z1);
			glColor3f(texture[i], texture[i], texture[i]);
			glVertex3d(x1,y1,z1);
			
			glNormal3d(x2,y2,z2);
			glColor3f(texture[i], texture[i], texture[i]);
			glVertex3d(x2,y2,z2);
			
			glNormal3d(x3,y3,z3);
			glColor3f(texture[i], texture[i], texture[i]);
			glVertex3d(x3,y3,z3);
			
			glNormal3d(x4,y4,z4);
			glColor3f(texture[i], texture[i], texture[i]);
			glVertex3d(x4,y4,z4);			
		glEnd();
	}
}



void draw_mask(void)
{
	/*glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4d(0.5,0.5,0.5,0.5);
	glBegin( GL_QUADS );
		glVertex3d (cam_x-0.01, cam_y + 0.08, 1.05 ) ;
		glVertex3d (cam_x + 0.01, cam_y +0.08, 1.05 ) ;
		glVertex3d (cam_x+0.01, cam_y - 0.08, 1.05 ) ;
		glVertex3d (cam_x - 0.01, cam_y-0.08, 1.05 ) ;
	glEnd() ;
	glDisable(GL_BLEND);*/
	
	GLUquadricObj *quad;
	quad = gluNewQuadric();
	gluQuadricNormals(quad, GLU_SMOOTH);
	gluQuadricTexture(quad, GL_TRUE);
	//glTranslatef(1.2, 1.2, 0.0);
	//glRotatef();
	
	gluCylinder(quad, 0.2, 0.2, 0.5, 32, 32);

}


void drawTore(void)
{
	int j = 0;
	
	while (j<(NbPts-3))
	{
		glBegin(GL_QUADS);
		{
			glNormal3d(ListCoordX_tore[j],ListCoordY_tore[j],ListCoordZ_tore[j]);
			glColor3f(texture_tore[j], texture_tore[j], texture_tore[j]);
			glVertex3d(ListCoordX_tore[j],ListCoordY_tore[j],ListCoordZ_tore[j]);
	
			glNormal3d(ListCoordX_tore[j+1],ListCoordY_tore[j+1],ListCoordZ_tore[j+1]);
			glColor3f(texture_tore[j+1], texture_tore[j+1], texture_tore[j+1]);
			glVertex3d(ListCoordX_tore[j+1],ListCoordY_tore[j+1],ListCoordZ_tore[j+1]);

			glNormal3d(ListCoordX_tore[j+3],ListCoordY_tore[j+3],ListCoordZ_tore[j+3]);
			glColor3f(texture_tore[j+3], texture_tore[j+3], texture_tore[j+3]);
			glVertex3d(ListCoordX_tore[j+3],ListCoordY_tore[j+3],ListCoordZ_tore[j+3]);
			
			glNormal3d(ListCoordX_tore[j+2],ListCoordY_tore[j+2],ListCoordZ_tore[j+2]);
			glColor3f(texture_tore[j+2], texture_tore[j+2], texture_tore[j+2]);
			glVertex3d(ListCoordX_tore[j+2],ListCoordY_tore[j+2],ListCoordZ_tore[j+2]);
		}
		glEnd();
		j = j+2;
	}

}








