Browse Source

Merge pull request #149 from Hoikas/physx

More PhysX Fixes
NadnerbD 13 years ago
parent
commit
ccf5f59fda
  1. 4
      Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp
  2. 41
      Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp
  3. 2
      Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h
  4. 74
      Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp
  5. 57
      Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
  6. 9
      Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
  7. 367
      Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp
  8. 61
      Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h

4
Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp

@ -133,8 +133,10 @@ void plWalkingController::RecalcVelocity(double timeNow, double timePrev, hsBool
if (fController && !fWalkingStrategy->IsOnGround()) if (fController && !fWalkingStrategy->IsOnGround())
{ {
// PhysX Hack: AchievedLinearVelocity is a Cyanic fix for superjumps. LinearVelocity is
// always (0,0,0) outside of the controller update proc
fImpactTime = fWalkingStrategy->GetAirTime(); fImpactTime = fWalkingStrategy->GetAirTime();
fImpactVelocity = fController->GetLinearVelocity(); fImpactVelocity = fController->GetAchievedLinearVelocity();
fClearImpact = false; fClearImpact = false;
} }
else else

41
Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp

@ -323,48 +323,7 @@ void plWalkingStrategy::Apply(float delSecs)
LinearVelocity.fX = AchievedLinearVelocity.fX; LinearVelocity.fX = AchievedLinearVelocity.fX;
LinearVelocity.fY = AchievedLinearVelocity.fY; LinearVelocity.fY = AchievedLinearVelocity.fY;
} }
if (!IsOnGround() || IsOnFalseGround())
{
// We're not on solid ground, so we should be sliding against whatever
// we're hitting (like a rock cliff). Each vector in fSlidingNormals is
// the surface normal of a collision that's too steep to be ground, so
// we project our current velocity onto that plane and slide along the
// wall.
//
// Also, sometimes PhysX reports a bunch of collisions from the wall,
// but nothing from underneath (when there should be). So if we're not
// touching ground, we offset the avatar in the direction of the
// surface normal(s). This doesn't fix the issue 100%, but it's a hell
// of a lot better than nothing, and suitable duct tape until a future
// PhysX revision fixes the issue.
//
// Yes, there's room for optimization here if we care.
hsVector3 offset(0.f, 0.f, 0.f);
for (int i = 0; i < fContactNormals.GetCount(); i++)
{
offset += fContactNormals[i];
hsVector3 velNorm = LinearVelocity;
if (velNorm.MagnitudeSquared() > 0)
velNorm.Normalize();
if (velNorm * fContactNormals[i] < 0)
{
hsVector3 proj = (velNorm % fContactNormals[i]) % fContactNormals[i];
if (velNorm * proj < 0)
proj *= -1.f;
LinearVelocity = LinearVelocity.Magnitude() * proj;
}
}
if (offset.MagnitudeSquared() > 0)
{
// 5 ft/sec is roughly the speed we walk backwards.
// The higher the value, the less likely you'll trip
// the bug, and this seems reasonable.
offset.Normalize();
LinearVelocity += offset * 5.0f;
}
}
//make terminal velocity equal to k. it is wrong but has been this way and //make terminal velocity equal to k. it is wrong but has been this way and
//don't want to break any puzzles. on top of that it will reduce tunneling behavior //don't want to break any puzzles. on top of that it will reduce tunneling behavior
if(LinearVelocity.fZ<kGravity)LinearVelocity.fZ=kGravity; if(LinearVelocity.fZ<kGravity)LinearVelocity.fZ=kGravity;

2
Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h

@ -50,7 +50,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "hsQuat.h" #include "hsQuat.h"
#define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1 #define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1
#define kSLOPELIMIT (cosf(hsDegreesToRadians(55.f))) #define kSLOPELIMIT (cosf(hsDegreesToRadians(45.f)))
class plCoordinateInterface; class plCoordinateInterface;
class plPhysical; class plPhysical;

74
Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp

