#include "culooks.h"

#include <GL/glut.h>

#include <iostream>
#include <cmath>

using namespace std;

using namespace std;

int culooks::cube::allid = 0;

void culooks::cube::setLink (const int& posdir,
			     const float& red, const float& green, const float& blue, const float& alpha) {
  linkbuf[(linkbuf_active+1)%2][ posdir*4 ] = red;
  linkbuf[(linkbuf_active+1)%2][ posdir*4 + 1 ] = green;
  linkbuf[(linkbuf_active+1)%2][ posdir*4 + 2 ] = blue;
  linkbuf[(linkbuf_active+1)%2][ posdir*4 + 3 ] = alpha;
}

void culooks::cube::setPlaq (const int& posdir,
			     const float& red, const float& green, const float& blue, const float& alpha) {
  plaqbuf[(plaqbuf_active+1)%2][ posdir*4 ] = red;
  plaqbuf[(plaqbuf_active+1)%2][ posdir*4 + 1 ] = green;
  plaqbuf[(plaqbuf_active+1)%2][ posdir*4 + 2 ] = blue;
  plaqbuf[(plaqbuf_active+1)%2][ posdir*4 + 3 ] = alpha;
}

void culooks::cube::hidePlaqs()
{
  hideplaquettes = true;
}

void culooks::cube::hideLinks()
{
  hidelinks = true;
}

void culooks::cube::swapLinkBuffer()
{
  linkbuf_active = (linkbuf_active+1)%2;
  link = linkbuf[linkbuf_active];
}

void culooks::cube::swapPlaqBuffer()
{
  plaqbuf_active = (plaqbuf_active+1)%2;
  plaq = plaqbuf[plaqbuf_active];
}

void culooks::cube::draw()
{
  glMatrixMode(GL_MODELVIEW);

  /* draw frame */
  glEnable(GL_DEPTH_TEST);
  glDepthMask(GL_TRUE);
  glDisable(GL_BLEND);
  glPushMatrix();
  glScalef(zoom*1.01, zoom*1.01, zoom*1.01);
  glRotatef(alt, 1, 0, 0);
  glRotatef(az, 0, 1, 0);
  glColor4f(wireColor[0], wireColor[1], wireColor[2], wireColor[3]);
  glLineWidth(framewidth);
  glutWireCube(2);
  glPopMatrix();

  glEnable(GL_DEPTH_TEST);
  glDepthMask(GL_FALSE);
  glEnable(GL_BLEND);
  glPushMatrix();
  glScalef(zoom, zoom, zoom);
  glRotatef(alt, 1, 0, 0);
  glRotatef(az, 0, 1, 0);
  drawAll();
  glPopMatrix();

  glDepthMask(GL_TRUE);
}

void culooks::cube::drawAll()
{
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();

  glTranslatef(-1,-1,-1);

  for (int iz=0; iz<l; iz++) {
    for (int iy=0; iy<l; iy++) {
      for (int ix=0; ix<l; ix++) {
	glPushMatrix();
	glTranslatef(2.0*ix/l,2.0*iy/l,2.0*iz/l);
	glScalef(2.0/l,2.0/l,2.0/l);

	glLineWidth(linkwidth);

	/* draw links */
	if (!hidelinks) {
	  glBegin(GL_LINES);
	  glColor4f(link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 0],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 1],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 2],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 3]);
	  glVertex3f(0,0,0); glVertex3f(1,0,0);
	  glColor4f(link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 0],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 1],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 2],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 3]);
	  glVertex3f(0,0,0); glVertex3f(0,1,0);
	  glColor4f(link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 0],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 1],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 2],
		    link[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 3]);
	  glVertex3f(0,0,0); glVertex3f(0,0,1);
	  glEnd();
	}

	glLineWidth(1);

	/* draw plaquettes */
	if (!hideplaquettes) {
	  glBegin(GL_QUADS);
	  glColor4f(plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 0],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 1],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 2],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 2*4 + 3]);
	  glVertex3f(0, 0, 0); glVertex3f(1, 0, 0); glVertex3f(1, 1, 0); glVertex3f(0, 1, 0);
	  glColor4f(plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 0],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 1],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 2],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 1*4 + 3]);
	  glVertex3f(0, 0, 0); glVertex3f(1, 0, 0); glVertex3f(1, 0, 1); glVertex3f(0, 0, 1);
	  glColor4f(plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 0],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 1],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 2],
		    plaq[iz*l*l*3*4 + iy*l*3*4 + ix*3*4 + 0*4 + 3]);
	  glVertex3f(0, 0, 0); glVertex3f(0, 1, 0); glVertex3f(0, 1, 1); glVertex3f(0, 0, 1);
	  glEnd();
	}

	glPopMatrix();
      }
    }
  }
    
  glPopMatrix();
}

culooks::cube::cube(int _l)
{
  azRotSpeed = 0;

  l = _l;
  plaqbuf[0] = new float[l*l*l*3 * 4];
  plaqbuf[1] = new float[l*l*l*3 * 4];
  linkbuf[0] = new float[l*l*l*3 * 4];
  linkbuf[1] = new float[l*l*l*3 * 4];
  
  linkbuf_active = 0;
  plaqbuf_active = 0;

  link = linkbuf[0];
  plaq = plaqbuf[0];
  az = 45;
  alt = -30;
  zoom = 0.57;
  id = allid;
  allid++;

  for (int ibuf=0; ibuf<2; ibuf++)
    for (int i=0; i<l*l*l*3; i++) {
      linkbuf[ibuf][i*4+0]=1; linkbuf[ibuf][i*4+3]=0.6;
      plaqbuf[ibuf][i*4+1]=1; plaqbuf[ibuf][i*4+3]=0.2;
    }
  
  hideplaquettes = 0;
  hidelinks = 0;
}

void culooks::cube::setWireColor(const float& r, const float& g, const float& b, const float& a)
{
  wireColor[0] = r;
  wireColor[1] = g;
  wireColor[2] = b;
  wireColor[3] = a;
}

void culooks::cube::setFrameWidth(float width) {
  framewidth = width;
}

void culooks::cube::setLinkWidth(float width) {
  linkwidth = width;
}
