
/*
	file : controller.h

	Dragon Wings (c) 2005 Philipp Roßberger, Sebastian Roll
		www.einszunull.net
		www.sebastianroll.de

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any damages
	arising from the use of this software.

	Permission is granted to anyone to use this software for any purpose,
	including commercial applications, and to alter it and redistribute it
	freely, subject to the following restrictions:

	1. The origin of this software must not be misrepresented; you must not
		claim that you wrote the original software. If you use this software
		in a product, an acknowledgment in the product documentation would be
		appreciated but is not required.
	2. Altered source versions must be plainly marked as such, and must not be
		misrepresented as being the original software.
	3. This notice may not be removed or altered from any source distribution.

	Used software libraries from other people (thank you very much):

	The Irrlicht Engine:
		Copyright (c) 2002-2005 Nikolaus Gebhardt
		www.irrlicht.sourceforge.net
  
	The Character Animation Library (cal3D):
		Copyright (c) 2001, 2002 Bruno 'Beosil' Heidelberger
		www.cal3d.sourceforge.net

	The FMOD audio library:
		Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004
		www.fmod.org

	Article - Using Cal3D with Irrlicht:
		Copyright (c) Thomas Suter 2004
		www.thomas.webtracker.ch/jahia/Jahia/cache/off/pid/672

*/



/*
// debug skybox
#define MEDIAFILE_SKYBOX_TOP		"boxSide1.PNG"
#define MEDIAFILE_SKYBOX_BOTTOM		"boxSide2.PNG"
#define MEDIAFILE_SKYBOX_RIGHT		"boxSide3.PNG"
#define MEDIAFILE_SKYBOX_LEFT		"boxSide4.PNG"
#define MEDIAFILE_SKYBOX_FRONT		"boxSide5.PNG"
#define MEDIAFILE_SKYBOX_BACK		"boxSide6.PNG"
*/

#define MEDIAFILE_SKYBOX_TOP		"skybox_1.jpg"
#define MEDIAFILE_SKYBOX_BOTTOM		"skybox_2.jpg"
#define MEDIAFILE_SKYBOX_RIGHT		"skybox_3.jpg"
#define MEDIAFILE_SKYBOX_LEFT		"skybox_4.jpg"
#define MEDIAFILE_SKYBOX_FRONT		"skybox_5.jpg"
#define MEDIAFILE_SKYBOX_BACK		"skybox_6.jpg"

#define MEDIAFILE_TEXTURE_LIGHT		"particlewhite.bmp"
#define MEDIAFILE_ARROW				"arrow.3ds"
#define PLAYER_ACCELERATION			0.1f
#define PLAYER_MAX_ACCEL			0.5f
#define PLAYER_ACCEL_Y				0.01f
#define PLAYER_MAX_ACCEL_Y			0.5f

// will be overwritten by config file "level.xml":
extern int PLAYER_LEFTRIGHT_FLIP		= false;	// tracking server can change leading sign of incomming tracking-y value
extern int PLAYER_WING_ROLL_FLIP		= false;	// tracking server can change leading sign of incomming tracking-roll value
extern int PLAYER_WING_ROLL_ARRAY_POS	= 0;		// tracking server can change data order of roll-value
extern float PLAYER_LEFTRIGHT_DOWNGRADE	= 1.00f;	// downgrade every frame to no left/right
extern float PLAYER_WING_ANGLE_SCALE	= 10.0f;	// influences wing-animation, incomming tracking-y value divided by
extern float PLAYER_WING_ROLL_SCALE		= 10.0f;	// influences "ydirection", incomming tracking-roll value divided by
extern float PLAYER_LEFTRIGHT_SCALE		= 10.0f;	// influences "direction", incomming tracking-y value divided by
extern float CAMERA_Y_DIRECTION_MAX		= 10.0f;	// range = -10..+10, position of camera above/under player
extern float CAMERA_FAR_VALUE			= 5000.0f;
extern int TRACKER_BODY_ROLL_OFFSET		= 0;		// adding this to incomming tracking-roll value to avoid +/- change
extern float PLAYER_MAX_SPEED_Y			= 32.0f;	// max up/down speed
extern float PLAYER_MAX_SPEED			= 32.0f;	// max forward speed



