#include "ZGo.h"



//---- ZGo3DOBJECT -----------------------------------------------------------//

//---- ZGo3DOBJECT

ZGo3DOBJECT::ZGo3DOBJECT(ZGo *zgo)
{
  this->zgo = zgo;

  trans = new ZGoMATRIX(zgo);

  points = 0;
  point = new double[4096][3];

  faces = 0;
  face = new int[4096][3];

  objects = 0;
  object = new ZGo3DOBJECT *[256];
}



//---- clear

void ZGo3DOBJECT::clear()
{
  for(int i=0; i<objects; i++) delete object[i];

  points = 0;
  faces = 0;
  objects = 0;
}



//---- addFace

void ZGo3DOBJECT::addFace(int p1, int p2, int p3)
{
  face[faces][0] = p1;
  face[faces][1] = p2;
  face[faces][2] = p3;
  faces ++;
}



//---- addFace

void ZGo3DOBJECT::addFace(int p1, int p2, int p3, int p4)
{
  face[faces][0] = p1;
  face[faces][1] = p2;
  face[faces][2] = p3;
  faces ++;
  face[faces][0] = p3;
  face[faces][1] = p4;
  face[faces][2] = p1;
  faces ++;
}



//---- addPoint

void ZGo3DOBJECT::addPoint(double x, double y, double z)
{
  point[points][0] = x;
  point[points][1] = y;
  point[points][2] = z;
  points ++;
}



//---- addObject

void ZGo3DOBJECT::addObject(ZGo3DOBJECT *obj)
{
  object[objects] = obj;
  objects ++;
}



//---- transform

void ZGo3DOBJECT::transform(ZGoMATRIX *m)
{
  trans->setMatrix(m);
}



//---- render

void ZGo3DOBJECT::render(ZGoCAMERA *camera, ZGoIMAGE *im, ZGoIMAGE *zbuf)
{
  render(camera, NULL, im, zbuf);
}



//---- render

void ZGo3DOBJECT::render(ZGoCAMERA *camera, ZGoMATRIX *m, ZGoIMAGE *im, ZGoIMAGE *zbuf)
{
  int i;

  //- Set up matrix for this object

  ZGoMATRIX *objm = new ZGoMATRIX(zgo, trans, m);

  //- Transform points & calculate screen points

  double (*tpoint)[3] = new double[points][3];

  camera->screenSpace(im, objm, point, tpoint, points);

  //- Render faces

  for(i=0; i<faces; i++)
  {
    int p1 = face[i][0];
    int p2 = face[i][1];
    int p3 = face[i][2];

    if(tpoint[p1][2] > 0 && tpoint[p2][2] > 0 && tpoint[p3][2] > 0)
    {
      im->zbufTri(
        zbuf,
        tpoint[p1],
        tpoint[p2],
        tpoint[p3],
        i*0x89387278 + 0x17863267*(int)this
      );
    }
  }

  //- Render points

  for(i=0; i<points; i++)
  {
    double x = tpoint[i][0];
    double y = tpoint[i][1];
//    im->fillRect(x-1, y-2, x+1, y+2, 0x00000000);
//    im->fillRect(x-2, y-1, x+2, y+1, 0x00000000);
//    im->fillRect(x-1, y-1, x+1, y+1, 0x0000FF00);
//	im->putPixel((int)x, (int)y, 0x00FFFF00);
  }

  //- Render sub-objects

  for(i=0; i<objects; i++)
  {
    object[i]->render(camera, objm, im, zbuf);
  }

  //- Done

  delete tpoint;
  delete objm;
}



//---- cube

