From d2af7efc619e32b1cc1217b14ef89aa6215f1313 Mon Sep 17 00:00:00 2001 From: Cedric Pinson Date: Mon, 3 Aug 2009 09:48:12 +0000 Subject: [PATCH] From Cedric Pinson, Add UpdateMaterial callback to animate material\nUpdate LinkVisitor to traverse stateset\nUpdate ReaderWriter to read osgAnimation::UpdateMaterial Callback\nUpdate nathan.osg data file to demonstrate the MaterialAnimation --- include/osgAnimation/Bone | 7 +- include/osgAnimation/LinkVisitor | 9 ++ include/osgAnimation/MorphGeometry | 2 +- include/osgAnimation/UpdateCallback | 101 +++++++++++++++-- src/osgAnimation/Bone.cpp | 2 +- src/osgAnimation/LinkVisitor.cpp | 55 +++++++-- src/osgAnimation/MorphGeometry.cpp | 8 +- src/osgAnimation/UpdateCallback.cpp | 113 +++++++++++-------- src/osgPlugins/osgAnimation/ReaderWriter.cpp | 25 +++- 9 files changed, 242 insertions(+), 80 deletions(-) diff --git a/include/osgAnimation/Bone b/include/osgAnimation/Bone index 2c120396a..8c7a63d05 100644 --- a/include/osgAnimation/Bone +++ b/include/osgAnimation/Bone @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +92,7 @@ namespace osgAnimation }; - class OSGANIMATION_EXPORT UpdateBone : public AnimationUpdateCallback + class OSGANIMATION_EXPORT UpdateBone : public AnimationUpdateCallback { protected: osg::ref_ptr _position; @@ -102,7 +103,7 @@ namespace osgAnimation META_Object(osgAnimation, UpdateBone); UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop); - UpdateBone(const std::string& name = "") + UpdateBone(const std::string& name = "") : AnimationUpdateCallback (name) { setName(name); _quaternion = new osgAnimation::QuatTarget; @@ -155,7 +156,7 @@ namespace osgAnimation } else { - std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl; + osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << className() << std::endl; } return false; } diff --git a/include/osgAnimation/LinkVisitor b/include/osgAnimation/LinkVisitor index d25ab5ffd..3f0789a33 100644 --- a/include/osgAnimation/LinkVisitor +++ b/include/osgAnimation/LinkVisitor @@ -16,10 +16,13 @@ #define OSGANIMATION_NODE_VISITOR_H #include +#include #include namespace osgAnimation { + class AnimationUpdateCallbackBase; + /** This class is instancied by the AnimationManagerBase, it will link animation target to updatecallback that have the same name */ class OSGANIMATION_EXPORT LinkVisitor : public osg::NodeVisitor @@ -30,10 +33,16 @@ namespace osgAnimation META_NodeVisitor("osgAnimation","LinkVisitor"); void apply(osg::Node& node); + void apply(osg::Geode& node); + AnimationList& getAnimationList(); void reset(); protected: + + void handle_stateset(osg::StateSet* stateset); + void link(osgAnimation::AnimationUpdateCallbackBase* cb); + // animation list to link AnimationList _animations; diff --git a/include/osgAnimation/MorphGeometry b/include/osgAnimation/MorphGeometry index bdffe432d..d03d2a7f2 100644 --- a/include/osgAnimation/MorphGeometry +++ b/include/osgAnimation/MorphGeometry @@ -131,7 +131,7 @@ namespace osgAnimation bool _morphNormals; }; - class OSGANIMATION_EXPORT UpdateMorph : public AnimationUpdateCallback + class OSGANIMATION_EXPORT UpdateMorph : public AnimationUpdateCallback { protected: std::map > _weightTargets; diff --git a/include/osgAnimation/UpdateCallback b/include/osgAnimation/UpdateCallback index d0d396089..16c6b2a25 100644 --- a/include/osgAnimation/UpdateCallback +++ b/include/osgAnimation/UpdateCallback @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include #include @@ -24,23 +26,80 @@ namespace osgAnimation { - class OSGANIMATION_EXPORT AnimationUpdateCallback : public osg::NodeCallback + class AnimationUpdateCallbackBase + { + public: + virtual AnimationManagerBase* getAnimationManager() = 0; + virtual bool needLink() const = 0; + virtual bool link(osgAnimation::Channel* channel) = 0; + virtual int link(osgAnimation::Animation* animation) = 0; + virtual void updateLink() = 0; + virtual const std::string& getName() const = 0; + }; + + template + class AnimationUpdateCallback : public AnimationUpdateCallbackBase, public T { protected: + osg::observer_ptr _manager; public: - AnimationUpdateCallback(const std::string& name = "") { setName(name); } - AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop); - osgAnimation::AnimationManagerBase* getAnimationManager(); - virtual bool needLink() const = 0; - virtual bool link(osgAnimation::Channel* channel) = 0; - virtual int link(osgAnimation::Animation* animation); - virtual void updateLink(); - }; - + AnimationUpdateCallback(const std::string& name) { T::setName(name);} + AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop): + T(apc, copyop), + _manager(apc._manager) {} - class OSGANIMATION_EXPORT UpdateTransform : public AnimationUpdateCallback + osgAnimation::AnimationManagerBase* getAnimationManager() { return _manager.get(); } + + const std::string& getName() const { return T::getName(); } + int link(osgAnimation::Animation* animation) + { + if (T::getName().empty()) + osg::notify(osg::WARN) << "An update callback has no name, it means it can link only with \"\" named Target, often an error" << std::endl; + int nbLinks = 0; + for (osgAnimation::ChannelList::iterator it = animation->getChannels().begin(); + it != animation->getChannels().end(); + it++) + { + std::string targetName = (*it)->getTargetName(); + if (targetName == T::getName()) + { + AnimationUpdateCallbackBase* a = this; + a->link((*it).get()); + nbLinks++; + } + } + return nbLinks; + } + + void updateLink() + { + if (_manager.valid()) + { + if (needLink()) + { + /** this item is not linked yet then we do it for all animation + registered in the manager. + Maybe this function should be on the manager side like + _manager->linkItem(Bone); + */ + const AnimationList& animationList = _manager->getAnimationList(); + for (AnimationList::const_iterator it = animationList.begin(); it != animationList.end(); it++) + { + AnimationUpdateCallbackBase* a = this; + a->link(it->get()); + } + _manager->buildTargetReference(); + } + } + } + }; + + + + + class OSGANIMATION_EXPORT UpdateTransform : public AnimationUpdateCallback { protected: osg::ref_ptr _euler; @@ -63,6 +122,26 @@ namespace osgAnimation }; + + class OSGANIMATION_EXPORT UpdateMaterial : public AnimationUpdateCallback + { + protected: + osg::ref_ptr _diffuse; + + public: + + META_Object(osgAnimation, UpdateMaterial); + + UpdateMaterial(const std::string& name = ""); + UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop); + + /** Callback method called by the NodeVisitor when visiting a node.*/ + virtual void operator () (osg::StateAttribute*, osg::NodeVisitor*); + void update(osg::Material& material); + bool needLink() const; + bool link(osgAnimation::Channel* channel); + }; + } #endif diff --git a/src/osgAnimation/Bone.cpp b/src/osgAnimation/Bone.cpp index 2b1c5a188..80e0a40c7 100644 --- a/src/osgAnimation/Bone.cpp +++ b/src/osgAnimation/Bone.cpp @@ -18,7 +18,7 @@ osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& apc,const osg::CopyOp& copyop) : osg::Object(apc, copyop), - osgAnimation::AnimationUpdateCallback(apc, copyop) + osgAnimation::AnimationUpdateCallback(apc, copyop) { _quaternion = new osgAnimation::QuatTarget(apc._quaternion->getValue()); _position = new osgAnimation::Vec3Target(apc._position->getValue()); diff --git a/src/osgAnimation/LinkVisitor.cpp b/src/osgAnimation/LinkVisitor.cpp index af73014b3..6037f8f5f 100644 --- a/src/osgAnimation/LinkVisitor.cpp +++ b/src/osgAnimation/LinkVisitor.cpp @@ -15,6 +15,7 @@ #include #include #include +#include using namespace osgAnimation; @@ -32,19 +33,55 @@ AnimationList& LinkVisitor::getAnimationList() { return _animations; } +void LinkVisitor::link(osgAnimation::AnimationUpdateCallbackBase* cb) +{ + int result = 0; + for (int i = 0; i < (int)_animations.size(); i++) + { + result += cb->link(_animations[i].get()); + _nbLinkedTarget += result; + } + osg::notify(osg::NOTICE) << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl; +} + +void LinkVisitor::handle_stateset(osg::StateSet* stateset) +{ + if (!stateset) + return; + osg::StateSet::AttributeList& attr = stateset->getAttributeList(); + for (osg::StateSet::AttributeList::iterator it = attr.begin(); it != attr.end(); it++) + { + osg::StateAttribute* sattr = it->second.first.get(); + osgAnimation::AnimationUpdateCallbackBase* cb = dynamic_cast(sattr->getUpdateCallback()); + if (cb) + link(cb); + } +} void LinkVisitor::apply(osg::Node& node) { - osgAnimation::AnimationUpdateCallback* cb = dynamic_cast(node.getUpdateCallback()); - if (cb) + osg::StateSet* st = node.getStateSet(); + if (st) + handle_stateset(st); + + osg::NodeCallback* cb = node.getUpdateCallback(); + while (cb) { - int result = 0; - for (int i = 0; i < (int)_animations.size(); i++) - { - result += cb->link(_animations[i].get()); - _nbLinkedTarget += result; - } - osg::notify(osg::NOTICE) << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl; + osgAnimation::AnimationUpdateCallbackBase* cba = dynamic_cast(cb); + if (cba) + link(cba); + cb = cb->getNestedCallback(); } traverse(node); } + +void LinkVisitor::apply(osg::Geode& node) +{ + for (unsigned int i = 0; i < node.getNumDrawables(); i++) + { + osg::Drawable* drawable = node.getDrawable(i); + if (drawable && drawable->getStateSet()) + handle_stateset(drawable->getStateSet()); + } + apply(static_cast(node)); +} diff --git a/src/osgAnimation/MorphGeometry.cpp b/src/osgAnimation/MorphGeometry.cpp index f195e6833..4ff244008 100644 --- a/src/osgAnimation/MorphGeometry.cpp +++ b/src/osgAnimation/MorphGeometry.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ * Authors: * * Roland Smeenk - * Cedric Pinson + * Cedric Pinson * */ #include @@ -202,11 +202,11 @@ void MorphGeometry::transformSoftwareMethod() } } -UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) : AnimationUpdateCallback(apc, copyop) +UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) : AnimationUpdateCallback(apc, copyop) { } -UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback(name) +UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback(name) { } diff --git a/src/osgAnimation/UpdateCallback.cpp b/src/osgAnimation/UpdateCallback.cpp index 9a7d1b3c2..c95442db3 100644 --- a/src/osgAnimation/UpdateCallback.cpp +++ b/src/osgAnimation/UpdateCallback.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -18,63 +18,18 @@ using namespace osgAnimation; -osgAnimation::AnimationManagerBase* AnimationUpdateCallback::getAnimationManager() { return _manager.get(); } - -AnimationUpdateCallback::AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop): - osg::NodeCallback(apc, copyop), - _manager(apc._manager) {} - -int AnimationUpdateCallback::link(osgAnimation::Animation* animation) -{ - if (getName().empty()) - osg::notify(osg::WARN) << "An update callback has no name, it means it can link only with \"\" named Target, often an error" << std::endl; - int nbLinks = 0; - for (osgAnimation::ChannelList::iterator it = animation->getChannels().begin(); - it != animation->getChannels().end(); - it++) - { - std::string targetName = (*it)->getTargetName(); - if (targetName == getName()) - { - link((*it).get()); - nbLinks++; - } - } - return nbLinks; -} - -void AnimationUpdateCallback::updateLink() -{ - if (_manager.valid()) - { - if (needLink()) - { - /** this item is not linked yet then we do it for all animation - registered in the manager. - Maybe this function should be on the manager side like - _manager->linkItem(Bone); - */ - const AnimationList& animationList = _manager->getAnimationList(); - for (AnimationList::const_iterator it = animationList.begin(); it != animationList.end(); it++) - link(it->get()); - _manager->buildTargetReference(); - } - } -} - - - UpdateTransform::UpdateTransform(const UpdateTransform& apc,const osg::CopyOp& copyop) : osg::Object(apc, copyop), - AnimationUpdateCallback(apc, copyop) + AnimationUpdateCallback(apc, copyop) { _euler = new osgAnimation::Vec3Target(apc._euler->getValue()); _position = new osgAnimation::Vec3Target(apc._position->getValue()); _scale = new osgAnimation::Vec3Target(apc._scale->getValue()); } -UpdateTransform::UpdateTransform(const std::string& name) : AnimationUpdateCallback(name) +UpdateTransform::UpdateTransform(const std::string& name): + AnimationUpdateCallback(name) { _euler = new osgAnimation::Vec3Target; _position = new osgAnimation::Vec3Target; @@ -167,7 +122,65 @@ bool UpdateTransform::link(osgAnimation::Channel* channel) } else { - std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl; + osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << className() << std::endl; + } + return false; +} + + + + + +UpdateMaterial::UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop) + : osg::Object(apc, copyop), + AnimationUpdateCallback(apc, copyop) +{ + _diffuse = new osgAnimation::Vec4Target(apc._diffuse->getValue()); +} + +UpdateMaterial::UpdateMaterial(const std::string& name): + AnimationUpdateCallback(name) +{ + _diffuse = new osgAnimation::Vec4Target(osg::Vec4(1,1,1,1)); +} + +/** Callback method called by the NodeVisitor when visiting a node.*/ +void UpdateMaterial::operator()(osg::StateAttribute* sa, osg::NodeVisitor* nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::Material* material = dynamic_cast(sa); + if (material) + update(*material); + } +} + +void UpdateMaterial::update(osg::Material& material) +{ + osg::Vec4 diffuse = _diffuse->getValue(); + material.setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + +bool UpdateMaterial::needLink() const +{ + // the idea is to return true if nothing is linked + return (_diffuse->getCount() < 2); +} + +bool UpdateMaterial::link(osgAnimation::Channel* channel) +{ + if (channel->getName().find("diffuse") != std::string::npos) + { + osgAnimation::Vec4LinearChannel* d = dynamic_cast(channel); + if (d) + { + d->setTarget(_diffuse.get()); + return true; + } + } + else + { + osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class " << className() << std::endl; } return false; } diff --git a/src/osgPlugins/osgAnimation/ReaderWriter.cpp b/src/osgPlugins/osgAnimation/ReaderWriter.cpp index 2f0b8f0f4..39dbc698f 100644 --- a/src/osgPlugins/osgAnimation/ReaderWriter.cpp +++ b/src/osgPlugins/osgAnimation/ReaderWriter.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or @@ -1041,6 +1041,29 @@ RegisterDotOsgWrapperProxy g_atkUpdateTransformProxy DotOsgWrapper::READ_AND_WRITE ); + + +bool UpdateMaterial_readLocalData(Object& obj, Input& fr) +{ + bool iteratorAdvanced = false; + return iteratorAdvanced; +} + +bool UpdateMaterial_writeLocalData(const Object& obj, Output& fw) +{ + return true; +} + +RegisterDotOsgWrapperProxy g_UpdateMaterialProxy +( + new osgAnimation::UpdateMaterial, + "osgAnimation::UpdateMaterial", + "Object StateAttribute::Callback osgAnimation::UpdateMaterial", + &UpdateMaterial_readLocalData, + &UpdateMaterial_writeLocalData, + DotOsgWrapper::READ_AND_WRITE +); + bool UpdateMorph_readLocalData(Object& obj, Input& fr) { bool iteratorAdvanced = false;