/***************************************************************************
                          BigSphere.cpp  -  description
                             -------------------
    begin                : Wed Jan 26 2000
    copyright            : (C) 2000 by Henrik Enqvist
    email                : henqvist@excite.com
***************************************************************************/

#include "Private.h"
#include "BigSphere.h"
#include "Polygon.h"

#define MEDIAN(v1, v2, vo) \
  vo.x = v1.x + (v2.x - v1.x)/2; \
  vo.y = v1.y + (v2.y - v1.y)/2; \
  vo.z = v1.z + (v2.z - v1.z)/2;

BigSphere::BigSphere(float fSize, int level, float fR, float fG, float fB, float fA) : Shape3D(1, 1) {
  // top vertex
  this->add(0, -1*fSize, 0, 
	    fR, fG, fB, fA,
	    0.0f, 0.0f);
  
  // front left
  this->add(-EM_SIN_45*fSize, 0, EM_SIN_45*fSize,
	    fR, fG, fB, fA,
	    0.0f, 0.0f);
  // front right
  this->add(EM_SIN_45*fSize, 0, EM_SIN_45*fSize,
	    fR, fG, fB, fA,
	    0.0f, 0.0f);
  // back left
  this->add(EM_SIN_45*fSize, 0, -EM_SIN_45*fSize,
	    fR, fG, fB, fA,
	    0.0f, 0.0f);
  // back right
  this->add(-EM_SIN_45*fSize, 0, -EM_SIN_45*fSize,
	    fR, fG, fB, fA,
	    0.0f, 0.0f);
  // bottom vertex
  this->add(0, 1*fSize, 0,
	    fR, fG, fB, fA,
	    0.0f, 0.0f);

  // TODO: Check if this causes a memory leak!!!
  vector<int> triangles;

  // push back first eight triangles
  triangles.push_back(0);
  triangles.push_back(1);
  triangles.push_back(2);

  triangles.push_back(0);
  triangles.push_back(2);
  triangles.push_back(3);

  triangles.push_back(0);
  triangles.push_back(3);
  triangles.push_back(4);

  triangles.push_back(0);
  triangles.push_back(4);
  triangles.push_back(1);

  triangles.push_back(5);
  triangles.push_back(2);
  triangles.push_back(1);

  triangles.push_back(5);
  triangles.push_back(3);
  triangles.push_back(2);

  triangles.push_back(5);
  triangles.push_back(4);
  triangles.push_back(3);

  triangles.push_back(5);
  triangles.push_back(1);
  triangles.push_back(4);

  int start = 0;
  int end = triangles.size();

  // split each triangle into three triangles
  while (level-- > 0) {
    for (int a = start; a < end; a += 3) {
      int A = triangles[a];
      int B = triangles[a+1];
      int C = triangles[a+2];
      Vertex3D vtxA = *(this->getVertex3D(triangles[a]));
      Vertex3D vtxB = *(this->getVertex3D(triangles[a+1]));
      Vertex3D vtxC = *(this->getVertex3D(triangles[a+2]));
			
      // new vertices
      Vertex3D vtxD, vtxE, vtxF;
			
      MEDIAN(vtxA, vtxB, vtxD);
      MEDIAN(vtxB, vtxC, vtxE);
      MEDIAN(vtxC, vtxA, vtxF);
			
      // move vertices out to the sphere surface
      EMath::normalizeVector(vtxD);
      EMath::normalizeVector(vtxE);
      EMath::normalizeVector(vtxF);
      EMath::scaleVector(vtxD, fSize);
      EMath::scaleVector(vtxE, fSize);
      EMath::scaleVector(vtxF, fSize);
			
      EM_COUT("BigSphere::BigSphere() vtxA " << vtxA.x <<" "<< vtxA.y <<" "<< vtxA.z, 0);
      EM_COUT("BigSphere::BigSphere() vtxB " << vtxB.x <<" "<< vtxB.y <<" "<< vtxB.z, 0);
      EM_COUT("BigSphere::BigSphere() vtxC " << vtxC.x <<" "<< vtxC.y <<" "<< vtxC.z, 0);
			
      EM_COUT("BigSphere::BigSphere() vtxD " << vtxD.x <<" "<< vtxD.y <<" "<< vtxD.z, 0);
      EM_COUT("BigSphere::BigSphere() vtxE " << vtxE.x <<" "<< vtxE.y <<" "<< vtxE.z, 0);
      EM_COUT("BigSphere::BigSphere() vtxF " << vtxF.x <<" "<< vtxF.y <<" "<< vtxF.z, 0);
			
      int D, E, F;
      if ((D = this->find(vtxD.x, vtxD.y, vtxD.z, 0.001)) == -1) {
	D = this->add(vtxD.x, vtxD.y, vtxD.z,
		      fR, fG, fB, fA,	0.0f, 0.0f);
      }
      if ((E = this->find(vtxE.x, vtxE.y, vtxE.z, 0.001)) == -1) {
	E = this->add(vtxE.x, vtxE.y, vtxE.z,
		      fR, fG, fB, fA,	0.0f, 0.0f);
      }
      if ((F = this->find(vtxF.x, vtxF.y, vtxF.z, 0.001)) == -1) {
	F = this->add(vtxF.x, vtxF.y, vtxF.z,
		      fR, fG, fB, fA,	0.0f, 0.0f);
      }
			
      // push back four new triangles
      triangles.push_back(A);
      triangles.push_back(D);
      triangles.push_back(F);
			
      triangles.push_back(D);
      triangles.push_back(B);
      triangles.push_back(E);
			
      triangles.push_back(F);
      triangles.push_back(E);
      triangles.push_back(C);
			
      triangles.push_back(D);
      triangles.push_back(E);
      triangles.push_back(F);
    }
    // discard the old triangles
    start = end;
    end = triangles.size();
  }

  // add the triangles to the shape
  for (int a = start; a < end; a +=  3) {
    Polygon3D * p;
    p = new Polygon3D(this, 3);
    p->add(triangles[a]);
    p->add(triangles[a+1]);
    p->add(triangles[a+2]);
    if (fA < 0.95f) {
      p->setProperty(EM_POLY_TRANS);
    }
    this->add(p);
  }
  if (fA < 0.95f) {
    this->setProperty(EM_SHAPE3D_USE_TRANS);
  }

  this->countNormals();
}