void reset()
{
	if (dbg)
	{
		dbg->remove();
		dbg = 0;
	}
	if (isDebug)
		dbg = guienv->addStaticText(L"", rect<s32>(10, 10, SCREEN_X/2-100, SCREEN_Y/2), true, true, 0, -1, true);
	
	if (cam) cam->remove();
	cam = smgr->addCameraSceneNode();
	cam->setFarValue(CAMERA_FAR_VALUE);	// render also far objects

	if (light) light->remove();
	light = smgr->addLightSceneNode(0, v3(100,100,100), SColorf(1.0f, 1.0f, 1.0f), 10);
	
	if (skyBox) skyBox->remove();

	skyBox = smgr->addSkyBoxSceneNode(
				driver->getTexture(makeMediaString(MEDIAFILE_SKYBOX_TOP).c_str()),
				driver->getTexture(makeMediaString(MEDIAFILE_SKYBOX_BOTTOM).c_str()),
				driver->getTexture(makeMediaString(MEDIAFILE_SKYBOX_LEFT).c_str()),
				driver->getTexture(makeMediaString(MEDIAFILE_SKYBOX_RIGHT).c_str()),
				driver->getTexture(makeMediaString(MEDIAFILE_SKYBOX_FRONT).c_str()),
				driver->getTexture(makeMediaString(MEDIAFILE_SKYBOX_BACK).c_str())
			 );

	if (arrow) arrow->remove();
	arrow = smgr->addMeshSceneNode(smgr->getMesh(makeMediaString(MEDIAFILE_ARROW).c_str())->getMesh(0));
	arrow->setMaterialTexture(0, driver->getTexture("media/white.jpg"));
	arrow->setScale(v3(0.02f,0.02f,0.02f));
	arrow->setMaterialType(EMT_TRANSPARENT_ADD_COLOR);
	arrow->setMaterialFlag(EMF_WIREFRAME, false);
	arrow->setMaterialFlag(EMF_LIGHTING, true);
	arrow->getMaterial(0).EmissiveColor = SColor(250 ,255, 0, 0);
	arrow->getMaterial(0).AmbientColor = SColor(0, 255, 0, 0);
	
	timer = device->getTimer();
	nextRingPosition = v3(0,0,0);
	
	// remove all items in list
	list<Obj*>::Iterator it = objects.begin();
	while(it != objects.end())
	{
		if ((*it)->pssn)	// only rings have particle systems
		{
			(*it)->pssn->removeAll();
			(*it)->pssn->remove();
			(*it)->pssn = 0;
		}
		(*it)->node->remove();
		delete (*it);
		it++;
	}
	objects.clear();

	// remove player
	if (player.node)
	{	
		player.node->remove();
		delete player.node;
		player.node = 0;
	}
	player.velocity = v3(0, 0, 0);
	player.acceleration = v3(0, 0, PLAYER_ACCELERATION);

	// create number[0..9] font to display levelTime
	for (int i=0; i<10; i++)
	{
		stringc fileName(MEDIAPATH_NUMBERS);
		fileName.append(makeASCII(i));
		fileName.append(".png");
		numbers[i] = driver->getTexture(fileName.c_str());
	}

	// create images for time display [123]
	for (int i=0; i<3; i++)
	{
		s32 offset = SCREEN_X / 3 - (128/2);
		if (time[i]) time[i]->remove();
		time[i] = guienv->addImage(rect<s32>(i*128+offset, 20, i*128+128+offset, 148));
		time[i]->setUseAlphaChannel(true);
		time[i]->setVisible(true);
	}

	// center mouse-pointer and get rid of it
	device->getCursorControl()->setPosition( 0.5f, 0.5f );
	device->getCursorControl()->setVisible(false);

	// init game time
	oldTime = timer->getTime();

	numLeftRings = 0;

	if (ringsLeftImg) ringsLeftImg->remove();
	ringsLeftImg = guienv->addImage(rect<s32>(-42, -107, -42+128, -107+128));
	ringsLeftImg->setImage(driver->getTexture("media/ringsLeftAlpha.png"));
	ringsLeftImg->setVisible(true);
	ringsLeftImg->setUseAlphaChannel(true);

	if (ringCntDownImg) ringCntDownImg->remove();
	ringCntDownImg = guienv->addImage(rect<s32>(-20, 20, -20+128, 20+128));
	ringCntDownImg->setVisible(true);
	ringCntDownImg->setUseAlphaChannel(true);

	if (logo) logo->remove();
	logo = guienv->addImage(rect<s32>(0, 0, 128, 128));
	logo->setImage(driver->getTexture("media/logo.png"));
	logo->setVisible(false);
	logo->setUseAlphaChannel(true);
}


