#include "MidiVizGeometrizer.h"

MidiVizGeometrizer::MidiVizGeometrizer(){

        for (int i = 0; i < 127; i++){
                noteAngles[i][0] = (float) rand()/(float) 32768.0;
                noteAngles[i][1] = (float) rand()/(float) 32768.0;
        }
        
}

MidiVizGeometrizer::~MidiVizGeometrizer(){
        
}

void MidiVizGeometrizer::drawAll(){

  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]);

  drawAllVolumoids();
  
  glTranslatef(-20,0,0);
  drawAllFigures();

  glPopMatrix();

}

void MidiVizGeometrizer::drawAllVolumoids(){
        
  // draw border
  /*
  glColor3f(0.4, 0.7, 0.8);
  glBegin(GL_LINE_LOOP);
  glVertex3f(10,10,0);
  glVertex3f(-10,10,0);
  glVertex3f(-10,-10,0);
  glVertex3f(10,-10,0);
  glEnd();
  */

  glPushMatrix();
  glRotatef(rotate_angle[0], 1, 0, 0 );
  glRotatef(rotate_angle[1], 0, 1, 0 );
  glRotatef(rotate_angle[2], 0, 0, 1 );

  if (numNotes != 0){
    if (numNotes  == 1){
      drawCircle(noteValues[activeNotes[0]]);
    } else  {
      drawVolumoid();
    }
  }                 

  glPopMatrix();

}

void MidiVizGeometrizer::drawAllFigures(){
  
  // draw border
  /*
  glColor3f(0.7, 0.4, 0.8);
  glBegin(GL_LINE_LOOP);
  glVertex3f(10,10,0);
  glVertex3f(-10,10,0);
  glVertex3f(-10,-10,0);
  glVertex3f(10,-10,0);
  glEnd();
  */  
  
  glPushMatrix();
  glRotatef(rotate_angle[0], 1, 0, 0 );
  glRotatef(rotate_angle[1], 0, 1, 0 );
  glRotatef(rotate_angle[2], 0, 0, 1 );
  
  if (numNotes != 0){
    if (numNotes  == 1){
      drawCircle(noteValues[activeNotes[0]]);
    } else  {
      drawFigure();
    }
  }              
 
  glPopMatrix();
  
}

void MidiVizGeometrizer::setActiveColor(int activeAngleIndex){

  int angleIndex = activeNotes[activeAngleIndex];
  
  float* color= note_color_table.getValue(angleIndex%12);
  activeColor[0] = noteValues[angleIndex] * color[0];
  activeColor[1] = noteValues[angleIndex] * color[1];
  activeColor[2] = noteValues[angleIndex] * color[2];
  
  glColor3fv(activeColor);

}


