From 60f112d11c00390c58e8b2c16b2a913981d99902 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 20 Feb 2019 22:55:40 +0400 Subject: [PATCH] Add support for NiRollController (feature #4675) --- CHANGELOG.md | 1 + components/nif/controller.cpp | 12 ++++++++++ components/nif/controller.hpp | 9 +++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 1 + components/nifosg/controller.cpp | 40 ++++++++++++++++++++++++++++++++ components/nifosg/controller.hpp | 16 +++++++++++++ components/nifosg/nifloader.cpp | 11 +++++++++ 8 files changed, 91 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c3eba7e5..ec43e9e52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Feature #3610: Option to invert X axis Feature #4209: Editor: Faction rank sub-table Feature #4673: Weapon sheathing + Feature #4675: Support for NiRollController Feature #4730: Native animated containers support Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 26c3f43f0..6de720b52 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -173,6 +173,18 @@ namespace Nif data.post(nif); } + void NiRollController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiRollController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + void NiGeomMorpherController::read(NIFStream *nif) { Controller::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 7a05b0715..113a7becd 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -136,6 +136,15 @@ public: void post(NIFFile *nif); }; +class NiRollController : public Controller +{ +public: + NiFloatDataPtr data; + + void read(NIFStream *nif); + void post(NIFFile *nif); +}; + class NiGeomMorpherController : public Controller { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 66bbfdb65..0519e0cc6 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -73,6 +73,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiGeomMorpherController", &construct , RC_NiGeomMorpherController )); newFactory.insert(makeEntry("NiKeyframeController", &construct , RC_NiKeyframeController )); newFactory.insert(makeEntry("NiAlphaController", &construct , RC_NiAlphaController )); + newFactory.insert(makeEntry("NiRollController", &construct , RC_NiRollController )); newFactory.insert(makeEntry("NiUVController", &construct , RC_NiUVController )); newFactory.insert(makeEntry("NiPathController", &construct , RC_NiPathController )); newFactory.insert(makeEntry("NiMaterialColorController", &construct , RC_NiMaterialColorController )); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index ee4d508ab..4a044ac47 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiGeomMorpherController, RC_NiKeyframeController, RC_NiAlphaController, + RC_NiRollController, RC_NiUVController, RC_NiPathController, RC_NiMaterialColorController, diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 83841e0e5..934b3b914 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -309,6 +309,46 @@ void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) traverse(node, nv); } +RollController::RollController(const Nif::NiFloatData *data) + : mData(data->mKeyList, 1.f) +{ +} + +RollController::RollController() +{ +} + +RollController::RollController(const RollController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mData(copy.mData) + , mStartingTime(0) +{ +} + +void RollController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + traverse(node, nv); + + if (hasInput()) + { + double newTime = nv->getFrameStamp()->getSimulationTime(); + double duration = newTime - mStartingTime; + mStartingTime = newTime; + + float value = mData.interpKey(getInputValue(nv)); + osg::MatrixTransform* transform = static_cast(node); + osg::Matrix matrix = transform->getMatrix(); + + // Rotate around "roll" axis. + // Note: in original game rotation speed is the framerate-dependent in a very tricky way. + // Do not replicate this behaviour until we will really need it. + // For now consider controller's current value as an angular speed in radians per 1/60 seconds. + matrix = osg::Matrix::rotate(value * duration * 60.f, 0, 0, 1) * matrix; + transform->setMatrix(matrix); + } +} + AlphaController::AlphaController(const Nif::NiFloatData *data) : mData(data->mKeyList, 1.f) { diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 0e87af44f..36217f31a 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -246,6 +246,22 @@ namespace NifOsg virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; + class RollController : public osg::NodeCallback, public SceneUtil::Controller + { + private: + FloatInterpolator mData; + double mStartingTime; + + public: + RollController(const Nif::NiFloatData *data); + RollController(); + RollController(const RollController& copy, const osg::CopyOp& copyop); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); + + META_Object(NifOsg, RollController) + }; + class AlphaController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller { private: diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a2dad247d..f2403dd61 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -697,6 +697,10 @@ namespace NifOsg { handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); } + else if (ctrl->recType == Nif::RC_NiRollController) + { + handleRollController(static_cast(ctrl.getPtr()), transformNode, animflags); + } else Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } @@ -709,6 +713,13 @@ namespace NifOsg node->addUpdateCallback(callback); } + void handleRollController(const Nif::NiRollController* rollctrl, osg::Node* node, int animflags) + { + osg::ref_ptr callback(new RollController(rollctrl->data.getPtr())); + setupController(rollctrl, callback, animflags); + node->addUpdateCallback(callback); + } + void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next)