
#include "lib_collider.h"


#define LIBID			LIB_COLLIDERCACHE
#define LIB				ColliderCacheLib

static LIB *library_cache = NULL;


static LIB *CheckLibCache(LONG offset)
{
	return (LIB*)CheckLib(LIBID,offset,(C4DLibrary**)&library_cache);
}

GeColliderCache::GeColliderCache()
{
}

GeColliderCache* GeColliderCache::Alloc()
{
	LIB *lib = CheckLibCache(LIBOFFSET(LIB,Alloc)); if (!lib || !lib->Alloc) return NULL;
	return lib->Alloc();
}

void GeColliderCache::Free(GeColliderCache *&data)
{
	LIB *lib = CheckLibCache(LIBOFFSET(LIB,Free)); if (!lib || !lib->Free) return;
	lib->Free(data);
}

Bool GeColliderCache::CopyTo(GeColliderCache *dest)
{
	LIB *lib = CheckLibCache(LIBOFFSET(LIB,CopyTo)); if (!lib || !lib->CopyTo) return FALSE;
	return (this->*lib->CopyTo)(dest);
}

LONG GeColliderCache::BeginInput(LONG cnt_tris)
{
	LIB *lib = CheckLibCache(LIBOFFSET(LIB,BeginInput)); if (!lib || !lib->BeginInput) return FALSE;
	return (this->*lib->BeginInput)(cnt_tris);
}

LONG GeColliderCache::AddTriangle(const Vector& p1, const Vector& p2, const Vector& p3, LONG id)
{
	LIB *lib = CheckLibCache(LIBOFFSET(LIB,AddTriangle)); if (!lib || !lib->AddTriangle) return FALSE;
	return (this->*lib->AddTriangle)(p1,p2,p3,id);
}

LONG GeColliderCache::EndInput()
{
	LIB *lib = CheckLibCache(LIBOFFSET(LIB,EndInput)); if (!lib || !lib->EndInput) return FALSE;
	return (this->*lib->EndInput)();
}



//////////////////////////////////////////////////////


#undef LIBID
#undef LIB

#define LIBID			LIB_COLLIDERENGINE
#define LIB				ColliderEngineLib

static LIB *library_engine = NULL;


static LIB *CheckLibEngine(LONG offset)
{
	return (LIB*)CheckLib(LIBID,offset,(C4DLibrary**)&library_engine);
}

GeColliderEngine::GeColliderEngine()
{
}

GeColliderEngine* GeColliderEngine::Alloc()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,Alloc)); if (!lib || !lib->Alloc) return NULL;
	return lib->Alloc();
}

void GeColliderEngine::Free(GeColliderEngine *&data)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,Free)); if (!lib || !lib->Free) return;
	lib->Free(data);
}

LONG GeColliderEngine::DoCollide(const Matrix& M1, GeColliderCache *o1, const Matrix& M2, GeColliderCache *o2, LONG flag)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,DoCollide)); if (!lib || !lib->DoCollide) return FALSE;
	return (this->*lib->DoCollide)(M1,o1,M2,o2,flag);
}

LONG GeColliderEngine::DoPolyPairs(const Matrix& M1, GeColliderCache *o1, const Matrix& M2, GeColliderCache *o2, Real tolerance)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,DoPolyPairs)); if (!lib || !lib->DoPolyPairs) return FALSE;
	return (this->*lib->DoPolyPairs)(M1,o1,M2,o2,tolerance);
}

LONG GeColliderEngine::DoTolerance(const Matrix& M1, GeColliderCache *o1, const Matrix& M2, GeColliderCache *o2, Real tolerance)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,DoTolerance)); if (!lib || !lib->DoTolerance) return FALSE;
	return (this->*lib->DoTolerance)(M1,o1,M2,o2,tolerance);
}

LONG GeColliderEngine::DoDistance(const Matrix& M1, GeColliderCache *o1, const Matrix& M2, GeColliderCache *o2, Real rel_err, Real abs_err)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,DoDistance)); if (!lib || !lib->DoDistance) return FALSE;
	return (this->*lib->DoDistance)(M1,o1,M2,o2,rel_err,abs_err);
}

