// MidiVizStarField
// Lew Hill II

#include "MidiVizStarField.h"

MidiVizStarField::MidiVizStarField(){
  init();
}

void MidiVizStarField::init(){

  for (int i = 0; i < 12; i++){
    noteSettings[i] = 0;
  }

  position[0] = 0;
  position[1] = 0;  
  position[2] = 0;

  rotation[0] = 0;
  rotation[1] = 0;  
  rotation[2] = 0;

  scale[0] = 1;
  scale[1] = 1;  
  scale[2] = 1;

  direction[0] = 0;
  direction[1] = 0;
  direction[2] = 1;

  for (int i = 0; i < NUM_STARS; i++){
    starField[i][0] = rand()/32768.0 * 10.0;
    starField[i][1] = rand()/32768.0 * 10.0;
    starField[i][2] = rand()/32768.0 * 10.0;
    starNote[i] = i%12;
  }

}

void MidiVizStarField::processMidiEvent(MidiEvent event){
  
  int note = event.getNote();
  int velocity = event.getVelocity();

  int note_index = note %12;

  noteSettings[note_index] += velocity;
  
  accel += velocity;

}

void MidiVizStarField::frame(){

  float delta_t = .02;

  for (int i = 0; i < 12; i++){
    noteSettings[i] *=.98;
  }

  float distance[3];

  distance[0] = direction[0]*vel*delta_t;
  distance[1] = direction[1]*vel*delta_t;
  distance[2] = direction[2]*vel*delta_t;


  for (int i = 0; i < NUM_STARS; i++){
    starField[i][0]+= distance[0];
    starField[i][1]+= distance[1];
    starField[i][2]+= distance[2];
    
    // perform wrap around corrections for the star arrays
    
    if (starField[i][0] > 10){

      starField[i][0] -= 10;
      starField[i][1] = rand()/32768.0 * 10.0;
      starField[i][2] = rand()/32768.0 * 10.0;

    } else if (starField[i][1] > 10){

      starField[i][0] = rand()/32768.0 * 10.0;
      starField[i][1] -= 10;
      starField[i][2] = rand()/32768.0 * 10.0;

    } else if (starField[i][2] > 10){

      starField[i][0] = rand()/32768.0 * 10.0;
      starField[i][1] = rand()/32768.0 * 10.0;
      starField[i][2] -= 10;
    }
    
    if (starField[i][0] < 0){

      starField[i][0] +=10;
      starField[i][1] = rand()/32768.0 * 10.0;
      starField[i][2] = rand()/32768.0 * 10.0;    
      
    } else if (starField[i][1] < 0){
      
      starField[i][0] = rand()/32768.0 * 10.0;
      starField[i][1] +=10;
      starField[i][2] = rand()/32768.0 * 10.0;

    } else if (starField[i][2] < 0){
      
      starField[i][0] = rand()/32768.0 * 10.0;
      starField[i][1] = rand()/32768.0 * 10.0;
      starField[i][2] +=10;    }
  }
  
  vel = accel * delta_t;
  accel *= .99;

  if (vel < .15){
    vel = .15;
  } else {
    vel *= .99;
  }


}

void MidiVizStarField::draw(){

  // frame turn rate is the sum of the note spins.

  glPointSize(2.0);

  glPushMatrix();
  glTranslatef(position[0], position[1], position[2]);
  glRotatef(rotation[2], 0.0, 0.0, 1.0); 
  glRotatef(rotation[1], 0.0, 1.0, 0.0); 
  glRotatef(rotation[0], 1.0, 0.0, 0.0); 
  glScalef(scale[0], scale[1], scale[2]);

  float *color;
  
  for (int i =0 ; i < 12; i++){
    color = color_table.getValue(starNote[i]);
    float attScale = (noteSettings[i]/127.0 * .9) + .1;
    
    attNoteColors[i][0] = color[0] * attScale;
    attNoteColors[i][1] = color[1] * attScale;
    attNoteColors[i][2] = color[2] * attScale;
  }


  glBegin(GL_POINTS);
  for (int i = 0; i < NUM_STARS; i++){
    glColor3fv(attNoteColors[starNote[i]]);
    glVertex3fv(starField[i]);
  }
  glEnd();
  

  /*
  for (int i = 0; i < NUM_STARS; i++){

    glPushMatrix();
    glTranslatef(starField[i][0], starField[i][1], starField[i][2]); 
    glColor3fv(attNoteColors[starNote[i]]);
    drawbox(-.01, .01, -.01, .01, -.01, .01, GL_QUADS);
    glPopMatrix();
    }*/
  
  glPopMatrix();
  
}

void MidiVizStarField::drawbox(GLdouble x0, GLdouble x1, GLdouble y0, GLdouble y1,
             GLdouble z0, GLdouble z1, GLenum type)
{
   static GLdouble n[6][3] = {
      {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
      {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}
   };
   static GLint faces[6][4] = {
      { 0, 1, 2, 3}, { 3, 2, 6, 7}, { 7, 6, 5, 4},
      { 4, 5, 1, 0}, { 5, 6, 2, 1}, { 7, 4, 0, 3}
   };
   GLdouble v[8][3], tmp;
   GLint i;

   if (x0 > x1)
   {
      tmp = x0; x0 = x1; x1 = tmp;
   }
   if (y0 > y1)
   {
      tmp = y0; y0 = y1; y1 = tmp;
   }
   if (z0 > z1)
   {
      tmp = z0; z0 = z1; z1 = tmp;
   }
   v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
   v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
   v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
   v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
   v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
   v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;

   for (i = 0; i < 6; i++)
   {
      glBegin(type);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][0]][0]);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][1]][0]);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][2]][0]);
         glNormal3dv(&n[i][0]);
         glVertex3dv(&v[faces[i][3]][0]);
      glEnd();
   }
}

