/* Objets geometriques modelises par facettes   */
/*  - Cube                                      */
/*  - Cylindre                                  */
/*                                              */
/* Auteur: Nicolas JANEY                        */
/* nicolas.janey@univ-fcomte.fr                 */
/* Fevrier 2023                                 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include <GL/gl.h>
#include <GL/glu.h>

#include "ObjetsGeometriques.h"

#ifndef M_PI
#define M_PI 3.14159
#endif

static void face(float tx,float ty, int n,int m) {
  float dy = ty/m;
  float dx = tx/n;
  glPushMatrix();
  glNormal3f(0.0F,0.0F,1.0F);
  glTranslatef(-tx/2.0F,-ty/2.0F,0.0F);
  for ( int l = 0 ; l < m ; l++) {
    float yf = l * dy;
    float yi = yf + dy;
    float x = 0.0F;
    glBegin(GL_QUAD_STRIP);
    for ( int c = 0 ; c <= n ; c++ ) {
      glVertex2f(x,yi);
      glVertex2f(x,yf);
      x += dx; }
    glEnd(); }
  glPopMatrix();
}

void mySolidCube(double ct,int n) {
  glPushMatrix();
  glPushMatrix();
  glTranslatef(0.0F,0.0F,(GLfloat) ct/2.0F);
  face((float) ct,(float) ct,n,n);
  glPopMatrix();
  glPushMatrix();
  glRotatef(90.0F,0.0F,1.0F,0.0f);
  glTranslatef(0.0F,0.0F,(GLfloat) ct/2.0F);
  face((float) ct,(float) ct,n,n);
  glPopMatrix();
  glPushMatrix();
  glRotatef(180.0F,0.0F,1.0F,0.0f);
  glTranslatef(0.0F,0.0F,(GLfloat) ct/2.0F);
  face((float) ct,(float) ct,n,n);
  glPopMatrix();
  glPushMatrix();
  glRotatef(270.0F,0.0F,1.0F,0.0f);
  glTranslatef(0.0F,0.0F,(GLfloat) ct/2.0F);
  face((float) ct,(float) ct,n,n);
  glPopMatrix();
  glPushMatrix();
  glRotatef(90.0F,1.0F,0.0F,0.0f);
  glTranslatef(0.0F,0.0F,(GLfloat) ct/2.0F);
  face((float) ct,(float) ct,n,n);
  glPopMatrix();
  glPushMatrix();
  glRotatef(-90.0F,1.0F,0.0F,0.0f);
  glTranslatef(0.0F,0.0F,(GLfloat) ct/2.0F);
  face((float) ct,(float) ct,n,n);
  glPopMatrix();
  glPopMatrix();
}

#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif

void mySolidSphere(double rayon,int ns,int nl) {
  for ( int i = 0 ; i < nl ; i++ ) {
    float a1 =(float) (-M_PI/2.0F + i*M_PI/nl) ;
    float a2 = a1 + (float) (M_PI/nl) ;
    float cs1 =(float) cos(a1);
    float cs2 =(float) cos(a2);
    float sn1 =(float) sin(a1);
    float sn2 =(float) sin(a2);
    float t1 = 1.0F-(float) i/nl;
    float t2 = 1.0F-(float) (i+1)/nl;
    glBegin(GL_QUAD_STRIP);
    for ( int j = 0 ; j <= ns ; j++ ) {
      float a =(float) (j*2*M_PI/ns);
      float x1 =(float) (cs1*cos(a));
      float z1 =(float) (cs1*sin(a));
      float x2 =(float) (cs2*cos(a));
      float z2 =(float) (cs2*sin(a));
      float s = 1.0F-(float) j/ns;
      glNormal3f(x1,sn1,z1);
      glVertex3f((float) (rayon*x1),(float) (rayon*sn1),(float) (rayon*z1));
      glNormal3f(x2,sn2,z2);
      glVertex3f((float) (rayon*x2),(float) (rayon*sn2),(float) (rayon*z2)); }
    glEnd(); }
}

void mySolidCylindre(double hauteur,double rayon,int ns,int nl) {
  GLboolean nm = glIsEnabled(GL_NORMALIZE);
  if ( !nm )
    glEnable(GL_NORMALIZE);
  float normale[4];
  glGetFloatv(GL_CURRENT_NORMAL,normale);
  glPushMatrix();
  for ( int j = 0 ; j < nl ; j++ ) {
    float hi =(float) (hauteur/2-j*hauteur/nl);
    float hf =(float) (hi-hauteur/nl);
    glBegin(GL_QUAD_STRIP);
    for( int i = 0 ; i <= ns ; i++ ) {
      float a =(float) ((2*M_PI*i)/ns);
      float cs =(float) cos(a);
      float sn =(float) -sin(a);
      glNormal3f(cs,0.0F,sn);
      float x =(float) (rayon*cs);
      float z =(float) (rayon*sn);
      glVertex3f(x,hi,z);
      glVertex3f(x,hf,z); }
    glEnd(); }
  glPopMatrix();
  glNormal3f(normale[0],normale[1],normale[2]);
  if ( !nm )
    glDisable(GL_NORMALIZE);
}

void mySolidCylindre(double hauteur,double rayon,int ns,int nl,int bases) {
  mySolidCylindre(hauteur,rayon,ns,nl);
  GLboolean nm = glIsEnabled(GL_NORMALIZE);
  if ( !nm )
    glEnable(GL_NORMALIZE);
  float normale[4];
  glGetFloatv(GL_CURRENT_NORMAL,normale);
  glPushMatrix();
  if ( bases ) {
    glBegin(GL_POLYGON);
    glNormal3f(0.0F,1.0F,0.0F);
    for( int i = 0 ; i < ns ; i++ ) {
      float a =(float) ((2*M_PI*i)/ns);
      float cs =(float) cos(a);
      float sn =(float) -sin(a);
      float x =(float) (rayon*cs);
      float z =(float) (rayon*sn);
      glVertex3f(x,(float) (hauteur/2.0F),z); }
    glEnd();
    glBegin(GL_POLYGON);
    glNormal3f(0.0F,-1.0F,0.0F);
    for( int i = 0 ; i < ns ; i++ ) {
      float a =(float) ((2*M_PI*i)/ns);
      float cs =(float) cos(a);
      float sn =(float) sin(a);
      float x =(float) (rayon*cs);
      float z =(float) (rayon*sn);
      glVertex3f(x,(float) (-hauteur/2.0F),z); }
    glEnd(); }
  glPopMatrix();
  glNormal3f(normale[0],normale[1],normale[2]);
  if ( !nm )
    glDisable(GL_NORMALIZE);
}

int informationSolidCube(double ct,int n,typeInfo type) {
  switch (type) {
    case NOMBRE_VERTICES :
      return n*2*(n+1)*6;
      break;
    case NOMBRE_FACETTES_TRIANGULAIRES :
      return 0;
      break;
    case NOMBRE_TOTAL_FACETTES :
    case NOMBRE_FACETTES_QUADRANGULAIRES :
      return 6*n*n;
      break;
    default :
      return -1;
      break; }
}

int informationSolidSphere(double rayon,int ns,int nl,typeInfo type) {
  switch (type) {
    case NOMBRE_VERTICES :
      return nl*2*(ns+1);
      break;
    case NOMBRE_FACETTES_TRIANGULAIRES :
      return 0;
      break;
    case NOMBRE_TOTAL_FACETTES :
    case NOMBRE_FACETTES_QUADRANGULAIRES :
      return ns*nl;
      break;
    default :
      return -1;
      break; }
}

int informationSolidCylindre(double hauteur,double rayon,int ns,int nl,typeInfo type) {
 switch (type) {
    case NOMBRE_VERTICES :
      return nl*2*(ns+1)+2*ns;
      break;
    case NOMBRE_FACETTES_TRIANGULAIRES :
      return 0;
      break;
    case NOMBRE_TOTAL_FACETTES :
      return ns*nl+2;
      break;
    case NOMBRE_FACETTES_QUADRANGULAIRES :
      return ns*nl;
      break;
    default :
      return -1;
      break; }
}

int informationSolidCylindre(double hauteur,double rayon,int ns,int nl,int bases,typeInfo type) {
  int n = informationSolidCylindre(hauteur,rayon,ns,nl,type);
  return n;
}