From e938fa4a9d832cffd69003fbb7f0d43a49c554f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 25 Mar 2015 18:12:04 +0100 Subject: [PATCH] Implement extrapolation mode in ControllerFunction (Bug #1871) --- components/nifosg/controller.cpp | 59 ++++++++++++++++++-------------- components/nifosg/controller.hpp | 15 ++++---- components/nifosg/nifloader.cpp | 4 +-- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index a31263d8b..6aa920553 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -18,50 +18,59 @@ namespace NifOsg { -ControllerFunction::ControllerFunction(const Nif::Controller *ctrl, bool deltaInput) - : mDeltaInput(deltaInput) - , mFrequency(ctrl->frequency) +ControllerFunction::ControllerFunction(const Nif::Controller *ctrl) + : mFrequency(ctrl->frequency) , mPhase(ctrl->phase) , mStartTime(ctrl->timeStart) , mStopTime(ctrl->timeStop) - , mDeltaCount(0.f) + , mExtrapolationMode(static_cast((ctrl->flags&0x6) >> 1)) { - if(mDeltaInput) - mDeltaCount = mPhase; } float ControllerFunction::calculate(float value) { - if(mDeltaInput) + float time = mFrequency * value + mPhase; + if (time >= mStartTime && time <= mStopTime) + return time; + switch (mExtrapolationMode) { - if (mStopTime - mStartTime == 0.f) - return 0.f; - - mDeltaCount += value*mFrequency; - if(mDeltaCount < mStartTime) - mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, - mStopTime - mStartTime); - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; + case Cycle: + { + float delta = mStopTime - mStartTime; + if ( delta <= 0 ) + return mStartTime; + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; + return mStartTime + remainder; } + case Reverse: + { + float delta = mStopTime - mStartTime; + if ( delta <= 0 ) + return mStartTime; + + float cycles = ( time - mStartTime ) / delta; + float remainder = ( cycles - std::floor( cycles ) ) * delta; - value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); - return value; + // Even number of cycles? + if ( ( static_cast(std::fabs( std::floor( cycles ) )) % 2 ) == 0 ) + return mStartTime + remainder; + + return mStopTime - remainder; + } + case Constant: + default: + return std::min(mStopTime, std::max(mStartTime, time)); + } } FrameTimeSource::FrameTimeSource() - : mLastTime(0.0) { } float FrameTimeSource::getValue(osg::NodeVisitor *nv) { - // TODO: dt could be computed globally instead of once per instance - double time = nv->getFrameStamp()->getReferenceTime(); - float dt = static_cast(time - mLastTime); - mLastTime = time; - return dt; + return nv->getFrameStamp()->getReferenceTime(); } KeyframeController::KeyframeController() diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c6ef74d2a..7579735ca 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -81,17 +81,20 @@ namespace NifOsg float mFrequency; float mPhase; float mStartTime; - bool mDeltaInput; - float mDeltaCount; - public: float mStopTime; + enum ExtrapolationMode + { + Cycle = 0, + Reverse = 1, + Constant = 2 + }; + ExtrapolationMode mExtrapolationMode; public: - ControllerFunction(const Nif::Controller *ctrl, bool deltaInput); + ControllerFunction(const Nif::Controller *ctrl); float calculate(float value); }; - typedef ControllerFunction DefaultFunction; class ControllerSource { @@ -104,8 +107,6 @@ namespace NifOsg public: FrameTimeSource(); virtual float getValue(osg::NodeVisitor* nv); - private: - double mLastTime; }; class Controller diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a15ad7416..17a669312 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -302,7 +302,7 @@ namespace const Nif::NiKeyframeController* keyframectrl = found->second; osg::ref_ptr callback(new NifOsg::SourcedKeyframeController(keyframectrl->data.getPtr(), mSourceIndex)); - callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl, false)); + callback->mFunction = boost::shared_ptr(new NifOsg::ControllerFunction(keyframectrl)); // Insert in front of the callback list, to make sure UpdateBone is last. // The order of SourcedKeyframeControllers doesn't matter since only one of them should be enabled at a time. @@ -490,7 +490,7 @@ namespace NifOsg //if (autoPlay) toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl)); } osg::ref_ptr handleNode(const Nif::Node* nifNode, bool createSkeleton,