/*********************************************************************//**
*	Simulace lana.
*	Trida pouziva standardni system simulacec pomoci pruzin. Funkci teto
*	tridy je vytvoreni dat na zaklade grafu, ze ktereho vytvori lano.
*	Vykreslovani probiha pomoci vertex array.
*
*	author: Michal Jirous
*	date: 20.12.2008
*	file: rope_simul.cpp
**********************************************************************/

#include "rope_simul.h"
#include <SDL/SDL_opengl.h>

CRopeSimul::CRopeSimul()
{

}


CRopeSimul::~CRopeSimul()
{
	
}

bool CRopeSimul::mass_user_update( Mass *pMass, float dt )
{
	if( pMass )
	{
		ropenode_t *node = (ropenode_t*)pMass->user_data;
		return !node->moveable;
	}
	return false;
}


void CRopeSimul::draw()
{
	
	glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT );
	glColor4f( 0,0,0,1);
	glLineWidth( 3.0f );
	
	glDisable( GL_TEXTURE_2D );
	/*glBegin( GL_LINE_STRIP );
	for( unsigned int i = 0; i < m_uiNumMass*3; i+=3 )
		glVertex3f( m_fPoints[i], m_fPoints[i+1],m_fPoints[i+2] );
	
	glEnd();*/
	
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glVertexPointer(3, GL_FLOAT, 0, m_fPoints);
	glDrawArrays( GL_LINE_STRIP, 0, m_uiNumMass );
	glDisableClientState(GL_VERTEX_ARRAY);

	glPopAttrib();
}

bool CRopeSimul::determineRopeNodes( std::list<GraphNode<Point*>*> &ropeNodeList, GraphNode<Point*>* node )
{
	if( node && node->state != NODE_UNUSED )
		return false;

	ropeNodeList.push_back( node );
	node->state = NODE_OPEN;
	
	for( std::list< GraphNode<Point*>* >::iterator iter = node->m_neightbours.begin(); iter != node->m_neightbours.end(); iter++ )
	{
		if( determineRopeNodes( ropeNodeList, *iter ) )
			break;
	}
	node->state = NODE_CLOSED;
	return true;
}

