//---------------------------------------------------------------------------------
//
//---------------------------------------------------------------------------------

#include "giofx.h"

#define UPPER_BOUND 65535

//---------------------------------------------------------------------------------
//
//---------------------------------------------------------------------------------
int cScene::RayToPixel(cVertex &p)
{

#ifdef USE_VISIBILITY_TEST

	float	sx,sy,sz; 
	
	float   pMat[16];
	float	mMat[16];	

	glGetFloatv(GL_MODELVIEW_MATRIX, mMat);
	glGetFloatv(GL_PROJECTION_MATRIX,pMat);

	_gluProject(p.x,p.y,p.z,mMat,pMat,viewport,&sx,&sy,&sz);

    #if TARGET_OS_IPHONE
        //si assume che il rosso sia a zero nella copertura
        GLubyte pixelColor[4];
        glPixelStorei(GL_PACK_ALIGNMENT, 4);
        glReadPixels((int)sx,(int)sy,1,1,GL_RGBA,GL_UNSIGNED_BYTE,&pixelColor[0]);
        if (pixelColor[0] > 0)
            return 1;
    #else
        float	depth;
        glReadPixels((int)sx,(int)sy,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&depth);
        if(depth >= sz)
            return 1;
    #endif

    return 0;
    
#else

	return 1;

#endif

}
//---------------------------------------------------------------------------------------------------------
//
//---------------------------------------------------------------------------------------------------------	
void cScene::StoreFOV()						
{

#ifdef USE_VISIBILITY_TEST

	float	clip[16];								
	float	mMat[16],pMat[16];
	float	t;
	
	glGetFloatv(GL_MODELVIEW_MATRIX,mMat);
	glGetFloatv(GL_PROJECTION_MATRIX,pMat);

	clip[ 0] = (mMat[ 0] * pMat[ 0] + mMat[ 1] * pMat[ 4] + mMat[ 2] * pMat[ 8] + mMat[ 3] * pMat[12]);
	clip[ 1] = (mMat[ 0] * pMat[ 1] + mMat[ 1] * pMat[ 5] + mMat[ 2] * pMat[ 9] + mMat[ 3] * pMat[13]);
	clip[ 2] = (mMat[ 0] * pMat[ 2] + mMat[ 1] * pMat[ 6] + mMat[ 2] * pMat[10] + mMat[ 3] * pMat[14]);
	clip[ 3] = (mMat[ 0] * pMat[ 3] + mMat[ 1] * pMat[ 7] + mMat[ 2] * pMat[11] + mMat[ 3] * pMat[15]);

	clip[ 4] = (mMat[ 4] * pMat[ 0] + mMat[ 5] * pMat[ 4] + mMat[ 6] * pMat[ 8] + mMat[ 7] * pMat[12]);
	clip[ 5] = (mMat[ 4] * pMat[ 1] + mMat[ 5] * pMat[ 5] + mMat[ 6] * pMat[ 9] + mMat[ 7] * pMat[13]);
	clip[ 6] = (mMat[ 4] * pMat[ 2] + mMat[ 5] * pMat[ 6] + mMat[ 6] * pMat[10] + mMat[ 7] * pMat[14]);
	clip[ 7] = (mMat[ 4] * pMat[ 3] + mMat[ 5] * pMat[ 7] + mMat[ 6] * pMat[11] + mMat[ 7] * pMat[15]);

	clip[ 8] = (mMat[ 8] * pMat[ 0] + mMat[ 9] * pMat[ 4] + mMat[10] * pMat[ 8] + mMat[11] * pMat[12]);
	clip[ 9] = (mMat[ 8] * pMat[ 1] + mMat[ 9] * pMat[ 5] + mMat[10] * pMat[ 9] + mMat[11] * pMat[13]);
	clip[10] = (mMat[ 8] * pMat[ 2] + mMat[ 9] * pMat[ 6] + mMat[10] * pMat[10] + mMat[11] * pMat[14]);
	clip[11] = (mMat[ 8] * pMat[ 3] + mMat[ 9] * pMat[ 7] + mMat[10] * pMat[11] + mMat[11] * pMat[15]);

	clip[12] = (mMat[12] * pMat[ 0] + mMat[13] * pMat[ 4] + mMat[14] * pMat[ 8] + mMat[15] * pMat[12]);
	clip[13] = (mMat[12] * pMat[ 1] + mMat[13] * pMat[ 5] + mMat[14] * pMat[ 9] + mMat[15] * pMat[13]);
	clip[14] = (mMat[12] * pMat[ 2] + mMat[13] * pMat[ 6] + mMat[14] * pMat[10] + mMat[15] * pMat[14]);
	clip[15] = (mMat[12] * pMat[ 3] + mMat[13] * pMat[ 7] + mMat[14] * pMat[11] + mMat[15] * pMat[15]);

	frst[0][0] = clip[ 3] - clip[ 0];
	frst[0][1] = clip[ 7] - clip[ 4];
	frst[0][2] = clip[11] - clip[ 8];
	frst[0][3] = clip[15] - clip[12];

	t = (float)sqrt( frst[0][0] * frst[0][0] + frst[0][1] * frst[0][1] + frst[0][2] * frst[0][2] );
	frst[0][0] /= t;
	frst[0][1] /= t;
	frst[0][2] /= t;
	frst[0][3] /= t;

	frst[1][0] = clip[ 3] + clip[ 0];
	frst[1][1] = clip[ 7] + clip[ 4];
	frst[1][2] = clip[11] + clip[ 8];
	frst[1][3] = clip[15] + clip[12];

	t = (float) sqrt( frst[1][0] * frst[1][0] + frst[1][1] * frst[1][1] + frst[1][2] * frst[1][2] );
	frst[1][0] /= t;
	frst[1][1] /= t;
	frst[1][2] /= t;
	frst[1][3] /= t;

	frst[2][0] = clip[ 3] + clip[ 1];
	frst[2][1] = clip[ 7] + clip[ 5];
	frst[2][2] = clip[11] + clip[ 9];
	frst[2][3] = clip[15] + clip[13];

	t = (float) sqrt( frst[2][0] * frst[2][0] + frst[2][1] * frst[2][1] + frst[2][2] * frst[2][2] );
	frst[2][0] /= t;
	frst[2][1] /= t;
	frst[2][2] /= t;
	frst[2][3] /= t;

	frst[3][0] = clip[ 3] - clip[ 1];
	frst[3][1] = clip[ 7] - clip[ 5];
	frst[3][2] = clip[11] - clip[ 9];
	frst[3][3] = clip[15] - clip[13];

	t = (float) sqrt( frst[3][0] * frst[3][0] + frst[3][1] * frst[3][1] + frst[3][2] * frst[3][2] );
	frst[3][0] /= t;
	frst[3][1] /= t;
	frst[3][2] /= t;
	frst[3][3] /= t;

	frst[4][0] = clip[ 3] - clip[ 2];
	frst[4][1] = clip[ 7] - clip[ 6];
	frst[4][2] = clip[11] - clip[10];
	frst[4][3] = clip[15] - clip[14];

	t = (float) sqrt( frst[4][0] * frst[4][0] + frst[4][1] * frst[4][1] + frst[4][2] * frst[4][2] );
	frst[4][0] /= t;
	frst[4][1] /= t;
	frst[4][2] /= t;
	frst[4][3] /= t;

	frst[5][0] = clip[ 3] + clip[ 2];
	frst[5][1] = clip[ 7] + clip[ 6];
	frst[5][2] = clip[11] + clip[10];
	frst[5][3] = clip[15] + clip[14];

	t = (float) sqrt( frst[5][0] * frst[5][0] + frst[5][1] * frst[5][1] + frst[5][2] * frst[5][2] );
	frst[5][0] /= t;
	frst[5][1] /= t;
	frst[5][2] /= t;
	frst[5][3] /= t;
    
#endif

}
//-------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------
int cObj::BBoxTest(cBox &bb)
{

#ifdef USE_VISIBILITY_TEST
	
	for( int p = 0; p < 6; p++ ){
		
		if( parent->frst[p][0] * bb.pt[0].x + parent->frst[p][1] * bb.pt[0].y + parent->frst[p][2] * bb.pt[0].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[1].x + parent->frst[p][1] * bb.pt[1].y + parent->frst[p][2] * bb.pt[1].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[2].x + parent->frst[p][1] * bb.pt[2].y + parent->frst[p][2] * bb.pt[2].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[3].x + parent->frst[p][1] * bb.pt[3].y + parent->frst[p][2] * bb.pt[3].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[4].x + parent->frst[p][1] * bb.pt[4].y + parent->frst[p][2] * bb.pt[4].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[5].x + parent->frst[p][1] * bb.pt[5].y + parent->frst[p][2] * bb.pt[5].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[6].x + parent->frst[p][1] * bb.pt[6].y + parent->frst[p][2] * bb.pt[6].z + parent->frst[p][3] >0 )
			continue;
		if( parent->frst[p][0] * bb.pt[7].x + parent->frst[p][1] * bb.pt[7].y + parent->frst[p][2] * bb.pt[7].z + parent->frst[p][3] >0 )
			continue;

		return 0;
	}
#endif

	return 1;
}
//-------------------------------------------------------------------------------------------
void cObj::VisibilityTest()
{

#ifdef USE_VISIBILITY_TEST

	cVertex eye;
	cVertex cc = parent->position * -1;
	eye.World2Local(cc,identity);
			
	if (!depthTest)
	{
        //parent->StoreFOV();
        isVisible = true;
        for (int t=0;t<totObjects;t++)
            subObj[t].isVisible = true;
	}
    else
    {
		isVisible = BBoxTest(localBox);
        if (isVisible)
            for (int t=0;t<totObjects;t++)
                subObj[t].isVisible = BBoxTest(subObj[t].localBox);
    }
    
#endif
}

