/*********************************************************************//**
*	Decal system
*	Tento modul tvori system, ktery dokaze vykreslovat ruzne napisy
*	na zed.
*
*	author: Michal Jirous
*	date: 13.02.2009
*	file: level_decals.cpp
**********************************************************************/

#include "level_decals.h"
#include "level_loader.h"
DecalSystem decalSystem;


DecalSystem::DecalSystem()
{
	m_iStaticDecalsCount = m_iDynamicDecalsCount = 0;
	m_iElementsCount = 0;
}


bool find_face( Face &face, Vector *origin )
{
	if( !isPointOnPlane( levelLoader.m_LevelData.planes[face.planenum], *origin ) )
		return false;


	if( face.isPointIn( *origin ) )
		return true;


	return false;
}


void DecalSystem::addStaticTexture(parameters_t &parameters)
{
	std::string value = getParameterValue( parameters, "origin" );
	Vector origin( value );

	value = getParameterValue( parameters, "texture" );

	TextureElement *m_pTexture = textureLibrary.applyTexture( value );

	int angle_Z = 0;
	value = getParameterValue( parameters, "angles" );
	{
		Vector angles( value );
		angle_Z = (int)angles[0];	//prekvapeni..Z je prvni
	}

	if( m_pTexture )
	{
		Face *pTargetFace = NULL;
		//musime najit model a face, kam se ma decal umistit
		size_t modelId = 0;
		for( ; modelId < levelLoader.m_LevelData.models_count; ++modelId )
		{
			pTargetFace = levelLoader.forEachFaceDo( modelId, (bool (*)(Face &,void*) )find_face, &origin );
			if( pTargetFace )
				break;
		}

		//pokud decal lezi na nejakym facu, tak ho muzeme uz pekne vlozit do databaze
		if( pTargetFace )
		{
			if( m_DecalsPerModel[ modelId ].empty() )
				m_DecalsPerModel[ modelId ].push_back( DecalCluster() );
			DecalCluster &cluster = m_DecalsPerModel[ modelId ].back();
			cluster.m_Decals.push_back( Decal() );
			
			Decal &decal = cluster.m_Decals.back();
				
			decal.m_pMyFace = pTargetFace;
			decal.m_pTexture = m_pTexture;
		
			//now generate points
			generateDecal( decal, angle_Z, origin );
		}

	
	}
}

void DecalSystem::generateDecal( Decal &decal, int angle, Point &origin  )
{
	Plane plane = levelLoader.m_LevelData.planes[ decal.m_pMyFace->planenum ];

	if( decal.m_pMyFace->side )
		plane.m_vecNormal = -plane.m_vecNormal;
	
	origin += plane.m_vecNormal * 0.5f;

	ImageInfo &image = decal.m_pTexture->image;
	float fHalfWidth = (float)(image.width>>1);
	float fHalfHeight = (float)(image.height>>1);
	
	//takze pokud je x nebo y souradnice vetsi nez 0, tak polygon neni horizontalne polozen
	Vector sideVector;	//doleva
	Vector verticalVector;	//dolu
	if( fabs(plane.m_vecNormal.x) > 0.0f || fabs(plane.m_vecNormal.y) > 0.0f ) 
	{
		sideVector = plane.m_vecNormal * Vector( 0,0,1);
		verticalVector = plane.m_vecNormal * sideVector * fHalfHeight;

		sideVector = sideVector * fHalfWidth;
	}
	else
	{
		sideVector.x = -fHalfWidth;
		verticalVector.y = -fHalfHeight;
	}

	if( angle )
	{
		Quaternion q;
		q.create( (float)angle, plane.m_vecNormal );
	
		q.rotateVector( sideVector );
		q.rotateVector( verticalVector );
	}

	decal.first_element = m_iElementsCount;

	vertex_array[m_iElementsCount] = sideVector + verticalVector + origin;	//Left bottom
	texture_coords_array[m_iElementsCount].u = 0.0f;
	texture_coords_array[m_iElementsCount].v = 0.0f;

	++m_iElementsCount;

	vertex_array[m_iElementsCount] = sideVector - verticalVector + origin;	//Left top
	texture_coords_array[m_iElementsCount].u = 0.0f;
	texture_coords_array[m_iElementsCount].v = 1.0f;

	++m_iElementsCount;

	vertex_array[m_iElementsCount] = -sideVector - verticalVector + origin;	//Right top
	texture_coords_array[m_iElementsCount].u = 1.0f;
	texture_coords_array[m_iElementsCount].v = 1.0f;

	++m_iElementsCount;

	vertex_array[m_iElementsCount] = -sideVector + verticalVector + origin;	//Right bottom
	texture_coords_array[m_iElementsCount].u = 1.0f;
	texture_coords_array[m_iElementsCount].v = 0.0f;

	++m_iElementsCount;

}

void DecalSystem::destroy()
{
	for( size_t i = 0; i < levelLoader.m_LevelData.models_count; ++i )
	{
		m_DecalsPerModel[i].clear();
	}
	m_iStaticDecalsCount = 0;
	m_iDynamicDecalsCount = 0;
	m_iElementsCount = 0;
}
int modes[16] = {GL_ZERO,GL_ONE,GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR,GL_DST_COLOR,GL_ONE_MINUS_DST_COLOR,GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_DST_ALPHA,GL_ONE_MINUS_DST_ALPHA,GL_SRC_ALPHA_SATURATE,
GL_CONSTANT_COLOR,GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA };
int a = 0;

float white[] = {1,1,1};
#include "game.h"
#include "graphics.h"
void DecalSystem::renderDecalsForModel( size_t model, const RenderData &renderData  )
{
	glPushClientAttrib( GL_CLIENT_ALL_ATTRIB_BITS );
	glPushAttrib( GL_CURRENT_BIT );

	glClientActiveTextureARB( GL_TEXTURE1_ARB );
	glDisable( GL_TEXTURE_2D );
	glClientActiveTextureARB( GL_TEXTURE0_ARB );

	glEnable( GL_BLEND );

	glBlendFunc( GL_ZERO, GL_SRC_COLOR );

	glVertexPointer(3, GL_FLOAT, 0, vertex_array );
	glTexCoordPointer( 2, GL_FLOAT, 0, texture_coords_array );
	glEnable( GL_TEXTURE_2D );

	for( decCList_t::iterator iter = m_DecalsPerModel[model].begin(); iter != m_DecalsPerModel[model].end(); ++iter )
	{
		(*iter).render( renderData );
	}

	glDisable( GL_FOG );
	glPopClientAttrib();
	glPopAttrib();
	glDisable( GL_BLEND );

}

bool DecalSystem::containDecals( size_t model )
{
	if( m_DecalsPerModel[model].empty() )
		return false;

	for( decCList_t::iterator iter = m_DecalsPerModel[model].begin(); iter != m_DecalsPerModel[model].end(); ++iter )
		if( !(*iter).m_Decals.empty() )
			return true;
	return false;
}


//===================================================
//	DECAL CLUSTER
//==================================================


void DecalCluster::render( const RenderData &renderData )
{
	

	if( m_iDecalsCount > FRUSTUM_CULLING_DECAL_COUNT_TRESHOLD && !renderData.frustum->isBoundsInsideFrustum( m_Bounds) )
		 return;

	for( std::list<Decal>::iterator iterDecal = m_Decals.begin(); iterDecal != m_Decals.end(); ++iterDecal )
	{
		texBind( (*iterDecal).m_pTexture->texture_id );
		//backface culling?
		glDrawArrays( GL_POLYGON, (*iterDecal).first_element, 4 );	//always 4
	}

}