/* Nejprve je nutne nalezt v grafu cestu, ktera se pouzije na lano. To se provede tak, ze se
*	graf prochazi do hloubky dokud existuje nejaky stav a ten stav musi byt dosud nenavstiveny.
*	Pote uz zname zakladni konstru lana a pak je treba dopocitat pomoci linearni interpolace
*	vsechny ostatni body na zaklade zadane vzdalenosti mezi body. Nejprve je nutne spocitat,
*	kolik takovych bodu bude (zaroven se spocita pocet pruzin) a pote se nainicializuji data
*	k simulaci (vytvoreni poli bodu, sil, texturovacich souradnic, castic a pruzin). Po teto
*	inicializaci se postupne vytvareji pruziny a nastavuji se jim dve castice, mezi kterymi 
*	se pruzina ma vyskytovat plus dalsi parametry jako je delka pruziny v klidu, odpor a tuhost.
*
*	@param consistency Tuhost pruziny.
*	@param friction Odpor pohybu pruziny (treni).
*	@param default_point_distance Pozadovana vzdalenost bodu.
*	@param root Pocatecni uzel grafu, ze ktereho se ma lano vytvorit.
*	@param length_balance_add Vzdalenost o kterou ma byt vzdalenost drou castic zvetsena, coz zapricini proveseni lana.
*/
void CRopeSimul::create( float consistency, float friction, float default_points_distance, ropenode_t *root, float length_balance_add )
{
	if( !root || root->m_neightbours.empty() )
		return;

	unsigned int	uiNumPoints = 1,	//za root
					uiNumSpring = 0;
	
	//zjistit pocet bodu a pruzin
	std::list<GraphNode<Point*>*> rope_nodes;	//seznam bodu, ktere utvori lano
	determineRopeNodes( rope_nodes, root );	//nalezeni jedne vetve
	
	if( rope_nodes.size() < 2 )	//potrebujeme aspon 2 uzly k pouziti interpolace na vytvoreni lana
		return;

	std::list<GraphNode<Point*>*>::iterator iter1, iter2;	//dva iteratory nam umozni pruchod uzlu po dvojicich
	iter2 = rope_nodes.begin();	//prvni uzel
	iter1 = iter2++;			//a toto je vzdy jeoh nasledovnik

	std::list<Point*> finalPoints;
	
	//zjisteni poctu bodu a pruzin
	while( iter2 != rope_nodes.end() )
	{
		(*iter1)->state = NODE_UNUSED;	//reset stavu uzlu
		float length = Vector( *(*iter2)->value - *(*iter1)->value).absolute();	//vzdalenost uzlu
		int added = std::max( (int)(length / default_points_distance),0);	//pocet bodu, ktere se musi mezi ne pridat
	
		uiNumPoints += added;	//zvysime celkovy pocet castic
		uiNumSpring += added;	//zvysime celkovy pocet pruzin
		iter1 = iter2++;	//a posuneme se na dalsi dvojici
	}	

	//inicializace dat
	prepare( uiNumPoints, uiNumSpring );

	iter2 = rope_nodes.begin();	//prochazime po dvojicich zase od zacatku
	iter1 = iter2++;

	//nastavit body a vytvorit pruziny
	uiNumPoints = uiNumSpring = 0;	//odted to jsou indexy

	//nejprve osetrime prvni bod
	m_pMasses[uiNumPoints]->user_data = root;	//priradime castici tento uzel
	*m_pMasses[uiNumPoints]->m_pPosition = *root->value;	//castici nastavime pozici uzlu
	root->value = m_pMasses[uiNumPoints]->m_pPosition;	//a uzlu predame adresu pozice castice, aby bylo mozne zvenci menit pozici castice
	uiNumPoints++;	//jednu castici uz jsme presli
	
	while( iter2 != rope_nodes.end() )
	{
		Vector dir = *(*iter2)->value - *(*iter1)->value;
		float length = dir.absolute();	//zjistime delku
		int added = std::max( (int)(length / default_points_distance)-1,0);	//zjistime pocet pridanych castic bez uzlu ( proto -1 )
		float distance = length;
		if( added != 0 )	//jen pokud je opravdu potreba neco pridavat
		{
			dir.normalize();	//potrebujeme jednotkovy vektor
			distance = length / (added+1);	//spocitame vzdalenost mezi body (zde je potreba pocitat i s koncovym uzlem)
			dir = dir * distance;
			
			//nyni vytvorime pruziny mezi casticemi a casticim nastavime spravne souradnice
			for( int i = 0; i < added; i++ )
			{
				m_pSprings[uiNumSpring] = new Spring( m_pMasses[uiNumPoints-1], m_pMasses[uiNumPoints], consistency, distance+length_balance_add, friction );
				*m_pMasses[uiNumPoints]->m_pPosition = *m_pMasses[uiNumPoints-1]->m_pPosition + dir;
				uiNumSpring++;
				uiNumPoints++;
			}

		}

		//nakonec es postarame i o posledni pruzinu k uzlu
		m_pSprings[uiNumSpring] = new Spring( m_pMasses[uiNumPoints-1], m_pMasses[uiNumPoints], consistency, distance+length_balance_add, friction );
		m_pMasses[uiNumPoints]->user_data = *iter2;	//uzivatelskymi daty je uzel
		*m_pMasses[uiNumPoints]->m_pPosition = *(*iter2)->value;	//nastaveni spravne pozice castice
		(*iter2)->value = m_pMasses[uiNumPoints]->m_pPosition;	//nastaveni adresy pozice castice uzlu
		uiNumSpring++;
		uiNumPoints++;

		iter1 = iter2++;	//prechod na dalsi dva uzly, mezi kterymi se musi vygenerovat castice
	}
	
}