LONG GeColliderEngine::DoRayCollide(GeColliderCache *o1, const Vector &ray_p, const Vector &ray_dir, Real ray_length)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,DoRayCollide)); if (!lib || !lib->DoRayCollide) return FALSE;
	return (this->*lib->DoRayCollide)(o1, ray_p, ray_dir, ray_length);
}

void GeColliderEngine::FreePairsList()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,FreePairsList)); if (!lib || !lib->FreePairsList) return;
	(this->*lib->FreePairsList)();
}

LONG GeColliderEngine::GetNumPairs()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,GetNumPairs)); if (!lib || !lib->GetNumPairs) return FALSE;
	return (this->*lib->GetNumPairs)();
}

LONG GeColliderEngine::GetId1(LONG k)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,GetId1)); if (!lib || !lib->GetId1) return FALSE;
	return (this->*lib->GetId1)(k);
}

LONG GeColliderEngine::GetId2(LONG k)
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,GetId2)); if (!lib || !lib->GetId2) return FALSE;
	return (this->*lib->GetId2)(k);
}

Bool GeColliderEngine::IsCloser()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,IsCloser)); if (!lib || !lib->IsCloser) return FALSE;
	return (this->*lib->IsCloser)();
}

Real GeColliderEngine::GetDistance()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,GetDistance)); if (!lib || !lib->GetDistance) return FALSE;
	return (this->*lib->GetDistance)();
}

static Vector dummy;

const Vector& GeColliderEngine::GetP1()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,GetP1)); if (!lib || !lib->GetP1) return dummy;
	return (this->*lib->GetP1)();
}

const Vector& GeColliderEngine::GetP2()
{
	LIB *lib = CheckLibEngine(LIBOFFSET(LIB,GetP2)); if (!lib || !lib->GetP2) return dummy;
	return (this->*lib->GetP2)();
}


//////////////////////////////////////////////////////


#undef LIBID
#undef LIB

#define LIBID			LIB_RAYCOLLIDER
#define LIB				RayColliderLib

static LIB *library_ray = NULL;


static LIB *CheckLibRay(LONG offset)
{
	return (LIB*)CheckLib(LIBID,offset,(C4DLibrary**)&library_ray);
}

GeRayCollider::GeRayCollider()
{
}

GeRayCollider* GeRayCollider::Alloc()
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,Alloc)); if (!lib || !lib->Alloc) return NULL;
	return lib->Alloc();
}

void GeRayCollider::Free(GeRayCollider *&data)
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,Free)); if (!lib || !lib->Free) return;
	lib->Free(data);
}
Bool GeRayCollider::Init(BaseObject *object, Bool force)
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,Init)); if (!lib || !lib->Init) return FALSE;
	return (this->*lib->Init)(object, force);
}

Bool GeRayCollider::Intersect(const Vector &ray_p, const Vector &ray_dir, Real ray_length, Bool only_test)
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,Intersect)); if (!lib || !lib->Intersect) return FALSE;
	return (this->*lib->Intersect)(ray_p, ray_dir, ray_length, only_test);
}

LONG GeRayCollider::GetIntersectionCount()
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,GetIntersectionCount)); if (!lib || !lib->GetIntersectionCount) return 0;
	return (this->*lib->GetIntersectionCount)();
}

Bool GeRayCollider::GetIntersection(LONG n, GeRayColResult *result)
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,GetIntersection)); if (!lib || !lib->GetIntersection) return FALSE;
	return (this->*lib->GetIntersection)(n, result);
}

Bool GeRayCollider::GetNearestIntersection(GeRayColResult *result)
{
	LIB *lib = CheckLibRay(LIBOFFSET(LIB,GetNearestIntersection)); if (!lib || !lib->GetNearestIntersection) return FALSE;
	return (this->*lib->GetNearestIntersection)(result);
}
