
#include "btFractureBody.h"
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
#include "BulletCollision/CollisionShapes/btCompoundShape.h"
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"

void btFractureBody::recomputeConnectivity(btCollisionWorld* world)
{
	m_connections.clear();
	//@todo use the AABB tree to avoid N^2 checks

	if (getCollisionShape()->isCompound())
	{
		btCompoundShape* compound = (btCompoundShape*)getCollisionShape();
		for (int i = 0; i < compound->getNumChildShapes(); i++)
		{
			for (int j = i + 1; j < compound->getNumChildShapes(); j++)
			{
				struct MyContactResultCallback : public btCollisionWorld::ContactResultCallback
				{
					bool m_connected;
					btScalar m_margin;
					MyContactResultCallback() : m_connected(false), m_margin(0.05)
					{
					}
					virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1)
					{
						if (cp.getDistance() <= m_margin)
							m_connected = true;
						return 1.f;
					}
				};

				MyContactResultCallback result;

				btCollisionObject obA;
				obA.setWorldTransform(compound->getChildTransform(i));
				obA.setCollisionShape(compound->getChildShape(i));
				btCollisionObject obB;
				obB.setWorldTransform(compound->getChildTransform(j));
				obB.setCollisionShape(compound->getChildShape(j));
				world->contactPairTest(&obA, &obB, result);
				if (result.m_connected)
				{
					btConnection tmp;
					tmp.m_childIndex0 = i;
					tmp.m_childIndex1 = j;
					tmp.m_childShape0 = compound->getChildShape(i);
					tmp.m_childShape1 = compound->getChildShape(j);
					tmp.m_strength = 1.f;  //??
					m_connections.push_back(tmp);
				}
			}
		}
	}
}

btCompoundShape* btFractureBody::shiftTransformDistributeMass(btCompoundShape* boxCompound, btScalar mass, btTransform& shift)
{
	btVector3 principalInertia;

	btScalar* masses = new btScalar[boxCompound->getNumChildShapes()];
	for (int j = 0; j < boxCompound->getNumChildShapes(); j++)
	{
		//evenly distribute mass
		masses[j] = mass / boxCompound->getNumChildShapes();
	}

	return shiftTransform(boxCompound, masses, shift, principalInertia);
}

btCompoundShape* btFractureBody::shiftTransform(btCompoundShape* boxCompound, btScalar* masses, btTransform& shift, btVector3& principalInertia)
{
	btTransform principal;

	boxCompound->calculatePrincipalAxisTransform(masses, principal, principalInertia);

	///create a new compound with world transform/center of mass properly aligned with the principal axis

	///non-recursive compound shapes perform better

#ifdef USE_RECURSIVE_COMPOUND

	btCompoundShape* newCompound = new btCompoundShape();
	newCompound->addChildShape(principal.inverse(), boxCompound);
	newBoxCompound = newCompound;
	//m_collisionShapes.push_back(newCompound);

	//btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
	//btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,newCompound,principalInertia);

#else
#ifdef CHANGE_COMPOUND_INPLACE
	newBoxCompound = boxCompound;
	for (int i = 0; i < boxCompound->getNumChildShapes(); i++)
	{
		btTransform newChildTransform = principal.inverse() * boxCompound->getChildTransform(i);
		///updateChildTransform is really slow, because it re-calculates the AABB each time. todo: add option to disable this update
		boxCompound->updateChildTransform(i, newChildTransform);
	}
	bool isDynamic = (mass != 0.f);
	btVector3 localInertia(0, 0, 0);
	if (isDynamic)
		boxCompound->calculateLocalInertia(mass, localInertia);

#else
	///creation is faster using a new compound to store the shifted children
	btCompoundShape* newBoxCompound = new btCompoundShape();
	for (int i = 0; i < boxCompound->getNumChildShapes(); i++)
	{
		btTransform newChildTransform = principal.inverse() * boxCompound->getChildTransform(i);
		///updateChildTransform is really slow, because it re-calculates the AABB each time. todo: add option to disable this update
		newBoxCompound->addChildShape(newChildTransform, boxCompound->getChildShape(i));
	}

#endif

#endif  //USE_RECURSIVE_COMPOUND

	shift = principal;
	return newBoxCompound;
}
