#ifndef BT_COMPOUND_FROM_GIMPACT
#define BT_COMPOUND_FROM_GIMPACT

#include "BulletCollision/CollisionShapes/btCompoundShape.h"
#include "btGImpactShape.h"
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"

ATTRIBUTE_ALIGNED16(class)
btCompoundFromGimpactShape : public btCompoundShape
{
public:
	BT_DECLARE_ALIGNED_ALLOCATOR();

	virtual ~btCompoundFromGimpactShape()
	{
		/*delete all the btBU_Simplex1to4 ChildShapes*/
		for (int i = 0; i < m_children.size(); i++)
		{
			delete m_children[i].m_childShape;
		}
	}
};

struct MyCallback : public btTriangleRaycastCallback
{
	int m_ignorePart;
	int m_ignoreTriangleIndex;

	MyCallback(const btVector3& from, const btVector3& to, int ignorePart, int ignoreTriangleIndex)
		: btTriangleRaycastCallback(from, to),
		  m_ignorePart(ignorePart),
		  m_ignoreTriangleIndex(ignoreTriangleIndex)
	{
	}
	virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex)
	{
		if (partId != m_ignorePart || triangleIndex != m_ignoreTriangleIndex)
		{
			if (hitFraction < m_hitFraction)
				return hitFraction;
		}

		return m_hitFraction;
	}
};
struct MyInternalTriangleIndexCallback : public btInternalTriangleIndexCallback
{
	const btGImpactMeshShape* m_gimpactShape;
	btCompoundShape* m_colShape;
	btScalar m_depth;

	MyInternalTriangleIndexCallback(btCompoundShape* colShape, const btGImpactMeshShape* meshShape, btScalar depth)
		: m_colShape(colShape),
		  m_gimpactShape(meshShape),
		  m_depth(depth)
	{
	}

	virtual void internalProcessTriangleIndex(btVector3* triangle, int partId, int triangleIndex)
	{
		btVector3 scale = m_gimpactShape->getLocalScaling();
		btVector3 v0 = triangle[0] * scale;
		btVector3 v1 = triangle[1] * scale;
		btVector3 v2 = triangle[2] * scale;

		btVector3 centroid = (v0 + v1 + v2) / 3;
		btVector3 normal = (v1 - v0).cross(v2 - v0);
		normal.normalize();
		btVector3 rayFrom = centroid;
		btVector3 rayTo = centroid - normal * m_depth;

		MyCallback cb(rayFrom, rayTo, partId, triangleIndex);

		m_gimpactShape->processAllTrianglesRay(&cb, rayFrom, rayTo);
		if (cb.m_hitFraction < 1)
		{
			rayTo.setInterpolate3(cb.m_from, cb.m_to, cb.m_hitFraction);
			//rayTo = cb.m_from;
			//rayTo = rayTo.lerp(cb.m_to,cb.m_hitFraction);
			//gDebugDraw.drawLine(tr(centroid),tr(centroid+normal),btVector3(1,0,0));
		}

		btBU_Simplex1to4* tet = new btBU_Simplex1to4(v0, v1, v2, rayTo);
		btTransform ident;
		ident.setIdentity();
		m_colShape->addChildShape(ident, tet);
	}
};

btCompoundShape* btCreateCompoundFromGimpactShape(const btGImpactMeshShape* gimpactMesh, btScalar depth)
{
	btCompoundShape* colShape = new btCompoundFromGimpactShape();

	btTransform tr;
	tr.setIdentity();

	MyInternalTriangleIndexCallback cb(colShape, gimpactMesh, depth);
	btVector3 aabbMin, aabbMax;
	gimpactMesh->getAabb(tr, aabbMin, aabbMax);
	gimpactMesh->getMeshInterface()->InternalProcessAllTriangles(&cb, aabbMin, aabbMax);

	return colShape;
}

#endif  //BT_COMPOUND_FROM_GIMPACT
