// MidiVizDotPlot
// Lew Hill II

#include "MidiVizDotPlot.h"

MidiVizDotPlot::MidiVizDotPlot(){
  init();
}

void MidiVizDotPlot::init(){

  newpoints = 1;
  extents = 2;
  int i;
 
  for (i = 0; i< 12; i++){
    noteValue[i] = 0;
  }
  
}

void MidiVizDotPlot::initAnchors(){
  numPoints = 0;
  bisection = 0.5;
  
  initpoints = 12;
  
  // setup first n active points.
  
  int stepSize = 360/initpoints;
  
  float radians;
  float radius;
  int i;
  for (i =0; i < initpoints; i+= 1){
    
    radius = extents*((float)noteValue[i]/127.0);
    radians = i * (stepSize) * MV_PI_RAD;

    points[i][0] = cos(radians)*radius;
    points[i][1] = sin(radians)*radius;
    points[i][2] = (64-noteValue[i]) * extents/64.0;
    pointNotes[numPoints] = i;
    numPoints++;
  }
  
  lastPoint[0] = points[initpoints][0];
  lastPoint[1] = points[initpoints][1];
  lastPoint[2] = points[initpoints][2];
}


void MidiVizDotPlot::processMidiEvent(MidiEvent event){
  
  int note = event.getNote();
  int velocity = event.getVelocity();
  
  int note_index = note %12;
  noteValue[note_index] = velocity;

  //  delta_rotation[note_index%3] += (float)velocity/60.0;

  newpoints = 1;
}


void MidiVizDotPlot::generateDotPlot(){
  
  float newPos[3];  
  
  initAnchors();

  int anchorpoint;
  
  while (numPoints < MAX_NUM_POINTS){
    
    // select a point at random
    
    anchorpoint = rand() % (initpoints);
        
    newPos[0] = points[anchorpoint][0]*bisection + 
      points[numPoints][0]*(1-bisection);
    
    newPos[1] = points[anchorpoint][1]*bisection +
      points[numPoints][1]*(1-bisection);
    
    newPos[2] = points[anchorpoint][2]*bisection +
      points[numPoints][2]*(1-bisection); 
    
    numPoints++;
    
    points[numPoints][0] = newPos[0];
    points[numPoints][1] = newPos[1];
    points[numPoints][2] = newPos[2];
    pointNotes[numPoints] = anchorpoint;
  }
}


void MidiVizDotPlot::frame(){

  if (newpoints){
    generateDotPlot();
    newpoints = 0;
  }

  /*  
  rotation[0] += delta_rotation[0] + .02;
  rotation[1] += delta_rotation[1] + .02;
  rotation[2] += delta_rotation[2] + .02;
  
  delta_rotation[0] *=.80;
  delta_rotation[1] *=.80;
  delta_rotation[2] *=.80;
  */
}

void MidiVizDotPlot::draw(){

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

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

  glColor3f(1.0, 1.0, 1.0);

  glPushMatrix();
  glPointSize(2.0);

  glBegin(GL_LINES);
  for (int i = 0; i < initpoints; i++){
    glColor3fv(color_table.getValue(pointNotes[i]));
    glVertex3f(0,0,0);
    glVertex3f(points[i][0], points[i][1], points[i][2]);
  }
  glEnd();

  glBegin(GL_LINE_LOOP);
  for (int i = 0; i < initpoints; i++){
    glColor3fv(color_table.getValue(pointNotes[i]));
    glVertex3f(points[i][0], points[i][1], points[i][2]);
  }
  glEnd();

  glBegin(GL_POINTS);
  int i;
  for (i = 0; i < numPoints; i++){
    glColor3fv(color_table.getValue(pointNotes[i]));
    glVertex3f(points[i][0], points[i][1], points[i][2]);
  }
  glEnd();
  glPopMatrix();
  
  glColor3f(0.1, 0.1, 0.1);

  /*
  glBegin(GL_LINE_LOOP);
  glVertex3i(extents, extents, extents);
  glVertex3i(extents,-extents,extents);
  glVertex3i(-extents,-extents, extents);
  glVertex3i(-extents, extents, extents);
  glEnd();

  glBegin(GL_LINE_LOOP);
  glVertex3i(extents, extents,-extents);
  glVertex3i(extents,-extents,-extents);
  glVertex3i(-extents,-extents,-extents);
  glVertex3i(-extents, extents, -extents);
  glEnd();

  glBegin(GL_LINES);
  glVertex3i(extents,extents,extents);
  glVertex3i(extents,extents,-extents);

  glVertex3i(extents,-extents,extents);
  glVertex3i(extents,-extents,-extents);

  glVertex3i(-extents, -extents, extents);
  glVertex3i(-extents, -extents,-extents);

  glVertex3i(-extents, extents, extents);
  glVertex3i(-extents, extents, -extents);
  glEnd();

  */

  glPopMatrix();  
}

void MidiVizDotPlot::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();
   }
}

