//********************************************************************
// This source file is part of Ninfa3D Engine
// 
// Copyright (C) 2008-2009 Viz_fuerte.
// All rights reserved.
// 
// LIMITED WARRANTY
// This software is provided "as-is", without any express or implied warranty.
// In no event shall the author be held liable for any damages arising from the use of this software.
// This is a contract. By accepting the Ninfa3D Engine (the SOFTWARE), 
// you (either an individual or a single entity, the LICENSEE) accept the terms and conditions of this licensing agreement.
// 
// If the LICENSEE does not accept the terms and conditions, then LICENSEE must not accept the SOFTWARE.
// If at a later time the LICENSEE decides not to continue licensing the SOFTWARE under these terms and 
// conditions, then the LICENSEE must delete permanently all files constituting the SOFTWARE.
//
// File: CBodySceneNode.cpp
//********************************************************************

/*--------------------------------------------------------------------
Includos*/

	#include "CVehicleSceneNode.h"

/*--------------------------------------------------------------------
Variables externas*/

	extern NewtonWorld* nWorld;
	extern IVideoDriver* driver;
	extern int defaultMaterialID;

#define CUSTOM_VEHICLE_JOINT_ID		0xF4ED

/*--------------------------------------------------------------------
Declaracion global de funciones*/

	void _cdecl SetVehicleTransformEvent(const NewtonBody* body,const float* matrix,int threadIndex);
	void _cdecl NewtonCollisionDebug2(void* userData, int vertexCount, const float* FaceArray, int id);

	//Constructor
	CVehicleSceneNode::CVehicleSceneNode(ISceneNode* parent,ISceneManager* mgr,s32 id):ISceneNode(parent,mgr,id)
	{
	}

	//Destructor
	CVehicleSceneNode::~CVehicleSceneNode()
	{
	}

	//Crea un cuerpo vacio
	void CVehicleSceneNode::addVehicle(float X,float Y,float Z,float DX,float DY,float DZ,NewtonBody* carBody)
	{
		NewtonBodySetTransformCallback(carBody,SetVehicleTransformEvent);
		
		// set the vehicle local coordinate system 
		dMatrix chassisMatrix;
		chassisMatrix.m_front = dVector (DX,DY,DZ, 0);				// this is the vehicle direction of travel
		chassisMatrix.m_up	  = dVector (0.0f, 1.0f, 0.0f, 0.0f);			// this is the downward vehicle direction
		chassisMatrix.m_right = chassisMatrix.m_front * chassisMatrix.m_up;	// this is in the side vehicle direction (the plane of the wheels)
		chassisMatrix.m_posit = dVector (0.0f, 0.0f, 0.0f, 1.0f);

		NewtonBodySetMaterialGroupID(carBody,defaultMaterialID);

		Vehicle = new CustomDGRayCastCar(4,chassisMatrix,carBody);
		((CustomDGRayCastCar*)Vehicle)->SetJointID(CUSTOM_VEHICLE_JOINT_ID);

		NewtonBodySetAutoSleep(((CustomDGRayCastCar*)Vehicle)->GetBody0(),0);
		//((CustomDGRayCastCar*)Vehicle)->SetVarChassisRotationLimit(0.98f);
		//((CustomDGRayCastCar*)Vehicle)->SetVarMaxBrakeForce(165.0f);
		//((CustomDGRayCastCar*)Vehicle)->SetVarMaxTorque(5000.0f);
		//((CustomDGRayCastCar*)Vehicle)->SetVarMaxTorqueRate(500.0f);
		//((CustomDGRayCastCar*)Vehicle)->SetVarMaxSteerRate(0.1f);
		//((CustomDGRayCastCar*)Vehicle)->SetVarEngineSteerDiv(200.0f);
	}

	//Crea un cuerpo vacio
	void CVehicleSceneNode::addTire(void* userData,float X,float Y,float Z,float mass,float radius,float width,float friction,float suspensionLength,float springConst,float springDamper)
	{
		dVector localPosition(X,Y,Z);
		((CustomDGRayCastCar*)Vehicle)->AddSingleSuspensionTire(userData,&localPosition[0],mass,radius,width,friction,suspensionLength,springConst,springDamper,1);
	}

	//Crea un cuerpo vacio
	void CVehicleSceneNode::setApplyBrake(int index,float torque)
	{
		//dFloat vEngineBrake = ((CustomDGRayCastCar*)Vehicle)->GenerateTiresBrake(torque);
		// Set the generate brake value
		//((CustomDGRayCastCar*)Vehicle)->SetCustomTireBrake(index, vEngineBrake );
		((CustomDGRayCastCar*)Vehicle)->SetTireBrake(index, torque );
	}

	//Crea un cuerpo vacio
	void CVehicleSceneNode::setApplyTorque(int index,float value)
	{
		dFloat vEngineTorque = ((CustomDGRayCastCar*)Vehicle)->GenerateEngineTorque(value);
		// Set the generate torque value
		//((CustomDGRayCastCar*)Vehicle)->SetCustomTireTorque(index,vEngineTorque);
		((CustomDGRayCastCar*)Vehicle)->SetTireTorque(index,vEngineTorque);
	}

	//Crea un cuerpo vacio
	void CVehicleSceneNode::setApplySteering(int index,float value)
	{
		//((CustomDGRayCastCar*)Vehicle)->SetVarMaxSteerAngle(abs(value2)*30);
		dFloat vEngineSteerAngle = ((CustomDGRayCastCar*)Vehicle)->GenerateTiresSteerAngle(value);
		dFloat vEngineSteerForce = ((CustomDGRayCastCar*)Vehicle)->GenerateTiresSteerForce(vEngineSteerAngle);
		// Set the both generate steer angle and force value's
		((CustomDGRayCastCar*)Vehicle)->SetTireSteerAngleForce(index,vEngineSteerAngle,vEngineSteerForce);
	}
	/*
	void CVehicleSceneNode::setApplySteering(int index,float value1,float value2)
	{
		((CustomDGRayCastCar*)Vehicle)->SetVarMaxSteerAngle(abs(value2)*30);
		dFloat vEngineSteerAngle = ((CustomDGRayCastCar*)Vehicle)->GenerateTiresSteerAngle(value1);
		dFloat vEngineSteerForce = ((CustomDGRayCastCar*)Vehicle)->GenerateTiresSteerForce(vEngineSteerAngle);
		// Set the both generate steer angle and force value's
		((CustomDGRayCastCar*)Vehicle)->SetTireSteerAngleForce(index,vEngineSteerAngle,vEngineSteerForce);
	}
	*/
	//Crea un cuerpo vacio
	float CVehicleSceneNode::getVehicleSpeed()
	{
		return ((CustomDGRayCastCar*)Vehicle)->GetSpeed();
	}

	void CVehicleSceneNode::remove()
	{
		CustomDestroyJoint((NewtonUserJoint*) Vehicle);
	}

	void CVehicleSceneNode::OnPreRender()
	{
	}

	void CVehicleSceneNode::render()
	{
	}

	SMaterial& CVehicleSceneNode::getMaterial(s32 i)
	{
		return material;
	}

	const aabbox3d<f32>& CVehicleSceneNode::getBoundingBox() const
	{
		return BBox;
	}

	void _cdecl SetVehicleTransformEvent(const NewtonBody* body,const float* matrix,int threadIndex)
	{
		matrix4 mat;
		memcpy(mat.pointer(),matrix,sizeof(float)*16);

		ISceneNode* tmp1 = (ISceneNode*)NewtonBodyGetUserData(body);

		if(tmp1)
		{
			tmp1->setPosition(mat.getTranslation());
			tmp1->setRotation(mat.getRotationDegrees());
		}

		NewtonJoint* joint;
		CustomDGRayCastCar* car;

		for(joint = NewtonBodyGetFirstJoint(body);joint;joint = NewtonBodyGetNextJoint(body,joint))
		{
			car = (CustomDGRayCastCar*)NewtonJointGetUserData(joint);
			if(car->GetJointID() == CUSTOM_VEHICLE_JOINT_ID)
				break;
		}

		for(int i = 0;i<car->GetTiresCount();++i)
		{
			const CustomDGRayCastCar::Tire& tire = car->GetTire(i);
	
			ISceneNode* tmp2 = (ISceneNode*)tire.m_userData;

			dMatrix matrix2(car->CalculateTireMatrix(i));

			matrix4 mat3;
			memcpy(mat3.pointer(),&matrix2[0][0],sizeof(float)*16);

			if(tmp2)
			{
				tmp2->setPosition(mat3.getTranslation());
				tmp2->setRotation(mat3.getRotationDegrees());
			}
		}
	}

	void _cdecl NewtonCollisionDebug2(void* userData, int vertexCount, const float* FaceArray, int id)
	{
	   vector3df p0(FaceArray[0], FaceArray[1], FaceArray[2]);
	   const SColor c0(0, 0, 255, 0);
	   for(int i = 2; i < vertexCount; i ++)
	   {
		  vector3df p1(FaceArray[(i-1) * 3 + 0], FaceArray[(i-1) * 3 + 1], FaceArray[(i-1) * 3 + 2]);
		  vector3df p2(FaceArray[i * 3 + 0], FaceArray[i * 3 + 1], FaceArray[i * 3 + 2]);
		  triangle3df t;
		  t.set(p1, p2, p0);
		  driver->draw3DTriangle(t, c0);
		}
	}