void recognizeFlap()
{
	player.velocity.Y = ydirection;
	if (player.acceleration.Y > PLAYER_MAX_ACCEL_Y)
		player.acceleration.Y = PLAYER_MAX_ACCEL_Y;
	if (player.acceleration.Y < -PLAYER_MAX_ACCEL_Y)
		player.acceleration.Y = -PLAYER_MAX_ACCEL_Y;
	if (player.velocity.Y > PLAYER_MAX_SPEED_Y)
		player.velocity.Y = PLAYER_MAX_SPEED_Y;
	if (player.velocity.Y < -PLAYER_MAX_SPEED_Y)
		player.velocity.Y = -PLAYER_MAX_SPEED_Y;
}


void calibrate()
{
	player.calibratedLeftWing = *(udpGetLeftWing());
	player.calibratedRightWing = *(udpGetRightWing());
	
	player.calibratedLeftWing.ang[PLAYER_WING_ROLL_ARRAY_POS] += (float) TRACKER_BODY_ROLL_OFFSET;
	player.calibratedRightWing.ang[PLAYER_WING_ROLL_ARRAY_POS] += (float) TRACKER_BODY_ROLL_OFFSET;
}


void animateLeftWing(float trackedBodyPos, float rangeMin, float rangeMax)
{
	if (! player.node) return;

	/* bone 2 is left wing:
	---------------------------------
	Pos	x		y		z		w
	/	-0.567	0.728	 0.339	-0.179
	-	-0.611	0.791	 0.000	 0.000
	\	-0.606	0.784	-0.114	 0.064
	---------------------------------
	*/

	CalQuaternion q;
	if (trackedBodyPos > 0)
	{
		q.x =          mapToScale(-0.611f, -0.567f, trackedBodyPos, 0.0f, rangeMax);
		q.y = 0.791f - mapToScale(+0.000f, +0.063f, trackedBodyPos, 0.0f, rangeMax);
		q.z =          mapToScale(+0.000f, +0.339f, trackedBodyPos, 0.0f, rangeMax);
		q.w = 0.000f - mapToScale(+0.000f, +0.179f, trackedBodyPos, 0.0f, rangeMax);
	}
	else
	{
		q.x =-0.606f - mapToScale(+0.000f, +0.005f, trackedBodyPos, rangeMin, 0.0f);
		q.y =          mapToScale(+0.784f, +0.791f, trackedBodyPos, rangeMin, 0.0f);
		q.z =          mapToScale(-0.114f, +0.000f, trackedBodyPos, rangeMin, 0.0f);
		q.w = 0.061f - mapToScale(+0.000f, +0.064f, trackedBodyPos, rangeMin, 0.0f);
	}

	player.node->setBoneRotation(2, q);
}