void MidiVizGeometrizer::drawFigure(){
  
  if (numNotes == 0){
    cout << "draw figure num notes == 0 " << endl;
  }
  
  float angleStep = 360.0/numNotes;
  float radians, cosx, siny;
  
  int activeNoteIndex =0;
  int angleIndex = 0;

  if(numOctaves == 0){
    
    activeNoteIndex = 0;

    float firstX, firstY;
    
    glBegin(GL_LINE_LOOP);
    for(float angle = 0; angle< 360; angle+= angleStep){
      setActiveColor(activeNoteIndex);
      angleIndex = activeNotes[activeNoteIndex];
      radians = angle * MV_PI_RAD; 
      cosx = cos(radians) * noteValues[angleIndex] * 10;
      siny = sin(radians) * noteValues[angleIndex] * 10;
      if (angle == 0){
	firstX = cosx;
	firstY = siny;
      }
      glVertex3f(cosx, siny, 0);
      activeNoteIndex++;
    }
    setActiveColor(0);

    glVertex3f(firstX,firstY,0);


    glEnd();
    
  } else if (numOctaves == 1){
    
    activeNoteIndex = 0;
    glBegin(GL_TRIANGLE_FAN);
    glVertex3f(0,0,0);
    for(float angle = 0; angle< 360; angle+= angleStep){
      setActiveColor(activeNoteIndex);
      radians = angle * MV_PI_RAD; 
      cosx = cos(radians) * 10;
      siny = sin(radians) * 10;
      glVertex3f(cosx, siny, 0);
      activeNoteIndex++;
    }
    setActiveColor(0);
    glVertex3f(10, 0, 0);
    glEnd();
    
  } else if (numOctaves >= 2){
    
    cout << "numOctaves " << numOctaves << endl;
    
    activeNoteIndex=0;
    
    glBegin(GL_TRIANGLE_FAN);
    glNormal3f(0,0,1);
    glVertex3f(0,0,5);
    for(float angle = 0; angle< 360; angle+= angleStep){
      setActiveColor(activeNoteIndex);
      radians = angle * MV_PI_RAD; 
      cosx = cos(radians) * 10;
      siny = sin(radians) * 10;
      glNormal3f(cosx, siny,0);
      glVertex3f(cosx, siny, 0);
      activeNoteIndex++;
    }
    glNormal3f(1,0,0);
    setActiveColor(0);
    glVertex3f(10, 0, 0);
    glEnd();
        
    activeNoteIndex=0;
    
    glBegin(GL_TRIANGLE_FAN);
    glNormal3f(0,0,-1);
    glVertex3f(0,0,-5);
    for(float angle = 0; angle< 360; angle+= angleStep){
      setActiveColor(activeNoteIndex);
      radians = angle * MV_PI_RAD; 
      cosx = cos(radians) * 10;
      siny = sin(radians) * 10;
      glNormal3f(cosx, siny, 0);
      glVertex3f(cosx, siny, 0);
      activeNoteIndex++;
    }
    glNormal3f(1,0,0);
    setActiveColor(0);
    glVertex3f(10, 0, 0);
    
    glEnd();
  }
}


void MidiVizGeometrizer::drawCircle(float circle_scale){
  
  float radians, cosx, siny;
  
  setActiveColor(0);
  
  glBegin(GL_LINE_LOOP);
  
  for(float angle = 0; angle< 360; angle+= 1){
    radians = angle * MV_PI_RAD; 
    cosx = cos(radians) * 10.0 * circle_scale;
    siny = sin(radians) * 10.0 * circle_scale;
    glVertex3f(cosx, siny, 0);
  }
  
  glEnd();

}

void MidiVizGeometrizer::frame(){
  
  // total number of active notes

  rotate_angle_delta[0] *= .97;
  rotate_angle_delta[1] *= .93;
  rotate_angle_delta[2] *= .95;


  rotate_angle[0] += rotate_angle_delta[0];
  rotate_angle[1] += rotate_angle_delta[1];
  rotate_angle[2] += rotate_angle_delta[2];

  numNotes = 0;
  
  highNote = -1;
  lowNote = -1;
  
  for (int i = 0; i < 127; i++){
    if (noteValues[i] > 0){
      activeNotes[numNotes] = i;
      numNotes++;
      
      if ((i > highNote) || ( highNote  == -1)){
	highNote = i;
      }
      
      if ((i < lowNote) || (lowNote == -1)){
	lowNote = i;
      }
    }
  }
  
  numOctaves = (int)((highNote-lowNote)/12.0);
  
  /*
    cout << "num notes " << numNotes << 
    " octaves " << numOctaves << 
    " high-low"<< highNote << " " << lowNote << endl;
  */
  
  for (int i = 0; i < 3; i++){
    angle[i] += deltaAngle[i];
    deltaAngle[i] *= .98;
  }
  
  for (int i = 0; i < 128; i++){          
    noteAngles[i][0] += 4.0*deltaNoteAngles[i][0];
    noteAngles[i][1] += 4.0*deltaNoteAngles[i][1];
    
    deltaNoteAngles[i][0] *= .99;
    deltaNoteAngles[i][1] *= .94;
  } 
  
}

