diff --git a/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp b/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp
index 024f6183..d893d216 100644
--- a/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp
+++ b/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp
@@ -57,7 +57,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAvatar/plAvatarMgr.h"
#include "plAvatar/plArmatureMod.h"
-#include "plAvatar/plAvCallbackAction.h"
+#include "plAvatar/plPhysicalControllerCore.h"
bool plListener::fPrintDbgInfo = false;
diff --git a/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp b/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp
index 1488eaf1..852490d3 100644
--- a/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp
+++ b/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp
@@ -63,7 +63,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "pnSceneObject/plSimulationInterface.h"
#include "plAvatar/plAvatarMgr.h"
#include "plAvatar/plArmatureMod.h"
-#include "plAvatar/plAvCallbackAction.h"
+#include "plAvatar/plPhysicalControllerCore.h"
// new stuff
diff --git a/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp b/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp
index 0fce342f..aafb26e2 100644
--- a/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp
+++ b/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp
@@ -554,7 +554,7 @@ bool pySceneObject::IsAvatar()
return false;
}
-#include "plAvatar/plAvCallbackAction.h"
+#include "plAvatar/plPhysicalControllerCore.h"
PyObject* pySceneObject::GetAvatarVelocity()
{
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/CMakeLists.txt b/Sources/Plasma/PubUtilLib/plAvatar/CMakeLists.txt
index c8b82c78..f687d1f1 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/CMakeLists.txt
+++ b/Sources/Plasma/PubUtilLib/plAvatar/CMakeLists.txt
@@ -15,7 +15,6 @@ set(plAvatar_SOURCES
plAGMasterSDLModifier.cpp
plAGModifier.cpp
plAnimStage.cpp
- plAntiGravAction.cpp
plArmatureEffects.cpp
plArmatureMod.cpp
plAvatarClothing.cpp
@@ -32,7 +31,6 @@ set(plAvatar_SOURCES
plAvBrainHuman.cpp
plAvBrainRideAnimatedPhysical.cpp
plAvBrainSwim.cpp
- plAvCallbackAction.cpp
plAvLadderModifier.cpp
plAvTaskBrain.cpp
plAvTaskSeek.cpp
@@ -60,7 +58,6 @@ set(plAvatar_HEADERS
plAGMasterSDLModifier.h
plAGModifier.h
plAnimStage.h
- plAntiGravAction.h
plArmatureEffects.h
plArmatureMod.h
plAvatarClothing.h
@@ -78,7 +75,6 @@ set(plAvatar_HEADERS
plAvBrainHuman.h
plAvBrainRideAnimatedPhysical.h
plAvBrainSwim.h
- plAvCallbackAction.h
plAvDefs.h
plAvLadderModifier.h
plAvTask.h
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp
index 3b158848..f5dc5ac5 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp
@@ -39,7 +39,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
-#include "plAvCallbackAction.h" // must be first: references havok new
// singular
#include "plAnimStage.h"
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.cpp
deleted file mode 100644
index d5b4da3c..00000000
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.cpp
+++ /dev/null
@@ -1,171 +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==*/
-#if 0
-// havok first
-#include
-#include
-
-#include "plAntiGravAction.h"
-
-#include "pnSceneObject/plSceneObject.h"
-#include "plHavok1/plHKPhysical.h"
-#include "plAvatar/plSwimRegion.h"
-#include "hsTimer.h"
-
-// This is meant to be a specific physicsAction for the swim behavior
-plAntiGravAction::plAntiGravAction(plHKPhysical *physical, plAGApplicator *rootApp) :
- plAnimatedCallbackAction(physical, rootApp),
- fOnGround(false),
- fBuoyancy(1.f),
- fSurfaceHeight(0.f),
- fCurrentRegion(nil),
- fHadContacts(false)
-{
-}
-
-plSimDefs::ActionType plAntiGravAction::GetType()
-{
- return plSimDefs::kAntiGravAction;
-}
-
-void plAntiGravAction::apply(Havok::Subspace &space, Havok::hkTime time)
-{
- double elapsed = time.asDouble() - getRefresh().asDouble();
- setRefresh(time);
-
- IAdjustBuoyancy();
- Havok::RigidBody *body = fPhysical->GetBody();
- float mass = body->getMass();
- Havok::Vector3 gravity = space.getGravity();
- Havok::Vector3 force = -gravity * (mass * fBuoyancy);
- body->applyForce(force);
-
- hsVector3 vel;
- fPhysical->GetLinearVelocitySim(vel);
- fAnimPosVel.fZ = vel.fZ;
-
- hsVector3 linCurrent(0.f, 0.f, 0.f);
- float angCurrent = 0.f;
- if (fCurrentRegion != nil)
- fCurrentRegion->GetCurrent(fPhysical, linCurrent, angCurrent, (float)elapsed);
-
- int numContacts = fPhysical->GetNumContacts();
- fHadContacts = (numContacts > 0);
-
- const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f);
- fOnGround = false;
- int i;
- for (i = 0; i < numContacts; i++)
- {
- const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i);
- float dotUp = straightUp.dot(contact->m_normal);
- if (dotUp > .5)
- {
- fOnGround = true;
- break;
- }
- }
-
- fPhysical->SetLinearVelocitySim(fAnimPosVel + linCurrent);
- fPhysical->SetAngularVelocitySim(hsVector3(0.f, 0.f, fAnimAngVel + fTurnStr + angCurrent));
-}
-
-void plAntiGravAction::SetSurface(plSwimRegionInterface *region, float surfaceHeight)
-{
- fCurrentRegion = region;
- if (region != nil)
- fSurfaceHeight = surfaceHeight;
-}
-
-void plAntiGravAction::IAdjustBuoyancy()
-{
- // "surface depth" refers to the depth our handle object should be below
- // the surface for the avatar to be "at the surface"
- static const float surfaceDepth = 4.0f;
- // 1.0 = neutral buoyancy
- // 0 = no buoyancy (normal gravity)
- // 2.0 = opposite of gravity, floating upwards
- static const float buoyancyAtSurface = 1.0f;
-
- if (fCurrentRegion == nil)
- {
- fBuoyancy = 0.f;
- return;
- }
-
- hsMatrix44 l2w, w2l;
- fPhysical->GetTransform(l2w, w2l);
- float depth = fSurfaceHeight - surfaceDepth - l2w.GetTranslate().fZ;
- if (depth < -1)
- fBuoyancy = 0.f; // Same as being above ground. Plain old gravity.
- else if (depth < 0)
- fBuoyancy = 1 + depth;
- else
- {
- hsVector3 vel;
- fPhysical->GetLinearVelocitySim(vel);
- if (vel.fZ > 0)
- {
- if (vel.fZ > fCurrentRegion->fMaxUpwardVel)
- {
- vel.fZ = fCurrentRegion->fMaxUpwardVel;
- fPhysical->SetLinearVelocitySim(vel);
- }
- else
- {
- if (depth > 1)
- fBuoyancy = fCurrentRegion->fUpBuoyancy;
- else
- fBuoyancy = (fCurrentRegion->fUpBuoyancy - 1) * depth + 1;
- }
- }
- else
- {
- if (depth > 1)
- fBuoyancy = fCurrentRegion->fDownBuoyancy;
- else
- fBuoyancy = (fCurrentRegion->fDownBuoyancy - 1) * depth + 1;
- }
- }
-}
-
-#endif
\ No newline at end of file
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.h b/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.h
deleted file mode 100644
index ee4049ab..00000000
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.h
+++ /dev/null
@@ -1,79 +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==*/
-#if 0//ndef PL_ANTI_GRAV_ACTION_H
-#define PL_ANTI_GRAV_ACTION_H
-
-#include "plAvCallbackAction.h"
-
-class plSwimRegionInterface;
-
-class plAntiGravAction : public plAnimatedCallbackAction
-{
-public:
- plAntiGravAction(plHKPhysical *physical, plAGApplicator *rootApp);
-
- /** Return the type of the action as defined in the enum plSimDefs::ActionType.
- Used to retrieve actions by entity/type indexing, and to
- reuse actions that can be shared between entities. */
- virtual plSimDefs::ActionType GetType();
-
- /** Called by Havok at substep frequency. */
- void apply(Havok::Subspace &s, Havok::hkTime time);
-
- void SetSurface(plSwimRegionInterface *region, float surfaceHeight);
- float GetBuoyancy() { return fBuoyancy; }
- bool IsOnGround() { return fOnGround; }
- bool HadContacts() { return fHadContacts; }
-
-protected:
- void IAdjustBuoyancy();
-
- bool fOnGround;
- bool fHadContacts;
- float fBuoyancy;
- float fSurfaceHeight;
- plSwimRegionInterface *fCurrentRegion;
-};
-
-#endif
-
-
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp
index 1d53edca..526710a7 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp
@@ -39,7 +39,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
-#include "plAvCallbackAction.h"
#include "plStatusLog/plStatusLog.h"
#include "plArmatureEffects.h"
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp
index 018ccb09..c1b5cbe1 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp
@@ -54,7 +54,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAvBrainHuman.h"
#include "plMatrixChannel.h"
#include "plAvatarTasks.h"
-#include "plAvCallbackAction.h"
+#include "plPhysicalControllerCore.h"
#include "plAvBrainCritter.h"
// global
@@ -534,8 +534,7 @@ void plArmatureModBase::EnablePhysics(bool status, uint16_t reason /* = kDisable
// i.e. normal enabled physical
void plArmatureModBase::EnablePhysicsKinematic(bool status)
{
- if (fController)
- fController->Kinematic(status);
+ EnablePhysics(!status, kDisableReasonKinematic);
}
void plArmatureModBase::EnableDrawing(bool status, uint16_t reason /* = kDisableReasonUnknown */)
@@ -1994,7 +1993,11 @@ bool plArmatureMod::ValidatePhysics()
return false;
if (!fController)
- fController = plPhysicalControllerCore::Create(GetTarget(0)->GetKey(), fPhysHeight, fPhysWidth);
+ {
+ // The kinematic actor is made taller if the avatar is human (male or female)
+ fController = plPhysicalControllerCore::Create(GetTarget(0)->GetKey(), fPhysHeight,
+ fPhysWidth, (fBodyType == kBoneBaseMale || fBodyType == kBoneBaseFemale));
+ }
if (fController)
{
@@ -2670,19 +2673,7 @@ void plArmatureMod::DumpToDebugDisplay(int &x, int &y, int lineHeight, char *str
debugTxt.DrawString(x, y, strBuf);
y += lineHeight;
- hsPoint3 kPos;
- const char *kinematic = "n.a.";
const char* frozen = "n.a.";
- if (fController)
- {
- fController->GetKinematicPosition(kPos);
- kinematic = fController->IsKinematic() ? "on" : "off";
- }
- sprintf(strBuf, "kinematc(world): %.2f, %.2f, %.2f Kinematic: %3s",
- kPos.fX, kPos.fY, kPos.fZ,kinematic);
- debugTxt.DrawString(x, y, strBuf);
- y += lineHeight;
-
if (fController)
frozen = fController->IsEnabled() ? "no" : "yes";
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h
index c771a7a8..4f2a69c4 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h
@@ -146,6 +146,7 @@ public:
kDisableReasonCCR = 0x0008,
kDisableReasonVehicle = 0x0010,
kDisableReasonGenericBrain = 0x0020,
+ kDisableReasonKinematic = 0x0040
};
void EnablePhysics(bool status, uint16_t reason = kDisableReasonUnknown);
void EnablePhysicsKinematic(bool status);
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp
index dcc7bfdb..71314a78 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp
@@ -40,7 +40,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
-#include "plAvCallbackAction.h"
+#include "plPhysicalControllerCore.h"
#include "plAvBrainCritter.h"
#include "plAvBrainHuman.h"
#include "plArmatureMod.h"
@@ -125,7 +125,7 @@ protected:
///////////////////////////////////////////////////////////////////////////////
-plAvBrainCritter::plAvBrainCritter(): fCallbackAction(nil), fCurMode(kIdle), fNextMode(kIdle), fFadingNextBehavior(true),
+plAvBrainCritter::plAvBrainCritter(): fWalkingStrategy(nil), fCurMode(kIdle), fNextMode(kIdle), fFadingNextBehavior(true),
fAvoidingAvatars(false), fFinalGoalPos(0, 0, 0), fImmediateGoalPos(0, 0, 0), fDotGoal(0),
fAngRight(0)
{
@@ -143,8 +143,8 @@ plAvBrainCritter::~plAvBrainCritter()
fBehaviors[i] = nil;
}
- delete fCallbackAction;
- fCallbackAction = nil;
+ delete fWalkingStrategy;
+ fWalkingStrategy = nil;
fUserBehaviors.clear();
fReceivers.clear();
@@ -167,8 +167,8 @@ bool plAvBrainCritter::Apply(double time, float elapsed)
IProcessBehavior(time, elapsed); // just continue with the currently running one
// update our controller to keep us turned and moving to where we want to go
- fCallbackAction->RecalcVelocity(time, time - elapsed);
- fCallbackAction->SetTurnStrength(IGetTurnStrength(time));
+ fWalkingStrategy->SetTurnStrength(IGetTurnStrength(time));
+ fWalkingStrategy->RecalcVelocity(time, elapsed);
return plArmatureBrain::Apply(time, elapsed);
}
@@ -188,13 +188,13 @@ void plAvBrainCritter::Activate(plArmatureModBase* avMod)
IInitBaseAnimations();
// create the controller if we haven't done so already
- if (!fCallbackAction)
+ if (!fWalkingStrategy)
{
plSceneObject* avObj = fArmature->GetTarget(0);
plAGModifier* agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
plPhysicalControllerCore* controller = avMod->GetController();
- fCallbackAction = new plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller);
- fCallbackAction->ActivateController();
+ fWalkingStrategy = new plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller);
+ controller->SetMovementStrategy(fWalkingStrategy);
}
// tell people that care that we are good to go
@@ -224,7 +224,7 @@ void plAvBrainCritter::Resume()
// fade in the idle
fNextMode = kIdle;
- fCallbackAction->Reset(false);
+ fWalkingStrategy->Reset(false);
plArmatureBrain::Resume();
}
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h
index 0615932e..561797be 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h
@@ -47,7 +47,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "pnKeyedObject/plKey.h"
class plArmatureMod;
-class plWalkingController;
+class plWalkingStrategy;
class plAIMsg;
class plAvBrainCritter : public plArmatureBrain
@@ -134,8 +134,6 @@ public:
virtual void DumpToDebugDisplay(int& x, int& y, int lineHeight, char* strBuf, plDebugText& debugTxt);
- plWalkingController* GetCallbackAction() {return fCallbackAction;}
-
// For the console
static bool fDrawDebug;
@@ -159,7 +157,7 @@ protected:
std::vector IAvatarsICanSee() const;
std::vector IAvatarsICanHear() const;
- plWalkingController* fCallbackAction;
+ plWalkingStrategy* fWalkingStrategy;
int fCurMode; // current behavior we are running
int fNextMode; // the next behavior to run (-1 if we aren't switching on next eval)
bool fFadingNextBehavior; // is the next behavior supposed to blend?
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp
index a3b2cacd..0712a2fa 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp
@@ -42,7 +42,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
// local includes
#include "plAvBrainDrive.h"
#include "plArmatureMod.h"
-#include "plAvCallbackAction.h"
// global includes
#include "hsTimer.h"
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp
index 24bb67ba..a014e977 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp
@@ -39,7 +39,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
-#include "plAvCallbackAction.h" // havok-contaminated file: must go first
// singular
#include "plAvBrainGeneric.h"
@@ -94,7 +93,6 @@ plAvBrainGeneric::plAvBrainGeneric()
fFadeIn(0.0f),
fFadeOut(0.0f),
fMoveMode(kMoveRelative),
- fCallbackAction(nil),
fBodyUsage(plAGAnim::kBodyUnknown)
{
}
@@ -122,7 +120,6 @@ plAvBrainGeneric::plAvBrainGeneric(plAnimStageVec *stages,
fFadeIn(fadeIn),
fFadeOut(fadeOut),
fMoveMode(moveMode),
- fCallbackAction(nil),
fBodyUsage(plAGAnim::kBodyUnknown)
{
}
@@ -141,7 +138,6 @@ plAvBrainGeneric::plAvBrainGeneric(uint32_t exitFlags, float fadeIn, float fadeO
fFadeIn(fadeIn),
fFadeOut(fadeOut),
fMoveMode(moveMode),
- fCallbackAction(nil),
fBodyUsage(plAGAnim::kBodyUnknown)
{
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h
index 4a719153..305074aa 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h
@@ -49,7 +49,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
class plAnimStage;
class plAnimStageVec;
class plAvBrainGenericMsg;
-class plHorizontalFreezeAction;
class plNotifyMsg;
/** \class plAvBrainGeneric
@@ -300,7 +299,6 @@ protected:
int fCurStage; // which stage are we playing? (zero-based)
BrainType fType; // what type of brain are we?
uint32_t fExitFlags; // what will cause us to exit?
- plHorizontalFreezeAction *fCallbackAction;
bool fForward; // are we currently moving forward or backward through the stages?
// this is used by the "auto-" movement types in the stages
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp
index fe7f4923..05422c7b 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp
@@ -40,9 +40,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
-#include "plAvCallbackAction.h" // subclasses a havok object; must be in first include section
#include "HeadSpin.h"
+#include "plPhysicalControllerCore.h"
#include "plAvBrainHuman.h"
#include "plAvBrainClimb.h"
#include "plAvBrainDrive.h"
@@ -140,7 +140,7 @@ plAvBrainHuman::TurnCurve plAvBrainHuman::GetTurnCurve(bool walk)
plAvBrainHuman::plAvBrainHuman(bool isActor /* = false */) :
fHandleAGMod(nil),
fStartedTurning(-1.0f),
- fCallbackAction(nil),
+ fWalkingStrategy(nil),
fPreconditions(0),
fIsActor(isActor)
{
@@ -154,9 +154,9 @@ bool plAvBrainHuman::Apply(double timeNow, float elapsed)
#endif
// SetTurnStrength runs first to make sure it's set to a sane value
// (or cleared). RunStandardBehaviors may overwrite it.
- fCallbackAction->SetTurnStrength(IGetTurnStrength(timeNow));
+ fWalkingStrategy->SetTurnStrength(IGetTurnStrength(timeNow));
RunStandardBehaviors(timeNow, elapsed);
- fCallbackAction->RecalcVelocity(timeNow, timeNow - elapsed, (fPreconditions & plHBehavior::kBehaviorTypeNeedsRecalcMask));
+ fWalkingStrategy->RecalcVelocity(timeNow, elapsed, (fPreconditions & plHBehavior::kBehaviorTypeNeedsRecalcMask));
plArmatureBrain::Apply(timeNow, elapsed);
#ifndef _DEBUG
@@ -177,13 +177,13 @@ void plAvBrainHuman::Activate(plArmatureModBase *avMod)
IInitBoneMap();
IInitAnimations();
- if (!fCallbackAction)
+ if (!fWalkingStrategy)
{
plSceneObject* avObj = fArmature->GetTarget(0);
plAGModifier* agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
plPhysicalControllerCore* controller = avMod->GetController();
- fCallbackAction = new plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller);
- fCallbackAction->ActivateController();
+ fWalkingStrategy = new plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller);
+ controller->SetMovementStrategy(fWalkingStrategy);
}
@@ -328,8 +328,8 @@ plAvBrainHuman::~plAvBrainHuman()
delete fBehaviors[i];
fBehaviors.Reset();
- delete fCallbackAction;
- fCallbackAction = nil;
+ delete fWalkingStrategy;
+ fWalkingStrategy = nil;
}
void plAvBrainHuman::Deactivate()
@@ -361,7 +361,7 @@ void plAvBrainHuman::Resume()
if (fAvMod->GetInputFlag(S_PUSH_TO_TALK))
IChatOn();
- fCallbackAction->Reset(false);
+ fWalkingStrategy->Reset(false);
plArmatureBrain::Resume();
}
@@ -465,25 +465,23 @@ bool plAvBrainHuman::MsgReceive(plMessage * msg)
{
if(ride->Entering())
{
- //plAvBrainRideAnimatedPhysical *rideBrain = new plAvBrainRideAnimatedPhysical();
- //fAvMod->PushBrain(rideBrain);
- delete fCallbackAction;
+ // Switch to dynamic walking strategy
+ delete fWalkingStrategy;
plSceneObject* avObj = fArmature->GetTarget(0);
plAGModifier* agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
plPhysicalControllerCore* controller = fAvMod->GetController();
- fCallbackAction= new plRidingAnimatedPhysicalController(avObj, agMod->GetApplicator(kAGPinTransform), controller);
- fCallbackAction->ActivateController();
-
+ fWalkingStrategy = new plDynamicWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller);
+ controller->SetMovementStrategy(fWalkingStrategy);
}
else
{
- delete fCallbackAction;
+ // Restore default walking strategy
+ delete fWalkingStrategy;
plSceneObject* avObj = fArmature->GetTarget(0);
plAGModifier* agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
plPhysicalControllerCore* controller = fAvMod->GetController();
- fCallbackAction= new plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller);
- fCallbackAction->ActivateController();
- //hsStatusMessage("Got an exiting ride animated physical message");
+ fWalkingStrategy = new plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller);
+ controller->SetMovementStrategy(fWalkingStrategy);
}
}
@@ -557,8 +555,8 @@ float plAvBrainHuman::IGetTurnStrength(double timeNow)
// Turning based on keypress
if ((turnLeftStrength > 0.f)
|| (turnRightStrength > 0.f)
- || (!fCallbackAction->IsOnGround()
- && !fCallbackAction->IsControlledFlight())
+ || (!fWalkingStrategy->IsOnGround()
+ && !fWalkingStrategy->IsControlledFlight())
) {
float t = (float)(timeNow - fStartedTurning);
float turnSpeed;
@@ -590,7 +588,7 @@ float plAvBrainHuman::IGetTurnStrength(double timeNow)
result += fAvMod->GetKeyTurnStrength() * turnSpeed;
}
- if (!fCallbackAction->IsControlledFlight())
+ if (!fWalkingStrategy->IsControlledFlight())
result += fAvMod->GetAnalogTurnStrength() * maxTurnSpeed;
return result;
@@ -647,7 +645,7 @@ void plAvBrainHuman::ResetIdle()
void plAvBrainHuman::IdleOnly(bool instantOff)
{
- if (!fCallbackAction)
+ if (!fWalkingStrategy)
return;
float rate = instantOff ? 0.f : 1.f;
@@ -673,7 +671,7 @@ bool plAvBrainHuman::IsMovementZeroBlend()
void plAvBrainHuman::TurnToPoint(hsPoint3 point)
{
- if (!fCallbackAction->IsOnGround() || IsRunningTask() || fAvMod->GetCurrentBrain() != this || !IsMovementZeroBlend())
+ if (!fWalkingStrategy->IsOnGround() || IsRunningTask() || fAvMod->GetCurrentBrain() != this || !IsMovementZeroBlend())
return;
hsPoint3 avPos;
@@ -869,23 +867,23 @@ void plAvBrainHuman::Spawn(double timeNow)
bool plAvBrainHuman::LeaveAge()
{
plPhysicalControllerCore* controller = fAvMod->GetController();
- if(!controller->BehavingLikeAnAnimatedPhysical())
+
+ // If our current walking strategy is dynamic, restore the default kinematic strategy.
+ if (!fWalkingStrategy->IsKinematic())
{
- controller->BehaveLikeAnimatedPhysical(true);
- delete fCallbackAction;
+ delete fWalkingStrategy;
plSceneObject* avObj = fArmature->GetTarget(0);
plAGModifier* agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
- fCallbackAction= new plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller);
- fCallbackAction->ActivateController();
+ fWalkingStrategy = new plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller);
}
+
+ fWalkingStrategy->Reset(true);
+
plArmatureBrain::LeaveAge();
-
-
// pin the physical so it doesn't fall when the world is deleted
fAvMod->EnablePhysics(false);
- // this will get set to true when we hit ground
- fCallbackAction->Reset(true);
+
return false;
}
@@ -895,11 +893,10 @@ void plAvBrainHuman::DumpToDebugDisplay(int &x, int &y, int lineHeight, char *st
debugTxt.DrawString(x, y, strBuf);
y += lineHeight;
- const char *grounded = fCallbackAction->IsOnGround() ? "yes" : "no";
- const char *falseGrounded = fCallbackAction->IsOnFalseGround() ? "yes" : "no";
- const char *pushing = (fCallbackAction->GetPushingPhysical() ? (fCallbackAction->GetFacingPushingPhysical() ? "facing" : "behind") : "none");
- sprintf(strBuf, "Ground: %3s, FalseGround: %3s, AirTime: %5.2f (Peak: %5.2f), PushingPhys: %6s",
- grounded, falseGrounded, fCallbackAction->GetAirTime(), fCallbackAction->GetImpactTime(), pushing);
+ const char *grounded = fWalkingStrategy->IsOnGround() ? "yes" : "no";
+ const char *pushing = (fWalkingStrategy->GetPushingPhysical() ? (fWalkingStrategy->GetFacingPushingPhysical() ? "facing" : "behind") : "none");
+ sprintf(strBuf, "Ground: %3s, AirTime: %5.2f (Peak: %5.2f), PushingPhys: %6s",
+ grounded, fWalkingStrategy->GetAirTime(), fWalkingStrategy->GetImpactTime(), pushing);
debugTxt.DrawString(x, y, strBuf);
y += lineHeight;
@@ -1012,8 +1009,8 @@ bool Run::PreCondition(double time, float elapsed)
{
if (fAnim)
{
- if (fAvMod->ForwardKeyDown() && fAvMod->FastKeyDown() && fHuBrain->fCallbackAction->IsOnGround() &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || !fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ if (fAvMod->ForwardKeyDown() && fAvMod->FastKeyDown() && fHuBrain->fWalkingStrategy->IsOnGround() &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || !fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
return true;
}
return false;
@@ -1023,8 +1020,8 @@ bool Walk::PreCondition(double time, float elapsed)
{
if (fAnim)
{
- if (fAvMod->ForwardKeyDown() && !fAvMod->FastKeyDown() && fHuBrain->fCallbackAction->IsOnGround() &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || !fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ if (fAvMod->ForwardKeyDown() && !fAvMod->FastKeyDown() && fHuBrain->fWalkingStrategy->IsOnGround() &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || !fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
return true;
}
return false;
@@ -1034,8 +1031,8 @@ bool WalkBack::PreCondition(double time, float elapsed)
{
if (fAnim)
{
- if (fAvMod->BackwardKeyDown() && !fAvMod->ForwardKeyDown() && fHuBrain->fCallbackAction->IsOnGround() &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ if (fAvMod->BackwardKeyDown() && !fAvMod->ForwardKeyDown() && fHuBrain->fWalkingStrategy->IsOnGround() &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
return true;
}
return false;
@@ -1048,7 +1045,7 @@ bool StepLeft::PreCondition(double time, float elapsed)
return ((fAvMod->StrafeLeftKeyDown() || (fAvMod->StrafeKeyDown() && fAvMod->TurnLeftKeyDown())) &&
!(fAvMod->StrafeRightKeyDown() || (fAvMod->StrafeKeyDown() && fAvMod->TurnRightKeyDown())) &&
!(fAvMod->ForwardKeyDown() || fAvMod->BackwardKeyDown()) &&
- fHuBrain->fCallbackAction->IsOnGround());
+ fHuBrain->fWalkingStrategy->IsOnGround());
}
return false;
}
@@ -1060,7 +1057,7 @@ bool StepRight::PreCondition(double time, float elapsed)
return ((fAvMod->StrafeRightKeyDown() || (fAvMod->StrafeKeyDown() && fAvMod->TurnRightKeyDown())) &&
!(fAvMod->StrafeLeftKeyDown() || (fAvMod->StrafeKeyDown() && fAvMod->TurnLeftKeyDown())) &&
!(fAvMod->ForwardKeyDown() || fAvMod->BackwardKeyDown()) &&
- fHuBrain->fCallbackAction->IsOnGround());
+ fHuBrain->fWalkingStrategy->IsOnGround());
}
return false;
}
@@ -1101,8 +1098,8 @@ bool MovingTurnLeft::PreCondition(double time, float elapsed)
{
if (fAvMod->GetTurnStrength() > 0)
{
- if (fHuBrain->fCallbackAction->IsOnGround() && (fAvMod->ForwardKeyDown() || fAvMod->BackwardKeyDown()) &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || !fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ if (fHuBrain->fWalkingStrategy->IsOnGround() && (fAvMod->ForwardKeyDown() || fAvMod->BackwardKeyDown()) &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || !fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
return true;
}
return false;
@@ -1112,8 +1109,8 @@ bool MovingTurnRight::PreCondition(double time, float elapsed)
{
if (fAvMod->GetTurnStrength() < 0)
{
- if (fHuBrain->fCallbackAction->IsOnGround() && (fAvMod->ForwardKeyDown() || fAvMod->BackwardKeyDown()) &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || !fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ if (fHuBrain->fWalkingStrategy->IsOnGround() && (fAvMod->ForwardKeyDown() || fAvMod->BackwardKeyDown()) &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || !fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
return true;
}
@@ -1122,14 +1119,14 @@ bool MovingTurnRight::PreCondition(double time, float elapsed)
void Jump::IStart()
{
- fHuBrain->fCallbackAction->EnableControlledFlight(true);
+ fHuBrain->fWalkingStrategy->EnableControlledFlight(true);
plHBehavior::IStart();
}
void Jump::IStop()
{
- fHuBrain->fCallbackAction->EnableControlledFlight(false);
+ fHuBrain->fWalkingStrategy->EnableControlledFlight(false);
plHBehavior::IStop();
}
@@ -1140,7 +1137,7 @@ bool StandingJump::PreCondition(double time, float elapsed)
{
if (GetStrength() > 0.f)
{
- if (!fHuBrain->fCallbackAction->IsControlledFlight() ||
+ if (!fHuBrain->fWalkingStrategy->IsControlledFlight() ||
fAnim->GetTimeConvert()->WorldToAnimTimeNoUpdate(time) >= fAnim->GetTimeConvert()->GetEnd())
{
return false;
@@ -1152,7 +1149,7 @@ bool StandingJump::PreCondition(double time, float elapsed)
if (fAvMod->JumpKeyDown() &&
!fAvMod->ForwardKeyDown() &&
fAnim->GetBlend() == 0.0f &&
- fHuBrain->fCallbackAction->IsOnGround())
+ fHuBrain->fWalkingStrategy->IsOnGround())
{
if (fAvMod->ConsumeJump())
return true;
@@ -1168,7 +1165,7 @@ bool WalkingJump::PreCondition(double time, float elapsed)
{
if (GetStrength() > 0.f)
{
- if (!fHuBrain->fCallbackAction->IsControlledFlight() ||
+ if (!fHuBrain->fWalkingStrategy->IsControlledFlight() ||
fAnim->GetTimeConvert()->WorldToAnimTimeNoUpdate(time) >= fAnim->GetTimeConvert()->GetEnd())
{
return false;
@@ -1181,8 +1178,8 @@ bool WalkingJump::PreCondition(double time, float elapsed)
!fAvMod->FastKeyDown() &&
fAvMod->ForwardKeyDown() &&
fAnim->GetBlend() == 0.0f &&
- fHuBrain->fCallbackAction->IsOnGround() &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || !fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ fHuBrain->fWalkingStrategy->IsOnGround() &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || !fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
{
if (fAvMod->ConsumeJump())
return true;
@@ -1198,7 +1195,7 @@ bool RunningJump::PreCondition(double time, float elapsed)
{
if (GetStrength() > 0.f)
{
- if (!fHuBrain->fCallbackAction->IsControlledFlight() ||
+ if (!fHuBrain->fWalkingStrategy->IsControlledFlight() ||
fAnim->GetTimeConvert()->WorldToAnimTimeNoUpdate(time) >= fAnim->GetTimeConvert()->GetEnd())
{
return false;
@@ -1211,8 +1208,8 @@ bool RunningJump::PreCondition(double time, float elapsed)
fAvMod->ForwardKeyDown() &&
fAvMod->FastKeyDown() &&
fAnim->GetBlend() == 0.0f &&
- fHuBrain->fCallbackAction->IsOnGround() &&
- (!fHuBrain->fCallbackAction->GetPushingPhysical() || !fHuBrain->fCallbackAction->GetFacingPushingPhysical()))
+ fHuBrain->fWalkingStrategy->IsOnGround() &&
+ (!fHuBrain->fWalkingStrategy->GetPushingPhysical() || !fHuBrain->fWalkingStrategy->GetFacingPushingPhysical()))
{
if (fAvMod->ConsumeJump())
return true;
@@ -1237,13 +1234,13 @@ bool RunningImpact::PreCondition(double time, float elapsed)
{
if (fDuration > 0.0f)
fDuration = fDuration - elapsed;
- else if (fHuBrain->fCallbackAction->IsOnGround() && fHuBrain->fCallbackAction->GetImpactTime() > kMinAirTime)
+ else if (fHuBrain->fWalkingStrategy->IsOnGround() && fHuBrain->fWalkingStrategy->GetImpactTime() > kMinAirTime)
{
- if (fHuBrain->fCallbackAction->GetImpactVelocity().fZ < -kMinImpactVel)
+ if (fHuBrain->fWalkingStrategy->GetImpactVelocity().fZ < -kMinImpactVel)
{
- if (fHuBrain->fCallbackAction->GetImpactVelocity().fY < kRunningImpactThresh)
+ if (fHuBrain->fWalkingStrategy->GetImpactVelocity().fY < kRunningImpactThresh)
{
- fMaxBlend = 0.5f + (0.5f * (-fHuBrain->fCallbackAction->GetImpactVelocity().fZ / (kFullImpactVel - kMinImpactVel)));
+ fMaxBlend = 0.5f + (0.5f * (-fHuBrain->fWalkingStrategy->GetImpactVelocity().fZ / (kFullImpactVel - kMinImpactVel)));
if (fMaxBlend > 1)
fMaxBlend = 1;
fDuration = 1.0f / fFadeIn;
@@ -1267,13 +1264,13 @@ bool GroundImpact::PreCondition(double time, float elapsed)
bool result = false;
if (fDuration > 0.0f)
fDuration = fDuration - elapsed;
- else if (fHuBrain->fCallbackAction->IsOnGround() && fHuBrain->fCallbackAction->GetImpactTime() > kMinAirTime)
+ else if (fHuBrain->fWalkingStrategy->IsOnGround() && fHuBrain->fWalkingStrategy->GetImpactTime() > kMinAirTime)
{
- if (fHuBrain->fCallbackAction->GetImpactVelocity().fZ < -kMinImpactVel)
+ if (fHuBrain->fWalkingStrategy->GetImpactVelocity().fZ < -kMinImpactVel)
{
- if (fHuBrain->fCallbackAction->GetImpactVelocity().fY >= kRunningImpactThresh)
+ if (fHuBrain->fWalkingStrategy->GetImpactVelocity().fY >= kRunningImpactThresh)
{
- fMaxBlend = 0.5f + (0.5f * (-fHuBrain->fCallbackAction->GetImpactVelocity().fZ / (kFullImpactVel - kMinImpactVel)));
+ fMaxBlend = 0.5f + (0.5f * (-fHuBrain->fWalkingStrategy->GetImpactVelocity().fZ / (kFullImpactVel - kMinImpactVel)));
if (fMaxBlend > 1)
fMaxBlend = 1;
fDuration = 1.0f / fFadeIn;
@@ -1292,7 +1289,7 @@ void GroundImpact::IStop()
bool Fall::PreCondition(double time, float elapsed)
{
- return !fHuBrain->fCallbackAction->IsOnGround() && fHuBrain->fCallbackAction->HitGroundInThisAge();
+ return !fHuBrain->fWalkingStrategy->IsOnGround() && fHuBrain->fWalkingStrategy->HitGroundInThisAge();
}
void Fall::Process(double time, float elapsed)
@@ -1304,7 +1301,7 @@ void Fall::Process(double time, float elapsed)
if (fAnim && fAnim->GetBlend() > 0.8)
{
float panicThresh = plAvBrainHuman::kAirTimePanicThreshold;
- if (panicThresh > 0.0f && fHuBrain->fCallbackAction->GetAirTime() > panicThresh)
+ if (panicThresh > 0.0f && fHuBrain->fWalkingStrategy->GetAirTime() > panicThresh)
{
fHuBrain->IdleOnly(); // clear the fall state; we're going somewhere new
fAvMod->PanicLink();
@@ -1321,7 +1318,7 @@ void Push::Process(double time, float elapsed)
fAvMod->GetPositionAndRotationSim(&pos, &rot);
hsPoint3 lookAt;
- fHuBrain->fCallbackAction->GetPushingPhysical()->GetPositionSim(lookAt);
+ fHuBrain->fWalkingStrategy->GetPushingPhysical()->GetPositionSim(lookAt);
hsVector3 up(0.f, 0.f, 1.f);
float angle = atan2(lookAt.fY - pos.fY, lookAt.fX - pos.fX) + M_PI / 2;
hsQuat targRot(angle, &up);
@@ -1335,23 +1332,23 @@ void Push::Process(double time, float elapsed)
globFwd = rot.Rotate(&globFwd);
if (globFwd.fX < 0)
- fHuBrain->fCallbackAction->SetTurnStrength(-turnSpeed);
+ fHuBrain->fWalkingStrategy->SetTurnStrength(-turnSpeed);
else
- fHuBrain->fCallbackAction->SetTurnStrength(turnSpeed);
+ fHuBrain->fWalkingStrategy->SetTurnStrength(turnSpeed);
}
//bool PushIdle::PreCondition(double time, float elapsed)
//{
-// return (fHuBrain->fCallbackAction->GetPushingPhysical() &&
-// fHuBrain->fCallbackAction->IsOnGround() &&
+// return (fHuBrain->fWalkingStrategy->GetPushingPhysical() &&
+// fHuBrain->fWalkingStrategy->IsOnGround() &&
// !fAvMod->TurnLeftKeyDown() && !fAvMod->TurnRightKeyDown()
// && fAvMod->GetTurnStrength() == 0);
//}
bool PushWalk::PreCondition(double time, float elapsed)
{
- return (fHuBrain->fCallbackAction->GetPushingPhysical() && fHuBrain->fCallbackAction->GetFacingPushingPhysical() &&
- fHuBrain->fCallbackAction->IsOnGround() &&
+ return (fHuBrain->fWalkingStrategy->GetPushingPhysical() && fHuBrain->fWalkingStrategy->GetFacingPushingPhysical() &&
+ fHuBrain->fWalkingStrategy->IsOnGround() &&
fAvMod->ForwardKeyDown());
}
@@ -1366,7 +1363,7 @@ bool PushSimpleMultiStage(plArmatureMod *avatar, const char *enterAnim, const ch
{
plAvBrainHuman *huBrain = plAvBrainHuman::ConvertNoRef(avatar->FindBrainByClass(plAvBrainHuman::Index()));
const char *names[3] = {enterAnim, idleAnim, exitAnim};
- if (!huBrain || !huBrain->fCallbackAction->IsOnGround() || !huBrain->fCallbackAction->HitGroundInThisAge() || huBrain->IsRunningTask() ||
+ if (!huBrain || !huBrain->fWalkingStrategy->IsOnGround() || !huBrain->fWalkingStrategy->HitGroundInThisAge() || huBrain->IsRunningTask() ||
!avatar->IsPhysicsEnabled() || avatar->FindMatchingGenericBrain(names, 3))
return false;
@@ -1429,7 +1426,7 @@ bool AvatarEmote(plArmatureMod *avatar, const char *emoteName)
if (swimBrain && swimBrain->IsSwimming())
return false;
- if (huBrain && huBrain->fCallbackAction->IsOnGround() && huBrain->fCallbackAction->HitGroundInThisAge() && !huBrain->IsRunningTask() &&
+ if (huBrain && huBrain->fWalkingStrategy->IsOnGround() && huBrain->fWalkingStrategy->HitGroundInThisAge() && !huBrain->IsRunningTask() &&
emote && !alreadyActive && avatar->IsPhysicsEnabled())
{
plKey avKey = avatar->GetKey();
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h
index 69a40717..158b89ab 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h
@@ -58,7 +58,7 @@ class plAGAnimInstance;
class plAvTask;
class plAvTaskMsg;
class plAvBrainHuman;
-class plWalkingController;
+class plWalkingStrategy;
class plArmatureUpdateMsg;
class plClimbMsg;
class plControlEventMsg;
@@ -164,7 +164,7 @@ public:
static const float kControlledFlightThreshold;
static const float kAirTimeThreshold;
static const float kAirTimePanicThreshold;
- plWalkingController* fCallbackAction;
+ plWalkingStrategy* fWalkingStrategy;
protected:
plAGAnim *FindCustomAnim(const char *baseName);
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp
index d07ce063..4bf9661c 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp
@@ -44,7 +44,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAvBrainHuman.h"
#include "plAvBrain.h"
-#include "plAvCallbackAction.h"
+#include "plPhysicalControllerCore.h"
#include "plMessage/plRideAnimatedPhysMsg.h"
@@ -52,20 +52,19 @@ void plAvBrainRideAnimatedPhysical::Activate(plArmatureModBase *avMod)
{
plArmatureBrain::Activate(avMod);
IInitAnimations();
- if (!fCallbackAction)
+ if (!fWalkingStrategy)
{
plSceneObject* avObj = fArmature->GetTarget(0);
plAGModifier* agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
plPhysicalControllerCore* controller = avMod->GetController();
- fCallbackAction = new plRidingAnimatedPhysicalController(avObj, agMod->GetApplicator(kAGPinTransform), controller);
- fCallbackAction->ActivateController();
+ fWalkingStrategy = new plDynamicWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller);
+ controller->SetMovementStrategy(fWalkingStrategy);
}
}
plAvBrainRideAnimatedPhysical::~plAvBrainRideAnimatedPhysical()
{
- delete fCallbackAction;
- fCallbackAction=nil;
-
+ delete fWalkingStrategy;
+ fWalkingStrategy = nil;
}
void plAvBrainRideAnimatedPhysical::Deactivate()
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h
index c1c3f578..b5e923a1 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h
@@ -41,8 +41,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
#include "plAvBrainHuman.h"
-class plRidingAnimatedPhysicalController;
-
class plAvBrainRideAnimatedPhysical : public plAvBrainHuman
{
public:
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp
index b447d820..9046f298 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp
@@ -46,10 +46,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
//
/////////////////////////////////////////////////////////////////////////////////////////
-//#include
-//#include
-#include "plAntiGravAction.h" // descends from Havok class, so must be included first, like havok objects
-
// singular
#include "plAvBrainSwim.h"
@@ -69,7 +65,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "hsTimer.h"
#include "plPhysical.h"
#include "plPhysicalControllerCore.h"
-#include "plAvCallbackAction.h"
// other
#include "plPhysical/plCollisionDetector.h"
#include "plPipeline/plDebugText.h"
@@ -180,18 +175,16 @@ public:
static const float timeToMaxTurn = 0.5f;
static const float incPerSec = maxTurnSpeed / timeToMaxTurn;
-// hsAssert(0, "fixme physx");
- float oldSpeed = fabs(fSwimBrain->fCallbackAction->GetTurnStrength());
+ float oldSpeed = fabs(fSwimBrain->fSwimStrategy->GetTurnStrength());
float thisInc = elapsed * incPerSec;
float newSpeed = min(oldSpeed + thisInc, maxTurnSpeed);
- fSwimBrain->fCallbackAction->SetTurnStrength(newSpeed * fAvMod->GetKeyTurnStrength() + fAvMod->GetAnalogTurnStrength());
+ fSwimBrain->fSwimStrategy->SetTurnStrength(newSpeed * fAvMod->GetKeyTurnStrength() + fAvMod->GetAnalogTurnStrength());
// the turn is actually applied during PhysicsUpdate
}
virtual void IStop()
{
-// hsAssert(0, "fixme physx");
- if (fSwimBrain->fCallbackAction)
- fSwimBrain->fCallbackAction->SetTurnStrength(0.0f);
+ if (fSwimBrain->fSwimStrategy)
+ fSwimBrain->fSwimStrategy->SetTurnStrength(0.0f);
plSwimBehavior::IStop();
}
};
@@ -237,7 +230,7 @@ public:
const float plAvBrainSwim::kMinSwimDepth = 4.0f;
plAvBrainSwim::plAvBrainSwim() :
- fCallbackAction(nil),
+ fSwimStrategy(nil),
fMode(kWalking),
fSurfaceDistance(0.f)
{
@@ -250,12 +243,9 @@ plAvBrainSwim::plAvBrainSwim() :
plAvBrainSwim::~plAvBrainSwim()
{
- if(fCallbackAction)
- {
- IDetachAction();
- delete fCallbackAction;
- fCallbackAction=nil;
- }
+ delete fSwimStrategy;
+ fSwimStrategy = nil;
+
fSurfaceProbeMsg->UnRef();
int i;
@@ -273,8 +263,7 @@ bool plAvBrainSwim::Apply(double time, float elapsed)
fMode = kWading;
plAvBrainHuman *huBrain = plAvBrainHuman::ConvertNoRef(fAvMod->GetNextBrain(this));
-// hsAssert(0, "fixme physx");
- if (huBrain && !huBrain->fCallbackAction->IsOnGround())
+ if (huBrain && !huBrain->fWalkingStrategy->IsOnGround())
{
// We're jumping in! Trigger splash effect (sound)
plArmatureEffectMsg *msg = new plArmatureEffectMsg(fAvMod->GetArmatureEffects()->GetKey(), kTime);
@@ -318,8 +307,7 @@ bool plAvBrainSwim::Apply(double time, float elapsed)
// The contact check is so that if buoyancy bobs us a little too high, we don't
// switch to wading only to fall again.
-// hsAssert(0, "fixme physx");
- if (fSurfaceDistance < kMinSwimDepth-.5 && fCallbackAction->HadContacts())
+ if (fSurfaceDistance < kMinSwimDepth-.5 && fSwimStrategy->HadContacts())
IStartWading();
}
else if (fMode == kSwimming3D)
@@ -346,13 +334,12 @@ bool plAvBrainSwim::MsgReceive(plMessage *msg)
else
fSurfaceDistance = -100.f;
-// hsAssert(0, "fixme physx");
- if (fCallbackAction)
+ if (fSwimStrategy)
{
if (region)
- fCallbackAction->SetSurface(region, fArmature->GetTarget(0)->GetLocalToWorld().GetTranslate().fZ + fSurfaceDistance);
+ fSwimStrategy->SetSurface(region, fArmature->GetTarget(0)->GetLocalToWorld().GetTranslate().fZ + fSurfaceDistance);
else
- fCallbackAction->SetSurface(nil, 0.f);
+ fSwimStrategy->SetSurface(nil, 0.f);
}
return true;
}
@@ -419,20 +406,16 @@ void plAvBrainSwim::Activate(plArmatureModBase* avMod)
void plAvBrainSwim::Deactivate()
{
plArmatureBrain::Deactivate();
-
- IDetachAction();
}
void plAvBrainSwim::Suspend()
{
- if (fMode == kSwimming2D)
- IDetachAction();
}
void plAvBrainSwim::Resume()
{
if (fMode == kSwimming2D)
- IAttachAction();
+ fSwimStrategy->Reset(false);
}
bool plAvBrainSwim::IsWalking()
@@ -460,8 +443,6 @@ void plAvBrainSwim::IStartWading()
for (i = 0; i < fBehaviors.GetCount(); i++)
fBehaviors[i]->SetStrength(0.f, 2.f);
- IDetachAction();
-
if (fAvMod->IsLocalAvatar())
{
plCameraMsg* pMsg = new plCameraMsg;
@@ -479,7 +460,16 @@ void plAvBrainSwim::IStartSwimming(bool is2D)
plArmatureBrain *nextBrain = fAvMod->GetNextBrain(this);
nextBrain->Suspend();
- IAttachAction();
+ if (!fSwimStrategy)
+ {
+ plSceneObject * avObj = fArmature->GetTarget(0);
+ plAGModifier *agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
+ plPhysicalControllerCore *controller = fAvMod->GetController();
+ fSwimStrategy = new plSwimStrategy(agMod->GetApplicator(kAGPinTransform), controller);
+ }
+
+ fSwimStrategy->Reset(false);
+
if (is2D)
fMode = kSwimming2D;
else
@@ -509,8 +499,8 @@ bool plAvBrainSwim::IProcessSwimming2D(double time, float elapsed)
else
behavior->SetStrength(0.f, 2.f);
}
-// hsAssert(0, "fixme physx");
- fCallbackAction->RecalcVelocity(time, time - elapsed);
+
+ fSwimStrategy->RecalcVelocity(time, elapsed);
return true;
}
@@ -568,59 +558,6 @@ bool plAvBrainSwim::IInitAnimations()
return true;
}
-bool plAvBrainSwim::IAttachAction()
-{
- bool result = false;
- if(fAvMod)
- {
-// hsAssert(0, "fixme physx");
- plPhysicalControllerCore *physical = fAvMod->GetController();
-
- if (physical)
- {
- if (!fCallbackAction)
- {
- plSceneObject * avObj = fArmature->GetTarget(0);
- plAGModifier *agMod = const_cast(plAGModifier::ConvertNoRef(FindModifierByClass(avObj, plAGModifier::Index())));
- fCallbackAction = new plSwimmingController(avObj, agMod->GetApplicator(kAGPinTransform),physical);
-// physical->AttachAction(fCallbackAction, true, false);
- result = true;
- }
- else
- {
- fCallbackAction->ActivateController();
- }
-
- }
- }
- return result;
-}
-
-bool plAvBrainSwim::IDetachAction()
-{
- bool result = false;
-
- if (fCallbackAction)
- {
-// hsAssert(0, "fixme physx");
-// plPhysical *physical = fAvMod->GetPhysical();
-//
-// if(physical)
-// {
-// physical->RemoveAction(fCallbackAction);
-// result = true; // there was an action and we removed it
-// }
-
- // TODO: We get a compiler warning about deleting a pointer to an
- // undefined class. So, who knows what the code is actually doing.
- // Seems bad. Just putting a note in here for whoever fixes the
- // physx issue.
- //delete fCallbackAction;
- //fCallbackAction = nil;
- }
- return result;
-}
-
void plAvBrainSwim::IProbeSurface()
{
hsPoint3 ourPos = fAvMod->GetTarget(0)->GetLocalToWorld().GetTranslate();
@@ -676,21 +613,15 @@ void plAvBrainSwim::DumpToDebugDisplay(int &x, int &y, int lineHeight, char *str
debugTxt.DrawString(x, y, strBuf);
y += lineHeight;
+ float buoy = fSwimStrategy ? fSwimStrategy->GetBuoyancy() : 0.0f;
+ sprintf(strBuf, "Distance to surface: %f Buoyancy: %f", fSurfaceDistance, buoy);
+ debugTxt.DrawString(x, y, strBuf);
+ y += lineHeight;
-// hsAssert(0, "fixme physx");
-// float buoy = fCallbackAction? fCallbackAction->GetBuoyancy() : 0.0f;
-// sprintf(strBuf, "Distance to surface: %f Buoyancy: %f", fSurfaceDistance, buoy);
-// debugTxt.DrawString(x, y, strBuf);
-// y += lineHeight;
-//
-// hsVector3 linV;
-// fAvMod->GetPhysical()->GetLinearVelocitySim(linV);
-// hsVector3 angV;
-// fAvMod->GetPhysical()->GetAngularVelocitySim(angV);
-// float angle = angV.fZ > 0 ? angV.Magnitude() : -angV.Magnitude();
-// sprintf(strBuf, "Velocity: Linear (%5.2f, %5.2f, %5.2f), Angular %5.2f", linV.fX, linV.fY, linV.fZ, angle);
-// debugTxt.DrawString(x, y, strBuf);
-// y += lineHeight;
+ hsVector3 linV = fAvMod->GetController()->GetAchievedLinearVelocity();
+ sprintf(strBuf, "Linear Velocity: (%5.2f, %5.2f, %5.2f)", linV.fX, linV.fY, linV.fZ);
+ debugTxt.DrawString(x, y, strBuf);
+ y += lineHeight;
int i;
for (i = 0; i < fBehaviors.GetCount(); i++)
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h
index d3eec23d..6de11ee9 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h
@@ -51,7 +51,7 @@ class plAntiGravAction;
class plControlEventMsg;
class plLOSRequestMsg;
class plSwimRegionInterface;
-class plSwimmingController;
+class plSwimStrategy;
class plAvBrainSwim : public plArmatureBrain
{
public:
@@ -73,7 +73,7 @@ public:
bool IsSwimming();
float GetSurfaceDistance() { return fSurfaceDistance; }
- plSwimmingController *fCallbackAction;
+ plSwimStrategy *fSwimStrategy;
static const float kMinSwimDepth;
protected:
@@ -86,8 +86,6 @@ protected:
bool IProcessBehaviors(double time, float elapsed);
virtual bool IInitAnimations();
- bool IAttachAction();
- bool IDetachAction();
void IProbeSurface();
bool IHandleControlMsg(plControlEventMsg* msg);
float IGetTargetZ();
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp
deleted file mode 100644
index 76e22f5f..00000000
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp
+++ /dev/null
@@ -1,579 +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 "plAvCallbackAction.h"
-#include "plMessage/plLOSHitMsg.h"
-
-#include "plArmatureMod.h" // for LOS enum type
-#include "plMatrixChannel.h"
-#include "hsTimer.h"
-#include "plPhysicalControllerCore.h"
-
-// Generic geom utils.
-static bool LinearVelocity(hsVector3 &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat);
-static void AngularVelocity(float &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat);
-static float AngleRad2d (float x1, float y1, float x3, float y3);
-inline hsVector3 GetYAxis(hsMatrix44 &mat)
-{
- return hsVector3(mat.fMap[1][0], mat.fMap[1][1], mat.fMap[1][2]);
-}
-
-plAnimatedController::plAnimatedController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller)
- : fRootObject(rootObject)
- , fRootApp(rootApp)
- , fController(controller)
- , fTurnStr(0.f)
- , fAnimAngVel(0.f)
- , fAnimPosVel(0.f, 0.f, 0.f)
-{
-}
-
-void plAnimatedController::RecalcVelocity(double timeNow, double timePrev, bool useAnim /* = true */)
-{
- if (useAnim)
- {
- // while you may think it would be correct to cache this,
- // what we're actually asking is "what would the animation's
- // position be at the previous time given its *current*
- // parameters (particularly blends)"
- hsMatrix44 prevMat = ((plMatrixChannel *)fRootApp->GetChannel())->Value(timePrev, true);
- hsMatrix44 curMat = ((plMatrixChannel *)fRootApp->GetChannel())->Value(timeNow, true);
-
- // If we get a valid linear velocity (ie, we didn't wrap around in the anim),
- // use it. Otherwise just reuse the previous frames velocity.
- hsVector3 linearVel;
- if (LinearVelocity(linearVel, (float)(timeNow - timePrev), prevMat, curMat))
- fAnimPosVel = linearVel;
-
- // Automatically sets fAnimAngVel
- AngularVelocity(fAnimAngVel, (float)(timeNow - timePrev), prevMat, curMat);
- }
- else
- {
- fAnimPosVel.Set(0.f, 0.f, 0.f);
- fAnimAngVel = 0.f;
- }
-
- if (fController)
- fController->SetVelocities(fAnimPosVel, fAnimAngVel + fTurnStr);
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-const float plWalkingController::kControlledFlightThreshold = 1.f; // seconds
-
-plWalkingController::plWalkingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller)
- : plAnimatedController(rootObject, rootApp, controller)
- , fHitGroundInThisAge(false)
- , fWaitingForGround(false)
- , fControlledFlightTime(0)
- , fControlledFlight(0)
- , fImpactTime(0.f)
- , fImpactVelocity(0.f, 0.f, 0.f)
- , fClearImpact(false)
- , fGroundLastFrame(false)
-{
- if (fController)
- {
- fWalkingStrategy= new plWalkingStrategy(fController);
- fController->SetMovementSimulationInterface(fWalkingStrategy);
- }
- else
- fWalkingStrategy = nil;
-}
-
-void plWalkingController::RecalcVelocity(double timeNow, double timePrev, bool useAnim)
-{
- if (!fHitGroundInThisAge && fController && fController->IsEnabled() && fWalkingStrategy->IsOnGround())
- fHitGroundInThisAge = true; // if we're not pinned and we're not in an age yet, we are now.
-
- if (fClearImpact)
- {
- fImpactTime = 0.f;
- fImpactVelocity.Set(0.f, 0.f, 0.f);
- }
-
- if (fController && !fWalkingStrategy->IsOnGround())
- {
- // PhysX Hack: AchievedLinearVelocity is a Cyanic fix for superjumps. LinearVelocity is
- // always (0,0,0) outside of the controller update proc
- fImpactTime = fWalkingStrategy->GetAirTime();
- fImpactVelocity = fController->GetAchievedLinearVelocity();
- // convert orientation from subworld to avatar-local coordinates
- fImpactVelocity = (hsVector3)fController->GetLocalRotation().Rotate(&fImpactVelocity);
- fClearImpact = false;
- }
- else
- fClearImpact = true;
-
- if (IsControlledFlight())
- {
- if (fWalkingStrategy && fWalkingStrategy->IsOnGround())
- fControlledFlightTime = fWalkingStrategy->GetAirTime();
- if(fGroundLastFrame&&(fWalkingStrategy && !fWalkingStrategy->IsOnGround()))
- {
- //we have started to leave the ground tell the movement strategy in case it cares
- fWalkingStrategy->StartJump();
- }
- if (fControlledFlightTime > kControlledFlightThreshold)
- EnableControlledFlight(false);
- }
- if (fWalkingStrategy)
- fGroundLastFrame = fWalkingStrategy->IsOnGround();
- else
- fGroundLastFrame=false;
- plAnimatedController::RecalcVelocity(timeNow, timePrev, useAnim);
-}
-
-void plWalkingController::Reset(bool newAge)
-{
-
- ActivateController();
- if (newAge)
- {
- if (fWalkingStrategy)
- fWalkingStrategy->ResetAirTime();
- fHitGroundInThisAge = false;
- }
-}
- void plWalkingController::ActivateController()
-{
- if (fWalkingStrategy)
- {
- fWalkingStrategy->RefreshConnectionToControllerCore();
- }
- else
- {
- fWalkingStrategy= new plWalkingStrategy(fController);
- fWalkingStrategy->RefreshConnectionToControllerCore();
-
- }
-}
-
-bool plWalkingController::EnableControlledFlight(bool status)
-{
- if (status)
- {
- if (fControlledFlight == 0)
- fControlledFlightTime = 0.f;
-
- ++fControlledFlight;
- fWaitingForGround = true;
- }
- else
- fControlledFlight = max(--fControlledFlight, 0);
-
- return status;
-}
-plWalkingController::~plWalkingController()
-{
- delete fWalkingStrategy;
- if (fController)
- fController->SetMovementSimulationInterface(nil);
-}
-#if 0
-void plWalkingController::Update()
-{
-// double elapsed = time.asDouble() - getRefresh().asDouble();
-// setRefresh(time);
-//
-// bool isPhysical = !fPhysical->GetProperty(plSimulationInterface::kPinned);
-// const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f);
-// bool alreadyInAge = fHitGroundInThisAge;
-//
-// int numContacts = fPhysical->GetNumContacts();
-// bool ground = false;
-// fPushingPhysical = nil;
-// int i, j;
-
-/* for(i = 0; i < numContacts; i++)
- {
- plHKPhysical *contactPhys = fPhysical->GetContactPhysical(i);
- if (!contactPhys)
- continue; // Physical no longer exists. Skip it.
-
- const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i);
- float dotUp = straightUp.dot(contact->m_normal);
- if (dotUp > .5)
- ground = true;
- else if (contactPhys->GetProperty(plSimulationInterface::kAvAnimPushable))
- {
- hsPoint3 position;
- hsQuat rotation;
- fPhysical->GetPositionAndRotationSim(&position, &rotation);
-
- hsQuat inverseRotation = rotation.Inverse();
- hsVector3 normal(contact->m_normal.x, contact->m_normal.y, contact->m_normal.z);
- fFacingPushingPhysical = (inverseRotation.Rotate(&kAvatarForward).InnerProduct(normal) < 0 ? true : false);
-
- fPushingPhysical = contactPhys;
- }
- }
-
- // 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.
- const float threshold = hsDegreesToRadians(240);
- if (!ground && numContacts >= 2)
- {
- // Can probably do a special case for exactly 2 contacts. Not sure if it's worth it...
-
- fCollisionAngles.SetCount(numContacts);
- for (i = 0; i < numContacts; i++)
- {
- const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i);
- fCollisionAngles[i] = atan2(contact->m_normal.y, contact->m_normal.x);
- }
-
- // 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])
- {
- float 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 * M_PI)))
- ground = true;
- }
- }
-*/
-
- bool ground = fController ? fController->GotGroundHit() : true;
- bool isPhysical = true;
-
- if (!fHitGroundInThisAge && isPhysical)
- fHitGroundInThisAge = true; // if we're not pinned and we're not in an age yet, we are now.
-
- if (IsControlledFlight())
- fControlledFlightTime += (float)elapsed;
- if (fControlledFlightTime > kControlledFlightThreshold && numContacts > 0)
- EnableControlledFlight(false);
-
- if (ground || !isPhysical)
- {
- if (!IsControlledFlight() && !IsOnGround())
- {
- // The first ground contact in an age doesn't count.
-// if (alreadyInAge)
-// {
-// hsVector3 vel;
-// fPhysical->GetLinearVelocitySim(vel);
-// fImpactVel = vel.fZ;
-// fTimeInAirPeak = (float)(fTimeInAir + elapsed);
-// }
-
- fWaitingForGround = false;
- }
- fTimeInAir = 0;
- }
- else if (elapsed < plSimulationMgr::GetInstance()->GetMaxDelta())
- {
- // If the simultation skipped a huge chunk of time, we didn't process the
- // collisions, which could trick us into thinking we've just gone a long
- // time without hitting ground. So we only count the time if this wasn't
- // the case.
- fTimeInAir += (float)elapsed;
- }
-
-
- // Tweakage so that we still fall under the right conditions.
- // If we're in controlled flight, or standing still with ground solidly under us (probe hit). We only use anim velocity.
-// if (!IsControlledFlight() && !(ground && fProbeHitGround && fAnimPosVel.fX == 0 && fAnimPosVel.fY == 0))
-// {
-// hsVector3 curV;
-// fPhysical->GetLinearVelocitySim(curV);
-// fAnimPosVel.fZ = curV.fZ;
-//
-// // Prevents us from going airborn from running up bumps/inclines.
-// if (IsOnGround() && fAnimPosVel.fZ > 0.f)
-// fAnimPosVel.fZ = 0.f;
-//
-// // Unless we're on the ground and moving, or standing still with a probe hit, we use the sim's other axes too.
-// if (!(IsOnGround() && (fProbeHitGround || fAnimPosVel.fX != 0 || fAnimPosVel.fY != 0)))
-// {
-// fAnimPosVel.fX = curV.fX;
-// fAnimPosVel.fY = curV.fY;
-// }
-// }
-//
-// fPhysical->SetLinearVelocitySim(fAnimPosVel);
-// fPhysical->SetSpin(fAnimAngVel + fTurnStr, hsVector3(0.0f, 0.0f, 1.0f));
-}
-#endif
-
-
-#if 0
-
-/////////////////////////////////////////////////////////////////////////
-
-plSimDefs::ActionType plHorizontalFreezeAction::GetType()
-{
- return plSimDefs::kHorizontalFreeze;
-}
-
-void plHorizontalFreezeAction::apply(Havok::Subspace &s, Havok::hkTime time)
-{
- double elapsed = time.asDouble() - getRefresh().asDouble();
- setRefresh(time);
-
- int numContacts = fPhysical->GetNumContacts();
- bool ground = false;
- const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f);
- int i;
- for(i = 0; i < numContacts; i++)
- {
- const Havok::ContactPoint *contact = fPhysical->GetContactPoint(i);
- float dotUp = straightUp.dot(contact->m_normal);
- if (dotUp > .5)
- ground = true;
- }
-
- hsVector3 vel;
- fPhysical->GetLinearVelocitySim(vel);
- vel.fX = 0.0;
- vel.fY = 0.0;
- if (ground)
- vel.fZ = 0;
- fPhysical->SetLinearVelocitySim(vel);
- fPhysical->ClearContacts();
-}
-#endif
-plSwimmingController::plSwimmingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller)
-:plAnimatedController(rootObject,rootApp,controller)
-{
- if (controller)
- fSwimmingStrategy= new plSwimStrategy(controller);
- else
- fSwimmingStrategy = nil;
-}
-plSwimmingController::~plSwimmingController()
-{
- delete fSwimmingStrategy;
-}
-
-plRidingAnimatedPhysicalController::plRidingAnimatedPhysicalController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller)
-: plWalkingController(rootObject, rootApp, controller)
-{
- if(controller)
- fWalkingStrategy = new plRidingAnimatedPhysicalStrategy(controller);
- else
- fWalkingStrategy = nil;
-}
-plRidingAnimatedPhysicalController::~plRidingAnimatedPhysicalController()
-{
- delete fWalkingStrategy;
- fWalkingStrategy=nil;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-
-
-/*
-Purpose:
-
-ANGLE_RAD_2D returns the angle in radians swept out between two rays in 2D.
-
-Discussion:
-
-Except for the zero angle case, it should be true that
-
-ANGLE_RAD_2D(X1,Y1,X2,Y2,X3,Y3)
-+ ANGLE_RAD_2D(X3,Y3,X2,Y2,X1,Y1) = 2 * PI
-
-Modified:
-
-19 April 1999
-
-Author:
-
-John Burkardt
-
-Parameters:
-
-Input, float X1, Y1, X2, Y2, X3, Y3, define the rays
-( X1-X2, Y1-Y2 ) and ( X3-X2, Y3-Y2 ) which in turn define the
-angle, counterclockwise from ( X1-X2, Y1-Y2 ).
-
-Output, float ANGLE_RAD_2D, the angle swept out by the rays, measured
-in radians. 0 <= ANGLE_DEG_2D < 2 PI. If either ray has zero length,
-then ANGLE_RAD_2D is set to 0.
-*/
-
-static float AngleRad2d ( float x1, float y1, float x3, float y3 )
-{
- float value;
- float x;
- float y;
-
- x = ( x1 ) * ( x3 ) + ( y1 ) * ( y3 );
- y = ( x1 ) * ( y3 ) - ( y1 ) * ( x3 );
-
- if ( x == 0.0 && y == 0.0 ) {
- value = 0.0;
- }
- else
- {
- value = atan2 ( y, x );
-
- if ( value < 0.0 )
- {
- value = (float)(value + TWO_PI);
- }
- }
- return value;
-}
-
-static bool LinearVelocity(hsVector3 &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat)
-{
- bool result = false;
-
- hsPoint3 startPos(0.0f, 0.0f, 0.0f); // default position (at start of anim)
- hsPoint3 prevPos = prevMat.GetTranslate(); // position previous frame
- hsPoint3 nowPos = curMat.GetTranslate(); // position current frame
-
- hsVector3 prev2Now = (hsVector3)(nowPos - prevPos); // frame-to-frame delta
-
- if (fabs(prev2Now.fX) < 0.0001f && fabs(prev2Now.fY) < 0.0001f && fabs(prev2Now.fZ) < 0.0001f)
- {
- outputV.Set(0.f, 0.f, 0.f);
- result = true;
- }
- else
- {
- hsVector3 start2Now = (hsVector3)(nowPos - startPos); // start-to-frame delta
-
- float prev2NowMagSqr = prev2Now.MagnitudeSquared();
- float start2NowMagSqr = start2Now.MagnitudeSquared();
-
- float dot = prev2Now.InnerProduct(start2Now);
-
- // HANDLING ANIMATION WRAPPING:
- // the vector from the animation origin to the current frame should point in roughly
- // the same direction as the vector from the previous animation position to the
- // current animation position.
- //
- // If they don't agree (dot < 0,) then we probably mpst wrapped around.
- // The right answer would be to compare the current frame to the start of
- // the anim loop, but it's cheaper to cheat and return false,
- // telling the caller to use the previous frame's velocity.
- if (dot > 0.0f)
- {
- prev2Now /= elapsed;
-
- float xfabs = fabs(prev2Now.fX);
- float yfabs = fabs(prev2Now.fY);
- float zfabs = fabs(prev2Now.fZ);
- static const float maxVel = 20.0f;
- bool valid = xfabs < maxVel && yfabs < maxVel && zfabs < maxVel;
-
- if (valid)
- {
- outputV = prev2Now;
- result = true;
- }
- }
- }
-
- return result;
-}
-
-static void AngularVelocity(float &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat)
-{
- outputV = 0.f;
- float appliedVelocity = 0.0f;
- hsVector3 prevForward = GetYAxis(prevMat);
- hsVector3 curForward = GetYAxis(curMat);
-
- float angleSincePrev = AngleRad2d(curForward.fX, curForward.fY, prevForward.fX, prevForward.fY);
- bool sincePrevSign = angleSincePrev > 0.0f;
- if (angleSincePrev > M_PI)
- angleSincePrev = angleSincePrev - TWO_PI;
-
- const hsVector3 startForward = hsVector3(0, -1.0, 0); // the Y orientation of a "resting" armature....
- float angleSinceStart = AngleRad2d(curForward.fX, curForward.fY, startForward.fX, startForward.fY);
- bool sinceStartSign = angleSinceStart > 0.0f;
- if (angleSinceStart > M_PI)
- angleSinceStart = angleSinceStart - TWO_PI;
-
- // HANDLING ANIMATION WRAPPING:
- // under normal conditions, the angle from rest to the current frame will have the same
- // sign as the angle from the previous frame to the current frame.
- // if it does not, we have (most likely) wrapped the motivating animation from frame n back
- // to frame zero, creating a large angle from the previous frame to the current one
- if (sincePrevSign == sinceStartSign)
- {
- // signs are the same; didn't wrap; use the frame-to-frame angle difference
- appliedVelocity = angleSincePrev / elapsed; // rotation / time
- if (fabs(appliedVelocity) < 3)
- {
- outputV = appliedVelocity;
- }
- }
-}
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.h b/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.h
deleted file mode 100644
index 3462ca08..00000000
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.h
+++ /dev/null
@@ -1,217 +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 PL_HK_CALLBACK_ACTION_H
-#define PL_HK_CALLBACK_ACTION_H
-
-#include "hsGeometry3.h"
-#include "hsMatrix44.h"
-#include "hsTemplates.h"
-#include "pnKeyedObject/plKey.h"
-#include "plPhysical/plSimDefs.h"
-#include "pnMessage/plMessage.h"
-#include "plPhysicalControllerCore.h"
-class plLOSHitMsg;
-class plAGApplicator;
-class plSceneObject;
-class plPhysical;
-class plAvatarController;
-class plCoordinateInterface;
-class plPhysicalControllerCore;
-// Used by the other controllers to actually move the avatar. The actual
-// implementation is in the physics system.
-/*class plPhysicalController
-{
-public:
- // Implemented in the physics system. If you're linking this without that for
- // some reason, just stub this function out.
- //
- // Pass in the key to the root sceneobject for the avatar
- static plPhysicalController* Create(plKey ownerSO, float height, float width);
-
- virtual ~plPhysicalController() {}
-
- // A disabled avatar doesn't move or accumulate air time if he's off the ground.
- virtual void Enable(bool enable) = 0;
- virtual bool IsEnabled() const = 0;
-
- // Set the LOS DB this avatar will be in (only one)
- virtual void SetLOSDB(plSimDefs::plLOSDB losDB) = 0;
-
- // Call this once per frame with the velocities of the avatar in avatar space.
- virtual void SetVelocities(const hsVector3& linearVel, float angVel) = 0;
-
- // Gets the actual velocity we achieved in the last step (relative to our subworld)
- virtual const hsVector3& GetLinearVelocity() const = 0;
- virtual void ResetAchievedLinearVelocity() = 0;
-
- // Get and set the current subworld for the avatar. Use nil for the main world.
- virtual plKey GetSubworld() const = 0;
- virtual void SetSubworld(plKey world) = 0;
-
- // If IsOnGround returns false, GetAirTime will tell you how long the avatar
- // has been airborne. Use ResetAirTime to reset the air time to zero, for
- // cases like when the avatar spawns into a new age.
- virtual bool IsOnGround() const = 0;
- virtual bool IsOnFalseGround() const = 0;
- virtual float GetAirTime() const = 0;
- virtual void ResetAirTime() = 0;
-
- virtual plPhysical* GetPushingPhysical() const = 0;
- virtual bool GetFacingPushingPhysical() const = 0;
-
- // A helper function to get the coordinate interface for the avatars current
- // world. Handy if you need to convert points to and from that. This will
- // return nil if the avatar is in the main world (ie, you don't need to do
- // any translation).
- virtual const plCoordinateInterface* GetSubworldCI() const = 0;
-
- // For the avatar SDL only
- virtual void GetState(hsPoint3& pos, float& zRot) = 0;
- virtual void SetState(const hsPoint3& pos, float zRot) = 0;
-
- // kinematic stuff .... should be just for when playing a behavior...
- virtual void Kinematic(bool state) = 0;
- virtual bool IsKinematic() = 0;
- virtual void GetKinematicPosition(hsPoint3& pos) = 0;
-
- virtual const hsMatrix44& GetPrevSubworldW2L() = 0;
-
- //when seeking no longer want to interact with exclusion regions
- virtual void SetSeek(bool seek)=0;
-
-
-};
-*/
-class plAvatarController
-{
-public:
- virtual ~plAvatarController() {}
-};
-
-class plAnimatedController : public plAvatarController
-{
-public:
- plAnimatedController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller);
-
- virtual void RecalcVelocity(double timeNow, double timePrev, bool useAnim = true);
- void SetTurnStrength(float val) { fTurnStr = val; }
- float GetTurnStrength() { return fTurnStr; }
- virtual void ActivateController()=0;
-protected:
- plSceneObject* fRootObject;
- plPhysicalControllerCore* fController;
- plAGApplicator* fRootApp;
- float fAnimAngVel;
- hsVector3 fAnimPosVel;
- float fTurnStr; // Explicit turning, separate from animations
-};
-
-class plWalkingController : public plAnimatedController
-{
-public:
- plWalkingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller);
- virtual ~plWalkingController();
- virtual void RecalcVelocity(double timeNow, double timePrev, bool useAnim = true);
-
- void Reset(bool newAge);
- bool IsControlledFlight() const { return fControlledFlight != 0; }
- bool IsOnGround() const { return fWalkingStrategy ? fWalkingStrategy->IsOnGround() : true; }
- bool IsOnFalseGround() const { return fWalkingStrategy ? fWalkingStrategy->IsOnFalseGround() : true; }
- bool HitGroundInThisAge() const { return fHitGroundInThisAge; }
- bool EnableControlledFlight(bool status);
- float GetAirTime() const { return fWalkingStrategy ? fWalkingStrategy->GetAirTime() : 0.f; }
- void ResetAirTime() { if (fWalkingStrategy) fWalkingStrategy->ResetAirTime(); }
- float GetForwardVelocity() const;
- void ActivateController();
- // Check these after the avatar the avatar hits the ground for his total
- // hangtime and impact velocity.
- float GetImpactTime() const { return fImpactTime; }
- const hsVector3& GetImpactVelocity() const { return fImpactVelocity; }
-
- plPhysical* GetPushingPhysical() const
- {
- if(fController)return fController->GetPushingPhysical();
- else return nil;
- }
- bool GetFacingPushingPhysical() const
- { if(fController)return fController->GetFacingPushingPhysical();
- else return false;
- }
-
-
-protected:
- bool fHitGroundInThisAge;
- bool fWaitingForGround; // We've gone airborne. IsOnGround() returns false until we hit ground again.
- float fControlledFlightTime;
- int fControlledFlight; // Count of how many are currently forcing flight
- plWalkingStrategy* fWalkingStrategy;
- float fImpactTime;
- hsVector3 fImpactVelocity;
- bool fClearImpact;
- bool fGroundLastFrame;//used for a test to pass the event of first getting air during a jump
- static const float kControlledFlightThreshold;
-};
-class plSwimmingController: public plAnimatedController
-{
-public :
- plSwimmingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller);
- virtual ~plSwimmingController();
- void SetSurface(plSwimRegionInterface *region, float surfaceHeight){
- fSwimmingStrategy->SetSurface(region,surfaceHeight);
- }
- float GetBuoyancy() { return fSwimmingStrategy->GetBuoyancy(); }
- bool IsOnGround() { return fSwimmingStrategy->IsOnGround(); }
- bool HadContacts() { return fSwimmingStrategy->HadContacts();}
- void Enable(bool en){if (fController) fController->Enable(en);}
- plPhysicalControllerCore* GetController(){return fController;}
- virtual void ActivateController(){fSwimmingStrategy->RefreshConnectionToControllerCore();}
-protected:
- plSwimStrategy* fSwimmingStrategy;
-
-};
-class plRidingAnimatedPhysicalController: public plWalkingController
-{
-public:
- plRidingAnimatedPhysicalController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller);
- virtual ~plRidingAnimatedPhysicalController();
-};
-#endif // PL_HK_CALLBACK_ACTION_H
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp
index f1ef12f5..a1fdf22d 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp
@@ -39,7 +39,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
-#include "plAvatar/plAvCallbackAction.h"
+#include "plPhysicalControllerCore.h"
#include "HeadSpin.h"
@@ -129,7 +129,7 @@ bool plAvLadderMod::IIsReadyToClimb()
if (armMod)
{
plAvBrainHuman* brain = plAvBrainHuman::ConvertNoRef(armMod->GetCurrentBrain());
- if (brain && brain->IsMovingForward() && brain->fCallbackAction->IsOnGround())
+ if (brain && brain->IsMovingForward() && brain->fWalkingStrategy->IsOnGround())
movingForward = true;
}
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp
index 1207a180..60f2322e 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp
@@ -54,7 +54,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAGAnim.h"
#include "plArmatureMod.h"
#include "plAvatarMgr.h"
-#include "plAvCallbackAction.h"
+#include "plPhysicalControllerCore.h"
// other
#include "plMessage/plAvatarMsg.h"
@@ -463,10 +463,10 @@ bool plAvTaskSeek::IFinishPosition(hsPoint3 &newPosition,
{
// While warping, we might be hovering just above the ground. Don't want that to
// trigger any falling behavior.
- if(brain&&brain->fCallbackAction)
+ if(brain&&brain->fWalkingStrategy)
{
- brain->fCallbackAction->ResetAirTime();
+ brain->fWalkingStrategy->ResetAirTime();
}
// how far will we translate this frame?
float thisDist = kFloatSpeed * elapsed;
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp
index 5d202273..ab3f9070 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp
@@ -47,7 +47,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAvatar/plAvBrainClimb.h"
#include "plAvatar/plAvBrainDrive.h"
#include "plAvatar/plAnimStage.h"
-#include "plAvatar/plAvCallbackAction.h"
+#include "plAvatar/plPhysicalControllerCore.h"
#include "pnSceneObject/plSceneObject.h"
#include "pnMessage/plSDLModifierMsg.h"
#include "plSDL/plSDL.h"
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp
index b05d666c..a7f500c7 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp
@@ -52,7 +52,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAGAnimInstance.h"
#include "plAGModifier.h"
#include "plMatrixChannel.h"
-#include "plAvCallbackAction.h"
+#include "plPhysicalControllerCore.h"
#include "plAvatarMgr.h"
// global
@@ -671,7 +671,7 @@ bool plAvOneShotTask::Process(plArmatureMod *avatar, plArmatureBrain *brain, dou
if(fEnablePhysicsAtEnd)
{
#if 0//ndef PLASMA_EXTERNAL_RELEASE
- if (!humanBrain || humanBrain->fCallbackAction->HitGroundInThisAge())
+ if (!humanBrain || humanBrain->fWalkingStrategy->HitGroundInThisAge())
{
// For some reason, calling CheckValidPosition at the beginning of
// an age can cause detectors to incorrectly report collisions. So
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp
index 9ccb20a6..6fa701fc 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp
@@ -40,507 +40,631 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
#include "plPhysicalControllerCore.h"
-#include "plMessage/plLOSHitMsg.h"
+
+#include "plArmatureMod.h"
+#include "plSwimRegion.h"
+#include "plMatrixChannel.h"
#include "pnSceneObject/plCoordinateInterface.h"
#include "plPhysical.h"
#include "pnMessage/plCorrectionMsg.h"
-#include "plSwimRegion.h"
-#include "plArmatureMod.h" // for LOS enum type
-#include "plMatrixChannel.h"
-#include "hsTimer.h"
-#include "plPhysX/plSimulationMgr.h"
-#include "plPhysX/plPXPhysical.h"
-#include "pnMessage/plSetNetGroupIDMsg.h"
-#define kSWIMRADIUS 1.1f
-#define kSWIMHEIGHT 2.8f
-#define kGENERICCONTROLLERRADIUS 1.1f
-#define kGENERICCONTROLLERHEIGHT 2.8f
-
-//#define kSWIMMINGCONTACTSLOPELIMIT (cosf(hsDegreesToRadians(80.f)))
-const float plMovementStrategy::kAirTimeThreshold = .1f; // seconds
+
+// Gravity constants
+#define kGravity -32.174f
+#define kTerminalVelocity kGravity
+
+static inline hsVector3 GetYAxis(hsMatrix44 &mat) { return hsVector3(mat.fMap[1][0], mat.fMap[1][1], mat.fMap[1][2]); }
+static float AngleRad2d(float x1, float y1, float x3, float y3);
+
bool CompareMatrices(const hsMatrix44 &matA, const hsMatrix44 &matB, float tolerance);
-bool operator<(const plControllerSweepRecord left, const plControllerSweepRecord right)
+
+
+// plPhysicalControllerCore
+plPhysicalControllerCore::plPhysicalControllerCore(plKey OwnerSceneObject, float height, float radius)
+ : fOwner(OwnerSceneObject),
+ fWorldKey(nil),
+ fHeight(height),
+ fRadius(radius),
+ fLOSDB(plSimDefs::kLOSDBNone),
+ fMovementStrategy(nil),
+ fSimLength(0.0f),
+ fLocalRotation(0.0f, 0.0f, 0.0f, 1.0f),
+ fLocalPosition(0.0f, 0.0f, 0.0f),
+ fLastLocalPosition(0.0f, 0.0f, 0.0f),
+ fLinearVelocity(0.0f, 0.0f, 0.0f),
+ fAchievedLinearVelocity(0.0f, 0.0f, 0.0f),
+ fPushingPhysical(nil),
+ fFacingPushingPhysical(false),
+ fSeeking(false),
+ fEnabled(false),
+ fEnableChanged(false)
{
- if(left.TimeHit < right.TimeHit) return true;
- else return false;
+ fLastGlobalLoc.Reset();
+ fPrevSubworldW2L.Reset();
}
-plMovementStrategy::plMovementStrategy(plPhysicalControllerCore* core)
+
+const plCoordinateInterface* plPhysicalControllerCore::GetSubworldCI()
{
- this->fTimeInAir=0.0f;
- fCore=core;
- fOwner=core->GetOwner();
- this->fPreferedControllerHeight=kGENERICCONTROLLERHEIGHT;
- this->fPreferedControllerWidth=kGENERICCONTROLLERRADIUS;
+ if (fWorldKey)
+ {
+ plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded());
+ if (so)
+ return so->GetCoordinateInterface();
+ }
+
+ return nil;
}
-void plMovementStrategy::IApplyKinematic()
+
+void plPhysicalControllerCore::IncrementAngle(float deltaAngle)
{
- // first apply sceneobject update to the kinematic
+ hsVector3 axis;
+ float angle;
+
+ fLocalRotation.NormalizeIfNeeded();
+ fLocalRotation.GetAngleAxis(&angle, &axis);
+ if (axis.fZ < 0)
+ angle = (2.0f * float(M_PI)) - angle; // axis is backwards, so reverse the angle too
+
+ angle += deltaAngle;
+
+ // make sure we wrap around
+ if (angle < 0.0f)
+ angle = (2.0f * float(M_PI)) + angle; // angle is -, so this works like a subtract
+ if (angle >= (2.0f * float(M_PI)))
+ angle = angle - (2.0f * float(M_PI));
+
+ // set the new angle
+ axis.Set(0.0f, 0.0f, 1.0f);
+ fLocalRotation.SetAngleAxis(angle, axis);
+}
+
+void plPhysicalControllerCore::IApply(float delSecs)
+{
+ fSimLength = delSecs;
+
+ // Match controller to owner if transform has changed since the last frame
plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
+ const hsMatrix44& l2w = so->GetCoordinateInterface()->GetLocalToWorld();
+ if (!CompareMatrices(fLastGlobalLoc, l2w, 0.0001f))
+ SetGlobalLoc(l2w);
+
+ if (fEnabled)
{
- // 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, fCore->GetLastGlobalLoc(), .0001f))
+ // Convert velocity from avatar to world space
+ if (!fLinearVelocity.IsEmpty())
{
- fCore->SetKinematicLoc(l2w);
- //fCore->SetGlobalLoc(l2w);
+ fLinearVelocity = l2w * fLinearVelocity;
+
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
+ fLinearVelocity = subworldCI->GetWorldToLocal() * fLinearVelocity;
}
+
+ fMovementStrategy->Apply(delSecs);
}
}
-plPhysicalControllerCore::~plPhysicalControllerCore()
+void plPhysicalControllerCore::IUpdate(int numSubSteps, float alpha)
{
+ if (fEnabled)
+ {
+ // Update local position and acheived velocity
+ fLastLocalPosition = fLocalPosition;
+ GetPositionSim(fLocalPosition);
+ hsVector3 displacement = (hsVector3)(fLocalPosition - fLastLocalPosition);
+ fAchievedLinearVelocity = displacement / fSimLength;
+
+ displacement /= (float)numSubSteps;
+ fLastLocalPosition = fLocalPosition - displacement;
+ hsPoint3 interpLocalPos = fLastLocalPosition + (displacement * alpha);
+
+ // Update global location
+ fLocalRotation.MakeMatrix(&fLastGlobalLoc);
+ fLastGlobalLoc.SetTranslate(&interpLocalPos);
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
+ {
+ const hsMatrix44& subL2W = subworldCI->GetLocalToWorld();
+ fLastGlobalLoc = subL2W * fLastGlobalLoc;
+ fPrevSubworldW2L = subworldCI->GetWorldToLocal();
+ }
+
+ fMovementStrategy->Update(fSimLength);
+ ISendCorrectionMessages(true);
+ }
+ else
+ {
+ fAchievedLinearVelocity.Set(0.0f, 0.0f, 0.0f);
+
+ // Update global location if in a subworld
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
+ {
+ hsMatrix44 l2s = fPrevSubworldW2L * fLastGlobalLoc;
+ const hsMatrix44& subL2W = subworldCI->GetLocalToWorld();
+ fLastGlobalLoc = subL2W * l2s;
+ fPrevSubworldW2L = subworldCI->GetWorldToLocal();
+
+ ISendCorrectionMessages();
+ }
+ }
+
+ if (fEnableChanged)
+ IHandleEnableChanged();
}
-void plPhysicalControllerCore::Apply(float delSecs)
-{
- fSimLength=delSecs;
- hsAssert(fMovementInterface, "plPhysicalControllerCore::Apply() missing a movement interface");
- if(fMovementInterface)fMovementInterface->Apply(delSecs);
-}
-void plPhysicalControllerCore::PostStep(float delSecs)
-{
- hsAssert(fMovementInterface, "plPhysicalControllerCore::PostStep() missing a movement interface");
- if(fMovementInterface)fMovementInterface->PostStep(delSecs);
-}
-void plPhysicalControllerCore::Update(float delSecs)
+void plPhysicalControllerCore::IUpdateNonPhysical(float alpha)
{
- hsAssert(fMovementInterface, "plPhysicalControllerCore::Update() missing a movement interface");
- if(fMovementInterface)fMovementInterface->Update(delSecs);
-
+ // Update global location if owner transform hasn't changed.
+ plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
+ const hsMatrix44& l2w = so->GetCoordinateInterface()->GetLocalToWorld();
+ if (CompareMatrices(fLastGlobalLoc, l2w, 0.0001f))
+ {
+ if (fEnabled)
+ {
+ hsVector3 displacement = (hsVector3)(fLocalPosition - fLastLocalPosition);
+ hsPoint3 interpLocalPos = fLastLocalPosition + (displacement * alpha);
+
+ fLocalRotation.MakeMatrix(&fLastGlobalLoc);
+ fLastGlobalLoc.SetTranslate(&interpLocalPos);
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
+ {
+ const hsMatrix44& subL2W = subworldCI->GetLocalToWorld();
+ fLastGlobalLoc = subL2W * fLastGlobalLoc;
+ fPrevSubworldW2L = subworldCI->GetWorldToLocal();
+ }
+
+ ISendCorrectionMessages();
+ }
+ else
+ {
+ // Update global location if in a subworld
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
+ {
+ hsMatrix44 l2s = fPrevSubworldW2L * fLastGlobalLoc;
+ const hsMatrix44& subL2W = subworldCI->GetLocalToWorld();
+ fLastGlobalLoc = subL2W * l2s;
+ fPrevSubworldW2L = subworldCI->GetWorldToLocal();
+
+
+ ISendCorrectionMessages();
+ }
+ }
+ }
}
-void plPhysicalControllerCore::SendCorrectionMessages()
+
+void plPhysicalControllerCore::ISendCorrectionMessages(bool dirtySynch)
{
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- plCorrectionMsg* corrMsg = new plCorrectionMsg;
+ plCorrectionMsg* corrMsg = new plCorrectionMsg();
corrMsg->fLocalToWorld = fLastGlobalLoc;
corrMsg->fLocalToWorld.GetInverse(&corrMsg->fWorldToLocal);
- corrMsg->fDirtySynch = true;
- // 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->fDirtySynch = dirtySynch;
corrMsg->AddReceiver(fOwner);
corrMsg->Send();
}
-plPhysicalControllerCore::plPhysicalControllerCore(plKey OwnerSceneObject, float height, float radius)
-:fMovementInterface(nil)
-,fOwner(OwnerSceneObject)
-,fHeight(height)
-,fRadius(radius)
-,fWorldKey(nil)
-,fLinearVelocity(0.f,0.f,0.f)
-,fAngularVelocity(0.f)
-,fAchievedLinearVelocity(0.0f,0.0f,0.0f)
-,fLocalPosition(0.0f,0.0f,0.0f)
-,fLocalRotation(0.0f,0.0f,0.0f,1.0f)
-,fSeeking(false)
-,fEnabled(true)
-,fEnableChanged(false)
-,fLOSDB(plSimDefs::kLOSDBNone)
-,fDisplacementThisStep(0.f,0.f,0.f)
-,fSimLength(0.f)
-,fKinematic(false)
-,fKinematicEnableNextUpdate(false)
-,fNeedsResize(false)
-,fPushingPhysical(nil)
+
+
+// Movement Strategy
+plMovementStrategy::plMovementStrategy(plPhysicalControllerCore* controller)
+ : fController(controller)
{
}
-void plPhysicalControllerCore::UpdateSubstepNonPhysical()
-{
- // 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 =GetPrevSubworldW2L()* soL2W;
- l2w = ciL2W * l2w;
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
- ((plCoordinateInterface*)so->GetCoordinateInterface())->SetTransform(l2w, w2l);
- ((plCoordinateInterface*)so->GetCoordinateInterface())->FlushTransform();
- SetGlobalLoc(l2w);
- }
+void plMovementStrategy::Reset(bool newAge) { fController->SetMovementStrategy(this); }
-}
-void plPhysicalControllerCore::CheckAndHandleAnyStateChanges()
+// Animated Movement Strategy
+plAnimatedMovementStrategy::plAnimatedMovementStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller)
+ : plMovementStrategy(controller),
+ fRootApp(rootApp),
+ fAnimLinearVel(0.0f, 0.0f, 0.0f),
+ fAnimAngularVel(0.0f),
+ fTurnStr(0.0f)
{
- if (IsEnabledChanged())HandleEnableChanged();
- if (IsKinematicChanged())HandleKinematicChanged();
- if (IsKinematicEnableNextUpdate())HandleKinematicEnableNextUpdate();
-}
-void plPhysicalControllerCore::MoveActorToSim()
-{
- // Get the current position of the physical
- hsPoint3 curLocalPos;
- hsPoint3 lastLocalPos;
- GetPositionSim(curLocalPos);
- MoveKinematicToController(curLocalPos);
- lastLocalPos=GetLocalPosition();
- fDisplacementThisStep= hsVector3(curLocalPos - lastLocalPos);
- fLocalPosition = curLocalPos;
- if(fSimLength>0.0f)
- fAchievedLinearVelocity=fDisplacementThisStep/fSimLength;
- else fAchievedLinearVelocity.Set(0.0f,0.0f,0.0f);
-}
-void plPhysicalControllerCore::IncrementAngle(float deltaAngle)
-{
- float angle;
- hsVector3 axis;
- fLocalRotation.NormalizeIfNeeded();
- fLocalRotation.GetAngleAxis(&angle, &axis);
- // adjust it (quaternions are weird...)
- if (axis.fZ < 0)
- angle = (2*M_PI) - angle; // axis is backwards, so reverse the angle too
- angle += deltaAngle;
- // make sure we wrap around
- if (angle < 0)
- angle = (2*M_PI) + angle; // angle is -, so this works like a subtract
- if (angle >= (2*M_PI))
- angle = angle - (2*M_PI);
- // and set the new angle
- fLocalRotation.SetAngleAxis(angle, hsVector3(0,0,1));
}
-void plPhysicalControllerCore::UpdateWorldRelativePos()
+void plAnimatedMovementStrategy::RecalcVelocity(double timeNow, float elapsed, bool useAnim)
{
+ if (useAnim)
+ {
+ // while you may think it would be correct to cache this, what we're actually asking is "what would the animation's
+ // position be at the previous time given its *current* parameters (particularly blends)"
+ hsMatrix44 prevMat = ((plMatrixChannel *)fRootApp->GetChannel())->Value(timeNow - elapsed, true);
+ hsMatrix44 curMat = ((plMatrixChannel *)fRootApp->GetChannel())->Value(timeNow, true);
- // Apply rotation and translation
- fLocalRotation.MakeMatrix(&fLastGlobalLoc);
- fLastGlobalLoc.SetTranslate(&fLocalPosition);
- // Localize to global coords if in a subworld
- const plCoordinateInterface* ci = GetSubworldCI();
- if (ci)
+ IRecalcLinearVelocity(elapsed, prevMat, curMat);
+ IRecalcAngularVelocity(elapsed, prevMat, curMat);
+ }
+ else
{
- const hsMatrix44& l2w = ci->GetLocalToWorld();
- fLastGlobalLoc = l2w * fLastGlobalLoc;
+ fAnimLinearVel.Set(0.0f, 0.0f, 0.0f);
+ fAnimAngularVel = 0.0f;
}
+
+ // Update controller rotation
+ float zRot = fAnimAngularVel + fTurnStr;
+ if (hsABS(zRot) > 0.0001f)
+ fController->IncrementAngle(zRot * elapsed);
+
+ // Update controller velocity
+ fController->SetLinearVelocity(fAnimLinearVel);
}
-plPhysical* plPhysicalControllerCore::GetPushingPhysical()
+
+void plAnimatedMovementStrategy::IRecalcLinearVelocity(float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat)
{
- return fPushingPhysical;
+ hsPoint3 startPos(0.0f, 0.0f, 0.0f); // default position (at start of anim)
+ hsPoint3 prevPos = prevMat.GetTranslate(); // position previous frame
+ hsPoint3 nowPos = curMat.GetTranslate(); // position current frame
+
+ hsVector3 prev2Now = (hsVector3)(nowPos - prevPos); // frame-to-frame delta
+
+ if (fabs(prev2Now.fX) < 0.0001f && fabs(prev2Now.fY) < 0.0001f && fabs(prev2Now.fZ) < 0.0001f)
+ {
+ fAnimLinearVel.Set(0.f, 0.f, 0.f);
+ }
+ else
+ {
+ hsVector3 start2Now = (hsVector3)(nowPos - startPos); // start-to-frame delta
+
+ float prev2NowMagSqr = prev2Now.MagnitudeSquared();
+ float start2NowMagSqr = start2Now.MagnitudeSquared();
+
+ float dot = prev2Now.InnerProduct(start2Now);
+
+ // HANDLING ANIMATION WRAPPING:
+ // the vector from the animation origin to the current frame should point in roughly
+ // the same direction as the vector from the previous animation position to the
+ // current animation position.
+ //
+ // If they don't agree (dot < 0,) then we probably mpst wrapped around.
+ // The right answer would be to compare the current frame to the start of
+ // the anim loop, but it's cheaper to cheat and use the previous frame's velocity.
+ if (dot > 0.0f)
+ {
+ prev2Now /= elapsed;
+
+ float xfabs = fabs(prev2Now.fX);
+ float yfabs = fabs(prev2Now.fY);
+ float zfabs = fabs(prev2Now.fZ);
+ static const float maxVel = 20.0f;
+ bool valid = xfabs < maxVel && yfabs < maxVel && zfabs < maxVel;
+
+ if (valid)
+ {
+ fAnimLinearVel = prev2Now;
+ }
+ }
+ }
}
-const hsVector3& plPhysicalControllerCore::GetLinearVelocity()
+
+void plAnimatedMovementStrategy::IRecalcAngularVelocity(float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat)
{
- return fLinearVelocity;
+ fAnimAngularVel = 0.0f;
+ float appliedVelocity = 0.0f;
+ hsVector3 prevForward = GetYAxis(prevMat);
+ hsVector3 curForward = GetYAxis(curMat);
+
+ float angleSincePrev = AngleRad2d(curForward.fX, curForward.fY, prevForward.fX, prevForward.fY);
+ bool sincePrevSign = angleSincePrev > 0.0f;
+ if (angleSincePrev > float(M_PI))
+ angleSincePrev = angleSincePrev - TWO_PI;
+
+ const hsVector3 startForward = hsVector3(0.0f, -1.0f, 0.0f); // the Y orientation of a "resting" armature....
+ float angleSinceStart = AngleRad2d(curForward.fX, curForward.fY, startForward.fX, startForward.fY);
+ bool sinceStartSign = angleSinceStart > 0.0f;
+ if (angleSinceStart > float(M_PI))
+ angleSinceStart = angleSinceStart - TWO_PI;
+
+ // HANDLING ANIMATION WRAPPING:
+ // under normal conditions, the angle from rest to the current frame will have the same
+ // sign as the angle from the previous frame to the current frame.
+ // if it does not, we have (most likely) wrapped the motivating animation from frame n back
+ // to frame zero, creating a large angle from the previous frame to the current one
+ if (sincePrevSign == sinceStartSign)
+ {
+ // signs are the same; didn't wrap; use the frame-to-frame angle difference
+ appliedVelocity = angleSincePrev / elapsed; // rotation / time
+ if (fabs(appliedVelocity) < 3)
+ {
+ fAnimAngularVel = appliedVelocity;
+ }
+ }
}
-bool plPhysicalControllerCore::GetFacingPushingPhysical()
+
+
+// Walking Strategy
+plWalkingStrategy::plWalkingStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller)
+ : plAnimatedMovementStrategy(rootApp, controller),
+ fSlidingNormals(),
+ fImpactVelocity(0.0f, 0.0f, 0.0f),
+ fImpactTime(0.0f),
+ fTimeInAir(0.0f),
+ fControlledFlightTime(0.0f),
+ fControlledFlight(0),
+ fGroundHit(false),
+ fFalseGround(false),
+ fHeadHit(false),
+ fClearImpact(false),
+ fHitGroundInThisAge(false)
{
- return fFacingPushingPhysical;
}
-///////////////////////////
-//Walking Strategy
+
void plWalkingStrategy::Apply(float delSecs)
{
- //Apply Should Only be Called from a PhysicalControllerCore
- hsAssert(fCore,"No Core shouldn't be Applying");
- uint32_t collideFlags =
- 1<IsSeeking())
+ hsVector3 velocity = fController->GetLinearVelocity();
+ hsVector3 achievedVelocity = fController->GetAchievedLinearVelocity();
+
+ // Add in gravity if the avatar's z velocity isn't being set explicitly
+ if (hsABS(velocity.fZ) < 0.001f)
{
- collideFlags|=(1<GetLinearVelocity();
- hsVector3 AchievedLinearVelocity=fCore->GetAchievedLinearVelocity();
- hsPoint3 positionBegin;
- fCore->GetPositionSim(positionBegin);
- bool recovered=false;
- if (fCore->IsKinematic())
+
+ // If we're airborne and the velocity isn't set, use the velocity from
+ // the last frame so we maintain momentum.
+ if (!IsOnGround() && velocity.fX == 0.0f && velocity.fY == 0.0f)
{
- 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, fCore->GetLastGlobalLoc(), .0001f))
- {
- fCore->SetKinematicLoc(l2w);
- fCore->SetGlobalLoc(l2w);
- }
- }
- return;
+ velocity.fX = achievedVelocity.fX;
+ velocity.fY = achievedVelocity.fY;
}
- if (!fCore->IsEnabled())
- return;
-
- bool gotGroundHit = fGroundHit;
- fGroundHit = false;
-
- fCore->SetPushingPhysical(nil);
- fCore->SetFacingPushingPhysical( false);
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
+ if (!fGroundHit && fSlidingNormals.Count())
{
- static const float kGravity = -32.f;
- // 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, fCore->GetLastGlobalLoc(), .0001f))
- fCore->SetGlobalLoc(l2w);
-
- // Convert our avatar relative velocity to subworld relative
- if (!LinearVelocity.IsEmpty())
+ // 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.0f, 0.0f, 0.0f);
+ for (int i = 0; i < fSlidingNormals.GetCount(); i++)
{
- LinearVelocity = l2w * LinearVelocity;
- const plCoordinateInterface* subworldCI = fCore->GetSubworldCI();
- if (subworldCI)
- LinearVelocity = subworldCI->GetWorldToLocal() * LinearVelocity;
- }
+ offset += fSlidingNormals[i];
+ hsVector3 velNorm = velocity;
- // 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(LinearVelocity.fZ) < 0.001f)
- {
- // 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.
- float prevZVel = AchievedLinearVelocity.fZ;
- if (IsOnGround())
- prevZVel = hsMinimum(prevZVel, 0.f);
- float 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.
- float maxGrav = -.001f / delSecs;
- if (grav > maxGrav)
- grav = maxGrav;
- LinearVelocity.fZ = prevZVel + grav;
- }
-
- // If we're airborne and the velocity isn't set, use the velocity from
- // the last frame so we maintain momentum.
- if (!IsOnGround() && LinearVelocity.fX == 0.f && LinearVelocity.fY == 0.f)
- {
- LinearVelocity.fX = AchievedLinearVelocity.fX;
- LinearVelocity.fY = AchievedLinearVelocity.fY;
- }
+ if (velNorm.MagnitudeSquared() > 0.0f)
+ velNorm.Normalize();
- //make terminal velocity equal to k. it is wrong but has been this way and
- //don't want to break any puzzles. on top of that it will reduce tunneling behavior
- if(LinearVelocity.fZSetLinearVelocity(LinearVelocity);
- // Scale the velocity to our actual step size (by default it's feet/sec)
- hsVector3 vel(LinearVelocity.fX * delSecs, LinearVelocity.fY * delSecs, LinearVelocity.fZ * delSecs);
- unsigned int colFlags = 0;
- fGroundHit = false;
- fFalseGround = false;
- fContactNormals.Swap(fPrevSlidingNormals);
- fContactNormals.SetCount(0);
- fCore->Move(vel, collideFlags, colFlags);
- ICheckForFalseGround();
- //if(fReqMove2) fCore->Move2(vel);
- /*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&kBottom ) &&(fGroundHit==false))
- {
- fFalseGround=true;
+ velocity = velocity.Magnitude() * proj;
+ }
}
-
- if(colFlags&kTop)
+ if (offset.MagnitudeSquared() > 0.0f)
{
- fHitHead=true;
- //Did you hit your head on a dynamic?
- //with Physx's wonderful controller hit report vs flags issues we need to actually sweep to see
- std::multiset< plControllerSweepRecord > HitsDynamic;
- uint32_t testFlag=1<GetPositionSim(startPos);
- endPos= startPos + vel;
- int NumObjsHit=fCore->SweepControllerPath(startPos, endPos, true, false, testFlag, HitsDynamic);
- if(NumObjsHit>0)
- {
- for(std::multiset< plControllerSweepRecord >::iterator curObj= HitsDynamic.begin();
- curObj!=HitsDynamic.end(); curObj++)
- {
-
- hsAssert(curObj->ObjHit,"We allegedly hit something, but there is no plasma physical associated with it");
- if(curObj->ObjHit)
- {//really we shouldn't have to check hitObj should be nil only if we miss, or the physX object
- //doesn't have a user data associated with this either way this just shouldn't happen
- hsVector3 hitObjVel;
- curObj->ObjHit->GetLinearVelocitySim(hitObjVel);
- hsVector3 relativevel=LinearVelocity-hitObjVel;
- curObj->ObjHit->SetHitForce(relativevel * 10.0f * (*curObj).ObjHit->GetMass(), (*curObj).locHit);
- }
- }
- HitsDynamic.clear();
- }
+ // 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();
+ velocity += offset * 5.0f;
}
}
+
+ if (velocity.fZ < kTerminalVelocity)
+ velocity.fZ = kTerminalVelocity;
+
+ // Convert to a displacement vector
+ hsVector3 displacement = velocity * delSecs;
+
+ // Reset vars and move the controller
+ fController->SetPushingPhysical(nil);
+ fController->SetFacingPushingPhysical(false);
+ fGroundHit = fFalseGround = fHeadHit = false;
+ fSlidingNormals.SetCount(0);
+
+ unsigned int collideResults = 0;
+ unsigned int collideFlags = 1<IsSeeking())
+ collideFlags |= (1<Move(displacement, collideFlags, collideResults);
+
+ if ((!fGroundHit) && (collideResults & kBottom))
+ fFalseGround = true;
+
+ if (collideResults & kTop)
+ fHeadHit = true;
}
-void plWalkingStrategy::ICheckForFalseGround()
+void plWalkingStrategy::Update(float delSecs)
{
- 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 float threshold = hsDegreesToRadians(240.f);
- int numContacts = fContactNormals.GetCount() + fPrevSlidingNormals.GetCount();
- if (numContacts >= 2)
+ if (fGroundHit || fFalseGround)
+ fTimeInAir = 0.0f;
+ else
{
- // 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 < fContactNormals.GetCount(); i++, angleIdx++)
- {
- fCollisionAngles[angleIdx] = atan2(fContactNormals[i].fY, fContactNormals[i].fX);
- }
- for (i = 0; i < fPrevSlidingNormals.GetCount(); i++, angleIdx++)
- {
- fCollisionAngles[angleIdx] = atan2(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])
- {
- float 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)
+ fTimeInAir += delSecs;
+ if (fHeadHit)
{
- // We got to the end. Check the last with the first and make your decision.
- if (!(fCollisionAngles[0] - fCollisionAngles[numContacts - 1] >= (threshold - 2 * M_PI)))
- fFalseGround = true;
+ // If we're airborne and hit our head, override achieved velocity to avoid being shoved sideways
+ hsVector3 velocity = fController->GetLinearVelocity();
+ hsVector3 achievedVelocity = fController->GetAchievedLinearVelocity();
+
+ achievedVelocity.fX = velocity.fX;
+ achievedVelocity.fY = velocity.fY;
+ if (achievedVelocity.fZ > 0.0f)
+ achievedVelocity.fZ = 0.0f;
+
+ fController->OverrideAchievedLinearVelocity(achievedVelocity);
}
}
+
+ hsVector3 zeroVelocity(0.f, 0.f, 0.f);
+ fController->SetLinearVelocity(zeroVelocity);
+
+ if (!fHitGroundInThisAge && IsOnGround())
+ fHitGroundInThisAge = true;
+
+ if (fClearImpact)
+ {
+ fImpactTime = 0.0f;
+ fImpactVelocity.Set(0.0f, 0.0f, 0.0f);
+ }
+
+ if (IsOnGround())
+ fClearImpact = true;
+ else
+ {
+ fImpactTime = fTimeInAir;
+ fImpactVelocity = fController->GetAchievedLinearVelocity();
+ // convert orientation from subworld to avatar-local coordinates
+ fImpactVelocity = (hsVector3)fController->GetLocalRotation().Rotate(&fImpactVelocity);
+ fClearImpact = false;
+ }
}
-void plWalkingStrategy::Update(float delSecs)
+
+void plWalkingStrategy::AddContactNormals(hsVector3& vec)
{
- //Update Should Only be Called from a PhysicalControllerCore
- hsAssert(fCore,"Running Update: but have no Core");
- float AngularVelocity=fCore->GetAngularVelocity();
- hsVector3 LinearVelocity=fCore->GetLinearVelocity();
+ float dot = vec * kAvatarUp;
+ if (dot >= 0.5f)
+ fGroundHit = true;
+ else
+ fSlidingNormals.Append(vec);
+}
- if (!fCore->IsEnabled() || fCore->IsKinematic())
+void plWalkingStrategy::Reset(bool newAge)
+{
+ plMovementStrategy::Reset(newAge);
+ fImpactVelocity.Set(0.0f, 0.0f, 0.0f);
+ fImpactTime = 0.0f;
+ if (newAge)
{
- fCore->UpdateSubstepNonPhysical();
- return;
+ fTimeInAir = 0.0f;
+ fClearImpact = true;
+ fHitGroundInThisAge = false;
+ fSlidingNormals.SetCount(0);
}
- fCore->CheckAndHandleAnyStateChanges();
- if (!fGroundHit && !fFalseGround)
- fTimeInAir += delSecs;
- else
- fTimeInAir = 0.f;
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
+}
+
+void plWalkingStrategy::RecalcVelocity(double timeNow, float elapsed, bool useAnim)
+{
+ if (fControlledFlight != 0)
{
- fCore->MoveActorToSim();
- if (AngularVelocity != 0.f)
- {
- float deltaAngle=AngularVelocity*delSecs;
- fCore->IncrementAngle( deltaAngle);
- }
- // 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.
- fCore->UpdateWorldRelativePos();
- fCore->SendCorrectionMessages();
- bool headhit=fHitHead;
- fHitHead=false;
- hsVector3 AchievedLinearVelocity;
- AchievedLinearVelocity = fCore->DisplacementLastStep();
- AchievedLinearVelocity=AchievedLinearVelocity/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
- */
- 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
- float headFriction=0.0f;
- AchievedLinearVelocity.fX=(1.0f-headFriction)*LinearVelocity.fX;
- AchievedLinearVelocity.fY=(1.0f-headFriction)*LinearVelocity.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(AchievedLinearVelocity.fZ>0.0f)
- {
- AchievedLinearVelocity.fZ=0.0f;
- }
- fCore->OverrideAchievedVelocity(AchievedLinearVelocity);
- }
- fCore->OverrideAchievedVelocity(AchievedLinearVelocity);
- // Apply angular velocity
+ if (IsOnGround())
+ fControlledFlightTime = fTimeInAir;
+
+ if (fControlledFlightTime > kControlledFlightThreshold)
+ EnableControlledFlight(false);
}
- LinearVelocity.Set(0.f, 0.f, 0.f);
- AngularVelocity = 0.f;
- fCore->SetVelocities(LinearVelocity,AngularVelocity);
+ plAnimatedMovementStrategy::RecalcVelocity(timeNow, elapsed, useAnim);
+}
+bool plWalkingStrategy::EnableControlledFlight(bool status)
+{
+ if (status)
+ {
+ if (fControlledFlight == 0)
+ fControlledFlightTime = 0.0f;
+
+ ++fControlledFlight;
+ }
+ else
+ fControlledFlight = max(--fControlledFlight, 0);
+
+ return status;
+}
+
+plPhysical* plWalkingStrategy::GetPushingPhysical() const { return fController->GetPushingPhysical(); }
+bool plWalkingStrategy::GetFacingPushingPhysical() const { return fController->GetFacingPushingPhysical(); }
+
+const float plWalkingStrategy::kAirTimeThreshold = 0.1f;
+const float plWalkingStrategy::kControlledFlightThreshold = 1.0f;
+
+
+// Swim Strategy
+plSwimStrategy::plSwimStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller)
+ : plAnimatedMovementStrategy(rootApp, controller),
+ fBuoyancy(0.0f),
+ fSurfaceHeight(0.0f),
+ fCurrentRegion(nil),
+ fOnGround(false),
+ fHadContacts(false)
+{
}
+void plSwimStrategy::Apply(float delSecs)
+{
+ hsVector3 velocity = fController->GetLinearVelocity();
+ hsVector3 achievedVelocity = fController->GetAchievedLinearVelocity();
+
+ IAdjustBuoyancy();
+
+ //trying to dampen the oscillations
+ float retardent = 0.0f;
+ static float finalBobSpeed = 0.5f;
+ if ((achievedVelocity.fZ > finalBobSpeed) || (achievedVelocity.fZ < -finalBobSpeed))
+ retardent = achievedVelocity.fZ * -0.90f;
+
+ float zacc = (1.0f - fBuoyancy) * kGravity + retardent;
+ velocity.fZ += (zacc * delSecs);
+
+ velocity.fZ += achievedVelocity.fZ;
-void plWalkingStrategy::IAddContactNormals(hsVector3& vec)
-{
- //TODO: ADD in functionality to Adjust walkable slope for controller, also apply that in here
+ // Water Current
+ if (fCurrentRegion != nil)
+ {
+ float angCurrent = 0.0f;
+ hsVector3 linCurrent(0.0f, 0.0f, 0.0f);
+ fCurrentRegion->GetCurrent(fController, linCurrent, angCurrent, delSecs);
+
+ if (hsABS(angCurrent) > 0.0001f)
+ fController->IncrementAngle(angCurrent * delSecs);
+
+ velocity += linCurrent;
+
+ if (velocity.fZ > fCurrentRegion->fMaxUpwardVel)
+ velocity.fZ = fCurrentRegion->fMaxUpwardVel;
+ }
+
+ if (velocity.fZ < kTerminalVelocity)
+ velocity.fZ = kTerminalVelocity;
+
+ // Convert to displacement vector
+ hsVector3 displacement = velocity * delSecs;
+
+ // Reset vars and move controller //
+ fController->SetPushingPhysical(nil);
+ fController->SetFacingPushingPhysical(false);
+ fHadContacts = fOnGround = false;
+
+ unsigned int collideResults = 0;
+ unsigned int collideFlags = 1<IsSeeking())
+ collideFlags |= (1<Move(displacement, collideFlags, collideResults);
+
+ if ((collideResults & kBottom) || (collideResults & kSides))
+ fHadContacts = true;
+}
+
+void plSwimStrategy::AddContactNormals(hsVector3& vec)
+{
float dot = vec * kAvatarUp;
- if ( dot >= kSLOPELIMIT ) fGroundHit=true;
- else plMovementStrategySimulationInterface::IAddContactNormals(vec);
+ if (dot >= kSlopeLimit)
+ fOnGround = true;
}
-//swimming strategy
-plSwimStrategy::plSwimStrategy(plPhysicalControllerCore* core)
- :plMovementStrategy(core)
- ,fOnGround(false)
- ,fHadContacts(false)
- ,fBuoyancy(0.f)
- ,fSurfaceHeight(0.0f)
- ,fCurrentRegion(nil)
+void plSwimStrategy::SetSurface(plSwimRegionInterface *region, float surfaceHeight)
{
- fPreferedControllerHeight=kSWIMHEIGHT;
- fPreferedControllerWidth=kSWIMRADIUS;
- fCore->SetMovementSimulationInterface(this);
+ fCurrentRegion = region;
+ fSurfaceHeight = surfaceHeight;
}
void plSwimStrategy::IAdjustBuoyancy()
{
@@ -558,383 +682,148 @@ void plSwimStrategy::IAdjustBuoyancy()
return;
}
- hsMatrix44 l2w, w2l;
hsPoint3 posSim;
- fCore->GetPositionSim(posSim);
- float depth = fSurfaceHeight - posSim.fZ;
- //this isn't a smooth transition but hopefully it won't be too obvious
- if(depth<=0.0)//all the away above water
+ fController->GetPositionSim(posSim);
+ float depth = fSurfaceHeight - posSim.fZ;
+
+ // this isn't a smooth transition but hopefully it won't be too obvious
+ if (depth <= 0.0) //all the away above water
fBuoyancy = 0.f; // Same as being above ground. Plain old gravity.
- else if(depth >= 5.0f) fBuoyancy=3.0f;//completely Submereged
- else fBuoyancy =(depth/surfaceDepth );
-
+ else if (depth >= 5.0f)
+ fBuoyancy = 3.0f; //completely Submereged
+ else
+ fBuoyancy = depth / surfaceDepth;
}
-void plSwimStrategy::Apply(float delSecs)
-{
- hsAssert(fCore,"PlSwimStrategy::Apply No Core shouldn't be Applying");
- uint32_t collideFlags =
- 1<IsSeeking())
- {
- collideFlags|=(1<GetLinearVelocity();
- hsVector3 AchievedLinearVelocity=fCore->GetAchievedLinearVelocity();
- if (fCore->IsKinematic())
- {
- 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, fCore->GetLastGlobalLoc(), .0001f))
- {
- fCore->SetKinematicLoc(l2w);
- fCore->SetGlobalLoc(l2w);
- }
- }
- return;
-
- }
- if (!fCore->IsEnabled())
- return;
-
- fCore->SetPushingPhysical(nil);
- fCore->SetFacingPushingPhysical( false);
- fHadContacts=false;
- fOnGround=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, fCore->GetLastGlobalLoc(), .0001f))
- fCore->SetGlobalLoc(l2w);
-
- // Convert our avatar relative velocity to subworld relative
- if (!LinearVelocity.IsEmpty())
- {
- LinearVelocity = l2w * LinearVelocity;
- const plCoordinateInterface* subworldCI = fCore->GetSubworldCI();
- if (subworldCI)
- LinearVelocity = subworldCI->GetWorldToLocal() * LinearVelocity;
- }
- IAdjustBuoyancy();
- float zacc;
- float retardent=0.0f;
- static float FinalBobSpeed=0.5f;
- //trying to dampen the oscillations
- if((AchievedLinearVelocity.fZ>FinalBobSpeed)||(AchievedLinearVelocity.fZ<-FinalBobSpeed))
- retardent=AchievedLinearVelocity.fZ *-.90f;
- zacc=(1-fBuoyancy)*-32.f + retardent;
-
- hsVector3 linCurrent(0.0f,0.0f,0.0f);
- float angCurrent = 0.f;
- if (fCurrentRegion != nil)
- {
-
- fCurrentRegion->GetCurrent(fCore, linCurrent, angCurrent, delSecs);
- //fAngularVelocity+= angCurrent;
- }
- hsVector3 vel(LinearVelocity.fX , LinearVelocity.fY , AchievedLinearVelocity.fZ+ LinearVelocity.fZ );
- vel.fZ= vel.fZ + zacc*delSecs;
- if(fCurrentRegion!=nil){
- if (vel.fZ > fCurrentRegion->fMaxUpwardVel)
- {
- vel.fZ = fCurrentRegion->fMaxUpwardVel;
- }
- vel+= linCurrent;
- }
- static const float kGravity = -32.f;
- if(vel.fZMove(displacement,collideFlags,colFlags);
- if((colFlags&kBottom)||(colFlags&kSides))fHadContacts=true;
- float angvel=fCore->GetAngularVelocity();
- fCore->SetAngularVelocity(angvel +angCurrent);
- }
+
+// Dynamic Walking Strategy
+plDynamicWalkingStrategy::plDynamicWalkingStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller)
+ : plWalkingStrategy(rootApp, controller)
+{
}
-void plSwimStrategy::Update(float delSecs)
+
+void plDynamicWalkingStrategy::Apply(float delSecs)
{
- hsAssert(fCore,"Running Update: but have no Core");
- float AngularVelocity=fCore->GetAngularVelocity();
- hsVector3 LinearVelocity=fCore->GetLinearVelocity();
- if (!fCore->IsEnabled() || fCore->IsKinematic())
- {
- fCore->UpdateSubstepNonPhysical();
- return;
- }
- fCore->CheckAndHandleAnyStateChanges();
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
- {
- fCore->MoveActorToSim();
+ hsVector3 velocity = fController->GetLinearVelocity();
+ hsVector3 achievedVelocity = fController->GetAchievedLinearVelocity();
- if (AngularVelocity != 0.f)
- {
- float deltaAngle=AngularVelocity*delSecs;
- fCore->IncrementAngle( deltaAngle);
- }
- fCore->UpdateWorldRelativePos();
- fCore->SendCorrectionMessages();
- }
- LinearVelocity.Set(0.f, 0.f, 0.f);
- AngularVelocity = 0.f;
- fCore->SetVelocities(LinearVelocity,AngularVelocity);
-}
-void plSwimStrategy::IAddContactNormals(hsVector3& vec)
-{
- //TODO: ADD in functionality to Adjust walkable slope for controller, also apply that in here
- float dot = vec * kAvatarUp;
- if ( dot >= kSLOPELIMIT )
+ // Add in gravity if the avatar's z velocity isn't being set explicitly
+ if (hsABS(velocity.fZ) < 0.001f)
{
- fOnGround=true;
- // fHadContacts=true;
+ // 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.
+ float prevZVel = achievedVelocity.fZ;
+ if (IsOnGround())
+ prevZVel = hsMinimum(prevZVel, 0.f);
+
+ velocity.fZ = prevZVel + (kGravity * delSecs);
}
- else plMovementStrategySimulationInterface::IAddContactNormals(vec);
-}
-void plSwimStrategy::SetSurface(plSwimRegionInterface *region, float surfaceHeight)
-{
- fCurrentRegion=region;
- fSurfaceHeight=surfaceHeight;
+
+ if (velocity.fZ < kTerminalVelocity)
+ velocity.fZ = kTerminalVelocity;
+
+ fController->SetPushingPhysical(nil);
+ fController->SetFacingPushingPhysical(false);
+ fGroundHit = fFalseGround = false;
+
+ float groundZVelocity;
+ if (ICheckForGround(groundZVelocity))
+ velocity.fZ += groundZVelocity;
+
+ fController->SetLinearVelocitySim(velocity);
}
-void plRidingAnimatedPhysicalStrategy::Apply(float delSecs)
+
+bool plDynamicWalkingStrategy::ICheckForGround(float& zVelocity)
{
- hsVector3 LinearVelocity=fCore->GetLinearVelocity();
- hsVector3 AchievedLinearVelocity=fCore->GetAchievedLinearVelocity();
- if (fCore->IsKinematic())
- {
- //want to make sure nothing funky happens in the sim
- IApplyKinematic();
- return;
- }
- if (!fCore->IsEnabled())
- return;
+ std::vector groundHits;
+ uint32_t collideFlags = 1<GetPositionSim(startPos);
+ hsPoint3 endPos = startPos;
-
- fCore->SetPushingPhysical(nil);
- fCore->SetFacingPushingPhysical( false);
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- hsPoint3 startPos, desiredDestination, endPos;
- fCore->GetPositionSim(startPos);
- uint32_t collideFlags =
- 1< GroundHitRecords;
- int possiblePlatformCount =fCore->SweepControllerPath(startPos, startPos + hsPoint3(0.f,0.f, -0.002f), true, true, collideFlags, GroundHitRecords);
- float maxPlatformVel = - FLT_MAX;
- int platformCount=0;
- fGroundHit = false;
- if(possiblePlatformCount)
+ // Set sweep length
+ startPos.fZ += 0.05f;
+ endPos.fZ -= 0.05f;
+
+ int possiblePlatformCount = fController->SweepControllerPath(startPos, endPos, true, true, collideFlags, groundHits);
+ if (possiblePlatformCount)
{
-
- std::multiset::iterator curRecord;
+ zVelocity = -FLT_MAX;
- for(curRecord = GroundHitRecords.begin(); curRecord != GroundHitRecords.end(); curRecord++)
+ std::vector::iterator curRecord;
+ for (curRecord = groundHits.begin(); curRecord != groundHits.end(); ++curRecord)
{
- bool groundlike=false;
- if((curRecord->locHit.fZ - startPos.fZ)<= .2) groundlike= true;
- if(groundlike)
+ if (curRecord->ObjHit != nil)
{
- if(curRecord->ObjHit !=nil)
- {
- hsVector3 vel;
- curRecord->ObjHit->GetLinearVelocitySim(vel);
- if(vel.fZ > maxPlatformVel)
- {
- maxPlatformVel= vel.fZ;
- }
- }
- platformCount ++;
+ hsVector3 objVelocity;
+ curRecord->ObjHit->GetLinearVelocitySim(objVelocity);
+ if (objVelocity.fZ > zVelocity)
+ zVelocity = objVelocity.fZ;
+
fGroundHit = true;
}
}
}
-
-
-
- bool gotGroundHit = fGroundHit;
- 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, fCore->GetLastGlobalLoc(), .0001f))
- fCore->SetGlobalLoc(l2w);
-
- // Convert our avatar relative velocity to subworld relative
- if (!LinearVelocity.IsEmpty())
- {
- LinearVelocity = l2w * LinearVelocity;
- const plCoordinateInterface* subworldCI = fCore->GetSubworldCI();
- if (subworldCI)
- LinearVelocity = subworldCI->GetWorldToLocal() * LinearVelocity;
- }
-
- if(!IsOnGround())
- {
- if(!fNeedVelocityOverride)
- {
- LinearVelocity.fZ= AchievedLinearVelocity.fZ;
- }
- else
- {
- LinearVelocity = fOverrideVelocity;
- }
- }
- if(fStartJump)
- {
- LinearVelocity.fZ =12.0f;
- }
- if(platformCount)
- {
- LinearVelocity.fZ = LinearVelocity.fZ + maxPlatformVel;
- }
- //probably neeed to do something with contact normals in here
- //for false ground stuff
-
- fFalseGround = false;
- hsVector3 testLength = LinearVelocity * delSecs + hsVector3(0.0, 0.0, -0.00f);
- //
- hsPoint3 desiredDestination= startPos + testLength;
- if(!IsOnGround())
- {
- if(ICheckMove(startPos, desiredDestination))
- {//we can get there soley by the LinearVelocity
-
- fNeedVelocityOverride =false;
- }
- else
- {
-
- fNeedVelocityOverride =true;
- fOverrideVelocity = LinearVelocity;
- fOverrideVelocity.fZ -= delSecs * 32.f;
- }
- }
- else
- {
- fNeedVelocityOverride =false;
- }
-
- fCore->SetLinearVelocity(LinearVelocity);
-
- }
+ return fGroundHit;
}
-bool plRidingAnimatedPhysicalStrategy::ICheckMove(const hsPoint3& startPos, const hsPoint3& desiredPos)
+
+
+//////////////////////////////////////////////////////////////////////////
+
+/*
+Purpose:
+
+ANGLE_RAD_2D returns the angle in radians swept out between two rays in 2D.
+
+Discussion:
+
+Except for the zero angle case, it should be true that
+
+ANGLE_RAD_2D(X1,Y1,X2,Y2,X3,Y3)
++ ANGLE_RAD_2D(X3,Y3,X2,Y2,X1,Y1) = 2 * PI
+
+Modified:
+
+19 April 1999
+
+Author:
+
+John Burkardt
+
+Parameters:
+
+Input, float X1, Y1, X2, Y2, X3, Y3, define the rays
+( X1-X2, Y1-Y2 ) and ( X3-X2, Y3-Y2 ) which in turn define the
+angle, counterclockwise from ( X1-X2, Y1-Y2 ).
+
+Output, float ANGLE_RAD_2D, the angle swept out by the rays, measured
+in radians. 0 <= ANGLE_DEG_2D < 2 PI. If either ray has zero length,
+then ANGLE_RAD_2D is set to 0.
+*/
+
+static float AngleRad2d( float x1, float y1, float x3, float y3 )
{
- //returns false if it believes the end result can't be obtained by pure application of velocity (collides into somthing that it can't climb up)
- //used as a way to check if it needs to hack getting there like in jumping
-
- uint32_t collideFlags =
- 1<IsSeeking())
- {
- collideFlags|=(1< DynamicHits;
- int NumberOfHits=fCore->SweepControllerPath(startPos, desiredPos, true, true, collideFlags, DynamicHits);
-
- hsPoint3 stepFromPoint;
- hsVector3 movementdir(&startPos, &desiredPos);
- movementdir.Normalize();
- if(NumberOfHits)
- {
- hsPoint3 initBottomPos;
- fCore->GetPositionSim(initBottomPos);
- std::multiset< plControllerSweepRecord >::iterator cur;
- hsVector3 testLength(desiredPos - startPos);
- bool freeMove=true;
- for(cur = DynamicHits.begin(); cur != DynamicHits.end(); cur++)
- {
- if(movementdir.InnerProduct(cur->Norm)>0.01f)
- {
- hsVector3 topOfBottomHemAtTimeT=hsVector3(initBottomPos + testLength * cur->TimeHit );
- topOfBottomHemAtTimeT.fZ = topOfBottomHemAtTimeT.fZ + fCore->GetControllerWidth();
- if(cur->locHit.fZ <= (topOfBottomHemAtTimeT.fZ -.5f))
- {
- hitBottomOfCapsule=true;
- hsVector3 norm= hsVector3(-1*(cur->locHit-topOfBottomHemAtTimeT));
- norm.Normalize();
- IAddContactNormals(norm);
- }
- else
- {
- return false;
- }
- }
+ float value;
+ float x;
+ float y;
- }
- return true;
+ x = ( x1 ) * ( x3 ) + ( y1 ) * ( y3 );
+ y = ( x1 ) * ( y3 ) - ( y1 ) * ( x3 );
+
+ if ( x == 0.0 && y == 0.0 ) {
+ value = 0.0;
}
else
{
- return true;
- }
-
-}
-void plRidingAnimatedPhysicalStrategy::Update(float delSecs)
-{
- if (!fCore->IsEnabled() || fCore->IsKinematic())
- {
- fCore->UpdateSubstepNonPhysical();
- return;
- }
- fCore->CheckAndHandleAnyStateChanges();
-}
-void plRidingAnimatedPhysicalStrategy::PostStep(float delSecs)
-{
- if(!(!fCore->IsEnabled() || fCore->IsKinematic()))
- {
- if (!fGroundHit && !fFalseGround)
- fTimeInAir += delSecs;
- else
- fTimeInAir = 0.f;
- hsVector3 AchievedLinearVelocity, LinearVelocity;
- AchievedLinearVelocity = fCore->GetLinearVelocity();
- float AngularVelocity=fCore->GetAngularVelocity();
- fCore->OverrideAchievedVelocity(AchievedLinearVelocity);
- plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
- if (so)
+ value = atan2 ( y, x );
+
+ if ( value < 0.0 )
{
- fCore->UpdateControllerAndPhysicalRep();
- if (AngularVelocity != 0.f)
- {
- float deltaAngle=AngularVelocity*delSecs;
- fCore->IncrementAngle( deltaAngle);
- }
- fCore->UpdateWorldRelativePos();
- fCore->SendCorrectionMessages();
+ value = (float)(value + TWO_PI);
}
- LinearVelocity.Set(0.f, 0.f, 0.f);
- AngularVelocity = 0.f;
- fCore->SetVelocities(LinearVelocity, AngularVelocity);
}
- fStartJump = false;
+ return value;
}
+
diff --git a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h
index bb2c13cd..b0c3f9a7 100644
--- a/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h
+++ b/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h
@@ -41,310 +41,286 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
#ifndef PLPHYSICALCONTROLLERCORE_H
#define PLPHYSICALCONTROLLERCORE_H
+
#include "hsGeometry3.h"
#include "hsMatrix44.h"
+#include "hsQuat.h"
#include "hsTemplates.h"
#include "pnKeyedObject/plKey.h"
#include "plPhysical/plSimDefs.h"
-#include "pnMessage/plMessage.h"
-
-#include "hsQuat.h"
-#define PHYSX_ONLY_TRIGGER_FROM_KINEMATIC 1
-#define kSLOPELIMIT (cosf(hsDegreesToRadians(45.f)))
+#include
class plCoordinateInterface;
class plPhysical;
-class plPXPhysical;
+class plMovementStrategy;
+class plAGApplicator;
class plSwimRegionInterface;
-//Replacement for for plPhysicalController stripped out some walk specific code
-//plPhysicalControllerCore needs to have movement strategies registered to it these will then
-//be called by the controller during the simulation steps. The Strategies need to at least have an
-// Apply and Update definition. Everything else should be movement specific. I hope to come back and
-//and refactor when I have time this in the future.
-enum plControllerCollisionFlags
-{
- kSides=1,
- kTop= (1<<1),
- kBottom=(1<<2),
-};
-class plMovementStrategySimulationInterface
-{
-public:
+#define kSlopeLimit (cosf(hsDegreesToRadians(55.f)))
- virtual void Apply(float delSecs)=0;
- virtual void Update(float delSecs)=0;
- //most strategies don't require this. Only the ones that require behavior like a physical or need
- //something after the sim step. this used to be taken care of by Update, but this was moved to take care of
- //some of the frame lag
- virtual void PostStep(float delSecs){};
- virtual void IAddContactNormals(hsVector3& vec){fContactNormals.Append(vec);}
- virtual void AddOnTopOfObject(plPhysical* phys){ fOnTopOf.Append(phys);}
- virtual void LeaveAge()
- {
- fContactNormals.SetCount(0);
- fOnTopOf.SetCount(0);
- }
-protected:
- hsTArray fContactNormals;
- hsTArray fOnTopOf;
+enum plControllerCollisionFlags
+{
+ kSides = 1,
+ kTop = (1 << 1),
+ kBottom = (1 << 2)
};
-class plControllerSweepRecord
+struct plControllerSweepRecord
{
-public:
plPhysical *ObjHit;
- hsPoint3 locHit;//World space
- float TimeHit;//Normalized between 0 and 1
- hsVector3 Norm;
+ hsPoint3 Point;
+ hsVector3 Normal;
};
-bool operator<(const plControllerSweepRecord left, const plControllerSweepRecord right);
+
class plPhysicalControllerCore
{
public:
- virtual ~plPhysicalControllerCore();
- virtual void Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults)=0;
- virtual void SetMovementSimulationInterface(plMovementStrategySimulationInterface* strat){fMovementInterface=strat;}
- virtual void Apply(float delSecs);
- virtual void Update(float delSecs);
- virtual void PostStep(float delSecs);
- // A disabled avatar doesn't move or accumulate air time if he's off the ground.
+ plPhysicalControllerCore(plKey ownerSceneObject, float height, float radius);
+ virtual ~plPhysicalControllerCore() { }
+
+ // An ArmatureMod has its own idea about when physics should be enabled/disabled.
+ // Use plArmatureModBase::EnablePhysics() instead.
virtual void Enable(bool enable) = 0;
- virtual bool IsEnabled() {return fEnabled;}
- virtual plKey GetSubworld() {return fWorldKey;}
+ virtual bool IsEnabled() { return fEnabled; }
+
+ // Subworld
+ virtual plKey GetSubworld() { return fWorldKey; }
virtual void SetSubworld(plKey world) = 0;
- virtual const plCoordinateInterface* GetSubworldCI() const = 0;
+ virtual const plCoordinateInterface* GetSubworldCI();
+
// For the avatar SDL only
virtual void GetState(hsPoint3& pos, float& zRot) = 0;
virtual void SetState(const hsPoint3& pos, float zRot) = 0;
- // kinematic stuff .... should be just for when playing a behavior...
- virtual void Kinematic(bool state) = 0;
- virtual bool IsKinematic() = 0;
- virtual void GetKinematicPosition(hsPoint3& pos) = 0;
- virtual const hsMatrix44& GetPrevSubworldW2L() = 0;
- //when seeking no longer want to interact with exclusion regions
- virtual void SetSeek(bool seek){fSeeking=seek;}
- virtual bool IsSeeking(){return fSeeking;}
- static plPhysicalControllerCore* Create(plKey ownerSO, float height, float radius);
- virtual plMovementStrategySimulationInterface* GetMovementInterface(){return fMovementInterface;}
- plPhysicalControllerCore(plKey ownerSceneObject, float height, float radius);
- virtual plKey GetOwner(){return fOwner;};
- // Set the LOS DB this avatar will be in (only one)
- virtual void SetLOSDB(plSimDefs::plLOSDB losDB) { fLOSDB = losDB; } ;
- virtual plSimDefs::plLOSDB GetLOSDB() {return fLOSDB ; }
- virtual const hsMatrix44& GetLastGlobalLoc()=0;
- virtual void SetKinematicLoc(const hsMatrix44& l2w)=0;
- virtual void SetGlobalLoc(const hsMatrix44& l2w)=0;
- virtual bool IsEnabledChanged(){return fEnableChanged;}
- virtual void HandleEnableChanged()=0;
- virtual bool IsKinematicChanged(){return fKinematicChanged;}
- virtual void GetPositionSim(hsPoint3& pos)=0;
- virtual void HandleKinematicChanged()=0;
- virtual bool IsKinematicEnableNextUpdate(){return fKinematicEnableNextUpdate;}
- virtual void HandleKinematicEnableNextUpdate()=0;
- virtual void MoveKinematicToController(hsPoint3& pos)=0;
- virtual void UpdateControllerAndPhysicalRep()=0;
- virtual void CheckAndHandleAnyStateChanges();
- virtual void UpdateSubstepNonPhysical();
- virtual const hsPoint3& GetLocalPosition()=0;
- const hsQuat& GetLocalRotation() { return fLocalRotation; }
- virtual void MoveActorToSim();
-
- virtual void OverrideAchievedVelocity(hsVector3 newAchievedVel)
- {//because of things like superjumps this is needed I'd rather not, but can't help it
- fAchievedLinearVelocity=newAchievedVel;
- }
- //any clean up for the controller should go here
- virtual void LeaveAge()=0;
- hsVector3 DisplacementLastStep(){return fDisplacementThisStep;}
- hsVector3 MeanVelocityForLastStep()
- {
- hsVector3 vel=fDisplacementThisStep;
- return vel/fSimLength;
- }
- void SendCorrectionMessages();
+
+ // The LOS DB this avatar is in (only one)
+ virtual plSimDefs::plLOSDB GetLOSDB() { return fLOSDB; }
+ virtual void SetLOSDB(plSimDefs::plLOSDB losDB) { fLOSDB = losDB; }
+
+ // Movement strategy
+ virtual void SetMovementStrategy(plMovementStrategy* strategy) = 0;
+
+ // Global location
+ virtual const hsMatrix44& GetLastGlobalLoc() { return fLastGlobalLoc; }
+ virtual void SetGlobalLoc(const hsMatrix44& l2w) = 0;
+
+ // Local sim position
+ virtual void GetPositionSim(hsPoint3& pos) = 0;
+
+ // Move kinematic controller
+ virtual void Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults) = 0;
+
+ // Set linear velocity on dynamic controller
+ virtual void SetLinearVelocitySim(const hsVector3& linearVel) = 0;
+
+ // 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) = 0;
+
+ // any clean up for the controller should go here
+ virtual void LeaveAge() = 0;
+
+ // Local rotation
+ const hsQuat& GetLocalRotation() const { return fLocalRotation; }
void IncrementAngle(float deltaAngle);
- void UpdateWorldRelativePos();
- virtual void SetLinearVelocity(const hsVector3& linearVel){fLinearVelocity=linearVel;}
- //should actually be a 3 vector but everywhere else it is assumed to be just around Z
- virtual void SetAngularVelocity(const float angvel){ fAngularVelocity=angvel;}
- virtual void SetVelocities(const hsVector3& linearVel, float angVel)
- {
- fLinearVelocity=linearVel;
- fAngularVelocity=angVel;
- }
-
- virtual const hsVector3& GetLinearVelocity() ;
- virtual float GetAngularVelocity(){return fAngularVelocity;}
- virtual const hsVector3& GetAchievedLinearVelocity()const {return fAchievedLinearVelocity;}
- plPhysical* GetPushingPhysical();
- bool GetFacingPushingPhysical();
- virtual void SetPushingPhysical(plPhysical* pl){fPushingPhysical=pl;}
- virtual void SetFacingPushingPhysical(bool ans){fFacingPushingPhysical=ans;}
- //To be Used during runtime conversions, say to switch a tall controller to a ball for swimming
- virtual void SetControllerDimensions(float radius, float height)=0;
- virtual float GetControllerWidth(){return fRadius;}
- virtual float GetControllerHeight(){return fHeight;}
- virtual void ResetAchievedLinearVelocity()
- {
- fAchievedLinearVelocity.Set(0.f,0.f,0.f);
- }
- virtual int SweepControllerPath(const hsPoint3& startPos,const hsPoint3& endPos, bool vsDynamics, bool vsStatics, uint32_t& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut)=0;
- //this should only be used to force a move it could place your head into a wall and that would be good
- virtual float GetHeight() {return fHeight;}
- virtual float GetRadius() {return fRadius;}
- //Wether the avatar thing has mass and forces things down or not, and changes the way things move
- //This is an attempt fix things like riding on an animated physical
- virtual void BehaveLikeAnimatedPhysical(bool actLikeAnAnimatedPhys)=0;
- virtual bool BehavingLikeAnAnimatedPhysical()=0;
+
+ // Linear velocity
+ void SetLinearVelocity(const hsVector3& linearVel) { fLinearVelocity = linearVel; }
+ const hsVector3& GetLinearVelocity() const { return fLinearVelocity; }
+
+ // Acheived linear velocity
+ const hsVector3& GetAchievedLinearVelocity() const { return fAchievedLinearVelocity; }
+ void OverrideAchievedLinearVelocity(const hsVector3& linearVel) { fAchievedLinearVelocity = linearVel; }
+ void ResetAchievedLinearVelocity() { fAchievedLinearVelocity.Set(0.f, 0.f, 0.f); }
+
+ // SceneObject
+ plKey GetOwner() { return fOwner; }
+
+ // When seeking no longer want to interact with exclude regions
+ void SetSeek(bool seek) { fSeeking = seek; }
+ bool IsSeeking() const { return fSeeking; }
+
+ // Pushing physical
+ plPhysical* GetPushingPhysical() const { return fPushingPhysical; }
+ void SetPushingPhysical(plPhysical* phys) { fPushingPhysical = phys; }
+ bool GetFacingPushingPhysical() const { return fFacingPushingPhysical; }
+ void SetFacingPushingPhysical(bool facing) { fFacingPushingPhysical = facing; }
+
+ // Controller dimensions
+ float GetRadius() const { return fRadius; }
+ float GetHeight() const { return fHeight; }
+
+ // Create a new controller instance - Implemented in the physics system
+ static plPhysicalControllerCore* Create(plKey ownerSO, float height, float radius, bool human);
+
protected:
-
+ virtual void IHandleEnableChanged() = 0;
+
+ void IApply(float delSecs);
+ void IUpdate(int numSubSteps, float alpha);
+ void IUpdateNonPhysical(float alpha);
+
+ void ISendCorrectionMessages(bool dirtySynch = false);
+
plKey fOwner;
+ plKey fWorldKey;
+
float fHeight;
float fRadius;
- plKey fWorldKey;
+
plSimDefs::plLOSDB fLOSDB;
- bool fSeeking;
- bool fEnabled;
- bool fEnableChanged;
- bool fKinematic;
- bool fKinematicEnableNextUpdate;
- bool fKinematicChanged;
- plMovementStrategySimulationInterface* fMovementInterface;
- hsMatrix44 fLastGlobalLoc;
- hsPoint3 fLocalPosition;
+
+ plMovementStrategy* fMovementStrategy;
+
+ float fSimLength;
+
hsQuat fLocalRotation;
+ hsPoint3 fLocalPosition;
+ hsPoint3 fLastLocalPosition;
+
+ hsMatrix44 fLastGlobalLoc;
hsMatrix44 fPrevSubworldW2L;
- hsVector3 fDisplacementThisStep;
- float fSimLength;
-
- //physical properties
+
hsVector3 fLinearVelocity;
- float fAngularVelocity;
hsVector3 fAchievedLinearVelocity;
+
plPhysical* fPushingPhysical;
bool fFacingPushingPhysical;
- bool fNeedsResize;
+
+ bool fSeeking;
+ bool fEnabled;
+ bool fEnableChanged;
};
-class plMovementStrategy: public plMovementStrategySimulationInterface
+class plMovementStrategy
{
public:
- virtual void SetControllerCore(plPhysicalControllerCore* core)
- {
- fCore=core;
- fCore->SetMovementSimulationInterface(this);
- }
- virtual void RefreshConnectionToControllerCore()
- {
- fCore->SetMovementSimulationInterface(this);
- //fCore->SetControllerDimensions(fPreferedControllerWidth,fPreferedControllerHeight);
- fCore->BehaveLikeAnimatedPhysical(this->IRequireBehaviourLikeAnAnimatedPhysical());
- }
- plMovementStrategy(plPhysicalControllerCore* core);
- //should actually be a 3 vector but everywhere else it is assumed to be just around Z
- virtual void SetLinearAcceleration(const hsVector3& accel){fLinearAcceleration=accel;}
- virtual const hsVector3& GetLinearAcceleration()const{return fLinearAcceleration;}
- //should actually be a 3 vector but everywhere else it is assumed to be just around Z
- virtual void ResetAchievedLinearVelocity()
- {
- hsVector3 AchievedLinearVelocity(0.f,0.f,0.f);
- if(fCore)fCore->OverrideAchievedVelocity(AchievedLinearVelocity);
- }
-//proxy functions for Controller Core
- virtual float GetAirTime() const { return fTimeInAir; }
- virtual void ResetAirTime() { fTimeInAir = 0.f; }
-
+ plMovementStrategy(plPhysicalControllerCore* controller);
+ virtual ~plMovementStrategy() { }
+
+ virtual void Apply(float delSecs) = 0;
+ virtual void Update(float delSecs) { }
+
+ virtual void AddContactNormals(hsVector3& vec) { }
+ virtual void Reset(bool newAge);
+ virtual bool IsKinematic() { return true; }
+
protected:
- virtual bool IRequireBehaviourLikeAnAnimatedPhysical()=0;
- virtual void IApplyKinematic();
- plPhysicalControllerCore* fCore;
- hsVector3 fLinearAcceleration;
- float fAngularAcceleration;
- plKey fOwner;
- static const float kAirTimeThreshold;
- float fTimeInAir;
- float fPreferedControllerWidth;
- float fPreferedControllerHeight;
-
+ plPhysicalControllerCore* fController;
+};
+class plAnimatedMovementStrategy : public plMovementStrategy
+{
+public:
+ plAnimatedMovementStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller);
+ virtual ~plAnimatedMovementStrategy() { }
+
+ virtual void RecalcVelocity(double timeNow, float elapsed, bool useAnim = true);
+ void SetTurnStrength(float val) { fTurnStr = val; }
+ float GetTurnStrength() const { return fTurnStr; }
+
+private:
+ void IRecalcLinearVelocity(float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat);
+ void IRecalcAngularVelocity(float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat);
+
+ plAGApplicator* fRootApp;
+ hsVector3 fAnimLinearVel;
+ float fAnimAngularVel;
+ float fTurnStr;
};
-class plWalkingStrategy: public plMovementStrategy
+class plWalkingStrategy : public plAnimatedMovementStrategy
{
public:
- plWalkingStrategy(plPhysicalControllerCore* core):plMovementStrategy(core)
- {
- fGroundHit=false;
- fFalseGround=false;
- fHitHead=false;
- fCore->SetMovementSimulationInterface(this);
- fPreferedControllerWidth=core->GetControllerWidth();
- fPreferedControllerHeight=core->GetControllerHeight();
- fOnTopOfAnimatedPhysLastFrame=false;
- }
- virtual ~plWalkingStrategy(){};
+ plWalkingStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller);
+ virtual ~plWalkingStrategy() { }
+
virtual void Apply(float delSecs);
- virtual void Update(float delSecs);
+ virtual void Update(float delSecs);
+
+ virtual void AddContactNormals(hsVector3& vec);
+ virtual void Reset(bool newAge);
+ virtual void RecalcVelocity(double timeNow, float elapsed, bool useAnim = true);
+
+ bool HitGroundInThisAge() const { return fHitGroundInThisAge; }
bool IsOnGround() const { return fTimeInAir < kAirTimeThreshold || fFalseGround; }
- bool IsOnFalseGround() const { return fFalseGround && !fGroundHit; }
- void GroundHit() { fGroundHit = true; }
- virtual void IAddContactNormals(hsVector3& vec);
- virtual void StartJump(){};
-
+
+ float GetAirTime() const { return fTimeInAir; }
+ void ResetAirTime() { fTimeInAir = 0.0f; }
+
+ float GetImpactTime() const { return fImpactTime; }
+ const hsVector3& GetImpactVelocity() const { return fImpactVelocity; }
+
+ bool EnableControlledFlight(bool status);
+ bool IsControlledFlight() const { return fControlledFlight != 0; }
+
+ plPhysical* GetPushingPhysical() const;
+ bool GetFacingPushingPhysical() const;
protected:
-
- void ICheckForFalseGround();
+ static const float kAirTimeThreshold;
+ static const float kControlledFlightThreshold;
+
+ hsTArray fSlidingNormals;
+
+ hsVector3 fImpactVelocity;
+ float fImpactTime;
+
+ float fTimeInAir;
+
+ float fControlledFlightTime;
+ int fControlledFlight;
+
bool fGroundHit;
bool fFalseGround;
- bool fHitHead;
- bool fOnTopOfAnimatedPhysLastFrame;
- hsTArray fPrevSlidingNormals;
- virtual bool IRequireBehaviourLikeAnAnimatedPhysical(){return true;}
+ bool fHeadHit;
+ bool fSliding;
+ bool fClearImpact;
+ bool fHitGroundInThisAge;
};
-class plSwimStrategy: public plMovementStrategy
+
+class plSwimStrategy : public plAnimatedMovementStrategy
{
public:
- plSwimStrategy(plPhysicalControllerCore *core);
- virtual ~plSwimStrategy(){};
- void SetSurface(plSwimRegionInterface *region, float surfaceHeight);
+ plSwimStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller);
+ virtual ~plSwimStrategy() { }
+
virtual void Apply(float delSecs);
- virtual void Update(float delSecs);
- float GetBuoyancy() { return fBuoyancy; }
- bool IsOnGround() { return fOnGround; }
- bool HadContacts() { return fHadContacts; }
- virtual void IAddContactNormals(hsVector3& vec);
+
+ virtual void AddContactNormals(hsVector3& vec);
+
+ void SetSurface(plSwimRegionInterface* region, float surfaceHeight);
+
+ float GetBuoyancy() const { return fBuoyancy; }
+ bool IsOnGround() const { return fOnGround; }
+ bool HadContacts() const { return fHadContacts; }
+
protected:
- virtual bool IRequireBehaviourLikeAnAnimatedPhysical(){return true;}
-private:
void IAdjustBuoyancy();
+
float fBuoyancy;
- bool fOnGround;
- bool fHadContacts;
float fSurfaceHeight;
+
plSwimRegionInterface *fCurrentRegion;
+
+ bool fOnGround;
+ bool fHadContacts;
};
-class plRidingAnimatedPhysicalStrategy : public plWalkingStrategy
+
+class plDynamicWalkingStrategy : public plWalkingStrategy
{
public:
- plRidingAnimatedPhysicalStrategy(plPhysicalControllerCore *core ) :
- fNeedVelocityOverride(false),fStartJump(false),plWalkingStrategy(core){};
- virtual ~plRidingAnimatedPhysicalStrategy(){};
+ plDynamicWalkingStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller);
+ virtual ~plDynamicWalkingStrategy() { }
+
virtual void Apply(float delSecs);
- virtual void Update(float delSecs);
- virtual void PostStep(float delSecs);
- bool IsOnGround() const { return fTimeInAir < kAirTimeThreshold || fFalseGround; }
- bool IsOnFalseGround() const { return fFalseGround && !fGroundHit; }
- void GroundHit() { fGroundHit = true; }
- virtual void StartJump(){fStartJump = true;}
+
+ virtual bool IsKinematic() { return false; }
+
protected:
- virtual bool IRequireBehaviourLikeAnAnimatedPhysical(){return false;}
- bool ICheckMove(const hsPoint3& startPos, const hsPoint3& desiredPos);
- bool fNeedVelocityOverride;
- hsVector3 fOverrideVelocity;
- bool fStartJump;
+ bool ICheckForGround(float& zVelocity);
};
+
#endif// PLPHYSICALCONTROLLERCORE_H
+
diff --git a/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp b/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp
index 798e6c62..586c8301 100644
--- a/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp
+++ b/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp
@@ -70,7 +70,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAvatar/plArmatureMod.h"
#include "plAvatar/plAvBrain.h"
#include "plAvatar/plAvatarMgr.h"
-#include "plAvatar/plAvCallbackAction.h"
+#include "plAvatar/plPhysicalControllerCore.h"
#include "plModifier/plInterfaceInfoModifier.h"
#include "pnModifier/plLogicModBase.h"
#include "plVault/plVault.h"
diff --git a/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp b/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp
index 9de08fbc..85cb8b2b 100644
--- a/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp
+++ b/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp
@@ -54,7 +54,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plMessage/plAvatarMsg.h"
#include "plPhysical.h"
#include "plPhysical/plSimDefs.h"
-#include "plAvatar/plAvCallbackAction.h"
#include "plAvatar/plAvBrainGeneric.h"
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/plPXPhysical.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp
index 32d6ba18..55258d08 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.cpp
@@ -138,14 +138,10 @@ plPXPhysical::plPXPhysical()
, fSceneNode(nil)
, fWorldKey(nil)
, fSndGroup(nil)
- , fWorldHull(nil)
- , fSaveTriangles(nil)
- , fHullNumberPlanes(0)
, fMass(0.f)
, fWeWereHit(false)
, fHitForce(0,0,0)
, fHitPos(0,0,0)
- , fInsideConvexHull(false)
{
}
@@ -190,11 +186,6 @@ plPXPhysical::~plPXPhysical()
plSimulationMgr::GetInstance()->ReleaseScene(fWorldKey);
}
- if (fWorldHull)
- delete [] fWorldHull;
- if (fSaveTriangles)
- delete [] fSaveTriangles;
-
delete fProxyGen;
// remove sdl modifier
@@ -206,155 +197,6 @@ plPXPhysical::~plPXPhysical()
delete fSDLMod;
}
-static void MakeBoxFromHull(NxConvexMesh* convexMesh, NxBoxShapeDesc& box)
-{
- NxConvexMeshDesc desc;
- convexMesh->saveToDesc(desc);
-
- float minX, minY, minZ, maxX, maxY, maxZ;
- minX = minY = minZ = FLT_MAX;
- maxX = maxY = maxZ = -FLT_MAX;
-
- for (int i = 0; i < desc.numVertices; i++)
- {
- float* point = (float*)(((char*)desc.points) + desc.pointStrideBytes*i);
- float x = point[0];
- float y = point[1];
- float z = point[2];
-
- minX = hsMinimum(minX, x);
- minY = hsMinimum(minY, y);
- minZ = hsMinimum(minZ, z);
- maxX = hsMaximum(maxX, x);
- maxY = hsMaximum(maxY, y);
- maxZ = hsMaximum(maxZ, z);
- }
-
- float xWidth = maxX - minX;
- float yWidth = maxY - minY;
- float zWidth = maxZ - minZ;
- box.dimensions.x = xWidth / 2;
- box.dimensions.y = yWidth / 2;
- box.dimensions.z = zWidth / 2;
-
- //hsMatrix44 mat;
- //box.localPose.getRowMajor44(&mat.fMap[0][0]);
- hsPoint3 trans(minX + (xWidth / 2), minY + (yWidth / 2), minZ + (zWidth / 2));
- //mat.SetTranslate(&trans);
- //box.localPose.setRowMajor44(&mat.fMap[0][0]);
-
- hsMatrix44 boxL2W;
- boxL2W.Reset();
- boxL2W.SetTranslate(&trans);
- plPXConvert::Matrix(boxL2W, box.localPose);
-
-}
-
-void plPXPhysical::IMakeHull(NxConvexMesh* convexMesh, hsMatrix44 l2w)
-{
- NxConvexMeshDesc desc;
- convexMesh->saveToDesc(desc);
-
- // make sure there are some triangles to work with
- if (desc.numTriangles == 0)
- return;
-
- // get rid of any we may have already had
- if (fSaveTriangles)
- delete [] fSaveTriangles;
-
- fHullNumberPlanes = desc.numTriangles;
- fSaveTriangles = new hsPoint3[fHullNumberPlanes*3];
-
- for (int i = 0; i < desc.numTriangles; i++)
- {
- uint32_t* triangle = (uint32_t*)(((char*)desc.triangles) + desc.triangleStrideBytes*i);
- float* vertex1 = (float*)(((char*)desc.points) + desc.pointStrideBytes*triangle[0]);
- float* vertex2 = (float*)(((char*)desc.points) + desc.pointStrideBytes*triangle[1]);
- float* vertex3 = (float*)(((char*)desc.points) + desc.pointStrideBytes*triangle[2]);
- hsPoint3 pt1(vertex1[0],vertex1[1],vertex1[2]);
- hsPoint3 pt2(vertex2[0],vertex2[1],vertex2[2]);
- hsPoint3 pt3(vertex3[0],vertex3[1],vertex3[2]);
-
- fSaveTriangles[(i*3)+0] = pt1;
- fSaveTriangles[(i*3)+1] = pt2;
- fSaveTriangles[(i*3)+2] = pt3;
- }
-}
-
-void plPXPhysical::ISetHullToWorldWTriangles()
-{
- // if we have a detector hull and the world hasn't been updated
- if (fWorldHull == nil)
- {
- fWorldHull = new hsPlane3[fHullNumberPlanes];
- // use the local2world from the physics engine so that it matches the transform of the positions from the triggerees
- hsMatrix44 l2w;
- plPXConvert::Matrix(fActor->getGlobalPose(), l2w);
- int i;
- for( i = 0; i < fHullNumberPlanes; i++ )
- {
- hsPoint3 pt1 = fSaveTriangles[i*3];
- hsPoint3 pt2 = fSaveTriangles[(i*3)+1];
- hsPoint3 pt3 = fSaveTriangles[(i*3)+2];
-
- // local to world translation
- pt1 = l2w * pt1;
- pt2 = l2w * pt2;
- pt3 = l2w * pt3;
-
- hsPlane3 plane(&pt1, &pt2, &pt3);
- fWorldHull[i] = plane;
- }
- }
-}
-
-
-bool plPXPhysical::IsObjectInsideHull(const hsPoint3& pos)
-{
- if (fSaveTriangles)
- {
- ISetHullToWorldWTriangles();
- int i;
- for( i = 0; i < fHullNumberPlanes; i++ )
- {
- if (!ITestPlane(pos, fWorldHull[i]))
- return false;
- }
- return true;
- }
- return false;
-}
-
-bool plPXPhysical::Should_I_Trigger(bool enter, hsPoint3& pos)
-{
- // see if we are inside the detector hull, if so, then don't trigger
- bool trigger = false;
- bool inside = IsObjectInsideHull(pos);
- if ( !inside)
- {
- trigger = true;
- fInsideConvexHull = enter;
- }
- else
- {
- // catch those rare cases on slow machines that miss the collision before avatar penetrated the face
- if (enter && !fInsideConvexHull)
- {
-#ifdef PHYSX_SAVE_TRIGGERS_WORKAROUND
- trigger = true;
- fInsideConvexHull = enter;
- DetectorLogSpecial("**>Saved a missing enter collision: %s",GetObjectKey()->GetName().c_str());
-#else
- DetectorLogSpecial("**>Could have saved a missing enter collision: %s",GetObjectKey()->GetName().c_str());
-#endif PHYSX_SAVE_TRIGGERS_WORKAROUND
- }
- }
-
- return trigger;
-}
-
-
bool plPXPhysical::Init(PhysRecipe& recipe)
{
bool startAsleep = false;
@@ -388,29 +230,6 @@ bool plPXPhysical::Init(PhysRecipe& recipe)
}
break;
case plSimDefs::kHullBounds:
- // FIXME PHYSX - Remove when hull detection is fixed
- // If this is read time (ie, meshStream is nil), turn the convex hull
- // into a box. That way the data won't have to change when convex hulls
- // actually work right.
- if (fGroup == plSimDefs::kGroupDetector && recipe.meshStream == nil)
- {
-#ifdef USE_BOXES_FOR_DETECTOR_HULLS
- MakeBoxFromHull(recipe.convexMesh, boxDesc);
- plSimulationMgr::GetInstance()->GetSDK()->releaseConvexMesh(*recipe.convexMesh);
- boxDesc.group = fGroup;
- actorDesc.shapes.push_back(&boxDesc);
-#else
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
- // make a hull of planes for testing IsInside
- IMakeHull(recipe.convexMesh,recipe.l2s);
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
- convexShapeDesc.meshData = recipe.convexMesh;
- convexShapeDesc.userData = recipe.meshStream;
- convexShapeDesc.group = fGroup;
- actorDesc.shapes.pushBack(&convexShapeDesc);
-#endif // USE_BOXES_FOR_DETECTOR_HULLS
- }
- else
{
convexShapeDesc.meshData = recipe.convexMesh;
convexShapeDesc.userData = recipe.meshStream;
@@ -669,9 +488,6 @@ void plPXPhysical::IEnable(bool enable)
{
fActor->clearActorFlag(NX_AF_DISABLE_COLLISION);
- // PHYSX FIXME - after re-enabling a possible detector, we need to check to see if any avatar is already in the PhysX turdy hull detector region
- plSimulationMgr::GetInstance()->UpdateAvatarInDetector(fWorldKey, this);
-
if (fActor->isDynamic())
fActor->clearBodyFlag(NX_BF_FROZEN);
else
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h
index 693fbc97..07f407e4 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysical.h
@@ -156,11 +156,6 @@ public:
virtual uint16_t GetAllLOSDBs() { return fLOSDBs; }
virtual bool IsInLOSDB(uint16_t flag) { return hsCheckBits(fLOSDBs, flag); }
- virtual bool DoDetectorHullWorkaround() { return fSaveTriangles ? true : false; }
- virtual bool Should_I_Trigger(bool enter, hsPoint3& pos);
- virtual bool IsObjectInsideHull(const hsPoint3& pos);
- virtual void SetInsideConvexHull(bool inside) { fInsideConvexHull = inside; }
-
virtual plKey GetWorldKey() const { return fWorldKey; }
virtual plPhysicalSndGroup* GetSoundGroup() const { return fSndGroup; }
@@ -201,14 +196,6 @@ protected:
/** Handle messages about our references. */
bool HandleRefMsg(plGenRefMsg * refM);
- /////////////////////////////////////////////////////////////
- //
- // WORLDS, SUBWORLDS && CONTEXTS
- //
- /////////////////////////////////////////////////////////////
-
- void IConvertGroups(uint32_t memberOf, uint32_t reportsOn, uint32_t collideWith);
-
/** See if the object is in a valid, non-overlapping position.
A valid overlap is one which is approved by the collision
masking code, i.e. my memberOf has no intersection with your
@@ -236,8 +223,6 @@ protected:
// Enable/disable collisions and dynamic movement
void IEnable(bool enable);
- void IMakeHull(NxConvexMesh* convexMesh, hsMatrix44 l2w);
-
NxActor* fActor;
plKey fWorldKey; // either a subworld or nil
@@ -251,24 +236,6 @@ protected:
plKey fObjectKey; // the key to our scene object
plKey fSceneNode; // the room we're in
- // PHYSX FIXME - need to create a plasma hull so that we can determine if inside
- hsPlane3* fWorldHull;
- uint32_t fHullNumberPlanes;
- hsPoint3* fSaveTriangles;
- bool fInsideConvexHull;
- void ISetHullToWorldWTriangles();
- inline bool ITestPlane(const hsPoint3 &pos, const hsPlane3 &plane)
- {
- float dis = plane.fN.InnerProduct(pos);
- dis += plane.fD;
- if (dis == 0.f)
- return false;
- if( dis >= 0.f )
- return false;
-
- return true;
- }
-
// we need to remember the last matrices we sent to the coordinate interface
// so that we can recognize them when we send them back and not reapply them,
// which would reactivate our body. inelegant but effective
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..ef595a72 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,35 @@ public:
{
return NX_ACTION_NONE;
}
+} gControllerHitReport;
-} gMyReport;
-
-
-plPhysicalControllerCore* plPhysicalControllerCore::Create(plKey ownerSO, float height, float width)
+plPhysicalControllerCore* plPhysicalControllerCore::Create(plKey ownerSO, float height, float width, bool human)
{
- // Test to see how many controller there already is
- if ( !plPXPhysicalControllerCore::fPXControllersMax || plPXPhysicalControllerCore::NumControllers() < plPXPhysicalControllerCore::fPXControllersMax )
+ if (!plPXPhysicalControllerCore::fPXControllersMax || gControllers.size() < plPXPhysicalControllerCore::fPXControllersMax)
{
- float radius = width / 2.f;
- float realHeight = height - width + kPhysicalHeightFudge;
- return new plPXPhysicalControllerCore(ownerSO, realHeight,radius);
+ float radius = width / 2.0f;
+ float realHeight = height - width;
+ return new plPXPhysicalControllerCore(ownerSO, realHeight, radius, human);
}
return nil;
}
-//Static Helper Func
-plPXPhysicalControllerCore* plPXPhysicalControllerCore::FindController(NxController* controller)
-{
- for (int i = 0; i < gControllers.size(); i++)
- {
- plPXPhysicalControllerCore* ac = gControllers[i];
- if (ac->fController == controller)
- return ac;
- }
- 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)
+plPXPhysicalControllerCore::plPXPhysicalControllerCore(plKey ownerSO, float height, float radius, bool human)
+ : plPhysicalControllerCore(ownerSO, height, radius),
+ fController(nil),
+ fActor(nil),
+ fProxyGen(nil),
+ fKinematicCCT(true),
+ fHuman(human)
{
- fLocalPosition.Set(0, 0, 0);
- fLocalRotation.Set(0, 0, 0, 1);
+ 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 +189,109 @@ 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);
- }
- }
- }
-}
+ IDeleteController();
-void plPXPhysicalControllerCore::ISetKinematicLoc(const hsMatrix44& l2w)
-{
- hsPoint3 kPos;
- // Update our subworld position and rotation
- const plCoordinateInterface* subworldCI = GetSubworldCI();
- if (subworldCI)
+ // Release any queued messages we may have
+ int numMsgs = fQueuedCollideMsgs.size();
+ if (numMsgs)
{
- const hsMatrix44& w2s = subworldCI->GetWorldToLocal();
- hsMatrix44 l2s = w2s * l2w;
+ for (int i = 0; i < numMsgs; ++i)
+ delete fQueuedCollideMsgs[i];
- l2s.GetTranslate(&kPos);
- }
- else
- {
- l2w.GetTranslate(&kPos);
+ fQueuedCollideMsgs.clear();
}
- hsMatrix44 w2l;
- l2w.GetInverse(&w2l);
- if (fProxyGen)
- fProxyGen->SetTransform(l2w, w2l);
-
- // 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
- {
- 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?");
-
- 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");
- }
-
- // 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");
+
+ // We need our real global location here, not the interpolated location
+ fLocalRotation.MakeMatrix(&fLastGlobalLoc);
+ fLastGlobalLoc.SetTranslate(&fLocalPosition);
+ if (fWorldKey)
+ {
+ hsMatrix44 prevSubL2W;
+ fPrevSubworldW2L.GetInverse(&prevSubL2W);
+ fLastGlobalLoc = prevSubL2W * fLastGlobalLoc;
+ }
+ // Update our scene object so the change isn't wiped out
+ plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded());
+ if (so)
+ {
+ hsMatrix44 globalLocInv;
+ fLastGlobalLoc.GetInverse(&globalLocInv);
+ so->SetTransform(fLastGlobalLoc, globalLocInv);
+ so->FlushTransform();
+ }
+
+ // 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);
+
+ fLastLocalPosition = fLocalPosition;
+
+ // Create new controller
+ ICreateController(fLocalPosition);
RebuildCache();
}
}
-const plCoordinateInterface* plPXPhysicalControllerCore::GetSubworldCI() const
-{
- if (fWorldKey)
- {
- plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded());
- if (so)
- return so->GetCoordinateInterface();
- }
- 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 +317,542 @@ 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 (fKinematicCCT != strategy->IsKinematic())
+ {
+ IDeleteController();
+ fKinematicCCT = !fKinematicCCT;
+ ICreateController(fLocalPosition);
+ }
+
+ fMovementStrategy = strategy;
+}
+
+void plPXPhysicalControllerCore::SetGlobalLoc(const hsMatrix44& l2w)
{
- if (fKinematic != state)
+ fLastGlobalLoc = l2w;
+
+ // Update our local position and rotation
+ hsPoint3 prevPosition = fLocalPosition;
+ const plCoordinateInterface* subworldCI = GetSubworldCI();
+ if (subworldCI)
{
- fKinematic = state;
- if (fKinematic)
+ 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)
+ {
+ hsVector3 disp(&fLocalPosition, &prevPosition);
+ if (disp.Magnitude() > 2.f)
{
- // 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
+ // Teleport the underlying actor most of the way
+ disp.Normalize();
+ disp *= 0.001f;
+
+ hsPoint3 teleportPos = fLocalPosition - disp;
+ NxVec3 pos(teleportPos.fX, teleportPos.fY, teleportPos.fZ + kPhysZOffset);
+ fActor->setGlobalPosition(pos);
}
+
+ NxExtendedVec3 extPos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kCCTZOffset);
+ fController->setPosition(extPos);
+ }
+ else
+ {
+ NxVec3 pos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kPhysZOffset);
+ if (fActor->readBodyFlag(NX_BF_KINEMATIC))
+ fActor->moveGlobalPosition(pos);
else
- {
- fKinematicChanged = true;
- }
+ fActor->setGlobalPosition(pos);
}
}
-bool plPXPhysicalControllerCore::IsKinematic()
-{
- return fKinematic;
-}
-void plPXPhysicalControllerCore::GetKinematicPosition(hsPoint3& pos)
+
+void plPXPhysicalControllerCore::GetPositionSim(hsPoint3& pos)
{
- pos.Set(-1,-1,-1);
- if ( fKinematicActor )
+ if (fKinematicCCT)
{
- NxVec3 klPos = fKinematicActor->getGlobalPosition();
- pos.Set(float(klPos.x), float(klPos.y), float(klPos.z) - kPhysZOffset);
+ const NxExtendedVec3& extPos = fController->getPosition();
+ pos.Set((float)extPos.x, (float)extPos.y, (float)extPos.z - kCCTZOffset);
}
-}
-void plPXPhysicalControllerCore::UpdatePoststep( float 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++)
+ else
{
- 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();
- }
+ 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);
+
+/*
+ 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;
+}
- uint32_t collideFlags =
- 1<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)
+
+ fDynamicHits.push_back(phys);
+}
+
+void plPXPhysicalControllerCore::Apply(float delSecs)
+{
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
{
- fHeight=fPreferedHeight;
- fRadius=fPreferedRadius;
- fController->setRadius(fRadius);
- fController->setHeight(fHeight);
-
- fNeedsResize=false;
+ 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();
}
-// delete[] response;
+ gRebuildCache = false;
}
-void plPXPhysicalControllerCore::SetControllerDimensions(float radius, float height)
+void plPXPhysicalControllerCore::Update(int numSubSteps, float alpha)
{
- fNeedsResize=false;
- if(fRadius!=radius)
+ 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
}
- if(fHeight!=height)
+}
+void plPXPhysicalControllerCore::UpdateNonPhysical(float alpha)
+{
+ plPXPhysicalControllerCore* controller;
+ int numControllers = gControllers.size();
+ for (int i = 0; i < numControllers; ++i)
{
- fNeedsResize=true;
+ controller = gControllers[i];
+ controller->IUpdateNonPhysical(alpha);
}
- fPreferedRadius=radius;
- fPreferedHeight=height;
}
-void plPXPhysicalControllerCore::LeaveAge()
+void plPXPhysicalControllerCore::RebuildCache() { gRebuildCache = true; }
+
+plPXPhysicalControllerCore* plPXPhysicalControllerCore::GetController(NxActor& actor)
{
- 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];
+ if (controller->fActor == &actor)
+ return controller;
+ }
+
+ return nil;
}
-int plPXPhysicalControllerCore::SweepControllerPath(const hsPoint3& startPos, const hsPoint3& endPos, bool vsDynamics, bool vsStatics,
- uint32_t& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut)
-{
- 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;
- NxVec3 vec;
- vec.x = endPos.fX - startPos.fX;
- vec.y = endPos.fY - startPos.fY;
- vec.z = endPos.fZ - startPos.fZ;
+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;
+ }
- 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++;
- }
- }
+ 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;
+ NxCapsuleShape* capShape = shape->isCapsule();
+ if (fHuman)
+ {
+ kineHeight += kPhysHeightCorrection;
+ capShape->setLocalPosition(NxVec3(0.0f, (kPhysHeightCorrection / 2.0f), 0.0f));
+ }
+ capShape->setDimensions(kineRadius, kineHeight);
+ }
+ 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 +872,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..70ff44d1 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,113 @@ public:
bool fOverlap;
};
#endif // PLASMA_EXTERNAL_RELEASE
+
class plPXPhysicalControllerCore: public plPhysicalControllerCore
{
- friend class PXControllerHitReportWalk;
public:
- plPXPhysicalControllerCore(plKey ownerSO, float height, float radius);
+ plPXPhysicalControllerCore(plKey ownerSO, float height, float radius, bool human);
~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;
+ bool fHuman;
};
diff --git a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
index 5a4b768e..629163d6 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp
@@ -70,139 +70,43 @@ 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);
- }
- }
}
}
if (doReport)
{
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
- if ( triggerPhys->DoDetectorHullWorkaround() )
+ if (status & NX_TRIGGER_ON_ENTER)
{
- if (status & NX_TRIGGER_ON_ENTER && triggerPhys->Should_I_Trigger(status & NX_TRIGGER_ON_ENTER, otherPos) )
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
- plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true);
- }
- else if (status & NX_TRIGGER_ON_ENTER)
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s :failed Should I trigger",triggerPhys->GetObjectKey()->GetName().c_str());
- }
- if (status & NX_TRIGGER_ON_LEAVE && triggerPhys->Should_I_Trigger(status & NX_TRIGGER_ON_ENTER, otherPos) )
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("-->Send Collision (CH) %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
- plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false);
- }
- else if (status & NX_TRIGGER_ON_LEAVE)
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s :failed Should I trigger",triggerPhys->GetObjectKey()->GetName().c_str());
- }
- if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) )
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s :failed event(CH)",triggerPhys->GetObjectKey()->GetName().c_str());
- }
+ if (plSimulationMgr::fExtraProfile)
+ DetectorLogRed("-->Send Collision %s enter",triggerPhys->GetObjectKey()->GetName().c_str());
+ plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true);
}
- else
+ else if (status & NX_TRIGGER_ON_LEAVE)
{
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
- if (status & NX_TRIGGER_ON_ENTER)
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
- plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, true);
- }
- if (status & NX_TRIGGER_ON_LEAVE)
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("-->Send Collision %s %s",triggerPhys->GetObjectKey()->GetName().c_str(),status & NX_TRIGGER_ON_ENTER ? "enter" : "exit");
- plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false);
- }
- if (!(status & NX_TRIGGER_ON_ENTER) && !(status & NX_TRIGGER_ON_LEAVE) )
- {
- if (plSimulationMgr::fExtraProfile)
- DetectorLogRed("<--Kill collision %s :failed event",triggerPhys->GetObjectKey()->GetName().c_str());
- }
-#ifdef USE_PHYSX_CONVEXHULL_WORKAROUND
+ if (plSimulationMgr::fExtraProfile)
+ DetectorLogRed("-->Send Collision %s exit",triggerPhys->GetObjectKey()->GetName().c_str());
+ plSimulationMgr::GetInstance()->AddCollisionMsg(triggerPhys->GetObjectKey(), otherKey, false);
}
-#endif // USE_PHYSX_CONVEXHULL_WORKAROUND
}
}
} gSensorReport;
@@ -289,8 +193,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.15) // if the step is greater than .15 seconds, clamp to that
+#define kDefaultStepSize (1.f / 60.f) // default simulation freqency is 60hz
/////////////////////////////////////////////////////////////////
//
@@ -378,6 +282,8 @@ plSimulationMgr* plSimulationMgr::GetInstance()
plSimulationMgr::plSimulationMgr()
: fSuspended(true)
+ , fAccumulator(0.0f)
+ , fStepCount(0)
, fLOSDispatch(new plLOSDispatch())
, fSoundMgr(new plPhysicsSoundMgr)
, fLog(nil)
@@ -470,6 +376,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 +384,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);
@@ -507,86 +418,6 @@ void plSimulationMgr::ReleaseScene(plKey world)
}
}
-void plSimulationMgr::ISendCollisionMsg(plKey receiver, plKey hitter, bool entering)
-{
- DetectorLogYellow("Collision: %s is inside %s. Sending an %s msg", hitter ? hitter->GetName().c_str() : "(nil)",
- receiver->GetName().c_str(), entering ? "'enter'" : "'exit'");
- plCollideMsg* msg = new plCollideMsg;
- msg->fOtherKey = hitter;
- msg->fEntering = entering;
- msg->AddReceiver(receiver);
- msg->Send();
-}
-
-void plSimulationMgr::UpdateDetectorsInScene(plKey world, plKey avatar, hsPoint3& pos, bool entering)
-{
- // search thru the actors in a scene looking for convex hull detectors and see if the avatar is inside it
- // ... and then send appropiate collision message if needed
- NxScene* scene = GetScene(world);
- plSceneObject* avObj = plSceneObject::ConvertNoRef(avatar->ObjectIsLoaded());
- const plCoordinateInterface* ci = avObj->GetCoordinateInterface();
- hsPoint3 soPos = ci->GetWorldPos();
- if (scene)
- {
- uint32_t numActors = scene->getNbActors();
- NxActor** actors = scene->getActors();
-
- for (int i = 0; i < numActors; i++)
- {
- plPXPhysical* physical = (plPXPhysical*)actors[i]->userData;
- if (physical && physical->DoDetectorHullWorkaround())
- {
- if ( physical->IsObjectInsideHull(pos) )
- {
- physical->SetInsideConvexHull(entering);
- // we are entering this world... say we entered this detector
- ISendCollisionMsg(physical->GetObjectKey(), avatar, entering);
- }
- }
- }
- }
-}
-
-void plSimulationMgr::UpdateAvatarInDetector(plKey world, plPXPhysical* detector)
-{
- // search thru the actors in a scene looking for avatars that might be in the newly enabled detector region
- // ... and then send appropiate collision message if needed
- if ( detector->DoDetectorHullWorkaround() )
- {
- NxScene* scene = GetScene(world);
- if (scene)
- {
- uint32_t numActors = scene->getNbActors();
- NxActor** actors = scene->getActors();
-
- for (int i = 0; i < numActors; i++)
- {
- if ( actors[i]->userData == nil )
- {
- // we go a controller
- bool isController;
- plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(*actors[i],&isController);
- if (controller && controller->IsEnabled())
- {
- plKey avatar = controller->GetOwner();
- plSceneObject* avObj = plSceneObject::ConvertNoRef(avatar->ObjectIsLoaded());
- const plCoordinateInterface* ci;
- if ( avObj && ( ci = avObj->GetCoordinateInterface() ) )
- {
- if ( detector->IsObjectInsideHull(ci->GetWorldPos()) )
- {
- detector->SetInsideConvexHull(true);
- // we are entering this world... say we entered this detector
- ISendCollisionMsg(detector->GetObjectKey(), avatar, true);
- }
- }
- }
- }
- }
- }
- }
-}
-
void plSimulationMgr::AddCollisionMsg(plKey hitee, plKey hitter, bool enter)
{
// First, make sure we have no dupes
@@ -614,20 +445,41 @@ 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
+ ++fStepCount;
+
+ // Perform as many whole substeps as possible saving the remainder in our accumulator.
+ int numSubSteps = (int)(fAccumulator / kDefaultStepSize + 0.000001f);
+ 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 +494,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 +583,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..d8a38b50 100644
--- a/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
+++ b/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h
@@ -99,12 +99,11 @@ public:
int GetMaterialIdx(NxScene* scene, float friction, float restitution);
- // PHYSX FIXME - walk thru all the convex hull detector regions to see if we are in any... we're either coming or going
- void UpdateDetectorsInScene(plKey world, plKey avatar, hsPoint3& pos, bool entering);
- void UpdateAvatarInDetector(plKey world, plPXPhysical* detector);
-
+ uint32_t GetStepCount() const { return fStepCount; }
+
//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;
@@ -121,9 +120,6 @@ protected:
// Walk through the synchronization requests and send them as appropriate.
void IProcessSynchs();
- // PHYSX FIXME send a collision message - should only be used with UpdateDetectorsInScene
- void ISendCollisionMsg(plKey receiver, plKey hitter, bool entering);
-
NxPhysicsSDK* fSDK;
plPhysicsSoundMgr* fSoundMgr;
@@ -144,6 +140,9 @@ protected:
// but nothing will move.
bool fSuspended;
+ float fAccumulator;
+ uint32_t fStepCount;
+
// 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/plCollisionDetector.cpp b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp
index 43cfef3f..ca14aa0b 100644
--- a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp
+++ b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp
@@ -39,7 +39,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
-#include "plAvatar/plAvCallbackAction.h"
#include "HeadSpin.h"
#include "plCollisionDetector.h"
@@ -65,11 +64,15 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plAvatar/plAvatarMgr.h"
#include "plAvatar/plAvBrainHuman.h"
#include "plAvatar/plAvBrainDrive.h"
+#include "plAvatar/plPhysicalControllerCore.h"
#include "plModifier/plDetectorLog.h"
-#define USE_PHYSX_MULTIPLE_CAMREGION_ENTER 1
-#define USE_PHYSX_COLLISION_FLUTTER_WORKAROUND 1
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+#include "plPhysX/plSimulationMgr.h"
+#endif
+
+
plArmatureMod* plCollisionDetector::IGetAvatarModifier(plKey key)
{
@@ -240,58 +243,19 @@ plCameraRegionDetector::~plCameraRegionDetector()
hsRefCnt_SafeUnRef(*it);
}
-void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate)
+void plCameraRegionDetector::ISendTriggerMsg()
{
- if (fSavingSendMsg)
- DetectorLogRed("%s: Stale messages on ITrigger. This should never happen!", GetKeyName().c_str());
- if (fIsInside && entering)
- DetectorLogRed("%s: Duplicate enter! Did we miss an exit?", GetKeyName().c_str());
- else if (!fIsInside && !entering)
- DetectorLogRed("%s: Duplicate exit! Did we miss an enter?", GetKeyName().c_str());
-
- fSavingSendMsg = true;
- fSavedMsgEnterFlag = entering;
- if (entering)
- {
- DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName().c_str(),fNumEvals);
- fLastEnterEval = fNumEvals;
- }
- else
- {
- DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName().c_str(),fNumEvals);
- fLastExitEval = fNumEvals;
- }
-
- if (immediate)
- ISendSavedTriggerMsgs();
-}
-
-void plCameraRegionDetector::ISendSavedTriggerMsgs()
-{
- if (fSavingSendMsg)
+ for (plCameraMsgVec::iterator it = fMessages.begin(); it != fMessages.end(); ++it)
{
- for (size_t i = 0; i < fMessages.size(); ++i)
- {
- hsRefCnt_SafeRef(fMessages[i]);
- if (fSavedMsgEnterFlag)
- {
- fMessages[i]->SetCmd(plCameraMsg::kEntering);
- DetectorLog("Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size());
- fIsInside = true;
- }
- else
- {
- fMessages[i]->ClearCmd(plCameraMsg::kEntering);
- DetectorLog("Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName().c_str(),fNumEvals,i+1,fMessages.size());
- fIsInside = false;
- }
- plgDispatch::MsgSend(fMessages[i]);
- }
+ plCameraMsg* msg = *it;
+ if (fIsInside)
+ msg->SetCmd(plCameraMsg::kEntering);
+ else
+ msg->ClearCmd(plCameraMsg::kEntering);
+ msg->SendAndKeep();
}
- fSavingSendMsg = false;
}
-
bool plCameraRegionDetector::MsgReceive(plMessage* msg)
{
plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg);
@@ -300,8 +264,16 @@ bool plCameraRegionDetector::MsgReceive(plMessage* msg)
// camera collisions are only for the local player
if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey)
return true;
- // Fall through to plObjectInVolumeDetector, which will register us for plEvalMsg
- // and handle it for us. (Hint: See ISendSavedTriggerMsgs)
+
+ if (!fWaitingForEval)
+ IRegisterForEval();
+
+ fEntering = (pCollMsg->fEntering != 0);
+
+ #ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ fLastStep = plSimulationMgr::GetInstance()->GetStepCount();
+#endif
+ return true;
}
return plObjectInVolumeDetector::MsgReceive(msg);
@@ -327,56 +299,72 @@ void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr)
}
+void plCameraRegionDetector::IHandleEval(plEvalMsg*)
+{
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ if (plSimulationMgr::GetInstance()->GetStepCount() - fLastStep > 1)
+ {
+#endif
+ if (fIsInside != fEntering)
+ {
+ fIsInside = fEntering;
+ DetectorLog("%s CameraRegion: %s", fIsInside ? "Entering" : "Exiting", GetKeyName().c_str());
+ ISendTriggerMsg();
+ }
+ plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
+ fWaitingForEval = false;
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ }
+#endif
+}
+
/////////////////////////////////
/////////////////////////////////
/////////////////////////////////
/////////////////////////////////
// object-in-volume detector
-void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immediate)
+void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering)
{
- hsRefCnt_SafeUnRef(fSavedActivatorMsg);
- fSavedActivatorMsg = new plActivatorMsg;
- fSavedActivatorMsg->AddReceivers(fReceivers);
-
- if (fProxyKey)
- fSavedActivatorMsg->fHiteeObj = fProxyKey;
- else
- fSavedActivatorMsg->fHiteeObj = GetTarget()->GetKey();
-
- fSavedActivatorMsg->fHitterObj = hitter;
- fSavedActivatorMsg->SetSender(GetKey());
-
- if (entering)
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ for (bookKeepingList::iterator it = fCollisionList.begin(); it != fCollisionList.end(); ++it)
{
- DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
- fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter);
- fLastEnterEval = fNumEvals;
- }
- else
- {
- DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
- fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit);
- fLastExitEval = fNumEvals;
+ plCollisionBookKeepingInfo* collisionInfo = *it;
+ if (collisionInfo->fHitter == hitter)
+ {
+ collisionInfo->fEntering = entering;
+ collisionInfo->fLastStep = plSimulationMgr::GetInstance()->GetStepCount();
+ return;
+ }
}
+#endif
- if (immediate)
- ISendSavedTriggerMsgs();
+ plCollisionBookKeepingInfo* collisionInfo = new plCollisionBookKeepingInfo(hitter, entering);
+ fCollisionList.push_back(collisionInfo);
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ collisionInfo->fLastStep = plSimulationMgr::GetInstance()->GetStepCount();
+#endif
}
-void plObjectInVolumeDetector::ISendSavedTriggerMsgs()
+void plObjectInVolumeDetector::IRegisterForEval()
{
- if (fSavedActivatorMsg)
- {
- if (fSavedActivatorMsg->fTriggerType == plActivatorMsg::kVolumeEnter)
- DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
- else
- DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName().c_str(), fNumEvals);
+ fWaitingForEval = true;
+ plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
+}
- // we're saving the message to be dispatched later...
- plgDispatch::MsgSend(fSavedActivatorMsg);
- }
- fSavedActivatorMsg = nil;
+void plObjectInVolumeDetector::ISendTriggerMsg(plKey hitter, bool entering)
+{
+ plActivatorMsg* activatorMsg = new plActivatorMsg();
+ activatorMsg->SetSender(GetKey());
+ activatorMsg->AddReceivers(fReceivers);
+ activatorMsg->fHiteeObj = fProxyKey ? fProxyKey : GetTarget()->GetKey();
+ activatorMsg->fHitterObj = hitter;
+ if (entering)
+ activatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter);
+ else
+ activatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit);
+
+ plgDispatch::MsgSend(activatorMsg);
}
bool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
@@ -387,18 +375,17 @@ bool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
// If the avatar is disabled (flying around), don't trigger
if (IIsDisabledAvatar(pCollMsg->fOtherKey))
return false;
+
+ if (!fWaitingForEval)
+ IRegisterForEval();
+
ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0));
- plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
return true;
}
plEvalMsg* pEvalMsg = plEvalMsg::ConvertNoRef(msg);
if (pEvalMsg)
- {
- fNumEvals++;
- ISendSavedTriggerMsgs();
- plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
- }
+ IHandleEval(pEvalMsg);
plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg);
if (pageMsg && pageMsg->fUnload)
@@ -409,6 +396,48 @@ bool plObjectInVolumeDetector::MsgReceive(plMessage* msg)
return plCollisionDetector::MsgReceive(msg);
}
+void plObjectInVolumeDetector::IHandleEval(plEvalMsg*)
+{
+ bookKeepingList::iterator it = fCollisionList.begin();
+ while (it != fCollisionList.end())
+ {
+ plCollisionBookKeepingInfo* collisionInfo = *it;
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ if (plSimulationMgr::GetInstance()->GetStepCount() - collisionInfo->fLastStep > 1)
+ {
+#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ ResidentSet::iterator j = fCurrentResidents.find(collisionInfo->fHitter);
+ bool wasInside = j != fCurrentResidents.end();
+ if (collisionInfo->fEntering != wasInside)
+ {
+ if (collisionInfo->fEntering)
+ {
+ fCurrentResidents.insert(collisionInfo->fHitter);
+ DetectorLog("%s: Sending Volume Enter ActivatorMsg", GetKeyName().c_str());
+ ISendTriggerMsg(collisionInfo->fHitter, true);
+ }
+ else
+ {
+ fCurrentResidents.erase(j);
+ DetectorLog("%s: Sending Volume Exit ActivatorMsg", GetKeyName().c_str());
+ ISendTriggerMsg(collisionInfo->fHitter, false);
+ }
+ }
+
+ delete collisionInfo;
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ it = fCollisionList.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+#else
+ ++it;
+#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ }
+}
+
void plObjectInVolumeDetector::SetTarget(plSceneObject* so)
{
plCollisionDetector::SetTarget(so);
@@ -475,7 +504,7 @@ void plObjectInVolumeAndFacingDetector::ICheckForTrigger()
// And are we walking towards it?
plArmatureBrain* abrain = armMod->FindBrainByClass(plAvBrainHuman::Index()); //armMod->GetCurrentBrain();
plAvBrainHuman* brain = plAvBrainHuman::ConvertNoRef(abrain);
- if (brain && brain->IsMovingForward() && brain->fCallbackAction->IsOnGround())
+ if (brain && brain->IsMovingForward() && brain->fWalkingStrategy->IsOnGround())
movingForward = true;
}
else
@@ -485,13 +514,13 @@ void plObjectInVolumeAndFacingDetector::ICheckForTrigger()
{
DetectorLog("%s: Trigger InVolume&Facing", GetKeyName().c_str());
fTriggered = true;
- ITrigger(avatar->GetKey(), true, true);
+ ISendTriggerMsg(avatar->GetKey(), true);
}
else if (!facing && fTriggered)
{
DetectorLog("%s: Untrigger InVolume&Facing", GetKeyName().c_str());
fTriggered = false;
- ITrigger(avatar->GetKey(), false, true);
+ ISendTriggerMsg(avatar->GetKey(), false);
}
}
}
@@ -525,7 +554,7 @@ bool plObjectInVolumeAndFacingDetector::MsgReceive(plMessage* msg)
if (fTriggered)
{
fTriggered = false;
- ITrigger(plNetClientApp::GetInstance()->GetLocalPlayerKey(), false, true);
+ ISendTriggerMsg(plNetClientApp::GetInstance()->GetLocalPlayerKey(), false);
}
}
@@ -645,11 +674,11 @@ bool plPanicLinkRegion::MsgReceive(plMessage* msg)
{
if (avMod->IsLinkedIn())
{
- hsPoint3 kinPos;
+ hsPoint3 pos;
if (avMod->GetController())
{
- avMod->GetController()->GetKinematicPosition(kinPos);
- DetectorLogSpecial("Avatar is panic linking. KinPos at %f,%f,%f and is %s",kinPos.fX,kinPos.fY,kinPos.fZ,avMod->GetController()->IsEnabled() ? "enabled" : "disabled");
+ avMod->GetController()->GetPositionSim(pos);
+ DetectorLogSpecial("Avatar is panic linking. Position %f,%f,%f and is %s", pos.fX, pos.fY, pos.fZ, avMod->GetController()->IsEnabled() ? "enabled" : "disabled");
}
avMod->PanicLink(fPlayLinkOutAnim);
} else
diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h
index d350341f..237aa692 100644
--- a/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h
+++ b/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h
@@ -53,6 +53,8 @@ class plArmatureMod;
class plActivatorMsg;
class plEvalMsg;
+#define USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+
class plCollisionDetector : public plDetectorModifier
{
protected:
@@ -92,23 +94,37 @@ public:
class plObjectInVolumeDetector : public plCollisionDetector
{
protected:
- virtual void ITrigger(plKey hitter, bool entering, bool immediate=false);
- virtual void ISendSavedTriggerMsgs();
-
- plActivatorMsg* fSavedActivatorMsg;
- uint32_t fNumEvals;
- uint32_t fLastEnterEval;
- uint32_t fLastExitEval;
+ class plCollisionBookKeepingInfo
+ {
+ public:
+ plCollisionBookKeepingInfo(const plKey& key, bool entering)
+ : fHitter(key), fEntering(entering) { }
+
+ plKey fHitter;
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ uint32_t fLastStep;
+#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ bool fEntering;
+ };
+
+ void ITrigger(plKey hitter, bool entering);
+ void ISendTriggerMsg(plKey hitter, bool entering);
+ void IRegisterForEval();
+ virtual void IHandleEval(plEvalMsg*);
+ bool fWaitingForEval;
+
+ typedef std::list bookKeepingList;
+ bookKeepingList fCollisionList;
+ typedef std::set ResidentSet;
+ ResidentSet fCurrentResidents;
public:
plObjectInVolumeDetector()
- : plCollisionDetector(), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0)
- { }
+ : plCollisionDetector(), fWaitingForEval(false) { }
plObjectInVolumeDetector(int8_t type)
- : plCollisionDetector(type), fSavedActivatorMsg(nil), fNumEvals(0), fLastEnterEval(0), fLastExitEval(0)
- { }
+ : plCollisionDetector(type), fWaitingForEval(false) { }
virtual ~plObjectInVolumeDetector() { }
@@ -159,16 +175,17 @@ protected:
typedef std::vector plCameraMsgVec;
plCameraMsgVec fMessages;
- bool fIsInside;
- bool fSavingSendMsg;
- bool fSavedMsgEnterFlag;
-
- virtual void ITrigger(plKey hitter, bool entering, bool immediate=false);
- virtual void ISendSavedTriggerMsgs();
+#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND
+ uint32_t fLastStep;
+#endif
+ bool fIsInside;
+ bool fEntering;
+
+ void ISendTriggerMsg();
+ virtual void IHandleEval(plEvalMsg*);
public:
plCameraRegionDetector()
- : plObjectInVolumeDetector(), fIsInside(false), fSavingSendMsg(false)
- { }
+ : plObjectInVolumeDetector(), fIsInside(false) { }
~plCameraRegionDetector();
virtual bool MsgReceive(plMessage* msg);
diff --git a/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h b/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h
index 4ece4ccc..c22edd7f 100644
--- a/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h
+++ b/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h
@@ -68,27 +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,
- };
-
- /** A taxonomy of action types. Crucial for doing things like making sure you don't
- do things like attach duplicate actions. */
- enum ActionType
- {
- kUnknownAction = 0x01, // don't know the type (probably forgot to override GetType())
- kUnknownZAction = 0x02, // unknown type of z-order action
- kAntiGravityAction = 0x03, // an action that counters gravity exactly
- kUprightAction = 0x04, // an action that keeps an object upright by apply force
- kPhysAnimAction = 0x05, // an action that parses keyframed animation into physical information
- kConstraint = 0x06, // a general constraint.
- kCallbackAction = 0x07, // an action that just hands us the physics "tick"
- kPseudoPhysAction = 0x08, // replacement for the physAnim
- kAntiGravAction = 0x09, // makes things float in the air
- kBasicGroundAction = 0x0a, // for your basic walkAroundOnGround corrections
- kHorizontalFreeze = 0x0b, // Let's you fall vertically, but otherwise keeps you in place (generic brains)
-
- kMaxAction = 0xffff // force 16-bit
+ kGroupMax
};
/** Different types of line-of-sight requests. */