BVB Source Codes

CRYENGINE Show AnimatedCharacterPPS.cpp Source code

Return Download CRYENGINE: download AnimatedCharacterPPS.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include <CryExtension/CryCreateClassInstance.h>
  5. #include "AnimatedCharacter.h"
  6. #include "CryAction.h"
  7. #include "AnimationGraphCVars.h"
  8. #include "PersistantDebug.h"
  9. #include <CryAnimation/IFacialAnimation.h>
  10. #include "AnimatedCharacterEventProxies.h"
  11.  
  12. #include "CryActionCVars.h"
  13.  
  14. #include "DebugHistory.h"
  15.  
  16. #include <IViewSystem.h>
  17. #include <CryAISystem/IAIObject.h>
  18.  
  19. #include "../Animation/PoseAligner/PoseAligner.h"
  20.  
  21. #define UNKNOWN_GROUND_HEIGHT -1E10f
  22. //#define USE_PROCEDURAL_LANDING
  23.  
  24. //--------------------------------------------------------------------------------
  25.  
  26. bool CAnimatedCharacter::EvaluateSimpleMovementConditions() const
  27. {
  28.         IEntity* pEntity = GetEntity();
  29.         CRY_ASSERT(pEntity);
  30.  
  31.         if ((m_pAnimTarget != NULL) && m_pAnimTarget->activated)
  32.                 return false;
  33.  
  34.         EMovementControlMethod eMvmt = GetMCMH();
  35.         if (eMvmt == eMCM_Animation || eMvmt == eMCM_AnimationHCollision)
  36.                 return false;
  37.  
  38.         if (pEntity->IsHidden() && !(pEntity->GetFlags() & ENTITY_FLAG_UPDATE_HIDDEN))
  39.                 return true;
  40.  
  41.         if (gEnv->IsDedicated())
  42.                 return true;
  43.  
  44.         if (CAnimationGraphCVars::Get().m_forceSimpleMovement != 0)
  45.                 return true;
  46.  
  47.         //--- Don't do simplified movement for the player client
  48.         if (m_isPlayer && GetEntityId() == CCryAction::GetCryAction()->GetClientActorId())
  49.                 return false;
  50.  
  51.         if ((m_pCharacter == NULL) || !m_pCharacter->IsCharacterVisible())
  52.                 return true;
  53.  
  54.         return false;
  55. }
  56.  
  57. //--------------------------------------------------------------------------------
  58.  
  59. void CAnimatedCharacter::UpdateSimpleMovementConditions()
  60. {
  61.         bool simplifyMovement = EvaluateSimpleMovementConditions();
  62.         bool forceDisableSlidingContactEvents = (CAnimationGraphCVars::Get().m_disableSlidingContactEvents != 0);
  63.  
  64.         // TODO: For some reason the current frame id is always one more than the last reset frame id, should be the same, afaik.
  65.         if ((m_simplifyMovement != simplifyMovement) ||
  66.             (m_forceDisableSlidingContactEvents != forceDisableSlidingContactEvents) ||
  67.             ((m_lastResetFrameId + 5) >= m_curFrameID) ||
  68.             !m_bSimpleMovementSetOnce) // Loading a singleplayer map in game takes too long between character reset and update.
  69.         {
  70.                 m_bSimpleMovementSetOnce = true;
  71.  
  72.                 m_forceDisableSlidingContactEvents = forceDisableSlidingContactEvents;
  73.                 m_simplifyMovement = simplifyMovement;
  74.  
  75.                 GetGameObject()->SetUpdateSlotEnableCondition(this, 0, m_simplifyMovement ? eUEC_Never : eUEC_Always);
  76.  
  77.                 IEntity* pEntity = GetEntity();
  78.                 //string name = pEntity->GetName();
  79.                 //CryLogAlways("AC[%s]: simplified movement %s!", name, (m_simplifyMovement ? "enabled" : "disabled"));
  80.                 IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
  81.                 if ((pPhysEnt != NULL) && (pPhysEnt->GetType() == PE_LIVING))
  82.                 {
  83.                         pe_params_flags pf;
  84.  
  85.                         if (m_simplifyMovement || m_forceDisableSlidingContactEvents)
  86.                         {
  87.                                 pf.flagsAND = ~lef_report_sliding_contacts;
  88.                                 //CryLogAlways("AC[%s]: events disabled!", name);
  89.                         }
  90.                         else
  91.                         {
  92.                                 pf.flagsOR = lef_report_sliding_contacts;
  93.                                 //CryLogAlways("AC[%s]: events enabled!", name);
  94.                         }
  95.  
  96.                         pPhysEnt->SetParams(&pf);
  97.                 }
  98.         }
  99. }
  100.  
  101. //--------------------------------------------------------------------------------
  102. //--------------------------------------------------------------------------------
  103. //--------------------------------------------------------------------------------
  104. //- PreAnimationUpdate -----------------------------------------------------------
  105. //--------------------------------------------------------------------------------
  106. //--------------------------------------------------------------------------------
  107. //--------------------------------------------------------------------------------
  108.  
  109. void CAnimatedCharacter::PreAnimationUpdate()
  110. {
  111.         ANIMCHAR_PROFILE;
  112.  
  113.         if (m_curFrameTime <= 0.0f)
  114.                 return;
  115.  
  116.         AcquireRequestedBehaviourMovement();
  117.  
  118.         m_desiredLocalLocation = CalculateDesiredLocation();
  119. }
  120.  
  121. float CAnimatedCharacter::GetAngularSpeedHorizontal() const
  122. {
  123.         const float prevFrameTimeInv = (float)__fsel(-(float)m_prevFrameTime, 0.0f, __fres((float)m_prevFrameTime + FLT_MIN));
  124.         return m_actualEntMovement.q.GetRotZ() * prevFrameTimeInv;
  125. }
  126.  
  127. void CAnimatedCharacter::UpdateSkeletonSettings()
  128. {
  129.         ANIMCHAR_PROFILE_SCOPE("UpdateSkeletonSettings");
  130.  
  131.         if (m_pSkeletonAnim != NULL)
  132.         {
  133.                 m_pSkeletonAnim->SetAnimationDrivenMotion(1); // Tell motion playback to calculate root/locator trajectory.
  134.  
  135.                 if (m_isPlayer && GetEntityId() == CCryAction::GetCryAction()->GetClientActorId())
  136.                 {
  137.                         // Force the client skeleton to update always, even when seemingly invisible
  138.                         m_pSkeletonPose->SetForceSkeletonUpdate(ISkeletonPose::kForceSkeletonUpdatesInfinitely);
  139.                 }
  140.         }
  141.         if (m_pShadowSkeletonAnim != NULL)
  142.         {
  143.                 m_pShadowSkeletonAnim->SetAnimationDrivenMotion(1); // Tell motion playback to calculate root/locator trajectory.
  144.         }
  145.  
  146.         if (m_pPoseAligner)
  147.         {
  148.                 m_pPoseAligner->Clear();
  149.         }
  150. }
  151.  
  152. //--------------------------------------------------------------------------------
  153.  
  154. void CAnimatedCharacter::UpdateTime()
  155. {
  156.         float frameTime = gEnv->pTimer->GetFrameTime();
  157.         m_curFrameTimeOriginal = frameTime;
  158.         frameTime = (float) __fsel(-frameTime, 0.0001f, frameTime);
  159.  
  160.         CRY_ASSERT(NumberValid(frameTime));
  161.  
  162.         m_curFrameID = gEnv->nMainFrameID;
  163.  
  164.         // This is cached to be used by SelectLocomotionState, to not touch global timer more than once per frame.
  165.         m_curFrameStartTime = gEnv->pTimer->GetFrameStartTime();
  166.  
  167.         m_prevFrameTime = m_curFrameTime;
  168.         m_curFrameTime = frameTime;
  169.  
  170.         m_elapsedTimeMCM[eMCMComponent_Horizontal] += (float)m_prevFrameTime;
  171.         m_elapsedTimeMCM[eMCMComponent_Vertical] += (float)m_prevFrameTime;
  172.  
  173. #ifdef _DEBUG
  174.         DebugHistory_AddValue("eDH_FrameTime", (float)m_curFrameTime);
  175.  
  176.         if (DebugTextEnabled())
  177.         {
  178.                 const ColorF cWhite = ColorF(1, 1, 1, 1);
  179.                 IRenderAuxText::Draw2dLabel(10, 50, 2.0f, (float*)&cWhite, false, "FrameTime Cur[%f] Prev[%f]", m_curFrameTime, m_prevFrameTime);
  180.         }
  181. #endif
  182. }
  183.  
  184. //--------------------------------------------------------------------------------
  185.  
  186. void CAnimatedCharacter::AcquireRequestedBehaviourMovement()
  187. {
  188.         ANIMCHAR_PROFILE_DETAILED;
  189.  
  190.         m_requestedEntityMovementType = RequestedEntMovementType_Undefined;
  191.         m_requestedIJump = 0;
  192.  
  193.         if (m_moveRequestFrameID < m_curFrameID)
  194.         {
  195.                 m_requestedEntityMovement.SetIdentity();
  196.                 return;
  197.         }
  198.  
  199.         CRY_ASSERT(m_moveRequest.velocity.IsValid());
  200.         CRY_ASSERT(m_moveRequest.rotation.IsValid());
  201.  
  202.         m_requestedEntityMovement.q = m_moveRequest.rotation;
  203.         m_requestedEntityMovement.t.zero();
  204.  
  205.         m_bDisablePhysicalGravity = (m_moveRequest.type == eCMT_Swim);
  206.  
  207.         switch (m_moveRequest.type)
  208.         {
  209.         case eCMT_None:
  210.                 CRY_ASSERT(false);
  211.                 break;
  212.  
  213.         case eCMT_Normal:
  214.                 CRY_ASSERT(m_requestedEntityMovementType != RequestedEntMovementType_Impulse);
  215.                 m_requestedEntityMovementType = RequestedEntMovementType_Absolute;
  216.                 m_requestedEntityMovement.t = m_moveRequest.velocity;
  217.                 break;
  218.  
  219.         case eCMT_Fly:
  220.         case eCMT_Swim:
  221.         case eCMT_ZeroG:
  222.                 CRY_ASSERT(m_requestedEntityMovementType != RequestedEntMovementType_Impulse);
  223.                 m_requestedEntityMovementType = RequestedEntMovementType_Absolute;
  224.                 m_requestedEntityMovement.t = m_moveRequest.velocity;
  225.                 m_requestedIJump = 3;
  226.                 break;
  227.  
  228.         case eCMT_JumpAccumulate:
  229.                 CRY_ASSERT(m_requestedEntityMovementType != RequestedEntMovementType_Impulse);
  230.                 m_requestedEntityMovementType = RequestedEntMovementType_Absolute;
  231.                 m_requestedEntityMovement.t = m_moveRequest.velocity;
  232.                 m_requestedIJump = 1;
  233.                 break;
  234.  
  235.         case eCMT_JumpInstant:
  236.                 CRY_ASSERT(m_requestedEntityMovementType != RequestedEntMovementType_Impulse);
  237.                 m_requestedEntityMovementType = RequestedEntMovementType_Absolute;
  238.                 m_requestedEntityMovement.t = m_moveRequest.velocity;
  239.                 m_requestedIJump = 2;
  240.                 break;
  241.  
  242.         case eCMT_Impulse:
  243.                 CRY_ASSERT(m_requestedEntityMovementType != RequestedEntMovementType_Absolute);
  244.                 m_requestedEntityMovementType = RequestedEntMovementType_Impulse;
  245.                 CRY_ASSERT(m_curFrameTime > 0.0f);
  246.                 if (m_curFrameTime > 0.0f)
  247.                 {
  248.                         // TODO: Impulses are per frame at the moment, while normal movement is per second.
  249.                         // NOTE: Not anymore =). Impulses are now velocity per second through out the player/alien code.
  250.                         m_requestedEntityMovement.t = m_moveRequest.velocity /* / m_curFrameTime*/;
  251.                 }
  252.                 break;
  253.         }
  254.  
  255.         CRY_ASSERT(m_requestedEntityMovement.IsValid());
  256.  
  257.         // rotation is per frame (and can't be per second, since Quat's can only represent a max angle of 360 degrees),
  258.         // Convert velocity from per second into per frame.
  259.         m_requestedEntityMovement.t *= (float)m_curFrameTime;
  260.  
  261.         if (NoMovementOverride())
  262.         {
  263.                 m_requestedEntityMovement.SetIdentity();
  264.                 m_requestedEntityMovementType = RequestedEntMovementType_Absolute;
  265.                 m_requestedIJump = 0;
  266.         }
  267.  
  268. #if DEBUG_VELOCITY()
  269.         if (DebugVelocitiesEnabled())
  270.                 AddDebugVelocity(m_requestedEntityMovement, (float)m_curFrameTime, "AnimatedCharacted Input", Col_Yellow);
  271. #endif
  272.  
  273. #ifdef _DEBUG
  274.         DebugGraphQT(m_requestedEntityMovement, "eDH_ReqEntMovementTransX", "eDH_ReqEntMovementTransY", "eDH_ReqEntMovementRotZ");
  275.  
  276.         if (DebugTextEnabled())
  277.         {
  278.                 Ang3 requestedEntityRot(m_requestedEntityMovement.q);
  279.                 const ColorF cWhite = ColorF(1, 1, 1, 1);
  280.                 IRenderAuxText::Draw2dLabel(350, 50, 2.0f, (float*)&cWhite, false, "Req Movement[%.2f, %.2f, %.2f | %.2f, %.2f, %.2f]",
  281.                                              m_requestedEntityMovement.t.x / m_curFrameTime, m_requestedEntityMovement.t.y / m_curFrameTime, m_requestedEntityMovement.t.z / m_curFrameTime,
  282.                                              RAD2DEG(requestedEntityRot.x), RAD2DEG(requestedEntityRot.y), RAD2DEG(requestedEntityRot.z));
  283.         }
  284. #endif
  285.  
  286.         CRY_ASSERT(m_requestedEntityMovement.IsValid());
  287. }
  288.  
  289. //--------------------------------------------------------------------------------
  290. //--------------------------------------------------------------------------------
  291. //--------------------------------------------------------------------------------
  292. //- PostAnimationUpdate ----------------------------------------------------------
  293. //--------------------------------------------------------------------------------
  294. //--------------------------------------------------------------------------------
  295. //--------------------------------------------------------------------------------
  296.  
  297. void CAnimatedCharacter::PostAnimationUpdate()
  298. {
  299.         //ANIMCHAR_PROFILE_SCOPE("SetAnimGraphspeedInputs_Simplified");
  300.         ANIMCHAR_PROFILE;
  301.  
  302.         if (m_curFrameTime <= 0.0f)
  303.                 return;
  304. }
  305.  
  306. void CAnimatedCharacter::ComputeGroundSlope()
  307. {
  308.         const float time = (float)m_curFrameTime;
  309.  
  310.         IEntity* pEntity = GetEntity();
  311.         CRY_ASSERT(pEntity != NULL);
  312.         IPhysicalEntity* pPhysEntity = pEntity->GetPhysics();
  313.  
  314.         Vec3 normal = Vec3(0.0f, 0.0f, 1.0f);
  315.         if (pPhysEntity && pPhysEntity->GetType() == PE_LIVING)
  316.         {
  317.                 pe_status_living status;
  318.                 pPhysEntity->GetStatus(&status);
  319.                 normal = status.groundSlope;
  320.         }
  321.  
  322.         Vec3 up(0, 0, 1);
  323.         Vec3 rootNormal = normal;
  324.         Vec3 groundNormal = rootNormal * m_entLocation.q;
  325.         groundNormal.x = 0.0f;
  326.         float cosine = up | groundNormal;
  327.         Vec3 sine = up % groundNormal;
  328.         float groundSlope = atan2f(sgn(sine.x) * sine.GetLength(), cosine);
  329.         SmoothCD(m_fGroundSlopeMoveDirSmooth, m_fGroundSlopeMoveDirRate, time, groundSlope, 0.20f);
  330.  
  331.         m_pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelSlope, m_fGroundSlopeMoveDirSmooth, time);
  332.  
  333.         float fGroundAngle = RAD2DEG(acos_tpl(rootNormal.z));
  334.         if (fGroundAngle > 35.0f)
  335.                 fGroundAngle = 35.0f;
  336.         SmoothCD(m_fGroundSlopeSmooth, m_fGroundSlopeRate, time, fGroundAngle, 0.20f);
  337. }
  338.  
  339. void CAnimatedCharacter::PostProcessingUpdate()
  340. {
  341.         ANIMCHAR_PROFILE;
  342.  
  343.         IEntity* pEntity = GetEntity();
  344.         CRY_ASSERT(pEntity != NULL);
  345.  
  346.         if (m_pSkeletonAnim == NULL)
  347.                 return;
  348.         if (m_pSkeletonPose == NULL)
  349.                 return;
  350.  
  351.         ComputeGroundSlope();
  352.  
  353.         if (CAnimationGraphCVars::Get().m_groundAlignAll == 0)
  354.                 return;
  355.  
  356.         bool fallen = false;
  357.         bool isFirstPerson = false;
  358.         bool allowLandBob = false;
  359.         bool isMultiplayer = gEnv->bMultiplayer;
  360.         if (IActor* pActor = CCryAction::GetCryAction()->GetIActorSystem()->GetActor(pEntity->GetId()))
  361.         {
  362.                 fallen = pActor->IsFallen();
  363.                 isFirstPerson = pActor->IsThirdPerson() == false;
  364.                 allowLandBob = pActor->AllowLandingBob();
  365.         }
  366.  
  367.         bool bWasDisabled = (m_lastPostProcessUpdateFrameID != m_curFrameID - 1);
  368.         m_lastPostProcessUpdateFrameID = m_curFrameID;
  369.  
  370.         if (bWasDisabled)
  371.         {
  372.                 m_fJumpSmooth = 0.0f;
  373.                 m_fJumpSmoothRate = 0.0f;
  374.         }
  375.  
  376.         const float JUMP_SMOOTH_RATE = 0.30f;
  377.         SmoothCD(m_fJumpSmooth, m_fJumpSmoothRate, (float)m_curFrameTime, f32(m_moveRequest.jumping), JUMP_SMOOTH_RATE);
  378.         if (m_moveRequest.jumping)
  379.                 m_fJumpSmooth = 1.0f;
  380.  
  381.         //
  382.  
  383.         IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
  384.         if (!pPhysEnt)
  385.                 return;
  386.         if (pPhysEnt->GetType() != PE_LIVING)
  387.                 return;
  388.  
  389.         if (!m_pPoseAligner)
  390.                 return;
  391.         if (!m_pPoseAligner->Initialize(*pEntity))
  392.                 return;
  393.  
  394.         float poseBlendWeight = clamp_tpl(1.0f - m_fJumpSmooth, 0.0f, 1.0f);
  395.  
  396. #ifdef USE_PROCEDURAL_LANDING
  397.  
  398.         // Procedural landing code
  399.  
  400.         pe_status_living status;
  401.         pPhysEnt->GetStatus(&status);
  402.  
  403.         float entHeight = pEntity->GetWorldPos().z;
  404.         float groundHeight = status.groundHeight;
  405.         bool groundHeightValid = !status.bFlying;
  406.  
  407.         bool snapAlignFeet = false;
  408.         float landingOffset = 0.0f;
  409.  
  410.         if (allowLandBob && m_landBobParams.IsValid())
  411.         {
  412.                 const f32 IN_AIR_HEIGHT[2] = { 0.2f, 0.1f };
  413.  
  414.                 if (pPhysEnt != NULL)
  415.                 {
  416.                         bool inAir = status.bFlying != 0;
  417.  
  418.                         //                      IRenderAuxText::Draw2dLabel(10, 100, 1.3f, (float*)&Vec4(1, 1, 1, 1), false, "Ground: %f Ent: %f", groundHeight, entHeight);
  419.  
  420.                         if (inAir != m_wasInAir)
  421.                         {
  422.                                 m_wasInAir = inAir;
  423.  
  424.                                 if (!inAir)
  425.                                 {
  426.                                         m_landBobTime = m_landBobParams.maxTime;
  427.                                         float fallFactor = clamp_tpl((m_fallMaxHeight - entHeight) / m_landBobParams.maxFallDist, 0.0f, 1.0f);
  428.                                         m_totalLandBob = fallFactor * clamp_tpl(m_landBobParams.maxBob, 0.0f, 0.3f);
  429.  
  430.                                         snapAlignFeet = true;
  431.                                 }
  432.                                 else
  433.                                 {
  434.                                         m_fallMaxHeight = entHeight;
  435.                                 }
  436.                         }
  437.  
  438.                         if (inAir)
  439.                         {
  440.                                 m_fallMaxHeight = max(entHeight, m_fallMaxHeight);
  441.                         }
  442.                 }
  443.  
  444.                 if (m_landBobTime > 0.0f)
  445.                 {
  446.                         float landingBobFactor = CAnimationGraphCVars::Get().m_landingBobTimeFactor;
  447.                         float landingBobLandFactor = CAnimationGraphCVars::Get().m_landingBobLandTimeFactor;
  448.                         CRY_ASSERT_MESSAGE((landingBobFactor >= 0.0f) && (landingBobFactor <= 1.0f), "Invalid value for m_landingBobTimeFactor cvar, must be 0..1");
  449.                         landingBobFactor = clamp_tpl(landingBobFactor, 0.0f, 1.0f);
  450.                         landingBobLandFactor = clamp_tpl(landingBobLandFactor, 0.0f, landingBobFactor);
  451.  
  452.                         m_landBobTime = max(m_landBobTime - (float)m_curFrameTime, 0.0f);
  453.  
  454.                         f32 t = clamp_tpl(1.0f - (m_landBobTime / m_landBobParams.maxTime), 0.0f, 1.0f);
  455.                         if (t > landingBobFactor)
  456.                         {
  457.                                 f32 st = 1.0f - ((t - landingBobFactor) / (1.0f - landingBobFactor));
  458.                                 t = (1.0f + sin_tpl((st - 0.5f) * gf_PI)) * 0.5f;
  459.                         }
  460.                         else
  461.                         {
  462.                                 t = min(t / landingBobLandFactor, 1.0f);
  463.                         }
  464.                         landingOffset -= t * m_totalLandBob;
  465.                         snapAlignFeet = true;
  466.  
  467.                         //                      IRenderAuxText::Draw2dLabel(10, 220, 1.3f, (float*)&Vec4(1, 1, 1, 1), false, "FT: %f t: %f", m_landBobTime, t);
  468.                 }
  469.         }
  470.         else
  471.         {
  472.                 m_wasInAir = false;
  473.         }
  474.  
  475.         if (allowLandBob)
  476.         {
  477.                 if (snapAlignFeet)
  478.                         poseBlendWeight = 1.0f;
  479.  
  480.                 PoseAligner::CPose* pPoseAligner = (PoseAligner::CPose*)m_pPoseAligner.get();
  481.                 pPoseAligner->SetRootOffsetAdditional(Vec3(0.0f, 0.0f, landingOffset));
  482.  
  483.                 const uint chainCount = pPoseAligner->GetChainCount();
  484.                 for (uint i = 0; i < chainCount; ++i)
  485.                 {
  486.                         pPoseAligner->GetChain(i)->SetTargetForceWeightOne(snapAlignFeet);
  487.                 }
  488.         }
  489.  
  490. #endif
  491.  
  492.         // PoseAligner
  493.  
  494.         m_pPoseAligner->SetRootOffsetEnable(m_groundAlignmentParams.IsFlag(eGA_PoseAlignerUseRootOffset));
  495.         m_pPoseAligner->SetBlendWeight(poseBlendWeight);
  496.         m_pPoseAligner->Update(m_entLocation, (float)m_curFrameTime);
  497. }
  498.  
  499. //--------------------------------------------------------------------------------
  500.  
  501. QuatT CAnimatedCharacter::CalculateDesiredAnimMovement() const
  502. {
  503.         ANIMCHAR_PROFILE_DETAILED;
  504.  
  505.         IEntity* pEntity = GetEntity();
  506.         CRY_ASSERT(pEntity);
  507.         IEntity* pParent = pEntity->GetParent();
  508.  
  509.         QuatT desiredAnimMovement(IDENTITY);
  510.  
  511.         // If simplified, anim location will be set to entity anyway, so we don't need any of this.
  512.         if (m_simplifyMovement)
  513.                 return desiredAnimMovement;
  514.  
  515.         // ASSET MOVEMENT
  516.         if (m_pSkeletonAnim != NULL)
  517.         {
  518.                 QuatT assetAnimMovement;
  519.                 if (CAnimationGraphCVars::Get().m_useMovementPrediction)
  520.                 {
  521.                         // TODO: Figure out how many frames ahead the physics request we're calculating is
  522.                         //   This depends on how the CSystem::Update() is implemented, which cvars are set, and which platform we run on,
  523.                         //   so this information should be passed along somehow by the CSystem.
  524.                         //   For now we assume physics request have exactly 1 frame of delay.
  525.  
  526.                         if (CAnimationGraphCVars::Get().m_useQueuedRotation)
  527.                         {
  528.                                 assetAnimMovement = m_pSkeletonAnim->CalculateRelativeMovement((float)m_curFrameTime, 1);
  529.                         }
  530.                         else
  531.                         {
  532.                                 assetAnimMovement = m_pSkeletonAnim->CalculateRelativeMovement((float)m_curFrameTime, 0);
  533.  
  534.                                 const QuatT futureAssetAnimMovement = m_pSkeletonAnim->CalculateRelativeMovement((float)m_curFrameTime, 1);
  535.  
  536.                                 assetAnimMovement.t = assetAnimMovement.q * futureAssetAnimMovement.t; // request the 'future' translation, properly adjusted for the fact that the rotation we got back from cryanimation is relative to the rotation of the current frame
  537.                         }
  538.                 }
  539.                 else
  540.                 {
  541.                         assetAnimMovement = m_pSkeletonAnim->CalculateRelativeMovement((float)m_curFrameTime, 0);
  542.                 }
  543.  
  544.                 //
  545.                 assetAnimMovement.t = m_entLocation.q * assetAnimMovement.t;
  546.                 assetAnimMovement.q.Normalize();
  547.  
  548.                 desiredAnimMovement = assetAnimMovement;
  549.  
  550.                 /*{
  551.                    IRenderAuxGeom*      pAuxGeom        = gEnv->pRenderer->GetIRenderAuxGeom();
  552.                    pAuxGeom->SetRenderFlags( e_Def3DPublicRenderflags );
  553.                    pAuxGeom->DrawLine( desiredAnimMovement.t,RGBA8(0x00,0xff,0x00,0x00),desiredAnimMovement.t+Vec3(0,0,+20),RGBA8(0xff,0xff,0xff,0x00) );
  554.                    }*/
  555.         }
  556.  
  557. #ifdef _DEBUG
  558.         DebugGraphQT(desiredAnimMovement, "eDH_AnimAssetTransX", "eDH_AnimAssetTransY", "eDH_AnimAssetRotZ", "eDH_AnimAssetTransZ");
  559. #endif
  560.  
  561.         // This assert was removed, because Troppers use physicalized animation controlled movement to dodge.
  562.         // Have not investigated what problems this might cause, them penetrating into obstacles, entity trying to catch up with animation, etc.
  563.         // Luciano said it seems to work fine. We'll see...
  564.         //CRY_ASSERT((GetMCMH() != eMCM_Animation) || (m_colliderMode != eColliderMode_Pushable));
  565.  
  566.         if (NoMovementOverride())
  567.         {
  568.                 desiredAnimMovement.SetIdentity();
  569.         }
  570.  
  571.         // This is the only point where the eMCM_AnimationHCollision differs from the eMCM_Animation
  572.         // (though only when having 'atomic update')
  573.         if (RecentCollision() && (GetMCMH() != eMCM_Animation) && (GetMCMH() != eMCM_AnimationHCollision))
  574.         {
  575.                 desiredAnimMovement.t = RemovePenetratingComponent(desiredAnimMovement.t, m_collisionNormal[0]);
  576.                 desiredAnimMovement.t = RemovePenetratingComponent(desiredAnimMovement.t, m_collisionNormal[1]);
  577.                 desiredAnimMovement.t = RemovePenetratingComponent(desiredAnimMovement.t, m_collisionNormal[2]);
  578.                 desiredAnimMovement.t = RemovePenetratingComponent(desiredAnimMovement.t, m_collisionNormal[3]);
  579.         }
  580.  
  581.         //DebugGraphQT(desiredAnimMovement, eDH_TEMP00, eDH_TEMP01, eDH_TEMP03); DebugHistory_AddValue(eDH_TEMP02, desiredAnimMovement.t.z);
  582.  
  583.         CRY_ASSERT(desiredAnimMovement.IsValid());
  584.         return desiredAnimMovement;
  585. }
  586.  
  587. //--------------------------------------------------------------------------------
  588.  
  589. void CAnimatedCharacter::CalculateAndRequestPhysicalEntityMovement()
  590. {
  591.         ANIMCHAR_PROFILE_DETAILED;
  592.  
  593.         const QuatT desiredAnimMovement = CalculateDesiredAnimMovement();
  594.  
  595. #if DEBUG_VELOCITY()
  596.         if (DebugVelocitiesEnabled())
  597.                 AddDebugVelocity(desiredAnimMovement, (float)m_curFrameTime, "Anim Movement", Col_Blue);
  598. #endif
  599.  
  600.         const QuatT wantedEntMovement = CalculateWantedEntityMovement(desiredAnimMovement);
  601.  
  602.         RequestPhysicalEntityMovement(wantedEntMovement);
  603. }
  604.  
  605. //--------------------------------------------------------------------------------
  606.  
  607. QuatT CAnimatedCharacter::CalculateWantedEntityMovement(const QuatT& desiredAnimMovement) const
  608. {
  609.         ANIMCHAR_PROFILE_DETAILED;
  610.  
  611.         if (NoMovementOverride())
  612.         {
  613. #if DEBUG_VELOCITY()
  614.                 if (DebugVelocitiesEnabled())
  615.                         AddDebugVelocity(IDENTITY, (float)m_curFrameTime, "Wanted: NoMovementOverride", Col_GreenYellow);
  616. #endif
  617.                 return IDENTITY;
  618.         }
  619.  
  620.         CRY_ASSERT(desiredAnimMovement.IsValid());
  621.  
  622. #ifdef _DEBUG
  623.         if (DebugFilter())
  624.         {
  625.                 DebugHistory_AddValue("eDH_TEMP00", desiredAnimMovement.t.z);
  626.                 DebugHistory_AddValue("eDH_TEMP01", m_expectedEntMovement.z);
  627.                 DebugHistory_AddValue("eDH_TEMP02", m_actualEntMovement.t.z);
  628.                 DebugHistory_AddValue("eDH_TEMP10", m_requestedEntityMovement.t.z);
  629.         }
  630. #endif
  631.  
  632.         QuatT overriddenEntMovement = OverrideEntityMovement(m_requestedEntityMovement, desiredAnimMovement);
  633.  
  634.         QuatT wantedEntMovement;
  635.         if ((desiredAnimMovement.t == overriddenEntMovement.t) && (desiredAnimMovement.q == overriddenEntMovement.q))
  636.         {
  637.                 wantedEntMovement = overriddenEntMovement;
  638.         }
  639.         else
  640.         {
  641.                 wantedEntMovement = MergeMCM(overriddenEntMovement, desiredAnimMovement, false);
  642.         }
  643.         CRY_ASSERT(wantedEntMovement.IsValid());
  644.  
  645.         // Entity Clamping
  646.         if (AllowEntityClamping())
  647.                 wantedEntMovement = DoEntityClamping(wantedEntMovement);
  648.  
  649.         // Forced Movement (do we really need this?)
  650.         if (m_hasForcedMovement)
  651.         {
  652. #if DEBUG_VELOCITY()
  653.                 if (DebugVelocitiesEnabled())
  654.                 {
  655.                         AddDebugVelocity(m_forcedMovementRelative, (float)m_curFrameTime, "ForcedMovement (Relative", Col_IndianRed);
  656.                 }
  657. #endif
  658.  
  659.                 wantedEntMovement = ApplyWorldOffset(wantedEntMovement, m_forcedMovementRelative);
  660.         }
  661.  
  662. #if DEBUG_VELOCITY()
  663.         if (DebugVelocitiesEnabled())
  664.         {
  665.                 EMovementControlMethod mcmh = GetMCMH();
  666.                 EMovementControlMethod mcmv = GetMCMV();
  667.                 char* szMcmH = "???";
  668.                 switch (mcmh)
  669.                 {
  670.                 case eMCM_Entity:
  671.                         szMcmH = "ENT";
  672.                         break;
  673.                 case eMCM_ClampedEntity:
  674.                         szMcmH = "ENT_CL";
  675.                         break;
  676.                 case eMCM_SmoothedEntity:
  677.                         szMcmH = "ENT_SM";
  678.                         break;
  679.                 case eMCM_DecoupledCatchUp:
  680.                         szMcmH = "DEC";
  681.                         break;
  682.                 case eMCM_Animation:
  683.                         szMcmH = "ANM";
  684.                         break;
  685.                 case eMCM_AnimationHCollision:
  686.                         szMcmH = "ANM_HC";
  687.                         break;
  688.                 }
  689.                 char* szMcmV = "???";
  690.                 switch (mcmv)
  691.                 {
  692.                 case eMCM_Entity:
  693.                         szMcmV = "ENT";
  694.                         break;
  695.                 case eMCM_ClampedEntity:
  696.                         szMcmV = "ENT_CL";
  697.                         break;
  698.                 case eMCM_SmoothedEntity:
  699.                         szMcmV = "ENT_SM";
  700.                         break;
  701.                 case eMCM_DecoupledCatchUp:
  702.                         szMcmV = "DEC";
  703.                         break;
  704.                 case eMCM_Animation:
  705.                         szMcmV = "ANM";
  706.                         break;
  707.                 case eMCM_AnimationHCollision:
  708.                         szMcmV = "ANM_HC";
  709.                         break;
  710.                 }
  711.  
  712.                 char buffer[256];
  713.                 const char* const mcmHTag = m_currentMovementControlMethodTags[eMCMComponent_Horizontal];
  714.                 const char* const mcmVTag = m_currentMovementControlMethodTags[eMCMComponent_Vertical];
  715.                 cry_sprintf(buffer, "Wanted: Hor:%s%s%s(%s) Ver:%s%s(%s)", szMcmH, m_moveOverride_useAnimXY ? "+ANMXY" : "", m_moveOverride_useAnimRot ? "+ANMQ" : "", mcmHTag, szMcmV, m_moveOverride_useAnimZ ? "+ANMZ" : "", mcmVTag);
  716.  
  717.                 AddDebugVelocity(wantedEntMovement, (float)m_curFrameTime, buffer, Col_GreenYellow);
  718.         }
  719. #endif
  720.  
  721.         return wantedEntMovement;
  722. }
  723.  
  724. //--------------------------------------------------------------------------------
  725.  
  726. // PROTOTYPE: Limit entity velocity to animation velocity projected along entity velocity direction.
  727. // Problems due to:
  728. // - Animations can play at a faster speed than how they look good. Using this method to limit prone (for example)
  729. //   results in too-fast animations being "normal"
  730. // - Making entity movement dependant on animation results in a very variable entity speed
  731. // - Whenever the clamping happens the prediction becomes wrong - the AC tends to end up ahead of the entity (when
  732. //   the clamping is done after the animation is determined by the prediction etc.
  733. // - If the entity movement is clamped before the animation properties are set then starting becomes impossible - AC
  734. //   tells entity it can't move, so entity doesn't move, and that makes the AC not move etc
  735. //
  736. QuatT CAnimatedCharacter::DoEntityClamping(const QuatT& wantedEntMovement) const
  737. {
  738.         IEntity* pEntity = GetEntity();
  739.         CRY_ASSERT(pEntity != NULL);
  740.  
  741.         const float frameTime = (float)m_curFrameTime;
  742.  
  743.         ICharacterInstance* pCharacterInstance = pEntity->GetCharacter(0);
  744.         ISkeletonAnim* pSkeletonAnim = (pCharacterInstance != NULL) ? pCharacterInstance->GetISkeletonAnim() : NULL;
  745.  
  746.         QuatT clampedWantedEntMovement(wantedEntMovement);
  747.  
  748.         float requestedEntVelocity = iszero(frameTime) ? 0.0f : wantedEntMovement.t.GetLength() / frameTime;
  749.         if ((requestedEntVelocity > 0.0f) && (pSkeletonAnim != NULL))
  750.         {
  751.                 const QuatT& qt = pSkeletonAnim->GetRelMovement();
  752.                 Vec3 t1 = qt.t * qt.q;
  753.                 Vec3 assetAnimMovement = m_entLocation.q * t1;
  754.  
  755.                 Vec3 requestedEntMovementDir = m_requestedEntityMovement.t.GetNormalizedSafe();
  756.                 float projectedActualAnimVelocity = ((float)m_prevFrameTime > 0.0f) ? ((assetAnimMovement | requestedEntMovementDir) / (float)m_prevFrameTime) : 0.0f;
  757.  
  758.                 clampedWantedEntMovement.t *= clamp_tpl(projectedActualAnimVelocity / requestedEntVelocity, 0.0f, 1.0f);
  759.         }
  760.  
  761.         return clampedWantedEntMovement;
  762. }
  763.  
  764. void CAnimatedCharacter::RequestPhysicalEntityMovement(const QuatT& wantedEntMovement)
  765. {
  766.         ANIMCHAR_PROFILE_DETAILED;
  767.  
  768.         IEntity* pEntity = GetEntity();
  769.         CRY_ASSERT(pEntity != NULL);
  770.  
  771.         m_expectedEntMovement.zero();
  772.  
  773.         IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
  774.         if (pPhysEnt == NULL)
  775.                 return;
  776.  
  777.         if (pPhysEnt->GetType() == PE_ARTICULATED)
  778.                 return;
  779.  
  780.         // local/world movement into force/velocity or whatever.
  781.         // TODO: look at the tracker apply functions, see what they do different.
  782.  
  783.         const float frameTime = (float)m_curFrameTime;
  784.  
  785.         CRY_ASSERT(wantedEntMovement.IsValid());
  786.  
  787.         // This will update/activate the collider if needed, which makes it safe to move again.
  788.         // (According to Craig we don't need to wake up other things that the requester might have put to sleep).
  789.         if (!wantedEntMovement.t.IsZero())
  790.                 RequestPhysicalColliderMode(eColliderMode_Undefined, eColliderModeLayer_ForceSleep, "ReqPhysEntMove");
  791.  
  792.         IEntity* pParent = pEntity->GetParent();
  793.         if (pParent != NULL)
  794.         {
  795.                 // When mounted and we have entity driven movement the only code to update the entity matrix is the vehicle (ref: Michael Rauh)
  796.                 // TODO: If needed, find a solution that supports split horizontal & vertical components. Could just MergeMCM cur & wanted locations?
  797.                 //CRY_ASSERT(GetMCMH() == GetMCMV());
  798.                 if (GetMCMH() != eMCM_Entity)
  799.                 {
  800.                         QuatT curEntLocationLocal(pEntity->GetLocalTM());
  801.                         curEntLocationLocal.q.Normalize();
  802.                         CRY_ASSERT(curEntLocationLocal.IsValid());
  803.                         Quat ParentOrientation = pParent->GetWorldRotation();
  804.                         CRY_ASSERT(ParentOrientation.IsValid());
  805.                         Quat ParentOrientationInv = ParentOrientation.GetInverted();
  806.                         CRY_ASSERT(ParentOrientationInv.IsValid());
  807.                         QuatT wantedEntLocationLocal;
  808.                         wantedEntLocationLocal.t = curEntLocationLocal.t + ParentOrientationInv * wantedEntMovement.t;
  809.                         wantedEntLocationLocal.q = curEntLocationLocal.q * wantedEntMovement.q;
  810.                         CRY_ASSERT(wantedEntLocationLocal.IsValid());
  811.                         Matrix34 wantedEntLocationLocalMat(wantedEntLocationLocal);
  812.                         CRY_ASSERT(wantedEntLocationLocalMat.IsValid());
  813.                         pEntity->SetLocalTM(wantedEntLocationLocalMat);
  814.  
  815.                         pe_action_move move;
  816.                         move.dir = ZERO;
  817.                         move.iJump = 0;
  818.  
  819.                         pPhysEnt->Action(&move);
  820.                 }
  821.         }
  822.         else
  823.         {
  824.                 {
  825.                         ANIMCHAR_PROFILE_SCOPE("UpdatePhysicalEntityMovement_RequestToPhysics");
  826.  
  827.                         // Force normal movement type during animation controlled movement,
  828.                         // since the entity needs to catch up regardless of what movement type game code requests.
  829.                         if ((m_requestedEntityMovementType == RequestedEntMovementType_Absolute) ||
  830.                             ((GetMCMH() == eMCM_Animation || GetMCMH() == eMCM_AnimationHCollision) && (GetMCMV() == eMCM_Animation)))
  831.                         {
  832.                                 const float curFrameTimeInv = (frameTime != 0.0f) ? (1.0f / frameTime) : 0.0f;
  833.                                 pe_action_move move;
  834.                                 move.dir = wantedEntMovement.t * curFrameTimeInv;
  835.                                 move.iJump = m_requestedIJump;
  836.                                 move.dt = static_cast<float>(frameTime);
  837.                                 m_expectedEntMovement = wantedEntMovement.t;
  838.  
  839.                                 CRY_ASSERT(move.dir.IsValid());
  840.  
  841.                                 float curMoveVeloHash = 5.0f * move.dir.x + 7.0f * move.dir.y + 3.0f * move.dir.z;
  842.                                 float actualMoveVeloHash = 5.0f * m_actualEntMovement.t.x * curFrameTimeInv + 7.0f * m_actualEntMovement.t.y * curFrameTimeInv + 3.0f * m_actualEntMovement.t.z * curFrameTimeInv;
  843.                                 if ((curMoveVeloHash != m_prevMoveVeloHash) || (move.iJump != m_prevMoveJump) || (actualMoveVeloHash != curMoveVeloHash) || RecentQuickLoad())
  844.                                 {
  845.                                         ANIMCHAR_PROFILE_SCOPE("UpdatePhysicalEntityMovement_RequestToPhysics_Movement");
  846.  
  847.                                         if (!move.dir.IsZero() && !wantedEntMovement.t.IsZero())
  848.                                                 CRY_ASSERT(m_colliderModeLayers[eColliderModeLayer_ForceSleep] == eColliderMode_Undefined);
  849.  
  850. #if DEBUG_VELOCITY()
  851.                                         if (DebugVelocitiesEnabled())
  852.                                                 AddDebugVelocity(wantedEntMovement, frameTime, "Physics Request", Col_Red);
  853. #endif
  854.  
  855.                                         pPhysEnt->Action(&move);
  856.                                         m_prevMoveVeloHash = curMoveVeloHash;
  857.                                         m_prevMoveJump = move.iJump;
  858.  
  859.                                         pe_params_flags pf;
  860.                                         if (m_bDisablePhysicalGravity ||
  861.                                             (m_colliderMode == eColliderMode_Disabled) ||
  862.                                             (m_colliderMode == eColliderMode_PushesPlayersOnly) ||
  863.                                             (m_colliderMode == eColliderMode_Spectator) ||
  864.                                             (GetMCMV() == eMCM_Animation))
  865.                                                 pf.flagsOR = pef_ignore_areas;
  866.                                         else
  867.                                                 pf.flagsAND = ~pef_ignore_areas;
  868.                                         pPhysEnt->SetParams(&pf);
  869.                                 }
  870.                         }
  871.                         else if (m_requestedEntityMovementType == RequestedEntMovementType_Impulse)
  872.                         {
  873.                                 ANIMCHAR_PROFILE_SCOPE("UpdatePhysicalEntityMovement_RequestToPhysics_Impulse");
  874.  
  875.                                 pe_action_impulse impulse;
  876.                                 impulse.impulse = wantedEntMovement.t;
  877.                                 impulse.iApplyTime = 0;
  878.                                 m_expectedEntMovement = wantedEntMovement.t;
  879.  
  880.                                 pPhysEnt->Action(&impulse);
  881.                         }
  882.                         else
  883.                         {
  884.                                 if (m_requestedEntityMovementType != RequestedEntMovementType_Undefined) // Can be underfined right after start, if there is no requested movement yet.
  885.                                         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "AnimatedCharacter::UpdatePhysicalEntityMovement() - Undefined movement type %d, expected absolute(1) or impulse(2).", m_requestedEntityMovementType);
  886.  
  887.                                 // When there is no valid requested movement, clear the requested velocity in living entity.
  888.                                 pe_action_move move;
  889.                                 move.dir = ZERO;
  890.                                 move.iJump = 0;
  891.  
  892.                                 pPhysEnt->Action(&move);
  893.                         }
  894.                 }
  895.  
  896.                 if (!NoMovementOverride())
  897.                 {
  898.                         Quat newRotation = m_entLocation.q * wantedEntMovement.q;
  899.  
  900.                         if (m_hasForcedOverrideRotation)
  901.                         {
  902. #if DEBUG_VELOCITY()
  903.                                 if (DebugVelocitiesEnabled())
  904.                                 {
  905.                                         QuatT forcedRot(Vec3Constants<float>::fVec3_Zero, m_entLocation.q.GetInverted() * m_forcedOverrideRotationWorld);
  906.                                         AddDebugVelocity(forcedRot, (float)m_curFrameTime, "ForcedOverrideRotation", Col_Orchid);
  907.                                 }
  908. #endif
  909.  
  910.                                 newRotation = m_forcedOverrideRotationWorld;
  911.                         }
  912.  
  913.                         newRotation.Normalize();
  914.                         CRY_ASSERT(newRotation.IsValid());
  915.  
  916.                         if (CAnimationGraphCVars::Get().m_useQueuedRotation)
  917.                         {
  918.                                 m_pComponentPrepareCharForUpdate->QueueRotation(newRotation);
  919.                         }
  920.                         else
  921.                         {
  922.                                 m_entLocation.q = newRotation;
  923.  
  924.                                 pEntity->SetRotation(newRotation, ENTITY_XFORM_USER | ENTITY_XFORM_NOT_REREGISTER);
  925.                         }
  926.                 }
  927.  
  928.                 // Send expected location to AI so pathfollowing which runs in parallel with physics becomes more accurate
  929.                 {
  930.                         IAIObject* pAIObject = GetEntity()->GetAI();
  931.                         if (pAIObject)
  932.                         {
  933.                                 pAIObject->SetExpectedPhysicsPos(m_entLocation.t + m_expectedEntMovement);
  934.                         }
  935.                 }
  936.         }
  937.  
  938.         m_hasForcedOverrideRotation = false;
  939.         m_hasForcedMovement = false;
  940. }
  941.  
  942. //--------------------------------------------------------------------------------
  943.  
  944. void CAnimatedCharacter::UpdatePhysicalColliderMode()
  945. {
  946.         ANIMCHAR_PROFILE_DETAILED;
  947.  
  948.         bool debug = (CAnimationGraphCVars::Get().m_debugColliderMode != 0);
  949.  
  950.         // If filtered result is Undefined it will be forced to Pushable below.
  951.         EColliderMode newColliderMode = eColliderMode_Undefined;
  952.  
  953.         //#ifdef _DEBUG
  954.         if (debug && DebugFilter())
  955.         {
  956.                 if (m_isPlayer)
  957.                         m_colliderModeLayers[eColliderModeLayer_Debug] = (EColliderMode)CAnimationGraphCVars::Get().m_forceColliderModePlayer;
  958.                 else
  959.                         m_colliderModeLayers[eColliderModeLayer_Debug] = (EColliderMode)CAnimationGraphCVars::Get().m_forceColliderModeAI;
  960.         }
  961.         //#endif
  962.  
  963.         bool disabled = false;
  964.         for (int layer = 0; layer < eColliderModeLayer_COUNT; layer++)
  965.         {
  966.                 if (m_colliderModeLayers[layer] != eColliderMode_Undefined)
  967.                 {
  968.                         newColliderMode = m_colliderModeLayers[layer];
  969.                         if (m_colliderModeLayers[layer] == eColliderMode_Disabled)
  970.                                 disabled = true;
  971.                 }
  972.         }
  973.  
  974.         if (disabled && (m_colliderModeLayers[eColliderModeLayer_Debug] == eColliderMode_Undefined))
  975.                 newColliderMode = eColliderMode_Disabled;
  976.  
  977.         if (newColliderMode == eColliderMode_Undefined)
  978.                 newColliderMode = eColliderMode_Pushable;
  979.  
  980.         //#ifdef _DEBUG
  981.         if (debug && DebugFilter())
  982.         {
  983.                 ColorF color(1, 0.8f, 0.6f, 1);
  984.                 static float x = 50.0f;
  985.                 static float y = 70.0f;
  986.                 static float h = 20.0f;
  987.  
  988.                 string name = GetEntity()->GetName();
  989.                 IRenderAuxText::Draw2dLabel(x, y - h, 1.7f, (float*)&color, false, "ColliderMode (%s)", name.c_str());
  990.  
  991.                 int layer;
  992.                 const char* tag;
  993.                 for (layer = 0; layer < eColliderModeLayer_COUNT; layer++)
  994.                 {
  995.                         tag = (m_colliderModeLayersTag[layer] == NULL) ? "" : m_colliderModeLayersTag[layer];
  996.                         IRenderAuxText::Draw2dLabel(x, y + (float)layer * h, 1.7f, (float*)&color, false, "  %s(%d): %s(%d)   %s", g_szColliderModeLayerString[layer], layer, g_szColliderModeString[m_colliderModeLayers[layer]], m_colliderModeLayers[layer], tag);
  997.                 }
  998.                 IRenderAuxText::Draw2dLabel(x, y + (float)layer * h, 1.7f, (float*)&color, false, "  FINAL: %s(%d)", g_szColliderModeString[newColliderMode], newColliderMode);
  999.         }
  1000.         //#endif
  1001.  
  1002.         if (m_pRigidColliderPE)
  1003.         {
  1004.                 pe_params_pos pos;
  1005.                 pos.pos = GetEntity()->GetPos();
  1006.  
  1007.                 m_pRigidColliderPE->SetParams(&pos);
  1008.         }
  1009.  
  1010.         if ((newColliderMode == m_colliderMode) && !RecentQuickLoad() && !m_forcedRefreshColliderMode)
  1011.                 return;
  1012.  
  1013.         if (!m_forcedRefreshColliderMode &&
  1014.             (newColliderMode != eColliderMode_Disabled) &&
  1015.             (newColliderMode != eColliderMode_PushesPlayersOnly) &&
  1016.             (newColliderMode != eColliderMode_Spectator) &&
  1017.             ((m_curFrameID <= 0) || ((m_lastResetFrameId + 1) > m_curFrameID)))
  1018.         {
  1019.                 return;
  1020.         }
  1021.  
  1022.         m_forcedRefreshColliderMode = false;
  1023.         EColliderMode prevColliderMode = m_colliderMode;
  1024.         m_colliderMode = newColliderMode;
  1025.  
  1026.         CRY_ASSERT(m_colliderMode != eColliderMode_Undefined);
  1027.  
  1028.         IEntity* pEntity = GetEntity();
  1029.         CRY_ASSERT(pEntity);
  1030.  
  1031.         IPhysicalEntity* pPhysEnt = pEntity->GetPhysics();
  1032.         if (pPhysEnt == NULL || pPhysEnt->GetType() != PE_LIVING)
  1033.                 return;
  1034.  
  1035.         pe_player_dynamics pd;
  1036.         pe_params_part pp;
  1037.         pe_params_flags pf;
  1038.  
  1039.         const unsigned int characterGeomCollTypeFlags = m_characterCollisionFlags;
  1040.  
  1041.         if (m_colliderMode == eColliderMode_Disabled)
  1042.         {
  1043.                 pd.bActive = 0;
  1044.                 pd.collTypes = ent_terrain | ent_static | ent_rigid | ent_sleeping_rigid | ent_living;
  1045.                 pp.flagsAND = ~characterGeomCollTypeFlags;
  1046.  
  1047.                 pe_action_move move;
  1048.                 move.dir = ZERO;
  1049.                 move.iJump = 0;
  1050.                 pPhysEnt->Action(&move);
  1051.                 pf.flagsAND = ~(pef_ignore_areas | lef_loosen_stuck_checks);
  1052.         }
  1053.         else if (m_colliderMode == eColliderMode_GroundedOnly)
  1054.         {
  1055.                 pd.bActive = 1;
  1056.                 pd.collTypes = ent_terrain | ent_static | ent_rigid | ent_sleeping_rigid | ent_living;
  1057.                 pp.flagsAND = ~characterGeomCollTypeFlags;
  1058.                 pp.flagsColliderAND = ~characterGeomCollTypeFlags;
  1059.                 pf.flagsAND = ~(pef_ignore_areas | lef_loosen_stuck_checks);
  1060.         }
  1061.         else if (m_colliderMode == eColliderMode_Pushable)
  1062.         {
  1063.                 pd.bActive = 1;
  1064.                 pd.collTypes = ent_terrain | ent_static | ent_rigid | ent_sleeping_rigid | ent_living;
  1065.  
  1066.                 pp.flagsOR = characterGeomCollTypeFlags;
  1067.                 pp.flagsColliderOR = characterGeomCollTypeFlags;
  1068.  
  1069.                 // Enable the loosen stuck checks (essentially disabling an addition sanity
  1070.                 // check in livingentity::step) for all animated characters except for the
  1071.                 // local player instance (remote clients' livingentities get synchronized).
  1072.                 bool bIsClient = GetEntityId() == CCryAction::GetCryAction()->GetClientActorId();
  1073.                 pf.flagsOR = pef_pushable_by_players | (lef_loosen_stuck_checks & - (int)!bIsClient);
  1074.                 pf.flagsAND = ~(pef_ignore_areas | (lef_loosen_stuck_checks & - (int)bIsClient));
  1075.         }
  1076.         else if (m_colliderMode == eColliderMode_NonPushable)
  1077.         {
  1078.                 pd.bActive = 1;
  1079.                 pd.collTypes = ent_terrain | ent_static | ent_rigid | ent_sleeping_rigid | ent_living;
  1080.                 pp.flagsOR = characterGeomCollTypeFlags;
  1081.                 pp.flagsColliderOR = characterGeomCollTypeFlags;
  1082.                 pf.flagsOR = lef_loosen_stuck_checks;
  1083.                 pf.flagsAND = ~pef_pushable_by_players & ~pef_ignore_areas;
  1084.         }
  1085.         else if (m_colliderMode == eColliderMode_PushesPlayersOnly)
  1086.         {
  1087.                 pd.bActive = 1;
  1088.                 pd.collTypes = ent_living;
  1089.                 pd.gravity.zero();
  1090.                 pp.flagsOR = characterGeomCollTypeFlags;
  1091.                 pp.flagsColliderOR = characterGeomCollTypeFlags;
  1092.                 pf.flagsOR = pef_ignore_areas | lef_loosen_stuck_checks;
  1093.                 pf.flagsAND = ~pef_pushable_by_players;
  1094.         }
  1095.         else if (m_colliderMode == eColliderMode_Spectator)
  1096.         {
  1097.                 pd.bActive = 1;
  1098.                 pd.collTypes = ent_terrain;
  1099.  
  1100.                 if (CAnimationGraphCVars::Get().m_spectatorCollisions)
  1101.                 {
  1102.                         pd.collTypes |= ent_static;
  1103.                 }
  1104.  
  1105.                 pp.flagsAND = ~characterGeomCollTypeFlags;
  1106.                 pp.flagsColliderOR = characterGeomCollTypeFlags;
  1107.  
  1108.                 pe_action_move move;
  1109.                 move.dir = ZERO;
  1110.                 move.iJump = 0;
  1111.                 pPhysEnt->Action(&move);
  1112.                 pd.gravity.zero();
  1113.                 pf.flagsOR = pef_ignore_areas;
  1114.                 pf.flagsAND = ~lef_loosen_stuck_checks;
  1115.         }
  1116.         else
  1117.         {
  1118.                 CRY_ASSERT(!"ColliderMode not implemented!");
  1119.                 return;
  1120.         }
  1121.  
  1122.         if ((m_colliderMode == eColliderMode_NonPushable) && (m_pFeetColliderPE == NULL))
  1123.                 CreateExtraSolidCollider();
  1124.  
  1125.         if ((m_colliderMode != eColliderMode_NonPushable) && (m_pFeetColliderPE != NULL))
  1126.                 DestroyExtraSolidCollider();
  1127.  
  1128.         pp.ipart = 0;
  1129.         pPhysEnt->SetParams(&pd);
  1130.         pPhysEnt->SetParams(&pp);
  1131.         pPhysEnt->SetParams(&pf);
  1132. }
  1133.  
  1134. void CAnimatedCharacter::EnableRigidCollider(float radius)
  1135. {
  1136.         IPhysicalEntity* pPhysEnt = GetEntity()->GetPhysics();
  1137.         if (pPhysEnt && !m_pRigidColliderPE)
  1138.         {
  1139.                 pe_params_pos pp;
  1140.                 pp.pos = GetEntity()->GetWorldPos();
  1141.                 pp.iSimClass = 2;
  1142.                 m_pRigidColliderPE = gEnv->pPhysicalWorld->CreatePhysicalEntity(PE_RIGID, &pp, GetEntity(), PHYS_FOREIGN_ID_ENTITY);
  1143.  
  1144.                 primitives::capsule prim;
  1145.                 prim.axis.Set(0, 0, 1);
  1146.                 prim.center.Set(0.0f, 0.0f, 0.5f);
  1147.                 prim.r = radius;
  1148.                 prim.hh = 0.6f;
  1149.                 IGeometry* pPrimGeom = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::capsule::type, &prim);
  1150.                 phys_geometry* pGeom = gEnv->pPhysicalWorld->GetGeomManager()->RegisterGeometry(pPrimGeom, 0);
  1151.                 pPrimGeom->Release();
  1152.                 pGeom->nRefCount = 0;
  1153.  
  1154.                 pe_geomparams gp;
  1155.                 gp.pos.zero();
  1156.                 gp.flags = m_characterCollisionFlags;
  1157.                 gp.flagsCollider = m_characterCollisionFlags;
  1158.                 gp.mass = 0.0f;
  1159.                 gp.density = 0.0f;
  1160.                 m_pRigidColliderPE->AddGeometry(pGeom, &gp, 103);
  1161.         }
  1162. }
  1163.  
  1164. void CAnimatedCharacter::DisableRigidCollider()
  1165. {
  1166.         if (m_pRigidColliderPE)
  1167.         {
  1168.                 gEnv->pPhysicalWorld->DestroyPhysicalEntity(m_pRigidColliderPE);
  1169.                 m_pRigidColliderPE = NULL;
  1170.         }
  1171. }
  1172.  
  1173. //--------------------------------------------------------------------------------
  1174.  
  1175. void CAnimatedCharacter::CreateExtraSolidCollider()
  1176. {
  1177.         // TODO: The solid collider created below is not supported/ignored by AI walkability tests.
  1178.         // It needs to be disabled until AI probes are adjusted.
  1179.         if (CAnimationGraphCVars::Get().m_enableExtraSolidCollider == 0)
  1180.                 return;
  1181.  
  1182.         if (m_pFeetColliderPE != NULL)
  1183.                 DestroyExtraSolidCollider();
  1184.  
  1185.         IPhysicalEntity* pPhysEnt = GetEntity()->GetPhysics();
  1186.         if (pPhysEnt == NULL)
  1187.                 return;
  1188.  
  1189.         pe_params_pos pp;
  1190.         pp.pos = GetEntity()->GetWorldPos();
  1191.         pp.iSimClass = 2;
  1192.         m_pFeetColliderPE = gEnv->pPhysicalWorld->CreatePhysicalEntity(PE_ARTICULATED, &pp, GetEntity(), PHYS_FOREIGN_ID_ENTITY);
  1193.  
  1194.         primitives::capsule prim;
  1195.         prim.axis.Set(0, 0, 1);
  1196.         prim.center.zero();
  1197.         prim.r = 0.45f;
  1198.         prim.hh = 0.6f;
  1199.         IGeometry* pPrimGeom = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::capsule::type, &prim);
  1200.         phys_geometry* pGeom = gEnv->pPhysicalWorld->GetGeomManager()->RegisterGeometry(pPrimGeom, 0);
  1201.         pGeom->nRefCount = 0;
  1202.  
  1203.         pe_geomparams gp;
  1204.         gp.pos.zero();
  1205.         gp.flags = geom_colltype_solid & ~m_characterCollisionFlags;
  1206.         gp.flagsCollider = 0;
  1207.         gp.mass = 0.0f;
  1208.         gp.density = 0.0f;
  1209.         //gp.minContactDist = 0.0f;
  1210.         m_pFeetColliderPE->AddGeometry(pGeom, &gp, 102); // some arbitrary id (100 main collider, 101 veggie collider)
  1211.  
  1212.         pe_params_articulated_body pab;
  1213.         pab.pHost = pPhysEnt;
  1214.         pab.posHostPivot = Vec3(0, 0, 0.8f);
  1215.         pab.bGrounded = 1;
  1216.         m_pFeetColliderPE->SetParams(&pab);
  1217. }
  1218.  
  1219. //--------------------------------------------------------------------------------
  1220.  
  1221. void CAnimatedCharacter::DestroyExtraSolidCollider()
  1222. {
  1223.         if (m_pFeetColliderPE == NULL)
  1224.                 return;
  1225.  
  1226.         gEnv->pPhysicalWorld->DestroyPhysicalEntity(m_pFeetColliderPE);
  1227.         m_pFeetColliderPE = NULL;
  1228. }
  1229.  
  1230. //--------------------------------------------------------------------------------
  1231.  
  1232. void CAnimatedCharacter::UpdatePhysicsInertia()
  1233. {
  1234.         ANIMCHAR_PROFILE_DETAILED;
  1235.  
  1236.         IPhysicalEntity* pPhysEnt = GetEntity()->GetPhysics();
  1237.         if (pPhysEnt && (pPhysEnt->GetType() == PE_LIVING) &&
  1238.             !GetEntity()->IsHidden()) // Hidden entities will ignore inertia sets, we don't want to invalidate our cache because of that
  1239.         {
  1240.                 pe_player_dynamics dynNew;
  1241.  
  1242.                 int mcmh = GetMCMH();
  1243.                 int mcmv = GetMCMV();
  1244.                 if ((mcmv == eMCM_Animation) || (mcmh == eMCM_Animation) || (mcmh == eMCM_AnimationHCollision) || (m_colliderMode == eColliderMode_PushesPlayersOnly))
  1245.                 {
  1246.                         dynNew.kInertia = 0.0f;
  1247.                         dynNew.kInertiaAccel = 0.0f;
  1248.                         if (m_colliderMode != eColliderMode_PushesPlayersOnly)
  1249.                                 dynNew.timeImpulseRecover = 0.0f;
  1250.                         else
  1251.                                 dynNew.timeImpulseRecover = m_params.timeImpulseRecover;
  1252.                 }
  1253.                 else
  1254.                 {
  1255.                         dynNew.kInertia = m_params.inertia;
  1256.                         dynNew.kInertiaAccel = m_params.inertiaAccel;
  1257.                         dynNew.timeImpulseRecover = m_params.timeImpulseRecover;
  1258.                 }
  1259.  
  1260.                 // Only change inertia values when they have changed since the last set
  1261.                 if ((m_fPrevInertia != dynNew.kInertia) ||
  1262.                     (m_fPrevInertiaAccel != dynNew.kInertiaAccel) ||
  1263.                     (m_fPrevTimeImpulseRecover != dynNew.timeImpulseRecover))
  1264.                 {
  1265.                         pPhysEnt->SetParams(&dynNew, 1);
  1266.  
  1267.                         m_fPrevInertia = dynNew.kInertia;
  1268.                         m_fPrevInertiaAccel = dynNew.kInertiaAccel;
  1269.                         m_fPrevTimeImpulseRecover = dynNew.timeImpulseRecover;
  1270.                 }
  1271.         }
  1272. }
  1273.  
  1274. //--------------------------------------------------------------------------------
  1275.  
  1276. void CAnimatedCharacter::GetCurrentEntityLocation()
  1277. {
  1278.         if (CAnimationGraphCVars::Get().m_useQueuedRotation)
  1279.         {
  1280.                 m_prevEntLocation = m_entLocation;
  1281.         }
  1282.         else
  1283.         {
  1284.                 // m_entLocation.q was already updated to its new value when we synchronously set
  1285.                 // the rotation in RequestPhysicalEntityMovement, so we should be careful not to
  1286.                 // copy it over m_prevEntLocation here until we calculated m_actualEntMovement
  1287.                 // The q component of m_prevEntLocation will be filled at the end of this function
  1288.                 m_prevEntLocation.t = m_entLocation.t;
  1289.         }
  1290.  
  1291.         IEntity* pEntity = GetEntity();
  1292.         CRY_ASSERT(pEntity != NULL);
  1293.  
  1294.         m_entLocation.q = pEntity->GetWorldRotation();
  1295.         m_entLocation.t = pEntity->GetWorldPos();
  1296.  
  1297.         CRY_ASSERT(m_entLocation.IsValid());
  1298.  
  1299.         m_actualEntMovement = GetWorldOffset(m_prevEntLocation, m_entLocation);
  1300.  
  1301.         // actualEntMovement measures from the previous frame, so we need to use prevFrameTime.
  1302.         const float prevFrameTimeInv = (float)__fsel(-(float)m_prevFrameTime, 0.0f, __fres((float)m_prevFrameTime + FLT_MIN));  // approximates: (m_prevFrameTime > 0.0f) ? (1.0f / (float)m_prevFrameTime) : 0.0f;
  1303.  
  1304.         const Vec3 velocity = m_actualEntMovement.t * prevFrameTimeInv;
  1305.         const float speed = velocity.GetLength();
  1306.  
  1307.         const float prevSpeed = m_actualEntSpeed;
  1308.         m_actualEntSpeed = speed;
  1309.  
  1310.         const float speed2D = Vec2(velocity).GetLength();
  1311.  
  1312.         const float prevSpeed2D = m_actualEntSpeedHorizontal;
  1313.         m_actualEntSpeedHorizontal = speed2D;
  1314.  
  1315.         m_actualEntMovementDirHorizontal.x = (float)__fsel(-(speed2D - FLT_MIN), 0.0f, velocity.x / (speed2D + FLT_MIN));// approximates: (speed2D > FLT_MIN) ? (velocity2D / speed2D) : Vec2Constants<float>::fVec2_Zero;
  1316.         m_actualEntMovementDirHorizontal.y = (float)__fsel(-(speed2D - FLT_MIN), 0.0f, velocity.y / (speed2D + FLT_MIN));
  1317.  
  1318.         const Vec2 prevVelocity2D = m_actualEntVelocityHorizontal;
  1319.         m_actualEntVelocityHorizontal = Vec2(velocity);
  1320.         m_actualEntAccelerationHorizontal = (m_actualEntVelocityHorizontal - prevVelocity2D) * prevFrameTimeInv;
  1321.  
  1322.         m_actualEntTangentialAcceleration = (speed - prevSpeed) * prevFrameTimeInv;
  1323.  
  1324. #ifdef _DEBUG
  1325.         //DebugHistory_AddValue("eDH_TEMP02", (m_prevFrameTime != 0.0f) ? m_actualEntMovement.t.GetLength2D() / m_prevFrameTime : 0.0f);
  1326. #endif
  1327.  
  1328. #ifdef _DEBUG
  1329.         DebugGraphQT(m_entTeleportMovement, "eDH_EntTeleportMovementTransX", "eDH_EntTeleportMovementTransY", "eDH_EntTeleportMovementRotZ");
  1330. #endif
  1331.  
  1332.         m_entTeleportMovement.SetIdentity();
  1333.  
  1334.         if (!CAnimationGraphCVars::Get().m_useQueuedRotation)
  1335.         {
  1336.                 m_prevEntLocation.q = m_entLocation.q;
  1337.         }
  1338.  
  1339. #if DEBUG_VELOCITY()
  1340.         if (DebugVelocitiesEnabled())
  1341.                 AddDebugVelocity(m_actualEntMovement, (float)m_curFrameTime, "Entity Movement", Col_Green, true);
  1342. #endif
  1343. }
  1344.  
  1345. //--------------------------------------------------------------------------------
  1346.  
  1347. bool CAnimatedCharacter::EnableProceduralLeaning()
  1348. {
  1349.         return (m_moveRequest.proceduralLeaning > 0.0f);
  1350. }
  1351.  
  1352. //--------------------------------------------------------------------------------
  1353.  
  1354. float CAnimatedCharacter::GetProceduralLeaningScale()
  1355. {
  1356.         return m_moveRequest.proceduralLeaning;
  1357. }
  1358.  
  1359. //--------------------------------------------------------------------------------
  1360.  
  1361. QuatT CAnimatedCharacter::CalculateProceduralLeaning()
  1362. {
  1363.         ANIMCHAR_PROFILE_DETAILED;
  1364.  
  1365.         float frameTimeScale = ((float)m_curFrameTime > 0.0f) ? (1.0f / ((float)m_curFrameTime / 0.02f)) : 0.0f;
  1366.         float curving = 0.0f;
  1367.         Vec2 prevVelo(ZERO);
  1368.         Vec3 avgAxx(0);
  1369.         float weightSum = 0.0f;
  1370.         CTimeValue curTime = gEnv->pTimer->GetFrameStartTime();
  1371.         for (int i = 0; i < NumAxxSamples; i++)
  1372.         {
  1373.                 int j = (m_reqLocalEntAxxNextIndex + i) % NumAxxSamples;
  1374.  
  1375.                 // AGE WEIGHT
  1376.                 float age = CTimeValue(curTime.GetValue() - m_reqEntTime[j].GetValue()).GetSeconds();
  1377.                 float ageFraction = clamp_tpl(age / 0.3f, 0.0f, 1.0f);
  1378.                 float weight = (0.5f - fabs(0.5f - ageFraction)) * 2.0f;
  1379.                 weight = 1.0f - sqr(1.0f - weight);
  1380.                 weight = sqr(weight);
  1381.  
  1382.                 weightSum += weight;
  1383.                 avgAxx.x += m_reqLocalEntAxx[j].x * weight * frameTimeScale;
  1384.                 avgAxx.y += m_reqLocalEntAxx[j].y * weight * frameTimeScale;
  1385.  
  1386.                 // CURVING
  1387.                 float area = fabs(m_reqEntVelo[j].Cross(prevVelo));
  1388.                 float len = prevVelo.GetLength() * m_reqEntVelo[j].GetLength();
  1389.                 if (len > 0.0f)
  1390.                         area /= len;
  1391.                 curving += area * weight;
  1392.                 prevVelo = m_reqEntVelo[j];
  1393.         }
  1394.  
  1395.         CRY_ASSERT(avgAxx.IsValid());
  1396.         if (weightSum > 0.0f)
  1397.         {
  1398.                 avgAxx /= weightSum;
  1399.                 curving /= weightSum;
  1400.         }
  1401.         CRY_ASSERT(avgAxx.IsValid());
  1402.  
  1403.         /*
  1404.            Vec3 curAxx;
  1405.            curAxx.x = m_reqLocalEntAxx[(m_reqLocalEntAxxNextIndex-1)%NumAxxSamples].x * frameTimeScale;
  1406.            curAxx.y = m_reqLocalEntAxx[(m_reqLocalEntAxxNextIndex-1)%NumAxxSamples].y * frameTimeScale;
  1407.          */
  1408.  
  1409.         float curvingFraction = clamp_tpl(curving / 0.3f, 0.0f, 1.0f);
  1410.         curvingFraction = 1.0f - sqr(1.0f - curvingFraction);
  1411.         float pulldownFraction = sqr(1.0f - clamp_tpl(curvingFraction / 0.3f, 0.0f, 1.0f));
  1412.  
  1413.         Vec3 prevActualEntVeloW = ((float)m_curFrameTime > 0.0f) ? (m_requestedEntityMovement.t / (float)m_curFrameTime) : ZERO;
  1414.         //Vec3 prevActualEntVeloW = (m_curFrameTime > 0.0f) ? (m_actualEntMovement.t / m_curFrameTime) : ZERO;
  1415.         prevActualEntVeloW.z = 0.0f; // Only bother about horizontal accelerations.
  1416.         float smoothVeloBlend = clamp_tpl((float)m_curFrameTime / 0.1f, 0.0f, 1.0f);
  1417.         Vec3 prevSmoothedActualEntVelo = m_smoothedActualEntVelo;
  1418.         CRY_ASSERT(prevSmoothedActualEntVelo.IsValid());
  1419.         m_smoothedActualEntVelo = LERP(m_smoothedActualEntVelo, prevActualEntVeloW, smoothVeloBlend);
  1420.         Vec3 smoothedActualEntVeloL = m_entLocation.q.GetInverted() * m_smoothedActualEntVelo;
  1421.         CRY_ASSERT(smoothedActualEntVeloL.IsValid());
  1422.  
  1423.         Vec3 deltaVelo = (m_smoothedActualEntVelo - prevSmoothedActualEntVelo);
  1424.         deltaVelo = m_entLocation.q.GetInverted() * deltaVelo;
  1425.         m_reqLocalEntAxx[m_reqLocalEntAxxNextIndex].x = deltaVelo.x;
  1426.         m_reqLocalEntAxx[m_reqLocalEntAxxNextIndex].y = deltaVelo.y;
  1427.         m_reqEntVelo[m_reqLocalEntAxxNextIndex].x = m_smoothedActualEntVelo.x;
  1428.         m_reqEntVelo[m_reqLocalEntAxxNextIndex].y = m_smoothedActualEntVelo.y;
  1429.         m_reqEntTime[m_reqLocalEntAxxNextIndex] = curTime;//gEnv->pTimer->GetFrameStartTime();
  1430.         m_reqLocalEntAxxNextIndex = (m_reqLocalEntAxxNextIndex + 1) % NumAxxSamples;
  1431.  
  1432.         // EQUALIZE VELOCITIES
  1433.         float velo = m_smoothedActualEntVelo.GetLength();
  1434.         float equalizeScale = 1.0f;
  1435.         if ((velo >= 0.0f) && (velo < 1.5f))
  1436.         {
  1437.                 float fraction = (velo - 0.0f) / 1.5f;
  1438.                 equalizeScale *= LERP(1.0f, 2.5f, fraction);
  1439.         }
  1440.         else if ((velo >= 1.5f) && (velo < 3.0f))
  1441.         {
  1442.                 float fraction = (velo - 1.5f) / 1.5f;
  1443.                 equalizeScale *= LERP(2.5f, 1.0f, fraction);
  1444.         }
  1445.         else if ((velo >= 3.0f) && (velo < 6.0f))
  1446.         {
  1447.                 float fraction = (velo - 3.0f) / 3.0f;
  1448.                 equalizeScale *= LERP(1.0f, 0.7f, fraction);
  1449.         }
  1450.         else if ((velo >= 6.0f) && (velo < 10.0f))
  1451.         {
  1452.                 float fraction = (velo - 6.0f) / 4.0f;
  1453.                 equalizeScale *= LERP(0.7f, 0.3f, fraction);
  1454.         }
  1455.         else if ((velo >= 10.0f) && (velo < 50.0f))
  1456.         {
  1457.  
  1458.                 float fraction = (min(velo, 20.0f) - 10.0f) / 10.0f;
  1459.                 equalizeScale *= LERP(0.3f, 0.1f, fraction);
  1460.         }
  1461.  
  1462.         float scale = 1.0f;
  1463.         scale *= (1.0f + curvingFraction);
  1464.         scale *= equalizeScale;
  1465.         CRY_ASSERT(avgAxx.IsValid());
  1466.         Vec3 avgAxxScaled = avgAxx * scale;
  1467.         CRY_ASSERT(avgAxx.IsValid());
  1468.  
  1469.         if (avgAxxScaled.IsEquivalent(ZERO))
  1470.                 avgAxxScaled.zero();
  1471.  
  1472.         // CLAMP AMOUNT
  1473.         float alignmentOriginal = (smoothedActualEntVeloL | m_avgLocalEntAxx);
  1474.         float amount = avgAxxScaled.GetLength();
  1475.         float amountMaxNonCurving = (0.5f + 0.5f * clamp_tpl(alignmentOriginal * 2.0f, 0.0f, 1.0f));
  1476.         float amountMax = 0.35f;
  1477.         amountMax *= LERP(amountMaxNonCurving, 1.0f, curvingFraction);
  1478.         if (amount > 0.00001f) // (AdamR) Changed comparison from 0.0f to handle occasional X360 denormals
  1479.                 avgAxxScaled = (avgAxxScaled / amount) * min(amount, amountMax);
  1480.  
  1481.         CRY_ASSERT(avgAxxScaled.IsValid());
  1482.  
  1483.         float axxContinuityMag = avgAxxScaled.GetLength() * m_avgLocalEntAxx.GetLength();
  1484.         float axxContinuityDot = (avgAxxScaled | m_avgLocalEntAxx);
  1485.         float axxContinuity = (axxContinuityMag > 0.0f) ? (axxContinuityDot / axxContinuityMag) : 0.0f;
  1486.         axxContinuity = clamp_tpl(axxContinuity, 0.0f, 1.0f);
  1487.         float axxBlend = ((float)m_curFrameTime / 0.2f);
  1488.         axxBlend *= 0.5f + 0.5f * axxContinuity;
  1489.         float axxBlendClamped = clamp_tpl(axxBlend, 0.0f, 1.0f);
  1490.         m_avgLocalEntAxx = LERP(m_avgLocalEntAxx, avgAxxScaled, axxBlendClamped);
  1491.         CRY_ASSERT(m_avgLocalEntAxx.IsValid());
  1492.  
  1493.         amount = m_avgLocalEntAxx.GetLength();
  1494.  
  1495.         Vec3 lean = Vec3(0, 0, 1) + m_avgLocalEntAxx;
  1496.         lean.NormalizeSafe(Vec3(0, 0, 1));
  1497.         float pulldown = max(LERP((-0.0f), (-0.25f), pulldownFraction), -amount * 0.6f);
  1498.         //pulldown = 0.0f;
  1499.  
  1500.         QuatT leaning;
  1501.         leaning.q.SetRotationV0V1(Vec3(0, 0, 1), lean);
  1502.         leaning.t.zero();
  1503.         leaning.t = -m_avgLocalEntAxx;
  1504.         leaning.t *= (0.8f + 0.4f * curvingFraction);
  1505.         leaning.t.z = pulldown;
  1506.  
  1507.         leaning.t *= 0.1f;
  1508.         if (!m_isPlayer)
  1509.                 leaning.t *= 0.5f;
  1510.  
  1511.         float proceduralLeaningScale = GetProceduralLeaningScale();
  1512.         clamp_tpl(proceduralLeaningScale, 0.0f, 1.0f);
  1513.         leaning = leaning.GetScaled(proceduralLeaningScale);
  1514.  
  1515. #if _DEBUG && defined(USER_david)
  1516.         if (DebugFilter())
  1517.         {
  1518.                 CPersistantDebug* pPD = CCryAction::GetCryAction()->GetPersistantDebug();
  1519.  
  1520.                 if (pPD != NULL)
  1521.                 {
  1522.                         /*
  1523.                               DebugHistory_AddValue("eDH_TEMP00", m_actualEntMovement.t.x / m_curFrameTime);
  1524.                               DebugHistory_AddValue("eDH_TEMP01", m_actualEntMovement.t.y / m_curFrameTime);
  1525.                               DebugHistory_AddValue("eDH_TEMP02", m_smoothedActualEntVelo.x);
  1526.                               DebugHistory_AddValue("eDH_TEMP03", m_smoothedActualEntVelo.y);
  1527.                               DebugHistory_AddValue("eDH_TEMP04", curAxx.x);
  1528.                               DebugHistory_AddValue("eDH_TEMP05", curAxx.y);
  1529.                               DebugHistory_AddValue("eDH_TEMP06", avgAxx.x);
  1530.                               DebugHistory_AddValue("eDH_TEMP07", avgAxx.y);
  1531.  
  1532.                               DebugHistory_AddValue("eDH_TEMP10", alignmentOriginal);
  1533.                               DebugHistory_AddValue("eDH_TEMP11", amountMaxNonCurving);
  1534.                               DebugHistory_AddValue("eDH_TEMP12", equalizeScale);
  1535.                               DebugHistory_AddValue("eDH_TEMP13", curvingFraction);
  1536.                               DebugHistory_AddValue("eDH_TEMP14", scale);
  1537.  
  1538.                               DebugHistory_AddValue("eDH_TEMP15", amount);
  1539.                               DebugHistory_AddValue("eDH_TEMP16", m_avgLocalEntAxx.x);
  1540.                               DebugHistory_AddValue("eDH_TEMP17", m_avgLocalEntAxx.y);
  1541.                            /**/
  1542.                         //*
  1543.                         DebugHistory_AddValue("eDH_TEMP00", m_smoothedActualEntVelo.x);
  1544.                         DebugHistory_AddValue("eDH_TEMP01", m_smoothedActualEntVelo.y);
  1545.                         DebugHistory_AddValue("eDH_TEMP02", m_avgLocalEntAxx.x);
  1546.                         DebugHistory_AddValue("eDH_TEMP03", m_avgLocalEntAxx.y);
  1547.  
  1548.                         DebugHistory_AddValue("eDH_TEMP10", curving);
  1549.                         DebugHistory_AddValue("eDH_TEMP11", curvingFraction);
  1550.                         DebugHistory_AddValue("eDH_TEMP12", pulldownFraction);
  1551.                         DebugHistory_AddValue("eDH_TEMP13", pulldown);
  1552.  
  1553.                         DebugHistory_AddValue("eDH_TEMP06", alignmentOriginal);
  1554.                         /**/
  1555.  
  1556.                         /*
  1557.                               Vec3 bump(0,0,0.1f);
  1558.                               pPD->Begin(UNIQUE("AnimatedCharacter.FakeLeaning"), true);
  1559.                               pPD->AddLine(m_animLocation.t+bump, m_animLocation.t+bump + m_entLocation.q*lean, ColorF(1,1,1,1), 0.5f);
  1560.                               pPD->AddLine(m_animLocation.t+bump+Vec3(0,0,1), m_animLocation.t+bump+Vec3(0,0,1) + m_entLocation.q*m_avgLocalEntAxx, ColorF(0.5f,1,0.5f,1), 0.5f);
  1561.                               pPD->Begin(UNIQUE("AnimatedCharacter.FakeLeaningAxx"), false);
  1562.                               pPD->AddLine(m_animLocation.t+bump, m_animLocation.t+bump + m_entLocation.q*m_avgLocalEntAxx, ColorF(1.0f,1.0f,1.0f,1), 5.0f);
  1563.                          */
  1564.                 }
  1565.         }
  1566. #endif
  1567.  
  1568.         return leaning;
  1569. }
  1570.  
  1571. //--------------------------------------------------------------------------------
  1572.  
downloadAnimatedCharacterPPS.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top