
#include <cassert>
using namespace std;

#include <GL/glut.h>



#include <d4marchdisp.h>
#include <halfspaceD3.h>

#include <gobj.h>


void d4marchdisp::eval( pt4c & P0, pt4c & P1, pt4c & P2, pt4c & P3 ) const
{
  unsigned int res(0);
  if (P0.a<cvalue)
    res += 1;
  if (P1.a<cvalue)
    res += 2;
  if (P2.a<cvalue)
    res += 4;
  if (P3.a<cvalue)
    res += 8;

  if (res==0)
    return;

  if (res==15)
    return;

  switch(res)
  {
    case 14:
    case 1:
      writeone(P0,P1,P2,P3);
      //writeone(x0,y0,z0,f0,x1,y1,z1,f1,x2,y2,z2,f2,x3,y3,z3,f3);
      break;
    case 2:
    case 13:
      writeone(P1,P0,P2,P3);
      //writeone(x1,y1,z1,f1,x0,y0,z0,f0,x2,y2,z2,f2,x3,y3,z3,f3);
      break;
    case 4:
    case 11:
      writeone(P2,P1,P0,P3);
      //writeone(x2,y2,z2,f2,x1,y1,z1,f1,x0,y0,z0,f0,x3,y3,z3,f3);
      break;
    case 8:
    case 7:
      writeone(P3,P1,P2,P0);
      //writeone(x3,y3,z3,f3,x1,y1,z1,f1,x2,y2,z2,f2,x0,y0,z0,f0);
      break;

    case 3:
    case 12:
      writetwo(P0,P1,P2,P3);
      //writetwo(x0,y0,z0,f0,x1,y1,z1,f1,x2,y2,z2,f2,x3,y3,z3,f3);
      break;

    case 5:
    case 10:
      writetwo(P0,P2,P1,P3);
      //writetwo(x0,y0,z0,f0,x2,y2,z2,f2,x1,y1,z1,f1,x3,y3,z3,f3);
      break;

    case 9:
    case 6:
      writetwo(P0,P3,P2,P1);
      //writetwo(x0,y0,z0,f0,x3,y3,z3,f3,x2,y2,z2,f2,x1,y1,z1,f1);
      break;
  }

}


void d4marchdisp::writeone( pt4c & P0, pt4c & P1, pt4c & P2, pt4c & P3 ) const
{
  float t;

  t = (cvalue-P0.a)/(P1.a-P0.a);
  float ax=P0.x+(P1.x-P0.x)*t;
  float ay=P0.y+(P1.y-P0.y)*t;
  float az=P0.z+(P1.z-P0.z)*t;

  t = (cvalue-P0.a)/(P2.a-P0.a);
  float bx=P0.x+(P2.x-P0.x)*t;
  float by=P0.y+(P2.y-P0.y)*t;
  float bz=P0.z+(P2.z-P0.z)*t;

  t = (cvalue-P0.a)/(P3.a-P0.a);
  float cx=P0.x+(P3.x-P0.x)*t;
  float cy=P0.y+(P3.y-P0.y)*t;
  float cz=P0.z+(P3.z-P0.z)*t;

  // Double sided triangles.
  // The main emphasis is not on visulization but
  // algorithm development. I have commented 
  // because graphics people will be so critical.
  // 
  // I understand and will rewrite later.

  drawtriangle(ax,ay,az,bx,by,bz,cx,cy,cz);

}


void d4marchdisp::drawtriangle
(
  float const ax,
  float const ay,
  float const az,
  float const bx,
  float const by,
  float const bz,
  float const cx,
  float const cy,
  float const cz
) const 
{
  d3halfspace<float> p( 
    point3<float>(ax,ay,az),
    point3<float>(bx,by,bz),
    point3<float>(cx,cy,cz) );
//  p.pn.normalize();
  float const nx(p.pn.x);
  float const ny(p.pn.y);
  float const nz(p.pn.z);

  gobjContainer & x = * gobjContainer::global;

  x.push_back( new gobjglBegin(GL_TRIANGLES) );

  if (winding)
  {
    x.push_back( new gobjglColor3f(1.0,0.0,0.0) );
    x.push_back( new gobjglNormal3f(nx,ny,nz) );
    x.push_back( new gobjglVertex3f(ax,ay,az) );
    x.push_back( new gobjglColor3f(0.0,1.0,0.0) );
    x.push_back( new gobjglNormal3f(nx,ny,nz) );
    x.push_back( new gobjglVertex3f(bx,by,bz) );
    x.push_back( new gobjglColor3f(0.0,0.0,1.0) );
    x.push_back( new gobjglNormal3f(nx,ny,nz) );
    x.push_back( new gobjglVertex3f(cx,cy,cz) );
  }
  else
  {
    x.push_back( new gobjglNormal3f(nx,ny,nz) );
    x.push_back( new gobjglVertex3f(ax,ay,az) );
    x.push_back( new gobjglNormal3f(nx,ny,nz) );
    x.push_back( new gobjglVertex3f(bx,by,bz) );
    x.push_back( new gobjglNormal3f(nx,ny,nz) );
    x.push_back( new gobjglVertex3f(cx,cy,cz) );
  }

  x.push_back( new gobjglEnd() );

  if (seenormal)
  {
    x.push_back( new gobjglPushAttrib(GL_CURRENT_BIT) );
    x.push_back( new gobjglPushAttrib(GL_LIGHTING) );

    x.push_back( new gobjglDisable(GL_LIGHTING) );

    x.push_back( new gobjglColor3f(0.0,0.0,1.0) );

    float const r = 0.2;
    float const x2 = (ax+bx+cx)*0.3333333333;
    float const y2 = (ay+by+cy)*0.3333333333;
    float const z2 = (az+bz+cz)*0.3333333333;
    x.push_back( new gobjglBegin(GL_LINES) );

    x.push_back( new gobjglVertex3f(x2,y2,z2) );
    x.push_back( new gobjglVertex3f
    (
      x2+nx*r,
      y2+ny*r,
      z2+nz*r
    ) );

    x.push_back( new gobjglEnd() );
  
    x.push_back( new gobjglPopAttrib() );
    x.push_back( new gobjglPopAttrib() );
  }

}

void d4marchdisp::writetwo( pt4c & P0, pt4c & P1, pt4c & P2, pt4c & P3 ) const
{
  float t;

  t = (cvalue-P0.a)/(P2.a-P0.a);
  float ax=P0.x+(P2.x-P0.x)*t;
  float ay=P0.y+(P2.y-P0.y)*t;
  float az=P0.z+(P2.z-P0.z)*t;

  t = (cvalue-P0.a)/(P3.a-P0.a);
  float bx=P0.x+(P3.x-P0.x)*t;
  float by=P0.y+(P3.y-P0.y)*t;
  float bz=P0.z+(P3.z-P0.z)*t;

  t = (cvalue-P1.a)/(P2.a-P1.a);
  float cx=P1.x+(P2.x-P1.x)*t;
  float cy=P1.y+(P2.y-P1.y)*t;
  float cz=P1.z+(P2.z-P1.z)*t;

  t = (cvalue-P1.a)/(P3.a-P1.a);
  float ex=P1.x+(P3.x-P1.x)*t;
  float ey=P1.y+(P3.x-P1.y)*t;
  float ez=P1.z+(P3.x-P1.z)*t;

  drawtriangle(ax,ay,az,cx,cy,cz,ex,ey,ez);
  drawtriangle(bx,by,bz,ax,ay,az,ex,ey,ez);
}






