BVB Source Codes

CRYENGINE Show ForceFeedbackSystem.cpp Source code

Return Download CRYENGINE: download ForceFeedbackSystem.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /*************************************************************************
  4.    -------------------------------------------------------------------------
  5.  
  6.    Implementation for force feedback system
  7.  
  8. * Effect definition (shape, time, ...) are defined in xml
  9. * Effects are invoked by name, and updated here internally, feeding
  10.    input system in a per frame basis
  11.  
  12.    -------------------------------------------------------------------------
  13.    History:
  14.    - 18-02-2010:        Created by Benito Gangoso Rodriguez
  15.    - 20-09-2012: Updated by Dario Sancho (added support for Durango Triggers feedback)
  16.  
  17. *************************************************************************/
  18.  
  19. #include "StdAfx.h"
  20. #include "ForceFeedbackSystem.h"
  21. #include "GameXmlParamReader.h"
  22.  
  23. #include <CryString/StringUtils.h>
  24.  
  25. #if !defined(_RELEASE)
  26.         #define DEBUG_FORCEFEEDBACK_SYSTEM
  27. #endif
  28.  
  29. #define MAX_FORCE_FEEDBACK_EFFECTS 8
  30. //#define MAX_FORCE_FEEDBACK_EFFECTS 100  //For stress testing
  31.  
  32. #ifdef DEBUG_FORCEFEEDBACK_SYSTEM
  33.         #include <CryAction/IDebugHistory.h>
  34.  
  35. class CForceFeedBackSystemDebug
  36. {
  37. public:
  38.         static void Init()
  39.         {
  40.                 assert(s_pDebugHistoryManager == NULL);
  41.  
  42.                 if (s_pDebugHistoryManager == NULL)
  43.                 {
  44.                         s_pDebugHistoryManager = CCryAction::GetCryAction()->CreateDebugHistoryManager();
  45.                 }
  46.         }
  47.  
  48.         static void Shutdown()
  49.         {
  50.                 SAFE_RELEASE(s_pDebugHistoryManager);
  51.         }
  52.  
  53.         static void DebugFFOutput(bool debugEnabled, float motorA, float motorB, const SFFTriggerOutputData& triggers)
  54.         {
  55.  
  56.                 if (!debugEnabled)
  57.                 {
  58.                         if (s_pDebugHistoryManager)
  59.                         {
  60.                                 s_pDebugHistoryManager->Clear();
  61.                         }
  62.                         return;
  63.                 }
  64.  
  65.                 if (s_pDebugHistoryManager)
  66.                 {
  67.                         s_pDebugHistoryManager->LayoutHelper("FFMotorA_HighFreq", NULL, true, -20, 20, 0, 1, 0.0f, 0.0f);
  68.                         s_pDebugHistoryManager->LayoutHelper("FFMotorB_LowFreq", NULL, true, -20, 20, 0, 1, 1.0f, 0.0f);
  69.                         s_pDebugHistoryManager->LayoutHelper("FFLeftTriggerGain", NULL, true, 0, 1, 0, 1.f, 2.0f, 0.0f);
  70.                         s_pDebugHistoryManager->LayoutHelper("FFRightTriggerGain", NULL, true, 0, 1, 0, 1.f, 2.5f, 0.0f);
  71.                         s_pDebugHistoryManager->LayoutHelper("FFLeftTriggerEnv", NULL, true, 0, 2000, 0, 2000.f, 3.0f, 0.0f);
  72.                         s_pDebugHistoryManager->LayoutHelper("FFRightTriggerEnv", NULL, true, 0, 2000, 0, 2000.f, 3.5f, 0.0f);
  73.  
  74.                         IDebugHistory* pDHMotorA = s_pDebugHistoryManager->GetHistory("FFMotorA_HighFreq");
  75.                         if (pDHMotorA != NULL)
  76.                         {
  77.                                 pDHMotorA->AddValue(motorA);
  78.                         }
  79.  
  80.                         IDebugHistory* pDHMotorB = s_pDebugHistoryManager->GetHistory("FFMotorB_LowFreq");
  81.                         if (pDHMotorB != NULL)
  82.                         {
  83.                                 pDHMotorB->AddValue(motorB);
  84.                         }
  85.  
  86.                         IDebugHistory* pDHLeftTriggerGain = s_pDebugHistoryManager->GetHistory("FFLeftTriggerGain");
  87.                         if (pDHLeftTriggerGain != NULL)
  88.                         {
  89.                                 pDHLeftTriggerGain->AddValue(triggers.leftGain);
  90.                         }
  91.  
  92.                         IDebugHistory* pDHRightTriggerGain = s_pDebugHistoryManager->GetHistory("FFRightTriggerGain");
  93.                         if (pDHRightTriggerGain != NULL)
  94.                         {
  95.                                 pDHRightTriggerGain->AddValue(triggers.rightGain);
  96.                         }
  97.  
  98.                         IDebugHistory* pDHLeftTriggerEnv = s_pDebugHistoryManager->GetHistory("FFLeftTriggerEnv");
  99.                         if (pDHLeftTriggerEnv != NULL)
  100.                         {
  101.                                 pDHLeftTriggerEnv->AddValue(triggers.leftEnv);
  102.                         }
  103.  
  104.                         IDebugHistory* pDHRightTriggerEnv = s_pDebugHistoryManager->GetHistory("FFRightTriggerEnv");
  105.                         if (pDHRightTriggerEnv != NULL)
  106.                         {
  107.                                 pDHRightTriggerEnv->AddValue(triggers.rightEnv);
  108.                         }
  109.                 }
  110.         }
  111.  
  112. private:
  113.  
  114.         static IDebugHistoryManager* s_pDebugHistoryManager;
  115. };
  116.  
  117. IDebugHistoryManager* CForceFeedBackSystemDebug::s_pDebugHistoryManager = NULL;
  118. #else
  119. class CForceFeedBackSystemDebug
  120. {
  121. public:
  122.         ILINE static void Init()
  123.         {
  124.  
  125.         }
  126.  
  127.         ILINE static void Shutdown()
  128.         {
  129.  
  130.         }
  131.  
  132.         ILINE static void DebugFFOutput(bool debugEnabled, float motorA, float motorB, const SFFTriggerOutputData& triggers)
  133.         {
  134.  
  135.         }
  136. };
  137. #endif
  138.  
  139. #ifdef DEBUG_FORCEFEEDBACK_SYSTEM
  140.         #define FORCEFEEDBACK_LOG(...) GameWarning("[ForceFeedback System] " __VA_ARGS__)
  141. #else
  142.         #define FORCEFEEDBACK_LOG(...) (void)(0)
  143. #endif
  144.  
  145. //////////////////////////////////////////////////////////////////////////
  146. //////////////////////////////////////////////////////////////////////////
  147. #if defined(_DEBUG)
  148.  
  149. void CForceFeedBackSystem::FFBInternalId::Set(const char* _name)
  150. {
  151.         assert(_name);
  152.         name = _name;
  153.         id = CryStringUtils::CalculateHash(_name);
  154. }
  155.  
  156. const char* CForceFeedBackSystem::FFBInternalId::GetDebugName() const
  157. {
  158.         return name.c_str();
  159. }
  160.  
  161. #else
  162.  
  163. void CForceFeedBackSystem::FFBInternalId::Set(const char* _name)
  164. {
  165.         assert(_name);
  166.         id = CryStringUtils::CalculateHash(_name);
  167. }
  168.  
  169. const char* CForceFeedBackSystem::FFBInternalId::GetDebugName() const
  170. {
  171.         return "";
  172. }
  173.  
  174. #endif
  175.  
  176. CForceFeedBackSystem::FFBInternalId& CForceFeedBackSystem::FFBInternalId::GetIdForName(const char* name)
  177. {
  178.         static FFBInternalId cachedId;
  179.  
  180.         cachedId.id = CryStringUtils::CalculateHash(name);
  181.  
  182.         return cachedId;
  183. }
  184.  
  185. //////////////////////////////////////////////////////////////////////////
  186. //////////////////////////////////////////////////////////////////////////
  187.  
  188. CForceFeedBackSystem::CForceFeedBackSystem()
  189.         : m_effectLock(0)
  190. {
  191.         CForceFeedBackSystemDebug::Init();
  192.  
  193.         m_defaultPattern.ResetToDefault();
  194.         m_defaultEnvelope.ResetToDefault();
  195.  
  196.         m_activeEffects.reserve(MAX_FORCE_FEEDBACK_EFFECTS);
  197. }
  198.  
  199. CForceFeedBackSystem::~CForceFeedBackSystem()
  200. {
  201.         CForceFeedBackSystemDebug::Shutdown();
  202. }
  203.  
  204. void CForceFeedBackSystem::PlayForceFeedbackEffect(ForceFeedbackFxId id, const SForceFeedbackRuntimeParams& runtimeParams)
  205. {
  206.         if (m_effectLock > 0)
  207.         {
  208.                 return;
  209.         }
  210.  
  211.         //Note: As requested, if the effect is running prefer to re-start, and reset its runtimeParams
  212.         if (TryToRestartEffectIfAlreadyRunning(id, runtimeParams))
  213.         {
  214.                 return;
  215.         }
  216.  
  217.         const int activeEffectSize = m_activeEffects.size();
  218.         bool freeSlotsAvailable = (activeEffectSize < (int)MAX_FORCE_FEEDBACK_EFFECTS);
  219.  
  220.         if (freeSlotsAvailable)
  221.         {
  222.                 const int testId = (int)id;
  223.                 bool validId = ((testId >= 0) && (testId < (int)(m_effects.size())));
  224.  
  225.                 if (validId)
  226.                 {
  227.                         const SEffect& effect = m_effects[id];
  228.  
  229.                         const SPattern& effectPatternA = FindPattern(effect.patternA);
  230.                         const SPattern& effectPatternB = (effect.patternA == effect.patternB) ? effectPatternA : FindPattern(effect.patternB);
  231.                         const SPattern& effectPatternLT = FindPattern(effect.patternLT);
  232.                         const SPattern& effectPatternRT = (effect.patternLT == effect.patternRT) ? effectPatternLT : FindPattern(effect.patternRT);
  233.  
  234.                         const SEnvelope& effectEnvelopeA = FindEnvelope(effect.envelopeA);
  235.                         const SEnvelope& effectEnvelopeB = (effect.envelopeA == effect.envelopeB) ? effectEnvelopeA : FindEnvelope(effect.envelopeB);
  236.                         const SEnvelope& effectEnvelopeLT = FindEnvelope(effect.envelopeLT);
  237.                         const SEnvelope& effectEnvelopeRT = (effect.envelopeLT == effect.envelopeRT) ? effectEnvelopeLT : FindEnvelope(effect.envelopeRT);
  238.  
  239.                         SActiveEffect newActiveEffect;
  240.                         m_activeEffects.push_back(newActiveEffect);
  241.  
  242.                         SActiveEffect& justAddedEffect = m_activeEffects[activeEffectSize];
  243.                         justAddedEffect.effectId = id;
  244.                         justAddedEffect.effectTime = effect.time;
  245.                         justAddedEffect.runningTime = 0.0f;
  246.                         justAddedEffect.frequencyA = effect.frequencyA;
  247.                         justAddedEffect.frequencyB = effect.frequencyB;
  248.                         justAddedEffect.frequencyLT = effect.frequencyLT;
  249.                         justAddedEffect.frequencyRT = effect.frequencyRT;
  250.                         justAddedEffect.runtimeParams = runtimeParams;
  251.  
  252.                         //Patters are copied, for faster access when loop-processing, instead of being a pointer
  253.                         //Since we have a very small amount of fixed FX it should not be a big deal.
  254.                         justAddedEffect.m_patternA = effectPatternA;
  255.                         justAddedEffect.m_envelopeA = effectEnvelopeA;
  256.                         justAddedEffect.m_patternB = effectPatternB;
  257.                         justAddedEffect.m_envelopeB = effectEnvelopeB;
  258.                         justAddedEffect.m_patternLT = effectPatternLT;
  259.                         justAddedEffect.m_envelopeLT = effectEnvelopeLT;
  260.                         justAddedEffect.m_patternRT = effectPatternRT;
  261.                         justAddedEffect.m_envelopeRT = effectEnvelopeRT;
  262.                 }
  263.                 else
  264.                 {
  265.                         FORCEFEEDBACK_LOG("Play effect could not find effect. Invalid id '%d' provided", id);
  266.                 }
  267.  
  268.         }
  269.         else
  270.         {
  271.                 FORCEFEEDBACK_LOG("Too many effects already running, could not execute");
  272.         }
  273. }
  274.  
  275. bool CForceFeedBackSystem::TryToRestartEffectIfAlreadyRunning(ForceFeedbackFxId id, const SForceFeedbackRuntimeParams& runtimeParams)
  276. {
  277.         TActiveEffectsArray::iterator activeEffectsEndIt = m_activeEffects.end();
  278.  
  279.         for (TActiveEffectsArray::iterator activeEffectIt = m_activeEffects.begin(); activeEffectIt != activeEffectsEndIt; ++activeEffectIt)
  280.         {
  281.                 if (activeEffectIt->effectId != id)
  282.                         continue;
  283.  
  284.                 activeEffectIt->runningTime = 0.0f;
  285.                 activeEffectIt->runtimeParams = runtimeParams;
  286.                 return true;
  287.         }
  288.  
  289.         return false;
  290. }
  291.  
  292. void CForceFeedBackSystem::StopForceFeedbackEffect(ForceFeedbackFxId id)
  293. {
  294.         TActiveEffectsArray::iterator activeEffectIt = m_activeEffects.begin();
  295.  
  296.         while (activeEffectIt != m_activeEffects.end())
  297.         {
  298.                 if (activeEffectIt->effectId != id)
  299.                 {
  300.                         ++activeEffectIt;
  301.                 }
  302.                 else
  303.                 {
  304.                         TActiveEffectsArray::iterator next = m_activeEffects.erase(activeEffectIt);
  305.                         activeEffectIt = next;
  306.                 }
  307.         }
  308. }
  309.  
  310. ForceFeedbackFxId CForceFeedBackSystem::GetEffectIdByName(const char* effectName) const
  311. {
  312.         TEffectToIndexMap::const_iterator cit = m_effectToIndexMap.find(FFBInternalId::GetIdForName(effectName));
  313.  
  314.         if (cit != m_effectToIndexMap.end())
  315.         {
  316.                 return cit->second;
  317.         }
  318.         FORCEFEEDBACK_LOG("Could not get effect id for \"%s\".", effectName);
  319.  
  320.         return InvalidForceFeedbackFxId;
  321. }
  322.  
  323. void CForceFeedBackSystem::StopAllEffects()
  324. {
  325.         m_activeEffects.clear();
  326.  
  327.         UpdateInputSystem(0.0f, 0.0f, SFFTriggerOutputData(SFFTriggerOutputData::Initial::ZeroIt));
  328. }
  329.  
  330. void CForceFeedBackSystem::AddFrameCustomForceFeedback(const float amplifierA, const float amplifierB, const float amplifierLT /*= 0.0f*/, const float amplifierRT /*= 0.0f*/)
  331. {
  332.         m_frameCustomForceFeedback.forceFeedbackA += amplifierA;
  333.         m_frameCustomForceFeedback.forceFeedbackB += amplifierB;
  334.         m_frameCustomForceFeedback.forceFeedbackLT += amplifierLT;
  335.         m_frameCustomForceFeedback.forceFeedbackRT += amplifierRT;
  336. }
  337.  
  338. void CForceFeedBackSystem::AddCustomTriggerForceFeedback(const SFFTriggerOutputData& triggersData)
  339. {
  340.         m_triggerCustomForceFeedBack += triggersData;
  341. }
  342.  
  343. void CForceFeedBackSystem::Update(float frameTime)
  344. {
  345.         SFFOutput forceFeedback;
  346.         SFFTriggerOutputData triggerForceFeedback;
  347.  
  348.         // If the game is paused then we must not apply force feedback, otherwise
  349.         // it might be left on whilst the game is paused
  350.         if (gEnv->pSystem->IsPaused() == false && frameTime > 0.001f)
  351.         {
  352.                 TActiveEffectsArray::iterator activeEffectIt = m_activeEffects.begin();
  353.  
  354.                 while (activeEffectIt != m_activeEffects.end())
  355.                 {
  356.                         SActiveEffect& currentEffect = *activeEffectIt;
  357.  
  358.                         SFFOutput current = currentEffect.Update(frameTime);
  359.                         forceFeedback += current;
  360.                         triggerForceFeedback.leftStrength += current.forceFeedbackLT;
  361.                         triggerForceFeedback.rightStrength += current.forceFeedbackRT;
  362.  
  363.                         if (!currentEffect.HasFinished())
  364.                         {
  365.                                 ++activeEffectIt;
  366.                         }
  367.                         else
  368.                         {
  369.                                 TActiveEffectsArray::iterator next = m_activeEffects.erase(activeEffectIt);
  370.                                 activeEffectIt = next;
  371.                         }
  372.                 }
  373.  
  374.                 forceFeedback += m_frameCustomForceFeedback;
  375.                 // DARIO_NOTE: so far designers do not want patters loaded from XML so all the data come direclty from
  376.                 // FlowGraph nodes
  377.                 triggerForceFeedback += m_triggerCustomForceFeedBack;
  378.                 m_frameCustomForceFeedback.ZeroIt();
  379.                 m_triggerCustomForceFeedBack.Init(SFFTriggerOutputData::Initial::ZeroIt);
  380.         }
  381.  
  382.         UpdateInputSystem(forceFeedback.GetClampedFFA(), forceFeedback.GetClampedFFB(), triggerForceFeedback);
  383.  
  384.         CForceFeedBackSystemDebug::DebugFFOutput((m_cvars.ffs_debug != 0), forceFeedback.GetClampedFFA(), forceFeedback.GetClampedFFB(), triggerForceFeedback);
  385. }
  386.  
  387. void CForceFeedBackSystem::UpdateInputSystem(const float amplifierA, const float amplifierB, const SFFTriggerOutputData& triggers)
  388. {
  389.         if (gEnv->pInput)
  390.         {
  391.                 SFFOutputEvent ffEvent;
  392.                 ffEvent.deviceType = eIDT_Gamepad;
  393.                 ffEvent.eventId = eFF_Rumble_Frame;
  394.                 ffEvent.amplifierA = amplifierA;
  395.                 ffEvent.amplifierS = amplifierB;
  396.                 ffEvent.triggerData = triggers;
  397.                 gEnv->pInput->ForceFeedbackEvent(ffEvent);
  398.         }
  399. }
  400.  
  401. void CForceFeedBackSystem::Initialize()
  402. {
  403.         LoadXmlData();
  404. }
  405.  
  406. void CForceFeedBackSystem::Reload()
  407. {
  408.         StopAllEffects();
  409.  
  410.         m_patters.clear();
  411.         m_envelopes.clear();
  412.         m_effects.clear();
  413.         m_effectToIndexMap.clear();
  414.  
  415.         LoadXmlData();
  416. }
  417.  
  418. void CForceFeedBackSystem::LoadXmlData()
  419. {
  420.         const char* xmlDataFile = "Libs/GameForceFeedback/ForceFeedbackEffects.xml";
  421.         XmlNodeRef rootNode = gEnv->pSystem->LoadXmlFromFile(xmlDataFile);
  422.  
  423.         if (!rootNode || strcmpi(rootNode->getTag(), "ForceFeedback"))
  424.         {
  425.                 FORCEFEEDBACK_LOG("Could not load force feedback system data. Invalid XML file '%s'! ", xmlDataFile);
  426.                 return;
  427.         }
  428.  
  429.         const int childCount = rootNode->getChildCount();
  430.         for (int i = 0; i < childCount; ++i)
  431.         {
  432.                 XmlNodeRef childNode = rootNode->getChild(i);
  433.  
  434.                 const char* childTag = childNode->getTag();
  435.                 if (strcmp(childTag, "Patterns") == 0)
  436.                 {
  437.                         LoadPatters(childNode);
  438.                 }
  439.                 else if (strcmp(childTag, "Envelopes") == 0)
  440.                 {
  441.                         LoadEnvelopes(childNode);
  442.                 }
  443.                 else if (strcmp(childTag, "Effects") == 0)
  444.                 {
  445.                         LoadEffects(childNode);
  446.                 }
  447.         }
  448. }
  449.  
  450. void CForceFeedBackSystem::LoadPatters(XmlNodeRef& patternsNode)
  451. {
  452.         const int patterCount = patternsNode->getChildCount();
  453.  
  454.         m_patters.reserve(patterCount);
  455.  
  456.         TSamplesBuffer samplesBuffer;
  457.         const int maxSampleCount = FFSYSTEM_MAX_PATTERN_SAMPLES / 2;
  458.         float readValues[maxSampleCount];
  459.  
  460.         for (int i = 0; i < patterCount; ++i)
  461.         {
  462.                 XmlNodeRef childPatternNode = patternsNode->getChild(i);
  463.  
  464.                 const char* customPatternName = childPatternNode->getAttr("name");
  465.                 if (!customPatternName || (customPatternName[0] == '\0'))
  466.                 {
  467.                         FORCEFEEDBACK_LOG("Could not load pattern without name (at line %d)", childPatternNode->getLine());
  468.                         continue;
  469.                 }
  470.  
  471.                 samplesBuffer = childPatternNode->haveAttr("name") ? childPatternNode->getAttr("samples") : "";
  472.  
  473.                 int samplesFound = ParseSampleBuffer(samplesBuffer, &readValues[0], maxSampleCount);
  474.  
  475.                 if (samplesFound != 0)
  476.                 {
  477.                         SPattern customPattern;
  478.                         customPattern.ResetToDefault();
  479.  
  480.                         DistributeSamples(&readValues[0], samplesFound, &customPattern.m_patternSamples[0], FFSYSTEM_MAX_PATTERN_SAMPLES);
  481.  
  482.                         customPattern.m_patternId.Set(customPatternName);
  483.                         m_patters.push_back(customPattern);
  484.                 }
  485.                 else
  486.                 {
  487.                         FORCEFEEDBACK_LOG("Pattern '%s' (at line %d) has not samples, skipping", customPatternName, childPatternNode->getLine());
  488.                 }
  489.         }
  490.  
  491.         std::sort(m_patters.begin(), m_patters.end());
  492. }
  493.  
  494. void CForceFeedBackSystem::LoadEnvelopes(XmlNodeRef& envelopesNode)
  495. {
  496.         const int envelopesCount = envelopesNode->getChildCount();
  497.  
  498.         m_envelopes.reserve(envelopesCount);
  499.  
  500.         TSamplesBuffer samplesBuffer;
  501.         const int maxSampleCount = FFSYSTEM_MAX_ENVELOPE_SAMPLES / 2;
  502.         float readValues[maxSampleCount];
  503.  
  504.         for (int i = 0; i < envelopesCount; ++i)
  505.         {
  506.                 XmlNodeRef envelopeChildNode = envelopesNode->getChild(i);
  507.  
  508.                 const char* customEnvelopeName = envelopeChildNode->getAttr("name");
  509.                 if (!customEnvelopeName || (customEnvelopeName[0] == '\0'))
  510.                 {
  511.                         FORCEFEEDBACK_LOG("Could not load envelope without name (at line %d)", envelopeChildNode->getLine());
  512.                         continue;
  513.                 }
  514.  
  515.                 samplesBuffer = envelopeChildNode->haveAttr("name") ? envelopeChildNode->getAttr("samples") : "";
  516.  
  517.                 int samplesFound = ParseSampleBuffer(samplesBuffer, &readValues[0], maxSampleCount);
  518.  
  519.                 if (samplesFound != 0)
  520.                 {
  521.                         SEnvelope customEnvelope;
  522.                         customEnvelope.ResetToDefault();
  523.  
  524.                         DistributeSamples(&readValues[0], samplesFound, &customEnvelope.m_envelopeSamples[0], FFSYSTEM_MAX_ENVELOPE_SAMPLES);
  525.  
  526.                         customEnvelope.m_envelopeId.Set(customEnvelopeName);
  527.                         m_envelopes.push_back(customEnvelope);
  528.                 }
  529.                 else
  530.                 {
  531.                         FORCEFEEDBACK_LOG("Envelope '%s' (at line %d) has not samples, skipping", customEnvelopeName, envelopeChildNode->getLine());
  532.                 }
  533.         }
  534.  
  535.         std::sort(m_envelopes.begin(), m_envelopes.end());
  536. }
  537.  
  538. void CForceFeedBackSystem::LoadEffects(XmlNodeRef& effectsNode)
  539. {
  540.         CGameXmlParamReader paramReader(effectsNode);
  541.         const int effectsCount = paramReader.GetUnfilteredChildCount();
  542.  
  543.         m_effectToIndexMap.reserve(effectsCount);
  544.         m_effects.reserve(effectsCount);
  545.         m_effectNames.reserve(effectsCount);
  546.  
  547.         for (int i = 0; i < effectsCount; ++i)
  548.         {
  549.                 XmlNodeRef childEffectNode = paramReader.GetFilteredChildAt(i);
  550.  
  551.                 if (childEffectNode)
  552.                 {
  553.                         SEffect newEffect;
  554.                         const int effectDataCount = childEffectNode->getChildCount();
  555.  
  556.                         const char* effectName = childEffectNode->getAttr("name");
  557.  
  558.                         //Check for invalid name
  559.                         if ((effectName == NULL) || (effectName[0] == '\0'))
  560.                         {
  561.                                 FORCEFEEDBACK_LOG("Could not load effect without name (at line %d)", childEffectNode->getLine());
  562.                                 continue;
  563.                         }
  564.  
  565.                         //Check for duplicates
  566.                         if (m_effectToIndexMap.find(FFBInternalId::GetIdForName(effectName)) != m_effectToIndexMap.end())
  567.                         {
  568.                                 FORCEFEEDBACK_LOG("Effect '%s' does already exists, skipping", effectName);
  569.                                 continue;
  570.                         }
  571.  
  572.                         childEffectNode->getAttr("time", newEffect.time);
  573.  
  574.                         for (int j = 0; j < effectDataCount; ++j)
  575.                         {
  576.                                 XmlNodeRef motorNode = childEffectNode->getChild(j);
  577.  
  578.                                 const char* motorTag = motorNode->getTag();
  579.  
  580.                                 if (strcmp(motorTag, "MotorAB") == 0)
  581.                                 {
  582.                                         newEffect.patternA.Set(motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "");
  583.                                         newEffect.patternB = newEffect.patternA;
  584.                                         newEffect.envelopeA.Set(motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "");
  585.                                         newEffect.envelopeB = newEffect.envelopeA;
  586.                                         motorNode->getAttr("frequency", newEffect.frequencyA);
  587.                                         newEffect.frequencyB = newEffect.frequencyA;
  588.                                 }
  589.                                 else if (strcmp(motorTag, "MotorA") == 0)
  590.                                 {
  591.                                         newEffect.patternA.Set(motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "");
  592.                                         newEffect.envelopeA.Set(motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "");
  593.                                         motorNode->getAttr("frequency", newEffect.frequencyA);
  594.                                 }
  595.                                 else if (strcmp(motorTag, "MotorB") == 0)
  596.                                 {
  597.                                         newEffect.patternB.Set(motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "");
  598.                                         newEffect.envelopeB.Set(motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "");
  599.                                         motorNode->getAttr("frequency", newEffect.frequencyB);
  600.                                 }
  601.                                 else if (strcmp(motorTag, "MotorLTRT") == 0)
  602.                                 {
  603.                                         newEffect.patternLT.Set(motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "");
  604.                                         newEffect.patternRT = newEffect.patternLT;
  605.                                         newEffect.envelopeLT.Set(motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "");
  606.                                         newEffect.envelopeRT = newEffect.envelopeLT;
  607.                                         motorNode->getAttr("frequency", newEffect.frequencyLT);
  608.                                         newEffect.frequencyRT = newEffect.frequencyLT;
  609.                                 }
  610.                                 else if (strcmp(motorTag, "MotorLT") == 0)
  611.                                 {
  612.                                         newEffect.patternLT.Set(motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "");
  613.                                         newEffect.envelopeLT.Set(motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "");
  614.                                         motorNode->getAttr("frequency", newEffect.frequencyLT);
  615.                                 }
  616.                                 else if (strcmp(motorTag, "MotorRT") == 0)
  617.                                 {
  618.                                         newEffect.patternRT.Set(motorNode->haveAttr("pattern") ? motorNode->getAttr("pattern") : "");
  619.                                         newEffect.envelopeRT.Set(motorNode->haveAttr("envelope") ? motorNode->getAttr("envelope") : "");
  620.                                         motorNode->getAttr("frequency", newEffect.frequencyRT);
  621.                                 }
  622.                         }
  623.  
  624.                         newEffect.frequencyA = (float)__fsel(-newEffect.frequencyA, 1.0f, newEffect.frequencyA);
  625.                         newEffect.frequencyB = (float)__fsel(-newEffect.frequencyB, 1.0f, newEffect.frequencyB);
  626.                         newEffect.frequencyLT = (float)__fsel(-newEffect.frequencyLT, 1.0f, newEffect.frequencyLT);
  627.                         newEffect.frequencyRT = (float)__fsel(-newEffect.frequencyRT, 1.0f, newEffect.frequencyRT);
  628.  
  629.                         m_effects.push_back(newEffect);
  630.                         m_effectNames.push_back(effectName);
  631.  
  632.                         FFBInternalId internalId;
  633.                         internalId.Set(effectName);
  634.                         m_effectToIndexMap.insert(TEffectToIndexMap::value_type(internalId, ((int)m_effects.size() - 1)));
  635.                 }
  636.         }
  637. }
  638.  
  639. int CForceFeedBackSystem::ParseSampleBuffer(const TSamplesBuffer& buffer, float* outputValues, const int maxOutputValues)
  640. {
  641.         int tokenStart = 0;
  642.         int tokenEnd = 0;
  643.         int samplesFound = 0;
  644.  
  645.         for (int i = 0; i < maxOutputValues; ++i)
  646.         {
  647.                 tokenEnd = buffer.find(",", tokenStart);
  648.                 if (tokenEnd != buffer.npos)
  649.                 {
  650.                         const int charCount = tokenEnd - tokenStart;
  651.                         samplesFound++;
  652.                         outputValues[i] = (float)atof(buffer.substr(tokenStart, charCount).c_str());
  653.                         tokenStart = tokenEnd + 1;
  654.                 }
  655.                 else
  656.                 {
  657.                         //Last token
  658.                         const int charCount = buffer.length() - tokenStart;
  659.                         samplesFound++;
  660.                         outputValues[i] = (float)atof(buffer.substr(tokenStart, charCount).c_str());
  661.                         break;
  662.                 }
  663.         }
  664.  
  665.         return samplesFound;
  666. }
  667.  
  668. void CForceFeedBackSystem::DistributeSamples(const float* sampleInput, const int sampleInputCount, uint16* sampleOutput, const int sampleOutputCount)
  669. {
  670.         const int sampleDistributionStep = (sampleOutputCount / sampleInputCount);
  671.         const int sampleIterations = ((sampleInputCount % 2) == 0) ? (sampleInputCount / 2) : (sampleInputCount / 2) + 1;
  672.  
  673.         int lastStartOffsetIdx = 0;
  674.         int lastEndOffsetIdx = (sampleOutputCount - 1);
  675.  
  676.         for (int i = 0; i < sampleIterations; ++i)
  677.         {
  678.                 const int startOffsetIdx = sampleDistributionStep * i;
  679.                 const int endOffsetIdx = sampleOutputCount - 1 - startOffsetIdx;
  680.  
  681.                 CRY_ASSERT((startOffsetIdx >= 0) && (startOffsetIdx < sampleOutputCount));
  682.                 CRY_ASSERT((endOffsetIdx >= 0) && (endOffsetIdx < sampleOutputCount));
  683.  
  684.                 sampleOutput[startOffsetIdx] = (uint16)(clamp_tpl(sampleInput[i], 0.0f, 1.0f) * 65535.0f);
  685.                 sampleOutput[endOffsetIdx] = (uint16)(clamp_tpl(sampleInput[sampleInputCount - 1 - i], 0.0f, 1.0f) * 65535.0f);
  686.  
  687.                 // Fill values in between, left side
  688.                 if (lastStartOffsetIdx < startOffsetIdx)
  689.                 {
  690.                         const int startValue = sampleOutput[lastStartOffsetIdx];
  691.                         const int step = (sampleOutput[startOffsetIdx] - sampleOutput[lastStartOffsetIdx]) / (startOffsetIdx - lastStartOffsetIdx);
  692.                         for (int j = lastStartOffsetIdx; j < startOffsetIdx; ++j)
  693.                         {
  694.                                 sampleOutput[j] = startValue + ((j - lastStartOffsetIdx) * step);
  695.                         }
  696.                 }
  697.  
  698.                 // ...and right side
  699.                 if (endOffsetIdx < lastEndOffsetIdx)
  700.                 {
  701.                         const int startValue = sampleOutput[endOffsetIdx];
  702.                         const int step = (sampleOutput[lastEndOffsetIdx] - sampleOutput[endOffsetIdx]) / (lastEndOffsetIdx - endOffsetIdx);
  703.                         for (int j = endOffsetIdx; j < lastEndOffsetIdx; ++j)
  704.                         {
  705.                                 sampleOutput[j] = startValue + ((j - endOffsetIdx) * step);
  706.                         }
  707.                 }
  708.  
  709.                 //Last iteration, requires to fill the remaining ones in the middle
  710.                 if (i == (sampleIterations - 1))
  711.                 {
  712.                         if (startOffsetIdx < endOffsetIdx)
  713.                         {
  714.                                 const int startValue = sampleOutput[startOffsetIdx];
  715.                                 const int step = (sampleOutput[endOffsetIdx] - sampleOutput[startOffsetIdx]) / (endOffsetIdx - startOffsetIdx);
  716.                                 for (int j = startOffsetIdx; j < endOffsetIdx; ++j)
  717.                                 {
  718.                                         sampleOutput[j] = startValue + ((j - startOffsetIdx) * step);
  719.                                 }
  720.                         }
  721.                 }
  722.  
  723.                 lastStartOffsetIdx = startOffsetIdx;
  724.                 lastEndOffsetIdx = endOffsetIdx;
  725.  
  726.         }
  727. }
  728.  
  729. const CForceFeedBackSystem::SPattern& CForceFeedBackSystem::FindPattern(const FFBInternalId& id) const
  730. {
  731.         TPatternsVector::const_iterator citEnd = m_patters.end();
  732.  
  733.         for (TPatternsVector::const_iterator cit = m_patters.begin(); ((cit != citEnd) && (id >= cit->m_patternId)); ++cit)
  734.         {
  735.                 if (cit->m_patternId != id)
  736.                         continue;
  737.  
  738.                 return (*cit);
  739.         }
  740.  
  741.         return m_defaultPattern;
  742. }
  743.  
  744. const CForceFeedBackSystem::SEnvelope& CForceFeedBackSystem::FindEnvelope(const FFBInternalId& id) const
  745. {
  746.         TEnvelopesVector::const_iterator citEnd = m_envelopes.end();
  747.  
  748.         for (TEnvelopesVector::const_iterator cit = m_envelopes.begin(); ((cit != citEnd) && (id >= cit->m_envelopeId)); ++cit)
  749.         {
  750.                 if (cit->m_envelopeId != id)
  751.                         continue;
  752.  
  753.                 return (*cit);
  754.         }
  755.  
  756.         return m_defaultEnvelope;
  757. }
  758.  
  759. //////////////////////////////////////////////////////////////////////////
  760. //////////////////////////////////////////////////////////////////////////
  761.  
  762. namespace
  763. {
  764. void FFSReload(IConsoleCmdArgs* pArgs)
  765. {
  766.         CForceFeedBackSystem* pFFS = static_cast<CForceFeedBackSystem*>(CCryAction::GetCryAction()->GetIForceFeedbackSystem());
  767.  
  768.         if (pFFS)
  769.         {
  770.                 pFFS->Reload();
  771.         }
  772. }
  773.  
  774. void FFSPlayEffect(IConsoleCmdArgs* pArgs)
  775. {
  776.         CForceFeedBackSystem* pFFS = static_cast<CForceFeedBackSystem*>(CCryAction::GetCryAction()->GetIForceFeedbackSystem());
  777.  
  778.         if (pFFS)
  779.         {
  780.                 if (pArgs->GetArgCount() >= 2)
  781.                 {
  782.                         ForceFeedbackFxId fxId = pFFS->GetEffectIdByName(pArgs->GetArg(1));
  783.                         const float intensity = (pArgs->GetArgCount() >= 3) ? (float)atof(pArgs->GetArg(2)) : 1.0f;
  784.                         const float delay = (pArgs->GetArgCount() >= 4) ? (float)atof(pArgs->GetArg(3)) : 0.0f;
  785.                         pFFS->PlayForceFeedbackEffect(fxId, SForceFeedbackRuntimeParams(intensity, delay));
  786.                 }
  787.         }
  788. }
  789.  
  790. void FFSStopAllEffects(IConsoleCmdArgs* pArgs)
  791. {
  792.         CForceFeedBackSystem* pFFS = static_cast<CForceFeedBackSystem*>(CCryAction::GetCryAction()->GetIForceFeedbackSystem());
  793.  
  794.         if (pFFS)
  795.         {
  796.                 pFFS->StopAllEffects();
  797.         }
  798. }
  799.  
  800. };
  801.  
  802. SForceFeedbackSystemCVars::SForceFeedbackSystemCVars()
  803. {
  804.         REGISTER_CVAR(ffs_debug, 0, 0, "Turns on/off force feedback system debug.");
  805.  
  806.         REGISTER_COMMAND("ffs_PlayEffect", FFSPlayEffect, 0, "Play force feedback effect, passed by name as first parameter");
  807.         REGISTER_COMMAND("ffs_StopAllEffects", FFSStopAllEffects, 0, "Stop force feedback effect, passed by name as first parameter");
  808.         REGISTER_COMMAND("ffs_Reload", FFSReload, 0, "Reload force feedback system data");
  809. }
  810.  
  811. SForceFeedbackSystemCVars::~SForceFeedbackSystemCVars()
  812. {
  813.         IConsole* pConsole = gEnv->pConsole;
  814.  
  815.         if (pConsole)
  816.         {
  817.                 pConsole->UnregisterVariable("ffs_debug", true);
  818.  
  819.                 pConsole->RemoveCommand("ffs_PlayEffect");
  820.                 pConsole->RemoveCommand("ffs_StopAllEffects");
  821.                 pConsole->RemoveCommand("ffs_Reload");
  822.         }
  823. }
  824.  
  825. //////////////////////////////////////////////////////////////////////////
  826. //////////////////////////////////////////////////////////////////////////
  827.  
  828. CForceFeedBackSystem::SFFOutput CForceFeedBackSystem::SActiveEffect::Update(float frameTime)
  829. {
  830.         SFFOutput effectFF;
  831.  
  832.         bool canPlay = (runtimeParams.delay <= 0.0f);
  833.  
  834.         if (canPlay)
  835.         {
  836.                 bool isLoopingEffect = (effectTime <= 0.0f);
  837.  
  838.                 const float effectTimeInv = !isLoopingEffect ? (float)__fres(effectTime) : 1.0f;
  839.                 const float sampleTime = runningTime * effectTimeInv;
  840.  
  841.                 const float sampleTimeAAtFreq = sampleTime * frequencyA;
  842.                 const float sampleTimeAAtFreqNorm = clamp_tpl(sampleTimeAAtFreq - floor_tpl(sampleTimeAAtFreq), 0.0f, 1.0f);
  843.  
  844.                 const float sampleTimeBAtFreq = sampleTime * frequencyB;
  845.                 const float sampleTimeBAtFreqNorm = clamp_tpl(sampleTimeBAtFreq - floor_tpl(sampleTimeBAtFreq), 0.0f, 1.0f);
  846.  
  847.                 const float sampleTimeLTAtFreq = sampleTime * frequencyLT;
  848.                 const float sampleTimeLTAtFreqNorm = clamp_tpl(sampleTimeLTAtFreq - floor_tpl(sampleTimeLTAtFreq), 0.0f, 1.0f);
  849.  
  850.                 const float sampleTimeRTAtFreq = sampleTime * frequencyRT;
  851.                 const float sampleTimeRTAtFreqNorm = clamp_tpl(sampleTimeRTAtFreq - floor_tpl(sampleTimeRTAtFreq), 0.0f, 1.0f);
  852.  
  853.                 effectFF.forceFeedbackA = m_patternA.SamplePattern(sampleTimeAAtFreqNorm) * m_envelopeA.SampleEnvelope(sampleTime) * runtimeParams.intensity;
  854.                 effectFF.forceFeedbackB = m_patternB.SamplePattern(sampleTimeBAtFreqNorm) * m_envelopeB.SampleEnvelope(sampleTime) * runtimeParams.intensity;
  855.                 effectFF.forceFeedbackLT = m_patternLT.SamplePattern(sampleTimeLTAtFreqNorm) * m_envelopeLT.SampleEnvelope(sampleTime) * runtimeParams.intensity;
  856.                 effectFF.forceFeedbackRT = m_patternRT.SamplePattern(sampleTimeRTAtFreqNorm) * m_envelopeRT.SampleEnvelope(sampleTime) * runtimeParams.intensity;
  857.                 runningTime += frameTime;
  858.  
  859.                 //Re-start the loop
  860.                 if (isLoopingEffect)
  861.                 {
  862.                         runningTime = (float)__fsel(1.0f - runningTime, runningTime, 0.0f);
  863.                 }
  864.         }
  865.         else
  866.         {
  867.                 runtimeParams.delay = clamp_tpl(runtimeParams.delay - frameTime, 0.0f, runtimeParams.delay);
  868.         }
  869.  
  870.         return effectFF;
  871. }
  872.  
  873. //////////////////////////////////////////////////////////////////////////
  874. //////////////////////////////////////////////////////////////////////////
  875. // calls callback once for each effect
  876.  
  877. void CForceFeedBackSystem::EnumerateEffects(IFFSPopulateCallBack* pCallBack)
  878. {
  879.         TEffectNamesArray::const_iterator iter = m_effectNames.begin();
  880.  
  881.         while (iter != m_effectNames.end())
  882.         {
  883.                 const char* const pName = iter->c_str();
  884.                 pCallBack->AddFFSEffectName(pName);
  885.                 ++iter;
  886.         }
  887. }
  888.  
  889. int CForceFeedBackSystem::GetEffectNamesCount() const
  890. {
  891.         return m_effectNames.size();
  892. }
  893.  
  894. void CForceFeedBackSystem::SuppressEffects(bool bSuppressEffects)
  895. {
  896.         if (bSuppressEffects)
  897.         {
  898.                 if (m_effectLock == 0)
  899.                         StopAllEffects();
  900.  
  901.                 m_effectLock++;
  902.         }
  903.         else
  904.                 m_effectLock--;
  905.  
  906.         CryLog("[FFB] ForceFeedback EffectLock now: %d was %d", m_effectLock, bSuppressEffects ? m_effectLock - 1 : m_effectLock + 1);
  907. }
  908.  
downloadForceFeedbackSystem.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