#include "CollisionShape.h"

CollisionShape::CollisionShape(void)
{
}

CollisionShape::~CollisionShape(void)
{
	m_Shapes.Clear();
}

NxActor* CollisionShape::BuildActor(PhysicsScene* const scene, const float scale, const float mass)
{
	//if(m_Shapes.GetElementCount())
	{
		//LList<NxShapeDesc> shapes;

		NxBodyDesc body;
		NxBoxShapeDesc temp;
		NxActorDesc ActorDesc;
		
		
		temp.dimensions.set(0.2f, 0.4f, 0.1f);
		ActorDesc.shapes.push_back(&temp);

		if(mass > 0)
			body.mass = mass;
		else
			body.mass = 1;

		ActorDesc.body = &body; 
		

		NxActor* Actor = scene->GetScene()->createActor(ActorDesc);
		//return Actor;

		NxVec3 cmass(0, 0, 0);
		NxVec3 cmassavg(0, 0, 0);

		float summass = 0;
		FOREACH(shape, m_Shapes, ShapeDesc)
		{
			DXMatrix matPose = shape->GetInfo()->LocalPose;
			matPose._41 *= scale;
			matPose._42 *= scale;
			matPose._43 *= scale;

			if (shape->GetInfo()->Mass > 0)
			{
				summass += shape->GetInfo()->Mass;
				cmass += NxVec3(matPose._41, matPose._42, matPose._43) * shape->GetInfo()->Mass;
			}

			cmassavg += NxVec3(matPose._41, matPose._42, matPose._43);

			if(shape->GetInfo()->Type == SHAPE_BOX)
			{
				NxBoxShapeDesc nxbox;// = new NxBoxShapeDesc();
				BoxShapeDesc* box = (BoxShapeDesc*)shape->GetInfo();

				if	(box->Mass > 0)
					nxbox.mass = box->Mass;
				nxbox.dimensions = NxVec3(box->Dimensions.x, box->Dimensions.y, box->Dimensions.z) * scale;
				nxbox.localPose.setColumnMajor44((float*)&matPose);
				nxbox.shapeFlags |= NX_SF_VISUALIZATION;

				Actor->createShape(nxbox);
				//shapes.AddTail(nxbox, 0);
				//ActorDesc.shapes.push_back(nxbox);
			}
			else if(shape->GetInfo()->Type == SHAPE_SPHERE)
			{
				NxSphereShapeDesc nxsphere;// = new NxSphereShapeDesc();
				SphereShapeDesc* sphere = (SphereShapeDesc*)shape->GetInfo();

				if	(sphere->Mass > 0)
					nxsphere.mass = sphere->Mass;
				nxsphere.radius = sphere->Radius * scale;
				nxsphere.localPose.setColumnMajor44((float*)&matPose);
				nxsphere.shapeFlags |= NX_SF_VISUALIZATION;

				Actor->createShape(nxsphere);
				//shapes.AddTail(nxsphere, 0);
				//ActorDesc.shapes.push_back(nxsphere);
			}
			else if(shape->GetInfo()->Type == SHAPE_CAPSULE)
			{
				NxCapsuleShapeDesc nxcapsule;// = new NxCapsuleShapeDesc();
				CapsuleShapeDesc* capsule = (CapsuleShapeDesc*)shape->GetInfo();

				if	(capsule->Mass > 0)
					nxcapsule.mass = capsule->Mass;
				nxcapsule.radius = capsule->Radius * scale;
				nxcapsule.height = capsule->Height * scale;
				nxcapsule.localPose.setColumnMajor44((float*)&matPose);
				nxcapsule.shapeFlags |= NX_SF_VISUALIZATION;

				Actor->createShape(nxcapsule);
				//shapes.AddTail(nxcapsule, 0);
				//ActorDesc.shapes.push_back(nxcapsule);
			}
			else if(shape->GetInfo()->Type == SHAPE_MESH)
			{
				NxTriangleMeshShapeDesc nxmesh;
				MeshShapeDesc* mesh = (MeshShapeDesc*)shape->GetInfo();

				if	(mesh->Mass > 0)
					nxmesh.mass = mesh->Mass;
				nxmesh.localPose.setColumnMajor44((float*)&matPose);
				nxmesh.shapeFlags |= NX_SF_VISUALIZATION;

				//Actor->createShape(nxmesh);
			}
		}
		
		Actor->releaseShape(*(Actor->getShapes()[0]));
		
		//shapes.Clear();

		//Actor->setMass(summass);
		if(mass == 0)
		{
			if (summass > 0)
			{
				Actor->updateMassFromShapes(0, summass);
				cmass *= 1 / summass;
				Actor->setCMassOffsetLocalPosition(cmass);
			}
			else
			{
				Actor->setMass(1);
				cmassavg *= 1 / (float)m_Shapes.GetElementCount();
				Actor->setCMassOffsetLocalPosition(cmass);
			}
		}

		return Actor;
	}
//	else
//	{
//		return NULL;
//	}
}

