diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 9a4c1b065..c63c83676 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -123,12 +123,10 @@ namespace Nif { Controller::read(nif); - /* - int = 1 - 2xfloat - short = 0 or 1 - */ - nif->skip(14); + bankDir = nif->getInt(); + maxBankAngle = nif->getFloat(); + smoothing = nif->getFloat(); + followAxis = nif->getShort(); posData.read(nif); floatData.read(nif); } diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 364eff1cd..41dd14fac 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -96,6 +96,20 @@ public: NiPosDataPtr posData; NiFloatDataPtr floatData; + enum Flags + { + Flag_OpenCurve = 0x020, + Flag_AllowFlip = 0x040, + Flag_Bank = 0x080, + Flag_ConstVelocity = 0x100, + Flag_Follow = 0x200, + Flag_FlipFollowAxis = 0x400 + }; + + int bankDir; + float maxBankAngle, smoothing; + short followAxis; + void read(NIFStream *nif); void post(NIFFile *nif); }; diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 100aa234a..a088ead4c 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -521,4 +521,50 @@ void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv traverse(node, nv); } +PathController::PathController(const PathController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mPath(copy.mPath) + , mPercent(copy.mPercent) + , mFlags(copy.mFlags) +{ +} + +PathController::PathController(const Nif::NiPathController* ctrl) + : mPath(ctrl->posData->mKeyList, osg::Vec3f()) + , mPercent(ctrl->floatData->mKeyList, 1.f) + , mFlags(ctrl->flags) +{ +} + +float PathController::getPercent(float time) const +{ + float percent = mPercent.interpKey(time); + if (percent < 0.f) + percent = std::fmod(percent, 1.f) + 1.f; + else if (percent > 1.f) + percent = std::fmod(percent, 1.f); + return percent; +} + +void PathController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (mPath.empty() || mPercent.empty() || !hasInput()) + { + traverse(node, nv); + return; + } + + osg::MatrixTransform* trans = static_cast(node); + osg::Matrix mat = trans->getMatrix(); + + float time = getInputValue(nv); + float percent = getPercent(time); + osg::Vec3f pos(mPath.interpKey(percent)); + mat.setTrans(pos); + trans->setMatrix(mat); + + traverse(node, nv); +} + } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index ad6ee4d87..3f66013a2 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -342,6 +342,25 @@ namespace NifOsg float mEmitStop; }; + class PathController : public osg::NodeCallback, public SceneUtil::Controller + { + public: + PathController(const Nif::NiPathController* ctrl); + PathController() = default; + PathController(const PathController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, PathController) + + virtual void operator() (osg::Node*, osg::NodeVisitor*); + + private: + Vec3Interpolator mPath; + FloatInterpolator mPercent; + int mFlags{0}; + + float getPercent(float time) const; + }; + } #endif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index be39f7d55..650d8db94 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -752,6 +752,17 @@ namespace NifOsg node->addUpdateCallback(callback); } } + else if (ctrl->recType == Nif::RC_NiPathController) + { + const Nif::NiPathController *path = static_cast(ctrl.getPtr()); + if (!path->posData.empty() && !path->floatData.empty()) + { + osg::ref_ptr callback(new PathController(path)); + + setupController(path, callback, animflags); + node->addUpdateCallback(callback); + } + } else if (ctrl->recType == Nif::RC_NiVisController) { handleVisController(static_cast(ctrl.getPtr()), node, animflags); @@ -780,6 +791,17 @@ namespace NifOsg transformNode->addUpdateCallback(callback); } } + else if (ctrl->recType == Nif::RC_NiPathController) + { + const Nif::NiPathController *path = static_cast(ctrl.getPtr()); + if (!path->posData.empty() && !path->floatData.empty()) + { + osg::ref_ptr callback(new PathController(path)); + + setupController(path, callback, animflags); + transformNode->addUpdateCallback(callback); + } + } else if (ctrl->recType == Nif::RC_NiVisController) { handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags);