diff --git a/apps/nifosgtest/test.cpp b/apps/nifosgtest/test.cpp index 7f9a7ce3f4..fee9197871 100644 --- a/apps/nifosgtest/test.cpp +++ b/apps/nifosgtest/test.cpp @@ -112,15 +112,11 @@ int main(int argc, char** argv) //osgDB::writeNodeFile(*newNode, "out.osg"); - std::vector controllers; osg::Group* newNode = new osg::Group; NifOsg::Loader loader; loader.resourceManager = &resourceMgr; loader.loadAsSkeleton(nif, newNode); - for (unsigned int i=0; iaddChild(trans); @@ -137,6 +133,8 @@ int main(int argc, char** argv) viewer.setCameraManipulator(new osgGA::TrackballManipulator()); viewer.addEventHandler(new WireframeKeyHandler(root)); + //viewer.getCamera()->setCullMask() + // We're going to change this from the event callback, set the variance to DYNAMIC so that // we don't interfere with the draw thread. root->getOrCreateStateSet()->setDataVariance(osg::Node::DYNAMIC); @@ -148,9 +146,6 @@ int main(int argc, char** argv) //trans->setAttitude(osg::Quat(viewer.getFrameStamp()->getSimulationTime()*5, osg::Vec3f(0,0,1))); viewer.frame(); - - for (unsigned int i=0; igetFrameStamp()->getReferenceTime(); + float dt = static_cast(time - mLastTime); + mLastTime = time; + return dt; +} + +KeyframeController::KeyframeController() +{ +} + +KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mRotations(copy.mRotations) + , mXRotations(copy.mXRotations) + , mYRotations(copy.mYRotations) + , mZRotations(copy.mZRotations) + , mTranslations(copy.mTranslations) + , mScales(copy.mScales) + , mNif(copy.mNif) + , mInitialQuat(copy.mInitialQuat) + , mInitialScale(copy.mInitialScale) +{ +} + +KeyframeController::KeyframeController(const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, + osg::Quat initialQuat, float initialScale) + : mRotations(&data->mRotations) + , mXRotations(&data->mXRotations) + , mYRotations(&data->mYRotations) + , mZRotations(&data->mZRotations) + , mTranslations(&data->mTranslations) + , mScales(&data->mScales) + , mNif(nif) + , mInitialQuat(initialQuat) + , mInitialScale(initialScale) +{ } + +osg::Quat KeyframeController::interpKey(const Nif::QuaternionKeyMap::MapType &keys, float time) { if(time <= keys.begin()->first) return keys.begin()->second.mValue; @@ -81,7 +127,7 @@ osg::Quat KeyframeControllerValue::interpKey(const Nif::QuaternionKeyMap::MapTyp return keys.rbegin()->second.mValue; } -osg::Quat KeyframeControllerValue::getXYZRotation(float time) const +osg::Quat KeyframeController::getXYZRotation(float time) const { float xrot = interpKey(mXRotations->mKeys, time); float yrot = interpKey(mYRotations->mKeys, time); @@ -92,96 +138,108 @@ osg::Quat KeyframeControllerValue::getXYZRotation(float time) const return (zr*yr*xr); } -KeyframeControllerValue::KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr &nif, const Nif::NiKeyframeData *data, - osg::Quat initialQuat, float initialScale) - : NodeTargetValue(target) - , mRotations(&data->mRotations) - , mXRotations(&data->mXRotations) - , mYRotations(&data->mYRotations) - , mZRotations(&data->mZRotations) - , mTranslations(&data->mTranslations) - , mScales(&data->mScales) - , mNif(nif) - , mInitialQuat(initialQuat) - , mInitialScale(initialScale) -{ } - -osg::Vec3f KeyframeControllerValue::getTranslation(float time) const +osg::Vec3f KeyframeController::getTranslation(float time) const { if(mTranslations->mKeys.size() > 0) return interpKey(mTranslations->mKeys, time); - osg::MatrixTransform* trans = static_cast(mNode); - return trans->getMatrix().getTrans(); + return osg::Vec3f(); } -void KeyframeControllerValue::setValue(float time) +void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) { - osg::MatrixTransform* trans = static_cast(mNode); - osg::Matrix mat = trans->getMatrix(); - - if(mRotations->mKeys.size() > 0) - mat.setRotate(interpKey(mRotations->mKeys, time)); - else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) - mat.setRotate(getXYZRotation(time)); - else - mat.setRotate(mInitialQuat); - - // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) - float scale = mInitialScale; - if(mScales->mKeys.size() > 0) - scale = interpKey(mScales->mKeys, time); + if (hasInput()) + { + osg::MatrixTransform* trans = static_cast(node); + osg::Matrix mat = trans->getMatrix(); + + float time = getInputValue(nv); + + if(mRotations->mKeys.size() > 0) + mat.setRotate(interpKey(mRotations->mKeys, time)); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + mat.setRotate(getXYZRotation(time)); + else + mat.setRotate(mInitialQuat); + + // let's hope no one's using multiple KeyframeControllers on the same node (not that would make any sense...) + float scale = mInitialScale; + if(mScales->mKeys.size() > 0) + scale = interpKey(mScales->mKeys, time); + + for (int i=0;i<3;++i) + for (int j=0;j<3;++j) + mat(i,j) *= scale; + + if(mTranslations->mKeys.size() > 0) + mat.setTrans(interpKey(mTranslations->mKeys, time)); + trans->setMatrix(mat); + } - for (int i=0;i<3;++i) - for (int j=0;j<3;++j) - mat(i,j) *= scale; + traverse(node, nv); +} - if(mTranslations->mKeys.size() > 0) - mat.setTrans(interpKey(mTranslations->mKeys, time)); - trans->setMatrix(mat); +Controller::Controller() +{ } -Controller::Controller(boost::shared_ptr src, boost::shared_ptr dest, boost::shared_ptr function) - : mSource(src) - , mDestValue(dest) - , mFunction(function) +bool Controller::hasInput() const { + return mSource.get() != NULL; +} +float Controller::getInputValue(osg::NodeVisitor* nv) +{ + return mFunction->calculate(mSource->getValue(nv)); } -void Controller::update() +GeomMorpherController::GeomMorpherController() { - if (mSource.get()) - { - mDestValue->setValue(mFunction->calculate(mSource->getValue())); - } } -GeomMorpherControllerValue::GeomMorpherControllerValue(osgAnimation::MorphGeometry *geom, const Nif::NiMorphData* morphData) - : mGeom(geom) - , mMorphs(morphData->mMorphs) +GeomMorpherController::GeomMorpherController(const GeomMorpherController ©, const osg::CopyOp ©op) + : osg::Drawable::UpdateCallback(copy, copyop) + , Controller(copy) + , mMorphs(copy.mMorphs) { +} +GeomMorpherController::GeomMorpherController(const Nif::NiMorphData *data) + : mMorphs(data->mMorphs) +{ } -void GeomMorpherControllerValue::setValue(float time) +void GeomMorpherController::update(osg::NodeVisitor *nv, osg::Drawable *drawable) { - if (mMorphs.size() <= 1) - return; - int i = 0; - for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + osgAnimation::MorphGeometry* morphGeom = dynamic_cast(drawable); + if (morphGeom) { - float val = 0; - if (!it->mData.mKeys.empty()) - val = interpKey(it->mData.mKeys, time); - val = std::max(0.f, std::min(1.f, val)); - - mGeom->setWeight(i, val); + if (hasInput()) + { + if (mMorphs.size() <= 1) + return; + float input = getInputValue(nv); + int i = 0; + for (std::vector::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i) + { + float val = 0; + if (!it->mData.mKeys.empty()) + val = interpKey(it->mData.mKeys, input); + val = std::max(0.f, std::min(1.f, val)); + + morphGeom->setWeight(i, val); + } + } + + morphGeom->transformSoftwareMethod(); } } -UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData *data, std::set textureUnits) - : mStateSet(target) - , mUTrans(data->mKeyList[0]) +UVController::UVController() +{ +} + +UVController::UVController(const Nif::NiUVData *data, std::set textureUnits) + : mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) , mUScale(data->mKeyList[2]) , mVScale(data->mKeyList[3]) @@ -189,26 +247,58 @@ UVControllerValue::UVControllerValue(osg::StateSet *target, const Nif::NiUVData { } -void UVControllerValue::setValue(float value) +UVController::UVController(const UVController& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), Controller(copy) + , mUTrans(copy.mUTrans) + , mVTrans(copy.mVTrans) + , mUScale(copy.mUScale) + , mVScale(copy.mVScale) + , mTextureUnits(copy.mTextureUnits) { - float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); - float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); - float uScale = interpKey(mUScale.mKeys, value, 1.0f); - float vScale = interpKey(mVScale.mKeys, value, 1.0f); - - osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); - mat.setTrans(uTrans, vTrans, 0); - - osg::TexMat* texMat = new osg::TexMat; - texMat->setMatrix(mat); +} - for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) +void UVController::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) { - mStateSet->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + osg::StateSet* stateset = node->getStateSet(); + float value = getInputValue(nv); + float uTrans = interpKey(mUTrans.mKeys, value, 0.0f); + float vTrans = interpKey(mVTrans.mKeys, value, 0.0f); + float uScale = interpKey(mUScale.mKeys, value, 1.0f); + float vScale = interpKey(mVScale.mKeys, value, 1.0f); + + osg::Matrixf mat = osg::Matrixf::scale(uScale, vScale, 1); + mat.setTrans(uTrans, vTrans, 0); + + osg::TexMat* texMat = new osg::TexMat; + texMat->setMatrix(mat); + + for (std::set::const_iterator it = mTextureUnits.begin(); it != mTextureUnits.end(); ++it) + { + stateset->setTextureAttributeAndModes(*it, texMat, osg::StateAttribute::ON); + } } + traverse(node, nv); +} + +VisController::VisController(const Nif::NiVisData *data) + : mData(data->mVis) +{ +} + +VisController::VisController() +{ +} + +VisController::VisController(const VisController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mData(copy.mData) +{ } -bool VisControllerValue::calculate(float time) const +bool VisController::calculate(float time) const { if(mData.size() == 0) return true; @@ -221,77 +311,140 @@ bool VisControllerValue::calculate(float time) const return mData.back().isSet; } -void VisControllerValue::setValue(float time) +void VisController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + bool vis = calculate(getInputValue(nv)); + node->setNodeMask(vis ? ~0 : 0); + } + traverse(node, nv); +} + +AlphaController::AlphaController(const Nif::NiFloatData *data) + : mData(data->mKeyList) { - bool vis = calculate(time); - mNode->setNodeMask(vis ? ~0 : 0); + } -AlphaControllerValue::AlphaControllerValue(osg::StateSet *target, const Nif::NiFloatData *data) - : mTarget(target) - , mData(data->mKeyList) +AlphaController::AlphaController() { } -void AlphaControllerValue::setValue(float time) +AlphaController::AlphaController(const AlphaController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), ValueInterpolator(), Controller(copy) { - float value = interpKey(mData.mKeys, time); - osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); - if (!mat) - return; +} - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.a() = value; - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +void AlphaController::operator () (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + float value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.a() = value; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + } + } + traverse(node, nv); } -MaterialColorControllerValue::MaterialColorControllerValue(osg::StateSet *target, const Nif::NiPosData *data) - : mTarget(target), mData(data->mKeyList) +MaterialColorController::MaterialColorController(const Nif::NiPosData *data) + : mData(data->mKeyList) { +} +MaterialColorController::MaterialColorController() +{ } -void MaterialColorControllerValue::setValue(float time) +MaterialColorController::MaterialColorController(const MaterialColorController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop), Controller(copy) + , mData(copy.mData) { - osg::Vec3f value = interpKey(mData.mKeys, time); - osg::Material* mat = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::MATERIAL)); - if (!mat) - return; +} - osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); - diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); - mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +void MaterialColorController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osg::StateSet* stateset = node->getStateSet(); + osg::Vec3f value = interpKey(mData.mKeys, getInputValue(nv)); + osg::Material* mat = dynamic_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + if (mat) + { + osg::Vec4f diffuse = mat->getDiffuse(osg::Material::FRONT_AND_BACK); + diffuse.set(value.x(), value.y(), value.z(), diffuse.a()); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); + } + } + traverse(node, nv); } -FlipControllerValue::FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController *ctrl, - std::vector > textures) +FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) : mTexSlot(ctrl->mTexSlot) , mDelta(ctrl->mDelta) , mTextures(textures) - , mTarget(target) { } -void FlipControllerValue::setValue(float time) +FlipController::FlipController() +{ +} + +FlipController::FlipController(const FlipController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mTexSlot(copy.mTexSlot) + , mDelta(copy.mDelta) + , mTextures(copy.mTextures) { - if (mDelta == 0) - return; - int curTexture = int(time / mDelta) % mTextures.size(); - osg::Texture2D* tex = dynamic_cast(mTarget->getAttribute(osg::StateAttribute::TEXTURE)); - if (!tex) - return; - tex->setImage(mTextures[curTexture].get()); } -ParticleSystemControllerValue::ParticleSystemControllerValue(osgParticle::Emitter *emitter, const Nif::NiParticleSystemController *ctrl) - : mEmitter(emitter), mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +void FlipController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput() && mDelta != 0) + { + osg::StateSet* stateset = node->getStateSet(); + int curTexture = int(getInputValue(nv) / mDelta) % mTextures.size(); + osg::Texture2D* tex = dynamic_cast(stateset->getAttribute(osg::StateAttribute::TEXTURE)); + if (tex) + tex->setImage(mTextures[curTexture].get()); + } + traverse(node, nv); +} + +ParticleSystemController::ParticleSystemController(const Nif::NiParticleSystemController *ctrl) + : mEmitStart(ctrl->startTime), mEmitStop(ctrl->stopTime) +{ +} + +ParticleSystemController::ParticleSystemController() { } -void ParticleSystemControllerValue::setValue(float time) +ParticleSystemController::ParticleSystemController(const ParticleSystemController ©, const osg::CopyOp ©op) + : osg::NodeCallback(copy, copyop) + , Controller(copy) + , mEmitStart(copy.mEmitStart) + , mEmitStop(copy.mEmitStop) { - mEmitter->setEnabled(time >= mEmitStart && time < mEmitStop); } +void ParticleSystemController::operator() (osg::Node* node, osg::NodeVisitor* nv) +{ + if (hasInput()) + { + osgParticle::ParticleProcessor* emitter = dynamic_cast(node); + float time = getInputValue(nv); + if (emitter) + emitter->setEnabled(time >= mEmitStart && time < mEmitStop); + } + traverse(node, nv); +} } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index c92a778165..5a9af6324d 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -17,6 +17,9 @@ #include #include +#include +#include +#include namespace osg @@ -93,76 +96,49 @@ namespace NifOsg class ControllerSource { public: - virtual float getValue() const = 0; + virtual float getValue(osg::NodeVisitor* nv) = 0; }; - // FIXME: Should return a dt instead of time class FrameTimeSource : public ControllerSource { public: - - virtual float getValue() const - { - return mTimer.time_s(); - } - + FrameTimeSource(); + virtual float getValue(osg::NodeVisitor* nv); private: - osg::Timer mTimer; - }; - - class ControllerValue - { - public: - virtual void setValue(float value) = 0; + double mLastTime; }; class Controller { public: - Controller (boost::shared_ptr src, boost::shared_ptr dest, - boost::shared_ptr function); + Controller(); + + bool hasInput() const; - virtual void update(); + float getInputValue(osg::NodeVisitor* nv); boost::shared_ptr mSource; - boost::shared_ptr mDestValue; // The source value gets passed through this function before it's passed on to the DestValue. boost::shared_ptr mFunction; }; - // FIXME: Should be with other general extensions. - class NodeTargetValue : public ControllerValue + class GeomMorpherController : public osg::Drawable::UpdateCallback, public Controller, public ValueInterpolator { - protected: - // TODO: get rid of target pointers, which are incompatible with a copy constructor we will need later - // instead, controllers can be a Node added as child of their target - osg::Node *mNode; - public: - NodeTargetValue(osg::Node *target) : mNode(target) - { } - - virtual osg::Vec3f getTranslation(float value) const = 0; - - osg::Node *getNode() const - { return mNode; } - }; + GeomMorpherController(const Nif::NiMorphData* data); + GeomMorpherController(); + GeomMorpherController(const GeomMorpherController& copy, const osg::CopyOp& copyop); - class GeomMorpherControllerValue : public ControllerValue, public ValueInterpolator - { - public: - // FIXME: don't copy the morph data? - GeomMorpherControllerValue(osgAnimation::MorphGeometry* geom, const Nif::NiMorphData *data); + META_Object(NifOsg, GeomMorpherController) - virtual void setValue(float time); + virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable); private: - osgAnimation::MorphGeometry* mGeom; std::vector mMorphs; }; - class KeyframeControllerValue : public NodeTargetValue, public ValueInterpolator + class KeyframeController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: const Nif::QuaternionKeyMap* mRotations; @@ -185,31 +161,39 @@ namespace NifOsg public: /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. - KeyframeControllerValue(osg::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, + KeyframeController(const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data, osg::Quat initialQuat, float initialScale); + KeyframeController(); + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, KeyframeController) virtual osg::Vec3f getTranslation(float time) const; - virtual void setValue(float time); + virtual void operator() (osg::Node*, osg::NodeVisitor*); }; - class UVControllerValue : public ControllerValue, ValueInterpolator + // Note we're using NodeCallback instead of StateSet::Callback because the StateSet callback doesn't support nesting + struct UVController : public osg::NodeCallback, public Controller, public ValueInterpolator { + public: + UVController(); + UVController(const UVController&,const osg::CopyOp& = osg::CopyOp::SHALLOW_COPY); + UVController(const Nif::NiUVData *data, std::set textureUnits); + + META_Object(NifOsg,UVController) + + virtual void operator() (osg::Node*, osg::NodeVisitor*); + private: - osg::StateSet* mStateSet; Nif::FloatKeyMap mUTrans; Nif::FloatKeyMap mVTrans; Nif::FloatKeyMap mUScale; Nif::FloatKeyMap mVScale; std::set mTextureUnits; - - public: - UVControllerValue(osg::StateSet* target, const Nif::NiUVData *data, std::set textureUnits); - - virtual void setValue(float value); }; - class VisControllerValue : public NodeTargetValue + class VisController : public osg::NodeCallback, public Controller { private: std::vector mData; @@ -217,65 +201,75 @@ namespace NifOsg bool calculate(float time) const; public: - VisControllerValue(osg::Node *target, const Nif::NiVisData *data) - : NodeTargetValue(target) - , mData(data->mVis) - { } + VisController(const Nif::NiVisData *data); + VisController(); + VisController(const VisController& copy, const osg::CopyOp& copyop); - virtual osg::Vec3f getTranslation(float time) const - { return osg::Vec3f(); } + META_Object(NifOsg, VisController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class AlphaControllerValue : public ControllerValue, public ValueInterpolator + class AlphaController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - osg::StateSet* mTarget; Nif::FloatKeyMap mData; public: - AlphaControllerValue(osg::StateSet* target, const Nif::NiFloatData *data); + AlphaController(const Nif::NiFloatData *data); + AlphaController(); + AlphaController(const AlphaController& copy, const osg::CopyOp& copyop); + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); - virtual void setValue(float time); + META_Object(NifOsg, AlphaController) }; - class MaterialColorControllerValue : public ControllerValue, public ValueInterpolator + class MaterialColorController : public osg::NodeCallback, public Controller, public ValueInterpolator { private: - osg::StateSet* mTarget; Nif::Vector3KeyMap mData; public: - MaterialColorControllerValue(osg::StateSet* target, const Nif::NiPosData *data); + MaterialColorController(const Nif::NiPosData *data); + MaterialColorController(); + MaterialColorController(const MaterialColorController& copy, const osg::CopyOp& copyop); - virtual void setValue(float time); + META_Object(NifOsg, MaterialColorController) + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; // untested - class FlipControllerValue : public ControllerValue + class FlipController : public osg::NodeCallback, public Controller { private: - osg::StateSet* mTarget; int mTexSlot; float mDelta; std::vector > mTextures; public: - FlipControllerValue(osg::StateSet* target, const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(); + FlipController(const FlipController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, FlipController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); }; - class ParticleSystemControllerValue : public ControllerValue + class ParticleSystemController : public osg::NodeCallback, public Controller { public: - ParticleSystemControllerValue(osgParticle::Emitter* emitter, const Nif::NiParticleSystemController* ctrl); + ParticleSystemController(const Nif::NiParticleSystemController* ctrl); + ParticleSystemController(); + ParticleSystemController(const ParticleSystemController& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, ParticleSystemController) - virtual void setValue(float time); + virtual void operator() (osg::Node* node, osg::NodeVisitor* nv); private: - osgParticle::Emitter* mEmitter; float mEmitStart; float mEmitStop; }; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a92baee790..26f0927b55 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -285,17 +285,13 @@ namespace NifOsg } } - void Loader::createController(const Nif::Controller *ctrl, boost::shared_ptr value, int animflags) + void Loader::setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags) { - // FIXME animflags currently not passed to this function //bool autoPlay = animflags & Nif::NiNode::AnimFlag_AutoPlay; - boost::shared_ptr src(new FrameTimeSource); // if autoPlay + //if (autoPlay) + toSetup->mSource = boost::shared_ptr(new FrameTimeSource); - boost::shared_ptr function (new ControllerFunction(ctrl - , 0/*autoPlay*/)); - //scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength); - - mControllers.push_back(Controller(src, value, function)); + toSetup->mFunction = boost::shared_ptr(new ControllerFunction(ctrl, 1 /*autoPlay*/)); } void Loader::handleNode(const Nif::Node* nifNode, osg::Group* parentNode, bool createSkeleton, @@ -308,7 +304,6 @@ namespace NifOsg transformNode = bone; bone->setMatrix(toMatrix(nifNode->trafo)); bone->setName(nifNode->name); - bone->setUpdateCallback(new UpdateBone); bone->setInvBindMatrixInSkeletonSpace(osg::Matrixf::inverse(getWorldTransform(nifNode))); } else @@ -332,6 +327,7 @@ namespace NifOsg // We could probably skip hidden nodes entirely if they don't have a VisController that // might make them visible later + // FIXME: this disables update callbacks, so VisController no longer works if (nifNode->flags & Nif::NiNode::Flag_Hidden) transformNode->setNodeMask(0); @@ -358,6 +354,10 @@ namespace NifOsg if (!nifNode->controller.empty()) handleNodeControllers(nifNode, transformNode, animflags); + // Added last so the changes from KeyframeControllers are taken into account + if (osgAnimation::Bone* bone = dynamic_cast(transformNode.get())) + bone->addUpdateCallback(new UpdateBone); + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -382,9 +382,12 @@ namespace NifOsg std::set texUnits; for (std::map::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) texUnits.insert(it->first); - boost::shared_ptr dest(new UVControllerValue(transformNode->getOrCreateStateSet() - , uvctrl->data.getPtr(), texUnits)); - createController(uvctrl, dest, animflags); + + osg::ref_ptr ctrl = new UVController(uvctrl->data.getPtr(), texUnits); + setupController(uvctrl, ctrl, animflags); + transformNode->getOrCreateStateSet()->setDataVariance(osg::StateSet::DYNAMIC); + + transformNode->addUpdateCallback(ctrl); } } } @@ -406,23 +409,27 @@ namespace NifOsg std::cerr << "Warning: multiple KeyframeControllers on the same node" << std::endl; continue; } - boost::shared_ptr dest(new KeyframeControllerValue(transformNode, mNif, key->data.getPtr(), - transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + osg::ref_ptr callback(new KeyframeController(mNif, key->data.getPtr(), + transformNode->getMatrix().getRotate(), nifNode->trafo.scale)); + + setupController(key, callback, animflags); + transformNode->addUpdateCallback(callback); - createController(key, dest, animflags); seenKeyframeCtrl = true; } } else if (ctrl->recType == Nif::RC_NiVisController) { const Nif::NiVisController* visctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new VisControllerValue(transformNode, visctrl->data.getPtr())); - createController(visctrl, dest, animflags); + + osg::ref_ptr callback(new VisController(visctrl->data.getPtr())); + setupController(visctrl, callback, animflags); + transformNode->addUpdateCallback(callback); } } } - void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::StateSet *stateset, int animflags) + void Loader::handleMaterialControllers(const Nif::Property *materialProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -431,21 +438,25 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiAlphaController) { const Nif::NiAlphaController* alphactrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new AlphaControllerValue(stateset, alphactrl->data.getPtr())); - createController(alphactrl, dest, animflags); + osg::ref_ptr ctrl(new AlphaController(alphactrl->data.getPtr())); + setupController(alphactrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } else if (ctrl->recType == Nif::RC_NiMaterialColorController) { const Nif::NiMaterialColorController* matctrl = static_cast(ctrl.getPtr()); - boost::shared_ptr dest(new MaterialColorControllerValue(stateset, matctrl->data.getPtr())); - createController(matctrl, dest, animflags); + osg::ref_ptr ctrl(new MaterialColorController(matctrl->data.getPtr())); + setupController(matctrl, ctrl, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(ctrl); } else std::cerr << "Unexpected material controller " << ctrl->recType << std::endl; } } - void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::StateSet *stateset, int animflags) + void Loader::handleTextureControllers(const Nif::Property *texProperty, osg::Node* node, osg::StateSet *stateset, int animflags) { for (Nif::ControllerPtr ctrl = texProperty->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -470,8 +481,10 @@ namespace NifOsg osgDB::ReaderWriter::ReadResult result = reader->readImage(*resourceManager->get(filename.c_str()), opts); textures.push_back(osg::ref_ptr(result.getImage())); } - boost::shared_ptr dest(new FlipControllerValue(stateset, flipctrl, textures)); - createController(flipctrl, dest, animflags); + osg::ref_ptr callback(new FlipController(flipctrl, textures)); + setupController(ctrl.getPtr(), callback, animflags); + stateset->setDataVariance(osg::StateSet::DYNAMIC); + node->addUpdateCallback(callback); } else std::cerr << "Unexpected texture controller " << ctrl->recName << std::endl; @@ -577,7 +590,9 @@ namespace NifOsg // If something ever violates this assumption, the worst that could happen is the culling being one frame late, which wouldn't be a disaster. parentNode->addChild(emitter); - createController(partctrl, boost::shared_ptr(new ParticleSystemControllerValue(emitter, partctrl)), animflags); + osg::ref_ptr callback(new ParticleSystemController(partctrl)); + setupController(partctrl, callback, animflags); + emitter->setUpdateCallback(callback); // ----------- affector (must be after emitters in the scene graph) osgParticle::ModularProgram* program = new osgParticle::ModularProgram; @@ -615,14 +630,16 @@ namespace NifOsg // ----------- + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(partsys); + std::vector materialProps; collectMaterialProperties(nifNode, materialProps); - applyMaterialProperties(partsys->getOrCreateStateSet(), materialProps, true, animflags); + applyMaterialProperties(geode, materialProps, true, animflags); partsys->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); partsys->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(partsys); + if (rf == osgParticle::ParticleProcessor::RELATIVE_RF) parentNode->addChild(geode); @@ -640,7 +657,7 @@ namespace NifOsg parentNode->addChild(updater); } - void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, const std::map& boundTextures, int animflags) + void Loader::triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Geode* parentGeode, const std::map& boundTextures, int animflags) { const Nif::NiTriShapeData* data = triShape->data.getPtr(); @@ -720,7 +737,7 @@ namespace NifOsg // above the actual renderable would be tedious. std::vector materialProps; collectMaterialProperties(triShape, materialProps); - applyMaterialProperties(geometry->getOrCreateStateSet(), materialProps, !data->colors.empty(), animflags); + applyMaterialProperties(parentGeode, materialProps, !data->colors.empty(), animflags); } void Loader::handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags) @@ -733,10 +750,11 @@ namespace NifOsg if(ctrl->recType == Nif::RC_NiGeomMorpherController && ctrl->flags & Nif::NiNode::ControllerFlag_Active) { geometry = handleMorphGeometry(static_cast(ctrl.getPtr())); - boost::shared_ptr value( - new GeomMorpherControllerValue(static_cast(geometry.get()), - static_cast(ctrl.getPtr())->data.getPtr())); - createController(ctrl.getPtr(), value, 0); + + osg::ref_ptr morphctrl = new GeomMorpherController( + static_cast(ctrl.getPtr())->data.getPtr()); + setupController(ctrl.getPtr(), morphctrl, animflags); + geometry->setUpdateCallback(morphctrl); break; } } while(!(ctrl=ctrl->next).empty()); @@ -744,9 +762,10 @@ namespace NifOsg if (!geometry.get()) geometry = new osg::Geometry; - triShapeToGeometry(triShape, geometry, boundTextures, animflags); osg::ref_ptr geode (new osg::Geode); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); + geode->addDrawable(geometry); parentNode->addChild(geode); @@ -754,8 +773,9 @@ namespace NifOsg void Loader::handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, const std::map& boundTextures, int animflags) { + osg::ref_ptr geode (new osg::Geode); osg::ref_ptr geometry (new osg::Geometry); - triShapeToGeometry(triShape, geometry, boundTextures, animflags); + triShapeToGeometry(triShape, geometry, geode, boundTextures, animflags); osg::ref_ptr rig(new osgAnimation::RigGeometry); rig->setSourceGeometry(geometry); @@ -795,7 +815,6 @@ namespace NifOsg osg::ref_ptr trans(new osg::MatrixTransform); trans->setUpdateCallback(new InvertBoneMatrix()); - osg::ref_ptr geode (new osg::Geode); geode->addDrawable(rig); trans->addChild(geode); @@ -987,7 +1006,7 @@ namespace NifOsg stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF); boundTextures.erase(i); } - handleTextureControllers(texprop, stateset, animflags); + handleTextureControllers(texprop, node, stateset, animflags); } break; } @@ -1003,9 +1022,11 @@ namespace NifOsg } } - void Loader::applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + void Loader::applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags) { + osg::StateSet* stateset = node->getOrCreateStateSet(); + int specFlags = 0; // Specular is disabled by default, even if there's a specular color in the NiMaterialProperty osg::Material* mat = new osg::Material; mat->setColorMode(hasVertexColors ? osg::Material::AMBIENT_AND_DIFFUSE : osg::Material::OFF); @@ -1032,7 +1053,7 @@ namespace NifOsg mat->setShininess(osg::Material::FRONT_AND_BACK, matprop->data.glossiness); if (!matprop->controller.empty()) - handleMaterialControllers(matprop, stateset, animflags); + handleMaterialControllers(matprop, node, stateset, animflags); break; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 7b38ce5607..5bd25f6ca7 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -9,8 +9,6 @@ #include -#include "controller.hpp" - namespace osg { class Geometry; @@ -25,10 +23,12 @@ namespace Nif class Node; class NiTriShape; class Property; + class Controller; } namespace NifOsg { + class Controller; /// The main class responsible for loading NIF files into an OSG-Scenegraph. class Loader @@ -41,9 +41,6 @@ namespace NifOsg const VFS::Manager* resourceManager; - // FIXME move - std::vector mControllers; - private: /// @param createSkeleton If true, use an osgAnimation::Bone for NIF nodes, otherwise an osg::MatrixTransform. @@ -54,9 +51,9 @@ namespace NifOsg void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags); - void handleMaterialControllers(const Nif::Property* materialProperty, osg::StateSet* stateset, int animflags); + void handleMaterialControllers(const Nif::Property* materialProperty, osg::Node* node, osg::StateSet* stateset, int animflags); - void handleTextureControllers(const Nif::Property* texProperty, osg::StateSet* stateset, int animflags); + void handleTextureControllers(const Nif::Property* texProperty, osg::Node* node, osg::StateSet* stateset, int animflags); void handleProperty (const Nif::Property* property, const Nif::Node* nifNode, osg::Node* node, std::map& boundTextures, int animflags); @@ -67,7 +64,7 @@ namespace NifOsg void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); // Fills the vertex data for the given TriShape into the given Geometry. - void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, const std::map& boundTextures, int animflags); + void triShapeToGeometry(const Nif::NiTriShape* triShape, osg::Geometry* geom, osg::Geode* parentGeode, const std::map& boundTextures, int animflags); // Creates a skinned osg::Geometry object for the given TriShape, populates it, and attaches it to the given node. void handleSkinnedTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, const std::map& boundTextures, int animflags); @@ -75,10 +72,11 @@ namespace NifOsg // Applies the Properties of the given nifNode onto the StateSet of the given OSG node. void applyNodeProperties(const Nif::Node* nifNode, osg::Node* applyTo, std::map& boundTextures, int animflags); - void applyMaterialProperties(osg::StateSet* stateset, const std::vector& properties, + void applyMaterialProperties(osg::Node* node, const std::vector& properties, bool hasVertexColors, int animflags); - void createController(const Nif::Controller* ctrl, boost::shared_ptr value, int animflags); + // Set up the default input and controller function for the given controller. + void setupController(const Nif::Controller* ctrl, Controller* toSetup, int animflags); Nif::NIFFilePtr mNif; diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index 58501763b2..f2f59195cf 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -39,6 +39,7 @@ ParticleShooter::ParticleShooter() } ParticleShooter::ParticleShooter(const osgParticle::Shooter ©, const osg::CopyOp ©op) + : osgParticle::Shooter(copy, copyop) { *this = copy; }