@ -71,13 +71,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#define kPhysxSkinWidth 0.1f #define kPhysxSkinWidth 0.1f
#define kPhysZOffset ((fRadius + (fHeight / 2)) + kPhysxSkinWidth) #define kPhysZOffset ((fRadius + (fHeight / 2)) + kPhysxSkinWidth)
//#define kSLOPELIMIT (cosf(NxMath::degToRad(55.f)))
//#define kPhysicalHeightFudge 0.4f // this fudge was used for PhysX 2.4
#define kPhysicalHeightFudge 0.0f #define kPhysicalHeightFudge 0.0f
#define STEP_OFFSET 1.f
//#define STEP_OFFSET 1.0f #define kAvatarMass 160.f
#define STEP_OFFSET 0.5f
//#define STEP_OFFSET 0.15f
#ifndef PLASMA_EXTERNAL_RELEASE #ifndef PLASMA_EXTERNAL_RELEASE
@ -89,8 +85,6 @@ static ControllerManager gControllerMgr;
static std::vector<plPXPhysicalControllerCore*> gControllers; static std::vector<plPXPhysicalControllerCore*> gControllers;
static bool gRebuildCache=false; static bool gRebuildCache=false;
#define AvatarMass 200.f
class PXControllerHitReportWalk : public NxUserControllerHitReport class PXControllerHitReportWalk : public NxUserControllerHitReport
{ {
public: public:
@ -99,9 +93,9 @@ public:
plPXPhysicalControllerCore* ac = plPXPhysicalControllerCore::FindController(hit.controller); plPXPhysicalControllerCore* ac = plPXPhysicalControllerCore::FindController(hit.controller);
NxActor& actor = hit.shape->getActor(); NxActor& actor = hit.shape->getActor();
plPXPhysical* phys = (plPXPhysical*)actor.userData; plPXPhysical* phys = (plPXPhysical*)actor.userData;
static float SlopeLimit = kSLOPELIMIT;
hsVector3 normal = plPXConvert::Vector(hit.worldNormal); hsVector3 normal = plPXConvert::Vector(hit.worldNormal);
ac->fMovementInterface->IAddContactNormals(normal); ac->fMovementInterface->IAddContactNormals(normal);
#ifndef PLASMA_EXTERNAL_RELEASE #ifndef PLASMA_EXTERNAL_RELEASE
plDbgCollisionInfo info; plDbgCollisionInfo info;
info.fNormal = normal; info.fNormal = normal;
@ -124,6 +118,7 @@ public:
} }
ac->fDbgCollisionInfo.Append(info); ac->fDbgCollisionInfo.Append(info);
#endif PLASMA_EXTERNAL_RELEASE #endif PLASMA_EXTERNAL_RELEASE
// If the avatar hit a movable physical, apply some force to it. // If the avatar hit a movable physical, apply some force to it.
hsVector3 dir = plPXConvert::Vector(hit.dir); hsVector3 dir = plPXConvert::Vector(hit.dir);
float dirdotup=dir.fZ; float dirdotup=dir.fZ;
@ -131,15 +126,16 @@ public:
NxExtendedVec3 controllerPos=hit.controller->getPosition(); NxExtendedVec3 controllerPos=hit.controller->getPosition();
hsVector3 bottomOfTheCapsule((float)controllerPos.x,(float)controllerPos.y,(float)controllerPos.z); hsVector3 bottomOfTheCapsule((float)controllerPos.x,(float)controllerPos.y,(float)controllerPos.z);
bottomOfTheCapsule.fZ=bottomOfTheCapsule.fZ-(ac->fHeight/2.0f + ac->fRadius); bottomOfTheCapsule.fZ=bottomOfTheCapsule.fZ-(ac->fHeight/2.0f + ac->fRadius);
if (actor.isDynamic() ) if (actor.isDynamic() && phys )
{ {
if((hit.worldPos.z- bottomOfTheCapsule.fZ)<=ac->fRadius)//bottom hemisphere if((hit.worldPos.z- bottomOfTheCapsule.fZ)<=ac->fRadius)//bottom hemisphere
{ {
//onTopOfSlopeLimit // If this is an animated physical, we can stand on it
if (phys && phys->GetProperty(plSimulationInterface::kPhysAnim)) if (phys->GetProperty(plSimulationInterface::kPhysAnim))
{ {
if(normal.fZ>=0) if(normal.fZ>=0)
{//we consider this ground {
//we consider this ground
ac->fMovementInterface->AddOnTopOfObject(phys); ac->fMovementInterface->AddOnTopOfObject(phys);
} }
} }
@ -161,52 +157,22 @@ public:
setNetGroupID->Send(obj->GetKey()); setNetGroupID->Send(obj->GetKey());
} }
plSimulationMgr::GetInstance()->ConsiderSynch(phys, nil); plSimulationMgr::GetInstance()->ConsiderSynch(phys, nil);
// We only allow horizontal pushes. Vertical pushes when we stand on
// dynamic objects creates useless stress on the solver.
hsVector3 vel=ac->GetLinearVelocity()- plPXConvert::Vector( actor.getLinearVelocity()); // Now, let's impart some force, fool.
if(dirdotup>=0)vel.fZ=0.001f; // Note: This is a VERY simple implementation. The old one was too hacky and caused weird stuff to happen.
else vel.fZ=0.0f; hsVector3 acceleration = (ac->GetLinearVelocity() - plPXConvert::Vector(actor.getLinearVelocity()));
static float kAvieMass = 140.f/32.f; hsVector3 force2impart = acceleration * kAvatarMass;
if (!vel.IsEmpty()) // Bad things happen if we impart force directly on top of the actor, so let's allow the avatar to run
{ // over those physicals and not break them. This is mostly an issue with stuff smaller than step size.
static float kForceScale = 140.0f; if (!force2impart.IsEmpty() && normal.fZ < .90f)
NxF32 coeff; phys->SetHitForce(force2impart, pos);
NxExtendedVec3 norm2=hit.controller->getPosition();
norm2.x=hit.worldPos.x-bottomOfTheCapsule.fX;
norm2.y=hit.worldPos.y-bottomOfTheCapsule.fY;
if((hit.worldPos.z- bottomOfTheCapsule.fZ)<ac->fRadius)//bottom hemisphere
{
norm2.normalize();
norm2.z=0.01f;
}
else if((hit.worldPos.z- bottomOfTheCapsule.fZ)<(ac->fRadius+ac->fHeight))
{
norm2.z=0.0f;
norm2.normalize();
}
else
{//must be the top so the normal is displacement from the pos - center
//of top hemisphere
norm2.z=hit.worldPos.z - ((ac->fRadius+ac->fHeight + bottomOfTheCapsule.fZ));
norm2.normalize();
}
float proj=(float)(norm2.x*dir.fX+dir.fY*norm2.y+dir.fZ*norm2.z);
coeff =abs(proj*kForceScale*vel.Magnitude());
vel.fZ=(float)norm2.z;
vel.fY=(float)norm2.y;
vel.fX=(float)norm2.x;
phys->SetHitForce(vel*coeff, pos);
}
} }
} }
else // else if the avatar hit a static else // else if the avatar hit a static
{ {
return NX_ACTION_NONE; return NX_ACTION_NONE;
} }
if (phys && phys->GetProperty(plSimulationInterface::kAvAnimPushable)) if (phys->GetProperty(plSimulationInterface::kAvAnimPushable))
{ {
hsQuat inverseRotation = ac->fLocalRotation.Inverse(); hsQuat inverseRotation = ac->fLocalRotation.Inverse();
hsVector3 normal = plPXConvert::Vector(hit.worldNormal); hsVector3 normal = plPXConvert::Vector(hit.worldNormal);
@ -546,7 +512,7 @@ NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0); capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0);
actorDesc.shapes.pushBack(&capDesc); actorDesc.shapes.pushBack(&capDesc);
NxBodyDesc bodyDesc; NxBodyDesc bodyDesc;
bodyDesc.mass = AvatarMass;//1.f; bodyDesc.mass = kAvatarMass;
actorDesc.body = &bodyDesc; actorDesc.body = &bodyDesc;
bodyDesc.flags = NX_BF_KINEMATIC; bodyDesc.flags = NX_BF_KINEMATIC;
bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ; bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ;
@ -619,7 +585,7 @@ void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos)
capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0); capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0);
actorDesc.globalPose=actor->getGlobalPose(); actorDesc.globalPose=actor->getGlobalPose();
NxBodyDesc bodyDesc; NxBodyDesc bodyDesc;
bodyDesc.mass = AvatarMass; bodyDesc.mass = kAvatarMass;
actorDesc.body = &bodyDesc; actorDesc.body = &bodyDesc;
bodyDesc.flags = NX_BF_KINEMATIC; bodyDesc.flags = NX_BF_KINEMATIC;
bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ; bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ;

