diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp
index 43ad60a0..27964d8f 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp
@@ -94,8 +94,7 @@ private:
}
else
{
- bool isController;
- plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(hitActor,&isController);
+ plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(hitActor);
if (controller)
{
objKey = controller->GetOwner();
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp
deleted file mode 100644
index 7e8e4667..00000000
--- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp
+++ /dev/null
@@ -1,1280 +0,0 @@
-/*==LICENSE==*
-
-CyanWorlds.com Engine - MMOG client, server and tools
-Copyright (C) 2011 Cyan Worlds, Inc.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-Additional permissions under GNU GPL version 3 section 7
-
-If you modify this Program, or any covered work, by linking or
-combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
-NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
-JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
-(or a modified version of those libraries),
-containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
-PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
-JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
-licensors of this Program grant you additional
-permission to convey the resulting work. Corresponding Source for a
-non-source form of such a combination shall include the source code for
-the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
-work.
-
-You can contact Cyan Worlds, Inc. by email legal@cyan.com
- or by snail mail at:
- Cyan Worlds, Inc.
- 14617 N Newport Hwy
- Mead, WA 99021
-
-*==LICENSE==*/
-#include "plPXPhysicalController.h"
-#include "plSimulationMgr.h"
-#include "plPXPhysical.h"
-#include "plPXConvert.h"
-#include "pnSceneObject/plSimulationInterface.h"
-#include "pnSceneObject/plSceneObject.h"
-#include "pnMessage/plCorrectionMsg.h"
-#include "plAvatar/plArmatureMod.h"
-#include "pnSceneObject/plCoordinateInterface.h"
-#include "plDrawable/plDrawableGenerator.h"
-#include "plPhysical/plPhysicalProxy.h"
-
-#include "pnMessage/plSetNetGroupIDMsg.h
-
-#include "plSurface/hsGMaterial.h"
-#include "plSurface/plLayerInterface.h""
-#include "plMessage/plCollideMsg.h"
-
-
-#include
-#include
-#include
-#include
-
-#define kPhysxSkinWidth 0.1f
-#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 STEP_OFFSET 1.0f
-#define STEP_OFFSET 0.5f
-//#define STEP_OFFSET 0.15f
-
-
-#ifndef PLASMA_EXTERNAL_RELEASE
-#include "plPipeline/plDebugText.h"
-bool plPXPhysicalController::fDebugDisplay = false;
-#endif // PLASMA_EXTERNAL_RELEASE
-
-static ControllerManager gControllerMgr;
-static std::vector gControllers;
-static bool gRebuildCache = false;
-
-// KLUDGE: From plPXPhysical.cpp
-bool CompareMatrices(const hsMatrix44 &matA, const hsMatrix44 &matB, float tolerance);
-
-plPhysicalController* plPhysicalController::Create(plKey ownerSO, hsScalar height, hsScalar width)
-{
- hsScalar radius = width / 2.f;
- //hsScalar realHeight = height - width;
- hsScalar realHeight = height - radius + kPhysicalHeightFudge;
- return new plPXPhysicalController(ownerSO, radius, realHeight);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-plPXPhysicalController* plPXPhysicalController::FindController(NxController* controller)
-{
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalController* ac = gControllers[i];
- if (ac->fController == controller)
- return ac;
- }
- return nil;
-}
-
-plPXPhysicalController* plPXPhysicalController::GetController(NxActor& actor, bool* isController)
-{
- *isController = false;
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalController* ac = gControllers[i];
- if (ac->fController && ac->fController->getActor() == &actor)
- {
- *isController = true;
- return ac;
- }
- if ( ac->fKinematicActor == &actor)
- {
- return ac;
- }
- }
-
- return nil;
-}
-void plPXPhysicalController::GetWorldSpaceCapsule(NxCapsule& cap)
-{
- if(fController){
- int numshapes=fController->getActor()->getNbShapes();
- if (numshapes==1)
- {//there should only be one shape on a controller
- NxShape* const *shapes=fController->getActor()->getShapes();
- //and since it is a capsule controller it better be a capsule;
- NxCapsuleShape *capShape = shapes[0]->isCapsule();
- if(capShape) capShape->getWorldCapsule(cap);
-
- }
- }
-
-}
-bool plPXPhysicalController::AnyControllersInThisWorld(plKey world)
-{
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalController* ac = gControllers[i];
- if (ac->GetSubworld() == world)
- return true;
- }
- return false;
-}
-
-int plPXPhysicalController::NumControllers()
-{
- return gControllers.size();
-}
-int plPXPhysicalController::GetControllersInThisSubWorld(plKey world, int maxToReturn,plPXPhysicalController** bufferout)
-{
- int i=0;
- for (int j=0;jGetSubworld()==world)
- {
- if(iGetSubworld()==world)i++;
- }
- return i;
-}
-void plPXPhysicalController::Update(bool prestep, hsScalar delSecs)
-{
- // Apparently the user data field of the controllers is broken
-// uint32_t count = gControllerMgr.getNbControllers();
-// NxController* controllers = (NxController*)gControllerMgr.getControllers();
-//
-// for (int i = 0; i < count; i++)
-// {
-// plPXPhysicalController* ac = (plPXPhysicalController*)controllers[i].getAppData();
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalController* ac = gControllers[i];
-
- hsAssert(ac, "Bad avatar controller");
- if (prestep)
- {
- if (gRebuildCache)
- ac->fController->reportSceneChanged();
- ac->IApply(delSecs);
- }
- else
- {
- gControllerMgr.updateControllers();
- ac->ISendUpdates(delSecs);
-
- if (ac->GetSubworldCI())
- ac->fPrevSubworldW2L = ac->GetSubworldCI()->GetWorldToLocal();
- else
- {
- if (!ac->fPrevSubworldW2L.IsIdentity())
- ac->fPrevSubworldW2L.Reset();
- }
- }
- }
-
- gRebuildCache = false;
-}
-
-void plPXPhysicalController::RebuildCache()
-{
- gRebuildCache = true;
-}
-void plPXPhysicalController::IInformDetectors(bool entering)
-{
- static const NxU32 DetectorFlag= 1<GetScene(fWorldKey);
- int kNumofShapesToStore=30;
- NxCapsule cap;
- GetWorldSpaceCapsule(cap);
- NxShape* shapes[30];
- int numCollided=scene->overlapCapsuleShapes(cap,NX_ALL_SHAPES,kNumofShapesToStore,shapes,NULL,DetectorFlag,NULL,true);
- for (int i=0;igetActor());
-
- if (myactor)
- {
-
- plPXPhysical* physical = (plPXPhysical*)myactor->userData;
- if (physical)
- {
- plCollideMsg* msg = new plCollideMsg;
-
- msg->fOtherKey = fOwner;
- msg->fEntering = entering;
- msg->AddReceiver(physical->GetKey());
- msg->Send();
- }
- }
- }
-
-
- }
-
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-
-class PXControllerHitReport : public NxUserControllerHitReport
-{
-public:
- virtual NxControllerAction onShapeHit(const NxControllerShapeHit& hit)
- {
- plPXPhysicalController* ac = plPXPhysicalController::FindController(hit.controller);
-
- NxActor& actor = hit.shape->getActor();
- plPXPhysical* phys = (plPXPhysical*)actor.userData;
-
- static hsScalar SlopeLimit = kSLOPELIMIT;
- hsVector3 normal = plPXConvert::Vector(hit.worldNormal);
- hsScalar dot = normal * kAvatarUp;
- if ( dot < SlopeLimit )
- ac->AddSlidingNormal(normal);
- else
- ac->GroundHit();
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- plDbgCollisionInfo info;
- info.fNormal = normal;
- info.fSO = plSceneObject::ConvertNoRef(phys->GetObjectKey()->ObjectIsLoaded());
- info.fOverlap = false;
- NxShape* const *shapes = hit.controller->getActor()->getShapes();
- int numShapes = hit.controller->getActor()->getNbShapes();
- int i;
- for (i = 0; i < numShapes; i++)
- {
- // should only be one capsule shape
- const NxCapsuleShape *capShape = shapes[i]->isCapsule();
- if (capShape)
- {
- NxCapsule cap;
- capShape->getWorldCapsule(cap);
- if (hit.shape->checkOverlapCapsule(cap))
- info.fOverlap = true;
- }
- }
- ac->fDbgCollisionInfo.Append(info);
-#endif PLASMA_EXTERNAL_RELEASE
-
- // If the avatar hit a movable physical, apply some force to it.
- if (actor.isDynamic() )
- {
- if ( !actor.readBodyFlag(NX_BF_KINEMATIC) && !actor.readBodyFlag(NX_BF_FROZEN))
- {
- // If this is the local avatar, we need to take ownership of this
- // dynamic if we haven't already
- if (ac->fLOSDB == plSimDefs::kLOSDBLocalAvatar && !phys->IsLocallyOwned() &&
- !phys->GetProperty(plSimulationInterface::kNoOwnershipChange))
- {
- plSynchedObject* obj = plSynchedObject::ConvertNoRef(phys->GetObjectKey()->ObjectIsLoaded());
-
- obj->SetNetGroupConstant(plNetGroup::kNetGroupLocalPhysicals);
-
- // Tell all the other clients that we own this physical
- plSetNetGroupIDMsg* setNetGroupID = new plSetNetGroupIDMsg;
- setNetGroupID->fId = plNetGroup::kNetGroupRemotePhysicals;
- setNetGroupID->SetBCastFlag(plMessage::kNetPropagate | plMessage::kNetForce);
- setNetGroupID->SetBCastFlag(plMessage::kLocalPropagate, false);
- setNetGroupID->Send(obj->GetKey());
- }
-
- plSimulationMgr::GetInstance()->ConsiderSynch(phys, nil);
-
- hsVector3 dir = plPXConvert::Vector(hit.dir);
- // We only allow horizontal pushes. Vertical pushes when we stand on
- // dynamic objects creates useless stress on the solver.
- if (dir.fZ < 0)
- {
- dir.fZ = 0;
- dir.Normalize();
- }
-
- if (!dir.IsEmpty())
- {
- static hsScalar kForceScale = 5.f;
- //static hsScalar kForceScale = 4.f;
- NxF32 coeff = actor.getMass() * hit.length * kForceScale;
- hsPoint3 pos((hsScalar)hit.worldPos.x, (hsScalar)hit.worldPos.y, (hsScalar)hit.worldPos.z);
- phys->SetHitForce((dir*coeff), pos);
- }
- }
- }
- else // else if the avatar hit a static
- {
- return NX_ACTION_NONE;
- }
-
- if (phys && phys->GetProperty(plSimulationInterface::kAvAnimPushable))
- {
- hsQuat inverseRotation = ac->fLocalRotation.Inverse();
- hsVector3 normal = plPXConvert::Vector(hit.worldNormal);
- ac->fPushingPhysical = phys;
- ac->fFacingPushingPhysical = (inverseRotation.Rotate(&kAvatarForward).InnerProduct(normal) < 0 ? true : false);
- }
-
- return NX_ACTION_NONE;
- }
-
- virtual NxControllerAction onControllerHit(const NxControllersHit& hit)
- {
- return NX_ACTION_NONE;
- }
-
-} gMyReport;
-
-
-//////////////////////////////////////////////////////////////////////////
-
-const hsScalar plPXPhysicalController::kAirTimeThreshold = .1f; // seconds
-
-plPXPhysicalController::plPXPhysicalController(plKey ownerSO, hsScalar radius, hsScalar height)
- : fOwner(ownerSO)
- , fWorldKey(nil)
- , fRadius(radius)
- , fHeight(height)
- , fController(nil)
- , fLinearVelocity(0, 0, 0)
- , fAngularVelocity(0)
- , fAchievedLinearVelocity(0, 0, 0)
- , fLocalPosition(0, 0, 0)
- , fLocalRotation(0, 0, 0, 1)
- , fEnable(true)
- , fEnableChanged(false)
- , fLOSDB(plSimDefs::kLOSDBNone)
- , fGroundHit(false)
- , fFalseGround(false)
- , fTimeInAir(0)
- , fPushingPhysical(nil)
- , fFacingPushingPhysical(false)
- , fProxyGen(nil)
- , fKinematicActor(nil)
- , fKinematic(false)
- , fKinematicChanged(false)
- , fKinematicEnableNextUpdate(false)
- , fHitHead(false)
-{
- gControllers.push_back(this);
- fLastGlobalLoc.Reset();
- ICreateController();
- Enable(false);
-}
-
-plPXPhysicalController::~plPXPhysicalController()
-{
- IDeleteController();
-
- for (int i = 0; i < gControllers.size(); i++)
- {
- if (gControllers[i] == this)
- {
- gControllers.erase(gControllers.begin()+i);
- break;
- }
- }
-
- delete fProxyGen;
-}
-
-// WARNING: If this is an armatureMod, it'll have its own idea about when
-// physics should be enabled/disabled. Use plArmatureModBase::EnablePhysics() instead.
-void plPXPhysicalController::Enable(bool enable)
-{
- if (fEnable != enable)
- {
- fEnable = enable;
- if (fEnable)
- fEnableChanged = true;
- else
- {
- // See ISendUpdates for why we don't re-enable right away
- fController->setCollision(fEnable);
- }
- }
-}
-
-void plPXPhysicalController::AddSlidingNormal(hsVector3 vec)
-{
- // We get lots of duplicates, so check.
- int i;
- for (i = 0; i < fSlidingNormals.GetCount(); i++)
- {
- if (hsABS(fSlidingNormals[i].fX - vec.fX) <= .01 &&
- hsABS(fSlidingNormals[i].fY - vec.fY) <= .01 &&
- hsABS(fSlidingNormals[i].fZ - vec.fZ) <= .01)
- {
- return;
- }
- }
- fSlidingNormals.Append(vec);
-}
-
-
-void plPXPhysicalController::IGetPositionSim(hsPoint3& pos) const
-{
- const NxExtendedVec3& nxPos = fController->getPosition();
- pos.Set(hsScalar(nxPos.x), hsScalar(nxPos.y), hsScalar(nxPos.z) - kPhysZOffset);
-}
-
-void plPXPhysicalController::SetSubworld(plKey world)
-{
- if (fWorldKey != world)
- {
- bool wasEnabled = fEnable;
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
- // PHYSX FIXME - before leaving this world, sending leaving detector events if we are inside a convex hull detector
- hsPoint3 pos;
- IGetPositionSim(pos);
- plSimulationMgr::GetInstance()->UpdateDetectorsInScene(fWorldKey,GetOwner(),pos,false);
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
- //need to inform detectors in the old world that we are leaving
- //IInformDetectors(false);
- //done informing old world
-
- IDeleteController();
- fWorldKey = world;
- ICreateController();
- if (wasEnabled)
- Enable(false);
- // need to disable the kinematic also so that it doesn't trip over random detector regions
- fKinematicActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
- hsMatrix44 globalLoc = fLastGlobalLoc;
- if (GetSubworldCI())
- fPrevSubworldW2L = GetSubworldCI()->GetWorldToLocal();
- ISetGlobalLoc(globalLoc);
- // we need to let the re-enable code put thing in order... so that 0,0,0 is not triggered and ISendUpdates do the enable and update detectors
- if (wasEnabled)
- Enable(true);
- // and then re-enable the kinematic on the next update (ISendUpdates)
- fKinematicEnableNextUpdate = true;
- plPXPhysicalController::RebuildCache();
- }
-}
-
-const plCoordinateInterface* plPXPhysicalController::GetSubworldCI() const
-{
- if (fWorldKey)
- {
- plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded());
- if (so)
- return so->GetCoordinateInterface();
- }
- return nil;
-}
-
-void plPXPhysicalController::GetState(hsPoint3& pos, float& zRot)
-{
- // Temporarily use the position point while we get the z rotation
- fLocalRotation.NormalizeIfNeeded();
- fLocalRotation.GetAngleAxis(&zRot, (hsVector3*)&pos);
-
- if (pos.fZ < 0)
- zRot = (2 * hsScalarPI) - zRot; // axis is backwards, so reverse the angle too
-
- pos = fLocalPosition;
-}
-
-void plPXPhysicalController::SetState(const hsPoint3& pos, float zRot)
-{
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
- {
- hsQuat worldRot;
- hsVector3 zAxis(0.f, 0.f, 1.f);
- worldRot.SetAngleAxis(zRot, zAxis);
-
- hsMatrix44 l2w, w2l;
- worldRot.MakeMatrix(&l2w);
- l2w.SetTranslate(&pos);
-
- // Localize new position and rotation to global coords if we're in a subworld
- const plCoordinateInterface* ci = GetSubworldCI();
- if (ci)
- {
- const hsMatrix44& subworldL2W = ci->GetLocalToWorld();
- l2w = subworldL2W * l2w;
- }
-
- l2w.GetInverse(&w2l);
- so->SetTransform(l2w, w2l);
- so->FlushTransform();
- }
-}
-
-void plPXPhysicalController::ISetGlobalLoc(const hsMatrix44& l2w)
-{
- fLastGlobalLoc = l2w;
-
- // Update our subworld position and rotation
- const plCoordinateInterface* subworldCI = GetSubworldCI();
- if (subworldCI)
- {
- const hsMatrix44& w2s = fPrevSubworldW2L;
- hsMatrix44 l2s = w2s * l2w;
-
- l2s.GetTranslate(&fLocalPosition);
- fLocalRotation.SetFromMatrix44(l2s);
- }
- else
- {
- l2w.GetTranslate(&fLocalPosition);
- fLocalRotation.SetFromMatrix44(l2w);
- }
-
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
- if (fProxyGen)
- fProxyGen->SetTransform(l2w, w2l);
-
- // Update the physical position
- NxExtendedVec3 nxPos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kPhysZOffset);
- fController->setPosition(nxPos);
- IMatchKinematicToController();
-}
-
-void plPXPhysicalController::IMatchKinematicToController()
-{
- if ( fKinematicActor)
- {
- NxExtendedVec3 cPos = fController->getPosition();
- NxVec3 prevKinPos = fKinematicActor->getGlobalPosition();
- NxVec3 kinPos;
- kinPos.x = (NxReal)cPos.x;
- kinPos.y = (NxReal)cPos.y;
- kinPos.z = (NxReal)cPos.z;
- if (plSimulationMgr::fExtraProfile)
- SimLog("Match setting kinematic from %f,%f,%f to %f,%f,%f",prevKinPos.x,prevKinPos.y,prevKinPos.z,kinPos.x,kinPos.y,kinPos.z );
- fKinematicActor->setGlobalPosition(kinPos);
- }
-}
-
-void plPXPhysicalController::IMoveKinematicToController(hsPoint3& pos)
-{
- if ( fKinematicActor)
- {
- NxVec3 kinPos = fKinematicActor->getGlobalPosition();
- if ( abs(kinPos.x-pos.fX) + abs(kinPos.y-pos.fY) + (abs(kinPos.z-pos.fZ-kPhysZOffset)) > 0.0001f)
- {
- NxVec3 newPos;
- newPos.x = (NxReal)pos.fX;
- newPos.y = (NxReal)pos.fY;
- newPos.z = (NxReal)pos.fZ+kPhysZOffset;
- if (fEnable || fKinematic)
- {
- if (plSimulationMgr::fExtraProfile)
- SimLog("Moving kinematic from %f,%f,%f to %f,%f,%f",pos.fX,pos.fY,pos.fZ+kPhysZOffset,kinPos.x,kinPos.y,kinPos.z );
- // use the position
- fKinematicActor->moveGlobalPosition(newPos);
- }
- else
- {
- if (plSimulationMgr::fExtraProfile)
- SimLog("Setting kinematic from %f,%f,%f to %f,%f,%f",pos.fX,pos.fY,pos.fZ+kPhysZOffset,kinPos.x,kinPos.y,kinPos.z );
- fKinematicActor->setGlobalPosition(newPos);
- }
- }
- }
-}
-
-void plPXPhysicalController::ISetKinematicLoc(const hsMatrix44& l2w)
-{
-
- hsPoint3 kPos;
- // Update our subworld position and rotation
- const plCoordinateInterface* subworldCI = GetSubworldCI();
- if (subworldCI)
- {
- const hsMatrix44& w2s = subworldCI->GetWorldToLocal();
- hsMatrix44 l2s = w2s * l2w;
-
- l2s.GetTranslate(&kPos);
- }
- else
- {
- l2w.GetTranslate(&kPos);
- }
-
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
- if (fProxyGen)
- fProxyGen->SetTransform(l2w, w2l);
-
- // add z offset
- kPos.fZ += kPhysZOffset;
- // Update the physical position of kinematic
- if (fEnable || fKinematic)
- fKinematicActor->moveGlobalPosition(plPXConvert::Point(kPos));
- else
- fKinematicActor->setGlobalPosition(plPXConvert::Point(kPos));
-}
-
-
-void plPXPhysicalController::Kinematic(bool state)
-{
- if (fKinematic != state)
- {
- fKinematic = state;
- if (fKinematic)
- {
- // See ISendUpdates for why we don't re-enable right away
- fController->setCollision(false);
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- fKinematicActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
-#endif
- }
- else
- {
- fKinematicChanged = true;
- }
- }
-}
-
-bool plPXPhysicalController::IsKinematic()
-{
- if (fKinematicActor)
- {
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- if (!fKinematicActor->readActorFlag(NX_AF_DISABLE_COLLISION))
- return true;
-#else
- return fKinematic;
-#endif
- }
- return false;
-}
-
-void plPXPhysicalController::GetKinematicPosition(hsPoint3& pos)
-{
- pos.Set(-1,-1,-1);
- if ( fKinematicActor )
- {
- NxVec3 klPos = fKinematicActor->getGlobalPosition();
- pos.Set(hsScalar(klPos.x), hsScalar(klPos.y), hsScalar(klPos.z) - kPhysZOffset);
- }
-}
-
-
-void plPXPhysicalController::IApply(hsScalar delSecs)
-{
- /*static const uint32_t collideFlags =
- 1<ObjectIsLoaded());
- if (so)
- {
- // If we've been moved since the last physics update (somebody warped us),
- // update the physics before we apply velocity.
- const hsMatrix44& l2w = so->GetCoordinateInterface()->GetLocalToWorld();
- if (!CompareMatrices(l2w, fLastGlobalLoc, .0001f))
- {
- ISetKinematicLoc(l2w);
- }
- }
- // then jump out
- return;
- }
-
- if (!fEnable)
- return;
-
- bool gotGroundHit = fGroundHit;
- fGroundHit = false;
-
- fPushingPhysical = nil;
- fFacingPushingPhysical = false;
-
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
- {
- // If we've been moved since the last physics update (somebody warped us),
- // update the physics before we apply velocity.
- const hsMatrix44& l2w = so->GetCoordinateInterface()->GetLocalToWorld();
- if (!CompareMatrices(l2w, fLastGlobalLoc, .0001f))
- ISetGlobalLoc(l2w);
-
- // Convert our avatar relative velocity to subworld relative
- if (!fLinearVelocity.IsEmpty())
- {
- fLinearVelocity = l2w * fLinearVelocity;
-
- const plCoordinateInterface* subworldCI = GetSubworldCI();
- if (subworldCI)
- fLinearVelocity = subworldCI->GetWorldToLocal() * fLinearVelocity;
- }
-
- // Add in gravity if the avatar's z velocity isn't being set explicitly
- // (Add in a little fudge factor, since the animations usually add a
- // tiny bit of z.)
- if (hsABS(fLinearVelocity.fZ) < 0.001f)
- {
- static const float kGravity = -32.f;
-
- // Get our previous z velocity. If we're on the ground, clamp it to zero at
- // the largest, so we won't launch into the air if we're running uphill.
- hsScalar prevZVel = fAchievedLinearVelocity.fZ;
- if (IsOnGround())
- prevZVel = hsMinimum(prevZVel, 0.f);
-
- hsScalar grav = kGravity * delSecs;
-
- // If our gravity contribution isn't high enough this frame, we won't
- // report a collision even when standing on solid ground.
- hsScalar maxGrav = -.001f / delSecs;
- if (grav > maxGrav)
- grav = maxGrav;
-
- fLinearVelocity.fZ = prevZVel + grav;
-
- // Technically this is nonsensical and wrong, capping our velocity to
- // an accelleration constant. But no one seems to really mind.
- if (fLinearVelocity.fZ < kGravity)
- fLinearVelocity.fZ = kGravity;
- }
-
- // If we're airborne and the velocity isn't set, use the velocity from
- // the last frame so we maintain momentum.
- if (!IsOnGround() && fLinearVelocity.fX == 0.f && fLinearVelocity.fY == 0.f)
- {
- fLinearVelocity.fX = fAchievedLinearVelocity.fX;
- fLinearVelocity.fY = fAchievedLinearVelocity.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 (i = 0; i < fSlidingNormals.GetCount(); i++)
- {
- offset += fSlidingNormals[i];
-
- hsVector3 velNorm = fLinearVelocity;
- if (velNorm.MagnitudeSquared() > 0)
- velNorm.Normalize();
-
- if (velNorm * fSlidingNormals[i] < 0)
- {
- hsVector3 proj = (velNorm % fSlidingNormals[i]) % fSlidingNormals[i];
- if (velNorm * proj < 0)
- proj *= -1.f;
-
- fLinearVelocity = fLinearVelocity.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();
- fLinearVelocity += offset * 5;
- }
- }
-
- // Scale the velocity to our actual step size (by default it's feet/sec)
- NxVec3 vel(fLinearVelocity.fX * delSecs, fLinearVelocity.fY * delSecs, fLinearVelocity.fZ * delSecs);
- NxU32 colFlags = 0;
-
- fGroundHit = false;
- fFalseGround = false;
- fSlidingNormals.Swap(fPrevSlidingNormals);
- fSlidingNormals.SetCount(0);
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- fDbgCollisionInfo.SetCount(0);
-#endif // PLASMA_EXTERNAL_RELEASE
-
- fController->move(vel, collideFlags, 0.0001, colFlags);
-
-
- ICheckForFalseGround();
- /*If the Physx controller thinks we have a collision from below, need to make sure we
- have at least have false ground, otherwise Autostepping can send us into the air, and we will some times
- float/panic link. For some reason the NxControllerHitReport does not always send messages
- regarding Controller contact with ground plane, but will (almost) always return NXCC_COLLISION_DOWN
- with the move method.
- */
- if(((colFlags&NXCC_COLLISION_DOWN )==NXCC_COLLISION_DOWN )&&(fGroundHit==false))
- {
- fFalseGround=true;
- }
- /*
- The top sphere half was hit, but the ControllerHit Report doesn't know
- In IUpdate fHitHead will be used to keep from gaining unrealistic velocity in the x&y Direction
- */
- if(colFlags&NXCC_COLLISION_UP)
- {
- fHitHead=true;
- }
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- if (fDebugDisplay)
- IDrawDebugDisplay();
-#endif // PLASMA_EXTERNAL_RELEASE
- }
-}
-
-void plPXPhysicalController::ISendUpdates(hsScalar delSecs)
-{
- if (!fEnable || fKinematic)
- {
- // When we're in non-phys or a behavior we can't go through the rest of the function
- // so we need to get out early, but we need to update the current position if we're
- // in a subworld.
-
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- const plCoordinateInterface* ci = GetSubworldCI();
- if (ci && so)
- {
- const hsMatrix44& soL2W = so->GetCoordinateInterface()->GetLocalToWorld();
- const hsMatrix44& ciL2W = ci->GetLocalToWorld();
-
- hsMatrix44 l2w = fPrevSubworldW2L * soL2W;
- l2w = ciL2W * l2w;
-
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
-
- ((plCoordinateInterface*)so->GetCoordinateInterface())->SetTransform(l2w, w2l);
- ((plCoordinateInterface*)so->GetCoordinateInterface())->FlushTransform();
-
- ISetGlobalLoc(l2w);
- }
-
- return;
- }
-
- // PhysX loves to cache stuff. However, it doesn't like to update it (see
- // the RebuildCache crap above). Say the avatar is disabled and sitting at
- // point 0,0,0. We warp him to some other position and enable him. If you
- // do the enable before the sim step is done, regardless of whether you move
- // him first, he will send out a penetration with any detector at 0,0,0. As
- // far as I can tell there's no way around this, and I tried a lot of things.
- // The only solution I found is to move the avatar, run the sim step, then
- // enable him. This means he won't trigger any detectors at his new position
- // until the next frame, but hopefully that won't be too noticeable.
- if (fEnableChanged)
- {
- fEnableChanged = false;
- fController->setCollision(fEnable);
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
- // PHYSX FIXME - after re-enabling check to see if we are inside any convex hull detector regions
- hsPoint3 pos;
- IGetPositionSim(pos);
- plSimulationMgr::GetInstance()->UpdateDetectorsInScene(fWorldKey,GetOwner(),pos,fEnable);
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
- //IInformDetectors(true);
- }
- if (fKinematicChanged)
- {
- fKinematicChanged = false;
- fController->setCollision(true);
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- fKinematicActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
-#endif // PHYSX_KINEMATIC_IS_DISABLED
- }
- if (fKinematicEnableNextUpdate)
- {
- fKinematicActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
- fKinematicEnableNextUpdate = false;
- }
-
- if (!fGroundHit && !fFalseGround)
- fTimeInAir += delSecs;
- else
- fTimeInAir = 0.f;
-
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
- {
- // Get the current position of the physical
- hsPoint3 curLocalPos;
- IGetPositionSim(curLocalPos);
- IMoveKinematicToController(curLocalPos);
-
- {
- const hsMatrix44& w2l = so->GetCoordinateInterface()->GetLocalToWorld();
- fAchievedLinearVelocity = hsVector3(curLocalPos - fLocalPosition);
- fAchievedLinearVelocity /= delSecs;
- }
- /*if we hit our head the sweep api might try to
- move us laterally to go as high as we requested kind of like autostep, to top it off the
- way the NxCharacter and the sweep api work as a whole NxControllerHitReport::OnShapeHit
- wont be called regarding the head blow.
- if we are airborne: with out this we will gain large amounts of velocity in the x y plane
- and on account of fAchievedLinearVelocity being used in the next step we will fly sideways
- */
- bool headhit=fHitHead;
- fHitHead=false;
- if(headhit&&!(fGroundHit||fFalseGround))
- {
- //we have hit our head and we don't have anything beneath our feet
- //not really friction just a way to make it seem more realistic keep between 0 and 1
- hsScalar headFriction=0.0;
- fAchievedLinearVelocity.fX=(1.0-headFriction)*fLinearVelocity.fX;
- fAchievedLinearVelocity.fY=(1.0-headFriction)*fLinearVelocity.fY;
- //only clamping when hitting head and going upwards, if going down leave it be
- // this should only occur when going down stairwells with low ceilings like in cleft
- //kitchen area
- if(fAchievedLinearVelocity.fZ>0.0)
- {
- fAchievedLinearVelocity.fZ=0.0;
- }
-
- }
-
- // Apply angular velocity
- if (fAngularVelocity != 0.f)
- {
- hsScalar angle;
- hsVector3 axis;
- fLocalRotation.NormalizeIfNeeded();
- fLocalRotation.GetAngleAxis(&angle, &axis);
-
- // adjust it (quaternions are weird...)
- if (axis.fZ < 0)
- angle = (2*hsScalarPI) - angle; // axis is backwards, so reverse the angle too
-
- angle += fAngularVelocity * delSecs;
-
- // make sure we wrap around
- if (angle < 0)
- angle = (2*hsScalarPI) + angle; // angle is -, so this works like a subtract
- if (angle >= (2*hsScalarPI))
- angle = angle - (2*hsScalarPI);
-
- // and set the new angle
- fLocalRotation.SetAngleAxis(angle, hsVector3(0,0,1));
- }
-
- // We can't only send updates when the physical position changes because the
- // world relative position may be changing all the time if we're in a subworld.
-// if (curLocalPos != fLocalPosition || fAngularVelocity != 0.f)
- {
- fLocalPosition = curLocalPos;
-
- // Apply rotation and translation
- fLocalRotation.MakeMatrix(&fLastGlobalLoc);
- fLastGlobalLoc.SetTranslate(&fLocalPosition);
-
- // Localize to global coords if in a subworld
- const plCoordinateInterface* ci = GetSubworldCI();
- if (ci)
- {
- const hsMatrix44& l2w = ci->GetLocalToWorld();
- fLastGlobalLoc = l2w * fLastGlobalLoc;
- }
-
- plCorrectionMsg* corrMsg = new plCorrectionMsg;
- corrMsg->fLocalToWorld = fLastGlobalLoc;
- corrMsg->fLocalToWorld.GetInverse(&corrMsg->fWorldToLocal);
- corrMsg->fDirtySynch = true;
-
- hsMatrix44 w2l;
- fLastGlobalLoc.GetInverse(&w2l);
- //if (fProxyGen)
- // fProxyGen->SetTransform(fLastGlobalLoc, w2l);
-
- // Send the new position to the plArmatureMod and the scene object
- const plArmatureMod* armMod = plArmatureMod::ConvertNoRef(so->GetModifierByType(plArmatureMod::Index()));
- if (armMod)
- corrMsg->AddReceiver(armMod->GetKey());
- corrMsg->AddReceiver(fOwner);
-
- corrMsg->Send();
- }
- }
-
- fLinearVelocity.Set(0, 0, 0);
- fAngularVelocity = 0;
-}
-
-void plPXPhysicalController::ICheckForFalseGround()
-{
- if (fGroundHit)
- return; // Already collided with "real" ground.
-
- // We need to check for the case where the avatar hasn't collided with "ground", but is colliding
- // with a few other objects so that he's not actually falling (wedged in between some slopes).
- // We do this by answering the following question (in 2d top-down space): "If you sort the contact
- // normals by angle, is there a large enough gap between normals?"
- //
- // If you think in terms of geometry, this means a collection of surfaces are all pushing on you.
- // If they're pushing from all sides, you have nowhere to go, and you won't fall. There needs to be
- // a gap, so that you're pushed out and have somewhere to fall. This is the same as finding a gap
- // larger than 180 degrees between sorted normals.
- //
- // The problem is that on top of that, the avatar needs enough force to shove him out that gap (he
- // has to overcome friction). I deal with that by making the threshold (360 - (180 - 60) = 240). I've
- // seen up to 220 reached in actual gameplay in a situation where we'd want this to take effect.
- // This is the same running into 2 walls where the angle between them is 60.
- int i, j;
- const hsScalar threshold = hsScalarDegToRad(240);
- int numContacts = fSlidingNormals.GetCount() + fPrevSlidingNormals.GetCount();
- if (numContacts >= 2)
- {
- // For extra fun... PhysX will actually report some collisions every other frame, as though
- // we're bouncing back and forth between the two (or more) objects blocking us. So it's not
- // enough to look at this frame's collisions, we have to check previous frames too.
- hsTArray fCollisionAngles;
- fCollisionAngles.SetCount(numContacts);
- int angleIdx = 0;
- for (i = 0; i < fSlidingNormals.GetCount(); i++, angleIdx++)
- {
- fCollisionAngles[angleIdx] = hsATan2(fSlidingNormals[i].fY, fSlidingNormals[i].fX);
- }
- for (i = 0; i < fPrevSlidingNormals.GetCount(); i++, angleIdx++)
- {
- fCollisionAngles[angleIdx] = hsATan2(fPrevSlidingNormals[i].fY, fPrevSlidingNormals[i].fX);
- }
-
- // numContacts is rarely larger than 6, so let's do a simple bubble sort.
- for (i = 0; i < numContacts; i++)
- {
- for (j = i + 1; j < numContacts; j++)
- {
- if (fCollisionAngles[i] > fCollisionAngles[j])
- {
- hsScalar tempAngle = fCollisionAngles[i];
- fCollisionAngles[i] = fCollisionAngles[j];
- fCollisionAngles[j] = tempAngle;
- }
- }
- }
-
- // sorted, now we check.
- for (i = 1; i < numContacts; i++)
- {
- if (fCollisionAngles[i] - fCollisionAngles[i - 1] >= threshold)
- break;
- }
-
- if (i == numContacts)
- {
- // We got to the end. Check the last with the first and make your decision.
- if (!(fCollisionAngles[0] - fCollisionAngles[numContacts - 1] >= (threshold - 2 * hsScalarPI)))
- fFalseGround = true;
- }
- }
-}
-
-void plPXPhysicalController::ICreateController()
-{
- NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
-
- NxCapsuleControllerDesc desc;
- desc.position.x = 0;
- desc.position.y = 0;
- desc.position.z = 0;
- desc.upDirection = NX_Z;
- desc.slopeLimit = kSLOPELIMIT;
- desc.skinWidth = kPhysxSkinWidth;
- desc.stepOffset = STEP_OFFSET;
- desc.callback = &gMyReport;
- desc.userData = this;
- desc.radius = fRadius;
- desc.height = fHeight;
- desc.interactionFlag = NXIF_INTERACTION_EXCLUDE;
- //desc.interactionFlag = NXIF_INTERACTION_INCLUDE;
- fController = (NxCapsuleController*)gControllerMgr.createController(scene, desc);
-
- // Change the avatars shape groups. The avatar doesn't actually use these when
- // it's determining collision, but if you're standing still and an object runs
- // into you, it'll pass through without this.
- NxActor* actor = fController->getActor();
- NxShape* shape = actor->getShapes()[0];
- shape->setGroup(plSimDefs::kGroupAvatar);
-
- // need to create the non-bouncing object that can be used to trigger things while the avatar is doing behaviors.
- NxActorDesc actorDesc;
- NxCapsuleShapeDesc capDesc;
- capDesc.radius = fRadius;
- capDesc.height = fHeight;
- capDesc.group = plSimDefs::kGroupAvatar;
- actorDesc.shapes.pushBack(&capDesc);
- NxBodyDesc bodyDesc;
- bodyDesc.mass = 1.f;
- actorDesc.body = &bodyDesc;
- bodyDesc.flags |= NX_BF_KINEMATIC;
- actorDesc.name = "AvatarTriggerKinematicGuy";
- fSeeking=false;
- try
- {
- fKinematicActor = scene->createActor(actorDesc);
- } catch (...)
- {
- hsAssert(false, "Actor creation crashed");
- }
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- // initially start as in-active
- fKinematicActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
-#endif
- // set the matrix to be the same as the controller's actor... that should orient it to be the same
- fKinematicActor->setGlobalPose(actor->getGlobalPose());
-
- // the proxy for the debug display
- //hsAssert(!fProxyGen, "Already have proxy gen, double read?");
-
- hsColorRGBA physColor;
- hsScalar opac = 1.0f;
-
- // local avatar is light purple and transparent
- physColor.Set(.2f, .1f, .2f, 1.f);
- opac = 0.8f;
-
- // the avatar proxy doesn't seem to work... not sure why?
- fProxyGen = new plPhysicalProxy(hsColorRGBA().Set(0,0,0,1.f), physColor, opac);
- fProxyGen->Init(this);
-}
-
-void plPXPhysicalController::IDeleteController()
-{
- if (fController)
- {
- gControllerMgr.releaseController(*fController);
- fController = nil;
-
- if (fKinematicActor)
- {
- NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
- scene->releaseActor(*fKinematicActor);
- fKinematicActor = nil;
- }
- plSimulationMgr::GetInstance()->ReleaseScene(fWorldKey);
- }
-}
-
-// Make a visible object that can be viewed by users for debugging purposes.
-plDrawableSpans* plPXPhysicalController::CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo)
-{
- plDrawableSpans* myDraw = addTo;
-
- bool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask));
- float radius = fRadius;
- myDraw = plDrawableGenerator::GenerateSphericalDrawable(fLocalPosition, radius,
- mat, fLastGlobalLoc, blended,
- nil, &idx, myDraw);
-
-/*
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
- {
- bool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask));
-
- myDraw = plDrawableGenerator::GenerateConicalDrawable(fRadius*10, fHeight*10,
- mat, so->GetLocalToWorld(), blended,
- nil, &idx, myDraw);
- }
-*/
- return myDraw;
-}
-
-#ifndef PLASMA_EXTERNAL_RELEASE
-
-void plPXPhysicalController::IDrawDebugDisplay()
-{
- plDebugText &debugTxt = plDebugText::Instance();
- char strBuf[ 2048 ];
- int lineHeight = debugTxt.GetFontSize() + 4;
- uint32_t scrnWidth, scrnHeight;
-
- debugTxt.GetScreenSize( &scrnWidth, &scrnHeight );
- int y = 10;
- int x = 10;
-
- sprintf(strBuf, "Controller Count: %d", gControllers.size());
- debugTxt.DrawString(x, y, strBuf);
- y += lineHeight;
-
- debugTxt.DrawString(x, y, "Avatar Collisions:");
- y += lineHeight;
-
- int i;
- for (i = 0; i < fDbgCollisionInfo.GetCount(); i++)
- {
- hsVector3 normal = fDbgCollisionInfo[i].fNormal;
- char *overlapStr = fDbgCollisionInfo[i].fOverlap ? "yes" : "no";
- hsScalar angle = hsScalarRadToDeg(hsACosine(normal * hsVector3(0, 0, 1)));
- sprintf(strBuf, " Obj: %s, Normal: (%.2f, %.2f, %.2f), Angle(%.1f), Overlap(%3s)",
- fDbgCollisionInfo[i].fSO->GetKeyName(),
- normal.fX, normal.fY, normal.fZ, angle, overlapStr);
- debugTxt.DrawString(x, y, strBuf);
- y += lineHeight;
- }
-}
-
-#endif PLASMA_EXTERNAL_RELEASE
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.h b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.h
deleted file mode 100644
index be03fabe..00000000
--- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*==LICENSE==*
-
-CyanWorlds.com Engine - MMOG client, server and tools
-Copyright (C) 2011 Cyan Worlds, Inc.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-Additional permissions under GNU GPL version 3 section 7
-
-If you modify this Program, or any covered work, by linking or
-combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
-NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
-JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
-(or a modified version of those libraries),
-containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
-PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
-JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
-licensors of this Program grant you additional
-permission to convey the resulting work. Corresponding Source for a
-non-source form of such a combination shall include the source code for
-the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
-work.
-
-You can contact Cyan Worlds, Inc. by email legal@cyan.com
- or by snail mail at:
- Cyan Worlds, Inc.
- 14617 N Newport Hwy
- Mead, WA 99021
-
-*==LICENSE==*/
-#ifndef plPXPhysicalController_h_inc
-#define plPXPhysicalController_h_inc
-
-#include "plAvatar/plAvCallbackAction.h"
-#include "hsQuat.h"
-
-#define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1
-
-class NxController;
-class NxCapsuleController;
-class NxActor;
-class plCoordinateInterface;
-class plPhysicalProxy;
-class plDrawableSpans;
-class hsGMaterial;
-class NxCapsule;
-#ifndef PLASMA_EXTERNAL_RELEASE
-class plDbgCollisionInfo
-{
-public:
- plSceneObject *fSO;
- hsVector3 fNormal;
- bool fOverlap;
-};
-#endif // PLASMA_EXTERNAL_RELEASE
-
-class plPXPhysicalController : public plPhysicalController
-{
-public:
- plPXPhysicalController(plKey ownerSO, hsScalar height, hsScalar radius);
- virtual ~plPXPhysicalController();
-
- virtual void Enable(bool enable);
- virtual bool IsEnabled() const { return fEnable; }
-
- virtual void SetLOSDB(plSimDefs::plLOSDB losDB) { fLOSDB = losDB; }
- plSimDefs::plLOSDB GetLOSDB() const { return fLOSDB; }
-
- virtual void SetVelocities(const hsVector3& linearVel, hsScalar angVel)
- {
- fLinearVelocity = linearVel;
- fAngularVelocity = angVel;
- }
-
- virtual const hsVector3& GetLinearVelocity() const { return fAchievedLinearVelocity; }
- virtual void ResetAchievedLinearVelocity() { fAchievedLinearVelocity.Set(0.f, 0.f, 0.f); }
-
- virtual plKey GetSubworld() const { return fWorldKey; }
- virtual void SetSubworld(plKey world);
-
- virtual bool IsOnGround() const { return fTimeInAir < kAirTimeThreshold || fFalseGround; }
- virtual bool IsOnFalseGround() const { return fFalseGround && !fGroundHit; }
- virtual void GroundHit() { fGroundHit = true; }
- virtual hsScalar GetAirTime() const { return fTimeInAir; }
- virtual void ResetAirTime() { fTimeInAir = 0.f; }
- virtual void AddSlidingNormal(hsVector3 vec);
- virtual hsTArray* GetSlidingNormals() { return &fSlidingNormals; }
-
- virtual plPhysical* GetPushingPhysical() const { return fPushingPhysical; }
- virtual bool GetFacingPushingPhysical() const { return fFacingPushingPhysical; }
-
- virtual const plCoordinateInterface* GetSubworldCI() const;
-
- virtual void GetState(hsPoint3& pos, float& zRot);
- virtual void SetState(const hsPoint3& pos, float zRot);
-
- plKey GetOwner() const { return fOwner; }
-
- // Called by the simulation mgr each frame
- static void Update(bool prestep, hsScalar delSecs);
- // Used by the LOS mgr to find the controller for an actor it hit
- static plPXPhysicalController* GetController(NxActor& actor, bool* isController);
- // test to see if there are any controllers (i.e. avatars) in this subworld
- static bool plPXPhysicalController::AnyControllersInThisWorld(plKey world);
- static int plPXPhysicalController::NumControllers();
- static int plPXPhysicalController::GetControllersInThisSubWorld(plKey world, int maxToReturn,
- plPXPhysicalController** bufferout);
- static int plPXPhysicalController::GetNumberOfControllersInThisSubWorld(plKey world);
- // Call this if a static physical in the scene has changed (unloaded,
- // collision enabled/disabled, etc)
- static void RebuildCache();
-
- virtual void GetPositionSim(hsPoint3& pos) const { IGetPositionSim(pos); }
-
- virtual void Kinematic(bool state);
- virtual bool IsKinematic();
- virtual void GetKinematicPosition(hsPoint3& pos);
-
- virtual plDrawableSpans* CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo);
-
- virtual const hsMatrix44& GetPrevSubworldW2L() { return fPrevSubworldW2L; }
-
- virtual void SetSeek(bool seek){fSeeking=seek;}
- virtual void GetWorldSpaceCapsule(NxCapsule& cap);
-#ifndef PLASMA_EXTERNAL_RELEASE
- static bool fDebugDisplay;
-#endif // PLASMA_EXTERNAL_RELEASE
-
-protected:
- static const hsScalar kAirTimeThreshold;
-
- friend class PXControllerHitReport;
- static plPXPhysicalController* FindController(NxController* controller);
-
- void IApply(hsScalar delSecs);
- void ISendUpdates(hsScalar delSecs);
- void ICheckForFalseGround();
- void ISetGlobalLoc(const hsMatrix44& l2w);
- void IMatchKinematicToController();
- void IMoveKinematicToController(hsPoint3& pos);
- void ISetKinematicLoc(const hsMatrix44& l2w);
- void IGetPositionSim(hsPoint3& pos) const;
-
- void ICreateController();
- void IDeleteController();
-
- void IInformDetectors(bool entering);
-
- plKey fOwner;
- plKey fWorldKey;
- hsScalar fRadius, fHeight;
- NxCapsuleController* fController;
-
- // this is the kinematic actor for triggering things when the avatar is collision-less during behaviors
- NxActor* fKinematicActor;
-
- hsVector3 fLinearVelocity;
- hsScalar fAngularVelocity;
-
- hsVector3 fAchievedLinearVelocity;
-
- // The global position and rotation of the avatar last time we set it (so we
- // can detect if someone else moves him)
- hsMatrix44 fLastGlobalLoc;
- //
- hsPoint3 fLocalPosition;
- hsQuat fLocalRotation;
-
- hsMatrix44 fPrevSubworldW2L;
-
- bool fEnable;
- bool fEnableChanged;
- plSimDefs::plLOSDB fLOSDB;
-
- bool fKinematic;
- bool fKinematicChanged;
- bool fKinematicEnableNextUpdate;
-
- bool fGroundHit;
- bool fFalseGround;
- hsScalar fTimeInAir;
- hsTArray fSlidingNormals;
- hsTArray fPrevSlidingNormals;
-
-#ifndef PLASMA_EXTERNAL_RELEASE
- hsTArray fDbgCollisionInfo;
- void IDrawDebugDisplay();
-#endif // PLASMA_EXTERNAL_RELEASE
-
- plPhysical* fPushingPhysical;
- bool fFacingPushingPhysical;
-
- plPhysicalProxy* fProxyGen; // visual proxy for debugging
-
- bool fHitHead;
-
- bool fSeeking;
-};
-
-#endif // plPXPhysicalController_h_inc
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp
index cdb1b968..edbb6808 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp
@@ -40,13 +40,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
#include "plPXPhysicalControllerCore.h"
-#include "plgDispatch.h"
#include "plSimulationMgr.h"
#include "plPXPhysical.h"
#include "plPXConvert.h"
#include "pnSceneObject/plSimulationInterface.h"
#include "pnSceneObject/plSceneObject.h"
-#include "pnMessage/plCorrectionMsg.h"
#include "plAvatar/plArmatureMod.h"
#include "pnSceneObject/plCoordinateInterface.h"
#include "plDrawable/plDrawableGenerator.h"
@@ -54,130 +52,100 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "pnMessage/plSetNetGroupIDMsg.h"
#include "plMessage/plCollideMsg.h"
#include "plModifier/plDetectorLog.h"
-//#include "NxVecExtendedVec3.h"
+
+#include "plSurface/hsGMaterial.h" // For our proxy
+#include "plSurface/plLayerInterface.h" // For our proxy
#include "NxPhysics.h"
-#include "ControllerManager.h"
#include "NxCapsuleController.h"
#include "NxCapsuleShape.h"
+#include "ControllerManager.h"
-#include "plSurface/hsGMaterial.h"
-#include "plSurface/plLayerInterface.h"
-
-
-#ifndef PLASMA_EXTERNAL_RELEASE
-#include "plPipeline/plDebugText.h"
-#endif
-
-#define kPhysxSkinWidth 0.1f
-#define kPhysZOffset ((fRadius + (fHeight / 2)) + kPhysxSkinWidth)
-#define kPhysicalHeightFudge 0.0f
-#define STEP_OFFSET 1.f
-#define kAvatarMass 160.f
-
+static ControllerManager gControllerMgr;
+static std::vector gControllers;
+static bool gRebuildCache = false;
#ifndef PLASMA_EXTERNAL_RELEASE
bool plPXPhysicalControllerCore::fDebugDisplay = false;
#endif // PLASMA_EXTERNAL_RELEASE
int plPXPhysicalControllerCore::fPXControllersMax = 0;
-static ControllerManager gControllerMgr;
-static std::vector gControllers;
-static bool gRebuildCache=false;
+#define kCCTSkinWidth 0.1f
+#define kCCTStepOffset 0.6f
+#define kCCTZOffset ((fRadius + (fHeight / 2)) + kCCTSkinWidth)
+#define kPhysHeightCorrection 0.8f
+#define kPhysZOffset ((kCCTZOffset + (kPhysHeightCorrection / 2)) - 0.05f)
+#define kAvatarMass 200.0f
-class PXControllerHitReportWalk : public NxUserControllerHitReport
+static class PXControllerHitReport : public NxUserControllerHitReport
{
public:
virtual NxControllerAction onShapeHit(const NxControllerShapeHit& hit)
{
- plPXPhysicalControllerCore* ac = plPXPhysicalControllerCore::FindController(hit.controller);
+ plPXPhysicalControllerCore* controller = (plPXPhysicalControllerCore*)hit.controller->getUserData();
NxActor& actor = hit.shape->getActor();
plPXPhysical* phys = (plPXPhysical*)actor.userData;
hsVector3 normal = plPXConvert::Vector(hit.worldNormal);
- ac->fMovementInterface->IAddContactNormals(normal);
#ifndef PLASMA_EXTERNAL_RELEASE
plDbgCollisionInfo info;
info.fNormal = normal;
info.fSO = plSceneObject::ConvertNoRef(phys->GetObjectKey()->ObjectIsLoaded());
- info.fOverlap = false;
- NxShape* const *shapes = hit.controller->getActor()->getShapes();
- int numShapes = hit.controller->getActor()->getNbShapes();
- int i;
- for (i = 0; i < numShapes; i++)
- {
- // should only be one capsule shape
- const NxCapsuleShape *capShape = shapes[i]->isCapsule();
- if (capShape)
- {
- NxCapsule cap;
- capShape->getWorldCapsule(cap);
- if (hit.shape->checkOverlapCapsule(cap))
- info.fOverlap = true;
- }
- }
- ac->fDbgCollisionInfo.Append(info);
+
+ NxCapsule capsule;
+ controller->GetWorldSpaceCapsule(capsule);
+ info.fOverlap = hit.shape->checkOverlapCapsule(capsule);
+
+ controller->fDbgCollisionInfo.Append(info);
#endif PLASMA_EXTERNAL_RELEASE
// If the avatar hit a movable physical, apply some force to it.
- hsVector3 dir = plPXConvert::Vector(hit.dir);
- float dirdotup=dir.fZ;
- hsPoint3 pos((float)hit.worldPos.x, (float)hit.worldPos.y, (float)hit.worldPos.z);
- NxExtendedVec3 controllerPos=hit.controller->getPosition();
- hsVector3 bottomOfTheCapsule((float)controllerPos.x,(float)controllerPos.y,(float)controllerPos.z);
- bottomOfTheCapsule.fZ=bottomOfTheCapsule.fZ-(ac->fHeight/2.0f + ac->fRadius);
- if (actor.isDynamic() && phys )
+ if (actor.isDynamic())
{
- if((hit.worldPos.z- bottomOfTheCapsule.fZ)<=ac->fRadius)//bottom hemisphere
+ if (!actor.readBodyFlag(NX_BF_KINEMATIC) && !actor.readBodyFlag(NX_BF_FROZEN))
{
- // If this is an animated physical, we can stand on it
- if (phys->GetProperty(plSimulationInterface::kPhysAnim))
+ // Don't apply force when standing on top of an object.
+ if (normal.fZ < 0.85f)
{
- if(normal.fZ>=0)
+ hsVector3 velocity = controller->GetLinearVelocity();
+ velocity.fZ = 0.0f;
+ float length = velocity.Magnitude();
+ if (length > 0)
{
- //we consider this ground
- ac->fMovementInterface->AddOnTopOfObject(phys);
+ // Only allow horizontal pushes for now
+ NxVec3 hitDir = hit.worldPos - hit.controller->getPosition();
+ hitDir.z = 0.0f;
+ hitDir.normalize();
+
+ // Get controller speed along the hitDir
+ float cctProj = velocity.fX * hitDir.x + velocity.fY * hitDir.y;
+ length = length + cctProj / 2.0f;
+
+ // Get hit actors speed along the hitDir
+ float hitProj = actor.getLinearVelocity().dot(hitDir);
+ if (hitProj > 0)
+ length -= hitProj;
+
+ length *= kAvatarMass;
+
+ hsPoint3 pos((float)hit.worldPos.x, (float)hit.worldPos.y, (float)hit.worldPos.z);
+ phys->SetHitForce(plPXConvert::Vector(hitDir * length), pos);
+ controller->AddDynamicHit(phys);
}
}
}
- if ( !actor.readBodyFlag(NX_BF_KINEMATIC) && !actor.readBodyFlag(NX_BF_FROZEN))
- {
- // If this is the local avatar, we need to take ownership of this
- // dynamic if we haven't already
- if (ac->fLOSDB == plSimDefs::kLOSDBLocalAvatar && !phys->IsLocallyOwned() &&
- !phys->GetProperty(plSimulationInterface::kNoOwnershipChange))
- {
- plSynchedObject* obj = plSynchedObject::ConvertNoRef(phys->GetObjectKey()->ObjectIsLoaded());
- obj->SetNetGroupConstant(plNetGroup::kNetGroupLocalPhysicals);
- // Tell all the other clients that we own this physical
- plSetNetGroupIDMsg* setNetGroupID = new plSetNetGroupIDMsg;
- setNetGroupID->fId = plNetGroup::kNetGroupRemotePhysicals;
- setNetGroupID->SetBCastFlag(plMessage::kNetPropagate | plMessage::kNetForce);
- setNetGroupID->SetBCastFlag(plMessage::kLocalPropagate, false);
- setNetGroupID->Send(obj->GetKey());
- }
- plSimulationMgr::GetInstance()->ConsiderSynch(phys, nil);
-
- // Now, let's impart some force, fool.
- // Note: This is a VERY simple implementation. The old one was too hacky and caused weird stuff to happen.
- hsVector3 acceleration = (ac->GetLinearVelocity() - plPXConvert::Vector(actor.getLinearVelocity()));
- hsVector3 force2impart = acceleration * kAvatarMass;
- // 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.
- if (!force2impart.IsEmpty() && normal.fZ < .90f)
- phys->SetHitForce(force2impart, pos);
- }
}
else // else if the avatar hit a static
{
+ controller->fMovementStrategy->AddContactNormals(normal);
return NX_ACTION_NONE;
}
- if (phys->GetProperty(plSimulationInterface::kAvAnimPushable))
+ if (phys && phys->GetProperty(plSimulationInterface::kAvAnimPushable))
{
- hsQuat inverseRotation = ac->fLocalRotation.Inverse();
+ hsQuat inverseRotation = controller->fLocalRotation.Inverse();
hsVector3 normal = plPXConvert::Vector(hit.worldNormal);
- ac->SetPushingPhysical( phys);
- ac->SetFacingPushingPhysical((inverseRotation.Rotate(&kAvatarForward).InnerProduct(normal) < 0 ? true : false));
+ controller->SetPushingPhysical(phys);
+ controller->SetFacingPushingPhysical((inverseRotation.Rotate(&kAvatarForward).InnerProduct(normal) < 0 ? true : false));
}
return NX_ACTION_NONE;
}
@@ -185,161 +153,34 @@ public:
{
return NX_ACTION_NONE;
}
-
-} gMyReport;
-
+} gControllerHitReport;
plPhysicalControllerCore* plPhysicalControllerCore::Create(plKey ownerSO, float height, float width)
{
- // Test to see how many controller there already is
- if ( !plPXPhysicalControllerCore::fPXControllersMax || plPXPhysicalControllerCore::NumControllers() < plPXPhysicalControllerCore::fPXControllersMax )
- {
- float radius = width / 2.f;
- float realHeight = height - width + kPhysicalHeightFudge;
- return new plPXPhysicalControllerCore(ownerSO, realHeight,radius);
- }
- return nil;
-}
-
-//Static Helper Func
-plPXPhysicalControllerCore* plPXPhysicalControllerCore::FindController(NxController* controller)
-{
- for (int i = 0; i < gControllers.size(); i++)
+ if (!plPXPhysicalControllerCore::fPXControllersMax || gControllers.size() < plPXPhysicalControllerCore::fPXControllersMax)
{
- plPXPhysicalControllerCore* ac = gControllers[i];
- if (ac->fController == controller)
- return ac;
+ float radius = width / 2.0f;
+ float realHeight = height - width;
+ return new plPXPhysicalControllerCore(ownerSO, realHeight, radius);
}
return nil;
}
-void plPXPhysicalControllerCore::RebuildCache(){gRebuildCache=true;}
-
-plPXPhysicalControllerCore* plPXPhysicalControllerCore::GetController(NxActor& actor, bool* isController)
-{
- *isController = false;
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalControllerCore* ac = gControllers[i];
- if (ac->fController && ac->fController->getActor() == &actor)
- {
- *isController = true;
- return ac;
- }
- if ( ac->fKinematicActor == &actor)
- {
- return ac;
- }
- }
-
- return nil;
-}
-void plPXPhysicalControllerCore::GetWorldSpaceCapsule(NxCapsule& cap) const
-{
- if(this->fKinematicActor)
- {
- int numshapes=fKinematicActor->getNbShapes();
- if (numshapes==1)
- {
- //there should only be one shape on a controller
- NxShape* const *shapes=fKinematicActor->getShapes();
- //and since it is a capsule controller it better be a capsule;
- NxCapsuleShape *capShape = shapes[0]->isCapsule();
- if(capShape) capShape->getWorldCapsule(cap);
- }
- }
-}
-bool plPXPhysicalControllerCore::AnyControllersInThisWorld(plKey world)
-{
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalControllerCore* ac = gControllers[i];
- if (ac->GetSubworld() == world)
- return true;
- }
- return false;
-}
-
-int plPXPhysicalControllerCore::NumControllers()
-{
- return gControllers.size();
-}
-int plPXPhysicalControllerCore::GetControllersInThisSubWorld(plKey world, int maxToReturn,plPXPhysicalControllerCore** bufferout)
-{
- int i=0;
- for (int j=0;jGetSubworld()==world)
- {
- if(iGetSubworld()==world)i++;
- }
- return i;
-}
-//
plPXPhysicalControllerCore::plPXPhysicalControllerCore(plKey ownerSO, float height, float radius)
- : plPhysicalControllerCore(ownerSO,height,radius)
- , fController(nil)
- , fProxyGen(nil)
- , fKinematicActor(nil)
- ,fPreferedRadius(radius)
- ,fPreferedHeight(height)
- , fBehavingLikeAnimatedPhys(true)
-{
- fLocalPosition.Set(0, 0, 0);
- fLocalRotation.Set(0, 0, 0, 1);
+ : plPhysicalControllerCore(ownerSO, height, radius),
+ fController(nil),
+ fActor(nil),
+ fProxyGen(nil),
+ fKinematicCCT(true)
+{
+ ICreateController(fLocalPosition);
+ fActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
gControllers.push_back(this);
- fLastGlobalLoc.Reset();
- ICreateController();
- Enable(false);
-}
-
-void plPXPhysicalControllerCore::ISetGlobalLoc(const hsMatrix44& l2w)
-{
- fLastGlobalLoc = l2w;
- // Update our subworld position and rotation
- const plCoordinateInterface* subworldCI = GetSubworldCI();
- if (subworldCI)
- {
- const hsMatrix44& w2s = fPrevSubworldW2L;
- hsMatrix44 l2s = w2s * l2w;
-
- l2s.GetTranslate(&fLocalPosition);
- fLocalRotation.SetFromMatrix44(l2s);
- }
- else
- {
- l2w.GetTranslate(&fLocalPosition);
- fLocalRotation.SetFromMatrix44(l2w);
- }
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
- if (fProxyGen)
- fProxyGen->SetTransform(l2w, w2l);
- // Update the physical position
- NxExtendedVec3 nxPos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kPhysZOffset);
- fController->setPosition(nxPos);
- IMatchKinematicToController();
}
plPXPhysicalControllerCore::~plPXPhysicalControllerCore()
{
- IDeleteController();
- for (int i = 0; i < gControllers.size(); i++)
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
{
if (gControllers[i] == this)
{
@@ -347,445 +188,89 @@ plPXPhysicalControllerCore::~plPXPhysicalControllerCore()
break;
}
}
- delete fProxyGen;
-}
-void plPXPhysicalControllerCore::IMatchKinematicToController()
-{
- if ( fKinematicActor)
- {
- NxExtendedVec3 cPos = fController->getPosition();
- NxVec3 prevKinPos = fKinematicActor->getGlobalPosition();
- NxVec3 kinPos;
- kinPos.x = (NxReal)cPos.x;
- kinPos.y = (NxReal)cPos.y;
- kinPos.z = (NxReal)cPos.z;
- if (plSimulationMgr::fExtraProfile)
- SimLog("Match setting kinematic from %f,%f,%f to %f,%f,%f",prevKinPos.x,prevKinPos.y,prevKinPos.z,kinPos.x,kinPos.y,kinPos.z );
- if (fKinematicActor->readBodyFlag(NX_BF_KINEMATIC))
- fKinematicActor->moveGlobalPosition(kinPos);
- else
- fKinematicActor->setGlobalPosition(kinPos);
- }
-}
-void plPXPhysicalControllerCore::UpdateControllerAndPhysicalRep()
-{
- if ( fKinematicActor)
- {
- if(this->fBehavingLikeAnimatedPhys)
- {//this means we are moving the controller and then synchnig the kin
- NxExtendedVec3 ControllerPos= fController->getPosition();
- NxVec3 NewKinPos((NxReal)ControllerPos.x, (NxReal)ControllerPos.y, (NxReal)ControllerPos.z);
- if (fKinematicActor->readBodyFlag(NX_BF_KINEMATIC))
- {
- if (plSimulationMgr::fExtraProfile)
- SimLog("Moving kinematic to %f,%f,%f",NewKinPos.x, NewKinPos.y, NewKinPos.z );
- // use the position
- fKinematicActor->moveGlobalPosition(NewKinPos);
-
- }
- else
- {
- if (plSimulationMgr::fExtraProfile)
- SimLog("Setting kinematic to %f,%f,%f", NewKinPos.x, NewKinPos.y, NewKinPos.z );
- fKinematicActor->setGlobalPosition(NewKinPos);
- }
-
- }
- else
- {
- NxVec3 KinPos= fKinematicActor->getGlobalPosition();
- NxExtendedVec3 NewControllerPos(KinPos.x, KinPos.y, KinPos.z);
- if (plSimulationMgr::fExtraProfile)
- SimLog("Setting Controller to %f,%f,%f", NewControllerPos.x, NewControllerPos.y, NewControllerPos.z );
- fController->setPosition(NewControllerPos);
- }
- hsPoint3 curLocalPos;
- GetPositionSim(curLocalPos);
- fLocalPosition = curLocalPos;
- }
-}
-void plPXPhysicalControllerCore::MoveKinematicToController(hsPoint3& pos)
-{
- if ( fKinematicActor)
- {
- NxVec3 kinPos = fKinematicActor->getGlobalPosition();
- if ( abs(kinPos.x-pos.fX) + abs(kinPos.y-pos.fY) + (abs(kinPos.z-pos.fZ+kPhysZOffset)) > 0.0001f)
- {
- NxVec3 newPos;
- newPos.x = (NxReal)pos.fX;
- newPos.y = (NxReal)pos.fY;
- newPos.z = (NxReal)pos.fZ+kPhysZOffset;
- if (fKinematicActor->readBodyFlag(NX_BF_KINEMATIC))
- {
- if (plSimulationMgr::fExtraProfile)
- SimLog("Moving kinematic from %f,%f,%f to %f,%f,%f",pos.fX,pos.fY,pos.fZ+kPhysZOffset,kinPos.x,kinPos.y,kinPos.z );
- // use the position
- fKinematicActor->moveGlobalPosition(newPos);
- }
- else
- {
- if (plSimulationMgr::fExtraProfile)
- SimLog("Setting kinematic from %f,%f,%f to %f,%f,%f",pos.fX,pos.fY,pos.fZ+kPhysZOffset,kinPos.x,kinPos.y,kinPos.z );
- fKinematicActor->setGlobalPosition(newPos);
- }
- }
- }
-}
-
-void plPXPhysicalControllerCore::ISetKinematicLoc(const hsMatrix44& l2w)
-{
- hsPoint3 kPos;
- // Update our subworld position and rotation
- const plCoordinateInterface* subworldCI = GetSubworldCI();
- if (subworldCI)
- {
- const hsMatrix44& w2s = subworldCI->GetWorldToLocal();
- hsMatrix44 l2s = w2s * l2w;
-
- l2s.GetTranslate(&kPos);
- }
- else
- {
- l2w.GetTranslate(&kPos);
- }
-
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
- if (fProxyGen)
- fProxyGen->SetTransform(l2w, w2l);
+ IDeleteController();
- // add z offset
- kPos.fZ += kPhysZOffset;
- // Update the physical position of kinematic
- if (fKinematicActor->readBodyFlag(NX_BF_KINEMATIC))
- fKinematicActor->moveGlobalPosition(plPXConvert::Point(kPos));
- else
- fKinematicActor->setGlobalPosition(plPXConvert::Point(kPos));
-}
-void plPXPhysicalControllerCore::IGetPositionSim(hsPoint3& pos) const
-{
-
- if(this->fBehavingLikeAnimatedPhys)
- {
- const NxExtendedVec3& nxPos = fController->getPosition();
- pos.Set(float(nxPos.x), float(nxPos.y), float(nxPos.z) - kPhysZOffset);
- }
- else
- {
- NxVec3 Pos = fKinematicActor->getGlobalPosition();
- pos.Set(float(Pos.x), float(Pos.y), float(Pos.z) - kPhysZOffset);
- }
-}
-void plPXPhysicalControllerCore::ICreateController()
-{
-NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
-
- NxCapsuleControllerDesc desc;
- desc.position.x = 0;
- desc.position.y = 0;
- desc.position.z = -10000; // No one should be building down there... (-2000 is kickable limit)
- desc.upDirection = NX_Z;
- desc.slopeLimit = kSLOPELIMIT;
- desc.skinWidth = kPhysxSkinWidth;
- desc.stepOffset = STEP_OFFSET;
- desc.callback = &gMyReport;
- desc.userData = this;
- desc.radius = fRadius;
- desc.height = fHeight;
- desc.interactionFlag = NXIF_INTERACTION_EXCLUDE;
- //desc.interactionFlag = NXIF_INTERACTION_INCLUDE;
- fController = (NxCapsuleController*)gControllerMgr.createController(scene, desc);
-
- // Change the avatars shape groups. The avatar doesn't actually use these when
- // it's determining collision, but if you're standing still and an object runs
- // into you, it'll pass through without this.
- NxActor* actor = fController->getActor();
- NxShape* shape = actor->getShapes()[0];
- shape->setGroup(plSimDefs::kGroupAvatar);
-
- // need to create the non-bouncing object that can be used to trigger things while the avatar is doing behaviors.
- NxActorDesc actorDesc;
- NxCapsuleShapeDesc capDesc;
- capDesc.radius = fRadius;
- capDesc.height = fHeight;
- capDesc.group = plSimDefs::kGroupAvatar;
- capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0);
- actorDesc.shapes.pushBack(&capDesc);
- NxBodyDesc bodyDesc;
- bodyDesc.mass = kAvatarMass;
- actorDesc.body = &bodyDesc;
- bodyDesc.flags = NX_BF_KINEMATIC;
- bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ;
-
- actorDesc.name = "AvatarTriggerKinematicGuy";
- fSeeking=false;
- try
+ // Release any queued messages we may have
+ int numMsgs = fQueuedCollideMsgs.size();
+ if (numMsgs)
{
- fKinematicActor = scene->createActor(actorDesc);
- } catch (...)
- {
- hsAssert(false, "Actor creation crashed");
- }
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- // initially start as in-active
- fKinematicActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
-#endif
- // set the matrix to be the same as the controller's actor... that should orient it to be the same
- // PhysX HACK TURD: Sometimes, using the ***wrong*** function is desirable...
- // Changing this to moveGlobalPose will cause camera regions to fire before linking in.
- fKinematicActor->setGlobalPose(actor->getGlobalPose());
-
- // the proxy for the debug display
- //hsAssert(!fProxyGen, "Already have proxy gen, double read?");
+ for (int i = 0; i < numMsgs; ++i)
+ delete fQueuedCollideMsgs[i];
- hsColorRGBA physColor;
- float opac = 1.0f;
-
- // local avatar is light purple and transparent
- physColor.Set(.2f, .1f, .2f, 1.f);
- opac = 0.8f;
-
- /*
- // the avatar proxy doesn't seem to work... not sure why?
- fProxyGen = new plPhysicalProxy(hsColorRGBA().Set(0,0,0,1.f), physColor, opac);
- fProxyGen->Init(this);
- */
-}
-void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos)
-{
- NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
- NxCapsuleControllerDesc desc;
- desc.position.x = pos.fX;
- desc.position.y = pos.fY;
- desc.position.z = pos.fZ;
- desc.upDirection = NX_Z;
- desc.slopeLimit = kSLOPELIMIT;
- desc.skinWidth = kPhysxSkinWidth;
- desc.stepOffset = STEP_OFFSET;
- desc.callback = &gMyReport;
- desc.userData = this;
- desc.radius = fRadius;
- desc.height = fHeight;
- desc.interactionFlag = NXIF_INTERACTION_EXCLUDE;
- //desc.interactionFlag = NXIF_INTERACTION_INCLUDE;
- fController = (NxCapsuleController*)gControllerMgr.createController(scene, desc);
-
- // Change the avatars shape groups. The avatar doesn't actually use these when
- // it's determining collision, but if you're standing still and an object runs
- // into you, it'll pass through without this.
- NxActor* actor = fController->getActor();
- NxShape* shape = actor->getShapes()[0];
- shape->setGroup(plSimDefs::kGroupAvatar);
-
- // need to create the non-bouncing object that can be used to trigger things while the avatar is doing behaviors.
- NxActorDesc actorDesc;
- NxCapsuleShapeDesc capDesc;
- capDesc.radius = fRadius;
- capDesc.height = fHeight;
- capDesc.group = plSimDefs::kGroupAvatar;
- actorDesc.shapes.pushBack(&capDesc);
- capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0);
- actorDesc.globalPose=actor->getGlobalPose();
- NxBodyDesc bodyDesc;
- bodyDesc.mass = kAvatarMass;
- actorDesc.body = &bodyDesc;
- bodyDesc.flags = NX_BF_KINEMATIC;
- bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ;
- actorDesc.name = "AvatarTriggerKinematicGuy";
- fSeeking=false;
- try
- {
- fKinematicActor = scene->createActor(actorDesc);
- }
- catch (...)
- {
- hsAssert(false, "Actor creation crashed");
+ fQueuedCollideMsgs.clear();
}
- // set the matrix to be the same as the controller's actor... that should orient it to be the same
- //fKinematicActor->setGlobalPose(actor->getGlobalPose());
-
- // the proxy for the debug display
- //hsAssert(!fProxyGen, "Already have proxy gen, double read?");
-
- hsColorRGBA physColor;
- float opac = 1.0f;
-
- // local avatar is light purple and transparent
- physColor.Set(.2f, .1f, .2f, 1.f);
- opac = 0.8f;
-
- /*
- // the avatar proxy doesn't seem to work... not sure why?
- fProxyGen = new plPhysicalProxy(hsColorRGBA().Set(0,0,0,1.f), physColor, opac);
- fProxyGen->Init(this);
- */
-
-}
-void plPXPhysicalControllerCore::IDeleteController()
-{
- if (fController)
- {
- gControllerMgr.releaseController(*fController);
- fController = nil;
-
- if (fKinematicActor)
- {
- NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
- scene->releaseActor(*fKinematicActor);
- fKinematicActor = nil;
- }
- plSimulationMgr::GetInstance()->ReleaseScene(fWorldKey);
- }
+ delete fProxyGen;
}
-void plPXPhysicalControllerCore::IInformDetectors(bool entering,bool deferUntilNextSim=true)
-{
- static const NxU32 DetectorFlag= 1<GetScene(fWorldKey);
- int kNumofShapesToStore=30;
- NxCapsule cap;
- GetWorldSpaceCapsule(cap);
- NxShape* shapes[30];
- int numCollided=scene->overlapCapsuleShapes(cap,NX_ALL_SHAPES,kNumofShapesToStore,shapes,NULL,DetectorFlag,NULL,true);
- for (int i=0;igetActor());
-
- if (myactor)
- {
- plPXPhysical* physical = (plPXPhysical*)myactor->userData;
- if (physical)
- {
- bool doReport = physical->DoReportOn(plSimDefs::kGroupAvatar);
- if(doReport)
- {
- plCollideMsg* msg = new plCollideMsg;
- msg->fOtherKey = fOwner;
- msg->fEntering = entering;
- msg->AddReceiver(physical->GetObjectKey());
- if(!deferUntilNextSim)
- {
- DetectorLog("Sending an %s msg to %s" , entering? "entering":"exit", physical->GetObjectKey()->GetName().c_str());
- msg->Send();
- }
- else
- {
- DetectorLog("Queuing an %s msg to %s, which will be sent after the client update" , entering? "entering":"exit", physical->GetObjectKey()->GetName().c_str());
- plgDispatch::Dispatch()->MsgQueue(msg);
- }
- }
- }
- }
- }
- DetectorLog("Done informing from plPXPhysicalControllerCore::IInformDetectors");
- }
-}
-void plPXPhysicalControllerCore::Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults)
-{
- collisionResults=0;
- if(fController)
- {
- NxVec3 dis(displacement.fX,displacement.fY,displacement.fZ);
- NxU32 colFlags = 0;
- this->fController->move(dis,collideWith,.00001,colFlags);
- if(colFlags&NXCC_COLLISION_DOWN)collisionResults|=kBottom;
- if(colFlags&NXCC_COLLISION_UP)collisionResults|=kTop;
- if(colFlags&&NXCC_COLLISION_SIDES)collisionResults|=kSides;
- }
- return;
-}
void plPXPhysicalControllerCore::Enable(bool enable)
{
if (fEnabled != enable)
{
fEnabled = enable;
if (fEnabled)
+ {
+ // Defer until the next physics update.
fEnableChanged = true;
+ }
else
{
- // See ISendUpdates for why we don't re-enable right away
- fController->setCollision(fEnabled);
+ if (!fKinematicCCT)
+ {
+ // Dynamic controllers are forced kinematic
+ fActor->raiseBodyFlag(NX_BF_KINEMATIC);
+ NxShape* shape = fActor->getShapes()[0];
+ shape->setGroup(plSimDefs::kGroupAvatarKinematic);
+ }
}
}
}
void plPXPhysicalControllerCore::SetSubworld(plKey world)
-{
+{
if (fWorldKey != world)
{
- bool wasEnabled = fEnabled;
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
- // PHYSX FIXME - before leaving this world, sending leaving detector events if we are inside a convex hull detector
- hsPoint3 pos;
- IGetPositionSim(pos);
- plSimulationMgr::GetInstance()->UpdateDetectorsInScene(fWorldKey,GetOwner(),pos,false);
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
- //need to inform detectors in the old world that we are leaving
- IInformDetectors(false);
- //done informing old world
SimLog("Changing subworlds!");
+
+ // Inform detectors in the old world that we are leaving
+ IInformDetectors(false);
IDeleteController();
- SimLog("Deleted old controller");
+
+ // Update Local Position and rotation
fWorldKey = world;
- if (GetSubworldCI())
- fPrevSubworldW2L = GetSubworldCI()->GetWorldToLocal();
- // Update our subworld position and rotation
const plCoordinateInterface* subworldCI = GetSubworldCI();
if (subworldCI)
{
- const hsMatrix44& w2s = fPrevSubworldW2L;
- hsMatrix44 l2s = w2s * fLastGlobalLoc;
+ fPrevSubworldW2L = subworldCI->GetWorldToLocal();
+ hsMatrix44 l2s = fPrevSubworldW2L * fLastGlobalLoc;
l2s.GetTranslate(&fLocalPosition);
fLocalRotation.SetFromMatrix44(l2s);
}
else
{
+ fPrevSubworldW2L.Reset();
fLastGlobalLoc.GetTranslate(&fLocalPosition);
fLocalRotation.SetFromMatrix44(fLastGlobalLoc);
}
- hsMatrix44 w2l;
- fLastGlobalLoc.GetInverse(&w2l);
- if (fProxyGen)
- fProxyGen->SetTransform(fLastGlobalLoc, w2l);
- // Update the physical position
- SimLog("creating new controller");
- hsPoint3 PositionPlusOffset=fLocalPosition;
- PositionPlusOffset.fZ +=kPhysZOffset;
- //placing new controller and kinematic in the appropriate location
- ICreateController(PositionPlusOffset);
- RebuildCache();
- }
-}
-const plCoordinateInterface* plPXPhysicalControllerCore::GetSubworldCI() const
-{
- if (fWorldKey)
- {
- plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded());
- if (so)
- return so->GetCoordinateInterface();
+
+ fLastLocalPosition = fLocalPosition;
+
+ // Create new controller
+ ICreateController(fLocalPosition);
}
- return nil;
}
-// For the avatar SDL only
+
void plPXPhysicalControllerCore::GetState(hsPoint3& pos, float& zRot)
-{
+{
// Temporarily use the position point while we get the z rotation
fLocalRotation.NormalizeIfNeeded();
fLocalRotation.GetAngleAxis(&zRot, (hsVector3*)&pos);
if (pos.fZ < 0)
- zRot = (2 * M_PI) - zRot; // axis is backwards, so reverse the angle too
+ zRot = (2 * float(M_PI)) - zRot; // axis is backwards, so reverse the angle too
pos = fLocalPosition;
-
}
-
void plPXPhysicalControllerCore::SetState(const hsPoint3& pos, float zRot)
{
plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
@@ -811,361 +296,525 @@ void plPXPhysicalControllerCore::SetState(const hsPoint3& pos, float zRot)
so->FlushTransform();
}
}
-// kinematic stuff .... should be just for when playing a behavior...
-void plPXPhysicalControllerCore::Kinematic(bool state)
+
+void plPXPhysicalControllerCore::SetMovementStrategy(plMovementStrategy* strategy)
{
- if (fKinematic != state)
+ if (fKinematicCCT != strategy->IsKinematic())
{
- fKinematic = state;
- if (fKinematic)
- {
- // See ISendUpdates for why we don't re-enable right away
- fController->setCollision(false);
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- fKinematicActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
-#endif
- }
- else
- {
- fKinematicChanged = true;
- }
+ IDeleteController();
+ fKinematicCCT = !fKinematicCCT;
+ ICreateController(fLocalPosition);
}
+
+ fMovementStrategy = strategy;
}
-bool plPXPhysicalControllerCore::IsKinematic()
-{
- return fKinematic;
-}
-void plPXPhysicalControllerCore::GetKinematicPosition(hsPoint3& pos)
+
+void plPXPhysicalControllerCore::SetGlobalLoc(const hsMatrix44& l2w)
{
- pos.Set(-1,-1,-1);
- if ( fKinematicActor )
+ fLastGlobalLoc = l2w;
+
+ // Update our local position and rotation
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
+ {
+ hsMatrix44 l2s = fPrevSubworldW2L * l2w;
+
+ l2s.GetTranslate(&fLocalPosition);
+ fLocalRotation.SetFromMatrix44(l2s);
+ }
+ else
+ {
+ l2w.GetTranslate(&fLocalPosition);
+ fLocalRotation.SetFromMatrix44(l2w);
+ }
+
+ fLastLocalPosition = fLocalPosition;
+
+ if (fProxyGen)
+ {
+ hsMatrix44 w2l;
+ l2w.GetInverse(&w2l);
+ fProxyGen->SetTransform(l2w, w2l);
+ }
+
+ // Update the physical position
+ if (fKinematicCCT)
{
- NxVec3 klPos = fKinematicActor->getGlobalPosition();
- pos.Set(float(klPos.x), float(klPos.y), float(klPos.z) - kPhysZOffset);
+ NxExtendedVec3 pos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kCCTZOffset);
+ fController->setPosition(pos);
+ }
+ else
+ {
+ NxVec3 pos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kPhysZOffset);
+ if (fActor->readBodyFlag(NX_BF_KINEMATIC))
+ fActor->moveGlobalPosition(pos);
+ else
+ fActor->setGlobalPosition(pos);
}
}
-void plPXPhysicalControllerCore::UpdatePoststep( float delSecs)
+
+void plPXPhysicalControllerCore::GetPositionSim(hsPoint3& pos)
{
- // Apparently the user data field of the controllers is broken
-// uint32_t count = gControllerMgr.getNbControllers();
-// NxController* controllers = (NxController*)gControllerMgr.getControllers();
-//
-// for (int i = 0; i < count; i++)
-// {
-// plPXPhysicalController* ac = (plPXPhysicalController*)controllers[i].getAppData();
- for (int i = 0; i < gControllers.size(); i++)
+ if (fKinematicCCT)
{
- plPXPhysicalControllerCore* ac = gControllers[i];
-
- hsAssert(ac, "Bad avatar controller");
-
- gControllerMgr.updateControllers();
- if(ac->fMovementInterface)
- ac->Update(delSecs);
-
- if (ac->GetSubworldCI())
- ac->fPrevSubworldW2L = ac->GetSubworldCI()->GetWorldToLocal();
- else
- {
- if (!ac->fPrevSubworldW2L.IsIdentity())
- ac->fPrevSubworldW2L.Reset();
- }
+ const NxExtendedVec3& extPos = fController->getPosition();
+ pos.Set((float)extPos.x, (float)extPos.y, (float)extPos.z - kCCTZOffset);
+ }
+ else
+ {
+ NxVec3 nxPos = fActor->getGlobalPosition();
+ pos.Set(nxPos.x, nxPos.y, nxPos.z - kPhysZOffset);
}
}
-void plPXPhysicalControllerCore::UpdatePrestep(float delSecs)
+
+void plPXPhysicalControllerCore::Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults)
{
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalControllerCore* ac = gControllers[i];
+ NxU32 colFlags = 0;
- hsAssert(ac, "Bad avatar controller");
- //FIXME
-#ifndef PLASMA_EXTERNAL_RELEASE
- ac->fDbgCollisionInfo.SetCount(0);
-#endif // PLASMA_EXTERNAL_RELEASE
+ fController->move(plPXConvert::Vector(displacement), collideWith, 0.00001f, colFlags);
- if (gRebuildCache&&ac->fController)
- ac->fController->reportSceneChanged();
- //hsAssert(ac->fMovementInterface,"Updating a controller with out a movement strategy");
- if(ac)
- {
- if(ac->fNeedsResize)ac->IHandleResize();
- ac->Apply(delSecs);
- }
-#ifndef PLASMA_EXTERNAL_RELEASE
- if (fDebugDisplay)
- ac->IDrawDebugDisplay();
-#endif // PLASMA_EXTERNAL_RELEASE
- }
- gRebuildCache = false;
+ collisionResults = 0;
+ if (colFlags & NXCC_COLLISION_DOWN)
+ collisionResults |= kBottom;
+ if (colFlags & NXCC_COLLISION_UP)
+ collisionResults |= kTop;
+ if (colFlags & NXCC_COLLISION_SIDES)
+ collisionResults |= kSides;
}
-void plPXPhysicalControllerCore::UpdatePostSimStep(float delSecs)
+
+void plPXPhysicalControllerCore::SetLinearVelocitySim(const hsVector3& linearVel)
{
- for (int i = 0; i < gControllers.size(); i++)
+ if (!fKinematicCCT)
{
- plPXPhysicalControllerCore* ac = gControllers[i];
- hsAssert(ac, "Bad avatar controller");
- ac->PostStep(delSecs);
-
+ NxVec3 vel = plPXConvert::Vector(linearVel);
+ fActor->setLinearVelocity(vel);
}
}
-void plPXPhysicalControllerCore::HandleEnableChanged()
+
+int plPXPhysicalControllerCore::SweepControllerPath(const hsPoint3& startPos, const hsPoint3& endPos, bool vsDynamics, bool vsStatics,
+ uint32_t& vsSimGroups, std::vector& hits)
{
- fEnableChanged = false;
- if(this->fBehavingLikeAnimatedPhys)
- {
- fController->setCollision(fEnabled);
- }
- else
+ NxSweepQueryHit queryHit[10];
+
+ unsigned int flags = NX_SF_ALL_HITS;
+ if (vsDynamics)
+ flags |= NX_SF_DYNAMICS;
+ if (vsStatics)
+ flags |= NX_SF_STATICS;
+
+ NxVec3 vec;
+ vec.x = endPos.fX - startPos.fX;
+ vec.y = endPos.fY - startPos.fY;
+ vec.z = endPos.fZ - startPos.fZ;
+
+ NxShape* shape = fActor->getShapes()[0];
+ NxCapsuleShape* capShape = shape->isCapsule();
+ float radius = capShape->getRadius();
+ float height = capShape->getHeight();
+
+ NxCapsule capsule;
+ capsule.p0 = plPXConvert::Point(startPos);
+ capsule.p0.z = capsule.p0.z + radius;
+ capsule.radius = radius;
+ capsule.p1 = capsule.p0;
+ capsule.p1.z = capsule.p1.z + height;
+
+ NxScene *scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
+ int numHits = scene->linearCapsuleSweep(capsule, vec, flags, nil, 10, queryHit, nil, vsSimGroups);
+ if (numHits)
+ {
+ for (int i = 0; i < numHits; ++i)
{
- fController->setCollision(false);
+ plControllerSweepRecord currentHit;
+ currentHit.ObjHit = (plPhysical*)queryHit[i].hitShape->getActor().userData;
+ if (currentHit.ObjHit)
+ {
+ currentHit.Point = plPXConvert::Point(queryHit[i].point);
+ currentHit.Normal = plPXConvert::Vector(queryHit[i].normal);
+ hits.push_back(currentHit);
+ }
}
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
- // PHYSX FIXME - after re-enabling check to see if we are inside any convex hull detector regions
- hsPoint3 pos;
- IGetPositionSim(pos);
- plSimulationMgr::GetInstance()->UpdateDetectorsInScene(fWorldKey,GetOwner(),pos,fEnabled);
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
- //IInformDetectors(true);
+ }
+
+ return hits.size();
}
-void plPXPhysicalControllerCore::HandleKinematicChanged()
+void plPXPhysicalControllerCore::LeaveAge()
{
- fKinematicChanged = false;
- if(this->fBehavingLikeAnimatedPhys)
- {
- fController->setCollision(true);
- }
- else
- {
- fController->setCollision(false);
- }
-#ifdef PHYSX_KINEMATIC_IS_DISABLED
- fKinematicActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
-#endif // PHYSX_KINEMATIC_IS_DISABLED
+ SetPushingPhysical(nil);
+ if (fWorldKey)
+ SetSubworld(nil);
+
+ // Disable all collisions
+ fActor->raiseActorFlag(NX_AF_DISABLE_COLLISION);
}
-void plPXPhysicalControllerCore::HandleKinematicEnableNextUpdate()
+
+void plPXPhysicalControllerCore::GetWorldSpaceCapsule(NxCapsule& cap) const
{
- fKinematicActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
- fKinematicEnableNextUpdate = false;
+ NxShape* shape = fActor->getShapes()[0];
+ NxCapsuleShape* capShape = shape->isCapsule();
+ capShape->getWorldCapsule(cap);
}
-void plPXPhysicalControllerCore::IHandleResize()
+
+plDrawableSpans* plPXPhysicalControllerCore::CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo)
{
+ // FIXME
+ plDrawableSpans* myDraw = addTo;
+ bool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask));
+ float radius = fRadius;
+ myDraw = plDrawableGenerator::GenerateSphericalDrawable(fLocalPosition, radius,
+ mat, fLastGlobalLoc, blended,
+ nil, &idx, myDraw);
- uint32_t collideFlags =
- 1<ObjectIsLoaded());
+ if (so)
{
- collideFlags|=(1<GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask));
+
+ myDraw = plDrawableGenerator::GenerateConicalDrawable(fRadius*10, fHeight*10,
+ mat, so->GetLocalToWorld(), blended,
+ nil, &idx, myDraw);
}
- NxScene* myscene = plSimulationMgr::GetInstance()->GetScene(this->fWorldKey);
-// NxShape** response=new NxShape*[2];
-
- NxVec3 center(fLocalPosition.fX,fLocalPosition.fY,fLocalPosition.fZ+fPreferedRadius);
- NxSegment Seg(center,center);
- const NxCapsule newCap(Seg,fPreferedRadius);
- int numintersect =myscene->checkOverlapCapsule(newCap,NX_ALL_SHAPES,collideFlags);
- //with new capsule dimensions check for overlap
- //with objects we would collide with
-
- if(numintersect==0)
+*/
+ return myDraw;
+}
+
+void plPXPhysicalControllerCore::AddDynamicHit(plPXPhysical* phys)
+{
+ int numHits = fDynamicHits.size();
+ for (int i = 0; i < numHits; ++i)
{
- fHeight=fPreferedHeight;
- fRadius=fPreferedRadius;
- fController->setRadius(fRadius);
- fController->setHeight(fHeight);
-
- fNeedsResize=false;
+ if (fDynamicHits[i] == phys)
+ return;
}
-// delete[] response;
+ fDynamicHits.push_back(phys);
}
-void plPXPhysicalControllerCore::SetControllerDimensions(float radius, float height)
+
+void plPXPhysicalControllerCore::Apply(float delSecs)
{
- fNeedsResize=false;
- if(fRadius!=radius)
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
{
- fNeedsResize=true;
+ controller = gControllers[i];
+ if (gRebuildCache && controller->fController)
+ controller->fController->reportSceneChanged();
+
+#ifndef PLASMA_EXTERNAL_RELEASE
+ controller->fDbgCollisionInfo.SetCount(0);
+#endif
+
+ controller->IDispatchQueuedMsgs();
+ controller->IApply(delSecs);
+ controller->IProcessDynamicHits();
}
- if(fHeight!=height)
+
+ gRebuildCache = false;
+}
+void plPXPhysicalControllerCore::Update(int numSubSteps, float alpha)
+{
+ gControllerMgr.updateControllers();
+
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
{
- fNeedsResize=true;
+ controller = gControllers[i];
+
+ controller->IUpdate(numSubSteps, alpha);
+
+#ifndef PLASMA_EXTERNAL_RELEASE
+ if (fDebugDisplay)
+ controller->IDrawDebugDisplay();
+#endif
}
- fPreferedRadius=radius;
- fPreferedHeight=height;
}
-
-void plPXPhysicalControllerCore::LeaveAge()
+void plPXPhysicalControllerCore::UpdateNonPhysical(float alpha)
{
- SetPushingPhysical(nil);
- if(fWorldKey) this->SetSubworld(nil);
- this->fMovementInterface->LeaveAge();
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
+ {
+ controller = gControllers[i];
+ controller->IUpdateNonPhysical(alpha);
+ }
}
-int plPXPhysicalControllerCore::SweepControllerPath(const hsPoint3& startPos, const hsPoint3& endPos, bool vsDynamics, bool vsStatics,
- uint32_t& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut)
+
+void plPXPhysicalControllerCore::RebuildCache() { gRebuildCache = true; }
+
+plPXPhysicalControllerCore* plPXPhysicalControllerCore::GetController(NxActor& actor)
{
- NxCapsule tempCap;
- tempCap.p0 =plPXConvert::Point( startPos);
- tempCap.p0.z = tempCap.p0.z + fPreferedRadius;
- tempCap.radius = fPreferedRadius ;
- tempCap.p1 = tempCap.p0;
- tempCap.p1.z = tempCap.p1.z + fPreferedHeight;
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
+ {
+ controller = gControllers[i];
+ if (controller->fActor == &actor)
+ return controller;
+ }
- NxVec3 vec;
- vec.x = endPos.fX - startPos.fX;
- vec.y = endPos.fY - startPos.fY;
- vec.z = endPos.fZ - startPos.fZ;
+ return nil;
+}
- int numberofHits = 0;
- int HitsReturned = 0;
- WhatWasHitOut.clear();
- NxScene *myscene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
- NxSweepQueryHit whatdidIhit[10];
- unsigned int flags = NX_SF_ALL_HITS;
- if(vsDynamics)
- flags |= NX_SF_DYNAMICS;
- if(vsStatics)
- flags |= NX_SF_STATICS;
- numberofHits = myscene->linearCapsuleSweep(tempCap, vec, flags, nil, 10, whatdidIhit, nil, vsSimGroups);
- if(numberofHits)
- {//we hit a dynamic object lets make sure it is not animatable
- for(int i=0; igetActor().userData;
- CurrentHit.Norm.fX = whatdidIhit[i].normal.x;
- CurrentHit.Norm.fY = whatdidIhit[i].normal.y;
- CurrentHit.Norm.fZ = whatdidIhit[i].normal.z;
- if(CurrentHit.ObjHit != nil)
- {
- hsPoint3 where;
- where.fX = whatdidIhit[i].point.x;
- where.fY = whatdidIhit[i].point.y;
- where.fZ = whatdidIhit[i].point.z;
- CurrentHit.locHit = where;
- CurrentHit.TimeHit = whatdidIhit[i].t ;
- WhatWasHitOut.insert(CurrentHit);
- HitsReturned++;
- }
- }
+bool plPXPhysicalControllerCore::AnyControllersInThisWorld(plKey world)
+{
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
+ {
+ controller = gControllers[i];
+ if (controller->GetSubworld() == world)
+ return true;
+ }
+
+ return false;
+}
+int plPXPhysicalControllerCore::GetNumberOfControllersInThisSubWorld(plKey world)
+{
+ int count = 0;
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
+ {
+ controller = gControllers[i];
+ if (controller->GetSubworld() == world)
+ ++count;
}
- return HitsReturned;
+ return count;
}
-void plPXPhysicalControllerCore::BehaveLikeAnimatedPhysical(bool actLikeAnAnimatedPhys)
+int plPXPhysicalControllerCore::GetControllersInThisSubWorld(plKey world, int maxToReturn, plPXPhysicalControllerCore** bufferout)
{
- hsAssert(fKinematicActor, "Changing behavior, but plPXPhysicalControllerCore has no Kinematic actor associated with it");
- if(fBehavingLikeAnimatedPhys!=actLikeAnAnimatedPhys)
+ int count = 0;
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
{
- fBehavingLikeAnimatedPhys=actLikeAnAnimatedPhys;
- if(fKinematicActor)
+ controller = gControllers[i];
+ if (controller->GetSubworld() == world)
{
- if(actLikeAnAnimatedPhys)
+ if (count < maxToReturn)
{
- //need to set BX Kinematic if true and kill any rotation
- fController->setCollision(fEnabled);
- fKinematicActor->raiseBodyFlag(NX_BF_KINEMATIC);
- fKinematicActor->clearBodyFlag(NX_BF_FROZEN_ROT);
- fKinematicActor->raiseBodyFlag(NX_BF_DISABLE_GRAVITY);
- }
- else
- {
- //don't really use the controller now don't bother with collisions
- fController->setCollision(false);
- fKinematicActor->clearBodyFlag(NX_BF_KINEMATIC);
- fKinematicActor->raiseBodyFlag(NX_BF_FROZEN_ROT_X);
- fKinematicActor->raiseBodyFlag(NX_BF_FROZEN_ROT_Y);
- fKinematicActor->clearBodyFlag(NX_BF_DISABLE_GRAVITY);
-
-
+ bufferout[count] = controller;
+ ++count;
}
}
}
-}
-bool plPXPhysicalControllerCore::BehavingLikeAnAnimatedPhysical()
-{
- hsAssert(fKinematicActor, "plPXPhysicalControllerCore is missing a kinematic actor");
- return fBehavingLikeAnimatedPhys;
+ return count;
}
-void plPXPhysicalControllerCore::SetLinearVelocity(const hsVector3& linearVel)
+int plPXPhysicalControllerCore::NumControllers() { return gControllers.size(); }
+
+void plPXPhysicalControllerCore::IHandleEnableChanged()
{
- plPhysicalControllerCore::SetLinearVelocity(linearVel);
- if(fKinematicActor && !fBehavingLikeAnimatedPhys)
+ // Defered enable
+ fEnableChanged = false;
+
+ if (!fKinematicCCT)
{
- NxVec3 vel= plPXConvert::Vector(linearVel);
- fKinematicActor->setLinearVelocity(vel);
+ // Restore dynamic controller
+ fActor->clearBodyFlag(NX_BF_KINEMATIC);
+ NxShape* shape = fActor->getShapes()[0];
+ shape->setGroup(plSimDefs::kGroupAvatar);
}
+
+ // Enable actor collisions
+ if (fActor->readActorFlag(NX_AF_DISABLE_COLLISION))
+ fActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
}
-void plPXPhysicalControllerCore::SetAngularVelocity(const float angvel)
+
+void plPXPhysicalControllerCore::IInformDetectors(bool entering)
{
- plPhysicalControllerCore::SetAngularVelocity(angvel);
- if(fKinematicActor && !fBehavingLikeAnimatedPhys)
+ static const NxU32 kDetectorFlag = 1<GetScene(fWorldKey);
+ int numCollided = scene->overlapCapsuleShapes(capsule, NX_ALL_SHAPES, kNumShapes, shapes, NULL, kDetectorFlag, NULL, true);
+ for (int i = 0; i < numCollided; ++i)
{
- NxVec3 vel(0.0f, 0.0f, angvel);
- fKinematicActor->setAngularVelocity(vel);
+ plPXPhysical* physical = (plPXPhysical*)shapes[i]->getActor().userData;
+ if (physical && physical->DoReportOn(plSimDefs::kGroupAvatar))
+ {
+ plCollideMsg* msg = new plCollideMsg();
+ msg->fOtherKey = fOwner;
+ msg->fEntering = entering;
+ msg->AddReceiver(physical->GetObjectKey());
+
+ // Queue until the next sim step
+ fQueuedCollideMsgs.push_back(msg);
+ }
}
-}
-void plPXPhysicalControllerCore::SetVelocities(const hsVector3& linearVel, float angVel)
-{
- SetLinearVelocity(linearVel);
- SetAngularVelocity(angVel);
+
+ DetectorLog("Done informing from plPXPhysicalControllerCore::IInformDetectors");
}
-void plPXPhysicalControllerCore::IMatchControllerToKinematic()
+void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos)
{
- NxExtendedVec3 newpos;
- NxVec3 pos=fKinematicActor->getGlobalPosition();
- newpos.x=pos.x;
- newpos.y=pos.y;
- newpos.z=pos.z;
- fController->setPosition(newpos);
+ NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
+
+ if (fKinematicCCT)
+ {
+ // Use PhysX character controller
+ NxCapsuleControllerDesc desc;
+ desc.position.x = pos.fX;
+ desc.position.y = pos.fY;
+ desc.position.z = pos.fZ + kCCTZOffset;
+ desc.upDirection = NX_Z;
+ desc.slopeLimit = kSlopeLimit;
+ desc.skinWidth = kCCTSkinWidth;
+ desc.stepOffset = kCCTStepOffset;
+ desc.callback = &gControllerHitReport;
+ desc.userData = this;
+ desc.radius = fRadius;
+ desc.height = fHeight;
+ desc.interactionFlag = NXIF_INTERACTION_EXCLUDE;
+ fController = (NxCapsuleController*)gControllerMgr.createController(scene, desc);
+ fActor = fController->getActor();
+
+ // Set the actor group - Dynamics are in group 1 and will report on everything in group 0.
+ // We don't want notifications
+ fActor->setGroup(2);
+
+ // Set the shape group. Not used by the NxController itself,
+ // But required for correct group interactions in the simulation.
+ NxShape* shape = fActor->getShapes()[0];
+ shape->setGroup(plSimDefs::kGroupAvatarKinematic);
+
+ // In PhysX 2, the kinematic actors scale factor isn't exposed.
+ // It is hardcoded at 0.8 which doesn't suit, so we have to manually adjust its dimensions.
+ float kineRadius = fRadius + kCCTSkinWidth;
+ float kineHeight = fHeight + kPhysHeightCorrection;
+ NxCapsuleShape* capShape = shape->isCapsule();
+ capShape->setDimensions(kineRadius, kineHeight);
+ capShape->setLocalPosition(NxVec3(0.0f, (kPhysHeightCorrection / 2.0f), 0.0f));
+ }
+ else
+ {
+ // Use dynamic actor for the character controller
+ NxCapsuleShapeDesc capDesc;
+ capDesc.materialIndex = plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0f, 0.0f);
+ capDesc.radius = fRadius + kCCTSkinWidth;
+ capDesc.height = fHeight + kPhysHeightCorrection;
+
+ NxBodyDesc bodyDesc;
+ bodyDesc.mass = kAvatarMass;
+ bodyDesc.flags = NX_BF_DISABLE_GRAVITY;
+ bodyDesc.flags |= NX_BF_FROZEN_ROT;
+
+ if (fEnabled)
+ capDesc.group = plSimDefs::kGroupAvatar;
+ else
+ {
+ bodyDesc.flags |= NX_BF_KINEMATIC;
+ capDesc.group = plSimDefs::kGroupAvatarKinematic;
+ }
+
+ NxActorDesc actorDesc;
+ actorDesc.shapes.pushBack(&capDesc);
+ actorDesc.body = &bodyDesc;
+ actorDesc.group = 2;
+
+ actorDesc.globalPose.M.rotX(NxHalfPiF32);
+ actorDesc.globalPose.t.x = pos.fX;
+ actorDesc.globalPose.t.y = pos.fY;
+ actorDesc.globalPose.t.z = pos.fZ + kPhysZOffset;
+
+ fActor = scene->createActor(actorDesc);
+ }
+
+ fSeeking = false;
+
+ // Create proxy for the debug display
+ /* FIXME
+ // the avatar proxy doesn't seem to work... not sure why?
+ hsColorRGBA physColor;
+ float opac = 1.0f;
+
+ // local avatar is light purple and transparent
+ physColor.Set(.2f, .1f, .2f, 1.f);
+ opac = 0.8f;
+
+ fProxyGen = new plPhysicalProxy(hsColorRGBA().Set(0,0,0,1.f), physColor, opac);
+ fProxyGen->Init(this);
+ */
}
-const hsVector3& plPXPhysicalControllerCore::GetLinearVelocity()
+void plPXPhysicalControllerCore::IDeleteController()
{
- if(BehavingLikeAnAnimatedPhysical())
- return fLinearVelocity;
+ if (fKinematicCCT)
+ {
+ gControllerMgr.releaseController(*fController);
+ fController = nil;
+ }
else
{
- fLinearVelocity = plPXConvert::Vector(fKinematicActor->getLinearVelocity());
- return fLinearVelocity;
+ NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey);
+ scene->releaseActor(*fActor);
}
+
+ fActor = nil;
+ plSimulationMgr::GetInstance()->ReleaseScene(fWorldKey);
}
-// Make a visible object that can be viewed by users for debugging purposes.
-plDrawableSpans* plPXPhysicalControllerCore::CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo)
+void plPXPhysicalControllerCore::IDispatchQueuedMsgs()
{
- plDrawableSpans* myDraw = addTo;
- bool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask));
- float radius = fRadius;
- myDraw = plDrawableGenerator::GenerateSphericalDrawable(fLocalPosition, radius,
- mat, fLastGlobalLoc, blended,
- nil, &idx, myDraw);
+ int numMsgs = fQueuedCollideMsgs.size();
+ if (numMsgs)
+ {
+ plSimulationMgr* simMgr = plSimulationMgr::GetInstance();
+ for (int i = 0; i < numMsgs; ++i)
+ simMgr->AddCollisionMsg(fQueuedCollideMsgs[i]);
-/*
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
+ fQueuedCollideMsgs.clear();
+ }
+}
+void plPXPhysicalControllerCore::IProcessDynamicHits()
+{
+ int numHits = fDynamicHits.size();
+ if (numHits)
{
- bool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask));
+ plPXPhysical* phys;
+ plSimulationMgr* simMgr = plSimulationMgr::GetInstance();
+ for (int i = 0; i < numHits; ++i)
+ {
+ phys = fDynamicHits[i];
- myDraw = plDrawableGenerator::GenerateConicalDrawable(fRadius*10, fHeight*10,
- mat, so->GetLocalToWorld(), blended,
- nil, &idx, myDraw);
+ // If this is the local avatar, we need to take ownership of this dynamic if we haven't already
+ if (fLOSDB == plSimDefs::kLOSDBLocalAvatar && !phys->IsLocallyOwned() && !phys->GetProperty(plSimulationInterface::kNoOwnershipChange))
+ {
+ plSynchedObject* obj = plSynchedObject::ConvertNoRef(phys->GetObjectKey()->ObjectIsLoaded());
+ obj->SetNetGroupConstant(plNetGroup::kNetGroupLocalPhysicals);
+
+ plSetNetGroupIDMsg* setNetGroupID = new plSetNetGroupIDMsg;
+ setNetGroupID->fId = plNetGroup::kNetGroupRemotePhysicals;
+ setNetGroupID->SetBCastFlag(plMessage::kNetPropagate | plMessage::kNetForce);
+ setNetGroupID->SetBCastFlag(plMessage::kLocalPropagate, false);
+ setNetGroupID->Send(obj->GetKey());
+ }
+
+ phys->ApplyHitForce();
+ simMgr->ConsiderSynch(phys, nil);
+ }
+ fDynamicHits.clear();
}
-*/
- return myDraw;
}
+
#ifndef PLASMA_EXTERNAL_RELEASE
+#include "../plPipeline/plDebugText.h"
void plPXPhysicalControllerCore::IDrawDebugDisplay()
{
plDebugText &debugTxt = plDebugText::Instance();
char strBuf[ 2048 ];
int lineHeight = debugTxt.GetFontSize() + 4;
- uint32_t scrnWidth, scrnHeight;
+ uint32_t scrnWidth, scrnHeight;
debugTxt.GetScreenSize( &scrnWidth, &scrnHeight );
int y = 10;
@@ -1185,10 +834,11 @@ void plPXPhysicalControllerCore::IDrawDebugDisplay()
char *overlapStr = fDbgCollisionInfo[i].fOverlap ? "yes" : "no";
float angle = hsRadiansToDegrees(acos(normal * hsVector3(0, 0, 1)));
sprintf(strBuf, " Obj: %s, Normal: (%.2f, %.2f, %.2f), Angle(%.1f), Overlap(%3s)",
- fDbgCollisionInfo[i].fSO->GetKeyName().c_str(),
+ fDbgCollisionInfo[i].fSO->GetKeyName(),
normal.fX, normal.fY, normal.fZ, angle, overlapStr);
debugTxt.DrawString(x, y, strBuf);
y += lineHeight;
}
}
#endif PLASMA_EXTERNAL_RELEASE
+
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h
index a2dad48e..4e80b6ff 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h
@@ -40,22 +40,19 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
#include "plAvatar/plPhysicalControllerCore.h"
-#include "hsQuat.h"
-#define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1
-class NxController;
class NxCapsuleController;
class NxActor;
-class plCoordinateInterface;
+class NxCapsule;
+class PXControllerHitReport;
class plPhysicalProxy;
class plDrawableSpans;
class hsGMaterial;
-class NxCapsule;
class plSceneObject;
-class PXControllerHitReportWalk;
+class plPXPhysical;
class plCollideMsg;
-#ifndef PLASMA_EXTERNAL_RELEASE
+#ifndef PLASMA_EXTERNAL_RELEASE
class plDbgCollisionInfo
{
public:
@@ -64,97 +61,112 @@ public:
bool fOverlap;
};
#endif // PLASMA_EXTERNAL_RELEASE
+
class plPXPhysicalControllerCore: public plPhysicalControllerCore
{
- friend class PXControllerHitReportWalk;
public:
plPXPhysicalControllerCore(plKey ownerSO, float height, float radius);
~plPXPhysicalControllerCore();
- //should actually be a 3 vector but everywhere else it is assumed to be just around Z
-
- inline virtual void Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults);
- // A disabled avatar doesn't move or accumulate air time if he's off the ground.
+
+ // An ArmatureMod has its own idea about when physics should be enabled/disabled.
+ // Use plArmatureModBase::EnablePhysics() instead.
virtual void Enable(bool enable);
-
- virtual void SetSubworld(plKey world) ;
- virtual const plCoordinateInterface* GetSubworldCI() const ;
+
+ // Subworld
+ virtual void SetSubworld(plKey world);
+
// For the avatar SDL only
virtual void GetState(hsPoint3& pos, float& zRot);
virtual void SetState(const hsPoint3& pos, float zRot);
- // kinematic stuff .... should be just for when playing a behavior...
- virtual void Kinematic(bool state);
- virtual bool IsKinematic();
- virtual void GetKinematicPosition(hsPoint3& pos);
- virtual const hsMatrix44& GetPrevSubworldW2L(){ return fPrevSubworldW2L; }
- //when seeking no longer want to interact with exclusion regions
- virtual void GetWorldSpaceCapsule(NxCapsule& cap) const;
- static void RebuildCache();
- virtual const hsMatrix44& GetLastGlobalLoc(){return fLastGlobalLoc;}
- virtual void SetKinematicLoc(const hsMatrix44& l2w){ISetKinematicLoc(l2w);}
- virtual void SetGlobalLoc(const hsMatrix44& l2w){ISetGlobalLoc(l2w);}
- virtual void HandleEnableChanged();
- virtual void HandleKinematicChanged();
- virtual void HandleKinematicEnableNextUpdate();
- virtual void GetPositionSim(hsPoint3& pos){IGetPositionSim(pos);}
- virtual void MoveKinematicToController(hsPoint3& pos);
- virtual const hsPoint3& GetLocalPosition(){return fLocalPosition;}
- virtual void SetControllerDimensions(float radius, float height);
+
+ // Movement strategy
+ virtual void SetMovementStrategy(plMovementStrategy* strategy);
+
+ // Global location
+ virtual void SetGlobalLoc(const hsMatrix44& l2w);
+
+ // Local Sim Position
+ virtual void GetPositionSim(hsPoint3& pos);
+
+ // Move kinematic controller
+ virtual void Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults);
+
+ // Set linear velocity on dynamic controller
+ virtual void SetLinearVelocitySim(const hsVector3& linearVel);
+
+ // Sweep the controller path from startPos through endPos
+ virtual int SweepControllerPath(const hsPoint3& startPos, const hsPoint3& endPos, bool vsDynamics,
+ bool vsStatics, uint32_t& vsSimGroups, std::vector& hits);
+
+ // any clean up for the controller should go here
virtual void LeaveAge();
- virtual void UpdateControllerAndPhysicalRep();
+
+ // Capsule
+ void GetWorldSpaceCapsule(NxCapsule& cap) const;
+
+ // Create Proxy for debug rendering
+ plDrawableSpans* CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo);
+
+ // Dynamic hits
+ void AddDynamicHit(plPXPhysical* phys);
//////////////////////////////////////////
//Static Helper Functions
////////////////////////////////////////
- // Used by the LOS mgr to find the controller for an actor it hit
- static plPXPhysicalControllerCore* GetController(NxActor& actor, bool* isController);
- // test to see if there are any controllers (i.e. avatars) in this subworld
+
+ // Call pre-sim to apply movement to controllers
+ static void Apply(float delSecs);
+
+ // Call post-sim to update controllers
+ static void Update(int numSubSteps, float alpha);
+
+ // Update controllers when not performing a physics step
+ static void UpdateNonPhysical(float alpha);
+
+ // Rebuild the controller cache, required when a static actor in the scene has changed.
+ static void RebuildCache();
+
+ // Returns the plPXPhysicalControllerCore associated with the given NxActor
+ static plPXPhysicalControllerCore* GetController(NxActor& actor);
+
+ // Subworld controller queries
static bool AnyControllersInThisWorld(plKey world);
- static int NumControllers();
- static int GetControllersInThisSubWorld(plKey world, int maxToReturn,
- plPXPhysicalControllerCore** bufferout);
static int GetNumberOfControllersInThisSubWorld(plKey world);
- static void UpdatePrestep(float delSecs);
- static void UpdatePoststep(float delSecs);
- static void UpdatePostSimStep(float delSecs);
- virtual plDrawableSpans* CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo);
-#ifndef PLASMA_EXTERNAL_RELEASE
- static bool fDebugDisplay;
-#endif // PLASMA_EXTERNAL_RELEASE
+ static int GetControllersInThisSubWorld(plKey world, int maxToReturn, plPXPhysicalControllerCore** bufferout);
+
+ // Controller count
+ static int NumControllers();
static void SetMaxNumberOfControllers(int max) { fPXControllersMax = max; }
static int fPXControllersMax;
- virtual int SweepControllerPath(const hsPoint3& startPos, const hsPoint3& endPos, bool vsDynamics, bool vsStatics, uint32_t& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut);
- virtual void BehaveLikeAnimatedPhysical(bool actLikeAnAnimatedPhys);
- virtual bool BehavingLikeAnAnimatedPhysical();
- virtual const hsVector3& GetLinearVelocity();
- virtual void SetLinearVelocity(const hsVector3& linearVel);
- //should actually be a 3 vector but everywhere else it is assumed to be just around Z
- virtual void SetAngularVelocity(const float angvel);
- virtual void SetVelocities(const hsVector3& linearVel, float angVel);
+#ifndef PLASMA_EXTERNAL_RELEASE
+ static bool fDebugDisplay;
+#endif
protected:
friend class PXControllerHitReport;
- static plPXPhysicalControllerCore* FindController(NxController* controller);
- void ISetGlobalLoc(const hsMatrix44& l2w);
- void IMatchKinematicToController();
- void IMatchControllerToKinematic();
- void ISetKinematicLoc(const hsMatrix44& l2w);
- void IGetPositionSim(hsPoint3& pos) const;
- void ICreateController();
- void IDeleteController();
- void IInformDetectors(bool entering,bool deferUntilNextSim);
+
+ virtual void IHandleEnableChanged();
+
+ void IInformDetectors(bool entering);
+
void ICreateController(const hsPoint3& pos);
- NxActor* fKinematicActor;
- NxCapsuleController* fController;
+ void IDeleteController();
+
+ void IDispatchQueuedMsgs();
+ void IProcessDynamicHits();
+
#ifndef PLASMA_EXTERNAL_RELEASE
- hsTArray fDbgCollisionInfo;
void IDrawDebugDisplay();
+ hsTArray fDbgCollisionInfo;
#endif
- void IHandleResize();
- float fPreferedRadius;
- float fPreferedHeight;
- // The global position and rotation of the avatar last time we set it (so we
- // can detect if someone else moves him)
- plPhysicalProxy* fProxyGen;
- bool fBehavingLikeAnimatedPhys;
+
+ std::vector fQueuedCollideMsgs;
+ std::vector fDynamicHits;
+
+ NxCapsuleController* fController;
+ NxActor* fActor;
+
+ plPhysicalProxy* fProxyGen;
+ bool fKinematicCCT;
};
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
index 5a4b768e..c7156c4f 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
@@ -70,80 +70,26 @@ class SensorReport : public NxUserTriggerReport
{
virtual void onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status)
{
- // Get our trigger physical. This should definitely have a plPXPhysical
- plPXPhysical* triggerPhys = (plPXPhysical*)triggerShape.getActor().userData;
- bool doReport = false;
-
- // Get the triggerer. This may be an avatar, which doesn't have a
- // plPXPhysical, so we have to extract the necessary info.
plKey otherKey = nil;
- hsPoint3 otherPos = plPXConvert::Point(otherShape.getGlobalPosition());
+ bool doReport = false;
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("-->%s %s (status=%x) other@(%f,%f,%f)",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit",status,otherPos.fX,otherPos.fY,otherPos.fZ);
+ // Get our trigger physical. This should definitely have a plPXPhysical
+ plPXPhysical* triggerPhys = (plPXPhysical*)triggerShape.getActor().userData;
+ // Get the triggerer. If it doesn't have a plPXPhyscial, it's an avatar
plPXPhysical* otherPhys = (plPXPhysical*)otherShape.getActor().userData;
if (otherPhys)
{
otherKey = otherPhys->GetObjectKey();
doReport = triggerPhys->DoReportOn((plSimDefs::Group)otherPhys->GetGroup());
- if (!doReport)
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s :failed group. US=%x OTHER=(%s)%x",triggerPhys->GetObjectKey()->GetName().c_str(),triggerPhys->GetGroup(),otherPhys->GetObjectKey()->GetName().c_str(),otherPhys->GetGroup());
- }
}
else
{
- bool isController;
- plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(otherShape.getActor(),&isController);
+ plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(otherShape.getActor());
if (controller)
{
- if (isController)
- {
-#ifdef PHYSX_ONLY_TRIGGER_FROM_KINEMATIC
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s : ignoring controller events.",triggerPhys->GetObjectKey()->GetName().c_str());
- return;
-#else // else if trigger on both controller and kinematic
- // only suppress controller collision 'enters' when disabled but let 'exits' continue
- // ...this is because there are detector regions that are on the edge on ladders that the exit gets missed.
- if ( ( !controller->IsEnabled() /*&& (status & NX_TRIGGER_ON_ENTER)*/ ) || controller->IsKinematic() )
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s : controller is not enabled.",triggerPhys->GetObjectKey()->GetName().c_str());
- return;
- }
-#endif // PHYSX_ONLY_TRIGGER_FROM_KINEMATIC
- }
-#ifndef PHYSX_ONLY_TRIGGER_FROM_KINEMATIC // if triggering only kinematics, then all should trigger
- else
- {
- // only suppress kinematic collision 'enters' when disabled but let 'exits' continue
- // ...this is because there are detector regions that are on the edge on ladders that the exit gets missed.
- if ( !controller->IsKinematic() /*&& (status & NX_TRIGGER_ON_ENTER) */ )
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s : kinematic is not enabled.",triggerPhys->GetObjectKey()->GetName().c_str());
- return;
- }
- }
-#endif // PHYSX_ONLY_TRIGGER_FROM_KINEMATIC
otherKey = controller->GetOwner();
doReport = triggerPhys->DoReportOn(plSimDefs::kGroupAvatar);
- if (plSimulationMgr::fExtraProfile )
- {
- if (!doReport)
- {
- DetectorLogRed("<--Kill collision %s :failed group. US=%x OTHER=(NotAvatar)",triggerPhys->GetObjectKey()->GetName().c_str(),triggerPhys->GetGroup());
- }
- else
- {
- hsPoint3 avpos;
- controller->GetPositionSim(avpos);
- DetectorLogRed("-->Avatar at (%f,%f,%f)",avpos.fX,avpos.fY,avpos.fZ);
- }
- }
}
}
@@ -289,8 +235,8 @@ class ErrorStream : public NxUserOutputStream
//
/////////////////////////////////////////////////////////////////
-#define kDefaultMaxDelta 0.1 // if the step is greater than .1 seconds, clamp to that
-#define kDefaultStepSize 1.f / 60.f // default simulation freqency is 60hz
+#define kDefaultMaxDelta (0.1) // if the step is greater than .1 seconds, clamp to that
+#define kDefaultStepSize (1.f / 60.f) // default simulation freqency is 60hz
/////////////////////////////////////////////////////////////////
//
@@ -378,6 +324,7 @@ plSimulationMgr* plSimulationMgr::GetInstance()
plSimulationMgr::plSimulationMgr()
: fSuspended(true)
+ , fAccumulator(0.0f)
, fLOSDispatch(new plLOSDispatch())
, fSoundMgr(new plPhysicsSoundMgr)
, fLog(nil)
@@ -470,6 +417,7 @@ NxScene* plSimulationMgr::GetScene(plKey world)
scene->setGroupCollisionFlag(i, plSimDefs::kGroupDynamicBlocker, false);
scene->setGroupCollisionFlag(i, plSimDefs::kGroupLOSOnly, false);
scene->setGroupCollisionFlag(plSimDefs::kGroupLOSOnly, i, false);
+ scene->setGroupCollisionFlag(i, plSimDefs::kGroupAvatarKinematic, false);
}
scene->setGroupCollisionFlag(plSimDefs::kGroupAvatar, plSimDefs::kGroupAvatar, false);
scene->setGroupCollisionFlag(plSimDefs::kGroupAvatar, plSimDefs::kGroupAvatarBlocker, true);
@@ -477,7 +425,11 @@ NxScene* plSimulationMgr::GetScene(plKey world)
scene->setGroupCollisionFlag(plSimDefs::kGroupAvatar, plSimDefs::kGroupStatic, true);
scene->setGroupCollisionFlag( plSimDefs::kGroupStatic, plSimDefs::kGroupAvatar, true);
scene->setGroupCollisionFlag(plSimDefs::kGroupAvatar, plSimDefs::kGroupDynamic, true);
-
+
+ // Kinematically controlled avatars interact with detectors and dynamics
+ scene->setGroupCollisionFlag(plSimDefs::kGroupAvatarKinematic, plSimDefs::kGroupDetector, true);
+ scene->setGroupCollisionFlag(plSimDefs::kGroupAvatarKinematic, plSimDefs::kGroupDynamic, true);
+
// The dynamics are in actor group 1, everything else is in 0. Request
// a callback for whenever a dynamic touches something.
scene->setActorGroupPairFlags(0, 1, NX_NOTIFY_ON_TOUCH);
@@ -564,8 +516,7 @@ void plSimulationMgr::UpdateAvatarInDetector(plKey world, plPXPhysical* detector
if ( actors[i]->userData == nil )
{
// we go a controller
- bool isController;
- plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(*actors[i],&isController);
+ plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(*actors[i]);
if (controller && controller->IsEnabled())
{
plKey avatar = controller->GetOwner();
@@ -614,20 +565,39 @@ void plSimulationMgr::AddCollisionMsg(plKey hitee, plKey hitter, bool enter)
pMsg->fEntering = enter;
fCollideMsgs.push_back(pMsg);
}
+void plSimulationMgr::AddCollisionMsg(plCollideMsg* msg)
+{
+ fCollideMsgs.push_back(msg);
+}
void plSimulationMgr::Advance(float delSecs)
{
if (fSuspended)
return;
- plProfile_IncCount(StepLen, (int)(delSecs*1000));
+ fAccumulator += delSecs;
+ if (fAccumulator < kDefaultStepSize)
+ {
+ // Not enough time has passed to perform a substep.
+ plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / kDefaultStepSize);
+ return;
+ }
+ else if (fAccumulator > kDefaultMaxDelta)
+ {
+ if (fExtraProfile)
+ Log("Step clamped from %f to limit of %f", fAccumulator, kDefaultMaxDelta);
+ fAccumulator = kDefaultMaxDelta;
+ }
-#ifndef PLASMA_EXTERNAL_RELASE
- uint32_t stepTime = hsTimer::GetPrecTickCount();
-#endif
+ // Perform as many whole substeps as possible saving the remainder in our accumulator.
+ int numSubSteps = (int)(fAccumulator / kDefaultStepSize);
+ float delta = numSubSteps * kDefaultStepSize;
+ fAccumulator -= delta;
+
+ plProfile_IncCount(StepLen, (int)(delta*1000));
plProfile_BeginTiming(Step);
- plPXPhysicalControllerCore::UpdatePrestep(delSecs);
- plPXPhysicalControllerCore::UpdatePoststep( delSecs);
+
+ plPXPhysicalControllerCore::Apply(delta);
for (SceneMap::iterator it = fScenes.begin(); it != fScenes.end(); it++)
{
@@ -642,12 +612,13 @@ void plSimulationMgr::Advance(float delSecs)
}
if (do_advance)
{
- scene->simulate(delSecs);
+ scene->simulate(delta);
scene->flushStream();
scene->fetchResults(NX_RIGID_BODY_FINISHED, true);
}
}
- plPXPhysicalControllerCore::UpdatePostSimStep(delSecs);
+
+ plPXPhysicalControllerCore::Update(numSubSteps, fAccumulator / kDefaultStepSize);
plProfile_EndTiming(Step);
#ifndef PLASMA_EXTERNAL_RELEASE
@@ -730,9 +701,6 @@ void plSimulationMgr::ISendUpdates()
plPXPhysical* physical = (plPXPhysical*)actors[i]->userData;
if (physical)
{
- // apply any hit forces
- physical->ApplyHitForce();
-
if (physical->GetSceneNode())
{
physical->SendNewLocation();
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
index 2cf07d90..552ccbff 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
@@ -105,6 +105,7 @@ public:
//Fix to Move collision messages and their handling out of the simulation step
void AddCollisionMsg(plKey hitee, plKey hitter, bool entering);
+ void AddCollisionMsg(plCollideMsg* msg);
#ifndef PLASMA_EXTERNAL_RELEASE
static bool fDisplayAwakeActors;
@@ -144,6 +145,8 @@ protected:
// but nothing will move.
bool fSuspended;
+ float fAccumulator;
+
// A utility class to keep track of a request for a physical synchronization.
// These requests must pass a certain criteria (see the code for the latest)
// before they are actually either sent over the network or rejected.
diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h b/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h
index 81da4934..c22edd7f 100644
--- a/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h
+++ b/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h
@@ -68,8 +68,10 @@ namespace plSimDefs
kGroupLOSOnly,
//kExcludeRegion setting up so only blocks avatars and only when not in seek mode
kGroupExcludeRegion,
+ // A kinematic avatar only interacts with dynamics and detectors
+ kGroupAvatarKinematic,
// Just for error checking
- kGroupMax,
+ kGroupMax
};
/** Different types of line-of-sight requests. */