//-------------------------------------------------------------------------------------------
/*

	4-----------5
	| \			| \
	|   0-----------1
	|	|       |   |
	|	|       |   |
	|	|       |   |
	7---|-------6   |
      \ |         \ |
		3-----------2
        
*/
//-------------------------------------------------------------------------------------------

void cObj::CreateBoundBoxes()
{

#ifdef USE_VISIBILITY_TEST

float	minX,maxX;
float	minY,maxY;
float	minZ,maxZ;

	for (int q=0;q<8;q++)
		localBox.pt[q].Clear();

	localBox.pt[0].x =
	localBox.pt[3].x =
	localBox.pt[4].x =
	localBox.pt[7].x = +UPPER_BOUND;
	
	localBox.pt[1].x =
	localBox.pt[2].x =
	localBox.pt[5].x =
	localBox.pt[6].x = -UPPER_BOUND;

	localBox.pt[3].y =
	localBox.pt[2].y =
	localBox.pt[6].y =
	localBox.pt[7].y = +UPPER_BOUND;
	
	localBox.pt[0].y =
	localBox.pt[1].y =
	localBox.pt[5].y =
	localBox.pt[4].y = -UPPER_BOUND;

	localBox.pt[4].z =
	localBox.pt[5].z =
	localBox.pt[6].z =
	localBox.pt[7].z = +UPPER_BOUND;

	localBox.pt[0].z =
	localBox.pt[1].z =
	localBox.pt[2].z =
	localBox.pt[3].z = -UPPER_BOUND;

	for (int t=0;t<totObjects;t++){
		
		minX=
		minY=
		minZ=+UPPER_BOUND;
		
		maxX=
		maxY=
		maxZ=-UPPER_BOUND;
		
		for (int v=0;v<subObj[t].totVertex;v++){
			minX  = __min((int)subObj[t].vertex[v].x,minX);
			maxX  = __max((int)subObj[t].vertex[v].x,maxX);
			
			minY  = __min((int)subObj[t].vertex[v].y,minY);
			maxY  = __max((int)subObj[t].vertex[v].y,maxY);
			
			minZ  = __min((int)subObj[t].vertex[v].z,minZ);
			maxZ  = __max((int)subObj[t].vertex[v].z,maxZ);
		}

		subObj[t].localBox.pt[0].x =
		subObj[t].localBox.pt[3].x =
		subObj[t].localBox.pt[4].x =
		subObj[t].localBox.pt[7].x = minX;

		subObj[t].localBox.pt[1].x =
		subObj[t].localBox.pt[2].x =
		subObj[t].localBox.pt[5].x =
		subObj[t].localBox.pt[6].x = maxX;

		subObj[t].localBox.pt[3].y =
		subObj[t].localBox.pt[2].y =
		subObj[t].localBox.pt[6].y =
		subObj[t].localBox.pt[7].y = minY;

		subObj[t].localBox.pt[0].y =
		subObj[t].localBox.pt[1].y =
		subObj[t].localBox.pt[5].y =
		subObj[t].localBox.pt[4].y = maxY;

		subObj[t].localBox.pt[4].z =
		subObj[t].localBox.pt[5].z =
		subObj[t].localBox.pt[6].z =
		subObj[t].localBox.pt[7].z = minZ;

		subObj[t].localBox.pt[0].z =
		subObj[t].localBox.pt[1].z =
		subObj[t].localBox.pt[2].z =
		subObj[t].localBox.pt[3].z = maxZ;
	
		localBox.pt[0].x =
		localBox.pt[3].x =
		localBox.pt[4].x =
		localBox.pt[7].x = __min(minX,localBox.pt[7].x);
		
		localBox.pt[1].x =
		localBox.pt[2].x =
		localBox.pt[5].x =
		localBox.pt[6].x = __max(maxX,localBox.pt[6].x);

		localBox.pt[3].y =
		localBox.pt[2].y =
		localBox.pt[6].y =
		localBox.pt[7].y = __min(minY,localBox.pt[7].y);
		
		localBox.pt[0].y =
		localBox.pt[1].y =
		localBox.pt[5].y =
		localBox.pt[4].y = __max(maxY,localBox.pt[4].y);

		localBox.pt[4].z =
		localBox.pt[5].z =
		localBox.pt[6].z =
		localBox.pt[7].z = __min(minZ,localBox.pt[7].z);

		localBox.pt[0].z =
		localBox.pt[1].z =
		localBox.pt[2].z =
		localBox.pt[3].z = __max(maxZ,localBox.pt[3].z);

	}
#endif
}

//-------------------------------------------------------------------------------------------

void cObj::UpdateBoundBoxes()
{

#ifdef USE_VISIBILITY_TEST

	if (parent->useOrtho)
		return;

	glPushMatrix();
	glLoadIdentity();

	glTranslatef(this->position.x,this->position.y,this->position.z);

#ifdef USE_BULLET
	if (!p_Body)
	{
		glRotatef(rotation.x,1,0,0);
		glRotatef(rotation.y,0,1,0);
		glRotatef(rotation.z,0,0,1);
	}
	else
	{
		glRotatef(rotation.z,0,0,1);
		glRotatef(rotation.y,0,1,0);
		glRotatef(rotation.x,1,0,0);
	}
#else
	{
		glRotatef(rotation.x,1,0,0);
		glRotatef(rotation.y,0,1,0);
		glRotatef(rotation.z,0,0,1);
	}
#endif

	glGetFloatv(GL_MODELVIEW_MATRIX,identity.m);

	glPopMatrix();

	for (int q=0;q<8;q++)
	{
		worldBox.pt[q] = identity * this->localBox.pt[q];
		for (int t=0;t<totObjects;t++)
			subObj[t].worldBox.pt[q] = identity * subObj[t].localBox.pt[q];
	}
#endif

}

