BVB Source Codes

CRYENGINE Show AnimationDatabase.cpp Source code

Return Download CRYENGINE: download AnimationDatabase.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. //
  4. ////////////////////////////////////////////////////////////////////////////
  5. #include "StdAfx.h"
  6.  
  7. #include "AnimationDatabase.h"
  8.  
  9. int CAnimationDatabase::s_mnAllowEditableDatabasesInPureGame = 0;
  10. bool CAnimationDatabase::s_registeredCVars = false;
  11.  
  12. void CAnimationDatabase::RegisterCVars()
  13. {
  14.         if (!s_registeredCVars)
  15.         {
  16.                 REGISTER_CVAR3("mn_allowEditableDatabasesInPureGame", s_mnAllowEditableDatabasesInPureGame, 0, 0, "Do not store editable databases");
  17.                 s_registeredCVars = true;
  18.         }
  19. }
  20.  
  21. float AppendLayers(SFragmentData& fragmentData, const CFragment& fragment, uint8 partID, const IAnimationSet* animSet, float startTime, float startOffset, bool isBlend, bool& isOneShot)
  22. {
  23.         float totalTime = 0.0f;
  24.  
  25.         bool calcTime = true;
  26.  
  27.         SAnimClip nullClip;
  28.         nullClip.blend.exitTime = 0.0f;
  29.  
  30.         SProceduralEntry nullProc;
  31.         nullProc.blend.exitTime = 0.0f;
  32.  
  33.         uint32 numALayers = fragment.m_animLayers.size();
  34.         uint32 numPLayers = fragment.m_procLayers.size();
  35.         if (fragmentData.animLayers.size() < numALayers)
  36.                 fragmentData.animLayers.resize(numALayers);
  37.         if (fragmentData.procLayers.size() < numPLayers)
  38.                 fragmentData.procLayers.resize(numPLayers);
  39.         for (uint32 i = 0; i < numALayers; i++)
  40.         {
  41.                 const uint32 oldLength = fragmentData.animLayers[i].size();
  42.                 const uint32 fragLength = fragment.m_animLayers[i].size();
  43.                 const bool hadEntry = !fragmentData.animLayers[i].empty();
  44.                 const bool hasNewEntry = (fragLength > 0);
  45.                 float lastDuration = 0.0f;
  46.                 int startIdx = oldLength;
  47.  
  48.                 bool shouldOverride = false;
  49.                 if (hadEntry && hasNewEntry)
  50.                 {
  51.                         //--- Should we merge over the existing final blend or append to it?
  52.                         const SAnimBlend& prevBlend = fragmentData.animLayers[i][oldLength - 1].blend;
  53.                         shouldOverride = (prevBlend.exitTime >= startTime) || prevBlend.terminal;
  54.                         if (shouldOverride)
  55.                         {
  56.                                 startIdx = max(startIdx - 1, 0);
  57.                         }
  58.                 }
  59.  
  60.                 float layerTotalTime = 0.0f;
  61.  
  62.                 uint32 installFragLength = isBlend ? max(fragLength, 1u) : fragLength;
  63.  
  64.                 fragmentData.animLayers[i].resize(startIdx + installFragLength);
  65.                 for (uint32 k = 0; k < installFragLength; k++)
  66.                 {
  67.                         const bool firstClip = (k == 0);
  68.                         SAnimClip& animClip = fragmentData.animLayers[i][startIdx + k];
  69.                         const SAnimClip* sourceClip = (k < fragLength) ? &fragment.m_animLayers[i][k] : &nullClip;
  70.  
  71.                         animClip.animation = sourceClip->animation;
  72.                         animClip.part = partID;
  73.                         if (shouldOverride && firstClip)
  74.                         {
  75.                                 if (isBlend)
  76.                                 {
  77.                                         float oldExitTime = animClip.blend.exitTime;
  78.                                         animClip.blend = sourceClip->blend;
  79.                                         animClip.blend.exitTime = oldExitTime;
  80.                                         animClip.blendPart = partID;
  81.                                 }
  82.                         }
  83.                         else
  84.                         {
  85.                                 animClip.blend = sourceClip->blend;
  86.                                 int blendPart = partID;
  87.  
  88.                                 if (firstClip)
  89.                                 {
  90.                                         animClip.blend.exitTime = max(animClip.blend.exitTime, 0.0f);
  91.                                         animClip.blend.exitTime += startTime;
  92.  
  93.                                         if (!isBlend)
  94.                                         {
  95.                                                 blendPart = animClip.blendPart;
  96.                                         }
  97.                                 }
  98.                                 animClip.blendPart = blendPart;
  99.                         }
  100.                         animClip.animation.flags |= animClip.blend.flags;
  101.  
  102.                         if (animSet)
  103.                         {
  104.                                 float animDuration = 0.0f;
  105.                                 bool isVariableLength = false;
  106.                                 if (false == animClip.animation.animRef.IsEmpty()
  107.                                     && (0 == (animClip.animation.flags & CA_LOOP_ANIMATION))
  108.                                     && (animClip.animation.playbackSpeed > 0.0f))
  109.                                 {
  110.                                         int animID = animSet->GetAnimIDByCRC(animClip.animation.animRef.crc);
  111.                                         if (0 <= animID)
  112.                                         {
  113.                                                 animDuration = ((animSet->GetDuration_sec(animID) - animClip.blend.startTime) / animClip.animation.playbackSpeed);
  114.                                                 const uint32 flags = animSet->GetAnimationFlags(animID);
  115.                                                 isVariableLength = (flags & CA_ASSET_LMG) != 0;
  116.                                         }
  117.                                 }
  118.  
  119.                                 animClip.referenceLength = animDuration;
  120.                                 animClip.isVariableLength = isVariableLength;
  121.  
  122.                                 if (animClip.blend.exitTime < 0.0f)
  123.                                 {
  124.                                         animClip.blend.exitTime = lastDuration;
  125.                                 }
  126.  
  127.                                 if (calcTime)
  128.                                 {
  129.                                         totalTime += animClip.blend.exitTime;
  130.                                 }
  131.  
  132.                                 if (!isBlend)
  133.                                 {
  134.                                         float previousStartTime = layerTotalTime;
  135.                                         layerTotalTime += animClip.blend.exitTime;
  136.                                         float animStartTime = layerTotalTime;
  137.  
  138.                                         if (i == 0)
  139.                                         {
  140.                                                 //--- First layer is be used to check for a looping fragment
  141.                                                 isOneShot = ((animClip.animation.flags & CA_LOOP_ANIMATION) == 0);
  142.                                         }
  143.  
  144.                                         if (startOffset > animStartTime)
  145.                                         {
  146.                                                 // animation start is clipped by fragment transition
  147.                                                 float animStartOffset = startOffset - animStartTime;
  148.                                                 animClip.blend.startTime += animStartOffset / max(animDuration, 0.001f);
  149.                                                 animClip.blend.startTime = clamp_tpl(animClip.blend.startTime, 0.0f, 1.0f);
  150.                                                 animClip.blend.exitTime = 0.0f;
  151.                                         }
  152.                                         else if (startOffset > previousStartTime)
  153.                                         {
  154.                                                 // previous animation start was clipped by fragment transition: update exit time
  155.                                                 animClip.blend.exitTime -= startOffset - previousStartTime;
  156.                                                 animClip.blend.exitTime = max(0.0f, animClip.blend.exitTime);
  157.                                         }
  158.                                 }
  159.  
  160.                                 lastDuration = animDuration;
  161.                         }
  162.                 }
  163.  
  164.                 if (calcTime && !isBlend)
  165.                 {
  166.                         totalTime += lastDuration;
  167.                 }
  168.                 calcTime = false;
  169.         }
  170.         //--- Ensure that any dangling entries from the previous blend get assigned to last part
  171.         for (uint32 i = numALayers; i < fragmentData.animLayers.size(); i++)
  172.         {
  173.                 const uint32 oldLength = fragmentData.animLayers[i].size();
  174.                 const bool hadEntry = !fragmentData.animLayers[i].empty();
  175.  
  176.                 if (hadEntry)
  177.                 {
  178.                         //--- Should we merge over the existing final blend or append to it?
  179.                         SAnimClip& animClip = fragmentData.animLayers[i][oldLength - 1];
  180.                         if ((animClip.blend.exitTime >= startTime) || animClip.blend.terminal)
  181.                         {
  182.                                 animClip.part = partID;
  183.                         }
  184.                         else
  185.                         {
  186.                                 SAnimClip newClip;
  187.                                 newClip.blend.exitTime = startTime;
  188.                                 newClip.blendPart = animClip.part;
  189.                                 newClip.part = partID;
  190.                                 fragmentData.animLayers[i].push_back(newClip);
  191.                         }
  192.                 }
  193.         }
  194.  
  195.         for (uint32 i = 0; i < numPLayers; i++)
  196.         {
  197.                 const uint32 oldLength = fragmentData.procLayers[i].size();
  198.                 const uint32 fragLength = fragment.m_procLayers[i].size();
  199.                 const bool hadEntry = (oldLength > 0);
  200.                 const bool hasNewEntry = (fragLength > 0);
  201.                 int startIdx = oldLength;
  202.  
  203.                 bool shouldOverride = false;
  204.                 if (hadEntry && hasNewEntry)
  205.                 {
  206.                         //--- Should we merge over the existing final blend or append to it?
  207.                         const SAnimBlend& prevBlend = fragmentData.procLayers[i][oldLength - 1].blend;
  208.                         shouldOverride = (prevBlend.exitTime >= startTime) || prevBlend.terminal;
  209.                         if (shouldOverride)
  210.                         {
  211.                                 startIdx = max(startIdx - 1, 0);
  212.                         }
  213.                 }
  214.  
  215.                 uint32 installProcLength = isBlend ? max(fragLength, 1u) : fragLength;
  216.  
  217.                 fragmentData.procLayers[i].resize(startIdx + installProcLength);
  218.  
  219.                 float procTotalTime = 0.0f;
  220.                 for (uint32 k = 0; k < installProcLength; k++)
  221.                 {
  222.                         const bool firstClip = (k == 0);
  223.                         const SProceduralEntry* sourceClip = (k < fragLength) ? &fragment.m_procLayers[i][k] : &nullProc;
  224.                         SProceduralEntry& procClip = fragmentData.procLayers[i][startIdx + k];
  225.  
  226.                         procClip.typeNameHash = sourceClip->typeNameHash;
  227.                         procClip.pProceduralParams = sourceClip->pProceduralParams;
  228.                         procClip.part = partID;
  229.                         if (shouldOverride && firstClip)
  230.                         {
  231.                                 if (isBlend)
  232.                                 {
  233.                                         float oldExitTime = procClip.blend.exitTime;
  234.                                         procClip.blend = sourceClip->blend;
  235.                                         procClip.blend.exitTime = oldExitTime;
  236.                                         procClip.blendPart = partID;
  237.                                 }
  238.                         }
  239.                         else
  240.                         {
  241.                                 int blendPart = partID;
  242.                                 procClip.blend = sourceClip->blend;
  243.  
  244.                                 if (firstClip)
  245.                                 {
  246.                                         procClip.blend.exitTime = max(procClip.blend.exitTime, 0.0f);
  247.                                         procClip.blend.exitTime += startTime;
  248.  
  249.                                         if (!isBlend)
  250.                                         {
  251.                                                 blendPart = procClip.blendPart;
  252.                                         }
  253.                                 }
  254.                                 procClip.blendPart = blendPart;
  255.                         }
  256.  
  257.                         if (calcTime)
  258.                         {
  259.                                 totalTime += procClip.blend.exitTime;
  260.                         }
  261.  
  262.                         if (!isBlend)
  263.                         {
  264.                                 float previousStartTime = procTotalTime;
  265.                                 procTotalTime += procClip.blend.exitTime;
  266.                                 float layerStartTime = procTotalTime;
  267.  
  268.                                 if (startOffset > layerStartTime)
  269.                                 {
  270.                                         procClip.blend.exitTime = 0.0f;
  271.                                 }
  272.                                 else if (startOffset > previousStartTime)
  273.                                 {
  274.                                         procClip.blend.exitTime -= startOffset - previousStartTime;
  275.                                         procClip.blend.exitTime = max(0.0f, procClip.blend.exitTime);
  276.                                 }
  277.                         }
  278.                 }
  279.                 calcTime = false;
  280.         }
  281.         //--- Ensure that any dangling entries from the previous blend get assigned to last part
  282.         for (uint32 i = numPLayers; i < fragmentData.procLayers.size(); i++)
  283.         {
  284.                 const uint32 oldLength = fragmentData.procLayers[i].size();
  285.                 const bool hadEntry = !fragmentData.procLayers[i].empty();
  286.  
  287.                 if (hadEntry)
  288.                 {
  289.                         //--- Should we merge over the existing final blend or append to it?
  290.                         SProceduralEntry& procClip = fragmentData.procLayers[i][oldLength - 1];
  291.                         if ((procClip.blend.exitTime >= startTime) || procClip.blend.terminal)
  292.                         {
  293.                                 procClip.part = partID;
  294.                         }
  295.                         else
  296.                         {
  297.                                 SProceduralEntry newEntry;
  298.                                 newEntry.blend.exitTime = startTime;
  299.                                 newEntry.blendPart = procClip.part;
  300.                                 newEntry.part = partID;
  301.                                 fragmentData.procLayers[i].push_back(newEntry);
  302.                         }
  303.                 }
  304.         }
  305.         return totalTime - startTime;
  306. }
  307.  
  308. float AppendBlend(SFragmentData& outFragmentData, const SBlendQueryResult& blend, const IAnimationSet* inAnimSet, uint8 partID, float& timeOffset, float& timeTally, uint32& retFlags)
  309. {
  310.         const bool isExitTransition = blend.pFragmentBlend->IsExitTransition();
  311.         const float fragmentTime = AppendLayers(outFragmentData, *blend.pFragmentBlend->pFragment, partID, inAnimSet, timeTally, 0.0f, true, outFragmentData.isOneShot);
  312.         timeOffset = blend.pFragmentBlend->enterTime;
  313.         timeTally += fragmentTime;
  314.         retFlags |= (isExitTransition ? eSF_TransitionOutro : eSF_Transition);
  315.         outFragmentData.transitionType[partID] = (isExitTransition ? eCT_TransitionOutro : eCT_Transition);
  316.         outFragmentData.duration[partID] += fragmentTime;
  317.  
  318.         return fragmentTime;
  319. }
  320.  
  321. uint32 CAnimationDatabase::Query(SFragmentData& outFragmentData, const SBlendQuery& inBlendQuery, uint32 inOptionIdx, const IAnimationSet* inAnimSet, SFragmentSelection* outFragSelection) const
  322. {
  323.         uint32 retFlags = 0;
  324.  
  325.         SBlendQueryResult blend1, blend2;
  326.         if (!inBlendQuery.IsFlagSet(SBlendQuery::noTransitions))
  327.         {
  328.                 FindBestBlends(inBlendQuery, blend1, blend2);
  329.         }
  330.         const CFragment* fragment = NULL;
  331.  
  332.         if (inBlendQuery.IsFlagSet(SBlendQuery::toInstalled))
  333.         {
  334.                 SFragmentQuery fragQuery;
  335.                 fragQuery.fragID = inBlendQuery.fragmentTo;
  336.                 fragQuery.requiredTags = inBlendQuery.additionalTags;
  337.                 fragQuery.tagState = inBlendQuery.tagStateTo;
  338.                 fragQuery.optionIdx = inOptionIdx;
  339.  
  340.                 fragment = GetBestEntry(fragQuery, outFragSelection);
  341.         }
  342.  
  343.         outFragmentData.animLayers.resize(0);
  344.         outFragmentData.procLayers.resize(0);
  345.         outFragmentData.isOneShot = true;
  346.  
  347.         for (uint32 i = 0; i < SFragmentData::PART_TOTAL; i++)
  348.         {
  349.                 outFragmentData.duration[i] = 0.0f;
  350.                 outFragmentData.transitionType[i] = eCT_Normal;
  351.         }
  352.  
  353.         float timeTally = 0.0f;
  354.         float timeOffset = 0.0f;
  355.         EClipType prevClipType = eCT_Normal;
  356.         int clipIdx = 0;
  357.         if (blend1.pFragmentBlend)
  358.         {
  359.                 AppendBlend(outFragmentData, blend1, inAnimSet, clipIdx, timeOffset, timeTally, retFlags);
  360.                 clipIdx++;
  361.         }
  362.         if (blend2.pFragmentBlend)
  363.         {
  364.                 AppendBlend(outFragmentData, blend2, inAnimSet, clipIdx, timeOffset, timeTally, retFlags);
  365.                 clipIdx++;
  366.         }
  367.         if (fragment)
  368.         {
  369.                 outFragmentData.blendOutDuration = fragment->m_blendOutDuration;
  370.                 outFragmentData.duration[clipIdx] = AppendLayers(outFragmentData, *fragment, clipIdx, inAnimSet, timeTally, timeOffset, false, outFragmentData.isOneShot);
  371.                 outFragmentData.transitionType[clipIdx] = eCT_Normal;
  372.                 retFlags |= eSF_Fragment;
  373.         }
  374.  
  375.         return retFlags;
  376. }
  377.  
  378. bool CAnimationDatabase::ValidateSet(const TFragmentTagSetList& tagSetList)
  379. {
  380.         uint32 totalAnimClips = 0;
  381.         uint32 totalProcClips = 0;
  382.         const uint32 numFragmentTypes = m_fragmentList.size();
  383.         for (uint32 i = 0; i < numFragmentTypes; i++)
  384.         {
  385.                 const TFragmentOptionList& optionList = tagSetList.m_values[i];
  386.                 uint32 numOptions = optionList.size();
  387.                 for (uint32 o = 0; o < numOptions; o++)
  388.                 {
  389.                         uint32 numAnimLayers = optionList[o].fragment->m_animLayers.size();
  390.                         uint32 numProcLayers = optionList[o].fragment->m_procLayers.size();
  391.  
  392.                         for (uint32 l = 0; l < numAnimLayers; l++)
  393.                         {
  394.                                 totalAnimClips += optionList[o].fragment->m_animLayers[l].size();
  395.                         }
  396.  
  397.                         for (uint32 l = 0; l < numProcLayers; l++)
  398.                         {
  399.                                 totalProcClips += optionList[o].fragment->m_procLayers[l].size();
  400.                         }
  401.                 }
  402.         }
  403.  
  404.         return true;
  405. }
  406.  
  407. void CAnimationDatabase::SetEntry(FragmentID fragmentID, const SFragTagState& tags, uint32 optionIdx, const CFragment& fragment)
  408. {
  409.         const uint32 numFragmentTypes = m_fragmentList.size();
  410.         if (fragmentID < numFragmentTypes)
  411.         {
  412.                 SFragmentEntry& fragmentEntry = *m_fragmentList[fragmentID];
  413.                 TFragmentOptionList* pOptionList = fragmentEntry.tagSetList.Find(tags);
  414.                 if (pOptionList)
  415.                 {
  416.                         CRY_ASSERT(optionIdx < (uint32)pOptionList->size());
  417.                         if (optionIdx < (uint32)pOptionList->size())
  418.                         {
  419.                                 SFragmentOption& fragOption = (*pOptionList)[optionIdx];
  420.                                 *fragOption.fragment = fragment;
  421.                         }
  422.  
  423.                         return;
  424.                 }
  425.  
  426.                 //--- New fragment
  427.                 AddEntry(fragmentID, tags, fragment);
  428.         }
  429. }
  430.  
  431. bool CAnimationDatabase::DeleteEntry(FragmentID fragmentID, const SFragTagState& tags, uint32 optionIdx)
  432. {
  433.         const uint32 numFragmentTypes = m_fragmentList.size();
  434.         if (fragmentID < numFragmentTypes)
  435.         {
  436.                 SFragmentEntry& fragmentEntry = *m_fragmentList[fragmentID];
  437.  
  438.                 int idx = fragmentEntry.tagSetList.FindIdx(tags);
  439.  
  440.                 if (idx < 0)
  441.                 {
  442.                         CryWarning(VALIDATOR_MODULE_ANIMATION, VALIDATOR_WARNING, "[AnimDatabase:DeleteEntry] Invalid fragment tags: %d passed to %s", fragmentID, m_filename.c_str());
  443.                         return false;
  444.                 }
  445.                 else if (optionIdx == OPTION_IDX_INVALID)
  446.                 {
  447.                         fragmentEntry.tagSetList.Erase(idx);
  448.                 }
  449.                 else
  450.                 {
  451.                         TFragmentOptionList& optionList = fragmentEntry.tagSetList.m_values[idx];
  452.                         if (optionIdx < (uint32)optionList.size())
  453.                         {
  454.                                 SFragmentOption& fragOption = optionList[optionIdx];
  455.                                 delete fragOption.fragment;
  456.  
  457.                                 optionList.erase(optionList.begin() + optionIdx);
  458.  
  459.                                 if (optionList.empty())
  460.                                 {
  461.                                         fragmentEntry.tagSetList.Erase(idx);
  462.                                 }
  463.                         }
  464.                         else
  465.                         {
  466.                                 CryWarning(VALIDATOR_MODULE_ANIMATION, VALIDATOR_WARNING, "AnimDatabase: Invalid option index: %u for fragment id: %d passed to %s", optionIdx, fragmentID, m_filename.c_str());
  467.                                 return false;
  468.                         }
  469.                 }
  470.  
  471.                 CompressFragmentID(fragmentID);
  472.  
  473.                 return true;
  474.         }
  475.         else
  476.         {
  477.                 CryWarning(VALIDATOR_MODULE_ANIMATION, VALIDATOR_WARNING, "AnimDatabase: Invalid fragment id: %d passed to %s", fragmentID, m_filename.c_str());
  478.         }
  479.  
  480.         return false;
  481. }
  482.  
  483. uint32 CAnimationDatabase::AddEntry(FragmentID fragmentID, const SFragTagState& tags, const CFragment& fragment)
  484. {
  485.         const uint32 numFragmentTypes = m_fragmentList.size();
  486.         if (fragmentID < numFragmentTypes)
  487.         {
  488.                 CFragment* fragmentPtr = new CFragment(fragment);
  489.  
  490.                 SFragmentEntry& fragmentEntry = *m_fragmentList[fragmentID];
  491.                 TFragmentOptionList* pOptionList = fragmentEntry.tagSetList.Find(tags);
  492.                 bool addNew = (pOptionList == NULL);
  493.                 if (addNew)
  494.                 {
  495.                         pOptionList = &fragmentEntry.tagSetList.Insert(tags, TFragmentOptionList());
  496.                 }
  497.  
  498.                 pOptionList->push_back(SFragmentOption(fragmentPtr));
  499.                 const uint32 newOption = pOptionList->size() - 1;
  500.  
  501.                 if (m_autoSort)
  502.                 {
  503.                         if (addNew)
  504.                         {
  505.                                 //--- Re-sort based on priority
  506.                                 fragmentEntry.tagSetList.Sort(*m_pTagDef, m_pFragDef->GetSubTagDefinition(fragmentID));
  507.                         }
  508.  
  509.                         CompressFragmentID(fragmentID);
  510.                 }
  511.  
  512.                 return newOption;
  513.         }
  514.  
  515.         return 0;
  516. }
  517.  
  518. void CAnimationDatabase::Sort()
  519. {
  520.         const uint32 numFragmentTypes = m_fragmentList.size();
  521.         for (uint32 i = 0; i < numFragmentTypes; i++)
  522.         {
  523.                 m_fragmentList[i]->tagSetList.Sort(*m_pTagDef, m_pFragDef->GetSubTagDefinition(i));
  524.         }
  525.  
  526.         for (TFragmentBlendDatabase::iterator iter = m_fragmentBlendDB.begin(); iter != m_fragmentBlendDB.end(); ++iter)
  527.         {
  528.                 FragmentID fragmentIDFrom = iter->first.fragFrom;
  529.                 FragmentID fragmentIDTo = iter->first.fragTo;
  530.  
  531.                 const CTagDefinition* fragFromDef = (fragmentIDFrom != FRAGMENT_ID_INVALID) ? m_pFragDef->GetSubTagDefinition(fragmentIDFrom) : NULL;
  532.                 const CTagDefinition* fragToDef = (fragmentIDTo != FRAGMENT_ID_INVALID) ? m_pFragDef->GetSubTagDefinition(fragmentIDTo) : NULL;
  533.                 SCompareBlendVariantFunctor comparisonFunctor(*m_pTagDef, fragFromDef, fragToDef);
  534.                 std::stable_sort(iter->second.variantList.begin(), iter->second.variantList.end(), comparisonFunctor);
  535.         }
  536.  
  537.         Compress();
  538. }
  539.  
  540. void CAnimationDatabase::CompressFragmentID(FragmentID fragID)
  541. {
  542.         CAnimationDatabase::SFragmentEntry* pEntry = m_fragmentList[fragID];
  543.  
  544.         if (pEntry)
  545.         {
  546.                 SAFE_DELETE(pEntry->compiledList);
  547.                 const uint32 numUsed = pEntry->tagSetList.Size();
  548.                 if (numUsed > 0)
  549.                 {
  550.                         const CTagDefinition* pFragTagDef = m_pFragDef->GetSubTagDefinition(fragID);
  551.                         pEntry->compiledList = pEntry->tagSetList.Compress(*m_pTagDef, pFragTagDef);
  552.                 }
  553.         }
  554. }
  555.  
  556. void CAnimationDatabase::Compress()
  557. {
  558.         const uint32 numFragments = m_pFragDef->GetNum();
  559.  
  560.         SFragTagState usedTags(TAG_STATE_EMPTY, TAG_STATE_EMPTY);
  561. #if 0
  562.         uint32 totalMem = 0;
  563.         uint32 totalNewMem = 0;
  564.         uint32 totalEntries = 0;
  565. #endif //0
  566.         for (uint32 i = 0; i < numFragments; i++)
  567.         {
  568.                 CAnimationDatabase::SFragmentEntry* pEntry = m_fragmentList[i];
  569.  
  570.                 SAFE_DELETE(pEntry->compiledList);
  571.  
  572.                 const uint32 numUsed = pEntry->tagSetList.Size();
  573.                 if (numUsed > 0)
  574.                 {
  575.                         const CTagDefinition* pFragTagDef = m_pFragDef->GetSubTagDefinition(i);
  576.                         pEntry->compiledList = pEntry->tagSetList.Compress(*m_pTagDef, pFragTagDef);
  577.  
  578. #if 0
  579.                         uint32 cost = numUsed * 8 * 2;
  580.                         uint32 minmem = pEntry->compiledList->GetKeySize();
  581.                         uint32 newCost = numUsed * minmem;
  582.  
  583.                         totalMem += cost;
  584.                         totalNewMem += newCost;
  585.                         totalEntries += numUsed;
  586. #endif //0
  587.                 }
  588.         }
  589.  
  590. #if 0
  591.         {
  592.                 //--- Test performance
  593.                 LARGE_INTEGER updateStart, updateEnd;
  594.                 updateStart.QuadPart = 0;
  595.                 updateEnd.QuadPart = 0;
  596.  
  597.                 const uint32 numIts = 100;
  598.                 SFragTagState fragTagState;
  599.                 uint32 hash = 0;
  600.  
  601.                 QueryPerformanceCounter(&updateStart);
  602.  
  603.                 for (uint32 i = 0; i < numIts; i++)
  604.                 {
  605.                         for (uint32 f = 0; f < numFragments; f++)
  606.                         {
  607.                                 const CAnimationDatabase::SFragmentEntry& fragEntry = *m_fragmentList[f];
  608.                                 const CTagDefinition* fragTagDef = m_pFragDef->GetSubTagDefinition(f);
  609.                                 const CAnimationDatabase::TFragmentOptionList* pOptionList = fragEntry.tagSetList.GetBestMatch(fragTagState, m_pTagDef, fragTagDef);
  610.                                 if (pOptionList)
  611.                                 {
  612.                                         hash += pOptionList->size();
  613.                                 }
  614.                         }
  615.                 }
  616.                 QueryPerformanceCounter(&updateEnd);
  617.                 uint32 ticks = (uint32)(updateEnd.QuadPart - updateStart.QuadPart);
  618.                 CryLogAlways("Database %s Fragments: %d Time: %d Hash: %d", GetFilename(), numFragments, ticks, hash);
  619.  
  620.                 CryLogAlways("Compressing %s Num FragIDs: %d Num Frags: %d old cost: %d new cost: %d saving: %d", GetFilename(), numFragments, totalEntries, totalMem, totalNewMem, totalMem - totalNewMem);
  621.  
  622.                 //--- Validation pass
  623.                 for (uint32 f = 0; f < numFragments; f++)
  624.                 {
  625.                         const CAnimationDatabase::SFragmentEntry& fragEntry = *m_fragmentList[f];
  626.                         const CTagDefinition* fragTagDef = m_pFragDef->GetSubTagDefinition(f);
  627.                         const CAnimationDatabase::TFragmentOptionList* pOptionList = fragEntry.tagSetList.GetBestMatch(fragTagState, m_pTagDef, fragTagDef);
  628.                         const CAnimationDatabase::TFragmentOptionList* pOptionListNew = NULL;
  629.  
  630.                         if (fragEntry.compiledList)
  631.                         {
  632.                                 pOptionListNew = fragEntry.compiledList->GetBestMatch(fragTagState);
  633.                         }
  634.  
  635.                         if (pOptionListNew && pOptionList)
  636.                         {
  637.                                 CRY_ASSERT(pOptionList->size() == pOptionListNew->size());
  638.                         }
  639.                         else
  640.                         {
  641.                                 CRY_ASSERT(pOptionList == pOptionListNew);
  642.                         }
  643.                 }
  644.         }
  645. #endif //0
  646.  
  647.         if (!gEnv->IsEditor() && !s_mnAllowEditableDatabasesInPureGame)
  648.         {
  649.                 //--- Clear the existing ones
  650.                 for (uint32 f = 0; f < numFragments; f++)
  651.                 {
  652.                         CAnimationDatabase::SFragmentEntry& fragEntry = *m_fragmentList[f];
  653.  
  654.                         fragEntry.tagSetList.Resize(0);
  655.                 }
  656.         }
  657. }
  658.  
  659. /*
  660.    bool ValidateBlend(const IAnimationSet *animSet, const SAnimBlend &animBlend, AnimID anim1, const char *animName1, AnimID anim2, const char *animName2, const TagState &tags, MannErrorCallback errorCallback, void *errorCallbackContext)
  661.    {
  662.    if (!animBlend.transition.animRef.IsEmpty())
  663.    {
  664.     int animID = animSet->GetAnimIDByCRC(animBlend.transition.animRef.crc);
  665.     if (animID == -1)
  666.     {
  667.       if (errorCallback)
  668.       {
  669.         //--- Missing animation
  670.         SMannequinErrorReport mannErrorReport;
  671.         mannErrorReport.errorType = SMannequinErrorReport::Blend;
  672.         cry_sprintf(mannErrorReport.error, "Animation not found: %s in blend from %s to %s", animBlend.transition.animRef.GetAnimName(), animName1, animName2);
  673.         mannErrorReport.animFrom = anim1;
  674.         mannErrorReport.animTo   = anim2;
  675.         mannErrorReport.tags             = tags;
  676.  
  677.         (*errorCallback)(mannErrorReport, errorCallbackContext);
  678.       }
  679.       CryLog("Animation not found: %s in blend from %s to %s", animBlend.transition.animRef.GetAnimName(), animName1, animName2);
  680.       return false;
  681.     }
  682.    }
  683.    return true;
  684.    }
  685.  */
  686.  
  687. CAnimationDatabase::~CAnimationDatabase()
  688. {
  689.         const uint32 numFragments = m_fragmentList.size();
  690.         for (uint32 i = 0; i < numFragments; i++)
  691.         {
  692.                 SFragmentEntry& entry = *m_fragmentList[i];
  693.  
  694.                 if (entry.compiledList)
  695.                 {
  696.                         const uint32 numTagVars = entry.compiledList->Size();
  697.                         for (uint32 t = 0; t < numTagVars; t++)
  698.                         {
  699.                                 TFragmentOptionList& optionList = entry.compiledList->m_values[t];
  700.                                 for (TFragmentOptionList::iterator optIt = optionList.begin(), optItEnd = optionList.end(); optIt != optItEnd; ++optIt)
  701.                                 {
  702.                                         SFragmentOption& opt = *optIt;
  703.                                         delete opt.fragment;
  704.                                 }
  705.                         }
  706.  
  707.                         delete entry.compiledList;
  708.                 }
  709.  
  710.                 delete &entry;
  711.         }
  712.  
  713.         for (TFragmentBlendDatabase::iterator blDbIt = m_fragmentBlendDB.begin(), blDbItEnd = m_fragmentBlendDB.end(); blDbIt != blDbItEnd; ++blDbIt)
  714.         {
  715.                 SFragmentBlendEntry& entry = blDbIt->second;
  716.                 for (TFragmentVariantList::iterator vrIt = entry.variantList.begin(), vrItEnd = entry.variantList.end(); vrIt != vrItEnd; ++vrIt)
  717.                 {
  718.                         SFragmentBlendVariant& variant = *vrIt;
  719.                         for (TFragmentBlendList::iterator fragIt = variant.blendList.begin(), fragItEnd = variant.blendList.end(); fragIt != fragItEnd; ++fragIt)
  720.                         {
  721.                                 delete fragIt->pFragment;
  722.                         }
  723.                 }
  724.         }
  725. }
  726.  
  727. bool CAnimationDatabase::ValidateFragment(const CFragment* pFragment, const IAnimationSet* animSet, SMannequinErrorReport& errorReport, MannErrorCallback errorCallback, void* errorCallbackContext) const
  728. {
  729.         bool noErrors = true;
  730.  
  731.         const uint32 numLayers = pFragment->m_animLayers.size();
  732.         for (uint32 l = 0; l < numLayers; l++)
  733.         {
  734.                 const TAnimClipSequence& animLayer = pFragment->m_animLayers[l];
  735.                 const uint32 numClips = animLayer.size();
  736.                 for (uint32 c = 0; c < numClips; c++)
  737.                 {
  738.                         const SAnimClip& animClip = animLayer[c];
  739.                         if (!animClip.animation.IsEmpty())
  740.                         {
  741.                                 int animID = animSet->GetAnimIDByCRC(animClip.animation.animRef.crc);
  742.                                 if (animID == -1)
  743.                                 {
  744.                                         noErrors = false;
  745.                                         if (errorCallback)
  746.                                         {
  747.                                                 cry_sprintf(errorReport.error, "Animation not found: %s in layer: %u", animClip.animation.animRef.c_str(), l);
  748.  
  749.                                                 (*errorCallback)(errorReport, errorCallbackContext);
  750.                                         }
  751.                                         CryLog("Animation not found: %s in layer: %u", animClip.animation.animRef.c_str(), l);
  752.                                 }
  753.                         }
  754.                 }
  755.         }
  756.  
  757.         return noErrors;
  758. }
  759.  
  760. bool CAnimationDatabase::ValidateAnimations(FragmentID fragID, uint32 tagSetID, uint32 numOptions, const SFragTagState& tagState, const IAnimationSet* animSet, MannErrorCallback errorCallback, void* errorCallbackContext) const
  761. {
  762.         bool noErrors = true;
  763.  
  764.         SMannequinErrorReport mannErrorReport;
  765.         mannErrorReport.errorType = SMannequinErrorReport::Fragment;
  766.         mannErrorReport.fragID = fragID;
  767.         mannErrorReport.tags = tagState;
  768.  
  769.         for (uint32 o = 0; o < numOptions; o++)
  770.         {
  771.                 const CFragment* fragment = GetEntry(fragID, tagSetID, o);
  772.  
  773.                 mannErrorReport.fragOptionID = o;
  774.  
  775.                 noErrors = ValidateFragment(fragment, animSet, mannErrorReport, errorCallback, errorCallbackContext) && noErrors;
  776.         }
  777.  
  778.         return noErrors;
  779. }
  780.  
  781. bool CAnimationDatabase::IsDuplicate(const CFragment* pFragmentA, const CFragment* pFragmentB) const
  782. {
  783.         if (pFragmentA == NULL || pFragmentB == NULL)
  784.         {
  785.                 return false;
  786.         }
  787.  
  788.         const uint32 numAnimLayersA = pFragmentA->m_animLayers.size();
  789.         const uint32 numAnimLayersB = pFragmentB->m_animLayers.size();
  790.  
  791.         const uint32 numProcLayersA = pFragmentA->m_procLayers.size();
  792.         const uint32 numProcLayersB = pFragmentB->m_procLayers.size();
  793.  
  794.         if (numAnimLayersA != numAnimLayersB || numProcLayersA != numProcLayersB)
  795.         {
  796.                 return false;
  797.         }
  798.  
  799.         for (uint32 l = 0; l < numAnimLayersA; l++)
  800.         {
  801.                 const TAnimClipSequence& animLayerA = pFragmentA->m_animLayers[l];
  802.                 const TAnimClipSequence& animLayerB = pFragmentB->m_animLayers[l];
  803.  
  804.                 const uint32 numAnimClipsA = animLayerA.size();
  805.                 const uint32 numAnimClipsB = animLayerB.size();
  806.  
  807.                 if (numAnimClipsA != numAnimClipsB)
  808.                 {
  809.                         return false;
  810.                 }
  811.  
  812.                 for (uint32 c = 0; c < numAnimClipsA; c++)
  813.                 {
  814.                         const SAnimClip& animClipA = animLayerA[c];
  815.                         const SAnimClip& animClipB = animLayerB[c];
  816.  
  817.                         if (!(animClipA == animClipB))
  818.                         {
  819.                                 return false;
  820.                         }
  821.                 }
  822.         }
  823.  
  824.         for (uint32 l = 0; l < numProcLayersA; l++)
  825.         {
  826.                 const TProcClipSequence& procLayerA = pFragmentA->m_procLayers[l];
  827.                 const TProcClipSequence& procLayerB = pFragmentB->m_procLayers[l];
  828.  
  829.                 const uint32 numProcClipsA = procLayerA.size();
  830.                 const uint32 numProcClipsB = procLayerB.size();
  831.  
  832.                 if (numProcClipsA != numProcClipsB)
  833.                 {
  834.                         return false;
  835.                 }
  836.  
  837.                 for (uint32 c = 0; c < numProcClipsA; c++)
  838.                 {
  839.                         const SProceduralEntry& procClipA = procLayerA[c];
  840.                         const SProceduralEntry& procClipB = procLayerB[c];
  841.  
  842.                         if (!(procClipA == procClipB))
  843.                         {
  844.                                 return false;
  845.                         }
  846.                 }
  847.         }
  848.  
  849.         return true;
  850. }
  851.  
  852. bool CAnimationDatabase::Validate(const IAnimationSet* animSet, MannErrorCallback errorCallback, MannErrorCallback warningCallback, void* errorCallbackContext) const
  853. {
  854.         bool noErrors = true;
  855.         const uint32 numFragments = m_fragmentList.size();
  856.         for (uint32 i = 0; i < numFragments; i++)
  857.         {
  858.                 const uint32 numTagSets = GetTotalTagSets(i);
  859.                 for (uint32 k = 0; k < numTagSets; k++)
  860.                 {
  861.                         SFragTagState tags;
  862.                         uint32 numOptions = GetTagSetInfo(i, k, tags);
  863.  
  864.                         if (animSet)
  865.                         {
  866.                                 noErrors = ValidateAnimations(i, k, numOptions, tags, animSet, errorCallback, errorCallbackContext);
  867.                         }
  868.  
  869.                         if (warningCallback)
  870.                         {
  871.                                 for (uint32 m = 0; m < numTagSets; m++)
  872.                                 {
  873.                                         if (k != m)
  874.                                         {
  875.                                                 SFragTagState compareTags;
  876.                                                 uint32 compareNumOptions = GetTagSetInfo(i, m, compareTags);
  877.  
  878.                                                 if (compareNumOptions == numOptions)
  879.                                                 {
  880.                                                         const CTagDefinition* pFragTagDef = m_pFragDef->GetSubTagDefinition(i);
  881.  
  882.                                                         if ((m_pTagDef->Contains(tags.globalTags, compareTags.globalTags))
  883.                                                             && ((pFragTagDef == NULL) || pFragTagDef->Contains(tags.fragmentTags, compareTags.fragmentTags)))
  884.                                                         {
  885.                                                                 //fragment uses a parent set of tags compare for unnecessary duplication
  886.  
  887.                                                                 bool allOptionsAreDuplicated = true;
  888.                                                                 for (uint32 n = 0; n < compareNumOptions && allOptionsAreDuplicated; n++)
  889.                                                                 {
  890.                                                                         const CFragment* childFragment = GetEntry(i, k, n);
  891.  
  892.                                                                         bool foundDuplicateOption = false;
  893.                                                                         for (uint32 p = 0; (p < compareNumOptions) && !foundDuplicateOption; p++)
  894.                                                                         {
  895.                                                                                 const CFragment* parentFragment = GetEntry(i, m, p);
  896.  
  897.                                                                                 foundDuplicateOption = IsDuplicate(childFragment, parentFragment);
  898.                                                                         }
  899.  
  900.                                                                         if (!foundDuplicateOption)
  901.                                                                         {
  902.                                                                                 allOptionsAreDuplicated = false;
  903.                                                                         }
  904.                                                                 }
  905.  
  906.                                                                 if (allOptionsAreDuplicated)
  907.                                                                 {
  908.                                                                         SMannequinErrorReport mannErrorReport;
  909.                                                                         mannErrorReport.errorType = SMannequinErrorReport::Fragment;
  910.                                                                         mannErrorReport.fragID = i;
  911.                                                                         mannErrorReport.fragOptionID = OPTION_IDX_INVALID;
  912.  
  913.                                                                         CryStackStringT<char, 1024> sTagList;
  914.                                                                         CryStackStringT<char, 1024> sFragTagList;
  915.  
  916.                                                                         m_pTagDef->FlagsToTagList(compareTags.globalTags, sTagList);
  917.                                                                         if (pFragTagDef)
  918.                                                                         {
  919.                                                                                 pFragTagDef->FlagsToTagList(compareTags.fragmentTags, sFragTagList);
  920.                                                                         }
  921.  
  922.                                                                         cry_sprintf(mannErrorReport.error, "Fragment is duplicate of a parent fragment! Parent Tags - Global: '%s' Fragment: '%s'", sTagList.c_str(), sFragTagList.c_str());
  923.                                                                         mannErrorReport.tags = tags;
  924.  
  925.                                                                         (*warningCallback)(mannErrorReport, errorCallbackContext);
  926.  
  927.                                                                         noErrors = false;
  928.                                                                         break;
  929.                                                                 }
  930.                                                         }
  931.                                                 }
  932.                                         }
  933.                                 }
  934.                         }
  935.                 }
  936.         }
  937.  
  938.         if (animSet)
  939.         {
  940.                 //--- Validate blends
  941.                 SMannequinErrorReport mannErrorReport;
  942.                 mannErrorReport.errorType = SMannequinErrorReport::Blend;
  943.                 for (TFragmentBlendDatabase::const_iterator iter = m_fragmentBlendDB.begin(); iter != m_fragmentBlendDB.end(); ++iter)
  944.                 {
  945.                         const TFragmentVariantList& variantList = iter->second.variantList;
  946.  
  947.                         mannErrorReport.fragID = iter->first.fragFrom;
  948.                         mannErrorReport.fragIDTo = iter->first.fragTo;
  949.  
  950.                         const uint32 numVariants = variantList.size();
  951.                         for (uint32 i = 0; i < numVariants; i++)
  952.                         {
  953.                                 mannErrorReport.tags = variantList[i].tagsFrom;
  954.                                 mannErrorReport.tagsTo = variantList[i].tagsTo;
  955.                                 const TFragmentBlendList& blendList = variantList[i].blendList;
  956.                                 const uint32 numBlends = blendList.size();
  957.                                 for (uint32 b = 0; b < numBlends; b++)
  958.                                 {
  959.                                         mannErrorReport.fragOptionID = b;
  960.                                         ValidateFragment(blendList[b].pFragment, animSet, mannErrorReport, errorCallback, errorCallbackContext);
  961.                                 }
  962.                         }
  963.                 }
  964.         }
  965.  
  966.         return noErrors;
  967. }
  968.  
  969. void CAnimationDatabase::EnumerateFragmentAnimAssets(const CFragment* pFragment, const IAnimationSet* animSet, SAnimAssetReport& assetReport, MannAssetCallback assetCallback, void* callbackContext) const
  970. {
  971.         const uint32 numLayers = pFragment->m_animLayers.size();
  972.         for (uint32 l = 0; l < numLayers; l++)
  973.         {
  974.                 const TAnimClipSequence& animLayer = pFragment->m_animLayers[l];
  975.                 const uint32 numClips = animLayer.size();
  976.                 for (uint32 c = 0; c < numClips; c++)
  977.                 {
  978.                         const SAnimClip& animClip = animLayer[c];
  979.                         if (!animClip.animation.IsEmpty())
  980.                         {
  981.                                 assetReport.pAnimName = animClip.animation.animRef.c_str();
  982.                                 assetReport.pAnimPath = NULL;
  983.                                 assetReport.animID = -1;
  984.                                 if (animSet)
  985.                                 {
  986.                                         int animID = animSet->GetAnimIDByCRC(animClip.animation.animRef.crc);
  987.                                         assetReport.animID = animID;
  988.                                         assetReport.pAnimPath = animSet->GetFilePathByID(animID);
  989.                                 }
  990.  
  991.                                 (*assetCallback)(assetReport, callbackContext);
  992.                         }
  993.                 }
  994.         }
  995. }
  996.  
  997. void CAnimationDatabase::EnumerateAnimAssets(const IAnimationSet* animSet, MannAssetCallback assetCallback, void* callbackContext) const
  998. {
  999.         SAnimAssetReport mannAssetReport;
  1000.  
  1001.         const uint32 numFragments = m_fragmentList.size();
  1002.         for (uint32 fragID = 0; fragID < numFragments; fragID++)
  1003.         {
  1004.                 const uint32 numTagSets = GetTotalTagSets(fragID);
  1005.                 for (uint32 k = 0; k < numTagSets; k++)
  1006.                 {
  1007.                         SFragTagState tags;
  1008.                         uint32 numOptions = GetTagSetInfo(fragID, k, tags);
  1009.  
  1010.                         mannAssetReport.fragID = fragID;
  1011.                         mannAssetReport.tags = tags;
  1012.  
  1013.                         for (uint32 o = 0; o < numOptions; o++)
  1014.                         {
  1015.                                 const CFragment* fragment = GetEntry(fragID, k, o);
  1016.  
  1017.                                 mannAssetReport.fragOptionID = o;
  1018.  
  1019.                                 EnumerateFragmentAnimAssets(fragment, animSet, mannAssetReport, assetCallback, callbackContext);
  1020.                         }
  1021.                 }
  1022.         }
  1023.  
  1024.         //--- Enumerate blends
  1025.         for (TFragmentBlendDatabase::const_iterator iter = m_fragmentBlendDB.begin(); iter != m_fragmentBlendDB.end(); ++iter)
  1026.         {
  1027.                 const TFragmentVariantList& variantList = iter->second.variantList;
  1028.  
  1029.                 mannAssetReport.fragID = iter->first.fragFrom;
  1030.                 mannAssetReport.fragIDTo = iter->first.fragTo;
  1031.  
  1032.                 const uint32 numVariants = variantList.size();
  1033.                 for (uint32 i = 0; i < numVariants; i++)
  1034.                 {
  1035.                         mannAssetReport.tags = variantList[i].tagsFrom;
  1036.                         mannAssetReport.tagsTo = variantList[i].tagsTo;
  1037.                         const TFragmentBlendList& blendList = variantList[i].blendList;
  1038.                         const uint32 numBlends = blendList.size();
  1039.                         for (uint32 b = 0; b < numBlends; b++)
  1040.                         {
  1041.                                 mannAssetReport.fragOptionID = b;
  1042.                                 EnumerateFragmentAnimAssets(blendList[b].pFragment, animSet, mannAssetReport, assetCallback, callbackContext);
  1043.                         }
  1044.                 }
  1045.         }
  1046.  
  1047. }
  1048.  
  1049. bool CAnimationDatabase::SCompareBlendVariantFunctor::operator()(const CAnimationDatabase::SFragmentBlendVariant& lhs, const CAnimationDatabase::SFragmentBlendVariant& rhs)
  1050. {
  1051.         uint32 bits1 = m_tagDefs.RateTagState(lhs.tagsFrom.globalTags) + (m_pFragTagDefsFrom ? m_pFragTagDefsFrom->RateTagState(lhs.tagsFrom.fragmentTags) : 0);
  1052.         uint32 bits2 = m_tagDefs.RateTagState(rhs.tagsFrom.globalTags) + (m_pFragTagDefsFrom ? m_pFragTagDefsFrom->RateTagState(rhs.tagsFrom.fragmentTags) : 0);
  1053.         bits1 += m_tagDefs.RateTagState(lhs.tagsTo.globalTags) + (m_pFragTagDefsTo ? m_pFragTagDefsTo->RateTagState(lhs.tagsTo.fragmentTags) : 0);
  1054.         bits2 += m_tagDefs.RateTagState(rhs.tagsTo.globalTags) + (m_pFragTagDefsTo ? m_pFragTagDefsTo->RateTagState(rhs.tagsTo.fragmentTags) : 0);
  1055.  
  1056.         return (bits1 > bits2);
  1057. }
  1058.  
  1059. SFragmentBlendUid CAnimationDatabase::AddBlendInternal(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagsFrom, const SFragTagState& tagsTo, const SFragmentBlend& fragBlend)
  1060. {
  1061.         const SFragmentBlendID blendID = { fragmentIDFrom, fragmentIDTo };
  1062.  
  1063.         TFragmentBlendDatabase::iterator iter = m_fragmentBlendDB.find(blendID);
  1064.         if (iter == m_fragmentBlendDB.end())
  1065.         {
  1066.                 std::pair<TFragmentBlendDatabase::iterator, bool> insert = m_fragmentBlendDB.insert(std::make_pair(blendID, SFragmentBlendEntry()));
  1067.                 iter = insert.first;
  1068.         }
  1069.  
  1070.         SFragmentBlendEntry& blendEntry = iter->second;
  1071.  
  1072.         const uint32 numVariants = blendEntry.variantList.size();
  1073.         SFragmentBlendVariant* variant = NULL;
  1074.         for (uint32 i = 0; i < numVariants; i++)
  1075.         {
  1076.                 SFragmentBlendVariant& variantIt = blendEntry.variantList[i];
  1077.                 if ((variantIt.tagsFrom == tagsFrom) && (variantIt.tagsTo == tagsTo))
  1078.                 {
  1079.                         variant = &variantIt;
  1080.                         break;
  1081.                 }
  1082.         }
  1083.  
  1084.         bool addedVariant = false;
  1085.         if (!variant)
  1086.         {
  1087.                 //--- Insert a new variant
  1088.                 blendEntry.variantList.resize(numVariants + 1);
  1089.                 variant = &blendEntry.variantList[numVariants];
  1090.                 variant->tagsFrom = tagsFrom;
  1091.                 variant->tagsTo = tagsTo;
  1092.  
  1093.                 addedVariant = true;
  1094.         }
  1095.  
  1096.         variant->blendList.push_back(fragBlend);
  1097.         std::sort(variant->blendList.begin(), variant->blendList.end());
  1098.  
  1099.         if (addedVariant && m_autoSort)
  1100.         {
  1101.                 //--- Re-sort based on priority
  1102.                 const CTagDefinition* fragFromDef = (fragmentIDFrom != FRAGMENT_ID_INVALID) ? m_pFragDef->GetSubTagDefinition(fragmentIDFrom) : NULL;
  1103.                 const CTagDefinition* fragToDef = (fragmentIDTo != FRAGMENT_ID_INVALID) ? m_pFragDef->GetSubTagDefinition(fragmentIDTo) : NULL;
  1104.                 SCompareBlendVariantFunctor comparisonFunctor(*m_pTagDef, fragFromDef, fragToDef);
  1105.                 std::stable_sort(blendEntry.variantList.begin(), blendEntry.variantList.end(), comparisonFunctor);
  1106.         }
  1107.  
  1108.         return fragBlend.uid;
  1109. }
  1110.  
  1111. SFragmentBlendUid CAnimationDatabase::AddBlend(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo, const SFragmentBlend& fragBlend)
  1112. {
  1113.         CFragment* internalFragment = new CFragment();
  1114.         *internalFragment = *fragBlend.pFragment;
  1115.  
  1116.         SFragmentBlend fragBlendCopy = fragBlend;
  1117.         fragBlendCopy.pFragment = internalFragment;
  1118.  
  1119.         return AddBlendInternal(fragmentIDFrom, fragmentIDTo, tagFrom, tagTo, fragBlendCopy);
  1120. }
  1121.  
  1122. uint32 CAnimationDatabase::GetNumBlends(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo) const
  1123. {
  1124.         const SFragmentBlendVariant* variant = GetVariant(fragmentIDFrom, fragmentIDTo, tagFrom, tagTo);
  1125.  
  1126.         if (variant)
  1127.         {
  1128.                 return variant->blendList.size();
  1129.         }
  1130.  
  1131.         return 0;
  1132. }
  1133.  
  1134. const SFragmentBlend* CAnimationDatabase::GetBlend(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo, uint32 blendNum) const
  1135. {
  1136.         const SFragmentBlendVariant* variant = GetVariant(fragmentIDFrom, fragmentIDTo, tagFrom, tagTo);
  1137.  
  1138.         if (variant && (variant->blendList.size() > blendNum))
  1139.         {
  1140.                 return &variant->blendList[blendNum];
  1141.         }
  1142.  
  1143.         return NULL;
  1144. }
  1145.  
  1146. const SFragmentBlend* CAnimationDatabase::GetBlend(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo, SFragmentBlendUid blendUid) const
  1147. {
  1148.         const SFragmentBlendVariant* variant = GetVariant(fragmentIDFrom, fragmentIDTo, tagFrom, tagTo);
  1149.  
  1150.         return variant ? variant->FindBlend(blendUid) : NULL;
  1151. }
  1152.  
  1153. void CAnimationDatabase::SetBlend(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo, SFragmentBlendUid blendUid, const SFragmentBlend& newFragmentBlend)
  1154. {
  1155.         CAnimationDatabase::SFragmentBlendVariant* variant = GetVariant(fragmentIDFrom, fragmentIDTo, tagFrom, tagTo);
  1156.  
  1157.         if (!variant)
  1158.                 return;
  1159.  
  1160.         SFragmentBlend* pFragmentBlend = variant->FindBlend(blendUid);
  1161.         CRY_ASSERT(pFragmentBlend);
  1162.  
  1163.         const bool sortIsNeeded = (pFragmentBlend->selectTime != newFragmentBlend.selectTime);
  1164.  
  1165.         CFragment* pOldFragment = pFragmentBlend->pFragment;
  1166.         *pFragmentBlend = newFragmentBlend;
  1167.         pFragmentBlend->pFragment = new CFragment(*newFragmentBlend.pFragment);
  1168.  
  1169.         delete(pOldFragment);
  1170.  
  1171.         if (sortIsNeeded)
  1172.         {
  1173.                 std::sort(variant->blendList.begin(), variant->blendList.end());
  1174.         }
  1175. }
  1176.  
  1177. void CAnimationDatabase::DeleteBlend(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo, SFragmentBlendUid blendUid)
  1178. {
  1179.         CAnimationDatabase::SFragmentBlendVariant* variant = GetVariant(fragmentIDFrom, fragmentIDTo, tagFrom, tagTo);
  1180.  
  1181.         if (variant)
  1182.         {
  1183.                 const uint32 blendNum = variant->FindBlendIndexForUid(blendUid);
  1184.                 if (blendNum < variant->blendList.size())
  1185.                 {
  1186.                         delete variant->blendList[blendNum].pFragment;
  1187.                         variant->blendList.erase(variant->blendList.begin() + blendNum);
  1188.                 }
  1189.  
  1190.                 if (variant->blendList.empty())
  1191.                 {
  1192.                         //--- Clear out empty variants
  1193.                         const SFragmentBlendID blendID = { fragmentIDFrom, fragmentIDTo };
  1194.                         TFragmentBlendDatabase::iterator iter = m_fragmentBlendDB.find(blendID);
  1195.                         SFragmentBlendEntry& blendEntry = iter->second;
  1196.  
  1197.                         const uint32 numVariants = blendEntry.variantList.size();
  1198.                         for (TFragmentVariantList::iterator _iter = blendEntry.variantList.begin(); _iter != blendEntry.variantList.end(); ++_iter)
  1199.                         {
  1200.                                 SFragmentBlendVariant& variantDel = *_iter;
  1201.  
  1202.                                 if (&variantDel == variant)
  1203.                                 {
  1204.                                         blendEntry.variantList.erase(_iter);
  1205.                                         break;
  1206.                                 }
  1207.                         }
  1208.                 }
  1209.         }
  1210. }
  1211.  
  1212. const char* CAnimationDatabase::FindSubADBFilenameForIDInternal(FragmentID fragmentID, const SSubADB& pSubADB) const
  1213. {
  1214.         // Search FragIDs
  1215.         if (std::find(pSubADB.vFragIDs.begin(), pSubADB.vFragIDs.end(), fragmentID) != pSubADB.vFragIDs.end())
  1216.                 return pSubADB.filename.c_str();
  1217.  
  1218.         // Search subADBs
  1219.         for (TSubADBList::const_iterator itSubADB = pSubADB.subADBs.begin(); itSubADB != pSubADB.subADBs.end(); ++itSubADB)
  1220.         {
  1221.                 const char* fName = FindSubADBFilenameForIDInternal(fragmentID, *itSubADB);
  1222.                 if (fName != 0 && strlen(fName) > 0)
  1223.                         return fName;
  1224.         }
  1225.  
  1226.         // Nothing
  1227.         return NULL;
  1228. }
  1229.  
  1230. const char* CAnimationDatabase::FindSubADBFilenameForID(FragmentID fragmentID) const
  1231. {
  1232.         // Find SubADB with the filename
  1233.         for (TSubADBList::const_iterator itSubADB = m_subADBs.begin(); itSubADB != m_subADBs.end(); ++itSubADB)
  1234.         {
  1235.                 const char* fName = FindSubADBFilenameForIDInternal(fragmentID, *itSubADB);
  1236.                 if (fName != 0 && strlen(fName) > 0)
  1237.                         return fName;
  1238.         }
  1239.  
  1240.         // Return me
  1241.         return m_filename.c_str();
  1242. }
  1243.  
  1244. bool CAnimationDatabase::RemoveSubADBFragmentFilterInternal(FragmentID fragmentID, SSubADB& subADB)
  1245. {
  1246.         bool bRemoved = false;
  1247.  
  1248.         SSubADB::TFragIDList::iterator itFID = std::find(subADB.vFragIDs.begin(), subADB.vFragIDs.end(), fragmentID);
  1249.         if (itFID != subADB.vFragIDs.end())
  1250.         {
  1251.                 subADB.vFragIDs.erase(itFID);
  1252.                 bRemoved = true;
  1253.         }
  1254.  
  1255.         for (TSubADBList::iterator itADB = subADB.subADBs.begin(); itADB != subADB.subADBs.end(); ++itADB)
  1256.                 bRemoved = bRemoved || RemoveSubADBFragmentFilterInternal(fragmentID, *itADB);
  1257.  
  1258.         return bRemoved;
  1259. }
  1260.  
  1261. bool CAnimationDatabase::RemoveSubADBFragmentFilter(FragmentID fragmentID)
  1262. {
  1263.         bool bRemoved = false;
  1264.         for (TSubADBList::iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1265.                 if (RemoveSubADBFragmentFilterInternal(fragmentID, *itADB))
  1266.                         bRemoved = true;
  1267.  
  1268.         return bRemoved;
  1269. }
  1270.  
  1271. const CAnimationDatabase::SSubADB* CAnimationDatabase::FindSubADB(const TSubADBList& subAdbList, const char* szSubADBFilename, bool recursive)
  1272. {
  1273.         CRY_ASSERT(szSubADBFilename);
  1274.  
  1275.         for (TSubADBList::const_iterator cit = subAdbList.begin(); cit != subAdbList.end(); ++cit)
  1276.         {
  1277.                 const SSubADB& subADB = *cit;
  1278.                 if (subADB.IsSubADB(szSubADBFilename))
  1279.                 {
  1280.                         return &subADB;
  1281.                 }
  1282.         }
  1283.  
  1284.         if (recursive)
  1285.         {
  1286.                 for (TSubADBList::const_iterator cit = subAdbList.begin(); cit != subAdbList.end(); ++cit)
  1287.                 {
  1288.                         const SSubADB& subADB = *cit;
  1289.                         const SSubADB* pFoundSubADB = FindSubADB(subADB.subADBs, szSubADBFilename, true);
  1290.                         if (pFoundSubADB)
  1291.                         {
  1292.                                 return pFoundSubADB;
  1293.                         }
  1294.                 }
  1295.         }
  1296.  
  1297.         return NULL;
  1298. }
  1299.  
  1300. CAnimationDatabase::SSubADB* CAnimationDatabase::FindSubADB(const char* szSubADBFilename, bool recursive)
  1301. {
  1302.         return const_cast<SSubADB*>(FindSubADB(m_subADBs, szSubADBFilename, recursive));
  1303. }
  1304.  
  1305. const CAnimationDatabase::SSubADB* CAnimationDatabase::FindSubADB(const char* szSubADBFilename, bool recursive) const
  1306. {
  1307.         return FindSubADB(m_subADBs, szSubADBFilename, recursive);
  1308. }
  1309.  
  1310. bool CAnimationDatabase::AddSubADBFragmentFilterInternal(const string& sADBFileName, FragmentID fragmentID, SSubADB& subADB)
  1311. {
  1312.         if (sADBFileName.compareNoCase(subADB.filename) == 0)
  1313.         {
  1314.                 SSubADB::TFragIDList::iterator itFID = std::find(subADB.vFragIDs.begin(), subADB.vFragIDs.end(), fragmentID);
  1315.                 if (itFID == subADB.vFragIDs.end())
  1316.                         subADB.vFragIDs.push_back(fragmentID);
  1317.                 return true;
  1318.         }
  1319.  
  1320.         for (TSubADBList::iterator itADB = subADB.subADBs.begin(); itADB != subADB.subADBs.end(); ++itADB)
  1321.                 if (AddSubADBFragmentFilterInternal(sADBFileName, fragmentID, *itADB))
  1322.                         return true;
  1323.  
  1324.         return false;
  1325. }
  1326.  
  1327. bool CAnimationDatabase::AddSubADBFragmentFilter(const string& sADBFileName, FragmentID fragmentID)
  1328. {
  1329.         // If the ADB's the root, just return true since it'll be added to the root~!
  1330.         if (sADBFileName.compareNoCase(m_filename) == 0)
  1331.                 return true;
  1332.  
  1333.         for (TSubADBList::iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1334.                 if (AddSubADBFragmentFilterInternal(sADBFileName, fragmentID, *itADB))
  1335.                         return true;
  1336.  
  1337.         // Got here, not found the file, so add it
  1338.         m_subADBs.push_back(SSubADB());
  1339.         SSubADB& newSubADB = m_subADBs.back();
  1340.         newSubADB.tags = TagState(TAG_STATE_EMPTY);
  1341.         newSubADB.comparisonMask = m_pTagDef->GenerateMask(newSubADB.tags);
  1342.         newSubADB.filename = sADBFileName;
  1343.         newSubADB.pTagDef = m_pTagDef;
  1344.         newSubADB.pFragDef = m_pFragDef;
  1345.         newSubADB.knownTags = TAG_STATE_FULL;
  1346.         newSubADB.vFragIDs.push_back(fragmentID);
  1347.         return false;
  1348. }
  1349.  
  1350. void CAnimationDatabase::FillMiniSubADB(SMiniSubADB& outMiniSub, const SSubADB& inSub) const
  1351. {
  1352.         outMiniSub.vSubADBs.push_back(SMiniSubADB());
  1353.         SMiniSubADB& miniSub = outMiniSub.vSubADBs.back();
  1354.         miniSub.tags = inSub.tags;
  1355.         miniSub.filename = inSub.filename;
  1356.         miniSub.pFragDef = inSub.pFragDef;
  1357.  
  1358.         for (SSubADB::TFragIDList::const_iterator itFragID = inSub.vFragIDs.begin(); itFragID != inSub.vFragIDs.end(); ++itFragID)
  1359.         {
  1360.                 miniSub.vFragIDs.push_back(*itFragID);
  1361.         }
  1362.  
  1363.         for (TSubADBList::const_iterator subitADB = inSub.subADBs.begin(); subitADB != inSub.subADBs.end(); ++subitADB)
  1364.         {
  1365.                 FillMiniSubADB(miniSub, *subitADB);
  1366.         }
  1367. }
  1368.  
  1369. void CAnimationDatabase::GetSubADBFragmentFilters(SMiniSubADB::TSubADBArray& outList) const
  1370. {
  1371.         outList.clear();
  1372.         for (TSubADBList::const_iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1373.         {
  1374.                 outList.push_back(SMiniSubADB());
  1375.                 SMiniSubADB& miniSub = outList.back();
  1376.                 miniSub.tags = (*itADB).tags;
  1377.                 miniSub.filename = (*itADB).filename;
  1378.                 miniSub.pFragDef = (*itADB).pFragDef;
  1379.  
  1380.                 for (SSubADB::TFragIDList::const_iterator itFragID = (*itADB).vFragIDs.begin(); itFragID != (*itADB).vFragIDs.end(); ++itFragID)
  1381.                 {
  1382.                         miniSub.vFragIDs.push_back(*itFragID);
  1383.                 }
  1384.  
  1385.                 for (TSubADBList::const_iterator subitADB = (*itADB).subADBs.begin(); subitADB != (*itADB).subADBs.end(); ++subitADB)
  1386.                 {
  1387.                         FillMiniSubADB(miniSub, *subitADB);
  1388.                 }
  1389.         }
  1390. }
  1391.  
  1392. bool CAnimationDatabase::AddSubADBTagFilterInternal(const string& sParentFilename, const string& sADBFileName, const TagState& tag, SSubADB& subADB)
  1393. {
  1394.         const string compSubFilename = subADB.filename.Right(sADBFileName.size());
  1395.         if (compSubFilename.compareNoCase(sADBFileName) == 0)
  1396.         {
  1397.                 subADB.tags = tag;
  1398.                 subADB.comparisonMask = subADB.pTagDef->GenerateMask(subADB.tags);
  1399.                 return true;
  1400.         }
  1401.  
  1402.         // is this the parent we're looking for?
  1403.         const string compFilename = subADB.filename.Right(sParentFilename.size());
  1404.         if (compFilename.compareNoCase(sParentFilename) == 0)
  1405.         {
  1406.                 subADB.subADBs.push_back(SSubADB());
  1407.                 SSubADB& newSubADB = subADB.subADBs.back();
  1408.                 newSubADB.tags = tag;
  1409.                 newSubADB.comparisonMask = subADB.pTagDef->GenerateMask(newSubADB.tags);
  1410.                 newSubADB.filename = sADBFileName;
  1411.                 newSubADB.pTagDef = subADB.pTagDef;
  1412.                 newSubADB.pFragDef = subADB.pFragDef;
  1413.                 newSubADB.knownTags = TAG_STATE_FULL;
  1414.                 newSubADB.vFragIDs.clear();
  1415.                 return true;
  1416.         }
  1417.  
  1418.         for (TSubADBList::iterator itADB = subADB.subADBs.begin(); itADB != subADB.subADBs.end(); ++itADB)
  1419.                 if (AddSubADBTagFilterInternal(sParentFilename, sADBFileName, tag, *itADB))
  1420.                         return true;
  1421.  
  1422.         return false;
  1423. }
  1424.  
  1425. bool CAnimationDatabase::AddSubADBTagFilter(const string& sParentFilename, const string& sADBFileName, const TagState& tag)
  1426. {
  1427.         // If the ADB's the root, just return true since it'll be added to the root~!
  1428.         if (sADBFileName.compareNoCase(m_filename) == 0)
  1429.                 return true;
  1430.  
  1431.         for (TSubADBList::iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1432.                 if (AddSubADBTagFilterInternal(sParentFilename, sADBFileName, tag, *itADB))
  1433.                         return true;
  1434.  
  1435.         // Got here, not found the file, so add it
  1436.         m_subADBs.push_back(SSubADB());
  1437.         SSubADB& newSubADB = m_subADBs.back();
  1438.         newSubADB.tags = tag;
  1439.         newSubADB.comparisonMask = m_pTagDef->GenerateMask(newSubADB.tags);
  1440.         newSubADB.filename = sADBFileName;
  1441.         newSubADB.pTagDef = m_pTagDef;
  1442.         newSubADB.pFragDef = m_pFragDef;
  1443.         newSubADB.knownTags = TAG_STATE_FULL;
  1444.         newSubADB.vFragIDs.clear();
  1445.         return false;
  1446. }
  1447.  
  1448. bool CAnimationDatabase::MoveSubADBFilterInternal(const string& sADBFileName, SSubADB& subADB, const bool bMoveUp)
  1449. {
  1450.         for (TSubADBList::iterator subitADB = subADB.subADBs.begin(); subitADB != subADB.subADBs.end(); ++subitADB)
  1451.         {
  1452.                 const string compFilename = (*subitADB).filename.Right(sADBFileName.size());
  1453.                 if (compFilename.compareNoCase(sADBFileName) == 0)
  1454.                 {
  1455.                         if (bMoveUp)
  1456.                         {
  1457.                                 if (subADB.subADBs.begin() != subitADB)
  1458.                                         std::iter_swap(subitADB, subitADB - 1);
  1459.                         }
  1460.                         else  // move down
  1461.                         {
  1462.                                 if (subADB.subADBs.end() - 1 != subitADB)
  1463.                                         std::iter_swap(subitADB, subitADB + 1);
  1464.                         }
  1465.                         return true;
  1466.                 }
  1467.                 else
  1468.                 {
  1469.                         if (MoveSubADBFilterInternal(sADBFileName, *subitADB, bMoveUp))
  1470.                                 return true;
  1471.                 }
  1472.         }
  1473.         return false;
  1474. }
  1475.  
  1476. bool CAnimationDatabase::MoveSubADBFilter(const string& sADBFileName, const bool bMoveUp)
  1477. {
  1478.         for (TSubADBList::iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1479.         {
  1480.                 const string compFilename = (*itADB).filename.Right(sADBFileName.size());
  1481.                 if (compFilename.compareNoCase(sADBFileName) == 0)
  1482.                 {
  1483.                         if (bMoveUp)
  1484.                         {
  1485.                                 if (m_subADBs.begin() != itADB)
  1486.                                         std::iter_swap(itADB, itADB - 1);
  1487.                         }
  1488.                         else  // move down
  1489.                         {
  1490.                                 if (m_subADBs.end() - 1 != itADB)
  1491.                                         std::iter_swap(itADB, itADB + 1);
  1492.                         }
  1493.                         return true;
  1494.                 }
  1495.                 else
  1496.                 {
  1497.                         if (MoveSubADBFilterInternal(sADBFileName, *itADB, bMoveUp))
  1498.                                 return true;
  1499.                 }
  1500.         }
  1501.  
  1502.         return false;
  1503. }
  1504.  
  1505. bool CAnimationDatabase::DeleteSubADBFilterInternal(const string& sADBFileName, SSubADB& subADB)
  1506. {
  1507.         for (TSubADBList::iterator subitADB = subADB.subADBs.begin(); subitADB != subADB.subADBs.end(); ++subitADB)
  1508.         {
  1509.                 const string compFilename = (*subitADB).filename.Right(sADBFileName.size());
  1510.                 if (compFilename.compareNoCase(sADBFileName) == 0)
  1511.                 {
  1512.                         subADB.subADBs.erase(subitADB);
  1513.                         return true;
  1514.                 }
  1515.                 else
  1516.                 {
  1517.                         if (DeleteSubADBFilterInternal(sADBFileName, *subitADB))
  1518.                                 return true;
  1519.                 }
  1520.         }
  1521.         return false;
  1522. }
  1523.  
  1524. bool CAnimationDatabase::DeleteSubADBFilter(const string& sADBFileName)
  1525. {
  1526.         if (sADBFileName.compareNoCase(m_filename) == 0)
  1527.                 return false;
  1528.  
  1529.         for (TSubADBList::iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1530.         {
  1531.                 const string compFilename = (*itADB).filename.Right(sADBFileName.size());
  1532.                 if (compFilename.compareNoCase(sADBFileName) == 0)
  1533.                 {
  1534.                         m_subADBs.erase(itADB);
  1535.                         return true;
  1536.                 }
  1537.                 else
  1538.                 {
  1539.                         if (DeleteSubADBFilterInternal(sADBFileName, *itADB))
  1540.                                 return true;
  1541.                 }
  1542.         }
  1543.  
  1544.         return false;
  1545. }
  1546.  
  1547. bool CAnimationDatabase::ClearSubADBFilterInternal(const string& sADBFileName, SSubADB& subADB)
  1548. {
  1549.         for (TSubADBList::iterator subitADB = subADB.subADBs.begin(); subitADB != subADB.subADBs.end(); ++subitADB)
  1550.         {
  1551.                 const string compFilename = (*subitADB).filename.Right(sADBFileName.size());
  1552.                 if (compFilename.compareNoCase(sADBFileName) == 0)
  1553.                 {
  1554.                         (*subitADB).tags = TagState(TAG_STATE_EMPTY);
  1555.                         (*subitADB).vFragIDs.clear();
  1556.                         return true;
  1557.                 }
  1558.                 else
  1559.                 {
  1560.                         if (ClearSubADBFilterInternal(sADBFileName, *subitADB))
  1561.                                 return true;
  1562.                 }
  1563.         }
  1564.         return false;
  1565. }
  1566.  
  1567. bool CAnimationDatabase::ClearSubADBFilter(const string& sADBFileName)
  1568. {
  1569.         if (sADBFileName.compareNoCase(m_filename) == 0)
  1570.                 return false;
  1571.  
  1572.         for (TSubADBList::iterator itADB = m_subADBs.begin(); itADB != m_subADBs.end(); ++itADB)
  1573.         {
  1574.                 const string compFilename = (*itADB).filename.Right(sADBFileName.size());
  1575.                 if (compFilename.compareNoCase(sADBFileName) == 0)
  1576.                 {
  1577.                         (*itADB).tags = TagState(TAG_STATE_EMPTY);
  1578.                         (*itADB).vFragIDs.clear();
  1579.                         return true;
  1580.                 }
  1581.                 else
  1582.                 {
  1583.                         if (ClearSubADBFilterInternal(sADBFileName, *itADB))
  1584.                                 return true;
  1585.                 }
  1586.         }
  1587.  
  1588.         return false;
  1589. }
  1590.  
  1591. CAnimationDatabase::SFragmentBlendVariant* CAnimationDatabase::GetVariant(FragmentID fragmentIDFrom, FragmentID fragmentIDTo, const SFragTagState& tagFrom, const SFragTagState& tagTo) const
  1592. {
  1593.         const SFragmentBlendID blendID = { fragmentIDFrom, fragmentIDTo };
  1594.         TFragmentBlendDatabase::const_iterator iter = m_fragmentBlendDB.find(blendID);
  1595.  
  1596.         if (iter != m_fragmentBlendDB.end())
  1597.         {
  1598.                 SFragmentBlendEntry& entry = (SFragmentBlendEntry&)iter->second;
  1599.                 const uint32 numVariants = entry.variantList.size();
  1600.                 for (uint32 i = 0; i < numVariants; i++)
  1601.                 {
  1602.                         SFragmentBlendVariant& variant = entry.variantList[i];
  1603.                         if ((tagFrom == variant.tagsFrom) && (tagTo == variant.tagsTo))
  1604.                         {
  1605.                                 return &variant;
  1606.                         }
  1607.                 }
  1608.         }
  1609.  
  1610.         return NULL;
  1611. }
  1612.  
  1613. const CAnimationDatabase::SFragmentBlendVariant* CAnimationDatabase::FindBestVariant(const SFragmentBlendID& fragmentBlendID, const SFragTagState& tagFrom, const SFragTagState& tagTo, const TagState& requiredTags, FragmentID& outFragmentFrom, FragmentID& outFragmentTo) const
  1614. {
  1615.         TFragmentBlendDatabase::const_iterator iter = m_fragmentBlendDB.find(fragmentBlendID);
  1616.  
  1617.         if (iter != m_fragmentBlendDB.end())
  1618.         {
  1619.                 const CTagDefinition* fragFromDef = (fragmentBlendID.fragFrom != FRAGMENT_ID_INVALID) ? m_pFragDef->GetSubTagDefinition(fragmentBlendID.fragFrom) : NULL;
  1620.                 const CTagDefinition* fragToDef = (fragmentBlendID.fragTo != FRAGMENT_ID_INVALID) ? m_pFragDef->GetSubTagDefinition(fragmentBlendID.fragTo) : NULL;
  1621.  
  1622.                 outFragmentFrom = iter->first.fragFrom;
  1623.                 outFragmentTo = iter->first.fragTo;
  1624.  
  1625.                 TagState requiredComparisonMask = m_pTagDef->GenerateMask(requiredTags);
  1626.  
  1627.                 //--- Found an entry, search for the best match
  1628.                 SFragmentBlendEntry& entry = (SFragmentBlendEntry&)iter->second;
  1629.                 const uint32 numVariants = entry.variantList.size();
  1630.                 for (uint32 j = 0; j < numVariants; j++)
  1631.                 {
  1632.                         SFragmentBlendVariant& variant = entry.variantList[j];
  1633.                         bool valid = (m_pTagDef->Contains(tagFrom.globalTags, variant.tagsFrom.globalTags) && m_pTagDef->Contains(tagTo.globalTags, variant.tagsTo.globalTags));
  1634.                         valid = valid && m_pTagDef->Contains(variant.tagsFrom.globalTags, requiredTags, requiredComparisonMask);
  1635.                         valid = valid && m_pTagDef->Contains(variant.tagsTo.globalTags, requiredTags, requiredComparisonMask);
  1636.                         valid = valid && (!fragFromDef || fragFromDef->Contains(tagFrom.fragmentTags, variant.tagsFrom.fragmentTags));
  1637.                         valid = valid && (!fragToDef || fragToDef->Contains(tagTo.fragmentTags, variant.tagsTo.fragmentTags));
  1638.                         if (valid)
  1639.                         {
  1640.                                 return &variant;
  1641.                         }
  1642.                 }
  1643.         }
  1644.  
  1645.         return NULL;
  1646. }
  1647.  
  1648. void CAnimationDatabase::FindBestBlendInVariant(const SFragmentBlendVariant& variant, const SBlendQuery& blendQuery, SBlendQueryResult& result) const
  1649. {
  1650.         const uint32 numBlends = variant.blendList.size();
  1651.  
  1652.         result.tagStateFrom = variant.tagsFrom;
  1653.         result.tagStateTo = variant.tagsTo;
  1654.  
  1655.         if (blendQuery.forceBlendUid.IsValid())
  1656.         {
  1657.                 const uint32 blendIdx = variant.FindBlendIndexForUid(blendQuery.forceBlendUid);
  1658.                 if (blendIdx < variant.blendList.size())
  1659.                 {
  1660.                         const SFragmentBlend& fragBlend = variant.blendList[blendIdx];
  1661.                         result.pFragmentBlend = &fragBlend;
  1662.                         result.blendIdx = blendIdx;
  1663.                         result.blendUid = fragBlend.uid;
  1664.                         result.selectTime = fragBlend.selectTime;
  1665.                         return;
  1666.                 }
  1667.         }
  1668.  
  1669.         for (uint32 i = 0; i < numBlends; i++)
  1670.         {
  1671.                 const SFragmentBlend& fragBlend = variant.blendList[i];
  1672.                 const float sourceTime = (fragBlend.flags & SFragmentBlend::CycleLocked) ? blendQuery.prevNormalisedTime : ((fragBlend.flags & SFragmentBlend::Cyclic) ? blendQuery.normalisedTime : blendQuery.fragmentTime);
  1673.                 if ((result.pFragmentBlend == NULL) || (sourceTime >= fragBlend.selectTime))
  1674.                 {
  1675.                         result.pFragmentBlend = &fragBlend;
  1676.                         result.blendIdx = i;
  1677.                         result.blendUid = fragBlend.uid;
  1678.                         result.selectTime = fragBlend.selectTime;
  1679.                 }
  1680.         }
  1681. }
  1682.  
  1683. //----------------------------------------------------------------------------
  1684. //      Selects the best matching variant from fragFrom to fragTo
  1685. //      If it fails to match tags at all then it will drop back to "any to fragTo" (an entry transition),
  1686. //      "fragFrom to any" (an exit transition) and finally "any to any" (a pure tag based transition)
  1687. //----------------------------------------------------------------------------
  1688. void CAnimationDatabase::FindBestBlends(const SBlendQuery& blendQuery, SBlendQueryResult& result1, SBlendQueryResult& result2) const
  1689. {
  1690.         const uint32 numVariants = 4;
  1691.         const SFragmentBlendID blendIDOptions[numVariants] = {
  1692.                 { blendQuery.fragmentFrom, blendQuery.fragmentTo }, { blendQuery.fragmentFrom, FRAGMENT_ID_INVALID }, { FRAGMENT_ID_INVALID, blendQuery.fragmentTo }, { FRAGMENT_ID_INVALID, FRAGMENT_ID_INVALID }
  1693.         };
  1694.         bool viableVariants[4] = { false, false, false, false };
  1695.  
  1696.         //--- Limit transitions based on whether our from or to are primary installations (as apposed to enslaved scopes)
  1697.         if (blendQuery.IsFlagSet(SBlendQuery::toInstalled))
  1698.         {
  1699.                 viableVariants[0] = (blendQuery.fragmentFrom != FRAGMENT_ID_INVALID) && (blendQuery.fragmentTo != FRAGMENT_ID_INVALID);
  1700.                 viableVariants[2] = (blendQuery.fragmentTo != FRAGMENT_ID_INVALID);
  1701.                 viableVariants[3] = true;
  1702.         }
  1703.         if (blendQuery.IsFlagSet(SBlendQuery::fromInstalled))
  1704.         {
  1705.                 viableVariants[0] = (blendQuery.fragmentFrom != FRAGMENT_ID_INVALID) && (blendQuery.fragmentTo != FRAGMENT_ID_INVALID);
  1706.                 viableVariants[1] = (blendQuery.fragmentFrom != FRAGMENT_ID_INVALID) && ((blendQuery.flags & SBlendQuery::higherPriority) == 0);
  1707.         }
  1708.  
  1709.         const SFragmentBlendVariant* pVariant1 = NULL;
  1710.         const SFragmentBlendVariant* pVariant2 = NULL;
  1711.  
  1712.         for (uint32 i = 0; i < numVariants; i++)
  1713.         {
  1714.                 if (viableVariants[i])
  1715.                 {
  1716.                         pVariant1 = FindBestVariant(blendIDOptions[i], blendQuery.tagStateFrom, blendQuery.tagStateTo, blendQuery.additionalTags, result1.fragmentFrom, result1.fragmentTo);
  1717.  
  1718.                         if (pVariant1)
  1719.                         {
  1720.                                 if ((i == 1) && viableVariants[2])
  1721.                                 {
  1722.                                         //--- This is exiting from the previous fragment, we can apply an entry to the new one if one exists too
  1723.                                         pVariant2 = FindBestVariant(blendIDOptions[2], blendQuery.tagStateFrom, blendQuery.tagStateTo, blendQuery.additionalTags, result2.fragmentFrom, result2.fragmentTo);
  1724.                                 }
  1725.                                 break;
  1726.                         }
  1727.                 }
  1728.         }
  1729.  
  1730.         if (pVariant1)
  1731.         {
  1732.                 FindBestBlendInVariant(*pVariant1, blendQuery, result1);
  1733.         }
  1734.         if (pVariant2)
  1735.         {
  1736.                 FindBestBlendInVariant(*pVariant2, blendQuery, result2);
  1737.         }
  1738. }
  1739.  
  1740. void CAnimationDatabase::AdjustSubADBListAfterFragmentIDDeletion(SSubADB::TSubADBList& subADBs, const FragmentID fragmentID)
  1741. {
  1742.         for (SSubADB::TSubADBList::iterator itSubADB = subADBs.begin(); itSubADB != subADBs.end(); ++itSubADB)
  1743.         {
  1744.                 for (SSubADB::TFragIDList::iterator itFragID = itSubADB->vFragIDs.begin(); itFragID != itSubADB->vFragIDs.end(); )
  1745.                 {
  1746.                         if (*itFragID == fragmentID)
  1747.                         {
  1748.                                 // Remove direct references to the removed fragmentID.
  1749.                                 // Note that this does not remove the sub ADB rule, it just leaves a subADB rule with less fragmentIDs.
  1750.                                 itFragID = itSubADB->vFragIDs.erase(itFragID);
  1751.                         }
  1752.                         else
  1753.                         {
  1754.                                 // Adjust any references to fragmentIDs above the deleted one
  1755.                                 if (*itFragID > fragmentID)
  1756.                                 {
  1757.                                         --(*itFragID);
  1758.                                 }
  1759.                                 ++itFragID;
  1760.                         }
  1761.                 }
  1762.  
  1763.                 AdjustSubADBListAfterFragmentIDDeletion(itSubADB->subADBs, fragmentID);
  1764.         }
  1765. }
  1766.  
  1767. void CAnimationDatabase::DeleteFragmentID(FragmentID fragmentID)
  1768. {
  1769.         m_fragmentList.erase(m_fragmentList.begin() + fragmentID);
  1770.  
  1771.         // Adjust blends
  1772.         {
  1773.                 TFragmentBlendDatabase newBlendDb;
  1774.  
  1775.                 for (TFragmentBlendDatabase::iterator it = m_fragmentBlendDB.begin(); it != m_fragmentBlendDB.end(); ++it)
  1776.                 {
  1777.                         const SFragmentBlendID& blendID = it->first;
  1778.  
  1779.                         // Drop any blends that refer to the deleted fragmentID
  1780.                         if ((blendID.fragFrom != fragmentID) && (blendID.fragTo != fragmentID))
  1781.                         {
  1782.                                 SFragmentBlendID newBlendID;
  1783.                                 newBlendID.fragFrom = blendID.fragFrom;
  1784.                                 newBlendID.fragTo = blendID.fragTo;
  1785.  
  1786.                                 // Adjust any references to fragmentIDs above the deleted one
  1787.                                 if (newBlendID.fragFrom > fragmentID)
  1788.                                         newBlendID.fragFrom--;
  1789.                                 if (newBlendID.fragTo > fragmentID)
  1790.                                         newBlendID.fragTo--;
  1791.  
  1792.                                 newBlendDb[newBlendID] = it->second;
  1793.                         }
  1794.                 }
  1795.  
  1796.                 // Swap the new one for the old one
  1797.                 m_fragmentBlendDB = newBlendDb;
  1798.         }
  1799.  
  1800.         // Adjust fragmentIDs in subADB definitions
  1801.         AdjustSubADBListAfterFragmentIDDeletion(m_subADBs, fragmentID);
  1802. }
  1803.  
  1804. void CAnimationDatabase::QueryUsedTags(const FragmentID fragmentID, const SFragTagState& filter, SFragTagState& usedTags) const
  1805. {
  1806.         const uint32 numFragmentTypes = m_fragmentList.size();
  1807.         if (fragmentID < numFragmentTypes)
  1808.         {
  1809.                 SFragmentEntry& fragmentEntry = *m_fragmentList[fragmentID];
  1810.                 const CTagDefinition* pFragTagDef = m_pFragDef->GetSubTagDefinition(fragmentID);
  1811.                 fragmentEntry.tagSetList.QueryUsedTags(usedTags, filter, m_pTagDef, pFragTagDef);
  1812.         }
  1813. }
  1814.  
downloadAnimationDatabase.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