//------------------------------------------------------------------------ bool CItem::PlayFragment(IAction* pAction, float speedOverride, float timeOverride, float animWeight, float ffeedbackWeight, bool concentratedFire) { _smart_ptr<IAction> pActionPtr(pAction); CRY_ASSERT(pAction); if(!pAction) { return false; } CWeapon *pWeapon = static_cast<CWeapon*>(GetIWeapon()); if (pWeapon && pWeapon->IsProxyWeapon()) { return false; } bool success = false; float speed = (float)__fsel(-speedOverride, 1.0f, speedOverride); FragmentID fragID = pAction->GetFragmentID(); pAction->SetSubContext(m_subContext); IActionController *pActionController = GetActionController(); if ((fragID != FRAGMENT_ID_INVALID) && pActionController) { float fragmentDuration, transitionDuration; if (pActionController->QueryDuration(*pAction, fragmentDuration, transitionDuration)) { float duration = fragmentDuration+transitionDuration; if ((duration > 0.0f) && (timeOverride > 0.0f)) { speed = (duration / timeOverride); CRY_ASSERT((speed > 0.0f) && (speed < 99999.0f)); } if(duration > 0.f) { m_animationTime[eIGS_Owner] = (uint32) MAX((duration*1000.0f/speed) - 20, 0.0f); } pAction->SetSpeedBias(speed); pAction->SetAnimWeight(animWeight); if(concentratedFire) { pAction->SetParam(CItem::sActionParamCRCs.concentratedFire, 1.f); } if(ffeedbackWeight != 1.f) { pAction->SetParam(CItem::sActionParamCRCs.ffeedbackScale, ffeedbackWeight); } pActionController->Queue(pAction); success = true; } } return success; }
// ---------------------------------------------------------------------------- void CMannequinAGState::Hurry() { // first check whether we have anything that is still pending, if not, we have nothing to hurry const bool oneShotActionIsPending = (m_pOneShotAction && (m_pOneShotAction->GetStatus() == IAction::Pending)); const bool loopingActionIsPending = (m_pLoopingAction && (m_pLoopingAction->GetStatus() == IAction::Pending)); if (!oneShotActionIsPending && !loopingActionIsPending) return; IActionController* pActionController = GetActionController(); if (!pActionController) return; // TODO: How do we mimic Hurry? Somehow we need to, in a clean way, end all actions on all scopes // (without screwing up the pending ones, properly moving interruptable ones to the queue, // calling Exit() when needed, etc) }
//------------------------------------------------------------------------ int CItem::GetFragmentID(const char* actionName, const CTagDefinition** tagDef) { int fragmentID = FRAGMENT_ID_INVALID; IActionController *pActionController = GetActionController(); if (pActionController) { SAnimationContext &animContext = pActionController->GetContext(); fragmentID = animContext.controllerDef.m_fragmentIDs.Find(actionName); if(tagDef && fragmentID != FRAGMENT_ID_INVALID) { *tagDef = animContext.controllerDef.GetFragmentTagDef(fragmentID); } } return fragmentID; }
// ---------------------------------------------------------------------------- const char* CMannequinAGState::GetCurrentStateName() { const char* result = "<unknown>"; // Figure out something which could pose as a 'state name' // Currently it's the name of the first fragmentID I can find on the scopes IActionController* pActionController = GetActionController(); if (!pActionController) return result; for(int scopeIndex = 0; scopeIndex < pActionController->GetTotalScopes(); ++scopeIndex) { IScope* pScope = pActionController->GetScope(scopeIndex); FragmentID fragmentID = pScope->GetLastFragmentID(); if (fragmentID != FRAGMENT_ID_INVALID) { result = pActionController->GetContext().controllerDef.m_fragmentIDs.GetTagName(fragmentID); break; } } return result ; }
//------------------------------------------------------------------------ _smart_ptr<IAction> CItem::PlayAction(FragmentID action, int layer, bool loop, uint32 flags, float speedOverride, float animWeigth, float ffeedbackWeight) { _smart_ptr<IAction> pAction; const CWeapon* pWeapon = static_cast<CWeapon*>(GetIWeapon()); if (pWeapon && pWeapon->IsProxyWeapon()) { return pAction; } IActionController* pActionController = GetActionController(); if (pActionController && action != FRAGMENT_ID_INVALID) { SAnimationContext& animContext = pActionController->GetContext(); const CTagDefinition* pTagDefinition = animContext.controllerDef.GetFragmentTagDef(action); float timeOverride = -1.0f; bool concentratedFire = (flags&eIPAF_ConcentratedFire) != 0; TagState actionTags = TAG_STATE_EMPTY; if (pTagDefinition) { CTagState fragTags(*pTagDefinition); SetFragmentTags(fragTags); actionTags = fragTags.GetMask(); } pAction = new CItemAction(PP_PlayerAction, action, actionTags); PlayFragment(pAction, speedOverride, timeOverride, animWeigth, ffeedbackWeight, concentratedFire); } return pAction; }
// ---------------------------------------------------------------------------- bool CMannequinAGState::SetActionOrSignalInput(_smart_ptr<CAnimActionAGAction>& pAction, TKeyValue& currentValue, InputID inputID, EAIActionType actionType, const char* defaultValue, uint32 defaultValueCRC, const char* value, TAnimationGraphQueryID* pQueryID, bool optional) { IActionController* pActionController = GetActionController(); if (!pActionController) return false; // TODO Where to get the priorities from? const int MANNEQUIN_PRIORITY = 2; // currently equal to PP_Action, just above movement, but underneath urgent actions, hit death, etc. TAnimationGraphQueryID queryID = 0; if (pQueryID) queryID = *pQueryID = GenerateQueryID(); const uint32 valueCRC = CCrc32::ComputeLowercase(value); static uint32 idleCRC = CCrc32::ComputeLowercase("idle"); static uint32 noneCRC = CCrc32::ComputeLowercase("none"); const bool isUnsupportedFragmentID = ((valueCRC == idleCRC) || (valueCRC == noneCRC)); const FragmentID fragmentID = isUnsupportedFragmentID ? FRAGMENT_ID_INVALID : pActionController->GetContext().controllerDef.m_fragmentIDs.Find(valueCRC); const bool isDefaultValue = (valueCRC == defaultValueCRC); const bool somethingIsPendingOrInstalled = pAction && pAction->IsPendingOrInstalled(); if (isDefaultValue) { if ( actionType == EAT_Looping ) { StopAnyLoopingExactPositioningAction(); } const bool isPendingOrInstalled = !somethingIsPendingOrInstalled; // the fake action 'idle' isPendingOrInstalled if something else is NOT pending or installed if (isPendingOrInstalled) { // In the old sense: the current requested 'value' did not change, we were already 'idle' SendEvent_Entered(NULL, queryID, true); } else { currentValue = defaultValue; if (pAction) { pAction->Stop(); // this will eventually call Entered(..,false) of the user that was waiting on Entered() pAction = NULL; } // TODO: This is not entirely correct. The Entered() event for the idle action should only // be called when you exactly "go back to idle". But this is not well defined in mannequin, // so I just send it right away... SendEvent_Entered(NULL, queryID, true); SendEvent_ChangedInput(inputID, true); // tell whoever is listening to the input that it changed } return true; } else if (fragmentID != FRAGMENT_ID_INVALID) { const bool isPendingOrInstalled = somethingIsPendingOrInstalled && (pAction->GetValueCRC() == valueCRC); if (isPendingOrInstalled) { // In the old sense: the current requested 'value' did not change // reuse the old queryid, if there is one, otherwise set the new one if (pAction->GetQueryID()) { queryID = pAction->GetQueryID(); if (pQueryID) *pQueryID = queryID; } else { if (queryID) pAction->SetQueryID(queryID); } if (pAction->GetStatus() == IAction::Installed) { // The other system is already playing the same action. // Send the 'entered' event immediately // (afai can see the AG only did this for signals for some reason??) SendEvent_Entered(pAction, pAction->GetQueryID(), true); } } else { currentValue = value; pAction = new CAnimActionAGAction(MANNEQUIN_PRIORITY, fragmentID, *this, actionType, value, valueCRC, queryID); pActionController->Queue(*pAction.get()); SendEvent_ChangedInput(inputID, true); // tell whoever is listening the input that it changed } return true; } else if (!optional) { // 'not optional' means invalid values get translated into the default value // (so we always set a value, hence the setting of values is 'not optional') // Recurse and pass the defaultValue as value: return SetActionOrSignalInput(pAction, currentValue, inputID, actionType, defaultValue, defaultValueCRC, defaultValue, NULL, true); } else { #ifndef _RELEASE if(!isUnsupportedFragmentID) { CryWarning( VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CMannequinAGState::SetInput: Unable to find animation '%s'", value); } #endif //#ifndef _RELEASE return false; } }
//------------------------------------------------------------------------ bool CItem::SetGeometry(int slot, const ItemString& name, const ItemString& material, bool useParentMaterial, const Vec3& poffset, const Ang3& aoffset, float scale, bool forceReload) { assert(slot >= 0 && slot < eIGS_Last); bool changedfp=false; switch(slot) { case eIGS_Owner: break; case eIGS_FirstPerson: case eIGS_ThirdPerson: default: { if (name.empty() || forceReload) { GetEntity()->FreeSlot(slot); #ifndef ITEM_USE_SHAREDSTRING m_geometry[slot].resize(0); #else m_geometry[slot].reset(); #endif } DestroyAttachmentHelpers(slot); if (!name.empty()) { if (m_geometry[slot] != name) { const char* ext = PathUtil::GetExt(name.c_str()); if ((stricmp(ext, "chr") == 0) || (stricmp(ext, "cdf") == 0) || (stricmp(ext, "cga") == 0) ) GetEntity()->LoadCharacter(slot, name.c_str(), 0); else GetEntity()->LoadGeometry(slot, name.c_str(), 0, 0); changedfp=slot==eIGS_FirstPerson; } CreateAttachmentHelpers(slot); } /* if (slot == eIGS_FirstPerson) { ICharacterInstance *pCharacter = GetEntity()->GetCharacter(eIGS_FirstPerson); if (pCharacter) { pCharacter->SetFlags(pCharacter->GetFlags()&(~CS_FLAG_UPDATE)); } } else */if (slot == eIGS_Destroyed) DrawSlot(eIGS_Destroyed, false); } break; } Matrix34 slotTM; slotTM = Matrix34::CreateRotationXYZ(aoffset); slotTM.ScaleColumn(Vec3(scale, scale, scale)); slotTM.SetTranslation(poffset); GetEntity()->SetSlotLocalTM(slot, slotTM); if (changedfp && m_stats.mounted) { if (m_sharedparams->pMountParams && !m_sharedparams->pMountParams->pivot.empty()) { Matrix34 tm=GetEntity()->GetSlotLocalTM(eIGS_FirstPerson, false); Vec3 pivot = GetSlotHelperPos(eIGS_FirstPerson, m_sharedparams->pMountParams->pivot.c_str(), false); tm.AddTranslation(pivot); GetEntity()->SetSlotLocalTM(eIGS_FirstPerson, tm); } GetEntity()->InvalidateTM(); } m_geometry[slot] = name ? name : ItemString(); ReAttachAccessories(); IEntity* pParentEntity = gEnv->pEntitySystem->GetEntity(GetParentId()); IMaterial* pOverrideMaterial = 0; if (!material.empty()) { pOverrideMaterial = gEnv->p3DEngine->GetMaterialManager()->LoadMaterial(material.c_str()); } else if (useParentMaterial && pParentEntity) { ICharacterInstance* pParentCharacter = pParentEntity->GetCharacter(slot); IEntityRenderProxy* pParentRenderProxy = static_cast<IEntityRenderProxy*>(pParentEntity->GetProxy(ENTITY_PROXY_RENDER)); if (pParentCharacter) pOverrideMaterial = pParentCharacter->GetIMaterial(); else if (pParentRenderProxy) pOverrideMaterial = pParentRenderProxy->GetSlotMaterial(slot); } if (pOverrideMaterial) { ICharacterInstance* pCharacter = GetEntity()->GetCharacter(slot); IEntityRenderProxy* pRenderProxy = static_cast<IEntityRenderProxy*>(GetEntity()->GetProxy(ENTITY_PROXY_RENDER)); OverrideAttachmentMaterial(pOverrideMaterial, this, slot); if (pCharacter) pCharacter->SetIMaterial_Instance(pOverrideMaterial); else if (pRenderProxy) pRenderProxy->SetSlotMaterial(slot, pOverrideMaterial); } if(slot == eIGS_FirstPerson && IsSelected()) { CActor* pOwnerActor = GetOwnerActor(); IActionController *pActionController = GetActionController(); if(pActionController && pOwnerActor && pOwnerActor->IsClient()) { UpdateScopeContexts(pActionController); } } return true; }
bool CActionScope::QueueFragment(FragmentID fragID, const SFragTagState &fragTagState, uint32 optionIdx, float startTime, uint32 userToken, bool isRootScope, bool isHigherPriority, bool principleContext) { if (m_scopeContext.pDatabase == NULL) { return false; } SBlendQuery query; FillBlendQuery(query, fragID, fragTagState, isHigherPriority, NULL); query.SetFlag(SBlendQuery::toInstalled, principleContext); SFragmentData fragData; IAnimationSet* pAnimSet = m_scopeContext.pCharInst ? m_scopeContext.pCharInst->GetIAnimationSet() : NULL; m_sequenceFlags = m_scopeContext.pDatabase->Query(fragData, query, optionIdx, pAnimSet, &m_lastFragSelection); m_lastQueueTagState = query.tagStateTo; m_lastNormalisedTime = m_normalisedTime = 0.0f; m_isOneShot = fragData.isOneShot && ((fragID == FRAGMENT_ID_INVALID) || ((m_context.controllerDef.GetFragmentDef(fragID).flags & SFragmentDef::PERSISTENT) == 0)); m_blendOutDuration = fragData.blendOutDuration; m_fragmentInstalled = principleContext; const bool fragmentInstalled = HasFragment(); #if MANNEQUIN_DEBUGGING_ENABLED CryStackStringT<char,128> sTagList = "No Match"; CryStackStringT<char,128> sFragTagList; if (!fragmentInstalled && (m_layer == 0) && (m_numLayers > 0)) { const char* fragmentName = fragID != FRAGMENT_ID_INVALID ? m_context.controllerDef.m_fragmentIDs.GetTagName(fragID) : "None"; m_context.controllerDef.m_tags.FlagsToTagList(fragTagState.globalTags, sTagList); const CTagDefinition* pFragTagDef = (fragID != FRAGMENT_ID_INVALID) ? m_context.controllerDef.GetFragmentTagDef(fragID) : NULL; if (pFragTagDef) { pFragTagDef->FlagsToTagList(fragTagState.fragmentTags, sFragTagList); } MannLog(GetActionController(), "Warning - Missing root level fragment %s(%s)", fragmentName, sTagList.c_str()); } if (m_actionController.DebugFragments(principleContext) && fragmentInstalled) { if (HasFragment()) { m_context.controllerDef.m_tags.FlagsToTagList(m_lastFragSelection.tagState.globalTags, sTagList); const CTagDefinition* pFragTagDef = m_context.controllerDef.GetFragmentTagDef(fragID); if (pFragTagDef) { pFragTagDef->FlagsToTagList(m_lastFragSelection.tagState.fragmentTags, sFragTagList); } } const char* fragmentName = fragID != FRAGMENT_ID_INVALID ? m_context.controllerDef.m_fragmentIDs.GetTagName(fragID) : "None"; const char* prevFragmentName = query.fragmentFrom != FRAGMENT_ID_INVALID ? m_context.controllerDef.m_fragmentIDs.GetTagName(query.fragmentFrom) : "None"; MannLog(GetActionController(), "Frag %s (%s,%s) queued on %s for action %s", fragmentName, sTagList.c_str(), sFragTagList.c_str(), m_name.c_str(), m_pAction ? m_pAction->GetName() : "None"); CryStackStringT<char,128> sTagStateFrom; CryStackStringT<char,128> sTagStateTo; SBlendQueryResult queryRes1, queryRes2; m_scopeContext.pDatabase->FindBestBlends(query, queryRes1, queryRes2); if (queryRes1.pFragmentBlend) { MannLog(GetActionController(), "Transition from (%s -> %s) %s", (queryRes1.fragmentFrom != FRAGMENT_ID_INVALID) ? prevFragmentName : "Any", (queryRes1.fragmentTo != FRAGMENT_ID_INVALID) ? fragmentName : "Any", queryRes1.pFragmentBlend->IsExitTransition() ? "Exit" : ""); m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes1.tagStateFrom.globalTags, sTagStateFrom); m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes1.tagStateTo.globalTags, sTagStateTo); MannLog(GetActionController(), "Transition tags (%s -> %s)", sTagStateFrom.c_str(), sTagStateTo.c_str()); } if (queryRes2.pFragmentBlend) { MannLog(GetActionController(), "And Transition from (%s -> %s) %s", (queryRes2.fragmentFrom != FRAGMENT_ID_INVALID) ? prevFragmentName : "Any", (queryRes2.fragmentTo != FRAGMENT_ID_INVALID) ? fragmentName : "Any", queryRes2.pFragmentBlend->IsExitTransition() ? "Exit" : ""); m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes2.tagStateFrom.globalTags, sTagStateFrom); m_actionController.GetContext().controllerDef.m_tags.FlagsToTagList(queryRes2.tagStateTo.globalTags, sTagStateTo); MannLog(GetActionController(), "Transition tags (%s -> %s)", sTagStateFrom.c_str(), sTagStateTo.c_str()); } } #endif //MANNEQUIN_DEBUGGING_ENABLED m_fragmentDuration = m_transitionOutroDuration = m_transitionDuration = 0.0f; for (uint32 i = 0; i < SFragmentData::PART_TOTAL; i++) { m_partTypes[i] = fragData.transitionType[i]; switch (fragData.transitionType[i]) { case eCT_Normal: m_fragmentDuration += fragData.duration[i]; break; case eCT_Transition: m_transitionDuration += fragData.duration[i]; break; case eCT_TransitionOutro: m_transitionOutroDuration += fragData.duration[i]; break; } } if (!isRootScope) { if (m_sequenceFlags & (eSF_Transition | eSF_TransitionOutro)) { startTime = 0.0f; } else { startTime = max(startTime - (m_transitionOutroDuration + m_transitionDuration), 0.0f); } } m_lastFragmentID = fragID; m_fragmentTime = -startTime; const uint32 numAnimLayers = fragData.animLayers.size(); const uint32 numScopeLayers = m_numLayers; const uint32 numLayers = min(numAnimLayers, numScopeLayers); CRY_ASSERT_MESSAGE(numLayers <= m_numLayers, "Invalid layer count"); m_userToken = userToken; uint32 nLayer = 0; for (nLayer = 0; nLayer < numLayers; nLayer++) { const bool hasClips = fragData.animLayers[nLayer].size() > 0; SSequencer &sequencer = m_layerSequencers[nLayer]; sequencer.pos = 0; sequencer.referenceTime = -1.0f; if (hasClips) { sequencer.sequence = fragData.animLayers[nLayer]; sequencer.blend = sequencer.sequence[0].blend; sequencer.installTime = startTime + sequencer.blend.exitTime; sequencer.flags = eSF_Queued; } else { sequencer.sequence.resize(0); sequencer.blend = SAnimBlend(); sequencer.installTime = startTime; sequencer.flags = eSF_Queued | eSF_BlendingOut; } } for (; nLayer < numScopeLayers; nLayer++) { //--- Layers that are not touched by the new fragment blend out using default blends SSequencer &sequencer = m_layerSequencers[nLayer]; sequencer.sequence.resize(0); sequencer.pos = 0; sequencer.blend = SAnimBlend(); sequencer.installTime = startTime; sequencer.flags = eSF_Queued | eSF_BlendingOut; } const size_t numProcSequencers = fragData.procLayers.size(); const size_t totNumProcSequencers = max(numProcSequencers, m_procSequencers.size()); m_procSequencers.resize(totNumProcSequencers); for (nLayer = 0; nLayer < numProcSequencers; nLayer++) { const bool hasClips = fragData.procLayers[nLayer].size() > 0; SProcSequencer &sequencerPush = m_procSequencers[nLayer]; sequencerPush.pos = 0; if (hasClips) { sequencerPush.sequence = fragData.procLayers[nLayer]; const float layerBlendTime = sequencerPush.sequence[0].blend.exitTime; sequencerPush.installTime = startTime; sequencerPush.blend = sequencerPush.sequence[0].blend; sequencerPush.flags = eSF_Queued; if (layerBlendTime > 0.0f) { sequencerPush.blend = SAnimBlend(); sequencerPush.flags |= eSF_BlendingOut; } } else { sequencerPush.sequence.resize(0); sequencerPush.blend = SAnimBlend(); sequencerPush.installTime = startTime; sequencerPush.flags = eSF_Queued | eSF_BlendingOut; } } for (; nLayer < totNumProcSequencers; nLayer++) { SProcSequencer &sequencerPush = m_procSequencers[nLayer]; sequencerPush.sequence.resize(0); sequencerPush.pos = 0; sequencerPush.blend = SAnimBlend(); sequencerPush.installTime = startTime; sequencerPush.flags = eSF_Queued | eSF_BlendingOut; } return fragmentInstalled; }