void MidiVizGeometrizer::processMidiEvent(MidiEvent event){
  
  int note = event.getNote();
  float intensity = event.getVelocity()/127.0;
  
  noteValues[note%128] = intensity;
  
  if (note %2 == 0){
    deltaAngle[note%3] += intensity;
  } else {
    deltaAngle[note%3] -= intensity;
  }
  
  rotate_angle_delta[0] += intensity * 2;
  rotate_angle_delta[1] += intensity * 2;
  rotate_angle_delta[2] += intensity * 2;

  if (intensity !=0){ 
    //not doing note offs
    
    if (note % 4 == 1){
      deltaNoteAngles[note%128][0] += intensity;
      deltaNoteAngles[note%128][1] += intensity;
    } else if (note % 4 == 2){
      deltaNoteAngles[note%128][0] += intensity;
      deltaNoteAngles[note%128][1] += intensity;
    } else if (note % 4 == 3){
      deltaNoteAngles[note%128][0] += intensity;
      deltaNoteAngles[note%128][1] += intensity;
    }       
  }       
}

void MidiVizGeometrizer::drawVolumoid(){
  
  float angleStep = 360.0/(float) numNotes;
  int activeNoteIndex;
  int angleIndex;
  // compute average note color
  
  if(numOctaves == 0){
    
    activeNoteIndex = 0;
    angleIndex = activeNotes[activeNoteIndex];
    
    glPushMatrix();

    glRotatef(noteAngles[angleIndex][0], 1, 0, 0);
    glRotatef(noteAngles[angleIndex][1], 0, 1, 0);

    for(float angle = 0; angle< 360; angle+= angleStep){
      setActiveColor(activeNoteIndex);
      angleIndex = activeNotes[activeNoteIndex];
      glPushMatrix();
      glRotatef(noteAngles[angleIndex][0], 0, 0, 1);
      glRotatef(noteAngles[angleIndex][1], 0, 1, 0);
      glBegin(GL_LINE_LOOP);
      glVertex3f(0,0,0);
      glVertex3f(noteValues[angleIndex]*3.0, 0, 0);
      glVertex3f(0,0,0);
      glVertex3f(0, noteValues[angleIndex]*10.0, 0);
      glEnd();
      activeNoteIndex++;
      glPopMatrix();
    }

    
    glPopMatrix();
    
  } else if (numOctaves == 1){
    
    for(activeNoteIndex = 0; activeNoteIndex < numNotes; activeNoteIndex++){
      setActiveColor(activeNoteIndex);
      angleIndex = activeNotes[activeNoteIndex];
      
      glPushMatrix();
      
      glRotatef(noteAngles[angleIndex][0], 0, 0, 1);
      glRotatef(noteAngles[angleIndex][1], 0, 1, 0);
      
      glBegin(GL_LINE_LOOP);
      glVertex3f(0,0,0);
      glVertex3f(noteValues[angleIndex]*3.0, 0, 0);
      glVertex3f(0, noteValues[angleIndex]*10.0, 0);
      glEnd();
      
      glBegin(GL_LINE_LOOP);
      glVertex3f(0,0,0);
      glVertex3f(-noteValues[angleIndex]*6.0, 0, 0);
      glVertex3f(0, -noteValues[angleIndex]*4.0, 0);
      glEnd();
      
      glPopMatrix();
    }
    
    
  } else if (numOctaves >= 2){
    
    for(activeNoteIndex = 0; activeNoteIndex < numNotes; activeNoteIndex++){
      setActiveColor(activeNoteIndex);
      angleIndex = activeNotes[activeNoteIndex];
      
      glPushMatrix();

      glRotatef(noteAngles[angleIndex][0], 0, 0, 1);
      glRotatef(noteAngles[angleIndex][1], 0, 1, 0);
      
      glBegin(GL_POLYGON);
      glNormal3f(0,0,1);
      glVertex3f(0,0,0);
      glVertex3f(noteValues[angleIndex]*3.0, 0, 0);
      glVertex3f(0, noteValues[angleIndex]*10.0, 0);
      glEnd();
      
      glBegin(GL_POLYGON);
      glNormal3f(0,0,1);
      glVertex3f(0,0,0);
      glVertex3f(-noteValues[angleIndex]*6.0, 0, 0);
      glVertex3f(0, -noteValues[angleIndex]*4.0, 0);
      glEnd();
      
      glPopMatrix();
      
    }
  }
}

