tge/engine/ts/tsCollision.cc
2017-04-17 06:17:10 -06:00

399 lines
11 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "ts/tsShapeInstance.h"
#include "sim/sceneObject.h"
//-------------------------------------------------------------------------------------
// Collision methods
//-------------------------------------------------------------------------------------
bool TSShapeInstance::buildPolyList(AbstractPolyList * polyList, S32 dl)
{
// if dl==-1, nothing to do
if (dl==-1)
return false;
AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
// get subshape and object detail
const TSDetail * detail = &mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// set up static data
setStatics(dl);
// nothing emitted yet...
bool emitted = false;
U32 surfaceKey = 0;
S32 start = mShape->subShapeFirstObject[ss];
S32 end = mShape->subShapeNumObjects[ss] + start;
if (start<end)
{
MatrixF initialMat;
Point3F initialScale;
polyList->getTransform(&initialMat,&initialScale);
// set up for first object's node
MatrixF mat;
MatrixF scaleMat(true);
F32* p = scaleMat;
p[0] = initialScale.x;
p[5] = initialScale.y;
p[10] = initialScale.z;
MatrixF * previousMat = mMeshObjects[start].getTransform();
mat.mul(initialMat,scaleMat);
mat.mul(*previousMat);
polyList->setTransform(&mat,Point3F(1, 1, 1));
// run through objects and collide
for (S32 i=start; i<end; i++)
{
MeshObjectInstance * mesh = &mMeshObjects[i];
if (od >= mesh->object->numMeshes)
continue;
if (mesh->getTransform() != previousMat)
{
// different node from before, set up for this node
previousMat = mesh->getTransform();
if (previousMat != NULL)
{
mat.mul(initialMat,scaleMat);
mat.mul(*previousMat);
polyList->setTransform(&mat,Point3F(1, 1, 1));
}
}
// collide...
emitted |= mesh->buildPolyList(od,polyList,surfaceKey);
}
// restore original transform...
polyList->setTransform(&initialMat,initialScale);
}
clearStatics();
return emitted;
}
bool TSShapeInstance::getFeatures(const MatrixF& mat, const Point3F& n, ConvexFeature* cf, S32 dl)
{
// if dl==-1, nothing to do
if (dl==-1)
return false;
AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
// get subshape and object detail
const TSDetail * detail = &mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// set up static data
setStatics(dl);
// nothing emitted yet...
bool emitted = false;
U32 surfaceKey = 0;
S32 start = mShape->subShapeFirstObject[ss];
S32 end = mShape->subShapeNumObjects[ss] + start;
if (start<end)
{
MatrixF final;
MatrixF* previousMat = mMeshObjects[start].getTransform();
final.mul(mat, *previousMat);
// run through objects and collide
for (S32 i=start; i<end; i++)
{
MeshObjectInstance * mesh = &mMeshObjects[i];
if (od >= mesh->object->numMeshes)
continue;
if (mesh->getTransform() != previousMat)
{
previousMat = mesh->getTransform();
final.mul(mat, *previousMat);
}
emitted |= mesh->getFeatures(od, final, n, cf, surfaceKey);
}
}
clearStatics();
return emitted;
}
bool TSShapeInstance::castRay(const Point3F & a, const Point3F & b, RayInfo * rayInfo, S32 dl)
{
// if dl==-1, nothing to do
if (dl==-1)
return false;
AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::buildPolyList");
// get subshape and object detail
const TSDetail * detail = &mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// set up static data
setStatics(dl);
S32 start = mShape->subShapeFirstObject[ss];
S32 end = mShape->subShapeNumObjects[ss] + start;
RayInfo saveRay;
saveRay.t = 1.0f;
const MatrixF * saveMat = NULL;
bool found = false;
if (start<end)
{
Point3F ta, tb;
// set up for first object's node
MatrixF mat;
MatrixF * previousMat = mMeshObjects[start].getTransform();
mat = *previousMat;
mat.inverse();
mat.mulP(a,&ta);
mat.mulP(b,&tb);
// run through objects and collide
for (S32 i=start; i<end; i++)
{
MeshObjectInstance * mesh = &mMeshObjects[i];
if (od >= mesh->object->numMeshes)
continue;
if (mesh->getTransform() != previousMat)
{
// different node from before, set up for this node
previousMat = mesh->getTransform();
if (previousMat != NULL)
{
mat = *previousMat;
mat.inverse();
mat.mulP(a,&ta);
mat.mulP(b,&tb);
}
}
// collide...
if (mesh->castRay(od,ta,tb,rayInfo))
{
if (!rayInfo)
{
clearStatics();
return true;
}
if (rayInfo->t <= saveRay.t)
{
saveRay = *rayInfo;
saveMat = previousMat;
}
found = true;
}
}
}
// collide with any skins for this detail level...
// TODO: if ever...
// finalize the deal...
if (found)
{
*rayInfo = saveRay;
saveMat->mulV(rayInfo->normal);
rayInfo->point = b-a;
rayInfo->point *= rayInfo->t;
rayInfo->point += a;
}
clearStatics();
return found;
}
Point3F TSShapeInstance::support(const Point3F & v, S32 dl)
{
// if dl==-1, nothing to do
AssertFatal(dl != -1, "Error, should never try to collide with a non-existant detail level!");
AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::support");
// get subshape and object detail
const TSDetail * detail = &mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// set up static data
setStatics(dl);
S32 start = mShape->subShapeFirstObject[ss];
S32 end = mShape->subShapeNumObjects[ss] + start;
const MatrixF * saveMat = NULL;
bool found = false;
F32 currMaxDP = -1e9f;
Point3F currSupport = Point3F(0, 0, 0);
MatrixF * previousMat = NULL;
MatrixF mat;
if (start<end)
{
Point3F va;
// set up for first object's node
previousMat = mMeshObjects[start].getTransform();
mat = *previousMat;
mat.inverse();
// run through objects and collide
for (S32 i=start; i<end; i++)
{
MeshObjectInstance * mesh = &mMeshObjects[i];
if (od >= mesh->object->numMeshes)
continue;
TSMesh* physMesh = mesh->getMesh(od);
if (physMesh && mesh->visible > 0.01f)
{
// collide...
F32 saveMDP = currMaxDP;
if (mesh->getTransform() != previousMat)
{
// different node from before, set up for this node
previousMat = mesh->getTransform();
mat = *previousMat;
mat.inverse();
}
mat.mulV(v, &va);
physMesh->support(mesh->frame, va, &currMaxDP, &currSupport);
}
}
}
clearStatics();
if (currMaxDP != -1e9f)
{
previousMat->mulP(currSupport);
return currSupport;
}
else
{
return Point3F(0, 0, 0);
}
}
void TSShapeInstance::computeBounds(S32 dl, Box3F & bounds)
{
// if dl==-1, nothing to do
if (dl==-1)
return;
AssertFatal(dl>=0 && dl<mShape->details.size(),"TSShapeInstance::computeBounds");
// get subshape and object detail
const TSDetail * detail = &mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// set up static data
setStatics(dl);
S32 start = mShape->subShapeFirstObject[ss];
S32 end = mShape->subShapeNumObjects[ss] + start;
// run through objects and updating bounds as we go
bounds.min.set( 10E30f, 10E30f, 10E30f);
bounds.max.set(-10E30f,-10E30f,-10E30f);
Box3F box;
for (S32 i=start; i<end; i++)
{
MeshObjectInstance * mesh = &mMeshObjects[i];
if (od >= mesh->object->numMeshes)
continue;
if (mesh->getMesh(od))
{
mesh->getMesh(od)->computeBounds(*mesh->getTransform(),box);
bounds.min.setMin(box.min);
bounds.max.setMax(box.max);
}
}
clearStatics();
}
//-------------------------------------------------------------------------------------
// Object (MeshObjectInstance & PluginObjectInstance) collision methods
//-------------------------------------------------------------------------------------
bool TSShapeInstance::ObjectInstance::buildPolyList(S32 objectDetail, AbstractPolyList * polyList, U32 & surfaceKey)
{
objectDetail,polyList,surfaceKey;
AssertFatal(0,"TSShapeInstance::ObjectInstance::buildPolyList: no default method.");
return false;
}
bool TSShapeInstance::ObjectInstance::getFeatures(S32 objectDetail, const MatrixF& mat, const Point3F& n, ConvexFeature* cf, U32& surfaceKey)
{
objectDetail,mat, n, cf, surfaceKey;
AssertFatal(0,"TSShapeInstance::ObjectInstance::buildPolyList: no default method.");
return false;
}
void TSShapeInstance::ObjectInstance::support(S32, const Point3F&, F32*, Point3F*)
{
AssertFatal(0,"TSShapeInstance::ObjectInstance::supprt: no default method.");
}
bool TSShapeInstance::ObjectInstance::castRay(S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo * rayInfo)
{
objectDetail,start,end,rayInfo;
AssertFatal(0,"TSShapeInstance::ObjectInstance::castRay: no default method.");
return false;
}
bool TSShapeInstance::MeshObjectInstance::buildPolyList(S32 objectDetail, AbstractPolyList * polyList, U32 & surfaceKey)
{
TSMesh * mesh = getMesh(objectDetail);
if (mesh && visible>0.01f)
return mesh->buildPolyList(frame,polyList,surfaceKey);
return false;
}
bool TSShapeInstance::MeshObjectInstance::getFeatures(S32 objectDetail, const MatrixF& mat, const Point3F& n, ConvexFeature* cf, U32& surfaceKey)
{
TSMesh* mesh = getMesh(objectDetail);
if (mesh && visible > 0.01f)
return mesh->getFeatures(frame, mat, n, cf, surfaceKey);
return false;
}
void TSShapeInstance::MeshObjectInstance::support(S32 objectDetail, const Point3F& v, F32* currMaxDP, Point3F* currSupport)
{
TSMesh* mesh = getMesh(objectDetail);
if (mesh && visible > 0.01f)
mesh->support(frame, v, currMaxDP, currSupport);
}
bool TSShapeInstance::MeshObjectInstance::castRay(S32 objectDetail, const Point3F & start, const Point3F & end, RayInfo * rayInfo)
{
TSMesh * mesh = getMesh(objectDetail);
if (mesh && visible>0.01f)
return mesh->castRay(frame,start,end,rayInfo);
return false;
}