/* Stockage d'une lumiere spot              */
/*                                          */
/* Auteur: Nicolas JANEY                    */
/* nicolas.janey@univ-fcomte.fr             */
/* Mars 2014                                */

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

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

#include "LumiereSpot.h"
#include "LumierePonctuelle.h"
#include "Pos3D.h"
#include "Dir3D.h"
#include "Energie.h"
#include "Couleur.h"
#include "RayonLumineux.h"
#include "Scene.h"
#include "TG3D.h"

/* Constructeurs                            */
LumiereSpot::LumiereSpot(void):LumierePonctuelle() {
  d = new Dir3D(0.0,0.0,-1.0);
  ouverture = 180.0;
}

LumiereSpot::LumiereSpot(LumiereSpot *ls):LumierePonctuelle(ls) {
  d = new Dir3D(ls->d);
  ouverture = ls->ouverture;
}

/* Destructeur                              */
LumiereSpot::~LumiereSpot(void) {
  delete(d);
}

//////////////////////////////////////////////

#ifndef M_PI
#define M_PI 3.14159
#endif

/* Methode de calcul de la quantite         */
/* d'energie diffusee en un point p         */
/* de normale n et de coefficient           */
/* de diffusion kd                          */
void LumiereSpot::energieDiffusee(Energie *e,Pos3D *p,Dir3D *n,Couleur *kd) {
  if ( !on ) {
    e->r = 0.0;
    e->v = 0.0;
    e->b = 0.0;
    return; }
  if ( ouverture > 90.0 ) {
    LumierePonctuelle::energieDiffusee(e,p,n,kd);
    return; }
  Dir3D *dirm = new Dir3D(d);
  Dir3D *dm = new Dir3D(p,this->p);
  double dist = dm->normalisation();
  dirm->normalisation();
  double ps = -dirm->produitScalaire(dm);
  delete(dirm);
  if ( ps < cos(ouverture*M_PI/180.0) ) {
    e->r = 0.0;
    e->v = 0.0;
    e->b = 0.0;
    return; }
  Dir3D *nm = new Dir3D(n);
  nm->normalisation();
  ps = nm->produitScalaire(dm);
  delete(nm);
  delete(dm);
  if ( ps < 0.0 ) {
    e->r = 0.0;
    e->v = 0.0;
    e->b = 0.0; }
    else {
    e->r = intensite*c->r*ps*kd->r;
    e->v = intensite*c->v*ps*kd->v;
    e->b = intensite*c->b*ps*kd->b;
    if ( attenuation ) {
      e->r /= (dist*dist);
      e->v /= (dist*dist);
      e->b /= (dist*dist); } }
}

//////////////////////////////////////////////

int LumiereSpot::eclaire(Pos3D *p,Scene *scn,double dist) {
  Dir3D *dir = new Dir3D(p,this->p);
  dir->normalisation();
  RayonLumineux *rlo = new RayonLumineux(p,dir);
  int res = !scn->intersection(rlo,dist);
  delete(dir);
  delete(rlo);
  return(res);
}

/* Methode d'affichage texte                */
void LumiereSpot::print(void) {
  LumierePonctuelle::print();
  printf(" - ");
  d->print();
  printf(" - %lf",ouverture);
}

double LumiereSpot::distance(Pos3D *p) {
  return(p->distance(this->p));
}

void LumiereSpot::transforme(TG3D *m) {
  p->transformation(m);
  p->transformation(m);
}

void LumiereSpot::modeliseOpenGL(int num) {
  float pos[4] = { p->x,p->y,p->z,1.0F };
  glLightfv(num,GL_POSITION,pos);
  float dir[3] = { d->x,d->y,d->z };
  glLightfv(num,GL_SPOT_DIRECTION,dir);
  glLightf(num,GL_SPOT_CUTOFF,this->ouverture);
}

LumiereSpot *LumiereSpot::clone(void) {
  return(new LumiereSpot(this));
}