void animateRightWing(float trackedBodyPos, float rangeMin, float rangeMax)
{
	if (! player.node) return;

	/* bone 1 is right wing:
	---------------------------------
	Pos	x		y		z		w
	/	0.220	0.315	0.574	0.723
	-	0.000	0.000	0.611	0.790
	\	-0.078	-0.110	0.606	0.783
	---------------------------------
	*/

	CalQuaternion q;
	if (trackedBodyPos > 0)
	{
		q.x =          mapToScale(+0.000f, +0.220f, trackedBodyPos, 0.0f, rangeMax);
		q.y =          mapToScale(+0.000f, +0.315f, trackedBodyPos, 0.0f, rangeMax);
		q.z = 0.611f - mapToScale(+0.000f, +0.037f, trackedBodyPos, 0.0f, rangeMax);
		q.w = 0.790f - mapToScale(+0.000f, +0.067f, trackedBodyPos, 0.0f, rangeMax);
	}
	else
	{
		q.x =          mapToScale(-0.078f, +0.000f, trackedBodyPos, rangeMin, 0.0f);
		q.y =          mapToScale(-0.110f, +0.000f, trackedBodyPos, rangeMin, 0.0f);
		q.z =          mapToScale(+0.606f, +0.611f, trackedBodyPos, rangeMin, 0.0f);
		q.w =          mapToScale(+0.783f, +0.790f, trackedBodyPos, rangeMin, 0.0f);
	}


	player.node->setBoneRotation(1, q);
}


void thirdPersonCam()
{
	v3 playerPos;
	if (player.node)
	{
		playerPos = player.node->getPosition();
		playerPos.Y += player.velocity.Y;
		player.node->setPosition(playerPos);
	}
			   
	float yf = playerPos.Y + sin( -ydirection * PI / 180.0f ) * 8.0f;
	float xf = playerPos.X - cos( ydirection * PI / 180.0f ) * cos( direction * PI / 180.0f ) * 1.0f;
    float zf = playerPos.Z + cos( ydirection * PI / 180.0f ) * sin( direction * PI / 180.0f ) * 1.0f; 

	cam->setPosition( v3( xf, yf+4.0f, zf ) );
	cam->setTarget( v3( playerPos.X, playerPos.Y+4.0f-player.velocity.Y, playerPos.Z-0.0f ) );

	if (player.node)
	{
		player.node->setRotation( v3( player.velocity.Y, direction, 0) ); 

		// make/check speed
		player.acceleration.Z++;
		if (player.acceleration.Z > PLAYER_MAX_ACCEL)
			player.acceleration.Z = PLAYER_MAX_ACCEL;
		player.velocity.Z += player.acceleration.Z;
		if (player.velocity.Z > PLAYER_MAX_SPEED)
			player.velocity.Z = PLAYER_MAX_SPEED;
		
		// move player
		float degree = ( player.node->getRotation().Y + 90.0f ) * PI/180.0f;
		v3 facing( sin(degree), 0, cos(degree)); 
		facing.normalize(); 
		
		v3 newPos = (facing * player.velocity.Z) + player.node->getPosition(); 
		player.node->setPosition(newPos);

		// correct view on dragon, don't know why...
		player.node->setRotation(player.node->getRotation() +  v3(-90, -90, 0) ); 
	}
	float camDeg = ( player.node->getRotation().Y + 0.0f ) * PI/180.0f;
	v3 camFace( sin(camDeg), 0, cos(camDeg)); 
	camFace.normalize(); 
		
	v3 camP = (camFace *  (11.0f-player.velocity.Z)) + cam->getPosition(); 
	cam->setPosition(camP);
}


// can only be called after smgr->drawAll() has been called!
void drawLine(v3 start, v3 end)
{
	matrix4 oldMatrix = driver->getTransform(ETS_WORLD);
	driver->setTransform(ETS_WORLD, matrix4());
	SMaterial m;
	m.EmissiveColor = SColor(255,255,255,255);
	driver->setMaterial(m);
	driver->draw3DLine(start, end);
	driver->setTransform(ETS_WORLD, oldMatrix);
	//driver->setMaterial(oldMaterial);
}