void ZGo3DOBJECT::cube()
{
  clear();

  points = 8;
  faces = 12;

  point[0][0] =  1; point[0][1] =  1; point[0][2] =  1;
  point[1][0] =  1; point[1][1] =  1; point[1][2] = -1;
  point[2][0] = -1; point[2][1] =  1; point[2][2] = -1;
  point[3][0] = -1; point[3][1] =  1; point[3][2] =  1;
  point[4][0] =  1; point[4][1] = -1; point[4][2] =  1;
  point[5][0] =  1; point[5][1] = -1; point[5][2] = -1;
  point[6][0] = -1; point[6][1] = -1; point[6][2] = -1;
  point[7][0] = -1; point[7][1] = -1; point[7][2] =  1;

  face[ 0][0] = 0; face[ 0][1] = 1; face[ 0][2] = 2;
  face[ 1][0] = 2; face[ 1][1] = 3; face[ 1][2] = 0;
  face[ 2][0] = 5; face[ 2][1] = 6; face[ 2][2] = 2;
  face[ 3][0] = 2; face[ 3][1] = 1; face[ 3][2] = 5;
  face[ 4][0] = 6; face[ 4][1] = 7; face[ 4][2] = 3;
  face[ 5][0] = 3; face[ 5][1] = 2; face[ 5][2] = 6;
  face[ 6][0] = 7; face[ 6][1] = 6; face[ 6][2] = 5;
  face[ 7][0] = 5; face[ 7][1] = 4; face[ 7][2] = 7;
  face[ 8][0] = 0; face[ 8][1] = 3; face[ 8][2] = 7;
  face[ 9][0] = 7; face[ 9][1] = 4; face[ 9][2] = 0;
  face[10][0] = 0; face[10][1] = 4; face[10][2] = 5;
  face[11][0] = 5; face[11][1] = 1; face[11][2] = 0;
}



//---- plane

void ZGo3DOBJECT::plane(float scale)
{
  int i, j;

  clear();

  for(j=0; j<=10; j++) for(i=0; i<=10; i++)
  {
    addPoint( (i-5) * scale, 0, (j-5) * scale);
    if(i < 10 && j < 10) addFace(i+j*11, i+j*11 + 1, i+j*11 + 12, i+j*11 + 11);
  }
}



//---- pqtorus

void ZGo3DOBJECT::pqtorus(int p, int q, double poffset)
{
  clear();

  int asteps = 120;
  int bsteps = 12;

  double a, r;

  for(int i=0; i<asteps; i++)
  {
    //  Get previous, current and next points

    a = (i+asteps*poffset)*3.14159*2/asteps; r = 0.25 * (4 + sin(q*a));
    double x1 = r * cos(p*a);
    double y1 = 0.25 * r * cos(q*a);
    double z1 = r * sin(p*a);

    a = (i+asteps*poffset+0.1)*3.14159*2/asteps; r = 0.25 * (4 + sin(q*a));
    double x2 = r * cos(p*a);
    double y2 = 0.25 * r * cos(q*a);
    double z2 = r * sin(p*a);

    //  Radial points

    double tx = x2-x1, ty = y2-y1, tz = z2-z1;
    double nx = x2+x1, ny = y2+y1, nz = z2+z1;
    double bx = ty*nz-tz*ny, by = tz*nx-tx*nz, bz = tx*ny-ty*nx;
           nx = by*tz-bz*ty; ny = bz*tx-bx*tz; nz = bx*ty-by*tx;

    double n = 1.0 / sqrt(nx*nx + ny*ny + nz*nz);
    nx *= n; ny *= n; nz *= n;

    double b = 1.0 / sqrt(bx*bx + by*by + bz*bz);
    bx *= b; by *= b; bz *= b;

    for(int j=0; j<bsteps; j++)
    {
      double rr = 0.2;//0.15 + 0.1*sin(i*3.14159*2*q/asteps); // + 0.1*sin(j*3.14159*2*4/bsteps + i*3.14159*2*7/asteps);

      if(rr < 0.08) rr = 0.16-rr;
      double s = sin(j*3.14159*2/bsteps);
      double c = cos(j*3.14159*2/bsteps);

      double x = rr*sin(j*3.15159*2/bsteps);
      double y = rr*cos(j*3.15159*2/bsteps);

      point[points][0] = x * nx + y * bx + x1;
      point[points][1] = x * ny + y * by + y1;
      point[points][2] = x * nz + y * bz + z1;
//      normal[points][0] = s * nx + c * bx;
//      normal[points][1] = s * ny + c * by;
//      normal[points][2] = s * nz + c * bz;
      points ++;

      face[faces][0] = i*bsteps + j;
      face[faces][1] = ((i+1)%asteps)*bsteps + j;
      face[faces][2] = ((i+1)%asteps)*bsteps + (j + 1)%bsteps;
      faces ++;

      face[faces][0] = ((i+1)%asteps)*bsteps + (j + 1)%bsteps;
      face[faces][1] = i*bsteps + (j + 1)%bsteps;
      face[faces][2] = i*bsteps + j;
      faces ++;
    }

  }
}



//---- end of file -----------------------------------------------------------//
