// LewHill2
// MIDIVIZ WALL

#include "MidiVizWall.h"

MidiVizWall::MidiVizWall(){

  for (int i =0; i < WALL_HEIGHT; i++){
    for (int j =0; j < WALL_WIDTH; j++){
      pointsA[i][j][0] = (GLubyte) 0;
      pointsA[i][j][1] = (GLubyte) 0;
      pointsA[i][j][2] = (GLubyte) 0;

      pointsB[i][j][0] = (GLubyte) 0;
      pointsB[i][j][1] = (GLubyte) 0;
      pointsB[i][j][2] = (GLubyte) 0;
     }
  }

  init();
}

void MidiVizWall::init(){
  drawPoints = 0;
}
  
void MidiVizWall::contextInit(){
  if (!(contextData->firstTime)) { 
    contextData->wallTextureIndex = glGenLists(1);
    contextData->firstTime = false;
  }
  
}

void MidiVizWall::generateTexture(){
  
  glDeleteLists(contextData->wallTextureIndex, 0);
  
  glNewList(contextData->wallTextureIndex, GL_COMPILE);
  glEnable(GL_TEXTURE_2D);
  
  if (drawPoints == 0){
    
    glTexImage2D(GL_TEXTURE_2D, 0, 3, WALL_WIDTH, WALL_HEIGHT, 
		 0, GL_RGB, GL_UNSIGNED_BYTE, &pointsA[0][0][0]); 
    drawPoints = 1;

  }else {
    
    glTexImage2D(GL_TEXTURE_2D, 0, 3, WALL_WIDTH, WALL_HEIGHT, 
		 0, GL_RGB, GL_UNSIGNED_BYTE, &pointsB[0][0][0]); 
    drawPoints = 0;

  }
  
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  glColor4f(1.0, 1.0, 1.0, 1.0);
  glEndList();
  
}

void MidiVizWall::draw(){

  generateTexture();

  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);
  glCallList(contextData->wallTextureIndex);
  glBegin(GL_QUADS);
  glNormal3f(0,0,1);
  glTexCoord2i(0, 0); glVertex3f(-5, -5, 0);
  glTexCoord2i(1, 0); glVertex3f(5, -5, 0);  
  glTexCoord2i(1, 1); glVertex3f(5, 5, 0);  
  glTexCoord2i(0, 1); glVertex3f(-5, 5, 0);
  glEnd();
  glDisable(GL_TEXTURE_2D); 

  glPopMatrix();
  
}

void MidiVizWall::frame(){

  // 1 2 3 
  // 4 5 6

  // cell 5 gets color evenly from 1 2 3

  int color_totals[3];

  for (int i =0; i < WALL_HEIGHT; i++){
    
    int up_i = i+1;
    if (up_i > WALL_HEIGHT){
      up_i -= WALL_HEIGHT;
    }
    
    int down_i =i-1;
    if (down_i < 0){
      down_i += WALL_HEIGHT;
    }
    
    for (int j =0; j < WALL_WIDTH; j++){
      
      int up_j = j+1;
      if (up_j > WALL_WIDTH){
	up_j -= WALL_WIDTH;
      }   
      
      int down_j = j-1;
      if (down_j < 0){
	down_j += WALL_WIDTH;
      }
      
      for (int k =0; k < 3; k++){
	
	if(drawPoints==0){
	  
	  color_totals[k] = 
	    pointsA[up_i][j][k] + 
	    pointsA[down_i][j][k] + 
	    pointsA[i][up_j][k] + 
	    pointsA[i][down_j][k]+
	    pointsA[i][j][k]*4;
	  pointsB[i][j][k] = (GLubyte) ((int) color_totals[k]/(int)8.3);

	  if (pointsA[i][j][k] > 0){
	    pointsA[i][j][k] -= 0x1;
	  }
	} else {
	  color_totals[k] = 
	    pointsB[up_i][j][k] + 
	    pointsB[down_i][j][k] + 
	    pointsB[i][up_j][k] + 
	    pointsB[i][down_j][k]+
	    pointsB[i][j][k]*4;
	  pointsA[i][j][k] = (GLubyte) ((int) color_totals[k]/(int)8.3);

	  if (pointsB[i][j][k] > 0){
	    pointsB[i][j][k] -= 0x1;
	  }

	}
      }
    }
  }
}

void MidiVizWall::processMidiEvent(MidiEvent event){
  

  int note = event.getNote();
  int velocity = event.getVelocity();
  
  int x_cdt, y_cdt;

  GLubyte color_r, color_g, color_b;
  
  GLubyte* colors = color_table.getByteValue(note %12);
  color_r = colors[0];
  color_g = colors[1];
  color_b = colors[2];
  
  if (velocity > 0){
    
    for (int i =0; i < WALL_HEIGHT * WALL_WIDTH; i+= (128-velocity)){
      
      //      int x_cdt = (int) ((rand()/32768.0) * WALL_HEIGHT);
      // int y_cdt = (int) ((rand()/32768.0) * WALL_WIDTH);

      x_cdt = (int)(((float) WALL_HEIGHT * rand()/RAND_MAX));
      y_cdt = (int)(((float)WALL_WIDTH * rand()/RAND_MAX));
      
      //      cout << "LS" << x_cdt << " "  << y_cdt << endl;
      
      if (drawPoints ==0){
	pointsA[x_cdt][y_cdt][0] = color_r;
	pointsA[x_cdt][y_cdt][1] = color_g;    
	pointsA[x_cdt][y_cdt][2] = color_b;
      } else {
	pointsB[x_cdt][y_cdt][0] = color_r;
	pointsB[x_cdt][y_cdt][1] = color_g;    
	pointsB[x_cdt][y_cdt][2] = color_b;
      }
    }
  }   
 
}