void CollisionShape::Read(FILE* const f)
{
	unsigned collshapecount = 0;
	fread(&collshapecount, sizeof(unsigned), 1, f);

	while(collshapecount--)
	{
		NxShapeType type;
		fread(&type, sizeof(NxShapeType), 1, f);
		
		ShapeDesc* shapedesc = NULL;

		if(type == SHAPE_BOX)
		{
			BoxShapeDesc* box = new BoxShapeDesc();

			fread(&box->Mass, sizeof(box->Mass), 1, f);
			fread(&box->LocalPose, sizeof(box->LocalPose), 1, f);
			fread(&box->Dimensions, sizeof(box->Dimensions), 1, f);
			
			shapedesc = box;
		}
		else if(type == SHAPE_SPHERE)
		{
			SphereShapeDesc* sphere = new SphereShapeDesc();
			
			fread(&sphere->Mass, sizeof(sphere->Mass), 1, f);
			fread(&sphere->LocalPose, sizeof(sphere->LocalPose), 1, f);
			fread(&sphere->Radius, sizeof(sphere->Radius), 1, f);
			
			shapedesc = sphere;
		}
		else if(type == SHAPE_CAPSULE)
		{
			CapsuleShapeDesc* capsule = new CapsuleShapeDesc();

			fread(&capsule->Mass, sizeof(capsule->Mass), 1, f);
			fread(&capsule->LocalPose, sizeof(capsule->LocalPose), 1, f);
			fread(&capsule->Radius, sizeof(capsule->Radius), 1, f);
			fread(&capsule->Height, sizeof(capsule->Height), 1, f);
			
			shapedesc = capsule;
		}
		else if(type == SHAPE_MESH)
		{
			MeshShapeDesc* mesh = new MeshShapeDesc();

			fread(&mesh->Mass, sizeof(mesh->Mass), 1, f);
			fread(&mesh->LocalPose, sizeof(mesh->LocalPose), 1, f);
			
			mesh->Filename.Read(f);
			fread(&mesh->Scale, sizeof(mesh->Scale), 1, f);

			shapedesc = mesh;
		}

		if(shapedesc)
		{
			m_Shapes.AddTail(shapedesc, 0);
		}
	}
}

void CollisionShape::Write(FILE* const f) const
{
	unsigned shapecount = m_Shapes.GetElementCount();
	fwrite(&shapecount, sizeof(unsigned), 1, f);

	FOREACH(shape, m_Shapes, ShapeDesc)
	{
		SHAPETYPE type = shape->GetInfo()->Type;
		
		if(type == SHAPE_BOX)
		{
			fwrite(shape->GetInfo(), sizeof(BoxShapeDesc), 1, f);
		}
		else if(type == SHAPE_SPHERE)
		{
			fwrite(shape->GetInfo(), sizeof(SphereShapeDesc), 1, f);
		}
		else if(type == SHAPE_CAPSULE)
		{
			fwrite(shape->GetInfo(), sizeof(CapsuleShapeDesc), 1, f);
		}
		else if(type == SHAPE_MESH)
		{
			fwrite(shape->GetInfo(), sizeof(ShapeDesc), 1, f);
		
			MeshShapeDesc* mesh = (MeshShapeDesc*)shape->GetInfo();
			mesh->Filename.Write(f);

			fwrite(&mesh->Scale, sizeof(mesh->Scale), 1, f);
		}
	}
}