void update()
{
	stringc searchName("ring");
	bool ringFound = false;
	ITriangleSelector* selector = 0;
	ISceneNodeAnimator* anim = 0;
	static float sinCnt = 0.4f; sinCnt += 0.1f;

	if (player.node)
	{
		// light up scene
		light->setPosition(player.node->getPosition() + v3(100,100,100));
		light->getLightData().DiffuseColor = SColorf(1.0f, 1.0f, 1.0f);
		// collision: remove all responses, they will be added again, if objects in range
		player.node->removeAnimators();
	}

	// iterate through all objects
	list<Obj*>::Iterator it = objects.begin();
	while(it != objects.end())
	{
		// rotate each asteroid
		(*it)->node->setRotation((*it)->node->getRotation() + (*it)->rot);

		if ( (*it)->pssn != 0) // only rings ghave particle system
		{
			v3 circle(300.0f * sin(sinCnt), 300.0f * cos(sinCnt), 0);
			(*it)->pssn->setPosition((*it)->node->getPosition() + circle);
		}
		
		// search next ring, player has to fly through
		if (! ringFound)
		{
			if ( searchName.equals_ignore_case((*it)->name) )
			{
				// save ring position. arrow will point to this position.
				nextRingPosition = (*it)->node->getPosition();
				ringFound = true;
			}
		}

		// collision:
		// how far is this object from player?
		f64 distance = (*it)->node->getPosition().getDistanceFrom(player.node->getPosition());
		if ( distance < 800.0f )
		{
			// is it a ring?
			if ( searchName.equals_ignore_case((*it)->name) )
			{
				// near enough, check for collission
				// delete ring, if hit
				v3 distPR = player.node->getPosition() - (*it)->node->getPosition();
				bool collided = false;
				if ( distPR.getLength() < 300.0f )
				{
					collided = true;
					
					// dives player really into ring?
					//float angelPR = getTargetAngle(p, r).Y;
					//if ( isInRange(angelPR, 000.00f, 030.0f) ||
					//	 isInRange(angelPR, 350.00f, 380.0f) ||
					//	 isInRange(angelPR, 150.00f, 210.0f) )
					//	collided = true;				
				}
				if (collided)
				{
					// hilight dragon red
					light->getLightData().DiffuseColor = SColorf(1.0f, 0, 0);

					// play sound
					soundRing();
					
					numLeftRings--;

					// display amount of rings left
					if (isInRange(numLeftRings, 0 , 9))
					{
						ringCntDownImg->setImage(numbers[numLeftRings]);
					}

					// delete ring
					(*it)->mesh = 0;
					(*it)->name = stringc("deleted ring");
					(*it)->node->remove();
					(*it)->node = 0;
					(*it)->rot = v3(0,0,0);
					(*it)->pssn->remove();
					(*it)->pssn = 0;
					delete (*it);
					it = objects.erase(it);

					if (it == NULL)		// this ring was the last element in list
						break;
					else
						continue;
				}
			}
			else	// its not a ring, its a asteroid
			{
				// near enough, add collission response
				selector = smgr->createTriangleSelector((*it)->mesh, (*it)->node);
				(*it)->node->setTriangleSelector(selector);
				selector->drop();
				anim = smgr->createCollisionResponseAnimator( selector, player.node, v3(30,50,30), v3(0,0,0), v3(0,0,0), 0.0f );
				player.node->addAnimator(anim);
				anim->drop();
			}
		}

		// goto next asteroid/ring
		it++;
	}

	if (! ringFound)
	{
		// no more rings in this level, goto next level
		gameState = STATE_LEVEL_END;
	}

	if (levelTime < 1)	
	{
		// game ends if game time == 0
		gameState = STATE_LEVEL_END;
	}

	// count down game time
	now = timer->getTime();
	if (oldTime + 1000 < now)
	{
		oldTime = now;
		levelTime--;

		// render bitmaps onto screen. use numbers font [0..9]
		stringc sTime(makeASCII(levelTime));
		// how many chars?
		int charNum = sTime.size();
		// prepare images
		for (int i=0; i<charNum; i++)
		{
			s32 offset;
			if (charNum < 2)
				offset = SCREEN_X / 2 + 64;
			else
				offset = SCREEN_X / charNum - (128/2);
			time[i]->setRelativePosition(rect<s32>(i*128+offset-((3-charNum)*64), 20, i*128+128+offset-((3-charNum)*64), 148));
			time[i]->setVisible(true);

			char cDigit = sTime[i];
			int index = cDigit - '0';
			if (isInRange(index, 0 , 9))
			{
				time[i]->setImage(numbers[index]);
			}
		}
		// hide unused images
		for (int i=charNum; i<3; i++)
		{
			time[i]->setVisible(false);
		}
	}

	// up/down movement
	recognizeFlap();

	// allways look at player
	thirdPersonCam();

	// play wind-sound loud, if flying a downwars. no wind-sound, if upwards
	soundWindAdjust( (int) (140 - mapToScale(0.0f, 128.0f, player.velocity.Y, -PLAYER_MAX_SPEED_Y, +PLAYER_MAX_SPEED_Y)) );

	// set arrow in front of camera and rotete its face to next ring
	float camDegree = ( direction + 120.0f  ) * PI/180.0f;
	float ycamDegree = ( -player.velocity.Y*0.5f + 110.0f) * PI/180.0f;
	v3 camFacing( sin(camDegree), cos(ycamDegree), cos(camDegree));//- 1.4f 
	camFacing.normalize();
	arrow->setPosition( camFacing*8.0f + cam->getPosition() );
	arrow->setRotation(getTargetAngle(arrow->getPosition(), nextRingPosition));

	// move player left/right set wing Up/down position
	// -> set global variables direction and ydirection
	if (! renderOfflineAnim)
	{
		if (haveTracker)
		{
			// apply tracking data to wings
			// left wing
			trackedBody* leftWing = udpGetLeftWing();
			float angleLeft = (leftWing->loc[1] - player.calibratedLeftWing.loc[1]) / PLAYER_WING_ANGLE_SCALE;
			if ( isInRange((int) angleLeft, -360, -10) )
				angleLeft = -10.0f;
			else if ( isInRange((int) angleLeft, +45, +360) )
				angleLeft = +45.0f;
			animateLeftWing(angleLeft, -10.0f, +45.0f);
			
			// right wing
			trackedBody* rightWing = udpGetRightWing();
			float angleRight = (rightWing->loc[1] - player.calibratedRightWing.loc[1]) / PLAYER_WING_ANGLE_SCALE;
			if ( isInRange((int) angleRight, -360, -10) )
				angleRight = -10.0f;
			else if ( isInRange((int) angleRight, +45, +360) )
				angleRight = +45.0f;
			animateRightWing(angleRight, -10.0f, +45.0f);

			// move left, right according to both wing positions
			direction /= PLAYER_LEFTRIGHT_DOWNGRADE;	// downgrade every frame
			direction += angleLeft / PLAYER_LEFTRIGHT_SCALE;
			direction -= angleRight / PLAYER_LEFTRIGHT_SCALE;
			if (PLAYER_LEFTRIGHT_FLIP)
				direction = -direction;

			// make up/down direction
			int idx = PLAYER_WING_ROLL_ARRAY_POS;
			float trackerInput = 0;

			trackerInput = rightWing->ang[idx] + (float) TRACKER_BODY_ROLL_OFFSET;
			float rollRight = (trackerInput - player.calibratedRightWing.ang[idx]) / PLAYER_WING_ROLL_SCALE;
			
			trackerInput = leftWing->ang[idx] + (float) TRACKER_BODY_ROLL_OFFSET;
			float rollLeft = (trackerInput - player.calibratedLeftWing.ang[idx]) / PLAYER_WING_ROLL_SCALE;

			ydirection = (rollRight + rollLeft) / 2.0f;	// middle of both wing roll angles
			if (PLAYER_WING_ROLL_FLIP)
				ydirection = -ydirection;				
		}
		else
		{
			// move left, right according to mouse x-movement
			// animate the wings according to mouse y-movement
			position2d<f32> cursorPos = device->getCursorControl()->getRelativePosition(); 
			    
			float change_x = ( cursorPos.X - 0.5f ) * 128.f;
			float change_y = ( cursorPos.Y - 0.5f ) * 128.f;
			direction += change_x; 
			ydirection -= change_y; 
			if( ydirection < -CAMERA_Y_DIRECTION_MAX ) 
				ydirection = -CAMERA_Y_DIRECTION_MAX; 
			else 
			if( ydirection > CAMERA_Y_DIRECTION_MAX ) 
				ydirection = CAMERA_Y_DIRECTION_MAX; 
			device->getCursorControl()->setPosition( 0.5f, 0.5f ); 
			
			animateLeftWing(ydirection, -CAMERA_Y_DIRECTION_MAX, CAMERA_Y_DIRECTION_MAX);
			animateRightWing(ydirection, -CAMERA_Y_DIRECTION_MAX, CAMERA_Y_DIRECTION_MAX);
		}
	}
}