57
Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp

@ -156,7 +156,7 @@ class SensorReport : public NxUserTriggerReport
{ {
if (plSimulationMgr::fExtraProfile) if (plSimulationMgr::fExtraProfile)
DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true);
} }
else if (status & NX_TRIGGER_ON_ENTER) else if (status & NX_TRIGGER_ON_ENTER)
{ {
@ -167,7 +167,7 @@ class SensorReport : public NxUserTriggerReport
{ {
if (plSimulationMgr::fExtraProfile) if (plSimulationMgr::fExtraProfile)
DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false);
} }
else if (status & NX_TRIGGER_ON_LEAVE) else if (status & NX_TRIGGER_ON_LEAVE)
{ {
@ -187,13 +187,13 @@ class SensorReport : public NxUserTriggerReport
{ {
if (plSimulationMgr::fExtraProfile) if (plSimulationMgr::fExtraProfile)
DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true);
} }
if (status & NX_TRIGGER_ON_LEAVE) if (status & NX_TRIGGER_ON_LEAVE)
{ {
if (plSimulationMgr::fExtraProfile) if (plSimulationMgr::fExtraProfile)
DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit"); DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
SendCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false); plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false);
} }
if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) ) if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) )
{ {
@ -205,18 +205,6 @@ class SensorReport : public NxUserTriggerReport
#endif // USE_PHYSX_CONVEXHULL_WORKAROUND #endif // USE_PHYSX_CONVEXHULL_WORKAROUND
} }
} }
void SendCollisionMsg(plKey receiver, plKey hitter, hsBool entering)
{
DetectorLogYellow("Collision: %s was triggered by %s. Sending an %s msg", receiver->GetName().c_str(),
hitter ? hitter->GetName().c_str() : "(nil)" , entering ? "'enter'" : "'exit'");
plCollideMsg* msg = new plCollideMsg;
msg->fOtherKey = hitter;
msg->fEntering = entering;
msg->AddReceiver(receiver);
plgDispatch::Dispatch()->MsgQueue(msg); // Sends the msg on the next client update
}
} gSensorReport; } gSensorReport;
// This gets called by PhysX whenever two actor groups that are set to report // This gets called by PhysX whenever two actor groups that are set to report
@ -599,6 +587,34 @@ void plSimulationMgr::UpdateAvatarInDetector(plKey world, plPXPhysical* detector
} }
} }
void plSimulationMgr::AddCollisionMsg(plKey hitee, plKey hitter, bool enter)
{
// First, make sure we have no dupes
for (CollisionVec::iterator it = fCollideMsgs.begin(); it != fCollideMsgs.end(); ++it)
{
plCollideMsg* pMsg = *it;
// Should only ever be one receiver.
// Oh, it seems we should update the hit status. The latest might be different than the older...
// Even in the same frame >.<
if (pMsg->fOtherKey == hitter && pMsg->GetReceiver(0) == hitee)
{
pMsg->fEntering = enter;
DetectorLogRed("DUPLICATE COLLISION: %s hit %s",
(hitter ? hitter->GetName().c_str() : "(nil)"),
(hitee ? hitee->GetName().c_str() : "(nil)"));
return;
}
}
// Still here? Then this must be a unique hit!
plCollideMsg* pMsg = new plCollideMsg;
pMsg->AddReceiver(hitee);
pMsg->fOtherKey = hitter;
pMsg->fEntering = enter;
fCollideMsgs.push_back(pMsg);
}
void plSimulationMgr::Advance(float delSecs) void plSimulationMgr::Advance(float delSecs)
{ {
if (fSuspended) if (fSuspended)
@ -693,6 +709,15 @@ void plSimulationMgr::Advance(float delSecs)
void plSimulationMgr::ISendUpdates() void plSimulationMgr::ISendUpdates()
{ {
for (CollisionVec::iterator it = fCollideMsgs.begin(); it != fCollideMsgs.end(); ++it)
{
plCollideMsg* pMsg = *it;
DetectorLogYellow("Collision: %s was triggered by %s. Sending an %s msg", pMsg->GetReceiver(0)->GetName().c_str(),
pMsg->fOtherKey ? pMsg->fOtherKey->GetName().c_str() : "(nil)" , pMsg->fEntering ? "'enter'" : "'exit'");
plgDispatch::Dispatch()->MsgSend(pMsg);
}
fCollideMsgs.clear();
SceneMap::iterator it = fScenes.begin(); SceneMap::iterator it = fScenes.begin();
for (; it != fScenes.end(); it++) for (; it != fScenes.end(); it++)
{ {

9
Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h

@ -102,11 +102,14 @@ public:
// PHYSX FIXME - walk thru all the convex hull detector regions to see if we are in any... we're either coming or going // PHYSX FIXME - walk thru all the convex hull detector regions to see if we are in any... we're either coming or going
void UpdateDetectorsInScene(plKey world, plKey avatar, hsPoint3& pos, bool entering); void UpdateDetectorsInScene(plKey world, plKey avatar, hsPoint3& pos, bool entering);
void UpdateAvatarInDetector(plKey world, plPXPhysical* detector); void UpdateAvatarInDetector(plKey world, plPXPhysical* detector);
//Fix to Move collision messages and their handling out of the simulation step //Fix to Move collision messages and their handling out of the simulation step
void AddCollisionMsg(plCollideMsg* msg); void AddCollisionMsg(plKey hitee, plKey hitter, bool entering);
#ifndef PLASMA_EXTERNAL_RELEASE #ifndef PLASMA_EXTERNAL_RELEASE
static bool fDisplayAwakeActors; static bool fDisplayAwakeActors;
#endif //PLASMA_EXTERNAL_RELEASE #endif //PLASMA_EXTERNAL_RELEASE
protected: protected:
friend class ContactReport; friend class ContactReport;
@ -125,6 +128,10 @@ protected:
plPhysicsSoundMgr* fSoundMgr; plPhysicsSoundMgr* fSoundMgr;
// Pending collision messages
typedef std::vector<plCollideMsg*> CollisionVec;
CollisionVec fCollideMsgs;
// A mapping from a key to a PhysX scene. The key is either the // A mapping from a key to a PhysX scene. The key is either the
// SimulationMgr key, for the main world, or a SceneObject key if it's a // SimulationMgr key, for the main world, or a SceneObject key if it's a
// subworld. // subworld.

367
Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp

@ -236,103 +236,56 @@ void plCollisionDetector::Write(hsStream* stream, hsResMgr* mgr)
plCameraRegionDetector::~plCameraRegionDetector() plCameraRegionDetector::~plCameraRegionDetector()
{ {
for(int i = 0; i < fMessages.Count(); i++) for (plCameraMsgVec::iterator it = fMessages.begin(); it != fMessages.end(); ++it)
{ hsRefCnt_SafeUnRef(*it);
plMessage* pMsg = fMessages[i];
fMessages.Remove(i);
delete(pMsg);
}
fMessages.SetCountAndZero(0);
} }
void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate) void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate)
{ {
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
// PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
if (entering && fNumEvals - fLastExitEval <= 1 && fSavingSendMsg)
{
DetectorLog("%s: Skipping Camera Entering volume", GetKeyName().c_str());
fLastEnterEval = fNumEvals;
if (fSavingSendMsg) if (fSavingSendMsg)
{ DetectorLogRed("%s: Stale messages on ITrigger. This should never happen!", GetKeyName().c_str());
DetectorLog("%s: Dumping saved Camera Exiting volume", GetKeyName().c_str()); if (fIsInside && entering)
} DetectorLogRed("%s: Duplicate enter! Did we miss an exit?", GetKeyName().c_str());
fSavingSendMsg = false; else if (!fIsInside && !entering)
return; DetectorLogRed("%s: Duplicate exit! Did we miss an enter?", GetKeyName().c_str());
}
if (!entering && fNumEvals - fLastEnterEval <= 1 && fSavingSendMsg)
{
DetectorLog("%s: Skipping Exiting volume", GetKeyName().c_str());
fLastExitEval = fNumEvals;
if (fSavingSendMsg)
{
DetectorLog("%s: Dumping saved Camera Entering volume", GetKeyName().c_str());
}
fSavingSendMsg = false;
return;
}
// get rid of any saved messages... this should happen though
if (fSavingSendMsg)
{
DetectorLog("%s: Killing saved camera message... shouldn't happen", GetKeyName().c_str());
}
// end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
fSavingSendMsg = true; fSavingSendMsg = true;
fSavedMsgEnterFlag = entering; fSavedMsgEnterFlag = entering;
if (entering) if (entering)
{ {
//DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName().c_str(),fNumEvals); DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName().c_str(),fNumEvals);
fLastEnterEval = fNumEvals; fLastEnterEval = fNumEvals;
} }
else else
{ {
//DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName().c_str(),fNumEvals); DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName().c_str(),fNumEvals);
fLastExitEval = fNumEvals; fLastExitEval = fNumEvals;
} }
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
// PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
// we're saving the message to be dispatched later...
if (immediate) if (immediate)
{
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
ISendSavedTriggerMsgs(); ISendSavedTriggerMsgs();
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
}
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
} }
void plCameraRegionDetector::ISendSavedTriggerMsgs() void plCameraRegionDetector::ISendSavedTriggerMsgs()
{ {
if (fSavingSendMsg) if (fSavingSendMsg)
{ {
for (int i = 0; i < fMessages.Count(); i++) for (size_t i = 0; i < fMessages.size(); ++i)
{ {
char str[256];
hsRefCnt_SafeRef(fMessages[i]); hsRefCnt_SafeRef(fMessages[i]);
if (fSavedMsgEnterFlag) if (fSavedMsgEnterFlag)
{ {
fMessages[i]->SetCmd(plCameraMsg::kEntering); fMessages[i]->SetCmd(plCameraMsg::kEntering);
sprintf(str, "Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.Count()); DetectorLog("Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size());
fIsInside = true; fIsInside = true;
} }
else else
{ {
fMessages[i]->ClearCmd(plCameraMsg::kEntering); fMessages[i]->ClearCmd(plCameraMsg::kEntering);
sprintf(str, "Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.Count()); DetectorLog("Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size());
fIsInside = false; fIsInside = false;
} }
plgDispatch::MsgSend(fMessages[i]); plgDispatch::MsgSend(fMessages[i]);
DetectorLog("%s", str);
} }
} }
fSavingSendMsg = false; fSavingSendMsg = false;
@ -342,38 +295,23 @@ void plCameraRegionDetector::ISendSavedTriggerMsgs()
hsBool plCameraRegionDetector::MsgReceive(plMessage* msg) hsBool plCameraRegionDetector::MsgReceive(plMessage* msg)
{ {
plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg);
if (pCollMsg) if (pCollMsg)
{ {
// camera collisions are only for the local player // camera collisions are only for the local player
if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey) if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey)
return true; return true;
// Fall through to plObjectInVolumeDetector, which will register us for plEvalMsg
// and handle it for us. (Hint: See ISendSavedTriggerMsgs)
#ifdef USE_PHYSX_MULTIPLE_CAMREGION_ENTER
// first determine if this is a multiple camera region enter (PHYSX BUG WORKAROUND)
if (!fWaitingForEval)
{//plObjectInVolumeCollisionDetector::MsgReceive() will flip fWaitingForEval
// and registers for the Eval, child objects of plObjectInVolumeCollisionDetector
//must decide when they are no longer interested in Evals. I suggest using IHandleEvals()
fNumEvals = 0;
fLastEnterEval=-999;
fLastExitEval=-999;
} }
// end of (PHYSX BUG WORKAROUND)
#endif // USE_PHYSX_MULTIPLE_CAMREG_ENTER
}
return plObjectInVolumeDetector::MsgReceive(msg); return plObjectInVolumeDetector::MsgReceive(msg);
} }
void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr) void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr)
{ {
plDetectorModifier::Read(stream, mgr); plDetectorModifier::Read(stream, mgr);
int n = stream->ReadLE32(); int n = stream->ReadLE32();
fMessages.SetCountAndZero(n); fMessages.resize(n);
for(int i = 0; i < n; i++ ) for(size_t i = 0; i < n; i++ )
{ {
plCameraMsg* pMsg = plCameraMsg::ConvertNoRef(mgr->ReadCreatable(stream)); plCameraMsg* pMsg = plCameraMsg::ConvertNoRef(mgr->ReadCreatable(stream));
fMessages[i] = pMsg; fMessages[i] = pMsg;
@ -383,27 +321,10 @@ void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr)
void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr) void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr)
{ {
plDetectorModifier::Write(stream, mgr); plDetectorModifier::Write(stream, mgr);
stream->WriteLE32(fMessages.GetCount()); stream->WriteLE32(fMessages.size());
for(int i = 0; i < fMessages.GetCount(); i++ ) for(plCameraMsgVec::iterator it = fMessages.begin(); it != fMessages.end(); ++it)
mgr->WriteCreatable( stream, fMessages[i] ); mgr->WriteCreatable( stream, *it );
}
void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval)
{
fNumEvals++;
if (fNumEvals - fLastEnterEval > 1 && fNumEvals-fLastExitEval>1)
{
ISendSavedTriggerMsgs();
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
fWaitingForEval = false;
}
else
{
if(fSavedActivatorMsg)
DetectorLog("%s didn't send its message. fNumEvals=%d fLastEnterEval=%d, fLastExit=%d",
GetKeyName().c_str(),fNumEvals, fLastEnterEval, fLastExitEval);
}
} }
///////////////////////////////// /////////////////////////////////
@ -414,127 +335,8 @@ void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval)
void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immediate) void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immediate)
{ {
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND hsRefCnt_SafeUnRef(fSavedActivatorMsg);
// PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame fSavedActivatorMsg = new plActivatorMsg;
/* if (entering && fNumEvals - fLastExitEval <= 1 && fSavedActivatorMsg)
{
//DetectorLog("%s: Skipping Entering volume", GetKeyName());
fLastEnterEval = fNumEvals;
if (fSavedActivatorMsg)
{
//DetectorLog("%s: Dumping saved Exiting volume", GetKeyName());
delete fSavedActivatorMsg;
}
fSavedActivatorMsg = nil;
return;
}
if (!entering && fNumEvals - fLastEnterEval <= 1 && fSavedActivatorMsg)
{
//DetectorLog("%s: Skipping Exiting volume", GetKeyName());
fLastExitEval = fNumEvals;
if (fSavedActivatorMsg)
{
//DetectorLog("%s: Dumping saved Entering volume", GetKeyName());
delete fSavedActivatorMsg;
}
fSavedActivatorMsg = nil;
return;
}
// get rid of any saved messages... this should happen though
if (fSavedActivatorMsg)
{
delete fSavedActivatorMsg;
DetectorLog("%s: Killing saved message... shouldn't happen", GetKeyName());
}
// end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
*/
if(!immediate)
{
bookKeepingList::iterator curit=fCollisionList.begin();
while(curit!=fCollisionList.end())
{
if(hitter==(*curit)->hitter)
{//hey the object is already in my list
//try and figure out what my real state is
if(entering)
{
(*curit)->enters++;
if(!(*curit)->fSubStepCurState)
{//We weren't already in
(*curit)->fSubStepCurState =true;
}
}
else
{
(*curit)->exits++;
if((*curit)->fSubStepCurState)
{//We were already in
(*curit)->fSubStepCurState =false;
}
}
//get out
break;
}
curit++;
}
if(curit==fCollisionList.end())
{
//hitter was not in the list add him in
//hitter was not in the current frame list
//lets find out its state in the begining of the frame
ResidentSet::iterator curres = fCurrentResidents.find(hitter);
bool initialState;
if(curres != fCurrentResidents.end())
initialState =true;
else
initialState =false;
plCollisionBookKeepingInfo* BookKeeper=new plCollisionBookKeepingInfo(hitter);
if(entering)
{
BookKeeper->enters++;
BookKeeper->fSubStepCurState =true;
}
else
{
BookKeeper->exits++;
BookKeeper->fSubStepCurState =false;
}
fCollisionList.push_front(BookKeeper);
}
}
else
{
plActivatorMsg* ActivatorMsg = new plActivatorMsg;
ActivatorMsg->AddReceivers(fReceivers);
if (fProxyKey)
ActivatorMsg->fHiteeObj = fProxyKey;
else
ActivatorMsg->fHiteeObj = GetTarget()->GetKey();
ActivatorMsg->fHitterObj = hitter;
ActivatorMsg->SetSender(GetKey());
if (entering)
{
ActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter);
}
else
{
ActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit);
}
plgDispatch::MsgSend(ActivatorMsg);
}
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
/* fSavedActivatorMsg = new plActivatorMsg;
fSavedActivatorMsg->AddReceivers(fReceivers); fSavedActivatorMsg->AddReceivers(fReceivers);
if (fProxyKey) if (fProxyKey)
@ -547,47 +349,36 @@ void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immedi
if (entering) if (entering)
{ {
//DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName(),fNumEvals); DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter); fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter);
fLastEnterEval = fNumEvals; fLastEnterEval = fNumEvals;
} }
else else
{ {
//DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName(),fNumEvals); DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit);
fLastExitEval = fNumEvals; fLastExitEval = fNumEvals;
} }
*/
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
// PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
// we're saving the message to be dispatched later...
if (immediate)
{
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
// fSavedActivatorMsg = nil; if (immediate)
ISendSavedTriggerMsgs();
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
}
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
} }
/*
void plObjectInVolumeDetector::ISendSavedTriggerMsgs() void plObjectInVolumeDetector::ISendSavedTriggerMsgs()
{ {
if (fSavedActivatorMsg) if (fSavedActivatorMsg)
{ {
if (fSavedActivatorMsg->fTriggerType == plActivatorMsg::kVolumeEnter) if (fSavedActivatorMsg->fTriggerType == plActivatorMsg::kVolumeEnter)
DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName(),fNumEvals); DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
else else
DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName(),fNumEvals); DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
// we're saving the message to be dispatched later... // we're saving the message to be dispatched later...
plgDispatch::MsgSend(fSavedActivatorMsg); plgDispatch::MsgSend(fSavedActivatorMsg);
} }
fSavedActivatorMsg = nil; fSavedActivatorMsg = nil;
} }
*/
hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
{ {
plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg);
@ -596,36 +387,18 @@ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
// If the avatar is disabled (flying around), don't trigger // If the avatar is disabled (flying around), don't trigger
if (IIsDisabledAvatar(pCollMsg->fOtherKey)) if (IIsDisabledAvatar(pCollMsg->fOtherKey))
return false; return false;
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
// PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
if (!fWaitingForEval)
{
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
fWaitingForEval = true;
}
// end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0)); ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0));
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
return true; return true;
} }
#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND plEvalMsg* pEvalMsg = plEvalMsg::ConvertNoRef(msg);
// PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame if (pEvalMsg)
plEvalMsg* pEval = plEvalMsg::ConvertNoRef(msg);
if (pEval)
{ {
fNumEvals++;
//if (fSavedActivatorMsg) ISendSavedTriggerMsgs();
// DetectorLog("%s: InVolumeEval=%d with saved message", GetKeyName(), fNumEvals); plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
//else
// DetectorLog("%s: InVolumeEval=%d without saved message", GetKeyName(), fNumEvals);
IHandleEval(pEval);
} }
// end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame
#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg); plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg);
if (pageMsg && pageMsg->fUnload) if (pageMsg && pageMsg->fUnload)
@ -636,75 +409,6 @@ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
return plCollisionDetector::MsgReceive(msg); return plCollisionDetector::MsgReceive(msg);
} }
void plObjectInVolumeDetector::IHandleEval(plEvalMsg* pEval)
{
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
fWaitingForEval = false;
for(bookKeepingList::reverse_iterator it= fCollisionList.rbegin();it!=fCollisionList.rend(); it++)
{
bool alreadyInside;
ResidentSet::iterator HitIt;
HitIt = fCurrentResidents.find((*it)->hitter);
if(HitIt != fCurrentResidents.end()) alreadyInside = true;
else alreadyInside=false;
plActivatorMsg* actout=new plActivatorMsg;
actout->fHitterObj=((*it)->hitter);
actout->SetSender(GetKey());
if (fProxyKey)
actout->fHiteeObj = fProxyKey;
else
actout->fHiteeObj = GetTarget()->GetKey();
if((*it)->fSubStepCurState)//current substate says we are entered
{//different enters and exits
//figure out what to do
if(!alreadyInside)
{//we are actuall entering
actout->SetTriggerType(plActivatorMsg::kVolumeEnter);
fCurrentResidents.insert((*it)->hitter);
actout->AddReceivers(fReceivers);
actout->Send();
DetectorLog("%s sent an Enter ActivatorMsg. To: %s", GetKeyName().c_str(), GetTarget()->GetKeyName().c_str() );
}
else
{
DetectorLog("%s squelched an Enter ActivatorMsg.", GetKeyName().c_str());
delete actout;
}
}
else
{
//fSubStepCurState says we are outside
if(alreadyInside)
{//we are actuall exiting
actout->SetTriggerType(plActivatorMsg::kVolumeExit);
fCurrentResidents.erase((*it)->hitter);
actout->AddReceivers(fReceivers);
actout->Send();
DetectorLog("%s sent an Exit ActivatorMsg. To: %s", GetKeyName().c_str(), GetTarget()->GetKeyName().c_str());
}
else
{
DetectorLog("%s squelched an Exit ActivatorMsg.", GetKeyName().c_str());
delete actout;
}
}
}
DetectorLog("*********");
for(bookKeepingList::iterator it = fCollisionList.begin(); it != fCollisionList.end(); it ++)
{
delete (*it);
}
DetectorLog("This is the regions inhabitants after the op");
for(ResidentSet::iterator it = fCurrentResidents.begin(); it!= fCurrentResidents.end(); it++)
{
DetectorLog("%s", (*it)->GetName().c_str());
}
DetectorLog("*********");
fCollisionList.clear();
}
void plObjectInVolumeDetector::SetTarget(plSceneObject* so) void plObjectInVolumeDetector::SetTarget(plSceneObject* so)
{ {
plCollisionDetector::SetTarget(so); plCollisionDetector::SetTarget(so);
@ -730,6 +434,7 @@ void plObjectInVolumeDetector::Write(hsStream* stream, hsResMgr* mgr)
plObjectInVolumeAndFacingDetector::plObjectInVolumeAndFacingDetector() : plObjectInVolumeAndFacingDetector::plObjectInVolumeAndFacingDetector() :
plObjectInVolumeDetector(),
fFacingTolerance(0), fFacingTolerance(0),
fNeedWalkingForward(false), fNeedWalkingForward(false),
fAvatarInVolume(false), fAvatarInVolume(false),

61
Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h

@ -73,7 +73,8 @@ public:
kTypeBump = 0x20, kTypeBump = 0x20,
}; };
plCollisionDetector() : fType(0), fTriggered(false), fBumped(false){;} plCollisionDetector() : fType(0), fTriggered(false), fBumped(false){ }
plCollisionDetector(int8_t type) : fType(type), fTriggered(false), fBumped(false) { }
virtual ~plCollisionDetector(){;} virtual ~plCollisionDetector(){;}
virtual hsBool MsgReceive(plMessage* msg); virtual hsBool MsgReceive(plMessage* msg);
@ -90,48 +91,26 @@ public:
// sub type for object-in-volume detectors // sub type for object-in-volume detectors
class plObjectInVolumeDetector : public plCollisionDetector class plObjectInVolumeDetector : public plCollisionDetector
{ {
public:
class plCollisionBookKeepingInfo
{
friend class plObjectInVolumeDetector;
public:
plCollisionBookKeepingInfo(plKey& hit)
{
hitter=hit;
enters=0;
exits=0;
}
~plCollisionBookKeepingInfo()
{
hitter=nil;
}
protected:
plKey hitter;
int enters,exits;
bool fSubStepCurState;
};
protected: protected:
virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); virtual void ITrigger(plKey hitter, bool entering, bool immediate=false);
//virtual void ISendSavedTriggerMsgs(); virtual void ISendSavedTriggerMsgs();
virtual void IHandleEval(plEvalMsg* pEval);
bool fWaitingForEval;
plActivatorMsg* fSavedActivatorMsg; plActivatorMsg* fSavedActivatorMsg;
uint32_t fNumEvals;
typedef std::list<plCollisionBookKeepingInfo*> bookKeepingList; uint32_t fLastEnterEval;
bookKeepingList fCollisionList; uint32_t fLastExitEval;
typedef std::set<plKey> ResidentSet;
ResidentSet fCurrentResidents;
public: public:
plObjectInVolumeDetector() plObjectInVolumeDetector()
{ : plCollisionDetector(), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0)
fWaitingForEval=false;fSavedActivatorMsg=nil; { }
} plObjectInVolumeDetector(int8_t type)
plObjectInVolumeDetector(int8_t i){fType = i;fWaitingForEval=false;fSavedActivatorMsg=nil;} : plCollisionDetector(type), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0)
virtual ~plObjectInVolumeDetector(){;} { }
virtual ~plObjectInVolumeDetector() { }
virtual hsBool MsgReceive(plMessage* msg); virtual hsBool MsgReceive(plMessage* msg);
@ -177,23 +156,23 @@ public:
class plCameraRegionDetector : public plObjectInVolumeDetector class plCameraRegionDetector : public plObjectInVolumeDetector
{ {
protected: protected:
hsTArray<plCameraMsg*> fMessages; typedef std::vector<plCameraMsg*> plCameraMsgVec;
plCameraMsgVec fMessages;
bool fIsInside; bool fIsInside;
bool fSavingSendMsg; bool fSavingSendMsg;
bool fSavedMsgEnterFlag; bool fSavedMsgEnterFlag;
int fNumEvals;
int fLastEnterEval;
int fLastExitEval;
virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); virtual void ITrigger(plKey hitter, bool entering, bool immediate=false);
virtual void ISendSavedTriggerMsgs(); virtual void ISendSavedTriggerMsgs();
virtual void IHandleEval(plEvalMsg* pEval);
public: public:
plCameraRegionDetector(){ fIsInside = false; fSavingSendMsg = false; } plCameraRegionDetector()
: plObjectInVolumeDetector(), fIsInside(false), fSavingSendMsg(false)
{ }
~plCameraRegionDetector(); ~plCameraRegionDetector();
virtual hsBool MsgReceive(plMessage* msg); virtual hsBool MsgReceive(plMessage* msg);
void AddMessage(plCameraMsg* pMsg) { fMessages.Append(pMsg); } void AddMessage(plCameraMsg* pMsg) { fMessages.push_back(pMsg); }
CLASSNAME_REGISTER( plCameraRegionDetector ); CLASSNAME_REGISTER( plCameraRegionDetector );
GETINTERFACE_ANY( plCameraRegionDetector, plCollisionDetector ); GETINTERFACE_ANY( plCameraRegionDetector, plCollisionDetector );

Loading…
Cancel
Save