#include "TextureSlicer.h"
#include <stdio.h>
#define EPSILON (0.000001)


const int TextureSlicer::m_pEdgeList[8][12] = {
		{ 0,1,5,6,   4,8,11,9,  3,7,2,10 }, // v0 is front
		{ 0,4,3,11,  1,2,6,7,   5,9,8,10 }, // v1 is front
		{ 1,5,0,8,   2,3,7,4,   6,10,9,11}, // v2 is front
		{ 7,11,10,8, 2,6,1,9,   3,0,4,5  }, // v3 is front
		{ 8,5,9,1,   11,10,7,6, 4,3,0,2  }, // v4 is front
		{ 9,6,10,2,  8,11,4,7,  5,0,1,3  }, // v5 is front
		{ 9,8,5,4,   6,1,2,0,   10,7,11,3}, // v6 is front
		{ 10,9,6,5,  7,2,3,1,   11,4,8,0 }  // v7 is front
	}; 

void TextureSlicer::getRayBoxIntersection(CVector rayDirn, double& nearDist, double& farDist, int& nearIdx, int& farIdx) {
		farIdx = 0; //initialize to 0
		farDist = rayDirn * m_pVertices[farIdx];
		nearDist = farDist;
		nearIdx = farIdx;
		for(int i = 1; i < 8; ++i) {
			double dist = rayDirn * m_pVertices[i];
			if ( dist > farDist) {
				farDist = dist;
				farIdx = i;
			}
			if ( dist < nearDist) {
				nearDist = dist;
				nearIdx = i;
			}
		}
		nearDist += EPSILON;
		farDist -= EPSILON;
}

TextureSlicer::TextureSlicer() {
	m_StepSize = 0.0005; 

	//back face counter clockwise
	m_pVertices[0] = CVector(0.0,0.0,0.0, 1.0,  0.0, 0.0, 0.0);
	m_pVertices[1] = CVector( 1.0,0.0,0.0, 1.0,  1.0, 0.0, 0.0);
	m_pVertices[2] = CVector( 1.0, 1.0,0.0, 1.0,  1.0, 1.0, 0.0);
	m_pVertices[3] = CVector(0.0, 1.0,0.0, 1.0,  0.0, 1.0, 0.0);
								
	//front face counter clockwise
	m_pVertices[4] = CVector(0.0,0.0, 1.0, 1.0,  0.0, 0.0, 1.0);
	m_pVertices[5] = CVector( 1.0,0.0, 1.0, 1.0,  1.0, 0.0, 1.0);
	m_pVertices[6] = CVector( 1.0, 1.0, 1.0, 1.0,  1.0, 1.0, 1.0);
	m_pVertices[7] = CVector(0.0, 1.0, 1.0, 1.0,  0.0, 1.0, 1.0);

	//We have 12 edges for our cube, 4 on frontface, 4 on backface, 4 connecting front-back
	m_pEdges[0]  = Edge(0,1);
	m_pEdges[1]  = Edge(1,2);
	m_pEdges[2]  = Edge(2,3);
	m_pEdges[3]  = Edge(3,0);
	m_pEdges[4]  = Edge(0,4);
	m_pEdges[5]  = Edge(1,5);
	m_pEdges[6]  = Edge(2,6);
	m_pEdges[7]  = Edge(3,7);
	m_pEdges[8]  = Edge(4,5);
	m_pEdges[9]  = Edge(5,6);
	m_pEdges[10] = Edge(6,7);
	m_pEdges[11] = Edge(7,4);

}

TextureSlicer::~TextureSlicer() {
}