void demoInit()
{
	for (int i=0; i<3; i++)
	{
		time[i]->setVisible(false);
	}

	soundWindAdjust(0);
	ISceneNodeAnimator* flyer = smgr->createFlyCircleAnimator(player.node->getPosition()+v3(0,27,0), 10.0f, 0.0005f);
	cam->addAnimator(flyer);
	flyer->drop();
	spotLight = smgr->addLightSceneNode(0, v3(0,0,0), SColorf(0.2f, 0.2f, 1.0f), 32.0f, -1);
	billB = smgr->addBillboardSceneNode(spotLight, dimension2d<f32>(20, 20));
	billB->setMaterialFlag(EMF_LIGHTING, false);
	billB->setMaterialType(EMT_TRANSPARENT_ADD_COLOR);
	billB->setMaterialTexture(0, driver->getTexture(makeMediaString(MEDIAFILE_TEXTURE_LIGHT).c_str() ) );
	flyer = smgr->createFlyCircleAnimator(player.node->getPosition() + v3(0,20,0), 30.0f, 0.0004f);
	spotLight->addAnimator(flyer);
	flyer->drop();
	arrow->setVisible(false);
	logo->setVisible(true);
	logo->setRelativePosition(rect<s32>(SCREEN_X+40, SCREEN_Y-30, SCREEN_X+10+128, SCREEN_Y-30+128));

	cam->setFarValue(10000);
	oldTime = timer->getTime();
}


