deargui-vpl/ref/virtools/Samples/Behaviors/Collision/Managers/CKCollisionManager_AdvancedIntersectionFunctions.cpp

719 lines
23 KiB
C++

/*************************************************************************/
/* File : CollisionManager.cpp */
/* */
/*************************************************************************/
#include "CKAll.h"
#include "CollisionManager.h"
#include "float.h"
#include "VxMath.h"
/*************************************************
Name: BoxBoxIntersection
Summary: Detect a collision between two 3d entities at the bounding box level
Arguments:
ent1: the first 3dEntity
hiera1: whether or not to test the entire hierarchy of entity 1
local1: do we want to test the local box(more precise, slower) or the world box (less precise, faster) of the first entity
ent2: the second 3dEntity
hiera2: whether or not we want to test the entire hierarchy of entity 2
local2: do we want to test the local box(more precise, slower) or the world box (less precise, faster) of the second entity
Return Value: TRUE if they intersect, FALSE otherwise
Remarks:
{Group:Advanced Intersection Functions}
See also: CollisionManager::BoxFaceIntersection, CollisionManager::FaceFaceIntersection
*************************************************/
CKBOOL
CollisionManager::BoxBoxIntersection(CK3dEntity* ent1,CKBOOL hiera1,CKBOOL local1,CK3dEntity* ent2,CKBOOL hiera2,CKBOOL local2)
{
// Object 1
VxMatrix Mat1;
VxBbox box1;
if(ent1->GetClassID() == CKCID_CHARACTER) {
CKBodyPart* root = ((CKCharacter*)ent1)->GetRootBodyPart();
if (!root) return FALSE;
if (local1) Mat1 = root->GetWorldMatrix();
box1 = root->GetHierarchicalBox(local1);
} else {
if(local1) Mat1 = ent1->GetWorldMatrix();
if(hiera1) box1 = ent1->GetHierarchicalBox(local1);
else box1 = ent1->GetBoundingBox(local1);
}
// Object 2
VxMatrix Mat2;
VxBbox box2;
if (ent2->GetClassID() == CKCID_CHARACTER) {
CKBodyPart* root = ((CKCharacter*)ent2)->GetRootBodyPart();
if (!root) return FALSE;
if (local2) Mat2 = root->GetWorldMatrix();
box2 = root->GetHierarchicalBox(local2);
} else {
if(local2) Mat2 = ent2->GetWorldMatrix();
if(hiera2) box2 = ent2->GetHierarchicalBox(local2);
else box2 = ent2->GetBoundingBox(local2);
}
if (local1|local2) {
if (local1) {
if (local2) { // 1 and 2 locals
return VxIntersect::OBBOBB(VxOBB(box1,Mat1),VxOBB(box2,Mat2));
} else { // 1 local and 2 in world
return VxIntersect::AABBOBB(box2,VxOBB(box1,Mat1));
}
} else { // 1 in world and 2 local
return VxIntersect::AABBOBB(box1,VxOBB(box2,Mat2));
}
} else { // we want simple world box intersection
return VxIntersect::AABBAABB(box1,box2);
}
}
/*************************************************
Name: BoxFaceIntersection
Summary: Detect a collision between two 3d entities at the bounding box level for the first object
and af the face level for the second one.
Arguments:
ent1: the first 3dEntity
hiera1: whether or not to test the entire hierarchy of entity 1
local1: do we want to test the local box(more precise, slower) or the world box (less precise, faster) of the first entity
ent2: the second 3dEntity
Return Value: TRUE if they intersect, FALSE otherwise
Remarks:
{Group:Advanced Intersection Functions}
See also: CollisionManager::BoxFaceIntersection, CollisionManager::FaceFaceIntersection
*************************************************/
CKBOOL
CollisionManager::BoxFaceIntersection(CK3dEntity* ent1,CKBOOL hiera1,CKBOOL local1,CK3dEntity* ent2)
{
// TODO : some optimisations can be done : flags the face concerned
// do the intbox like in FaceFace....
#define V_RIGHT 0x01
#define V_LEFT 0x02
#define V_TOP 0x04
#define V_BOTTOM 0x08
#define V_FRONT 0x10
#define V_BACK 0x20
#define V_ALL 0x3F
// Object 1
VxMatrix InvMat1 = VxMatrix::Identity();
VxBbox box1;
if(ent1->GetClassID() == CKCID_CHARACTER) {
CKBodyPart* root = ((CKCharacter*)ent1)->GetRootBodyPart();
if(!root) return FALSE;
if(local1)
InvMat1= root->GetInverseWorldMatrix();
box1 = root->GetHierarchicalBox(local1);
} else {
if(local1)
InvMat1 = ent1->GetInverseWorldMatrix();
if(hiera1) box1 = ent1->GetHierarchicalBox(local1);
else box1 = ent1->GetBoundingBox(local1);
}
VxVector pts[8];
// pts : points of the bounding box expressed in local coordinates
pts[0].x=box1.Min.x; pts[0].y=box1.Min.y; pts[0].z=box1.Min.z;
pts[1].x=box1.Min.x; pts[1].y=box1.Min.y; pts[1].z=box1.Max.z;
pts[2].x=box1.Min.x; pts[2].y=box1.Max.y; pts[2].z=box1.Min.z;
pts[3].x=box1.Min.x; pts[3].y=box1.Max.y; pts[3].z=box1.Max.z;
pts[4].x=box1.Max.x; pts[4].y=box1.Min.y; pts[4].z=box1.Min.z;
pts[5].x=box1.Max.x; pts[5].y=box1.Min.y; pts[5].z=box1.Max.z;
pts[6].x=box1.Max.x; pts[6].y=box1.Max.y; pts[6].z=box1.Min.z;
pts[7].x=box1.Max.x; pts[7].y=box1.Max.y; pts[7].z=box1.Max.z;
// Object 2
CKMesh* Mesh2 = ent2->GetCurrentMesh();
if (!Mesh2) return FALSE;
int Mesh2FaceCount = Mesh2->GetFaceCount();
if (!Mesh2FaceCount) return FALSE;
VxMatrix Mat = InvMat1 * ent2->GetWorldMatrix();
int acount = Mesh2->GetVertexCount();
VxScratch memp1(acount*4*sizeof(float)); // 3 for vector + 1 for vFlags
DWORD* avFlags = (DWORD *)memp1.Mem();
VxVector* av = (VxVector *)(avFlags+acount);
CKDWORD pStride;
void* apos = Mesh2->GetPositionsPtr(&pStride);
// we transform the vertices of 1 in the referential of 2, and vice versa
VxStridedData src(apos,pStride);
VxStridedData dst(av,sizeof(VxVector));
Vx3DMultiplyMatrixVectorStrided(&dst,&src,Mat,acount);
VxVector* vx = av;
DWORD all = V_ALL;
for(int x=0; x<acount; x++,++vx) {
avFlags[x] = 0;
if(vx->x < box1.Min.x) avFlags[x] |= V_LEFT;
else if(vx->x > box1.Max.x) avFlags[x] |= V_RIGHT;
if(vx->y < box1.Min.y) avFlags[x] |= V_BOTTOM;
else if(vx->y > box1.Max.y) avFlags[x] |= V_TOP;
if(vx->z < box1.Min.z) avFlags[x] |= V_FRONT;
else if(vx->z > box1.Max.z) avFlags[x] |= V_BACK;
all &= avFlags[x];
}
if (!all) {
VxVector p0,p1,p2;
CKVINDEX* aindices = Mesh2->GetFacesIndices();
for (int i=0;i<Mesh2FaceCount;i++,aindices+=3) {
if (!avFlags[aindices[0]]) return TRUE;
if (!avFlags[aindices[1]]) return TRUE;
if (!avFlags[aindices[2]]) return TRUE;
if (!(avFlags[aindices[0]]&avFlags[aindices[1]]&avFlags[aindices[2]])) {
// we now have to test the edges of the face
VxVector* p0 = av+aindices[0];
VxVector* p1 = av+aindices[1];
VxVector* p2 = av+aindices[2];
if (VxIntersect::SegmentBox(VxRay(*p0,*p1),box1)) return TRUE;
if (VxIntersect::SegmentBox(VxRay(*p1,*p2),box1)) return TRUE;
if (VxIntersect::SegmentBox(VxRay(*p0,*p2),box1)) return TRUE;
// if no segment of the face intersect the box, maybe one of the box diagonals intersect the face
// if faut tester les 4 diagonales du cube
VxVector normal = Mesh2->GetFaceNormal(i);;
Vx3DRotateVector(&normal,Mat,&normal);
int i0 = 0;
int i1 = 7;
float max = XFabs(DotProduct(normal,pts[0]-pts[7]));
float dp;
if ((dp = XFabs(DotProduct(normal,pts[1]-pts[6]))) > max) {
max = dp;
i0 = 1;
i1 = 6;
}
if ((dp = XFabs(DotProduct(normal,pts[2]-pts[5]))) > max) {
max = dp;
i0 = 2;
i1 = 5;
}
if ((dp = XFabs(DotProduct(normal,pts[3]-pts[4]))) > max) {
max = dp;
i0 = 3;
i1 = 4;
}
VxVector res;
if (VxIntersect::SegmentFace(VxRay(pts[i0],pts[i1]),*p0,*p1,*p2,normal,res,max)) return TRUE;
// well all this work for nothing : there is no intersection for this face
}
}
}
return FALSE;
}
/*************************************************
Name: FaceFaceIntersection
Summary: Detect a collision between two 3d entities at the face level
Arguments:
ent1: the first 3dEntity
ent2: the second 3dEntity
Return Value: TRUE if they intersect, FALSE otherwise
Remarks:
Detect a collision between two 3d entities at the face level
{Group:Advanced Intersection Functions}
See also: CollisionManager::BoxFaceIntersection, CollisionManager::FaceFaceIntersection
*************************************************/
CKBOOL
CollisionManager::FaceFaceIntersection(CK3dEntity* ent1,CK3dEntity* ent2)
{
#define V1_RIGHT 0x01
#define V1_LEFT 0x02
#define V1_TOP 0x04
#define V1_BOTTOM 0x08
#define V1_FRONT 0x10
#define V1_BACK 0x20
#define V1_ALL 0x3F
#define V2_RIGHT 0x0100
#define V2_LEFT 0x0200
#define V2_TOP 0x0400
#define V2_BOTTOM 0x0800
#define V2_FRONT 0x1000
#define V2_BACK 0x2000
#define V2_ALL 0x3F00
#define FACEEPSILON 0.001f
if (!ent1 || !ent2) return FALSE;
const VxBbox& box1 = ent1->GetBoundingBox();
const VxBbox& box2 = ent2->GetBoundingBox();
if (box1.Min.x > box2.Max.x+FACEEPSILON) return FALSE;
if (box1.Min.y > box2.Max.y+FACEEPSILON) return FALSE;
if (box1.Min.z > box2.Max.z+FACEEPSILON) return FALSE;
if (box1.Max.x < box2.Min.x-FACEEPSILON) return FALSE;
if (box1.Max.y < box2.Min.y-FACEEPSILON) return FALSE;
if (box1.Max.z < box2.Min.z-FACEEPSILON) return FALSE;
CKVINDEX spriteindices[6] = {0,1,2,0,2,3};
VxVector spritenormals[2] = {VxVector(0.0f,0.0f,1.0f),VxVector(0.0f,0.0f,1.0f)};
VxVector spritepos1[4];
VxVector spritepos2[4];
// Object 1
int fcount1;
int lcount1;
int vcount1;
void* vpos1;
BYTE* fnormals1;
CKVINDEX* findices1 = 0;
CKVINDEX* lindices1 = 0;
CKDWORD pStride1;
CKDWORD nStride1;
if (CKIsChildClassOf(ent1,CKCID_SPRITE3D)) { // Sprite 3D
fcount1 = 2;
lcount1 = 0;
vcount1 = 4;
vpos1 = &spritepos1[0];
findices1 = &spriteindices[0];
fnormals1 = (BYTE*)&spritenormals[0];
pStride1 = sizeof(VxVector);
nStride1 = sizeof(VxVector);
// filling the vectors positions
CKSprite3D* sprite = (CKSprite3D*)ent1;
Vx2DVector size;sprite->GetSize(size);
Vx2DVector offset;sprite->GetSize(size);
spritepos1[0].x = (-1.0f+offset.x)*size.x;
spritepos1[0].y = (-1.0f+offset.y)*size.y;
spritepos1[1].x = (-1.0f+offset.x)*size.x;
spritepos1[1].y = (1.0f+offset.y)*size.y;
spritepos1[2].x = (1.0f+offset.x)*size.x;
spritepos1[2].y = (1.0f+offset.y)*size.y;
spritepos1[3].x = (1.0f+offset.x)*size.x;
spritepos1[3].y = (-1.0f+offset.y)*size.y;
} else { // Mesh Normal
CKMesh* mesh = ent1->GetCurrentMesh();
if (!mesh) return FALSE;
vcount1 = mesh->GetVertexCount();
if (!vcount1) return FALSE;
fcount1 = mesh->GetFaceCount();
lcount1 = mesh->GetLineCount();
vpos1 = mesh->GetPositionsPtr(&pStride1);
findices1 = mesh->GetFacesIndices();
fnormals1 = mesh->GetFaceNormalsPtr(&nStride1);
lindices1 = mesh->GetLineIndices();
}
// Object 2
int fcount2;
int lcount2;
int vcount2;
void* vpos2;
BYTE* fnormals2 = 0;
CKVINDEX* findices2 = 0;
CKVINDEX* lindices2 = 0;
CKDWORD pStride2;
CKDWORD nStride2;
if (CKIsChildClassOf(ent2,CKCID_SPRITE3D)) { // Sprite 3D
fcount2 = 2;
lcount2 = 0;
vcount2 = 4;
vpos2 = &spritepos2[0];
findices2 = &spriteindices[0];
fnormals2 = (BYTE*)&spritenormals[0];
pStride2 = sizeof(VxVector);
nStride2 = sizeof(VxVector);
// filling the vectors positions
CKSprite3D* sprite = (CKSprite3D*)ent2;
Vx2DVector size;sprite->GetSize(size);
Vx2DVector offset;sprite->GetSize(size);
spritepos2[0].x = (-1.0f+offset.x)*size.x;
spritepos2[0].y = (-1.0f+offset.y)*size.y;
spritepos2[1].x = (-1.0f+offset.x)*size.x;
spritepos2[1].y = (1.0f+offset.y)*size.y;
spritepos2[2].x = (1.0f+offset.x)*size.x;
spritepos2[2].y = (1.0f+offset.y)*size.y;
spritepos2[3].x = (1.0f+offset.x)*size.x;
spritepos2[3].y = (-1.0f+offset.y)*size.y;
} else { // Mesh Normal
CKMesh* mesh = ent2->GetCurrentMesh();
if (!mesh) return FALSE;
vcount2 = mesh->GetVertexCount();
if (!vcount2) return FALSE;
fcount2 = mesh->GetFaceCount();
lcount2 = mesh->GetLineCount();
vpos2 = mesh->GetPositionsPtr(&pStride2);
findices2 = mesh->GetFacesIndices();
fnormals2 = mesh->GetFaceNormalsPtr(&nStride2);
lindices2 = mesh->GetLineIndices();
}
// Matrix
VxMatrix Mat21 = ent1->GetInverseWorldMatrix() * ent2->GetWorldMatrix();
VxMatrix Mat12 = ent2->GetInverseWorldMatrix() * ent1->GetWorldMatrix();
// we calculate the local boxes of the intersection
VxBbox intbox1,intbox2;
VxBbox lbox1 = ent1->GetBoundingBox(TRUE);
lbox1.Max += FACEEPSILON;
lbox1.Min -= FACEEPSILON;
VxBbox lbox2 = ent2->GetBoundingBox(TRUE);
lbox2.Max += FACEEPSILON;
lbox2.Min -= FACEEPSILON;
intbox1.TransformFrom(lbox1,Mat12);
intbox2.TransformFrom(lbox2,Mat21);
int max = XMax(vcount1,vcount2);
VxScratch memp1((max+vcount2*3)*sizeof(float)); // 3 for vector + 1 for vFlags
DWORD* avFlags = (DWORD *)memp1.Mem();
VxVector* bvIn1 = (VxVector *)(avFlags+max);
// we transform the vertices of 1 in the referential of 2, and vice versa
VxStridedData src(vpos2,pStride2);
VxStridedData dst(bvIn1,sizeof(VxVector));
Vx3DMultiplyMatrixVectorStrided(&dst,&src,Mat21,vcount2);
// we clear the vertices
memset(avFlags,0,max*4);
// We flag the vertices
VxVector* vx;
BYTE* var = (BYTE*)vpos1;
int x;
for(x=0; x<vcount1; x++,var += pStride1) {
vx = (VxVector*)var;
if (vx->x < intbox2.Min.x) avFlags[x] |= V1_LEFT;
else if (vx->x > intbox2.Max.x) avFlags[x] |= V1_RIGHT;
if (vx->y < intbox2.Min.y) avFlags[x] |= V1_BOTTOM;
else if (vx->y > intbox2.Max.y) avFlags[x] |= V1_TOP;
if (vx->z < intbox2.Min.z) avFlags[x] |= V1_FRONT;
else if (vx->z > intbox2.Max.z) avFlags[x] |= V1_BACK;
}
var = (BYTE*)vpos2;
for(x=0; x<vcount2; x++,var += pStride2) {
vx = (VxVector*)var;
if(vx->x < intbox1.Min.x) avFlags[x] |= V2_LEFT;
else if(vx->x > intbox1.Max.x) avFlags[x] |= V2_RIGHT;
if(vx->y < intbox1.Min.y) avFlags[x] |= V2_BOTTOM;
else if(vx->y > intbox1.Max.y) avFlags[x] |= V2_TOP;
if(vx->z < intbox1.Min.z) avFlags[x] |= V2_FRONT;
else if(vx->z > intbox1.Max.z) avFlags[x] |= V2_BACK;
}
BYTE* av = (BYTE*)vpos1;
VxVector* bv = bvIn1;
CKVINDEX* bindices = findices2;
///////////////////////////////////
// Test faces 1 vs Faces 2
int count = 0;
VxVector bn;
int i;
for (i=0; i<fcount2; ++i,bindices += 3) {
if ((avFlags[bindices[0]]&avFlags[bindices[1]]&avFlags[bindices[2]]) & V2_ALL) continue;
VxVector* b0 = bv+bindices[0];
VxVector* b1 = bv+bindices[1];
VxVector* b2 = bv+bindices[2];
Vx3DRotateVector(&bn,Mat21,(VxVector*)(fnormals2+i*nStride2));
CKVINDEX* aindices = findices1;
for (int j=0; j<fcount1; ++j,aindices += 3) {
if ((avFlags[aindices[0]]&avFlags[aindices[1]]&avFlags[aindices[2]]) & V1_ALL) continue;
VxVector* a0 = (VxVector*)(av+aindices[0]*pStride1);
VxVector* a1 = (VxVector*)(av+aindices[1]*pStride1);
VxVector* a2 = (VxVector*)(av+aindices[2]*pStride1);
VxVector* an = (VxVector*)(fnormals1+j*nStride1);
if (VxIntersect::FaceFace(*a0,*a1,*a2,*an,*b0,*b1,*b2,bn)) {
m_TouchingFaceIndex = j;
m_TouchedFaceIndex = i;
return TRUE;
}
}
}
//////////////////////////////////
// we now have to handle lines
// Test Faces 1 vs Lines 2
if (lcount2) {
// dummy variables
VxVector res;
float t;
CKVINDEX* aindices = findices1;
for (i=0; i<fcount1; ++i,aindices += 3) {
if ((avFlags[aindices[0]]&avFlags[aindices[1]]&avFlags[aindices[2]]) & V1_ALL) continue;
VxVector* a0 = (VxVector*)(av+aindices[0]*pStride1);
VxVector* a1 = (VxVector*)(av+aindices[1]*pStride1);
VxVector* a2 = (VxVector*)(av+aindices[2]*pStride1);
VxVector* an = (VxVector*)(fnormals1+i*nStride1);
bindices = lindices2;
for (int j=0; j<lcount2; ++j, bindices += 2) {
if ((avFlags[bindices[0]]&avFlags[bindices[1]]) & V2_ALL) continue;
VxVector* b0 = bv+bindices[0];
VxVector* b1 = bv+bindices[1];
if (VxIntersect::SegmentFace(VxRay(*b0,*b1),*a0,*a1,*a2,*an,res,t)) {
return TRUE;
}
}
}
}
// Test Faces 2 vs Lines 1
if (lcount1) {
// dummy variables
VxVector res;
float t;
bindices = findices2;
for (i=0; i<fcount2; ++i,bindices += 3) {
if ((avFlags[bindices[0]]&avFlags[bindices[1]]&avFlags[bindices[2]]) & V2_ALL) continue;
VxVector* b0 = bv+bindices[0];
VxVector* b1 = bv+bindices[1];
VxVector* b2 = bv+bindices[2];
Vx3DRotateVector(&bn,Mat21,(VxVector*)(fnormals2+i*nStride2));
CKVINDEX* aindices = lindices1;
for (int j=0; j<lcount1; ++j, aindices += 2) {
if ((avFlags[aindices[0]]&avFlags[aindices[1]]) & V1_ALL) continue;
VxVector* a0 = (VxVector*)(av+aindices[0]*pStride1);
VxVector* a1 = (VxVector*)(av+aindices[1]*pStride1);
if (VxIntersect::SegmentFace(VxRay(*a0,*a1),*b0,*b1,*b2,bn,res,t)) {
return TRUE;
}
}
}
}
// Test Lines 1 vs Lines 2
if (lcount1 && lcount2) {
VxVector res = box1.Max-box1.Min;
float threshold = SquareMagnitude(res)*0.0001f;
bindices = lindices2;
for (i=0; i<lcount2; ++i,bindices += 2) {
if ((avFlags[bindices[0]]&avFlags[bindices[1]]) & V2_ALL) continue;
VxVector* b0 = bv+bindices[0];
VxVector* b1 = bv+bindices[1];
CKVINDEX* aindices = lindices1;
for (int j=0; j<lcount1; ++j, aindices += 2) {
if ((avFlags[aindices[0]]&avFlags[aindices[1]]) & V1_ALL) continue;
VxVector* a0 = (VxVector*)(av+aindices[0]*pStride1);
VxVector* a1 = (VxVector*)(av+aindices[1]*pStride1);
if (VxDistance::SegmentSegmentSquareDistance(VxRay(*a0,*a1),VxRay(*b0,*b1)) < threshold) {
return TRUE;
}
}
}
}
return FALSE;
}
/*************************************************
Name: IsInCollision
Summary: Check if two 3dEntities are in collision
Arguments:
ent1: first obstacle
precis_level1: the geometric precision level you want the ent1 to be at. CKCOLLISION_NONE means nothing for this function
ent2: second obstacle
precis_level2: the geometric precision level you want the ent2 to be at. CKCOLLISION_NONE means nothing for this function
Return Value:
TRUE if the two entites are colliding, NULL otherwise.
Remarks:
This function is not finished yet. Its only check for obstacle with world bounding box occlusion, which
is by far too simple...
{Group:Advanced Intersection Functions}
See also: CollisionManager
*************************************************/
CKBOOL
CollisionManager::IsInCollision(CK3dEntity *ent1,CK_GEOMETRICPRECISION precis_level1,CK3dEntity *ent2,CK_GEOMETRICPRECISION precis_level2)
{
switch(precis_level1|precis_level2) {
case CKCOLLISION_BOX:
return BoxBoxIntersection(ent1,FALSE,FALSE,ent2,FALSE,FALSE);
// TODO : reput this line back
// return BoxBoxIntersection(ent1,FALSE,TRUE,ent2,FALSE,TRUE);
break;
case CKCOLLISION_FACE:
return FaceFaceIntersection(ent1,ent2);
break;
case CKCOLLISION_FACE|CKCOLLISION_BOX:
if(precis_level1 & CKCOLLISION_BOX) {
return BoxFaceIntersection(ent1,FALSE,TRUE,ent2);
} else {
return BoxFaceIntersection(ent2,FALSE,TRUE,ent1);
}
break;
}
return FALSE;
}
/*************************************************
Name: IsInCollisionWithHierarchy
Summary: Check if two 3dEntities are in collision, the second one considered with all its sub-hierarchy
Arguments:
ent1: first obstacle
precis_level1: the geometric precision level you want the ent1 to be at. CKCOLLISION_NONE means nothing for this function
ent2: second obstacle, hierarchic.
precis_level2: the geometric precision level you want the ent2 to be at. CKCOLLISION_NONE means nothing for this function
Return Value:
The pointer to the sub-object of entity 2 if the two entites are colliding, NULL otherwise.
Remarks:
Check if two 3dEntities are in collision, the second one considered with all its sub-hierarchy. All the sub objects of
entity 2 are tested at the same level of precision : precis_level2
{Group:Advanced Intersection Functions}
See also: CollisionManager, CollisionManager::IsHierarchyInCollisionWithHierarchy
*************************************************/
CK3dEntity*
CollisionManager::IsInCollisionWithHierarchy(CK3dEntity *ent1,CK_GEOMETRICPRECISION precis_level1,CK3dEntity *ent2,CK_GEOMETRICPRECISION precis_level2)
{
CK3dEntity* touched;
// if the hierarchy is a character, we go down to the root immediatly...
if(ent2->GetClassID() == CKCID_CHARACTER) {
ent2 = ((CKCharacter*)ent2)->GetRootBodyPart();
// Character has no root : we can't detect collision thus....
if(!ent2) return NULL;
}
// hierarchical rejection with world hierarchical box
if (!BoxBoxIntersection(ent1,FALSE,FALSE,ent2,TRUE,FALSE)) {
return NULL;
}
// if we arrived here, we know there could be a collision with the root
// so we test it right now
if(IsInCollision(ent1,precis_level1,ent2,precis_level2)) return ent2;
// the root wasn't in collision so we go down in the hierarchy
for(int i=0;i<ent2->GetChildrenCount();i++) {
CK3dEntity* child = ent2->GetChild(i);
if(touched=IsInCollisionWithHierarchy(ent1,precis_level1,child,precis_level2)) return touched;
}
return NULL;
}
/*************************************************
Name: IsHierarchyInCollisionWithHierarchy
Summary: Check if two 3dEntities are in collision, the two considered with all their sub-hierarchy
Arguments:
ent1: first obstacle, hierarchic
precis_level1: the geometric precision level you want the ent1 to be at. CKCOLLISION_NONE means nothing for this function
ent2: second obstacle, hierarchic.
precis_level2: the geometric precision level you want the ent2 to be at. CKCOLLISION_NONE means nothing for this function
sub: pointer on the sub object of the entity1, if there is a collision
subob: pointer on the sub object of the entity2, if there is a collision
Return Value:
TRUE if the two entites are colliding, NULL otherwise.
Remarks:
Check if two 3dEntities are in collision, the two considered with all their sub-hierarchy
{Group:Advanced Intersection Functions}
See also: CollisionManager, CollisionManager::IsInCollisionWithHierarchy
*************************************************/
CKBOOL
CollisionManager::IsHierarchyInCollisionWithHierarchy(CK3dEntity *ent1,CK_GEOMETRICPRECISION precis_level1,CK3dEntity *ent2,CK_GEOMETRICPRECISION precis_level2,CK3dEntity** sub, CK3dEntity** subob)
{
CK3dEntity* touched;
// if the hierarchy is a character, we go down to the root immediatly...
if(ent1->GetClassID() == CKCID_CHARACTER) {
ent1 = ((CKCharacter*)ent1)->GetRootBodyPart();
// Character has no root : we can't detect collision thus....
if(!ent1) return NULL;
}
// if the hierarchy is a character, we go down to the root immediatly...
if(ent2->GetClassID() == CKCID_CHARACTER) {
ent2 = ((CKCharacter*)ent2)->GetRootBodyPart();
// Character has no root : we can't detect collision thus....
if(!ent2) return NULL;
}
// hierarchical rejection with world hierarchical box
if(!BoxBoxIntersection(ent1,TRUE,FALSE,ent2,TRUE,FALSE)) {
return NULL;
}
// if we arrived here, we know there could be a collision with the root and the other hierarchy
// so we test it right now
if(touched = IsInCollisionWithHierarchy(ent1,precis_level1,ent2,precis_level2)) {
*sub = ent1;
*subob = touched;
return TRUE;
}
// the root wasn't in collision so we go down in the hierarchy
for(int i=0;i<ent1->GetChildrenCount();i++) {
CK3dEntity* child = ent1->GetChild(i);
if(IsHierarchyInCollisionWithHierarchy(child,precis_level1,ent2,precis_level2,sub,subob)) return TRUE;
}
return FALSE;
}