//Credits : Kniss et al, Real time Volume Graphics
void TextureSlicer::render(Data* theData) {
	glEnable(theData->getTarget());
	glBindTexture(theData->getTarget(), theData->getCurrentTexture());

	glTranslatef(-0.5f,-0.5f,-0.5f);	
	int i;
	
	//get the near and far intersection and vertex Index
	float pMatrix[16];
	glGetFloatv(GL_MODELVIEW_MATRIX,pMatrix);
	//this is the inverse of z rotation
	CVector viewVec(-pMatrix[2],-pMatrix[6],-pMatrix[10],0.0);
	double nearDist, farDist;
	int nearIdx, farIdx;
	getRayBoxIntersection(viewVec, nearDist, farDist, nearIdx, farIdx);
	int numSlices = (farDist-nearDist)/m_StepSize;

	glLineWidth(2.0);
	glBegin(GL_LINES);
	{
		glColor3f(1.0,1.0,1.0);		
		for(int i = 0; i < 12; i++) {
			glVertex4dv(&(m_pVertices[m_pEdges[m_pEdgeList[farIdx][i]].nV1])[0]);
			glVertex4dv(&(m_pVertices[m_pEdges[m_pEdgeList[farIdx][i]].nV2])[0]);
		}

	}
	glEnd();

	glDisable(GL_LIGHTING);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	
	CVector vecStart[12];
	CVector vecDir[12];
	float lambda[12];
	float lambda_inc[12];
	double denom;

	double dPlaneDist    =  nearDist;   
	float dVertices[12*3];
	float dEdges[12*3];

	for(i = 0; i < 12; i++) {
		vecStart[i] = m_pVertices[m_pEdges[m_pEdgeList[farIdx][i]].nV1];
		vecDir[i]   = m_pVertices[m_pEdges[m_pEdgeList[farIdx][i]].nV2] - m_pVertices[m_pEdges[m_pEdgeList[farIdx][i]].nV1];

		denom = vecDir[i] * viewVec;

		if (1.0 + denom != 1.0) {
			lambda_inc[i] =  m_StepSize/denom;
			lambda[i]     = (dPlaneDist - vecStart[i] *viewVec)/denom;
		} else {
			lambda[i]     = -1.0;
			lambda_inc[i] =  0.0;	
		}

		dVertices[3*i]   = vecStart[i][0];
		dVertices[3*i+1] = vecStart[i][1];
		dVertices[3*i+2] = vecStart[i][2];
		dEdges[3*i]      = vecDir[i][0];
		dEdges[3*i+1]    = vecDir[i][1];
		dEdges[3*i+2]    = vecDir[i][2];
	};

	CVector intersection[6];
	float lmb[12];
	//printf("TEXTURE SLICE Num Slices = %d, interslice distance %f\n",numSlices, m_dStepSize);
	for(int n = numSlices-1; n >= 0; --n) {

		for(int e = 0; e < 12; e++) {
			lmb[e] = lambda[e] + n*lambda_inc[e];
		}

		if      ((lmb[0] >= 0.0) && (lmb[0] < 1.0)) intersection[0] = vecStart[0] + lmb[0] * vecDir[0];
		else if ((lmb[1] >= 0.0) && (lmb[1] < 1.0)) intersection[0] = vecStart[1] + lmb[1] * vecDir[1];
		else if ((lmb[3] >= 0.0) && (lmb[3] < 1.0)) intersection[0] = vecStart[3] + lmb[3] * vecDir[3];
		else continue;
		
		if	    ((lmb[2] >= 0.0) && (lmb[2] < 1.0)) intersection[1] = vecStart[2] + lmb[2] * vecDir[2];
		else if ((lmb[0] >= 0.0) && (lmb[0] < 1.0)) intersection[1] = vecStart[0] + lmb[0] * vecDir[0];
		else if ((lmb[1] >= 0.0) && (lmb[1] < 1.0)) intersection[1] = vecStart[1] + lmb[1] * vecDir[1];
		else intersection[1] = vecStart[3] + lmb[3] * vecDir[3];

		if      ((lmb[4] >= 0.0) && (lmb[4] < 1.0)) intersection[2] = vecStart[4] + lmb[4] * vecDir[4];
		else if ((lmb[5] >= 0.0) && (lmb[5] < 1.0)) intersection[2] = vecStart[5] + lmb[5] * vecDir[5];
		else intersection[2] = vecStart[7] + lmb[7] * vecDir[7];
		
		if	    ((lmb[6] >= 0.0) && (lmb[6] < 1.0)) intersection[3] = vecStart[6] + lmb[6] * vecDir[6];
		else if ((lmb[4] >= 0.0) && (lmb[4] < 1.0)) intersection[3] = vecStart[4] + lmb[4] * vecDir[4];
		else if ((lmb[5] >= 0.0) && (lmb[5] < 1.0)) intersection[3] = vecStart[5] + lmb[5] * vecDir[5];
		else intersection[3] = vecStart[7] + lmb[7] * vecDir[7];

		if	    ((lmb[8] >= 0.0) && (lmb[8] < 1.0)) intersection[4] = vecStart[8] + lmb[8] * vecDir[8] ;
		else if ((lmb[9] >= 0.0) && (lmb[9] < 1.0)) intersection[4] = vecStart[9] + lmb[9] * vecDir[9] ;
		else intersection[4] = vecStart[11]+ lmb[11]* vecDir[11];
		
		if	    ((lmb[10]>= 0.0) && (lmb[10]< 1.0)) intersection[5] = vecStart[10]+ lmb[10]* vecDir[10];
		else if ((lmb[8] >= 0.0) && (lmb[8] < 1.0)) intersection[5] = vecStart[8] + lmb[8] * vecDir[8] ;
		else if ((lmb[9] >= 0.0) && (lmb[9] < 1.0)) intersection[5] = vecStart[9] + lmb[9] * vecDir[9] ;
		else intersection[5] = vecStart[11]+ lmb[11]* vecDir[11];

		for(int i = 0; i < 6; ++i) {
			double dLength = intersection[i].getLength();
		}

		
		float c = 1.0f-float(n)/float(numSlices);
		glColor3f(c,c,c);
		glBegin(GL_TRIANGLE_FAN);
		for(int i = 0; i < 6; ++i) {
			intersection[i].glVertex(false,true);
		}
		glEnd();
	}
	glDisable(GL_BLEND);
	glDisable(theData->getTarget());
}