void demo()
{
	static float sinCnt = 0;
	static float sinCnt2 = 0; sinCnt2 += 0.1f;

	list<Obj*>::Iterator it = objects.begin();
	while(it != objects.end())
	{
		(*it)->node->setRotation( (*it)->node->getRotation() + (*it)->rot );
		if ( (*it)->pssn != 0)
		{
			v3 circle(300.0f * sin(sinCnt2), 300.0f * cos(sinCnt2), 0);
			(*it)->pssn->setPosition((*it)->node->getPosition() + circle);
		}
		it++;
	}
	sinCnt += 0.01f;
	player.node->setPosition(player.node->getPosition() + v3(0, sin(sinCnt)/6.0f, 0));
	cam->setTarget(player.node->getPosition());
	
	if (oldTime + 10000 < timer->getTime())
	{
		if (logo->getRelativePosition().UpperLeftCorner.X > SCREEN_X-105)
			logo->move( position2d<s32>(-1, 0) );
		if (logo->getRelativePosition().UpperLeftCorner.X <= SCREEN_X-105)
		{
			if (oldTime + 16000 < timer->getTime())
                logo->move( position2d<s32>(0, +1) );
		}
		if (logo->getRelativePosition().UpperLeftCorner.Y > SCREEN_Y+40)
		{
			logo->setRelativePosition(rect<s32>(SCREEN_X+40, SCREEN_Y-30, SCREEN_X+10+128, SCREEN_Y-30+128));
			oldTime = timer->getTime();
		}
	}
} 


void demoClose()
{
	player.node->removeAnimators();
	spotLight->removeAnimators();
	spotLight->remove();
	spotLight = 0;
	billB = 0;
}

