1366 lines
34 KiB
C++
1366 lines
34 KiB
C++
/*************************************************************************/
|
|
/* File : FloorManager.cpp */
|
|
/* */
|
|
/*************************************************************************/
|
|
#include "CKAll.h"
|
|
#include "FloorManager.h"
|
|
#include "VSLManagerSDK.h"
|
|
|
|
#include "float.h"
|
|
|
|
#ifdef macintosh
|
|
#include "ManagerExport.h"
|
|
#endif
|
|
|
|
extern char* FloorManagerName;
|
|
|
|
// {secret}
|
|
char* FloorName = "Floor";
|
|
|
|
// {secret}
|
|
FloorManager::FloorManager(CKContext *Context):CKFloorManager(Context,FloorManagerName)
|
|
{
|
|
m_LimitAngle=80.0f*PI/180.0f;
|
|
m_CosAngle=(float)cos(m_LimitAngle);
|
|
|
|
m_Context->RegisterNewManager(this);
|
|
|
|
}
|
|
|
|
|
|
FloorManager::~FloorManager()
|
|
{
|
|
}
|
|
|
|
CKERROR
|
|
FloorManager::PreClearAll()
|
|
{
|
|
// Angle Limits
|
|
m_LimitAngle=80.0f*PI/180.0f;
|
|
m_CosAngle=(float)cos(m_LimitAngle);
|
|
|
|
// Destroy the computed edges
|
|
m_FloorEdges.Clear();
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
CKERROR
|
|
FloorManager::OnCKInit()
|
|
{
|
|
m_Context->GetParameterManager()->RegisterNewEnum(CKPGUID_FLOORGEOMETRY,"Geometry","Faces=0,Bounding Box=1");
|
|
#ifdef __GNUC__
|
|
CKGUID floor=CKPGUID_FLOORGEOMETRY;
|
|
CKGUID integer=CKPGUID_INT;
|
|
CKGUID bl=CKPGUID_BOOL;
|
|
m_Context->GetParameterManager()->RegisterNewStructure(CKPGUID_FLOOR,"Floor","Floor Geometry,Moving Floor,Floor Type,Use Hierarchy?,First Contact?",&floor,&bl,&integer,&bl,&bl);
|
|
#else
|
|
m_Context->GetParameterManager()->RegisterNewStructure(CKPGUID_FLOOR,"Floor","Floor Geometry,Moving Floor,Floor Type,Use Hierarchy?,First Contact?",CKPGUID_FLOORGEOMETRY,CKPGUID_BOOL,CKPGUID_INT,CKPGUID_BOOL,CKPGUID_BOOL);
|
|
#endif
|
|
// We create the attributes
|
|
// we register all the attributes types related to the Collision Manager
|
|
CKAttributeManager* attman = m_Context->GetAttributeManager();
|
|
// first we create the attribute category "Particle Systems"
|
|
attman->AddCategory(FloorManagerName);
|
|
|
|
int att;
|
|
// Floor Attribute
|
|
att = attman->RegisterNewAttributeType(FloorName,CKPGUID_FLOOR,CKCID_3DENTITY);
|
|
attman->SetAttributeCategory(att,FloorManagerName);
|
|
attman->SetAttributeDefaultValue(att,"0;TRUE;0;FALSE;TRUE");
|
|
m_FloorAttribute = att;
|
|
|
|
VSLBind();
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
CKERROR
|
|
FloorManager::OnCKPlay()
|
|
{
|
|
/* Sharing of meshes sucks !
|
|
CKAttributeManager* attman = m_Context->GetAttributeManager();
|
|
const XObjectPointerArray& floors = attman->GetAttributeListPtr(m_FloorAttribute);
|
|
|
|
for (CKObject** it = floors.Begin(); it != floors.End(); ++it) {
|
|
CK3dEntity *mov = (CK3dEntity *)*it;
|
|
// we test the entity
|
|
if(!mov) continue;
|
|
|
|
// we have to test if it is fixed
|
|
CKBOOL Moving;
|
|
ReadAttributeValues(mov,NULL,&Moving,NULL,NULL,NULL);
|
|
|
|
if (!Moving) {
|
|
// we test if the floor isn't WorldTransformed
|
|
if (!(mov->GetMoveableFlags() & VX_MOVEABLE_WORLDALIGNED)) {
|
|
// we have to transform it again
|
|
mov->ChangeReferential();
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
return CK_OK;
|
|
}
|
|
|
|
CKERROR
|
|
FloorManager::PostLoad()
|
|
{
|
|
/// Patch for old enums
|
|
CK_ID* ids = m_Context->GetObjectsListByClassID(CKCID_PARAMETEROUT);
|
|
int idcount = m_Context->GetObjectsCountByClassID(CKCID_PARAMETEROUT);
|
|
|
|
for (int j=0;j<idcount;++j) {
|
|
CKParameterOut* pl = (CKParameterOut*)m_Context->GetObject(ids[j]);
|
|
if (!pl) continue;
|
|
|
|
if (pl->GetGUID() == CKPGUID_FLOORGEOMETRY) {
|
|
int *value = (int*)pl->GetWriteDataPtr();
|
|
if (*value == 2) *value = 1;
|
|
}
|
|
}
|
|
|
|
// Si ya un pb su rles set atributes sur des ancinnes version de fichier,
|
|
// le faire aussi pour les locaux
|
|
|
|
///
|
|
// After a load, we destroy all the floor edges previously created
|
|
|
|
if (m_FloorEdges.Size()) {
|
|
HashFloor2Edges::Iterator it = m_FloorEdges.Begin();
|
|
HashFloor2Edges::Iterator itend = m_FloorEdges.End();
|
|
|
|
while (it != itend) {
|
|
(*it).Clear();
|
|
++it;
|
|
}
|
|
|
|
m_FloorEdges.Clear();
|
|
}
|
|
|
|
return CK_OK;
|
|
}
|
|
/*************************************************
|
|
Name:
|
|
|
|
Summary:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
See also:
|
|
|
|
*************************************************/
|
|
void FloorManager::SetLimitAngle(float angle)
|
|
{
|
|
if (angle>PI/2.0f) angle=PI/2.0f;
|
|
if (angle<0.0f) angle=0.0f;
|
|
m_LimitAngle=angle;
|
|
m_CosAngle=(float)cos(m_LimitAngle);
|
|
}
|
|
|
|
float FloorManager::GetLimitAngle()
|
|
{
|
|
return m_LimitAngle;
|
|
}
|
|
|
|
CKBOOL
|
|
FloorManager::ReadAttributeValues(CK3dEntity *ent,CKDWORD* geo,CKBOOL* moving,int* type,CKBOOL* hiera,CKBOOL* first)
|
|
{
|
|
if (!ent) return FALSE;
|
|
|
|
CKParameterOut* pout = ent->GetAttributeParameter(m_FloorAttribute);
|
|
if(!pout) return FALSE;
|
|
|
|
if (pout->GetGUID() == CKPGUID_FLOOR) {
|
|
CK_ID* paramids = (CK_ID*)pout->GetReadDataPtr();
|
|
if(geo) {
|
|
pout = (CKParameterOut*)CKGetObject(paramids[0]);
|
|
if(pout) pout->GetValue(geo);
|
|
}
|
|
if(moving) {
|
|
pout = (CKParameterOut*)CKGetObject(paramids[1]);
|
|
if(pout) pout->GetValue(moving);
|
|
}
|
|
if(type) {
|
|
pout = (CKParameterOut*)CKGetObject(paramids[2]);
|
|
if(pout) pout->GetValue(type);
|
|
}
|
|
if(hiera) {
|
|
pout = (CKParameterOut*)CKGetObject(paramids[3]);
|
|
if(pout) pout->GetValue(hiera);
|
|
}
|
|
if(first) {
|
|
pout = (CKParameterOut*)CKGetObject(paramids[4]);
|
|
if(pout) pout->GetValue(first);
|
|
}
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
// {secret}
|
|
CKBOOL
|
|
FloorManager::TestFixedFloor(CK3dEntity* mov, const VxVector& pos,VxVector& inter,VxVector& normal,CKBOOL first,int &face,int facetotestfirst)
|
|
{
|
|
CKMesh* mesh=mov->GetCurrentMesh();
|
|
|
|
// we test if the floor isn't WorldTransformed
|
|
if(!(mov->GetMoveableFlags() & VX_MOVEABLE_WORLDALIGNED)) {
|
|
// we have to transform it again
|
|
mov->ChangeReferential();
|
|
}
|
|
|
|
float x = pos.x;
|
|
float z = pos.z;
|
|
|
|
// we prepare for face travesal
|
|
CKDWORD StridePos;
|
|
BYTE* m_VertexArray = (BYTE *)mesh->GetPositionsPtr(&StridePos);
|
|
|
|
CKVINDEX* faces = mesh->GetFacesIndices();
|
|
int i,m_NbFaces = mesh->GetFaceCount();
|
|
VxVector* pts[3];
|
|
|
|
float xmin,xmax,zmin,zmax;
|
|
|
|
CKBOOL Collision = FALSE;
|
|
|
|
float tmax=100000000.0f;
|
|
|
|
VxVector p1=pos,p2,twup(0.0f,1.0f,0.0f),tempres;
|
|
float t;
|
|
p2 = p1+twup;
|
|
|
|
// we test every single face
|
|
CKVINDEX* currentface = faces+(facetotestfirst)*3;
|
|
for (i=facetotestfirst;i<m_NbFaces;i++,currentface += 3) {
|
|
pts[0]=(VxVector *)&m_VertexArray[*currentface * StridePos];
|
|
pts[1]=(VxVector *)&m_VertexArray[*(currentface+1) * StridePos];
|
|
pts[2]=(VxVector *)&m_VertexArray[*(currentface+2) * StridePos];
|
|
|
|
if(pts[0]->x < pts[1]->x) {
|
|
xmin = pts[0]->x;
|
|
xmax = pts[1]->x;
|
|
} else {
|
|
xmin = pts[1]->x;
|
|
xmax = pts[0]->x;
|
|
}
|
|
if(xmin > pts[2]->x) {
|
|
xmin = pts[2]->x;
|
|
} else {
|
|
if(xmax < pts[2]->x) {
|
|
xmax = pts[2]->x;
|
|
}
|
|
}
|
|
if(x<xmin) continue;
|
|
if(x>xmax) continue;
|
|
|
|
if(pts[0]->z < pts[1]->z) {
|
|
zmin = pts[0]->z;
|
|
zmax = pts[1]->z;
|
|
} else {
|
|
zmin = pts[1]->z;
|
|
zmax = pts[0]->z;
|
|
}
|
|
if(zmin > pts[2]->z) {
|
|
zmin = pts[2]->z;
|
|
} else {
|
|
if(zmax < pts[2]->z) {
|
|
zmax = pts[2]->z;
|
|
}
|
|
}
|
|
|
|
if(z<zmin) continue;
|
|
if(z>zmax) continue;
|
|
|
|
const VxVector& facenormal = mesh->GetFaceNormal(i);
|
|
|
|
// we now have to check if the face is not too inclined
|
|
if(DotProduct(twup,facenormal) < m_CosAngle) continue;
|
|
|
|
// see if floorfaceint couldn't take a point and a dir...
|
|
VxRay ray(p1,p2);
|
|
if (VxIntersect::LineFace(ray,*pts[0],*pts[1],*pts[2],facenormal,tempres,t)) {
|
|
// we test we need to get the nearest face or one is enough
|
|
if(first) {
|
|
normal = facenormal;
|
|
inter = tempres;
|
|
face = i;
|
|
return TRUE;
|
|
} else {
|
|
if (fabs(t)<tmax) {
|
|
tmax = (float)fabs(t);
|
|
normal = facenormal;
|
|
inter = tempres;
|
|
face = i;
|
|
Collision=TRUE;
|
|
}
|
|
}
|
|
}
|
|
} // end of the for(faces)
|
|
|
|
currentface = faces+(facetotestfirst-1)*3;
|
|
for (i=facetotestfirst-1;i>=0;i--,currentface -= 3) {
|
|
pts[0]=(VxVector *)&m_VertexArray[*currentface * StridePos];
|
|
pts[1]=(VxVector *)&m_VertexArray[*(currentface+1) * StridePos];
|
|
pts[2]=(VxVector *)&m_VertexArray[*(currentface+2) * StridePos];
|
|
|
|
if(pts[0]->x < pts[1]->x) {
|
|
xmin = pts[0]->x;
|
|
xmax = pts[1]->x;
|
|
} else {
|
|
xmin = pts[1]->x;
|
|
xmax = pts[0]->x;
|
|
}
|
|
if(xmin > pts[2]->x) {
|
|
xmin = pts[2]->x;
|
|
} else {
|
|
if(xmax < pts[2]->x) {
|
|
xmax = pts[2]->x;
|
|
}
|
|
}
|
|
if(x<xmin) continue;
|
|
if(x>xmax) continue;
|
|
|
|
if(pts[0]->z < pts[1]->z) {
|
|
zmin = pts[0]->z;
|
|
zmax = pts[1]->z;
|
|
} else {
|
|
zmin = pts[1]->z;
|
|
zmax = pts[0]->z;
|
|
}
|
|
if(zmin > pts[2]->z) {
|
|
zmin = pts[2]->z;
|
|
} else {
|
|
if(zmax < pts[2]->z) {
|
|
zmax = pts[2]->z;
|
|
}
|
|
}
|
|
|
|
if(z<zmin) continue;
|
|
if(z>zmax) continue;
|
|
|
|
const VxVector& facenormal = mesh->GetFaceNormal(i);
|
|
|
|
// we now have to check if the face is not too inclined
|
|
if(DotProduct(twup,facenormal) < m_CosAngle) continue;
|
|
|
|
// see if floorfaceint couldn't take a point and a dir...
|
|
VxRay ray(p1,p2);
|
|
if (VxIntersect::LineFace(ray,*pts[0],*pts[1],*pts[2],facenormal,tempres,t)) {
|
|
// we test we need to get the nearest face or one is enough
|
|
if(first) {
|
|
normal = facenormal;
|
|
inter = tempres;
|
|
face = i;
|
|
return TRUE;
|
|
} else {
|
|
if (fabs(t)<tmax) {
|
|
tmax=(float)fabs(t);
|
|
normal = facenormal;
|
|
inter = tempres;
|
|
face = i;
|
|
Collision=TRUE;
|
|
}
|
|
}
|
|
}
|
|
} // end of the for(faces)
|
|
|
|
return Collision;
|
|
}
|
|
|
|
CKBOOL
|
|
FloorManager::FloorRayIntersect(CK3dEntity* mov, CKMesh* mesh, const VxBbox& rayextents, CKBOOL first, int x, int z, const VxRay& ray, int facetotestfirst,int lastfacetotest, float& tmax, int& face, VxVector& inter)
|
|
{
|
|
int step = 1;
|
|
int stepface = 3;
|
|
if (lastfacetotest < facetotestfirst) {
|
|
step = -1;
|
|
stepface = -3;
|
|
}
|
|
|
|
CKDWORD StridePos;
|
|
BYTE* m_VertexArray = (BYTE *)mesh->GetPositionsPtr(&StridePos);
|
|
|
|
|
|
CKDWORD normalStride;
|
|
BYTE* facesPtr = mesh->GetFaceNormalsPtr(&normalStride);
|
|
|
|
float t;
|
|
VxVector tempres;
|
|
|
|
CKVINDEX* faces = mesh->GetFacesIndices();
|
|
|
|
CKBOOL Collision = FALSE;
|
|
|
|
CKVINDEX* currentface = faces+(facetotestfirst)*3;
|
|
for (int i = facetotestfirst; i != lastfacetotest; i+=step,currentface+=stepface) {
|
|
const VxVector& pt0 = *(VxVector *)&m_VertexArray[*currentface * StridePos];
|
|
const VxVector& pt1 = *(VxVector *)&m_VertexArray[*(currentface+1) * StridePos];
|
|
const VxVector& pt2 = *(VxVector *)&m_VertexArray[*(currentface+2) * StridePos];
|
|
|
|
// face rejection by Bbox 2D
|
|
float min,max;
|
|
XMinMax(pt0.v[x],pt1.v[x],pt2.v[x],min,max);
|
|
if (rayextents.Max.x < min) continue;
|
|
if (rayextents.Min.x > max) continue;
|
|
|
|
XMinMax(pt0.v[z],pt1.v[z],pt2.v[z],min,max);
|
|
if (rayextents.Max.z < min) continue;
|
|
if (rayextents.Min.z > max) continue;
|
|
|
|
// we now have to check if the face is not too inclined
|
|
const VxVector& facenormal = *(VxVector*)(facesPtr + i*normalStride);
|
|
if (DotProduct(ray.GetDirection(),facenormal) < m_CosAngle) continue;
|
|
|
|
// see if floorfaceint couldn't take a point and a dir...
|
|
if (VxIntersect::LineFace(ray,pt0,pt1,pt2,facenormal,tempres,t)) {
|
|
if (first) {
|
|
face = i;
|
|
inter = tempres;
|
|
return TRUE;
|
|
} else {
|
|
if (fabs(t) < tmax) {
|
|
tmax = (float)fabs(t);
|
|
face = i;
|
|
inter = tempres;
|
|
Collision=TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Collision;
|
|
}
|
|
|
|
// {secret}
|
|
CKBOOL
|
|
FloorManager::TestMovingFloor(CK3dEntity* mov, const VxVector& pos,VxVector& inter,VxVector& normal,CKBOOL first,int &face,int facetotestfirst)
|
|
{
|
|
CKMesh* mesh = mov->GetCurrentMesh();
|
|
|
|
VxVector p1,twup(0,1.0f,0),tempres;
|
|
|
|
mov->InverseTransform(&p1,&pos);
|
|
mov->InverseTransformVector(&twup,&twup);
|
|
twup.Normalize();
|
|
VxVector p2 = p1+twup;
|
|
|
|
// we first need to know the orientation
|
|
int x;
|
|
int z;
|
|
|
|
VxVector planenormal;
|
|
|
|
VxVector worldup(0.0f,1.0f,0.0f);
|
|
float smcp,min;
|
|
// Suppose first that X axis
|
|
//Is aligned with world Up axis
|
|
min=smcp = twup.y*twup.y+twup.z*twup.z;
|
|
planenormal.Set(1.0f,0.0f,0.0f);
|
|
min = smcp;
|
|
x = 1;
|
|
z = 2;
|
|
//Is Y axis aligned with world Up axis
|
|
smcp = twup.x*twup.x+twup.z*twup.z;
|
|
if(smcp < min) {
|
|
planenormal.Set(0.0f,1.0f,0.0f);
|
|
min = smcp;
|
|
x = 0;
|
|
z = 2;
|
|
}
|
|
//Is Z axis aligned with world Up axis
|
|
smcp = twup.x*twup.x+twup.y*twup.y;
|
|
if(smcp < min) {
|
|
planenormal.Set(0.0f,0.0f,1.0f);
|
|
x = 0;
|
|
z = 1;
|
|
}
|
|
|
|
// we now calulate the 2D extents of the ray
|
|
VxVector int1,int2;
|
|
const VxBbox& box = mesh->GetLocalBox();
|
|
|
|
VxRay ray(p1,twup,NULL);
|
|
float t;
|
|
{
|
|
VxPlane plane(planenormal,box.Max);
|
|
|
|
VxIntersect::LinePlane(ray,plane,int1,t);
|
|
plane.Create(planenormal,box.Min);
|
|
VxIntersect::LinePlane(ray,plane,int2,t);
|
|
}
|
|
|
|
VxBbox rayextents;
|
|
XMinMax(int1.v[x],int2.v[x],rayextents.Min.x,rayextents.Max.x);
|
|
XMinMax(int1.v[z],int2.v[z],rayextents.Min.z,rayextents.Max.z);
|
|
|
|
int nbfaces = mesh->GetFaceCount();
|
|
|
|
float tmax=100000000.0f;
|
|
|
|
CKBOOL Collision = FloorRayIntersect(mov,mesh,rayextents,first,x,z,ray,facetotestfirst,nbfaces,tmax,face,inter);
|
|
if (!first) {
|
|
Collision |= FloorRayIntersect(mov,mesh,rayextents,first,x,z,ray,facetotestfirst-1,-1,tmax,face,inter);
|
|
}
|
|
|
|
if (Collision) {
|
|
const VxVector& facenormal = mesh->GetFaceNormal(face);
|
|
mov->TransformVector(&normal,&facenormal);
|
|
normal.Normalize();
|
|
mov->Transform(&inter,&inter);
|
|
}
|
|
|
|
return Collision;
|
|
}
|
|
|
|
// {secret}
|
|
CKBOOL
|
|
FloorManager::TestBoxFloor(CK3dEntity* mov, const VxVector& pos,VxVector& inter,VxVector& normal)
|
|
{
|
|
CKMesh* mesh=mov->GetCurrentMesh();
|
|
const VxBbox& box = mesh->GetLocalBox();
|
|
|
|
VxVector p1=pos,dir(0.0f,1.0f,0.0f);
|
|
mov->InverseTransform(&p1,&p1);
|
|
mov->InverseTransformVector(&dir,&dir);
|
|
|
|
VxRay ray(p1,dir,NULL);
|
|
CKBOOL collision = VxIntersect::LineBox(ray,box,inter,NULL,&normal);
|
|
mov->Transform(&inter,&inter);
|
|
mov->Transform(&normal,&normal);
|
|
return collision;
|
|
}
|
|
|
|
// {secret}
|
|
CKBOOL
|
|
FloorManager::FloorFastRejection(CK3dEntity* mov,const VxVector& pos,float nearestdown,float nearestup)
|
|
{
|
|
CKMesh* mesh=mov->GetCurrentMesh();
|
|
// if the floor have no mesh, we skip it
|
|
if (!mesh) return TRUE;
|
|
// if the floor mesh is in line mode, we skip it
|
|
if (!mesh->GetFaceCount()) return TRUE;
|
|
|
|
const VxBbox& box = mov->GetBoundingBox();
|
|
if (pos.x<box.Min.x) return TRUE;
|
|
if (pos.x>box.Max.x) return TRUE;
|
|
if (pos.z<box.Min.z) return TRUE;
|
|
if (pos.z>box.Max.z) return TRUE;
|
|
float distmax = pos.y - box.Max.y;
|
|
if( distmax > 0.0) { // the pos is up the floor
|
|
if(distmax > -nearestdown) return TRUE;
|
|
} else { // the pos is down or in the floor
|
|
float distmin = pos.y - box.Min.y;
|
|
if( distmin > 0.0) { // the point is in the floor
|
|
return FALSE;
|
|
} else { // the point is beneath the floor
|
|
// we test if it is not too up
|
|
if(-distmin > nearestup) return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
CK_FLOORNEAREST
|
|
FloorManager::GetNearestFloors(const VxVector& iPosition, CKFloorPoint* oFP, CK3dEntity* iExcludeFloor)
|
|
{
|
|
#if defined(macintosh) || defined(PSX2)|| defined(PSP)
|
|
if (isnan(iPosition.x) ||
|
|
isnan(iPosition.y) ||
|
|
isnan(iPosition.z))
|
|
return CKFLOOR_NOFLOOR;
|
|
#else
|
|
if (_isnan(iPosition.x) ||
|
|
_isnan(iPosition.y) ||
|
|
_isnan(iPosition.z))
|
|
return CKFLOOR_NOFLOOR;
|
|
#endif
|
|
|
|
oFP->Clear();
|
|
|
|
StartProfile();
|
|
|
|
CKBOOL Collision=FALSE;
|
|
CKBOOL Moving = FALSE;
|
|
CKBOOL First = FALSE;
|
|
CKDWORD FloorGeometry = CKFLOOR_FACES;
|
|
|
|
VxVector res,norm;
|
|
|
|
CKAttributeManager* attman = m_Context->GetAttributeManager();
|
|
const XObjectPointerArray& floors = attman->GetAttributeListPtr(m_FloorAttribute);
|
|
|
|
int faceindex = 0;
|
|
|
|
for (CKObject** it = floors.Begin(); it != floors.End(); ++it) {
|
|
CK3dEntity *mov = (CK3dEntity *)*it;
|
|
// we test the entity
|
|
if(!mov) continue;
|
|
|
|
// if the floor is to be exclude
|
|
if (mov == iExcludeFloor)
|
|
continue;
|
|
|
|
// we rapidly test if the floor might interest us
|
|
if (FloorFastRejection(mov,iPosition,oFP->m_DownDistance,oFP->m_UpDistance))
|
|
continue;
|
|
|
|
// we have to test if it is moving
|
|
ReadAttributeValues(mov,&FloorGeometry,&Moving,NULL,NULL,&First);
|
|
switch (FloorGeometry) {
|
|
case CKFLOOR_FACES:
|
|
// if (!Moving) {
|
|
// Collision = TestFixedFloor(mov,pos,res,norm,First,faceindex);
|
|
//} else {
|
|
Collision = TestMovingFloor(mov,iPosition,res,norm,First,faceindex);
|
|
//}
|
|
break;
|
|
case CKFLOOR_BOX:
|
|
Collision = TestBoxFloor(mov,iPosition,res,norm);
|
|
faceindex = 0;
|
|
break;
|
|
default: // most probably faces geometry, but who knows....
|
|
// if (!Moving) {
|
|
// Collision = TestFixedFloor(mov,pos,res,norm,First,faceindex);
|
|
//} else {
|
|
Collision = TestMovingFloor(mov,iPosition,res,norm,First,faceindex);
|
|
//}
|
|
break;
|
|
}
|
|
if (Collision) {
|
|
float dist=res.y-iPosition.y;
|
|
if (dist>0.0f) {
|
|
if (dist < oFP->m_UpDistance) {
|
|
oFP->m_UpFloor=CKOBJID(mov);
|
|
oFP->m_UpDistance=dist;
|
|
oFP->m_UpNormal = norm;
|
|
oFP->m_UpFaceIndex = faceindex;
|
|
}
|
|
} else {
|
|
if (dist > oFP->m_DownDistance) {
|
|
oFP->m_DownFloor=CKOBJID(mov);
|
|
oFP->m_DownDistance=dist;
|
|
oFP->m_DownNormal=norm;
|
|
oFP->m_DownFaceIndex = faceindex;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // end of the for(mov)
|
|
|
|
|
|
StopProfile();
|
|
|
|
if (oFP->m_DownFloor) {
|
|
if (oFP->m_UpFloor) {
|
|
if(-oFP->m_DownDistance < oFP->m_UpDistance) {
|
|
return CKFLOOR_DOWN; // the down floor is closer
|
|
} else {
|
|
return CKFLOOR_UP; // the up floor is closer
|
|
}
|
|
} else return CKFLOOR_DOWN;// There is only a down floor : Choose the down floor
|
|
} else {
|
|
if (oFP->m_UpFloor) return CKFLOOR_UP; // There is only an up floor : Choose the up floor
|
|
}
|
|
|
|
return CKFLOOR_NOFLOOR; // No Floors Found
|
|
}
|
|
|
|
/*************************************************
|
|
Name:
|
|
|
|
Summary: Not Yet Documented
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
See also:
|
|
|
|
*************************************************/
|
|
int FloorManager::AddFloorObjectsByName(CKLevel* level,CKSTRING floorname,CK_FLOORGEOMETRY geo,CKBOOL moving,int type,CKBOOL hiera,CKBOOL first)
|
|
{
|
|
if (!level) return 0;
|
|
int count=0;
|
|
XObjectPointerArray myarray = level->ComputeObjectList(CKCID_3DENTITY);
|
|
for (CKObject** it = myarray.Begin(); it != myarray.End(); ++it) {
|
|
CKObject *obj = *it;
|
|
if (obj)
|
|
if (obj->GetName())
|
|
if (strstr(obj->GetName(),floorname))
|
|
{ AddFloorObject((CK3dEntity *)obj,geo,moving,type,hiera,first); count++; }
|
|
}
|
|
return count;
|
|
}
|
|
|
|
//-----------------------------------------------------
|
|
// Floors Objects
|
|
|
|
/*************************************************
|
|
Name:
|
|
|
|
Summary: Not Yet Documented
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
See also:
|
|
|
|
*************************************************/
|
|
void FloorManager::AddFloorObject(CK3dEntity *ent,CK_FLOORGEOMETRY geo,CKBOOL moving,int type,CKBOOL hiera,CKBOOL first)
|
|
{
|
|
ent->SetAttribute(m_FloorAttribute);
|
|
|
|
CKParameterOut* pout = ent->GetAttributeParameter(m_FloorAttribute);
|
|
if(!pout) return;
|
|
|
|
CK_ID* paramids = (CK_ID*)pout->GetReadDataPtr();
|
|
pout = (CKParameterOut*)CKGetObject(paramids[0]);
|
|
if(pout) pout->SetValue(&geo);
|
|
|
|
pout = (CKParameterOut*)CKGetObject(paramids[1]);
|
|
if(pout) pout->SetValue(&moving);
|
|
|
|
pout = (CKParameterOut*)CKGetObject(paramids[2]);
|
|
if(pout) pout->SetValue(&type);
|
|
|
|
pout = (CKParameterOut*)CKGetObject(paramids[3]);
|
|
if(pout) pout->SetValue(&hiera);
|
|
|
|
pout = (CKParameterOut*)CKGetObject(paramids[4]);
|
|
if(pout) pout->SetValue(&first);
|
|
|
|
}
|
|
|
|
/*************************************************
|
|
Name:
|
|
|
|
Summary: Not Yet Documented
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
See also:
|
|
|
|
*************************************************/
|
|
void FloorManager::RemoveFloorObject(CK3dEntity *ent)
|
|
{
|
|
if(ent) ent->RemoveAttribute(m_FloorAttribute);
|
|
}
|
|
|
|
/*************************************************
|
|
Name:
|
|
|
|
Summary: Not Yet Documented
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
See also:
|
|
|
|
*************************************************/
|
|
int FloorManager::GetFloorObjectCount()
|
|
{
|
|
CKAttributeManager* attman = m_Context->GetAttributeManager();
|
|
const XObjectPointerArray& floors = attman->GetAttributeListPtr(m_FloorAttribute);
|
|
|
|
return floors.Size();
|
|
}
|
|
|
|
/*************************************************
|
|
Name:
|
|
|
|
Summary: Not Yet Documented
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Remarks:
|
|
|
|
See also:
|
|
|
|
*************************************************/
|
|
CK3dEntity* FloorManager::GetFloorObject(int pos)
|
|
{
|
|
CKAttributeManager* attman = m_Context->GetAttributeManager();
|
|
const XObjectPointerArray& floors = attman->GetAttributeListPtr(m_FloorAttribute);
|
|
|
|
return (CK3dEntity *)floors[pos];
|
|
}
|
|
|
|
/*************************************************
|
|
Name: GetCacheThreshold
|
|
|
|
Summary: Return the current threshold use by the cache system of the FloorManager
|
|
|
|
Return Value:
|
|
A floating point value representing the threshold in all the 2 axis, x and z.
|
|
|
|
Remarks:
|
|
Return the current threshold use by the cache system of the FloorManager. A cached point is
|
|
reused if a new asked point fell in the threshold proximity of it.
|
|
|
|
{Group:Floors Cache Management}
|
|
|
|
See also: FloorManager, FloorManager::GetNearestFloors
|
|
*************************************************/
|
|
float
|
|
FloorManager::GetCacheThreshold()
|
|
{
|
|
return m_CacheThreshold;
|
|
}
|
|
|
|
/*************************************************
|
|
Name: SetCacheThreshold
|
|
|
|
Summary: Set the current threshold use by the cache system of the FloorManager
|
|
|
|
Arguments:
|
|
t: A floating point value representing the threshold in all the 2 axis, x and z.
|
|
|
|
Remarks:
|
|
Set the current threshold use by the cache system of the FloorManager. When a call to
|
|
GetNearestFloor is performed, the position given is kept with the nearest face found from the
|
|
nearest floor found. When GetNearestFloors is called again, if first test all the kept point,
|
|
with a fixed threshold, to accelerate the detection when the object has not moved, or just a little.
|
|
|
|
{Group:Floors Cache Management}
|
|
|
|
See also: FloorManager, FloorManager::GetNearestFloors
|
|
*************************************************/
|
|
void
|
|
FloorManager::SetCacheThreshold(float t)
|
|
{
|
|
m_CacheThreshold = t;
|
|
}
|
|
|
|
|
|
/*************************************************
|
|
Name: GetCacheSize
|
|
|
|
Summary: Get the current number of positions kept by the cache.
|
|
|
|
Return Value:
|
|
The current number of positions kept by the cache.
|
|
|
|
Remarks:
|
|
Get the current number of positions kept by the cache.
|
|
|
|
{Group:Floors Cache Management}
|
|
|
|
See also: FloorManager, FloorManager::GetNearestFloors
|
|
*************************************************/
|
|
int
|
|
FloorManager::GetCacheSize()
|
|
{
|
|
return m_CacheSize;
|
|
}
|
|
|
|
/*************************************************
|
|
Name: SetCacheSize
|
|
|
|
Summary: Get the current number of positions kept by the cache.
|
|
|
|
Arguments:
|
|
size: The current number of positions kept by the cache.
|
|
|
|
Remarks:
|
|
Set the current number of positions kept by the cache. Warning :
|
|
It clear the current cache as well...
|
|
|
|
{Group:Floors Cache Management}
|
|
|
|
See also: FloorManager, FloorManager::GetNearestFloors
|
|
*************************************************/
|
|
void
|
|
FloorManager::SetCacheSize(int size)
|
|
{
|
|
m_CacheSize = size;
|
|
}
|
|
|
|
CKERROR
|
|
FloorManager::SequenceToBeDeleted(CK_ID* iIDs,int iCount)
|
|
{
|
|
if (!m_FloorEdges.Size())
|
|
return CK_OK;
|
|
|
|
HashFloor2Edges::Iterator it = m_FloorEdges.Begin();
|
|
while (it != m_FloorEdges.End()) {
|
|
|
|
if (it.GetKey()->IsToBeDeleted()) {
|
|
it = m_FloorEdges.Remove(it);
|
|
} else {
|
|
++it;
|
|
}
|
|
|
|
}
|
|
|
|
return CK_OK;
|
|
}
|
|
|
|
void
|
|
FloorManager::ComputeEdges(CK3dEntity* iFloor, XArray<GeomEdge>& oEdges)
|
|
{
|
|
oEdges.Resize(0);
|
|
|
|
// first determine the edges of the floor
|
|
CKMesh* mesh = iFloor->GetCurrentMesh();
|
|
if (!mesh) return;
|
|
|
|
// Gestion des matrices indirectes
|
|
const VxMatrix& wm = iFloor->GetWorldMatrix();
|
|
VxVector dx = wm[0];
|
|
VxVector dy = wm[1];
|
|
VxVector cp = CrossProduct(dx,dy);
|
|
|
|
bool direct = true;
|
|
if (DotProduct(cp,wm[2]) < 0.0f)
|
|
direct = false;
|
|
|
|
XHashTable<int,Edge> hash;
|
|
|
|
CKDWORD fStride = 0;
|
|
BYTE* p = mesh->GetFaceNormalsPtr(&fStride);
|
|
XPtrStrided<VxVector> normals(p,fStride);
|
|
|
|
// first add all the edges
|
|
int faceCount = mesh->GetFaceCount();
|
|
CKVINDEX* facePtr = mesh->GetFacesIndices();
|
|
|
|
hash.Reserve(faceCount*3);
|
|
|
|
XHashTable<int,Edge>::Pair edgePair(hash.End(),0);
|
|
Edge newEdge;
|
|
|
|
for (int f=0; f < faceCount; ++f) {
|
|
|
|
CKVINDEX va = facePtr[f*3+0];
|
|
CKVINDEX vb = facePtr[f*3+1];
|
|
CKVINDEX vc = facePtr[f*3+2];
|
|
|
|
// add the 3 edges of the face
|
|
{
|
|
newEdge.a = va;
|
|
newEdge.b = vb;
|
|
edgePair = hash.TestInsert(newEdge,1);
|
|
if (!edgePair.m_New) {
|
|
(*edgePair.m_Iterator)++;
|
|
// edgePair.m_Iterator.GetKey().fb = f;
|
|
} else {
|
|
edgePair.m_Iterator.GetKey().fa = f;
|
|
}
|
|
}
|
|
|
|
{
|
|
newEdge.a = vb;
|
|
newEdge.b = vc;
|
|
edgePair = hash.TestInsert(newEdge,1);
|
|
if (!edgePair.m_New) {
|
|
(*edgePair.m_Iterator)++;
|
|
// edgePair.m_Iterator.GetKey().fb = f;
|
|
} else {
|
|
edgePair.m_Iterator.GetKey().fa = f;
|
|
}
|
|
}
|
|
|
|
{
|
|
newEdge.a = vc;
|
|
newEdge.b = va;
|
|
edgePair = hash.TestInsert(newEdge,1);
|
|
if (!edgePair.m_New) {
|
|
(*edgePair.m_Iterator)++;
|
|
// edgePair.m_Iterator.GetKey().fb = f;
|
|
} else {
|
|
edgePair.m_Iterator.GetKey().fa = f;
|
|
}
|
|
}
|
|
}
|
|
|
|
// then keep the single edges
|
|
// by creating geometric edges
|
|
|
|
XHashTable<int,Edge>::Iterator it = hash.Begin();
|
|
XHashTable<int,Edge>::Iterator itend = hash.End();
|
|
|
|
// get the mesh positions
|
|
CKDWORD stride;
|
|
void* ptr = mesh->GetPositionsPtr(&stride);
|
|
XPtrStrided<VxVector> positions(ptr,stride);
|
|
|
|
while (it != itend) {
|
|
if (*it == 1) {
|
|
const Edge& e = it.GetKey();
|
|
|
|
// add a new geom edge
|
|
oEdges.Expand();
|
|
GeomEdge& ge = oEdges.Back();
|
|
|
|
VxVector va;
|
|
iFloor->Transform(&va,&positions[(int)e.a]);
|
|
VxVector vb;
|
|
iFloor->Transform(&vb,&positions[(int)e.b]);
|
|
VxVector fnormal;
|
|
iFloor->TransformVector(&fnormal,&normals[(int)e.fa]);
|
|
|
|
if (fnormal.y <= EPSILON) { // this face is not facing the up direction
|
|
|
|
// skip this edge
|
|
oEdges.Expand(-1);
|
|
++it;
|
|
continue;
|
|
}
|
|
|
|
// store the positions
|
|
ge.a.Set(va.x,va.z);
|
|
ge.b.Set(vb.x,vb.z);
|
|
|
|
// create the plane
|
|
|
|
VxVector vedge = vb - va;
|
|
vedge.y = 0.0f;
|
|
|
|
// calculate the outward normal
|
|
VxVector norm = CrossProduct(fnormal,vedge);
|
|
|
|
if (!direct)
|
|
norm = -norm;
|
|
|
|
norm.y = 0.0f;
|
|
norm.Normalize();
|
|
|
|
ge.length = Magnitude(vedge);
|
|
ge.invLength = 1.0f / ge.length;
|
|
|
|
// the plane itself
|
|
ge.normal.Set(norm.x,norm.z);
|
|
ge.D = -ge.normal.Dot(ge.a);
|
|
}
|
|
|
|
++it;
|
|
}
|
|
}
|
|
|
|
CKBOOL
|
|
FloorManager::SlideOnEdges(VxVector& ioPosition, float iRadius, const XArray<GeomEdge>& iEdges, CK3dEntity* iFloor, CKAttributeType iExcludeAttribute)
|
|
{
|
|
CKBOOL touched = FALSE;
|
|
|
|
/*
|
|
// Drawing of the floor
|
|
CKRenderManager* rm = m_Context->GetRenderManager();
|
|
|
|
{
|
|
for (XArray<GeomEdge>::Iterator it = iEdges.Begin(); it != iEdges.End(); ++it) {
|
|
GeomEdge& ge = *it;
|
|
|
|
VxPlane plane;
|
|
plane.Create(VxVector(ge.normal.x,0.0f,ge.normal.y),VxVector(ge.a.x,0.0f,ge.a.y));
|
|
|
|
rm->RegisterPlane(plane,VxVector((ge.a.x+ge.b.x)*0.5f,ioPosition.y,(ge.a.y+ge.b.y)*0.5f),0xff00ff00,0.0f);
|
|
}
|
|
rm->RegisterSphere(VxSphere(ioPosition,2.0f),0xff00ff00,0.0f);
|
|
}
|
|
*/
|
|
|
|
|
|
Vx2DVector pos2D(ioPosition.x,ioPosition.z);
|
|
|
|
for (XArray<GeomEdge>::Iterator it = iEdges.Begin(); it != iEdges.End(); ++it) {
|
|
|
|
GeomEdge& ge = *it;
|
|
|
|
float dist = ge.normal.Dot(pos2D) + ge.D;
|
|
|
|
if (dist >= iRadius) // not in the edge area
|
|
continue;
|
|
if (dist <= 0.0f) // bad side of the edge
|
|
continue;
|
|
|
|
Vx2DVector leftEdge = ge.a - ge.b;
|
|
leftEdge *= ge.invLength;
|
|
|
|
float distLeft = leftEdge.Dot(pos2D - ge.a);
|
|
|
|
if (distLeft >= iRadius)
|
|
continue;
|
|
|
|
if (distLeft >= 0) { // touching the left corner
|
|
|
|
float distanceToMove = iRadius - sqrtf(distLeft*distLeft+ dist*dist);
|
|
if (distanceToMove > 0.0f) {
|
|
pos2D += (distanceToMove) * (pos2D - ge.a).Normalize();
|
|
touched = TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
float distRight = -(ge.length + distLeft);
|
|
|
|
if (distRight >= iRadius)
|
|
continue;
|
|
|
|
if (distRight >= 0) { // touching the right corner
|
|
float distanceToMove = iRadius - sqrtf(distRight*distRight + dist*dist);
|
|
if (distanceToMove > 0.0f) {
|
|
pos2D += (distanceToMove) * (pos2D - ge.b).Normalize();
|
|
touched = TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// else in the limit of the plane
|
|
|
|
///
|
|
// we need to check if we are not going to another floor...
|
|
{
|
|
Vx2DVector goingPosition2D = pos2D - iRadius*ge.normal;
|
|
VxVector goingPosition(goingPosition2D.x,ioPosition.y,goingPosition2D.y);
|
|
|
|
CKFloorPoint fp;
|
|
CK_FLOORNEAREST fn = GetNearestFloors(goingPosition,&fp,iFloor);
|
|
if (fn != CKFLOOR_NOFLOOR) {
|
|
|
|
CK3dEntity* nextFloor = NULL;
|
|
if (fn == CKFLOOR_DOWN)
|
|
nextFloor = (CK3dEntity*)CKGetObject(fp.m_DownFloor);
|
|
else
|
|
nextFloor = (CK3dEntity*)CKGetObject(fp.m_UpFloor);
|
|
|
|
// we do not take into account floor with the exclude attribute
|
|
// (if the attribute is != -1)
|
|
if ((iExcludeAttribute == -1) || !nextFloor->HasAttribute(iExcludeAttribute))
|
|
continue; // we're going somewhere, so do not constrain
|
|
}
|
|
}
|
|
|
|
|
|
pos2D += (iRadius - dist) * ge.normal;
|
|
|
|
// The object has been touched
|
|
touched = TRUE;
|
|
}
|
|
|
|
ioPosition.x = pos2D.x;
|
|
ioPosition.z = pos2D.y;
|
|
|
|
return touched;
|
|
}
|
|
|
|
|
|
CKBOOL
|
|
FloorManager::ConstrainToFloor(const VxVector &iPosition, float iRadius, VxVector* oPosition, CKAttributeType iExcludeAttribute)
|
|
{
|
|
CKBOOL touched = FALSE;
|
|
|
|
CKFloorPoint fp;
|
|
CK_FLOORNEAREST fn = GetNearestFloors(iPosition,&fp);
|
|
if (fn != CKFLOOR_NOFLOOR) { // we are over a floor
|
|
|
|
// get the floor
|
|
CK_ID floorID = NULL;
|
|
switch (fn) {
|
|
case CKFLOOR_DOWN:
|
|
floorID = fp.m_DownFloor;
|
|
break;
|
|
case CKFLOOR_UP:
|
|
floorID = fp.m_UpFloor;
|
|
break;
|
|
}
|
|
|
|
CK3dEntity* floor = CK3dEntity::Cast(CKGetObject(floorID));
|
|
if (floor) {
|
|
|
|
// If the floor must not be considered, we exit there
|
|
if ((iExcludeAttribute != -1) && (floor->HasAttribute(iExcludeAttribute))) {
|
|
CK_FLOORNEAREST fn = GetNearestFloors(iPosition,&fp,floor);
|
|
if (fn == CKFLOOR_NOFLOOR)
|
|
return FALSE;
|
|
|
|
// we are over a floor
|
|
// get the floor
|
|
CK_ID floorID = NULL;
|
|
switch (fn) {
|
|
case CKFLOOR_DOWN:
|
|
floorID = fp.m_DownFloor;
|
|
break;
|
|
case CKFLOOR_UP:
|
|
floorID = fp.m_UpFloor;
|
|
break;
|
|
}
|
|
|
|
floor = CK3dEntity::Cast(CKGetObject(floorID));
|
|
if (!floor)
|
|
return FALSE;
|
|
|
|
// If the floor must not be considered, we exit there
|
|
if ((iExcludeAttribute != -1) && (floor->HasAttribute(iExcludeAttribute))) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
CKMesh* floorMesh = floor->GetCurrentMesh();
|
|
|
|
// get the cached edges
|
|
EdgesArray* edges = m_FloorEdges.FindPtr(floorMesh);
|
|
|
|
if (!edges) { // we need to recalculate the edges
|
|
EdgesArray newEdges;
|
|
HashFloor2Edges::Iterator it = m_FloorEdges.Insert(floorMesh,newEdges);
|
|
|
|
edges = &(*it);
|
|
|
|
// the computing
|
|
ComputeEdges(floor,*edges);
|
|
}
|
|
|
|
///
|
|
// Now the sliding
|
|
|
|
// transform the position in the ref of the floor
|
|
VxVector lpos = iPosition;
|
|
|
|
touched = SlideOnEdges(lpos,iRadius,*edges, floor, iExcludeAttribute);
|
|
|
|
if (touched) {// sets back to the world the new position
|
|
*oPosition = lpos;
|
|
}
|
|
}
|
|
}
|
|
|
|
return touched;
|
|
}
|
|
|
|
CKBOOL
|
|
FloorManager::ConstrainToFloor(const VxVector &iOldPosition, const VxVector &iPosition, float iRadius, VxVector* oPosition, CKAttributeType iExcludeAttribute)
|
|
{
|
|
VxVector dir = iPosition - iOldPosition;
|
|
|
|
float dist = Magnitude(dir);
|
|
|
|
if (dist < iRadius) {
|
|
return ConstrainToFloor(iPosition,iRadius,oPosition,iExcludeAttribute);
|
|
} else {
|
|
|
|
// we have to reduce a little the radius because, if we have been constrained
|
|
// the past frame, the old position surely is at an exact radius distance
|
|
// from the edge, so the test could miss it...
|
|
float reducedRadius = iRadius * 0.99f; // Hard coded reduced factor
|
|
|
|
int steps = (int)(dist / reducedRadius);
|
|
|
|
// calculate the step vector
|
|
dir *= reducedRadius / dist;
|
|
|
|
VxVector pos = iOldPosition;
|
|
|
|
// test intermediate positions
|
|
while (steps--) {
|
|
pos += dir;
|
|
|
|
if (ConstrainToFloor(pos,iRadius,oPosition,iExcludeAttribute)) { // has been constrained
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// we now have to test the last position
|
|
return ConstrainToFloor(iPosition,iRadius,oPosition,iExcludeAttribute);
|
|
|
|
}
|
|
}
|
|
|
|
CK_FLOORNEAREST
|
|
FloorManager::GetNearestFloor(const VxVector &iPosition, CK3dEntity** oFloor, int* oFaceIndex, VxVector* oNormal, float* oDistance, CK3dEntity* iExcludeFloor)
|
|
{
|
|
CKFloorPoint fp;
|
|
|
|
CK_FLOORNEAREST res = GetNearestFloors(iPosition,&fp,iExcludeFloor);
|
|
|
|
switch(res) {
|
|
case CKFLOOR_UP:
|
|
*oFloor = (CK3dEntity*)m_Context->GetObject(fp.m_UpFloor);
|
|
*oFaceIndex = fp.m_UpFaceIndex;
|
|
*oNormal = fp.m_UpNormal;
|
|
*oDistance = fp.m_UpDistance;
|
|
break;
|
|
|
|
case CKFLOOR_DOWN:
|
|
*oFloor = (CK3dEntity*)m_Context->GetObject(fp.m_DownFloor);
|
|
*oFaceIndex = fp.m_DownFaceIndex;
|
|
*oNormal = fp.m_DownNormal;
|
|
*oDistance = fp.m_DownDistance;
|
|
break;
|
|
|
|
case CKFLOOR_NOFLOOR:
|
|
*oFloor = NULL;
|
|
*oFaceIndex = -1;
|
|
oNormal->Set(0,0,0);
|
|
*oDistance=100000000.0f;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// {secret}
|
|
CKGUID GetFloorManagerGuid()
|
|
{
|
|
return FLOOR_MANAGER_GUID;
|
|
}
|
|
|
|
// {secret}
|
|
void
|
|
FloorManager::VSLBind()
|
|
{
|
|
STARTVSLBIND(m_Context)
|
|
|
|
// enum
|
|
DECLAREENUM("CK_FLOORNEAREST")
|
|
DECLAREENUMVALUE("CK_FLOORNEAREST", "CKFLOOR_NOFLOOR" , 0x00000000)
|
|
DECLAREENUMVALUE("CK_FLOORNEAREST", "CKFLOOR_DOWN" , 0x00000001)
|
|
DECLAREENUMVALUE("CK_FLOORNEAREST", "CKFLOOR_UP" , 0x00000002)
|
|
|
|
DECLAREENUM("CK_FLOORGEOMETRY")
|
|
DECLAREENUMVALUE("CK_FLOORGEOMETRY", "CKFLOOR_FACES" , 0x00000000)
|
|
DECLAREENUMVALUE("CK_FLOORGEOMETRY", "CKFLOOR_BOX" , 0x00000001)
|
|
REGISTERVSLGUID(CKPGUID_FLOORGEOMETRY,"CK_FLOORGEOMETRY")
|
|
|
|
// Manager
|
|
DECLAREPOINTERTYPEALIAS(FloorManager, "FloorManager")
|
|
DECLAREFUN_C_0 (CKGUID ,GetFloorManagerGuid)
|
|
DECLARESTATIC_1 (FloorManager, FloorManager*, Cast, CKBaseManager* iM)
|
|
|
|
// Methods
|
|
DECLAREMETHOD_6_WITH_DEF_VALS (FloorManager, CK_FLOORNEAREST, GetNearestFloor, const VxVector &iPosition, NODEFAULT, CK3dEntity** oFloor, NODEFAULT, int* oFaceIndex, NULL, VxVector* oNormal, NULL, float* oDistance, NULL, CK3dEntity* iExcludeFloor, NULL)
|
|
DECLAREMETHOD_4_WITH_DEF_VALS (FloorManager, CKBOOL, ConstrainToFloor, const VxVector &iPosition, NODEFAULT, float iRadius, NODEFAULT, VxVector* oPosition, NODEFAULT, CKAttributeType iExcludeAttribute, -1)
|
|
DECLAREMETHOD_1 (FloorManager, void, SetLimitAngle, float angle)
|
|
DECLAREMETHOD_0 (FloorManager, float, GetLimitAngle)
|
|
DECLAREMETHOD_7 (FloorManager, int, AddFloorObjectsByName, CKLevel* level, char* floorname, CK_FLOORGEOMETRY geo, CKBOOL moving, int type, CKBOOL hiera, CKBOOL first)
|
|
DECLAREMETHOD_6 (FloorManager, void, AddFloorObject, CK3dEntity* ent, CK_FLOORGEOMETRY geo, CKBOOL moving, int type, CKBOOL hiera, CKBOOL first)
|
|
DECLAREMETHOD_1 (FloorManager, void, RemoveFloorObject, CK3dEntity* ent)
|
|
DECLAREMETHOD_0 (FloorManager, int, GetFloorObjectCount)
|
|
DECLAREMETHOD_1 (FloorManager, CK3dEntity*, GetFloorObject, int pos)
|
|
DECLAREMETHOD_5_WITH_DEF_VALS (FloorManager, CKBOOL, ConstrainToFloor, const VxVector &iOldPosition, NODEFAULT,const VxVector &iPosition, NODEFAULT, float iRadius, NODEFAULT, VxVector* oPosition, NODEFAULT, CKAttributeType iExcludeAttribute, -1)
|
|
|
|
STOPVSLBIND
|
|
}
|
|
|