From 383346c1aa9d111e17e04b5e8f0ebb2cd968b2d5 Mon Sep 17 00:00:00 2001 From: Skoader Date: Sat, 16 Jun 2012 13:35:59 +1000 Subject: [PATCH 01/14] Refactor avatar movement code plMovementStrategy classes have been reworked and completely replace all plAvatarControllers. While based on the old implementation, plPhysicalControllerCore has essentially been rewritten. Remnants of long gone physical "actions" have been removed. 4 files removed - plAVCallbackAction.h & plAVCallbackAction.cpp plAntiGravAction.h & plAntiGravAction.cpp This revision will not compile, requires new plPXPhysicalControllerCore implementation. --- .../PubUtilLib/plAvatar/plAvatar.vcxproj | 4 - .../plAvatar/plAvatar.vcxproj.filters | 12 - .../PubUtilLib/plAvatar/plAvatar.vcproj | 46 - .../Plasma/FeatureLib/pfAudio/plListener.cpp | 2 +- .../FeatureLib/pfCamera/plCameraModifier.cpp | 2 +- .../FeatureLib/pfPython/pySceneObject.cpp | 2 +- .../PubUtilLib/plAvatar/plAnimStage.cpp | 1 - .../PubUtilLib/plAvatar/plAntiGravAction.cpp | 171 -- .../PubUtilLib/plAvatar/plAntiGravAction.h | 79 - .../PubUtilLib/plAvatar/plArmatureEffects.cpp | 1 - .../PubUtilLib/plAvatar/plArmatureMod.cpp | 17 +- .../PubUtilLib/plAvatar/plArmatureMod.h | 1 + .../PubUtilLib/plAvatar/plAvBrainCritter.cpp | 20 +- .../PubUtilLib/plAvatar/plAvBrainCritter.h | 6 +- .../PubUtilLib/plAvatar/plAvBrainDrive.cpp | 1 - .../PubUtilLib/plAvatar/plAvBrainGeneric.cpp | 4 - .../PubUtilLib/plAvatar/plAvBrainGeneric.h | 2 - .../PubUtilLib/plAvatar/plAvBrainHuman.cpp | 159 +- .../PubUtilLib/plAvatar/plAvBrainHuman.h | 4 +- .../plAvBrainRideAnimatedPhysical.cpp | 13 +- .../plAvatar/plAvBrainRideAnimatedPhysical.h | 2 - .../PubUtilLib/plAvatar/plAvBrainSwim.cpp | 137 +- .../PubUtilLib/plAvatar/plAvBrainSwim.h | 7 +- .../plAvatar/plAvCallbackAction.cpp | 579 ------- .../PubUtilLib/plAvatar/plAvCallbackAction.h | 217 --- .../plAvatar/plAvLadderModifier.cpp | 4 +- .../PubUtilLib/plAvatar/plAvTaskSeek.cpp | 6 +- .../plAvatar/plAvatarSDLModifier.cpp | 2 +- .../PubUtilLib/plAvatar/plAvatarTasks.cpp | 4 +- .../plAvatar/plPhysicalControllerCore.cpp | 1436 +++++++---------- .../plAvatar/plPhysicalControllerCore.h | 442 +++-- .../plInputCore/plSceneInputInterface.cpp | 2 +- .../plModifier/plExcludeRegionModifier.cpp | 1 - .../plPhysical/plCollisionDetector.cpp | 12 +- .../Plasma/PubUtilLib/plPhysical/plSimDefs.h | 19 - 35 files changed, 989 insertions(+), 2428 deletions(-) delete mode 100644 MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.cpp delete mode 100644 MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.h delete mode 100644 MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp delete mode 100644 MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.h diff --git a/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj b/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj index 4f719944..bdff6ddc 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj +++ b/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj @@ -328,7 +328,6 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) - Disabled Disabled @@ -555,7 +554,6 @@ %(PreprocessorDefinitions) %(PreprocessorDefinitions) - Disabled Disabled @@ -807,7 +805,6 @@ - @@ -825,7 +822,6 @@ - diff --git a/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj.filters b/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj.filters index 4f4cb2d2..a1d89d7d 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj.filters +++ b/MOULOpenSourceClientPlugin/Plasma20/MSVC10Projects/Plasma/PubUtilLib/plAvatar/plAvatar.vcxproj.filters @@ -35,9 +35,6 @@ Source Files - - Source Files - Source Files @@ -86,9 +83,6 @@ Source Files - - Source Files - Source Files @@ -163,9 +157,6 @@ Header Files - - Header Files - Header Files @@ -217,9 +208,6 @@ Header Files - - Header Files - Header Files diff --git a/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/PubUtilLib/plAvatar/plAvatar.vcproj b/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/PubUtilLib/plAvatar/plAvatar.vcproj index ae798721..f8d53b38 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/PubUtilLib/plAvatar/plAvatar.vcproj +++ b/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/PubUtilLib/plAvatar/plAvatar.vcproj @@ -282,26 +282,6 @@ PreprocessorDefinitions=""/> - - - - - - - - - - - - - - - - - - @@ -993,9 +950,6 @@ - - diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp index 3dd47931..48401135 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfAudio/plListener.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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" hsBool plListener::fPrintDbgInfo = false; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp index 0a40eb29..90397012 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfCamera/plCameraModifier.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp index c7bacef2..20e8dcc2 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pySceneObject.cpp @@ -545,7 +545,7 @@ hsBool pySceneObject::IsAvatar() return false; } -#include "../plAvatar/plAvCallbackAction.h" +#include "../plAvatar/plPhysicalControllerCore.h" PyObject* pySceneObject::GetAvatarVelocity() { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp index 917ff1e0..129c052e 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAnimStage.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.cpp deleted file mode 100644 index e78d319e..00000000 --- a/MOULOpenSourceClientPlugin/Plasma20/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); - hsScalar angCurrent = 0.f; - if (fCurrentRegion != nil) - fCurrentRegion->GetCurrent(fPhysical, linCurrent, angCurrent, (hsScalar)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); - hsScalar 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, hsScalar 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAntiGravAction.h deleted file mode 100644 index f8dd2125..00000000 --- a/MOULOpenSourceClientPlugin/Plasma20/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, hsScalar surfaceHeight); - hsScalar GetBuoyancy() { return fBuoyancy; } - hsBool IsOnGround() { return fOnGround; } - hsBool HadContacts() { return fHadContacts; } - -protected: - void IAdjustBuoyancy(); - - hsBool fOnGround; - hsBool fHadContacts; - hsScalar fBuoyancy; - hsScalar fSurfaceHeight; - plSwimRegionInterface *fCurrentRegion; -}; - -#endif - - diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp index 2f6907f6..16835813 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureEffects.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp index 8f879739..051219c7 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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(hsBool status, UInt16 reason /* = kDisable // i.e. normal enabled physical void plArmatureModBase::EnablePhysicsKinematic(hsBool status) { - if (fController) - fController->Kinematic(status); + EnablePhysics(!status, kDisableReasonKinematic); } void plArmatureModBase::EnableDrawing(hsBool status, UInt16 reason /* = kDisableReasonUnknown */) @@ -2684,19 +2683,7 @@ void plArmatureMod::DumpToDebugDisplay(int &x, int &y, int lineHeight, char *str debugTxt.DrawString(x, y, strBuf); y += lineHeight; - hsPoint3 kPos; - 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h index afc1cddf..8353125e 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.h @@ -145,6 +145,7 @@ public: kDisableReasonCCR = 0x0008, kDisableReasonVehicle = 0x0010, kDisableReasonGenericBrain = 0x0020, + kDisableReasonKinematic = 0x0040 }; void EnablePhysics(hsBool status, UInt16 reason = kDisableReasonUnknown); void EnablePhysicsKinematic(hsBool status); diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp index 7a6ad23f..b86912cf 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.cpp @@ -42,7 +42,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsConfig.h" #include "hsWindows.h" -#include "plAvCallbackAction.h" +#include "plPhysicalControllerCore.h" #include "plAvBrainCritter.h" #include "plAvBrainHuman.h" #include "plArmatureMod.h" @@ -127,7 +127,7 @@ protected: /////////////////////////////////////////////////////////////////////////////// -plAvBrainCritter::plAvBrainCritter(): fCallbackAction(nil), fCurMode(kIdle), fNextMode(kIdle), fFadingNextBehavior(true), +plAvBrainCritter::plAvBrainCritter(): fWalkingStrategy(nil), fCurMode(kIdle), fNextMode(kIdle), fFadingNextBehavior(true), fLocallyControlled(false), fAvoidingAvatars(false), fFinalGoalPos(0, 0, 0), fImmediateGoalPos(0, 0, 0), fDotGoal(0), fAngRight(0) { @@ -145,8 +145,8 @@ plAvBrainCritter::~plAvBrainCritter() fBehaviors[i] = nil; } - delete fCallbackAction; - fCallbackAction = nil; + delete fWalkingStrategy; + fWalkingStrategy = nil; fUserBehaviors.clear(); fReceivers.clear(); @@ -169,8 +169,8 @@ hsBool plAvBrainCritter::Apply(double time, hsScalar 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); } @@ -190,13 +190,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 = TRACKED_NEW plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller); - fCallbackAction->ActivateController(); + fWalkingStrategy = TRACKED_NEW plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller); + controller->SetMovementStrategy(fWalkingStrategy); } // tell people that care that we are good to go @@ -226,7 +226,7 @@ void plAvBrainCritter::Resume() // fade in the idle fNextMode = kIdle; - fCallbackAction->Reset(false); + fWalkingStrategy->Reset(false); plArmatureBrain::Resume(); } diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h index ab44245b..7b6359d7 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainCritter.h +++ b/MOULOpenSourceClientPlugin/Plasma20/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 @@ -127,8 +127,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; @@ -152,7 +150,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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp index 9521cf95..1a5b6cb5 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainDrive.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp index d20862b9..32655893 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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 exitFlags, float fadeIn, float fadeOut fFadeIn(fadeIn), fFadeOut(fadeOut), fMoveMode(moveMode), - fCallbackAction(nil), fBodyUsage(plAGAnim::kBodyUnknown) { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h index 79be24fc..fc3c16c2 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainGeneric.h +++ b/MOULOpenSourceClientPlugin/Plasma20/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 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp index b6acd180..62ac40e5 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp @@ -42,9 +42,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "hsConfig.h" #include "hsWindows.h" -#include "plAvCallbackAction.h" // subclasses a havok object; must be in first include section - - +#include "plPhysicalControllerCore.h" #include "plAvBrainHuman.h" #include "plAvBrainClimb.h" #include "plAvBrainDrive.h" @@ -142,7 +140,7 @@ plAvBrainHuman::TurnCurve plAvBrainHuman::GetTurnCurve(hsBool walk) plAvBrainHuman::plAvBrainHuman(bool isActor /* = false */) : fHandleAGMod(nil), fStartedTurning(-1.0f), - fCallbackAction(nil), + fWalkingStrategy(nil), fPreconditions(0), fIsActor(isActor) { @@ -156,9 +154,9 @@ hsBool plAvBrainHuman::Apply(double timeNow, hsScalar 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 @@ -179,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 = TRACKED_NEW plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller); - fCallbackAction->ActivateController(); + fWalkingStrategy = TRACKED_NEW plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller); + controller->SetMovementStrategy(fWalkingStrategy); } @@ -330,8 +328,8 @@ plAvBrainHuman::~plAvBrainHuman() delete fBehaviors[i]; fBehaviors.Reset(); - delete fCallbackAction; - fCallbackAction = nil; + delete fWalkingStrategy; + fWalkingStrategy = nil; } void plAvBrainHuman::Deactivate() @@ -364,7 +362,7 @@ void plAvBrainHuman::Resume() if (fAvMod->GetInputFlag(S_PUSH_TO_TALK)) IChatOn(); - fCallbackAction->Reset(false); + fWalkingStrategy->Reset(false); plArmatureBrain::Resume(); } @@ -468,25 +466,23 @@ hsBool plAvBrainHuman::MsgReceive(plMessage * msg) { if(ride->Entering()) { - //plAvBrainRideAnimatedPhysical *rideBrain = TRACKED_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= TRACKED_NEW plRidingAnimatedPhysicalController(avObj, agMod->GetApplicator(kAGPinTransform), controller); - fCallbackAction->ActivateController(); - + fWalkingStrategy = TRACKED_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= TRACKED_NEW plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller); - fCallbackAction->ActivateController(); - //hsStatusMessage("Got an exiting ride animated physical message"); + fWalkingStrategy = TRACKED_NEW plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller); + controller->SetMovementStrategy(fWalkingStrategy); } } @@ -560,8 +556,8 @@ hsScalar 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; @@ -593,7 +589,7 @@ hsScalar plAvBrainHuman::IGetTurnStrength(double timeNow) result += fAvMod->GetKeyTurnStrength() * turnSpeed; } - if (!fCallbackAction->IsControlledFlight()) + if (!fWalkingStrategy->IsControlledFlight()) result += fAvMod->GetAnalogTurnStrength() * maxTurnSpeed; return result; @@ -650,7 +646,7 @@ void plAvBrainHuman::ResetIdle() void plAvBrainHuman::IdleOnly(bool instantOff) { - if (!fCallbackAction) + if (!fWalkingStrategy) return; hsScalar rate = instantOff ? 0.f : 1.f; @@ -676,7 +672,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; @@ -875,23 +871,23 @@ void plAvBrainHuman::Spawn(double timeNow) hsBool 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= TRACKED_NEW plWalkingController(avObj, agMod->GetApplicator(kAGPinTransform), controller); - fCallbackAction->ActivateController(); + fWalkingStrategy = TRACKED_NEW plWalkingStrategy(agMod->GetApplicator(kAGPinTransform), controller); } - plArmatureBrain::LeaveAge(); - + 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; } @@ -901,11 +897,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; @@ -1018,8 +1013,8 @@ hsBool 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; @@ -1029,8 +1024,8 @@ hsBool 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; @@ -1040,8 +1035,8 @@ hsBool 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; @@ -1054,7 +1049,7 @@ hsBool 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; } @@ -1066,7 +1061,7 @@ hsBool 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; } @@ -1107,8 +1102,8 @@ hsBool 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; @@ -1118,8 +1113,8 @@ hsBool 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; } @@ -1128,14 +1123,14 @@ hsBool 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(); } @@ -1146,7 +1141,7 @@ hsBool 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; @@ -1158,7 +1153,7 @@ hsBool 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; @@ -1174,7 +1169,7 @@ hsBool 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; @@ -1187,8 +1182,8 @@ hsBool 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; @@ -1204,7 +1199,7 @@ hsBool 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; @@ -1217,8 +1212,8 @@ hsBool 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; @@ -1243,13 +1238,13 @@ hsBool 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; @@ -1273,13 +1268,13 @@ hsBool 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; @@ -1298,7 +1293,7 @@ void GroundImpact::IStop() hsBool 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) @@ -1310,7 +1305,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(); @@ -1327,7 +1322,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); hsScalar angle = hsATan2(lookAt.fY - pos.fY, lookAt.fX - pos.fX) + hsScalarPI / 2; hsQuat targRot(angle, &up); @@ -1341,23 +1336,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); } //hsBool 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); //} hsBool 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()); } @@ -1372,7 +1367,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; @@ -1436,7 +1431,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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h index 008c0324..1544d151 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.h +++ b/MOULOpenSourceClientPlugin/Plasma20/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 hsScalar kControlledFlightThreshold; static const hsScalar kAirTimeThreshold; static const hsScalar kAirTimePanicThreshold; - plWalkingController* fCallbackAction; + plWalkingStrategy* fWalkingStrategy; protected: plAGAnim *FindCustomAnim(const char *baseName); diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp index 85a1d975..8c71b456 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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 = TRACKED_NEW plRidingAnimatedPhysicalController(avObj, agMod->GetApplicator(kAGPinTransform), controller); - fCallbackAction->ActivateController(); + fWalkingStrategy = TRACKED_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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h index 6e02bbe2..520dfb96 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainRideAnimatedPhysical.h +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp index 3f0bd8ca..1499b36f 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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 hsScalar 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 @@ hsBool plAvBrainSwim::Apply(double time, hsScalar 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 = TRACKED_NEW plArmatureEffectMsg(fAvMod->GetArmatureEffects()->GetKey(), kTime); @@ -318,8 +307,7 @@ hsBool plAvBrainSwim::Apply(double time, hsScalar 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 @@ hsBool 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 = TRACKED_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 @@ hsBool 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 @@ hsBool 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); -// hsScalar 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h index b75651ef..d3e9f83b 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvBrainSwim.h @@ -47,11 +47,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../pnKeyedObject/plKey.h" class plArmatureMod; -class plAntiGravAction; class plControlEventMsg; class plLOSRequestMsg; class plSwimRegionInterface; -class plSwimmingController; +class plSwimStrategy; class plAvBrainSwim : public plArmatureBrain { public: @@ -73,7 +72,7 @@ public: bool IsSwimming(); hsScalar GetSurfaceDistance() { return fSurfaceDistance; } - plSwimmingController *fCallbackAction; + plSwimStrategy *fSwimStrategy; static const hsScalar kMinSwimDepth; protected: @@ -86,8 +85,6 @@ protected: hsBool IProcessBehaviors(double time, float elapsed); virtual hsBool IInitAnimations(); - bool IAttachAction(); - bool IDetachAction(); void IProbeSurface(); hsBool IHandleControlMsg(plControlEventMsg* msg); float IGetTargetZ(); diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.cpp deleted file mode 100644 index c192f3b9..00000000 --- a/MOULOpenSourceClientPlugin/Plasma20/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. -hsBool LinearVelocity(hsVector3 &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat); -void AngularVelocity(hsScalar &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat); -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, hsBool 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 hsScalar 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= TRACKED_NEW plWalkingStrategy(fController); - fController->SetMovementSimulationInterface(fWalkingStrategy); - } - else - fWalkingStrategy = nil; -} - -void plWalkingController::RecalcVelocity(double timeNow, double timePrev, hsBool 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 - // LinearVelocity is always (0,0,0) outside the PhysController - 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= TRACKED_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); -// -// hsBool isPhysical = !fPhysical->GetProperty(plSimulationInterface::kPinned); -// const Havok::Vector3 straightUp(0.0f, 0.0f, 1.0f); -// hsBool 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); - hsScalar 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 hsScalar threshold = hsScalarDegToRad(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] = hsATan2(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]) - { - 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))) - 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 += (hsScalar)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 = (hsScalar)(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 += (hsScalar)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); - hsScalar 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= TRACKED_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 = TRACKED_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 hsBool 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; - hsBool valid = xfabs < maxVel && yfabs < maxVel && zfabs < maxVel; - - if (valid) - { - outputV = prev2Now; - result = true; - } - } - } - - return result; -} - -static void AngularVelocity(hsScalar &outputV, float elapsed, hsMatrix44 &prevMat, hsMatrix44 &curMat) -{ - outputV = 0.f; - hsScalar appliedVelocity = 0.0f; - hsVector3 prevForward = GetYAxis(prevMat); - hsVector3 curForward = GetYAxis(curMat); - - hsScalar angleSincePrev = AngleRad2d(curForward.fX, curForward.fY, prevForward.fX, prevForward.fY); - hsBool sincePrevSign = angleSincePrev > 0.0f; - if (angleSincePrev > hsScalarPI) - angleSincePrev = angleSincePrev - TWO_PI; - - const hsVector3 startForward = hsVector3(0, -1.0, 0); // the Y orientation of a "resting" armature.... - hsScalar angleSinceStart = AngleRad2d(curForward.fX, curForward.fY, startForward.fX, startForward.fY); - hsBool sinceStartSign = angleSinceStart > 0.0f; - if (angleSinceStart > hsScalarPI) - 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvCallbackAction.h deleted file mode 100644 index c4e374ba..00000000 --- a/MOULOpenSourceClientPlugin/Plasma20/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, hsScalar height, hsScalar 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, hsScalar 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 hsScalar 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, hsBool useAnim = true); - void SetTurnStrength(hsScalar val) { fTurnStr = val; } - hsScalar GetTurnStrength() { return fTurnStr; } - virtual void ActivateController()=0; -protected: - plSceneObject* fRootObject; - plPhysicalControllerCore* fController; - plAGApplicator* fRootApp; - hsScalar fAnimAngVel; - hsVector3 fAnimPosVel; - hsScalar 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, hsBool 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); - hsScalar GetAirTime() const { return fWalkingStrategy ? fWalkingStrategy->GetAirTime() : 0.f; } - void ResetAirTime() { if (fWalkingStrategy) fWalkingStrategy->ResetAirTime(); } - hsScalar GetForwardVelocity() const; - void ActivateController(); - // Check these after the avatar the avatar hits the ground for his total - // hangtime and impact velocity. - hsScalar 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. - hsScalar fControlledFlightTime; - int fControlledFlight; // Count of how many are currently forcing flight - plWalkingStrategy* fWalkingStrategy; - hsScalar fImpactTime; - hsVector3 fImpactVelocity; - bool fClearImpact; - bool fGroundLastFrame;//used for a test to pass the event of first getting air during a jump - static const hsScalar kControlledFlightThreshold; -}; -class plSwimmingController: public plAnimatedController -{ -public : - plSwimmingController(plSceneObject* rootObject, plAGApplicator* rootApp, plPhysicalControllerCore* controller); - virtual ~plSwimmingController(); - void SetSurface(plSwimRegionInterface *region, hsScalar surfaceHeight){ - fSwimmingStrategy->SetSurface(region,surfaceHeight); - } - hsScalar GetBuoyancy() { return fSwimmingStrategy->GetBuoyancy(); } - hsBool IsOnGround() { return fSwimmingStrategy->IsOnGround(); } - hsBool 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp index f303c47f..2c214e92 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvLadderModifier.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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 "hsTypes.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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp index 3b70bca4..84b80cfe 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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" @@ -462,10 +462,10 @@ hsBool 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp index d728b8fd..9f132f2a 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarSDLModifier.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp index b3ed9ea6..cf67d229 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plAvatarTasks.cpp @@ -53,7 +53,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 @@ -689,7 +689,7 @@ hsBool plAvOneShotTask::Process(plArmatureMod *avatar, plArmatureBrain *brain, d 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index 9dff5e3d..710645ff 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -40,548 +40,601 @@ 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 "../../NucleusLib/inc/plPhysical.h" #include "../../NucleusLib/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(hsScalarDegToRad(80.f))) -const hsScalar 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, hsScalar height, hsScalar 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) +{ + fLastGlobalLoc.Reset(); + fPrevSubworldW2L.Reset(); +} + +const plCoordinateInterface* plPhysicalControllerCore::GetSubworldCI() { - if(left.TimeHit < right.TimeHit) return true; - else return false; + if (fWorldKey) + { + plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded()); + if (so) + return so->GetCoordinateInterface(); + } + + return nil; } -plMovementStrategy::plMovementStrategy(plPhysicalControllerCore* core) + +void plPhysicalControllerCore::IncrementAngle(hsScalar deltaAngle) { - this->fTimeInAir=0.0f; - fCore=core; - fOwner=core->GetOwner(); - this->fPreferedControllerHeight=kGENERICCONTROLLERHEIGHT; - this->fPreferedControllerWidth=kGENERICCONTROLLERRADIUS; + hsVector3 axis; + hsScalar angle; + + fLocalRotation.NormalizeIfNeeded(); + fLocalRotation.GetAngleAxis(&angle, &axis); + if (axis.fZ < 0) + angle = (2.0f * hsScalarPI) - angle; // axis is backwards, so reverse the angle too + + angle += deltaAngle; + + // make sure we wrap around + if (angle < 0.0f) + angle = (2.0f * hsScalarPI) + angle; // angle is -, so this works like a subtract + if (angle >= (2.0f * hsScalarPI)) + angle = angle - (2.0f * hsScalarPI); + + // set the new angle + axis.Set(0.0f, 0.0f, 1.0f); + fLocalRotation.SetAngleAxis(angle, axis); } -void plMovementStrategy::IApplyKinematic() + +void plPhysicalControllerCore::IApply(hsScalar delSecs) { - // first apply sceneobject update to the kinematic + 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, hsScalar alpha) { + if (fEnabled) + { + // Update local position and acheived velocity + fLastLocalPosition = fLocalPosition; + GetPositionSim(fLocalPosition); + hsVector3 displacement = (hsVector3)(fLocalPosition - fLastLocalPosition); + fAchievedLinearVelocity = displacement / fSimLength; + + displacement /= (hsScalar)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 + { + // 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(hsScalar delSecs) -{ - fSimLength=delSecs; - hsAssert(fMovementInterface, "plPhysicalControllerCore::Apply() missing a movement interface"); - if(fMovementInterface)fMovementInterface->Apply(delSecs); -} -void plPhysicalControllerCore::PostStep(hsScalar delSecs) -{ - hsAssert(fMovementInterface, "plPhysicalControllerCore::PostStep() missing a movement interface"); - if(fMovementInterface)fMovementInterface->PostStep(delSecs); -} -void plPhysicalControllerCore::Update(hsScalar delSecs) +void plPhysicalControllerCore::IUpdateNonPhysical(hsScalar 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)) + { + 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(); + } } -void plPhysicalControllerCore::SendCorrectionMessages() + +void plPhysicalControllerCore::ISendCorrectionMessages(bool dirtySynch) { - plSceneObject* so = plSceneObject::ConvertNoRef(fOwner->ObjectIsLoaded()); - plCorrectionMsg* corrMsg = TRACKED_NEW plCorrectionMsg; + plCorrectionMsg* corrMsg = TRACKED_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, hsScalar height, hsScalar 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() -{ - if (IsEnabledChanged())HandleEnableChanged(); - if (IsKinematicChanged())HandleKinematicChanged(); - if (IsKinematicEnableNextUpdate())HandleKinematicEnableNextUpdate(); -} -void plPhysicalControllerCore::MoveActorToSim() +// 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) { - // 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(hsScalar deltaAngle) -{ - 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 += deltaAngle; - // 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)); } -void plPhysicalControllerCore::UpdateWorldRelativePos() +void plAnimatedMovementStrategy::RecalcVelocity(double timeNow, hsScalar elapsed, hsBool 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); + + // Update controller rotation + hsScalar zRot = fAnimAngularVel + fTurnStr; + if (hsABS(zRot) > 0.0001f) + fController->IncrementAngle(zRot * elapsed); + } + else { - const hsMatrix44& l2w = ci->GetLocalToWorld(); - fLastGlobalLoc = l2w * fLastGlobalLoc; + fAnimLinearVel.Set(0.0f, 0.0f, 0.0f); + fAnimAngularVel = 0.0f; } + + // 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; + hsBool 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; + hsScalar appliedVelocity = 0.0f; + hsVector3 prevForward = GetYAxis(prevMat); + hsVector3 curForward = GetYAxis(curMat); + + hsScalar angleSincePrev = AngleRad2d(curForward.fX, curForward.fY, prevForward.fX, prevForward.fY); + hsBool sincePrevSign = angleSincePrev > 0.0f; + if (angleSincePrev > hsScalarPI) + angleSincePrev = angleSincePrev - TWO_PI; + + const hsVector3 startForward = hsVector3(0.0f, -1.0f, 0.0f); // the Y orientation of a "resting" armature.... + hsScalar angleSinceStart = AngleRad2d(curForward.fX, curForward.fY, startForward.fX, startForward.fY); + hsBool sinceStartSign = angleSinceStart > 0.0f; + if (angleSinceStart > hsScalarPI) + 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(hsScalar delSecs) { - //Apply Should Only be Called from a PhysicalControllerCore - hsAssert(fCore,"No Core shouldn't be Applying"); - UInt32 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. - hsScalar prevZVel = AchievedLinearVelocity.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; - LinearVelocity.fZ = prevZVel + grav; - } + if (velNorm.MagnitudeSquared() > 0.0f) + velNorm.Normalize(); - // 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 (!IsOnGround() || IsOnFalseGround()) - { - // We're not on solid ground, so we should be sliding against whatever - // we're hitting (like a rock cliff). Each vector in fSlidingNormals is - // the surface normal of a collision that's too steep to be ground, so - // we project our current velocity onto that plane and slide along the - // wall. - // - // Also, sometimes PhysX reports a bunch of collisions from the wall, - // but nothing from underneath (when there should be). So if we're not - // touching ground, we offset the avatar in the direction of the - // surface normal(s). This doesn't fix the issue 100%, but it's a hell - // of a lot better than nothing, and suitable duct tape until a future - // PhysX revision fixes the issue. - // - // Yes, there's room for optimization here if we care. - hsVector3 offset(0.f, 0.f, 0.f); - for (int i = 0; i < fContactNormals.GetCount(); i++) + if (velNorm * fSlidingNormals[i] < 0.0f) { - offset += fContactNormals[i]; - hsVector3 velNorm = LinearVelocity; - - if (velNorm.MagnitudeSquared() > 0) - velNorm.Normalize(); - - if (velNorm * fContactNormals[i] < 0) - { - hsVector3 proj = (velNorm % fContactNormals[i]) % fContactNormals[i]; - if (velNorm * proj < 0) - proj *= -1.f; - LinearVelocity = LinearVelocity.Magnitude() * proj; - } - } - if (offset.MagnitudeSquared() > 0) - { - // 5 ft/sec is roughly the speed we walk backwards. - // The higher the value, the less likely you'll trip - // the bug, and this seems reasonable. - offset.Normalize(); - LinearVelocity += offset * 5.0f; - } - } - //make terminal velocity equal to k. it is wrong but has been this way and - //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 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(hsScalar 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 hsScalar threshold = hsScalarDegToRad(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] = hsATan2(fContactNormals[i].fY, fContactNormals[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; + fTimeInAir += delSecs; + if (fHeadHit) + { + // 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); } } + + 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; + } + + if (fControlledFlight != 0) + { + if (IsOnGround()) + fControlledFlightTime = fTimeInAir; + + if (fControlledFlightTime > kControlledFlightThreshold) + EnableControlledFlight(false); + } } -void plWalkingStrategy::Update(hsScalar delSecs) + +void plWalkingStrategy::AddContactNormals(hsVector3& vec) { - //Update Should Only be Called from a PhysicalControllerCore - hsAssert(fCore,"Running Update: but have no Core"); - hsScalar AngularVelocity=fCore->GetAngularVelocity(); - hsVector3 LinearVelocity=fCore->GetLinearVelocity(); + hsScalar 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); + 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) +} + +bool plWalkingStrategy::EnableControlledFlight(bool status) +{ + if (status) { - fCore->MoveActorToSim(); - if (AngularVelocity != 0.f) - { - hsScalar 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 - hsScalar 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 (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 hsScalar plWalkingStrategy::kAirTimeThreshold = 0.1f; +const hsScalar plWalkingStrategy::kControlledFlightThreshold = 1.0f; - LinearVelocity.Set(0.f, 0.f, 0.f); - AngularVelocity = 0.f; - fCore->SetVelocities(LinearVelocity,AngularVelocity); +// 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(hsScalar delSecs) +{ + hsVector3 velocity = fController->GetLinearVelocity(); + hsVector3 achievedVelocity = fController->GetAchievedLinearVelocity(); + + IAdjustBuoyancy(); + + //trying to dampen the oscillations + hsScalar retardent = 0.0f; + static hsScalar finalBobSpeed = 0.5f; + if ((achievedVelocity.fZ > finalBobSpeed) || (achievedVelocity.fZ < -finalBobSpeed)) + retardent = achievedVelocity.fZ * -0.90f; + + hsScalar zacc = (1.0f - fBuoyancy) * kGravity + retardent; + velocity.fZ += (zacc * delSecs); + + velocity.fZ += achievedVelocity.fZ; + + // Water Current + if (fCurrentRegion != nil) + { + hsScalar 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; -void plWalkingStrategy::IAddContactNormals(hsVector3& vec) -{ - //TODO: ADD in functionality to Adjust walkable slope for controller, also apply that in here + 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) +{ hsScalar 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, hsScalar surfaceHeight) { - fPreferedControllerHeight=kSWIMHEIGHT; - fPreferedControllerWidth=kSWIMRADIUS; - fCore->SetMovementSimulationInterface(this); + fCurrentRegion = region; + fSurfaceHeight = surfaceHeight; } void plSwimStrategy::IAdjustBuoyancy() { @@ -599,383 +652,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(hsScalar delSecs) -{ - hsAssert(fCore,"PlSwimStrategy::Apply No Core shouldn't be Applying"); - UInt32 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(); - hsScalar zacc; - hsScalar retardent=0.0f; - static hsScalar 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); - hsScalar 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; - hsScalar angvel=fCore->GetAngularVelocity(); - fCore->SetAngularVelocity(angvel +angCurrent); - } + +// Dynamic Walking Strategy +plDynamicWalkingStrategy::plDynamicWalkingStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller) + : plWalkingStrategy(rootApp, controller) +{ } -void plSwimStrategy::Update(hsScalar delSecs) + +void plDynamicWalkingStrategy::Apply(hsScalar delSecs) { - hsAssert(fCore,"Running Update: but have no Core"); - hsScalar 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) - { - hsScalar 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 - hsScalar 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. + hsScalar prevZVel = achievedVelocity.fZ; + if (IsOnGround()) + prevZVel = hsMinimum(prevZVel, 0.f); + + velocity.fZ = prevZVel + (kGravity * delSecs); } - else plMovementStrategySimulationInterface::IAddContactNormals(vec); -} -void plSwimStrategy::SetSurface(plSwimRegionInterface *region, hsScalar surfaceHeight) -{ - fCurrentRegion=region; - fSurfaceHeight=surfaceHeight; + + if (velocity.fZ < kTerminalVelocity) + velocity.fZ = kTerminalVelocity; + + fController->SetPushingPhysical(nil); + fController->SetFacingPushingPhysical(false); + fGroundHit = fFalseGround = false; + + hsScalar groundZVelocity; + if (ICheckForGround(groundZVelocity)) + velocity.fZ += groundZVelocity; + + fController->SetLinearVelocitySim(velocity); } -void plRidingAnimatedPhysicalStrategy::Apply(hsScalar delSecs) + +bool plDynamicWalkingStrategy::ICheckForGround(hsScalar& 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 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 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) { - hsBool 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 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 + else { - return true; - } - -} -void plRidingAnimatedPhysicalStrategy::Update(hsScalar delSecs) -{ - if (!fCore->IsEnabled() || fCore->IsKinematic()) - { - fCore->UpdateSubstepNonPhysical(); - return; - } - fCore->CheckAndHandleAnyStateChanges(); -} -void plRidingAnimatedPhysicalStrategy::PostStep(hsScalar delSecs) -{ - if(!(!fCore->IsEnabled() || fCore->IsKinematic())) - { - if (!fGroundHit && !fFalseGround) - fTimeInAir += delSecs; - else - fTimeInAir = 0.f; - hsVector3 AchievedLinearVelocity, LinearVelocity; - AchievedLinearVelocity = fCore->GetLinearVelocity(); - hsScalar 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) - { - hsScalar 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h index bc96f697..8f56ddc2 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h @@ -41,310 +41,284 @@ 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(hsScalarDegToRad(55.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(hsScalarDegToRad(55.f))) - virtual void Apply(hsScalar delSecs)=0; - virtual void Update(hsScalar 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(hsScalar 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 - hsScalar 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(hsScalar delSecs); - virtual void Update(hsScalar delSecs); - virtual void PostStep(hsScalar delSecs); - // A disabled avatar doesn't move or accumulate air time if he's off the ground. + plPhysicalControllerCore(plKey ownerSceneObject, hsScalar height, hsScalar 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, hsScalar height, hsScalar radius); - virtual plMovementStrategySimulationInterface* GetMovementInterface(){return fMovementInterface;} - plPhysicalControllerCore(plKey ownerSceneObject, hsScalar height, hsScalar 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, hsBool vsDynamics, hsBool vsStatics, + UInt32& 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(hsScalar 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 hsScalar angvel){ fAngularVelocity=angvel;} - virtual void SetVelocities(const hsVector3& linearVel, hsScalar angVel) - { - fLinearVelocity=linearVel; - fAngularVelocity=angVel; - } - virtual const hsVector3& GetLinearVelocity() ; - virtual hsScalar 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(hsScalar radius, hsScalar height)=0; - virtual hsScalar GetControllerWidth(){return fRadius;} - virtual hsScalar GetControllerHeight(){return fHeight;} - virtual void ResetAchievedLinearVelocity() - { - fAchievedLinearVelocity.Set(0.f,0.f,0.f); - } - virtual int SweepControllerPath(const hsPoint3& startPos,const hsPoint3& endPos, hsBool vsDynamics, hsBool vsStatics, UInt32& 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 hsScalar GetHeight() {return fHeight;} - virtual hsScalar 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(hsBool actLikeAnAnimatedPhys)=0; - virtual hsBool BehavingLikeAnAnimatedPhysical()=0; -protected: + // 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 + hsScalar GetRadius() const { return fRadius; } + hsScalar GetHeight() const { return fHeight; } + + // Create a new controller instance - Implemented in the physics system + static plPhysicalControllerCore* Create(plKey ownerSO, hsScalar height, hsScalar radius); + +protected: + virtual void IHandleEnableChanged() = 0; + + void IApply(hsScalar delSecs); + void IUpdate(int numSubSteps, hsScalar alpha); + void IUpdateNonPhysical(hsScalar alpha); + + void ISendCorrectionMessages(bool dirtySynch = false); + plKey fOwner; + plKey fWorldKey; + hsScalar fHeight; hsScalar 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; + + hsScalar fSimLength; + hsQuat fLocalRotation; + hsPoint3 fLocalPosition; + hsPoint3 fLastLocalPosition; + + hsMatrix44 fLastGlobalLoc; hsMatrix44 fPrevSubworldW2L; - hsVector3 fDisplacementThisStep; - hsScalar fSimLength; - //physical properties hsVector3 fLinearVelocity; - hsScalar 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 hsScalar GetAirTime() const { return fTimeInAir; } - virtual void ResetAirTime() { fTimeInAir = 0.f; } - + plMovementStrategy(plPhysicalControllerCore* controller); + virtual ~plMovementStrategy() { } + + virtual void Apply(hsScalar delSecs) = 0; + virtual void Update(hsScalar delSecs) { } + + virtual void AddContactNormals(hsVector3& vec) { } + virtual void Reset(bool newAge); + virtual bool IsKinematic() { return true; } + protected: - virtual hsBool IRequireBehaviourLikeAnAnimatedPhysical()=0; - virtual void IApplyKinematic(); - plPhysicalControllerCore* fCore; - hsVector3 fLinearAcceleration; - hsScalar fAngularAcceleration; - plKey fOwner; - static const hsScalar kAirTimeThreshold; - hsScalar fTimeInAir; - hsScalar fPreferedControllerWidth; - hsScalar fPreferedControllerHeight; - + plPhysicalControllerCore* fController; +}; + +class plAnimatedMovementStrategy : public plMovementStrategy +{ +public: + plAnimatedMovementStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller); + virtual ~plAnimatedMovementStrategy() { } + + void RecalcVelocity(double timeNow, hsScalar elapsed, hsBool useAnim = true); + void SetTurnStrength(hsScalar val) { fTurnStr = val; } + hsScalar 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; + hsScalar fAnimAngularVel; + hsScalar 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(hsScalar delSecs); - virtual void Update(hsScalar delSecs); + virtual void Update(hsScalar delSecs); + + virtual void AddContactNormals(hsVector3& vec); + virtual void Reset(bool newAge); + 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(){}; - + + hsScalar GetAirTime() const { return fTimeInAir; } + void ResetAirTime() { fTimeInAir = 0.0f; } + + hsScalar 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: + static const hsScalar kAirTimeThreshold; + static const hsScalar kControlledFlightThreshold; + + hsTArray fSlidingNormals; + + hsVector3 fImpactVelocity; + hsScalar fImpactTime; + + hsScalar fTimeInAir; - void ICheckForFalseGround(); + hsScalar fControlledFlightTime; + int fControlledFlight; + bool fGroundHit; bool fFalseGround; - bool fHitHead; - bool fOnTopOfAnimatedPhysLastFrame; - hsTArray fPrevSlidingNormals; - virtual hsBool 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, hsScalar surfaceHeight); + plSwimStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller); + virtual ~plSwimStrategy() { } + virtual void Apply(hsScalar delSecs); - virtual void Update(hsScalar delSecs); - hsScalar GetBuoyancy() { return fBuoyancy; } - hsBool IsOnGround() { return fOnGround; } - hsBool HadContacts() { return fHadContacts; } - virtual void IAddContactNormals(hsVector3& vec); + + virtual void AddContactNormals(hsVector3& vec); + + void SetSurface(plSwimRegionInterface* region, hsScalar surfaceHeight); + + hsScalar GetBuoyancy() const { return fBuoyancy; } + bool IsOnGround() const { return fOnGround; } + bool HadContacts() const { return fHadContacts; } + protected: - virtual hsBool IRequireBehaviourLikeAnAnimatedPhysical(){return true;} -private: void IAdjustBuoyancy(); + hsScalar fBuoyancy; - hsBool fOnGround; - hsBool fHadContacts; hsScalar 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(hsScalar delSecs); - virtual void Update(hsScalar delSecs); - virtual void PostStep(hsScalar 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 hsBool IRequireBehaviourLikeAnAnimatedPhysical(){return false;} - bool ICheckMove(const hsPoint3& startPos, const hsPoint3& desiredPos); - hsBool fNeedVelocityOverride; - hsVector3 fOverrideVelocity; - bool fStartJump; + bool ICheckForGround(hsScalar& zVelocity); }; + #endif// PLPHYSICALCONTROLLERCORE_H + diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp index 4d40e538..57d9ee7c 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plInputCore/plSceneInputInterface.cpp @@ -73,7 +73,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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp index c1f0d5f2..5872072a 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plModifier/plExcludeRegionModifier.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp index a2ea1df0..5b8f23a8 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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 "hsTypes.h" #include "plCollisionDetector.h" @@ -65,6 +64,7 @@ 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" @@ -770,7 +770,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 @@ -940,11 +940,11 @@ hsBool plPanicLinkRegion::MsgReceive(plMessage* msg) plArmatureMod* avMod = IGetAvatarModifier(pCollMsg->fOtherKey); if (avMod) { - 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); } @@ -1168,4 +1168,4 @@ hsBool plRidingAnimatedPhysicalDetector::MsgReceive(plMessage *msg) return true; } return plSimpleRegionSensor::MsgReceive(msg); -} +} diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h index 24b4583e..b98d6f97 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h @@ -72,25 +72,6 @@ namespace plSimDefs 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 - }; - /** Different types of line-of-sight requests. */ enum LOSReqType { From e92dc59db22ad913b09a775ac4bc1457b5907cd0 Mon Sep 17 00:00:00 2001 From: Skoader Date: Sat, 16 Jun 2012 21:48:32 +1000 Subject: [PATCH 02/14] Updated plPXPhysicalControllerCore to match 69377bc74f2e While based heavily on the old implementation, this is essentially a rewrite. Notable changes - Controllers are now updated at the same fixed frequency as the simulation. Resulting output is interpolated between steps to precisely match the frame delta. Physics work is only done when enough time has passed to perform a step. The kinematic actor that followed around the controller has been removed. The underlying kinematic actor created by the NxController is now used for triggering. A new sim group was added for a kinematically controlled avatar. 2 unused files removed - plPXPhysicalController.h & plPXPhysicalController.cpp --- .../PubUtilLib/plPhysX/plLOSDispatch.cpp | 3 +- .../plPhysX/plPXPhysicalController.cpp | 1279 --------------- .../plPhysX/plPXPhysicalController.h | 211 --- .../plPhysX/plPXPhysicalControllerCore.cpp | 1455 ++++++----------- .../plPhysX/plPXPhysicalControllerCore.h | 163 +- .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 108 +- .../PubUtilLib/plPhysX/plSimulationMgr.h | 1 + .../Plasma/PubUtilLib/plPhysical/plSimDefs.h | 4 +- 8 files changed, 654 insertions(+), 2570 deletions(-) delete mode 100644 MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp delete mode 100644 MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.h diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp index 933f1679..5fd769f1 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plLOSDispatch.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp deleted file mode 100644 index 3543f43e..00000000 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.cpp +++ /dev/null @@ -1,1279 +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 "../plMessage/plCollideMsg.h" - -#include "NxPhysics.h" -#include "ControllerManager.h" -#include "NxCapsuleController.h" -#include "NxCapsuleShape.h" - -#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 -hsBool plPXPhysicalController::fDebugDisplay = false; -#endif // PLASMA_EXTERNAL_RELEASE - -static ControllerManager gControllerMgr; -static std::vector gControllers; -static 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 TRACKED_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 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 = TRACKED_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 = TRACKED_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 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 = TRACKED_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 = TRACKED_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); - } -} - -#include "../plSurface/hsGMaterial.h" -#include "../plSurface/plLayerInterface.h" - -// 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; - - hsBool 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) - { - hsBool 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 -#include "../plPipeline/plDebugText.h" - -void plPXPhysicalController::IDrawDebugDisplay() -{ - plDebugText &debugTxt = plDebugText::Instance(); - char strBuf[ 2048 ]; - int lineHeight = debugTxt.GetFontSize() + 4; - UInt32 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalController.h deleted file mode 100644 index c0907df7..00000000 --- a/MOULOpenSourceClientPlugin/Plasma20/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; - hsBool 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 hsBool 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index a5947ada..1ccab366 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -45,7 +45,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #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" @@ -53,155 +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" -#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 +#include "ControllerManager.h" +static ControllerManager gControllerMgr; +static std::vector gControllers; +static bool gRebuildCache = false; #ifndef PLASMA_EXTERNAL_RELEASE hsBool 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.6f +#define kPhysZOffset ((kCCTZOffset + (kPhysHeightCorrection / 2)) - 0.05f) +#define kAvatarMass 200.0f -#define AvatarMass 200.f - -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; - static hsScalar SlopeLimit = kSLOPELIMIT; 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((hsScalar)hit.worldPos.x, (hsScalar)hit.worldPos.y, (hsScalar)hit.worldPos.z); - NxExtendedVec3 controllerPos=hit.controller->getPosition(); - hsVector3 bottomOfTheCapsule((hsScalar)controllerPos.x,(hsScalar)controllerPos.y,(hsScalar)controllerPos.z); - bottomOfTheCapsule.fZ=bottomOfTheCapsule.fZ-(ac->fHeight/2.0f + ac->fRadius); - if (actor.isDynamic() ) + if (actor.isDynamic()) { - if((hit.worldPos.z- bottomOfTheCapsule.fZ)<=ac->fRadius)//bottom hemisphere - { - //onTopOfSlopeLimit - if (phys && phys->GetProperty(plSimulationInterface::kPhysAnim)) - { - if(normal.fZ>=0) - {//we consider this ground - ac->fMovementInterface->AddOnTopOfObject(phys); - } - } - } - if ( !actor.readBodyFlag(NX_BF_KINEMATIC) && !actor.readBodyFlag(NX_BF_FROZEN)) + 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)) + // Don't apply force when standing on top of an object. + if (normal.fZ < 0.85f) { - plSynchedObject* obj = plSynchedObject::ConvertNoRef(phys->GetObjectKey()->ObjectIsLoaded()); - obj->SetNetGroupConstant(plNetGroup::kNetGroupLocalPhysicals); - // Tell all the other clients that we own this physical - plSetNetGroupIDMsg* setNetGroupID = TRACKED_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); - // We only allow horizontal pushes. Vertical pushes when we stand on - // dynamic objects creates useless stress on the solver. - - hsVector3 vel=ac->GetLinearVelocity()- plPXConvert::Vector( actor.getLinearVelocity()); - if(dirdotup>=0)vel.fZ=0.001f; - else vel.fZ=0.0f; - static hsScalar kAvieMass = 140.f/32.f; - if (!vel.IsEmpty()) - { - static hsScalar kForceScale = 140.0f; - NxF32 coeff; - NxExtendedVec3 norm2=hit.controller->getPosition(); - norm2.x=hit.worldPos.x-bottomOfTheCapsule.fX; - norm2.y=hit.worldPos.y-bottomOfTheCapsule.fY; - if((hit.worldPos.z- bottomOfTheCapsule.fZ)fRadius)//bottom hemisphere - { - norm2.normalize(); - norm2.z=0.01f; - } - else if((hit.worldPos.z- bottomOfTheCapsule.fZ)<(ac->fRadius+ac->fHeight)) + hsVector3 velocity = controller->GetLinearVelocity(); + velocity.fZ = 0.0f; + float length = velocity.Magnitude(); + if (length > 0) { - norm2.z=0.0f; - norm2.normalize(); - } - else - {//must be the top so the normal is displacement from the pos - center - //of top hemisphere - norm2.z=hit.worldPos.z - ((ac->fRadius+ac->fHeight + bottomOfTheCapsule.fZ)); - norm2.normalize(); + // 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); } - - - float proj=(float)(norm2.x*dir.fX+dir.fY*norm2.y+dir.fZ*norm2.z); - coeff =abs(proj*kForceScale*vel.Magnitude()); - vel.fZ=(hsScalar)norm2.z; - vel.fY=(hsScalar)norm2.y; - vel.fX=(hsScalar)norm2.x; - phys->SetHitForce(vel*coeff, pos); } } } else // else if the avatar hit a static { + controller->fMovementStrategy->AddContactNormals(normal); return NX_ACTION_NONE; } 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; } @@ -209,168 +153,34 @@ public: { return NX_ACTION_NONE; } - -} gMyReport; - +} gControllerHitReport; plPhysicalControllerCore* plPhysicalControllerCore::Create(plKey ownerSO, hsScalar height, hsScalar width) { - // Test to see how many controller there already is - if ( !plPXPhysicalControllerCore::fPXControllersMax || plPXPhysicalControllerCore::NumControllers() < plPXPhysicalControllerCore::fPXControllersMax ) + if (!plPXPhysicalControllerCore::fPXControllersMax || gControllers.size() < plPXPhysicalControllerCore::fPXControllersMax) { - hsScalar radius = width / 2.f; - hsScalar realHeight = height - width + kPhysicalHeightFudge; - return TRACKED_NEW plPXPhysicalControllerCore(ownerSO, realHeight,radius); + hsScalar radius = width / 2.0f; + hsScalar realHeight = height - width; + return TRACKED_NEW plPXPhysicalControllerCore(ownerSO, realHeight, radius); } 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, hsScalar height, hsScalar radius) - : plPhysicalControllerCore(ownerSO,height,radius) - , fController(nil) - , fProxyGen(nil) - , fKinematicActor(nil) - ,fPreferedRadius(radius) - ,fPreferedHeight(height) - , fBehavingLikeAnimatedPhys(true) -{ - fLocalPosition.Set(0, 0, 0); - fLocalRotation.Set(0, 0, 0, 1); + : plPhysicalControllerCore(ownerSO, height, radius), + fController(nil), + fActor(nil), + fProxyGen(nil), + fKinematicCCT(true) +{ + ICreateController(fLocalPosition); + fActor->raiseActorFlag(NX_AF_DISABLE_COLLISION); gControllers.push_back(this); - fLastGlobalLoc.Reset(); - ICreateController(); - Enable(false); -} - -void plPXPhysicalControllerCore::ISetGlobalLoc(const hsMatrix44& l2w) -{ - fLastGlobalLoc = l2w; - // Update our subworld position and rotation - const plCoordinateInterface* subworldCI = GetSubworldCI(); - if (subworldCI) - { - const hsMatrix44& w2s = fPrevSubworldW2L; - hsMatrix44 l2s = w2s * l2w; - - l2s.GetTranslate(&fLocalPosition); - fLocalRotation.SetFromMatrix44(l2s); - } - else - { - l2w.GetTranslate(&fLocalPosition); - fLocalRotation.SetFromMatrix44(l2w); - } - hsMatrix44 w2l; - l2w.GetInverse(&w2l); - if (fProxyGen) - fProxyGen->SetTransform(l2w, w2l); - // Update the physical position - NxExtendedVec3 nxPos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kPhysZOffset); - fController->setPosition(nxPos); - IMatchKinematicToController(); } plPXPhysicalControllerCore::~plPXPhysicalControllerCore() { - IDeleteController(); - //need to make sure my queued messages are released - for(int j=0;jgetPosition(); - 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 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 (fEnabled || fKinematic) - { - 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 ((fEnabled || fKinematic) && fBehavingLikeAnimatedPhys) - { - if (plSimulationMgr::fExtraProfile) - SimLog("Moving kinematic from %f,%f,%f to %f,%f,%f",pos.fX,pos.fY,pos.fZ+kPhysZOffset,kinPos.x,kinPos.y,kinPos.z ); - // use the position - fKinematicActor->moveGlobalPosition(newPos); - } - else - { - if (plSimulationMgr::fExtraProfile) - SimLog("Setting kinematic from %f,%f,%f to %f,%f,%f",pos.fX,pos.fY,pos.fZ+kPhysZOffset,kinPos.x,kinPos.y,kinPos.z ); - fKinematicActor->setGlobalPosition(newPos); - } - } - } -} - -void plPXPhysicalControllerCore::ISetKinematicLoc(const hsMatrix44& l2w) -{ - hsPoint3 kPos; - // Update our subworld position and rotation - const plCoordinateInterface* subworldCI = GetSubworldCI(); - if (subworldCI) - { - const hsMatrix44& w2s = subworldCI->GetWorldToLocal(); - hsMatrix44 l2s = w2s * l2w; - - l2s.GetTranslate(&kPos); - } - else - { - l2w.GetTranslate(&kPos); - } - - hsMatrix44 w2l; - l2w.GetInverse(&w2l); - if (fProxyGen) - fProxyGen->SetTransform(l2w, w2l); + IDeleteController(); - // add z offset - kPos.fZ += kPhysZOffset; - // Update the physical position of kinematic - if (fEnabled|| fKinematic) - 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(hsScalar(nxPos.x), hsScalar(nxPos.y), hsScalar(nxPos.z) - kPhysZOffset); - } - else - { - NxVec3 Pos = fKinematicActor->getGlobalPosition(); - pos.Set(hsScalar(Pos.x), hsScalar(Pos.y), hsScalar(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 = 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; - capDesc.materialIndex= plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0,0.0); - actorDesc.shapes.pushBack(&capDesc); - NxBodyDesc bodyDesc; - bodyDesc.mass = AvatarMass;//1.f; - 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 (...) + // Release any queued messages we may have + int numMsgs = fQueuedCollideMsgs.size(); + if (numMsgs) { - 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; + for (int i = 0; i < numMsgs; ++i) + delete fQueuedCollideMsgs[i]; - // 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 = TRACKED_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 = AvatarMass; - actorDesc.body = &bodyDesc; - bodyDesc.flags = NX_BF_KINEMATIC; - bodyDesc.flags |=NX_BF_DISABLE_GRAVITY ; - actorDesc.name = "AvatarTriggerKinematicGuy"; - fSeeking=false; - try - { - fKinematicActor = scene->createActor(actorDesc); - } - catch (...) - { - hsAssert(false, "Actor creation crashed"); + fQueuedCollideMsgs.clear(); } - // set the matrix to be the same as the controller's actor... that should orient it to be the same - //fKinematicActor->setGlobalPose(actor->getGlobalPose()); - - // the proxy for the debug display - //hsAssert(!fProxyGen, "Already have proxy gen, double read?"); - - hsColorRGBA physColor; - 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 = TRACKED_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 = TRACKED_NEW plCollideMsg; - msg->fOtherKey = fOwner; - msg->fEntering = entering; - msg->AddReceiver(physical->GetObjectKey()); - if(!deferUntilNextSim) - { -#ifndef PLASMA_EXTERNAL_RELEASE - DetectorLog("Sending an %s msg to %s" , entering? "entering":"exit", physical->GetObjectKey()->GetName()); -#endif - msg->Send(); - } - else - { -#ifndef PLASMA_EXTERNAL_RELEASE - DetectorLog("Queuing an %s msg to %s, which will be sent after the next simstep" , entering? "entering":"exit", physical->GetObjectKey()->GetName()); -#endif - //these will be fired in update prestep on the next lap - fQueuedCollideMsgs.Append(msg); - } - } - } - } - } -#ifndef PLASMA_EXTERNAL_RELEASE - DetectorLog("Done informing from plPXPhysicalControllerCore::IInformDetectors"); -#endif - } -} -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); + } } } } @@ -752,60 +230,36 @@ 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"); - fWorldKey = world; - if (GetSubworldCI()) - fPrevSubworldW2L = GetSubworldCI()->GetWorldToLocal(); - // Update our subworld position and rotation + + // Update Local Position and rotation + fWorldKey = world; const plCoordinateInterface* subworldCI = GetSubworldCI(); if (subworldCI) { - const hsMatrix44& w2s = fPrevSubworldW2L; - hsMatrix44 l2s = w2s * fLastGlobalLoc; + fPrevSubworldW2L = subworldCI->GetWorldToLocal(); + hsMatrix44 l2s = fPrevSubworldW2L * fLastGlobalLoc; l2s.GetTranslate(&fLocalPosition); fLocalRotation.SetFromMatrix44(l2s); } else { + fPrevSubworldW2L.Reset(); fLastGlobalLoc.GetTranslate(&fLocalPosition); fLocalRotation.SetFromMatrix44(fLastGlobalLoc); } - hsMatrix44 w2l; - fLastGlobalLoc.GetInverse(&w2l); - if (fProxyGen) - fProxyGen->SetTransform(fLastGlobalLoc, w2l); - // Update the physical position - SimLog("creating new controller"); - hsPoint3 PositionPlusOffset=fLocalPosition; - PositionPlusOffset.fZ +=kPhysZOffset; - //placing new controller and kinematic in the appropriate location - ICreateController(PositionPlusOffset); - RebuildCache(); - } -} -const plCoordinateInterface* plPXPhysicalControllerCore::GetSubworldCI() const -{ - if (fWorldKey) - { - plSceneObject* so = plSceneObject::ConvertNoRef(fWorldKey->ObjectIsLoaded()); - if (so) - return so->GetCoordinateInterface(); + + fLastLocalPosition = fLocalPosition; + + // Create new controller + ICreateController(fLocalPosition); } - return nil; } -// For the avatar SDL only + void plPXPhysicalControllerCore::GetState(hsPoint3& pos, float& zRot) { // Temporarily use the position point while we get the z rotation @@ -816,9 +270,7 @@ void plPXPhysicalControllerCore::GetState(hsPoint3& pos, float& zRot) zRot = (2 * hsScalarPI) - 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()); @@ -844,366 +296,516 @@ void plPXPhysicalControllerCore::SetState(const hsPoint3& pos, float zRot) so->FlushTransform(); } } -// kinematic stuff .... should be just for when playing a behavior... -void plPXPhysicalControllerCore::Kinematic(bool state) + +void plPXPhysicalControllerCore::SetMovementStrategy(plMovementStrategy* strategy) { - if (fKinematic != state) + if (fKinematicCCT != strategy->IsKinematic()) { - fKinematic = state; - if (fKinematic) - { - // See ISendUpdates for why we don't re-enable right away - fController->setCollision(false); -#ifdef PHYSX_KINEMATIC_IS_DISABLED - fKinematicActor->clearActorFlag(NX_AF_DISABLE_COLLISION); -#endif - } - else - { - fKinematicChanged = true; - } + IDeleteController(); + fKinematicCCT = !fKinematicCCT; + ICreateController(fLocalPosition); } + + fMovementStrategy = strategy; } -bool plPXPhysicalControllerCore::IsKinematic() -{ - return fKinematic; -} -void plPXPhysicalControllerCore::GetKinematicPosition(hsPoint3& pos) + +void plPXPhysicalControllerCore::SetGlobalLoc(const hsMatrix44& l2w) { - pos.Set(-1,-1,-1); - if ( fKinematicActor ) + fLastGlobalLoc = l2w; + + // Update our local position and rotation + const plCoordinateInterface* subworldCI = GetSubworldCI(); + if (subworldCI) { - NxVec3 klPos = fKinematicActor->getGlobalPosition(); - pos.Set(hsScalar(klPos.x), hsScalar(klPos.y), hsScalar(klPos.z) - kPhysZOffset); + hsMatrix44 l2s = fPrevSubworldW2L * l2w; + + l2s.GetTranslate(&fLocalPosition); + fLocalRotation.SetFromMatrix44(l2s); } -} -void plPXPhysicalControllerCore::UpdatePoststep( hsScalar delSecs) -{ - // Apparently the user data field of the controllers is broken -// UInt32 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]; + l2w.GetTranslate(&fLocalPosition); + fLocalRotation.SetFromMatrix44(l2w); + } - 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(); - } + fLastLocalPosition = fLocalPosition; + + if (fProxyGen) + { + hsMatrix44 w2l; + l2w.GetInverse(&w2l); + fProxyGen->SetTransform(l2w, w2l); + } + + // Update the physical position + if (fKinematicCCT) + { + NxExtendedVec3 pos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kCCTZOffset); + fController->setPosition(pos); + } + else + { + NxVec3 pos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kPhysZOffset); + if (fActor->readBodyFlag(NX_BF_KINEMATIC)) + fActor->moveGlobalPosition(pos); + else + fActor->setGlobalPosition(pos); } } -void plPXPhysicalControllerCore::UpdatePrestep(hsScalar delSecs) + +void plPXPhysicalControllerCore::GetPositionSim(hsPoint3& pos) { - for (int i = 0; i < gControllers.size(); i++) + if (fKinematicCCT) + { + const NxExtendedVec3& extPos = fController->getPosition(); + pos.Set((hsScalar)extPos.x, (hsScalar)extPos.y, (hsScalar)extPos.z - kCCTZOffset); + } + else { - plPXPhysicalControllerCore* ac = gControllers[i]; + NxVec3 nxPos = fActor->getGlobalPosition(); + pos.Set(nxPos.x, nxPos.y, nxPos.z - kPhysZOffset); + } +} - hsAssert(ac, "Bad avatar controller"); - //FIXME -#ifndef PLASMA_EXTERNAL_RELEASE - ac->fDbgCollisionInfo.SetCount(0); -#endif // PLASMA_EXTERNAL_RELEASE +void plPXPhysicalControllerCore::Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults) +{ + NxU32 colFlags = 0; - 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(); - int storedCollideMsgs=ac->fQueuedCollideMsgs.GetCount(); - if(storedCollideMsgs) - { - plSimulationMgr* simMgr=plSimulationMgr::GetInstance(); - for(int j=0; jAddCollisionMsg(ac->fQueuedCollideMsgs[j]); - } - ac->fQueuedCollideMsgs.SetCount(0); - } - ac->Apply(delSecs); - } -#ifndef PLASMA_EXTERNAL_RELEASE - if (fDebugDisplay) - ac->IDrawDebugDisplay(); -#endif // PLASMA_EXTERNAL_RELEASE - } - gRebuildCache = false; + fController->move(plPXConvert::Vector(displacement), collideWith, 0.00001f, colFlags); + + 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(hsScalar 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, hsBool vsDynamics, hsBool vsStatics, + UInt32& 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,fEnable); -#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; + hsBool blended = ((mat->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask)); + float radius = fRadius; + myDraw = plDrawableGenerator::GenerateSphericalDrawable(fLocalPosition, radius, + mat, fLastGlobalLoc, blended, + nil, &idx, myDraw); - UInt32 collideFlags = - 1<ObjectIsLoaded()); + if (so) { - collideFlags|=(1<GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendMask)); + + myDraw = plDrawableGenerator::GenerateConicalDrawable(fRadius*10, fHeight*10, + mat, so->GetLocalToWorld(), blended, + nil, &idx, myDraw); } - NxScene* myscene = plSimulationMgr::GetInstance()->GetScene(this->fWorldKey); -// NxShape** response=TRACKED_NEW NxShape*[2]; - - NxVec3 center(fLocalPosition.fX,fLocalPosition.fY,fLocalPosition.fZ+fPreferedRadius); - NxSegment Seg(center,center); - const NxCapsule newCap(Seg,fPreferedRadius); - int numintersect =myscene->checkOverlapCapsule(newCap,NX_ALL_SHAPES,collideFlags); - //with new capsule dimensions check for overlap - //with objects we would collide with - - if(numintersect==0) +*/ + return myDraw; +} + +void plPXPhysicalControllerCore::AddDynamicHit(plPXPhysical* phys) +{ + int numHits = fDynamicHits.size(); + for (int i = 0; i < numHits; ++i) { - fHeight=fPreferedHeight; - fRadius=fPreferedRadius; - fController->setRadius(fRadius); - fController->setHeight(fHeight); - - fNeedsResize=false; + if (fDynamicHits[i] == phys) + return; } -// delete[] response; + fDynamicHits.push_back(phys); } -void plPXPhysicalControllerCore::SetControllerDimensions(hsScalar radius, hsScalar height) + +void plPXPhysicalControllerCore::Apply(hsScalar delSecs) { - fNeedsResize=false; - if(fRadius!=radius) + plPXPhysicalControllerCore* controller; + int numControllers = gControllers.size(); + for (int i = 0; i < numControllers; ++i) { - fNeedsResize=true; + controller = gControllers[i]; + if (gRebuildCache && controller->fController) + controller->fController->reportSceneChanged(); + +#ifndef PLASMA_EXTERNAL_RELEASE + controller->fDbgCollisionInfo.SetCount(0); +#endif + + controller->IDispatchQueuedMsgs(); + controller->IApply(delSecs); + controller->IProcessDynamicHits(); } - if(fHeight!=height) + + gRebuildCache = false; +} +void plPXPhysicalControllerCore::Update(int numSubSteps, hsScalar alpha) +{ + gControllerMgr.updateControllers(); + + plPXPhysicalControllerCore* controller; + int numControllers = gControllers.size(); + for (int i = 0; i < numControllers; ++i) { - fNeedsResize=true; + controller = gControllers[i]; + + controller->IUpdate(numSubSteps, alpha); + +#ifndef PLASMA_EXTERNAL_RELEASE + if (fDebugDisplay) + controller->IDrawDebugDisplay(); +#endif } - fPreferedRadius=radius; - fPreferedHeight=height; } - -void plPXPhysicalControllerCore::LeaveAge() +void plPXPhysicalControllerCore::UpdateNonPhysical(hsScalar alpha) { - SetPushingPhysical(nil); - if(fWorldKey) this->SetSubworld(nil); - this->fMovementInterface->LeaveAge(); + plPXPhysicalControllerCore* controller; + int numControllers = gControllers.size(); + for (int i = 0; i < numControllers; ++i) + { + controller = gControllers[i]; + controller->IUpdateNonPhysical(alpha); + } } -int plPXPhysicalControllerCore::SweepControllerPath(const hsPoint3& startPos, const hsPoint3& endPos, hsBool vsDynamics, hsBool vsStatics, - UInt32& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut) + +void plPXPhysicalControllerCore::RebuildCache() { gRebuildCache = true; } + +plPXPhysicalControllerCore* plPXPhysicalControllerCore::GetController(NxActor& actor) { - NxCapsule tempCap; - tempCap.p0 =plPXConvert::Point( startPos); - tempCap.p0.z = tempCap.p0.z + fPreferedRadius; - tempCap.radius = fPreferedRadius ; - tempCap.p1 = tempCap.p0; - tempCap.p1.z = tempCap.p1.z + fPreferedHeight; + plPXPhysicalControllerCore* controller; + int numControllers = gControllers.size(); + for (int i = 0; i < numControllers; ++i) + { + controller = gControllers[i]; + if (controller->fActor == &actor) + return controller; + } - NxVec3 vec; - vec.x = endPos.fX - startPos.fX; - vec.y = endPos.fY - startPos.fY; - vec.z = endPos.fZ - startPos.fZ; + return nil; +} - int numberofHits = 0; - int HitsReturned = 0; - WhatWasHitOut.clear(); - NxScene *myscene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); - NxSweepQueryHit whatdidIhit[10]; - unsigned int flags = NX_SF_ALL_HITS; - if(vsDynamics) - flags |= NX_SF_DYNAMICS; - if(vsStatics) - flags |= NX_SF_STATICS; - numberofHits = myscene->linearCapsuleSweep(tempCap, vec, flags, nil, 10, whatdidIhit, nil, vsSimGroups); - if(numberofHits) - {//we hit a dynamic object lets make sure it is not animatable - for(int i=0; igetActor().userData; - CurrentHit.Norm.fX = whatdidIhit[i].normal.x; - CurrentHit.Norm.fY = whatdidIhit[i].normal.y; - CurrentHit.Norm.fZ = whatdidIhit[i].normal.z; - if(CurrentHit.ObjHit != nil) - { - hsPoint3 where; - where.fX = whatdidIhit[i].point.x; - where.fY = whatdidIhit[i].point.y; - where.fZ = whatdidIhit[i].point.z; - CurrentHit.locHit = where; - CurrentHit.TimeHit = whatdidIhit[i].t ; - WhatWasHitOut.insert(CurrentHit); - HitsReturned++; - } - } +bool plPXPhysicalControllerCore::AnyControllersInThisWorld(plKey world) +{ + plPXPhysicalControllerCore* controller; + int numControllers = gControllers.size(); + for (int i = 0; i < numControllers; ++i) + { + controller = gControllers[i]; + if (controller->GetSubworld() == world) + return true; + } + + return false; +} +int plPXPhysicalControllerCore::GetNumberOfControllersInThisSubWorld(plKey world) +{ + int count = 0; + plPXPhysicalControllerCore* controller; + int numControllers = gControllers.size(); + for (int i = 0; i < numControllers; ++i) + { + controller = gControllers[i]; + if (controller->GetSubworld() == world) + ++count; } - return HitsReturned; + return count; } -void plPXPhysicalControllerCore::BehaveLikeAnimatedPhysical(hsBool 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) - { - //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 + if (count < maxToReturn) { - //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; } } } -} -hsBool 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 hsScalar 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 = TRACKED_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, hsScalar angVel) -{ - SetLinearVelocity(linearVel); - SetAngularVelocity(angVel); + + DetectorLog("Done informing from plPXPhysicalControllerCore::IInformDetectors"); } -void plPXPhysicalControllerCore::IMatchControllerToKinematic() +void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos) { - NxExtendedVec3 newpos; - NxVec3 pos=fKinematicActor->getGlobalPosition(); - newpos.x=pos.x; - newpos.y=pos.y; - newpos.z=pos.z; - fController->setPosition(newpos); + NxScene* scene = plSimulationMgr::GetInstance()->GetScene(fWorldKey); + + if (fKinematicCCT) + { + // Use PhysX character controller + NxCapsuleControllerDesc desc; + desc.position.x = pos.fX; + desc.position.y = pos.fY; + desc.position.z = pos.fZ + kCCTZOffset; + desc.upDirection = NX_Z; + desc.slopeLimit = kSlopeLimit; + desc.skinWidth = kCCTSkinWidth; + desc.stepOffset = kCCTStepOffset; + desc.callback = &gControllerHitReport; + desc.userData = this; + desc.radius = fRadius; + desc.height = fHeight; + desc.interactionFlag = NXIF_INTERACTION_EXCLUDE; + fController = (NxCapsuleController*)gControllerMgr.createController(scene, desc); + fActor = fController->getActor(); + + // Set the actor group - Dynamics are in group 1 and will report on everything in group 0. + // We don't want notifications + fActor->setGroup(2); + + // Set the shape group. Not used by the NxController itself, + // But required for correct group interactions in the simulation. + NxShape* shape = fActor->getShapes()[0]; + shape->setGroup(plSimDefs::kGroupAvatarKinematic); + + // In PhysX 2, the kinematic actors scale factor isn't exposed. + // It is hardcoded at 0.8 which doesn't suit, so we have to manually adjust its dimensions. + float kineRadius = fRadius + kCCTSkinWidth; + float kineHeight = fHeight + kPhysHeightCorrection; + NxCapsuleShape* capShape = shape->isCapsule(); + capShape->setDimensions(kineRadius, kineHeight); + capShape->setLocalPosition(NxVec3(0.0f, (kPhysHeightCorrection / 2.0f), 0.0f)); + } + else + { + // Use dynamic actor for the character controller + NxCapsuleShapeDesc capDesc; + capDesc.materialIndex = plSimulationMgr::GetInstance()->GetMaterialIdx(scene, 0.0f, 0.0f); + capDesc.radius = fRadius + kCCTSkinWidth; + capDesc.height = fHeight + kPhysHeightCorrection; + + NxBodyDesc bodyDesc; + bodyDesc.mass = kAvatarMass; + bodyDesc.flags = NX_BF_DISABLE_GRAVITY; + bodyDesc.flags |= NX_BF_FROZEN_ROT; + + if (fEnabled) + capDesc.group = plSimDefs::kGroupAvatar; + else + { + bodyDesc.flags |= NX_BF_KINEMATIC; + capDesc.group = plSimDefs::kGroupAvatarKinematic; + } + + NxActorDesc actorDesc; + actorDesc.shapes.pushBack(&capDesc); + actorDesc.body = &bodyDesc; + actorDesc.group = 2; + + actorDesc.globalPose.M.rotX(NxHalfPiF32); + actorDesc.globalPose.t.x = pos.fX; + actorDesc.globalPose.t.y = pos.fY; + actorDesc.globalPose.t.z = pos.fZ + kPhysZOffset; + + fActor = scene->createActor(actorDesc); + } + + fSeeking = false; + + // Create proxy for the debug display + /* FIXME + // the avatar proxy doesn't seem to work... not sure why? + hsColorRGBA physColor; + hsScalar opac = 1.0f; + + // local avatar is light purple and transparent + physColor.Set(.2f, .1f, .2f, 1.f); + opac = 0.8f; + + fProxyGen = TRACKED_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); } -} -#include "../plSurface/hsGMaterial.h" -#include "../plSurface/plLayerInterface.h" + 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; - hsBool 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) { - hsBool 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 = TRACKED_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" @@ -1239,3 +841,4 @@ void plPXPhysicalControllerCore::IDrawDebugDisplay() } } #endif PLASMA_EXTERNAL_RELEASE + diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h index 4cf25f38..4697d66b 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h +++ b/MOULOpenSourceClientPlugin/Plasma20/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,98 +61,112 @@ public: hsBool fOverlap; }; #endif // PLASMA_EXTERNAL_RELEASE + class plPXPhysicalControllerCore: public plPhysicalControllerCore { - friend PXControllerHitReportWalk; public: plPXPhysicalControllerCore(plKey ownerSO, hsScalar height, hsScalar radius); ~plPXPhysicalControllerCore(); - //should actually be a 3 vector but everywhere else it is assumed to be just around Z - - inline virtual void Move(hsVector3 displacement, unsigned int collideWith, unsigned int &collisionResults); - // A disabled avatar doesn't move or accumulate air time if he's off the ground. + + // An ArmatureMod has its own idea about when physics should be enabled/disabled. + // Use plArmatureModBase::EnablePhysics() instead. virtual void Enable(bool enable); - - virtual void SetSubworld(plKey world) ; - virtual const plCoordinateInterface* GetSubworldCI() const ; + + // Subworld + virtual void SetSubworld(plKey world); + // For the avatar SDL only virtual void GetState(hsPoint3& pos, float& zRot); virtual void SetState(const hsPoint3& pos, float zRot); - // kinematic stuff .... should be just for when playing a behavior... - virtual void Kinematic(bool state); - virtual bool IsKinematic(); - virtual void GetKinematicPosition(hsPoint3& pos); - virtual const hsMatrix44& GetPrevSubworldW2L(){ return fPrevSubworldW2L; } - //when seeking no longer want to interact with exclusion regions - virtual void GetWorldSpaceCapsule(NxCapsule& cap) const; - static void RebuildCache(); - virtual const hsMatrix44& GetLastGlobalLoc(){return fLastGlobalLoc;} - virtual void SetKinematicLoc(const hsMatrix44& l2w){ISetKinematicLoc(l2w);} - virtual void SetGlobalLoc(const hsMatrix44& l2w){ISetGlobalLoc(l2w);} - virtual void HandleEnableChanged(); - virtual void HandleKinematicChanged(); - virtual void HandleKinematicEnableNextUpdate(); - virtual void GetPositionSim(hsPoint3& pos){IGetPositionSim(pos);} - virtual void MoveKinematicToController(hsPoint3& pos); - virtual const hsPoint3& GetLocalPosition(){return fLocalPosition;} - virtual void SetControllerDimensions(hsScalar radius, hsScalar 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, hsBool vsDynamics, + hsBool vsStatics, UInt32& 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(hsScalar delSecs); + + // Call post-sim to update controllers + static void Update(int numSubSteps, hsScalar alpha); + + // Update controllers when not performing a physics step + static void UpdateNonPhysical(hsScalar 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(hsScalar delSecs); - static void UpdatePoststep(hsScalar delSecs); - static void UpdatePostSimStep(hsScalar delSecs); - virtual plDrawableSpans* CreateProxy(hsGMaterial* mat, hsTArray& idx, plDrawableSpans* addTo); -#ifndef PLASMA_EXTERNAL_RELEASE - static hsBool fDebugDisplay; -#endif // PLASMA_EXTERNAL_RELEASE - static void plPXPhysicalControllerCore::SetMaxNumberOfControllers(int max) { fPXControllersMax = max; } + 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, hsBool vsDynamics, hsBool vsStatics, UInt32& vsSimGroups, std::multiset< plControllerSweepRecord >& WhatWasHitOut); - virtual void BehaveLikeAnimatedPhysical(hsBool actLikeAnAnimatedPhys); - virtual hsBool 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 hsScalar angvel); - virtual void SetVelocities(const hsVector3& linearVel, hsScalar angVel); +#ifndef PLASMA_EXTERNAL_RELEASE + static hsBool 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(); + + virtual void IHandleEnableChanged(); + + void IInformDetectors(bool entering); + + void ICreateController(const hsPoint3& pos); void IDeleteController(); - void IInformDetectors(bool entering,bool deferUntilNextSim); - void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos); - NxActor* fKinematicActor; - NxCapsuleController* fController; + + void IDispatchQueuedMsgs(); + void IProcessDynamicHits(); + #ifndef PLASMA_EXTERNAL_RELEASE - hsTArray fDbgCollisionInfo; void IDrawDebugDisplay(); + hsTArray fDbgCollisionInfo; #endif - void plPXPhysicalControllerCore::IHandleResize(); - hsTArray fQueuedCollideMsgs; - hsScalar fPreferedRadius; - hsScalar 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; - hsBool fBehavingLikeAnimatedPhys; + + std::vector fQueuedCollideMsgs; + std::vector fDynamicHits; + + NxCapsuleController* fController; + NxActor* fActor; + + plPhysicalProxy* fProxyGen; + bool fKinematicCCT; }; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index a97ac70f..d35a0959 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -67,80 +67,26 @@ class SensorReport : public NxUserTriggerReport { virtual void onTrigger(NxShape& triggerShape, NxShape& otherShape, NxTriggerFlag status) { - // Get our trigger physical. This should definitely have a plPXPhysical - plPXPhysical* triggerPhys = (plPXPhysical*)triggerShape.getActor().userData; - hsBool 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()); + hsBool doReport = false; - if (plSimulationMgr::fExtraProfile) - DetectorLogRed("-->%s %s (status=%x) other@(%f,%f,%f)",triggerPhys->GetObjectKey()->GetName(),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(),triggerPhys->GetGroup(),otherPhys->GetObjectKey()->GetName(),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()); - 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()); - 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()); - 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(),triggerPhys->GetGroup()); - } - else - { - hsPoint3 avpos; - controller->GetPositionSim(avpos); - DetectorLogRed("-->Avatar at (%f,%f,%f)",avpos.fX,avpos.fY,avpos.fZ); - } - } } } @@ -408,6 +354,7 @@ plSimulationMgr::plSimulationMgr() : fSuspended(true) , fMaxDelta(kDefaultMaxDelta) , fStepSize(kDefaultStepSize) + , fAccumulator(0.0f) , fLOSDispatch(TRACKED_NEW plLOSDispatch()) , fSoundMgr(new plPhysicsSoundMgr) , fLog(nil) @@ -496,6 +443,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); @@ -503,6 +451,10 @@ 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. @@ -616,8 +568,7 @@ void plSimulationMgr::UpdateAvatarInDetector(plKey world, plPXPhysical* detector if ( actors[i]->userData == nil ) { // we go a controller - bool isController; - plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(*actors[i],&isController); + plPXPhysicalControllerCore* controller = plPXPhysicalControllerCore::GetController(*actors[i]); if (controller && controller->IsEnabled()) { plKey avatar = controller->GetOwner(); @@ -644,20 +595,29 @@ void plSimulationMgr::Advance(float delSecs) if (fSuspended) return; - if (delSecs > fMaxDelta) + fAccumulator += delSecs; + if (fAccumulator < fStepSize) + { + // Not enough time has passed to perform a substep. + plPXPhysicalControllerCore::UpdateNonPhysical(fAccumulator / fStepSize); + return; + } + else if (fAccumulator > fMaxDelta) { if (fExtraProfile) - Log("Step clamped from %f to limit of %f", delSecs, fMaxDelta); - delSecs = fMaxDelta; + Log("Step clamped from %f to limit of %f", fAccumulator, fMaxDelta); + fAccumulator = fMaxDelta; } - plProfile_IncCount(StepLen, (int)(delSecs*1000)); -#ifndef PLASMA_EXTERNAL_RELASE - UInt32 stepTime = hsTimer::GetPrecTickCount(); -#endif + // Perform as many whole substeps as possible saving the remainder in our accumulator. + int numSubSteps = (int)(fAccumulator / fStepSize); + float delta = numSubSteps * fStepSize; + 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++) { @@ -672,12 +632,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 / fStepSize); //sending off and clearing the Collision Messages generated by scene->simulate IDispatchCollisionMessages(); @@ -754,9 +715,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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h index 60ad3d00..459035ee 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h @@ -159,6 +159,7 @@ protected: float fMaxDelta; float fStepSize; + float fAccumulator; // A utility class to keep track of a request for a physical synchronization. // These requests must pass a certain criteria (see the code for the latest) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h index b98d6f97..f0546ff6 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plSimDefs.h @@ -68,8 +68,10 @@ namespace plSimDefs kGroupLOSOnly, //kExcludeRegion setting up so only blocks avatars and only when not in seek mode kGroupExcludeRegion, + // A kinematic avatar only interacts with dynamics and detectors + kGroupAvatarKinematic, // Just for error checking - kGroupMax, + kGroupMax }; /** Different types of line-of-sight requests. */ From 264bc3355a4edb95bc4353242d25fbf2ba4ca941 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Fri, 28 Sep 2012 22:44:23 +0200 Subject: [PATCH 03/14] Fix horizontal mouse-look while standing still. --- .../PubUtilLib/plAvatar/plPhysicalControllerCore.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index 710645ff..304bd46d 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -253,11 +253,6 @@ void plAnimatedMovementStrategy::RecalcVelocity(double timeNow, hsScalar elapsed IRecalcLinearVelocity(elapsed, prevMat, curMat); IRecalcAngularVelocity(elapsed, prevMat, curMat); - - // Update controller rotation - hsScalar zRot = fAnimAngularVel + fTurnStr; - if (hsABS(zRot) > 0.0001f) - fController->IncrementAngle(zRot * elapsed); } else { @@ -265,6 +260,11 @@ void plAnimatedMovementStrategy::RecalcVelocity(double timeNow, hsScalar elapsed fAnimAngularVel = 0.0f; } + // Update controller rotation + hsScalar zRot = fAnimAngularVel + fTurnStr; + if (hsABS(zRot) > 0.0001f) + fController->IncrementAngle(zRot * elapsed); + // Update controller velocity fController->SetLinearVelocity(fAnimLinearVel); } From 025fb1fb02edb2f9477d3c1b0118323cee569e19 Mon Sep 17 00:00:00 2001 From: Skoader Date: Sat, 13 Oct 2012 21:21:33 +1100 Subject: [PATCH 04/14] Improve simulation timing at low frame rates. Increased kDefaultMaxDelta to 0.15. Added a small bias to combat a truncation issue. --- .../Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index d35a0959..ddace665 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -261,7 +261,7 @@ public: // ///////////////////////////////////////////////////////////////// -#define kDefaultMaxDelta 0.1 // if the step is greater than .1 seconds, clamp to that +#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 ///////////////////////////////////////////////////////////////// @@ -610,7 +610,7 @@ void plSimulationMgr::Advance(float delSecs) } // Perform as many whole substeps as possible saving the remainder in our accumulator. - int numSubSteps = (int)(fAccumulator / fStepSize); + int numSubSteps = (int)(fAccumulator / fStepSize + 0.000001f); float delta = numSubSteps * fStepSize; fAccumulator -= delta; From 87b8dfae0944044ba71fc220e5a13c15e33ea124 Mon Sep 17 00:00:00 2001 From: Skoader Date: Mon, 22 Oct 2012 12:57:16 +1100 Subject: [PATCH 05/14] Fix subworld transition bug Use the actual global location, not the interpolated location when moving between subworlds. Rebuild the controller cache. --- .../plPhysX/plPXPhysicalControllerCore.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index 1ccab366..f6b79f69 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -236,6 +236,25 @@ void plPXPhysicalControllerCore::SetSubworld(plKey world) IInformDetectors(false); IDeleteController(); + // 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; const plCoordinateInterface* subworldCI = GetSubworldCI(); @@ -257,6 +276,7 @@ void plPXPhysicalControllerCore::SetSubworld(plKey world) // Create new controller ICreateController(fLocalPosition); + RebuildCache(); } } From b5296d614fffb2c777e2141a30d624da0caba0f8 Mon Sep 17 00:00:00 2001 From: Skoader Date: Tue, 23 Oct 2012 13:45:21 +1100 Subject: [PATCH 06/14] Fix warping an avatar triggers all detectors along the path When explicitly moving an avatar over the given threshold, teleport the underlying actor most of the way before moving the controller. --- .../plPhysX/plPXPhysicalControllerCore.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index f6b79f69..a5cd51ae 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -334,6 +334,7 @@ void plPXPhysicalControllerCore::SetGlobalLoc(const hsMatrix44& l2w) fLastGlobalLoc = l2w; // Update our local position and rotation + hsPoint3 prevPosition = fLocalPosition; const plCoordinateInterface* subworldCI = GetSubworldCI(); if (subworldCI) { @@ -360,8 +361,20 @@ void plPXPhysicalControllerCore::SetGlobalLoc(const hsMatrix44& l2w) // Update the physical position if (fKinematicCCT) { - NxExtendedVec3 pos(fLocalPosition.fX, fLocalPosition.fY, fLocalPosition.fZ + kCCTZOffset); - fController->setPosition(pos); + hsVector3 disp(&fLocalPosition, &prevPosition); + if (disp.Magnitude() > 2.f) + { + // 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 { From 32ba4e06e2d0b77b665591c33bb6599443f504fd Mon Sep 17 00:00:00 2001 From: Skoader Date: Fri, 26 Oct 2012 10:48:30 +1100 Subject: [PATCH 07/14] Fix controlled flight bug fControlledFlight state should be handled outside of the physics step. --- .../plAvatar/plPhysicalControllerCore.cpp | 23 +++++++++++-------- .../plAvatar/plPhysicalControllerCore.h | 4 +++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index 304bd46d..60ac3f14 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -503,15 +503,6 @@ void plWalkingStrategy::Update(hsScalar delSecs) fImpactVelocity = (hsVector3)fController->GetLocalRotation().Rotate(&fImpactVelocity); fClearImpact = false; } - - if (fControlledFlight != 0) - { - if (IsOnGround()) - fControlledFlightTime = fTimeInAir; - - if (fControlledFlightTime > kControlledFlightThreshold) - EnableControlledFlight(false); - } } void plWalkingStrategy::AddContactNormals(hsVector3& vec) @@ -535,6 +526,20 @@ void plWalkingStrategy::Reset(bool newAge) } } +void plWalkingStrategy::RecalcVelocity(double timeNow, hsScalar elapsed, hsBool useAnim) +{ + if (fControlledFlight != 0) + { + if (IsOnGround()) + fControlledFlightTime = fTimeInAir; + + if (fControlledFlightTime > kControlledFlightThreshold) + EnableControlledFlight(false); + } + + plAnimatedMovementStrategy::RecalcVelocity(timeNow, elapsed, useAnim); +} + bool plWalkingStrategy::EnableControlledFlight(bool status) { if (status) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h index 8f56ddc2..4fd2806e 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h @@ -214,7 +214,7 @@ public: plAnimatedMovementStrategy(plAGApplicator* rootApp, plPhysicalControllerCore* controller); virtual ~plAnimatedMovementStrategy() { } - void RecalcVelocity(double timeNow, hsScalar elapsed, hsBool useAnim = true); + virtual void RecalcVelocity(double timeNow, hsScalar elapsed, hsBool useAnim = true); void SetTurnStrength(hsScalar val) { fTurnStr = val; } hsScalar GetTurnStrength() const { return fTurnStr; } @@ -240,6 +240,8 @@ public: virtual void AddContactNormals(hsVector3& vec); virtual void Reset(bool newAge); + virtual void RecalcVelocity(double timeNow, hsScalar elapsed, hsBool useAnim = true); + bool HitGroundInThisAge() const { return fHitGroundInThisAge; } bool IsOnGround() const { return fTimeInAir < kAirTimeThreshold || fFalseGround; } From d02cde1703b4b677f4fa4b64ce6f31b2127a3fa5 Mon Sep 17 00:00:00 2001 From: Skoader Date: Fri, 26 Oct 2012 17:36:04 +1100 Subject: [PATCH 08/14] Disabled avatar updates Only update disabled avatars between steps if in a subworld and then don't interpolate their position. --- .../plAvatar/plPhysicalControllerCore.cpp | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index 60ac3f14..516b1cca 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -195,20 +195,37 @@ void plPhysicalControllerCore::IUpdateNonPhysical(hsScalar alpha) const hsMatrix44& l2w = so->GetCoordinateInterface()->GetLocalToWorld(); if (CompareMatrices(fLastGlobalLoc, l2w, 0.0001f)) { - hsVector3 displacement = (hsVector3)(fLocalPosition - fLastLocalPosition); - hsPoint3 interpLocalPos = fLastLocalPosition + (displacement * alpha); - - fLocalRotation.MakeMatrix(&fLastGlobalLoc); - fLastGlobalLoc.SetTranslate(&interpLocalPos); - const plCoordinateInterface* subworldCI = GetSubworldCI(); - if (subworldCI) + if (fEnabled) { - const hsMatrix44& subL2W = subworldCI->GetLocalToWorld(); - fLastGlobalLoc = subL2W * fLastGlobalLoc; - fPrevSubworldW2L = subworldCI->GetWorldToLocal(); + 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(); + ISendCorrectionMessages(); + } + } } } From 860b071bb29b301e025ae456187c4a3a3640502e Mon Sep 17 00:00:00 2001 From: Skoader Date: Fri, 26 Oct 2012 18:03:40 +1100 Subject: [PATCH 09/14] Clear linear velocity after each update. --- .../Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index 516b1cca..f2ad919a 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -501,6 +501,9 @@ void plWalkingStrategy::Update(hsScalar delSecs) } } + hsVector3 zeroVelocity(0.f, 0.f, 0.f); + fController->SetLinearVelocity(zeroVelocity); + if (!fHitGroundInThisAge && IsOnGround()) fHitGroundInThisAge = true; From 03ecfe00b47e77d4e803e46ca1608ada46869abf Mon Sep 17 00:00:00 2001 From: Skoader Date: Fri, 26 Oct 2012 18:13:22 +1100 Subject: [PATCH 10/14] Increase height correction to match graphical representation Provides more accurate interaction with detectors when the avatar is moving up or down. Also decreases the severity of the PhysX trigger hull bug in some detectors. This change doesn't affect world collisions. --- .../Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index a5cd51ae..d615f60c 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -73,7 +73,7 @@ int plPXPhysicalControllerCore::fPXControllersMax = 0; #define kCCTSkinWidth 0.1f #define kCCTStepOffset 0.6f #define kCCTZOffset ((fRadius + (fHeight / 2)) + kCCTSkinWidth) -#define kPhysHeightCorrection 0.6f +#define kPhysHeightCorrection 0.8f #define kPhysZOffset ((kCCTZOffset + (kPhysHeightCorrection / 2)) - 0.05f) #define kAvatarMass 200.0f From 3d14321f2625418525a05eb82d23ced0ddbf6824 Mon Sep 17 00:00:00 2001 From: Skoader Date: Sun, 11 Nov 2012 22:59:04 +1100 Subject: [PATCH 11/14] Clear impact velocity on WalkingStrategy Reset. Fixes landing behaviours incorrectly firing after a brain transition. --- .../Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index f2ad919a..e20ec22f 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -537,6 +537,8 @@ void plWalkingStrategy::AddContactNormals(hsVector3& vec) void plWalkingStrategy::Reset(bool newAge) { plMovementStrategy::Reset(newAge); + fImpactVelocity.Set(0.0f, 0.0f, 0.0f); + fImpactTime = 0.0f; if (newAge) { fTimeInAir = 0.0f; From 79377e2b95330c9f841d718760804945cb3923f8 Mon Sep 17 00:00:00 2001 From: Skoader Date: Sun, 11 Nov 2012 23:48:51 +1100 Subject: [PATCH 12/14] Clear achieved linear velocity on disabled avatars. --- .../Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp index e20ec22f..4ed1cc50 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.cpp @@ -172,6 +172,8 @@ void plPhysicalControllerCore::IUpdate(int numSubSteps, hsScalar alpha) } else { + fAchievedLinearVelocity.Set(0.0f, 0.0f, 0.0f); + // Update global location if in a subworld const plCoordinateInterface* subworldCI = GetSubworldCI(); if (subworldCI) From 2c06d3b2d3258ae6b717f8d3b102891236b9743f Mon Sep 17 00:00:00 2001 From: Skoader Date: Mon, 12 Nov 2012 01:40:30 +1100 Subject: [PATCH 13/14] Only apply height correction to human avatars. --- .../PubUtilLib/plAvatar/plArmatureMod.cpp | 2 +- .../plAvatar/plPhysicalControllerCore.h | 2 +- .../plPhysX/plPXPhysicalControllerCore.cpp | 17 +++++++++++------ .../plPhysX/plPXPhysicalControllerCore.h | 3 ++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp index 051219c7..32828049 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp @@ -2006,7 +2006,7 @@ hsBool plArmatureMod::ValidatePhysics() return false; if (!fController) - fController = plPhysicalControllerCore::Create(GetTarget(0)->GetKey(), fPhysHeight, fPhysWidth); + fController = plPhysicalControllerCore::Create(GetTarget(0)->GetKey(), fPhysHeight, fPhysWidth, (fBodyType == kBoneBaseMale || fBodyType == kBoneBaseFemale)); if (fController) { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h index 4fd2806e..c4477ee4 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plAvatar/plPhysicalControllerCore.h @@ -150,7 +150,7 @@ public: hsScalar GetHeight() const { return fHeight; } // Create a new controller instance - Implemented in the physics system - static plPhysicalControllerCore* Create(plKey ownerSO, hsScalar height, hsScalar radius); + static plPhysicalControllerCore* Create(plKey ownerSO, hsScalar height, hsScalar radius, bool human); protected: virtual void IHandleEnableChanged() = 0; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp index d615f60c..90483b35 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.cpp @@ -155,23 +155,24 @@ public: } } gControllerHitReport; -plPhysicalControllerCore* plPhysicalControllerCore::Create(plKey ownerSO, hsScalar height, hsScalar width) +plPhysicalControllerCore* plPhysicalControllerCore::Create(plKey ownerSO, hsScalar height, hsScalar width, bool human) { if (!plPXPhysicalControllerCore::fPXControllersMax || gControllers.size() < plPXPhysicalControllerCore::fPXControllersMax) { hsScalar radius = width / 2.0f; hsScalar realHeight = height - width; - return TRACKED_NEW plPXPhysicalControllerCore(ownerSO, realHeight, radius); + return TRACKED_NEW plPXPhysicalControllerCore(ownerSO, realHeight, radius, human); } return nil; } -plPXPhysicalControllerCore::plPXPhysicalControllerCore(plKey ownerSO, hsScalar height, hsScalar radius) +plPXPhysicalControllerCore::plPXPhysicalControllerCore(plKey ownerSO, hsScalar height, hsScalar radius, bool human) : plPhysicalControllerCore(ownerSO, height, radius), fController(nil), fActor(nil), fProxyGen(nil), - fKinematicCCT(true) + fKinematicCCT(true), + fHuman(human) { ICreateController(fLocalPosition); fActor->raiseActorFlag(NX_AF_DISABLE_COLLISION); @@ -724,10 +725,14 @@ void plPXPhysicalControllerCore::ICreateController(const hsPoint3& pos) // In PhysX 2, the kinematic actors scale factor isn't exposed. // It is hardcoded at 0.8 which doesn't suit, so we have to manually adjust its dimensions. float kineRadius = fRadius + kCCTSkinWidth; - float kineHeight = fHeight + kPhysHeightCorrection; + 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); - capShape->setLocalPosition(NxVec3(0.0f, (kPhysHeightCorrection / 2.0f), 0.0f)); } else { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h index 4697d66b..039c1e71 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plPXPhysicalControllerCore.h @@ -65,7 +65,7 @@ public: class plPXPhysicalControllerCore: public plPhysicalControllerCore { public: - plPXPhysicalControllerCore(plKey ownerSO, hsScalar height, hsScalar radius); + plPXPhysicalControllerCore(plKey ownerSO, hsScalar height, hsScalar radius, bool human); ~plPXPhysicalControllerCore(); // An ArmatureMod has its own idea about when physics should be enabled/disabled. @@ -169,4 +169,5 @@ protected: plPhysicalProxy* fProxyGen; bool fKinematicCCT; + bool fHuman; }; From 7a47e52ac66e1ce3238b8848bf4c6c67baf3365f Mon Sep 17 00:00:00 2001 From: Skoader Date: Mon, 12 Nov 2012 03:28:53 +1100 Subject: [PATCH 14/14] Rework PhysX collision flutter bug workaround To better handle erroneous trigger events under the new timing method, use the number of times the simulation has actually advanced instead of the number of evals received. Cleaned up a bit. --- .../PubUtilLib/plPhysX/plSimulationMgr.cpp | 3 + .../PubUtilLib/plPhysX/plSimulationMgr.h | 4 + .../plPhysical/plCollisionDetector.cpp | 474 ++++-------------- .../plPhysical/plCollisionDetector.h | 71 ++- 4 files changed, 151 insertions(+), 401 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp index ddace665..797f15b0 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.cpp @@ -355,6 +355,7 @@ plSimulationMgr::plSimulationMgr() , fMaxDelta(kDefaultMaxDelta) , fStepSize(kDefaultStepSize) , fAccumulator(0.0f) + , fStepCount(0) , fLOSDispatch(TRACKED_NEW plLOSDispatch()) , fSoundMgr(new plPhysicsSoundMgr) , fLog(nil) @@ -609,6 +610,8 @@ void plSimulationMgr::Advance(float delSecs) fAccumulator = fMaxDelta; } + ++fStepCount; + // Perform as many whole substeps as possible saving the remainder in our accumulator. int numSubSteps = (int)(fAccumulator / fStepSize + 0.000001f); float delta = numSubSteps * fStepSize; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h index 459035ee..a5d75c21 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysX/plSimulationMgr.h @@ -99,6 +99,8 @@ public: int GetMaterialIdx(NxScene* scene, hsScalar friction, hsScalar restitution); + UInt32 GetStepCount() { return fStepCount; } + // 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); @@ -161,6 +163,8 @@ protected: float fStepSize; float fAccumulator; + UInt32 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/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp index 5b8f23a8..127a1cf6 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.cpp @@ -68,8 +68,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #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) { @@ -245,127 +246,40 @@ plCameraRegionDetector::~plCameraRegionDetector() fMessages.SetCountAndZero(0); } -void plCameraRegionDetector::ITrigger(plKey hitter, bool entering, bool immediate) +void plCameraRegionDetector::ISendTriggerMsg() { + for (int i = 0; i < fMessages.Count(); ++i) + { + hsRefCnt_SafeRef(fMessages[i]); + if (fIsInside) + fMessages[i]->SetCmd(plCameraMsg::kEntering); + else + fMessages[i]->ClearCmd(plCameraMsg::kEntering); -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - if (entering && fNumEvals - fLastExitEval <= 1 && fSavingSendMsg) - { - DetectorLog("%s: Skipping Camera Entering volume", GetKeyName()); - fLastEnterEval = fNumEvals; - if (fSavingSendMsg) - { - DetectorLog("%s: Dumping saved Camera Exiting volume", GetKeyName()); - } - fSavingSendMsg = false; - return; - } - if (!entering && fNumEvals - fLastEnterEval <= 1 && fSavingSendMsg) - { - DetectorLog("%s: Skipping Exiting volume", GetKeyName()); - fLastExitEval = fNumEvals; - if (fSavingSendMsg) - { - DetectorLog("%s: Dumping saved Camera Entering volume", GetKeyName()); - } - fSavingSendMsg = false; - return; - } - - // get rid of any saved messages... this should happen though - if (fSavingSendMsg) - { - DetectorLog("%s: Killing saved camera message... shouldn't happen", GetKeyName()); - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - - fSavingSendMsg = true; - fSavedMsgEnterFlag = entering; - if (entering) - { - //DetectorLog("%s: Saving camera Entering volume - Evals=%d", GetKeyName(),fNumEvals); - fLastEnterEval = fNumEvals; - } - else - { - //DetectorLog("%s: Saving camera Exiting volume - Evals=%d", GetKeyName(),fNumEvals); - fLastExitEval = fNumEvals; - } - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - // we're saving the message to be dispatched later... - if (immediate) - { -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - - ISendSavedTriggerMsgs(); - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - } -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - - -} - -void plCameraRegionDetector::ISendSavedTriggerMsgs() -{ - if (fSavingSendMsg) - { - for (int i = 0; i < fMessages.Count(); i++) - { - char str[256]; - - hsRefCnt_SafeRef(fMessages[i]); - if (fSavedMsgEnterFlag) - { - fMessages[i]->SetCmd(plCameraMsg::kEntering); - sprintf(str, "Entering cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName(),fNumEvals,i+1,fMessages.Count()); - fIsInside = true; - } - else - { - fMessages[i]->ClearCmd(plCameraMsg::kEntering); - sprintf(str, "Exiting cameraRegion: %s - Evals=%d -msg %d of %d\n", GetKeyName(),fNumEvals,i+1,fMessages.Count()); - fIsInside = false; - } - plgDispatch::MsgSend(fMessages[i]); - DetectorLog("%s", str); - } + plgDispatch::MsgSend(fMessages[i]); } - fSavingSendMsg = false; } - hsBool plCameraRegionDetector::MsgReceive(plMessage* msg) { plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); - if (pCollMsg) { // camera collisions are only for the local player if (plNetClientApp::GetInstance()->GetLocalPlayerKey() != pCollMsg->fOtherKey) return true; - -#ifdef USE_PHYSX_MULTIPLE_CAMREGION_ENTER - // first determine if this is a multiple camera region enter (PHYSX BUG WORKAROUND) if (!fWaitingForEval) - {//plObjectInVolumeCollisionDetector::MsgReceive() will flip fWaitingForEval - // and registers for the Eval, child objects of plObjectInVolumeCollisionDetector - //must decide when they are no longer interested in Evals. I suggest using IHandleEvals() - - fNumEvals = 0; - fLastEnterEval=-999; - fLastExitEval=-999; - } - - // end of (PHYSX BUG WORKAROUND) -#endif // USE_PHYSX_MULTIPLE_CAMREG_ENTER + IRegisterForEval(); + + fEntering = (pCollMsg->fEntering != 0); +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + fLastStep = plSimulationMgr::GetInstance()->GetStepCount(); +#endif + return true; } + return plObjectInVolumeDetector::MsgReceive(msg); } void plCameraRegionDetector::Read(hsStream* stream, hsResMgr* mgr) @@ -388,22 +302,24 @@ void plCameraRegionDetector::Write(hsStream* stream, hsResMgr* mgr) mgr->WriteCreatable( stream, fMessages[i] ); } -void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval) + +void plCameraRegionDetector::IHandleEval(plEvalMsg*) { - fNumEvals++; - if (fNumEvals - fLastEnterEval > 1 && fNumEvals-fLastExitEval>1) +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + if (plSimulationMgr::GetInstance()->GetStepCount() - fLastStep > 1) { - ISendSavedTriggerMsgs(); +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + if (fIsInside != fEntering) + { + fIsInside = fEntering; + DetectorLog("%s CameraRegion: %s", fIsInside ? "Entering" : "Exiting", GetKeyName()); + ISendTriggerMsg(); + } plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); fWaitingForEval = false; +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND } - else - { - if(fSavedActivatorMsg) - DetectorLog("%s didn't send its message. fNumEvals=%d fLastEnterEval=%d, fLastExit=%d", - GetKeyName(),fNumEvals, fLastEnterEval, fLastExitEval); - - } +#endif } ///////////////////////////////// @@ -412,182 +328,49 @@ void plCameraRegionDetector::IHandleEval(plEvalMsg *pEval) ///////////////////////////////// // object-in-volume detector -void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering, bool immediate) +void plObjectInVolumeDetector::ITrigger(plKey hitter, bool entering) { #ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -/* if (entering && fNumEvals - fLastExitEval <= 1 && fSavedActivatorMsg) + for (bookKeepingList::iterator it = fCollisionList.begin(); it != fCollisionList.end(); ++it) { - //DetectorLog("%s: Skipping Entering volume", GetKeyName()); - fLastEnterEval = fNumEvals; - if (fSavedActivatorMsg) + plCollisionBookKeepingInfo* collisionInfo = *it; + if (collisionInfo->fHitter == hitter) { - //DetectorLog("%s: Dumping saved Exiting volume", GetKeyName()); - delete fSavedActivatorMsg; + collisionInfo->fEntering = entering; + collisionInfo->fLastStep = plSimulationMgr::GetInstance()->GetStepCount(); + return; } - fSavedActivatorMsg = nil; - return; - } - if (!entering && fNumEvals - fLastEnterEval <= 1 && fSavedActivatorMsg) - { - //DetectorLog("%s: Skipping Exiting volume", GetKeyName()); - fLastExitEval = fNumEvals; - if (fSavedActivatorMsg) - { - //DetectorLog("%s: Dumping saved Entering volume", GetKeyName()); - delete fSavedActivatorMsg; - } - fSavedActivatorMsg = nil; - return; } +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // get rid of any saved messages... this should happen though - if (fSavedActivatorMsg) - { - delete fSavedActivatorMsg; - DetectorLog("%s: Killing saved message... shouldn't happen", GetKeyName()); - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -*/ - if(!immediate) - { - - bookKeepingList::iterator curit=fCollisionList.begin(); - while(curit!=fCollisionList.end()) - { - if(hitter==(*curit)->hitter) - {//hey the object is already in my list - //try and figure out what my real state is - if(entering) - { - (*curit)->enters++; - if(!(*curit)->fSubStepCurState) - {//We weren't already in - (*curit)->fSubStepCurState =true; - } - } - else - { - (*curit)->exits++; - if((*curit)->fSubStepCurState) - {//We were already in - (*curit)->fSubStepCurState =false; - } - } - //get out - break; - } - curit++; - } - if(curit==fCollisionList.end()) - { - //hitter was not in the list add him in - //hitter was not in the current frame list - //lets find out its state in the begining of the frame - ResidentSet::iterator curres = fCurrentResidents.find(hitter); - bool initialState; - if(curres != fCurrentResidents.end()) - initialState =true; - else - initialState =false; - - plCollisionBookKeepingInfo* BookKeeper=TRACKED_NEW plCollisionBookKeepingInfo(hitter); - if(entering) - { - BookKeeper->enters++; - BookKeeper->fSubStepCurState =true; - } - else - { - BookKeeper->exits++; - BookKeeper->fSubStepCurState =false; - } - fCollisionList.push_front(BookKeeper); - } - - - } - else - { - plActivatorMsg* ActivatorMsg = TRACKED_NEW plActivatorMsg; - ActivatorMsg->AddReceivers(fReceivers); - if (fProxyKey) - ActivatorMsg->fHiteeObj = fProxyKey; - else - ActivatorMsg->fHiteeObj = GetTarget()->GetKey(); - - ActivatorMsg->fHitterObj = hitter; - ActivatorMsg->SetSender(GetKey()); - if (entering) - { - ActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter); - } - else - { - ActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); - } - - plgDispatch::MsgSend(ActivatorMsg); - - - } -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - -/* fSavedActivatorMsg = TRACKED_NEW plActivatorMsg; - - fSavedActivatorMsg->AddReceivers(fReceivers); - - if (fProxyKey) - fSavedActivatorMsg->fHiteeObj = fProxyKey; - else - fSavedActivatorMsg->fHiteeObj = GetTarget()->GetKey(); + plCollisionBookKeepingInfo* collisionInfo = new plCollisionBookKeepingInfo(hitter, entering); + fCollisionList.push_back(collisionInfo); +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + collisionInfo->fLastStep = plSimulationMgr::GetInstance()->GetStepCount(); +#endif +} - fSavedActivatorMsg->fHitterObj = hitter; - fSavedActivatorMsg->SetSender(GetKey()); +void plObjectInVolumeDetector::IRegisterForEval() +{ + fWaitingForEval = true; + plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey()); +} +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) - { - //DetectorLog("%s: Saving Entering volume - Evals=%d", GetKeyName(),fNumEvals); - fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter); - fLastEnterEval = fNumEvals; - } + activatorMsg->SetTriggerType(plActivatorMsg::kVolumeEnter); else - { - //DetectorLog("%s: Saving Exiting volume - Evals=%d", GetKeyName(),fNumEvals); - fSavedActivatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); - fLastExitEval = fNumEvals; - } -*/ -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame - // we're saving the message to be dispatched later... - if (immediate) - { -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + activatorMsg->SetTriggerType(plActivatorMsg::kVolumeExit); - - // fSavedActivatorMsg = nil; - -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - } -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + plgDispatch::MsgSend(activatorMsg); } -/* -void plObjectInVolumeDetector::ISendSavedTriggerMsgs() -{ - if (fSavedActivatorMsg) - { - if (fSavedActivatorMsg->fTriggerType == plActivatorMsg::kVolumeEnter) - DetectorLog("%s: Sending Entering volume - Evals=%d", GetKeyName(),fNumEvals); - else - DetectorLog("%s: Sending Exiting volume - Evals=%d", GetKeyName(),fNumEvals); - // we're saving the message to be dispatched later... - plgDispatch::MsgSend(fSavedActivatorMsg); - } - fSavedActivatorMsg = nil; -} -*/ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) { plCollideMsg* pCollMsg = plCollideMsg::ConvertNoRef(msg); @@ -597,35 +380,16 @@ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) if (IIsDisabledAvatar(pCollMsg->fOtherKey)) return false; -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame if (!fWaitingForEval) - { - plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey()); - fWaitingForEval = true; - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0)); + IRegisterForEval(); + ITrigger(pCollMsg->fOtherKey, (pCollMsg->fEntering != 0)); return true; } -#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND - // PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame plEvalMsg* pEval = plEvalMsg::ConvertNoRef(msg); if (pEval) - { - - //if (fSavedActivatorMsg) - // DetectorLog("%s: InVolumeEval=%d with saved message", GetKeyName(), fNumEvals); - //else - // DetectorLog("%s: InVolumeEval=%d without saved message", GetKeyName(), fNumEvals); - IHandleEval(pEval); - - } - // end PHYSX_FIXME hack for PhysX turd that sends bunches of enter/exits over one frame -#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + IHandleEval(pEval); plPlayerPageMsg* pageMsg = plPlayerPageMsg::ConvertNoRef(msg); if (pageMsg && pageMsg->fUnload) @@ -636,73 +400,57 @@ hsBool plObjectInVolumeDetector::MsgReceive(plMessage* msg) return plCollisionDetector::MsgReceive(msg); } -void plObjectInVolumeDetector::IHandleEval(plEvalMsg* pEval) +void plObjectInVolumeDetector::IHandleEval(plEvalMsg*) { - plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); - fWaitingForEval = false; - for(bookKeepingList::reverse_iterator it= fCollisionList.rbegin();it!=fCollisionList.rend(); it++) + 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) { - bool alreadyInside; - ResidentSet::iterator HitIt; - HitIt = fCurrentResidents.find((*it)->hitter); - if(HitIt != fCurrentResidents.end()) alreadyInside = true; - else alreadyInside=false; - plActivatorMsg* actout=TRACKED_NEW plActivatorMsg; - actout->fHitterObj=((*it)->hitter); - actout->SetSender(GetKey()); - if (fProxyKey) - actout->fHiteeObj = fProxyKey; - else - actout->fHiteeObj = GetTarget()->GetKey(); - if((*it)->fSubStepCurState)//current substate says we are entered - {//different enters and exits - //figure out what to do - if(!alreadyInside) - {//we are actuall entering - actout->SetTriggerType(plActivatorMsg::kVolumeEnter); - fCurrentResidents.insert((*it)->hitter); - actout->AddReceivers(fReceivers); - actout->Send(); - DetectorLog("%s sent an Enter ActivatorMsg. To: %s", GetKeyName(), GetTarget()->GetKeyName() ); - } - else - { - DetectorLog("%s squelched an Enter ActivatorMsg.", GetKeyName()); - delete actout; - } - } - else +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + bool wasInside = fCurrentResidents.find(collisionInfo->fHitter) != fCurrentResidents.end(); + if (collisionInfo->fEntering != wasInside) { - //fSubStepCurState says we are outside - if(alreadyInside) - {//we are actuall exiting - actout->SetTriggerType(plActivatorMsg::kVolumeExit); - fCurrentResidents.erase((*it)->hitter); - actout->AddReceivers(fReceivers); - actout->Send(); - DetectorLog("%s sent an Exit ActivatorMsg. To: %s", GetKeyName(), GetTarget()->GetKeyName()); - } - else - { - DetectorLog("%s squelched an Exit ActivatorMsg.", GetKeyName()); - delete actout; - } + if (collisionInfo->fEntering) + { + fCurrentResidents.insert(collisionInfo->fHitter); + DetectorLog("%s: Sending Volume Enter ActivatorMsg", GetKeyName()); + ISendTriggerMsg(collisionInfo->fHitter, true); + } + else + { + fCurrentResidents.erase(collisionInfo->fHitter); + DetectorLog("%s: Sending Volume Exit ActivatorMsg", GetKeyName()); + ISendTriggerMsg(collisionInfo->fHitter, false); + } } + + delete collisionInfo; +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + it = fCollisionList.erase(it); } - DetectorLog("*********"); - for(bookKeepingList::iterator it = fCollisionList.begin(); it != fCollisionList.end(); it ++) - { - delete (*it); - } - DetectorLog("This is the regions inhabitants after the op"); - for(ResidentSet::iterator it = fCurrentResidents.begin(); it!= fCurrentResidents.end(); it++) + else { - DetectorLog("%s", (*it)->GetName()); + ++it; } - DetectorLog("*********"); +#else + ++it; +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + } - fCollisionList.clear(); - +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + if (fCollisionList.empty()) + { + plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); + fWaitingForEval = false; + } +#else + fCollisionList.clear(); + plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey()); + fWaitingForEval = false; +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND } void plObjectInVolumeDetector::SetTarget(plSceneObject* so) @@ -780,13 +528,13 @@ void plObjectInVolumeAndFacingDetector::ICheckForTrigger() { DetectorLog("%s: Trigger InVolume&Facing", GetKeyName()); fTriggered = true; - ITrigger(avatar->GetKey(), true, true); + ISendTriggerMsg(avatar->GetKey(), true); } else if (!facing && fTriggered) { DetectorLog("%s: Untrigger InVolume&Facing", GetKeyName()); fTriggered = false; - ITrigger(avatar->GetKey(), false, true); + ISendTriggerMsg(avatar->GetKey(), false); } } } @@ -820,7 +568,7 @@ hsBool plObjectInVolumeAndFacingDetector::MsgReceive(plMessage* msg) if (fTriggered) { fTriggered = false; - ITrigger(plNetClientApp::GetInstance()->GetLocalPlayerKey(), false, true); + ISendTriggerMsg(plNetClientApp::GetInstance()->GetLocalPlayerKey(), false); } } diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h index 803e83ad..c097f478 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPhysical/plCollisionDetector.h +++ b/MOULOpenSourceClientPlugin/Plasma20/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: @@ -90,34 +92,26 @@ public: // sub type for object-in-volume detectors class plObjectInVolumeDetector : public plCollisionDetector { -public: +protected: class plCollisionBookKeepingInfo { - friend plObjectInVolumeDetector; - public: - plCollisionBookKeepingInfo(plKey& hit) - { - hitter=hit; - enters=0; - exits=0; - } - ~plCollisionBookKeepingInfo() - { - hitter=nil; - } - protected: - plKey hitter; - int enters,exits; - bool fSubStepCurState; + public: + plCollisionBookKeepingInfo(plKey& key, bool entering) + : fHitter(key), fEntering(entering) { } + + plKey fHitter; +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + UInt32 fLastStep; +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + bool fEntering; }; -protected: - virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); - //virtual void ISendSavedTriggerMsgs(); + + virtual void ITrigger(plKey hitter, bool entering); + virtual void ISendTriggerMsg(plKey hitter, bool entering); + virtual void IRegisterForEval(); virtual void IHandleEval(plEvalMsg* pEval); bool fWaitingForEval; - plActivatorMsg* fSavedActivatorMsg; - typedef std::list bookKeepingList; bookKeepingList fCollisionList; typedef std::set ResidentSet; @@ -126,12 +120,12 @@ protected: public: plObjectInVolumeDetector() - { - fWaitingForEval=false;fSavedActivatorMsg=nil; - - } - plObjectInVolumeDetector(Int8 i){fType = i;fWaitingForEval=false;fSavedActivatorMsg=nil;} - virtual ~plObjectInVolumeDetector(){;} + : plCollisionDetector(), fWaitingForEval(false) { } + + plObjectInVolumeDetector(Int8 i) + : plCollisionDetector(), fWaitingForEval(false) { fType = i; } + + virtual ~plObjectInVolumeDetector() { } virtual hsBool MsgReceive(plMessage* msg); @@ -178,18 +172,19 @@ class plCameraRegionDetector : public plObjectInVolumeDetector { protected: hsTArray fMessages; - bool fIsInside; - bool fSavingSendMsg; - bool fSavedMsgEnterFlag; - int fNumEvals; - int fLastEnterEval; - int fLastExitEval; - - virtual void ITrigger(plKey hitter, bool entering, bool immediate=false); - virtual void ISendSavedTriggerMsgs(); + +#ifdef USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + UInt32 fLastStep; +#endif // USE_PHYSX_COLLISION_FLUTTER_WORKAROUND + bool fIsInside; + bool fEntering; + + virtual void ISendTriggerMsg(); virtual void IHandleEval(plEvalMsg* pEval); public: - plCameraRegionDetector(){ fIsInside = false; fSavingSendMsg = false; } + plCameraRegionDetector() + : plObjectInVolumeDetector(), fIsInside(false) { } + ~plCameraRegionDetector(); virtual hsBool MsgReceive(plMessage* msg);