Updated to slideshow3D to support animation + pausing of animation.
Updated associated osg/osgUtil classes that provide animation pausing.
This commit is contained in:
@@ -10,6 +10,8 @@
|
||||
#include <libxml/xmlmemory.h>
|
||||
#include <libxml/parser.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
||||
/**
|
||||
* OpenSceneGraph plugin wrapper/converter.
|
||||
@@ -57,7 +59,23 @@ public:
|
||||
return _colorMap[str];
|
||||
}
|
||||
|
||||
inline bool read(const char* str, float& value) const;
|
||||
inline bool read(const char* str, osg::Vec2& value) const;
|
||||
inline bool read(const char* str, osg::Vec3& value) const;
|
||||
inline bool read(const char* str, osg::Vec4& value) const;
|
||||
|
||||
inline bool read(const std::string& str, float& value) const;
|
||||
inline bool read(const std::string& str, osg::Vec2& value) const;
|
||||
inline bool read(const std::string& str, osg::Vec3& value) const;
|
||||
inline bool read(const std::string& str, osg::Vec4& value) const;
|
||||
|
||||
bool getProperty(xmlNodePtr cur, const char* token) const;
|
||||
bool getProperty(xmlNodePtr cur, const char* token, float& value) const;
|
||||
bool getProperty(xmlNodePtr cur, const char* token, osg::Vec2& value) const;
|
||||
bool getProperty(xmlNodePtr cur, const char* token, osg::Vec3& value) const;
|
||||
bool getProperty(xmlNodePtr cur, const char* token, osg::Vec4& value) const;
|
||||
bool getProperty(xmlNodePtr cur, const char* token, std::string& value) const;
|
||||
|
||||
std::map<std::string,osg::Vec4> _colorMap;
|
||||
|
||||
};
|
||||
@@ -65,46 +83,206 @@ public:
|
||||
// Register with Registry to instantiate the above reader/writer.
|
||||
osgDB::RegisterReaderWriterProxy<ReaderWriterSS3D> g_readerWriter_SS3D_Proxy;
|
||||
|
||||
bool ReaderWriterSS3D::read(const char* str, float& value) const
|
||||
{
|
||||
if (!str) return false;
|
||||
std::istringstream iss((const char*)str);
|
||||
iss >> value;
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::read(const char* str, osg::Vec2& value) const
|
||||
{
|
||||
if (!str) return false;
|
||||
std::istringstream iss((const char*)str);
|
||||
iss >> value.x() >> value.y();
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::read(const char* str, osg::Vec3& value) const
|
||||
{
|
||||
if (!str) return false;
|
||||
std::istringstream iss((const char*)str);
|
||||
iss >> value.x() >> value.y() >> value.z();
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::read(const char* str, osg::Vec4& value) const
|
||||
{
|
||||
if (!str) return false;
|
||||
std::istringstream iss((const char*)str);
|
||||
iss >> value.x() >> value.y() >> value.z() >> value.w();
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
|
||||
bool ReaderWriterSS3D::read(const std::string& str, float& value) const
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
iss >> value;
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::read(const std::string& str, osg::Vec2& value) const
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
iss >> value.x() >> value.y();
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::read(const std::string& str, osg::Vec3& value) const
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
iss >> value.x() >> value.y() >> value.z();
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::read(const std::string& str, osg::Vec4& value) const
|
||||
{
|
||||
std::istringstream iss(str);
|
||||
iss >> value.x() >> value.y() >> value.z() >> value.w();
|
||||
return !iss.fail();
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token) const
|
||||
{
|
||||
bool success = false;
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)token);
|
||||
if (key) success=true;
|
||||
xmlFree(key);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, float& value) const
|
||||
{
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)token);
|
||||
bool success = read((const char*)key,value);
|
||||
xmlFree(key);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, osg::Vec2& value) const
|
||||
{
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)token);
|
||||
bool success = read((const char*)key,value);
|
||||
xmlFree(key);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, osg::Vec3& value) const
|
||||
{
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)token);
|
||||
bool success = read((const char*)key,value);
|
||||
xmlFree(key);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, osg::Vec4& value) const
|
||||
{
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)token);
|
||||
bool success = read((const char*)key,value);
|
||||
xmlFree(key);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ReaderWriterSS3D::getProperty(xmlNodePtr cur, const char* token, std::string& value) const
|
||||
{
|
||||
bool success = false;
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)token);
|
||||
if (key)
|
||||
{
|
||||
success = true;
|
||||
value = (const char*)key;
|
||||
}
|
||||
xmlFree(key);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void ReaderWriterSS3D::parseModel(SlideShowConstructor& constructor, xmlDocPtr doc, xmlNodePtr cur)
|
||||
{
|
||||
std::string filename;
|
||||
float scale = 1.0f;
|
||||
float rotation = 0.0f;
|
||||
float position = 0.5f;
|
||||
|
||||
xmlChar *key;
|
||||
cur = cur->xmlChildrenNode;
|
||||
while (cur != NULL)
|
||||
SlideShowConstructor::CoordinateFrame coordinate_frame = SlideShowConstructor::SLIDE;
|
||||
osg::Vec3 position(0.0f,1.0f,0.0f);
|
||||
osg::Vec4 rotate(0.0f,0.0f,0.0f,1.0f);
|
||||
float scale = 1.0f;
|
||||
|
||||
osg::Vec4 rotation(0.0f,0.0f,0.0f,1.0f);
|
||||
std::string animation_path;
|
||||
std::string camera_path;
|
||||
|
||||
// temporary
|
||||
std::string str;
|
||||
|
||||
if (getProperty(cur, "coordinate_frame", str))
|
||||
{
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *)"filename")))
|
||||
{
|
||||
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (key) filename = (const char*)key;
|
||||
xmlFree(key);
|
||||
}
|
||||
else if ((!xmlStrcmp(cur->name, (const xmlChar *)"scale")))
|
||||
{
|
||||
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (key) scale = atoi((const char*)key);
|
||||
xmlFree(key);
|
||||
}
|
||||
else if ((!xmlStrcmp(cur->name, (const xmlChar *)"rotation")))
|
||||
{
|
||||
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (key) rotation = atoi((const char*)key);
|
||||
xmlFree(key);
|
||||
}
|
||||
else if ((!xmlStrcmp(cur->name, (const xmlChar *)"position")))
|
||||
{
|
||||
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (key) position = atoi((const char*)key)/100.0f;
|
||||
xmlFree(key);
|
||||
}
|
||||
cur = cur->next;
|
||||
if (str=="model") coordinate_frame = SlideShowConstructor::MODEL;
|
||||
else if (str=="slide") coordinate_frame = SlideShowConstructor::SLIDE;
|
||||
else std::cout<<"Parser error - coordinate_frame=\""<<str<<"\" unrecongonized value"<<std::endl;
|
||||
}
|
||||
|
||||
if (getProperty(cur, "position", str))
|
||||
{
|
||||
bool fail = false;
|
||||
if (str=="center") position.set(0.0f,1.0f,0.0f);
|
||||
else if (str=="eye") position.set(0.0f,0.0f,0.0f);
|
||||
else if (!read(str,position)) fail = true;
|
||||
|
||||
if (fail) std::cout<<"Parser error - position=\""<<str<<"\" unrecongonized value"<<std::endl;
|
||||
else std::cout<<"Read position="<<position<<std::endl;
|
||||
}
|
||||
|
||||
if (!filename.empty()) constructor.addModel(filename,scale,rotation,position);
|
||||
if (getProperty(cur, "scale", scale))
|
||||
{
|
||||
std::cout<<"scale read "<<scale<<std::endl;
|
||||
}
|
||||
|
||||
if (getProperty(cur, "rotate", rotate))
|
||||
{
|
||||
std::cout<<"rotate read "<<rotate<<std::endl;
|
||||
}
|
||||
|
||||
if (getProperty(cur, "rotation", rotation))
|
||||
{
|
||||
std::cout<<"rotation read "<<rotation<<std::endl;
|
||||
}
|
||||
|
||||
if (getProperty(cur, "path", animation_path))
|
||||
{
|
||||
std::cout<<"path read "<<animation_path<<std::endl;
|
||||
}
|
||||
|
||||
if (getProperty(cur, "camera_path", camera_path))
|
||||
{
|
||||
std::cout<<"camera path read "<<camera_path<<std::endl;
|
||||
}
|
||||
|
||||
xmlChar *key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if (key) filename = (const char*)key;
|
||||
xmlFree(key);
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (!camera_path.empty())
|
||||
{
|
||||
constructor.addModelWithCameraPath(filename,coordinate_frame,position,scale,rotate,camera_path);
|
||||
}
|
||||
else if (!animation_path.empty())
|
||||
{
|
||||
constructor.addModelWithPath(filename,coordinate_frame,position,scale,rotate,animation_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
constructor.addModel(filename,coordinate_frame,position,scale,rotate,rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReaderWriterSS3D::parseStereoPair(SlideShowConstructor& constructor, xmlDocPtr doc, xmlNodePtr cur)
|
||||
@@ -115,7 +293,7 @@ void ReaderWriterSS3D::parseStereoPair(SlideShowConstructor& constructor, xmlDoc
|
||||
float height = 1.0f;
|
||||
xmlChar *key;
|
||||
key = xmlGetProp (cur, (const xmlChar *)"height");
|
||||
if (key) height = atoi((const char*)key);
|
||||
if (key) height = atof((const char*)key);
|
||||
xmlFree(key);
|
||||
|
||||
cur = cur->xmlChildrenNode;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "SlideEventHandler.h"
|
||||
#include "SlideShowConstructor.h"
|
||||
|
||||
#include <osg/AnimationPath>
|
||||
#include <osgUtil/TransformCallback>
|
||||
|
||||
class FindNamedSwitchVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
@@ -109,7 +112,7 @@ bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIAction
|
||||
{
|
||||
case(osgGA::GUIEventAdapter::FRAME):
|
||||
{
|
||||
if (_autoSteppingActive)
|
||||
if (_autoSteppingActive && !_pause)
|
||||
{
|
||||
double time = ea.time();
|
||||
|
||||
@@ -183,12 +186,17 @@ bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIAction
|
||||
previousSlide();
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Pause)
|
||||
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Pause ||
|
||||
ea.getKey()=='p')
|
||||
{
|
||||
_pause = !_pause;
|
||||
if (_pause) std::cout<<"Pause"<<std::endl;
|
||||
else std::cout<<"End Pause"<<std::endl;
|
||||
|
||||
resetUpdateCallbackActivity();
|
||||
|
||||
}
|
||||
else if (ea.getKey()=='r')
|
||||
{
|
||||
resetUpdateCallbacks();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -297,3 +305,71 @@ bool SlideEventHandler::previousLayer()
|
||||
if (_activeLayer>0) return selectLayer(_activeLayer-1);
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
class ResetUpdateCallbacksVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
ResetUpdateCallbacksVisitor(bool pause):
|
||||
// osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
|
||||
_pause(pause) {}
|
||||
|
||||
|
||||
void apply(osg::Node& node)
|
||||
{
|
||||
osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(node.getUpdateCallback());
|
||||
osgUtil::TransformCallback* tc = dynamic_cast<osgUtil::TransformCallback*>(node.getUpdateCallback());
|
||||
if (apc)
|
||||
{
|
||||
apc->reset();
|
||||
apc->update(node);
|
||||
}
|
||||
if (tc)
|
||||
{
|
||||
//tc->reset();
|
||||
}
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
bool _pause;
|
||||
};
|
||||
|
||||
void SlideEventHandler::resetUpdateCallbacks()
|
||||
{
|
||||
ResetUpdateCallbacksVisitor rucv(_pause);
|
||||
_presentationSwitch->accept(rucv);
|
||||
}
|
||||
|
||||
class ActivityUpdateCallbacksVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
ActivityUpdateCallbacksVisitor(bool pause):
|
||||
// osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
|
||||
_pause(pause) {}
|
||||
|
||||
|
||||
void apply(osg::Node& node)
|
||||
{
|
||||
osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(node.getUpdateCallback());
|
||||
osgUtil::TransformCallback* tc = dynamic_cast<osgUtil::TransformCallback*>(node.getUpdateCallback());
|
||||
if (apc)
|
||||
{
|
||||
apc->setPause(_pause);
|
||||
}
|
||||
if (tc)
|
||||
{
|
||||
tc->setPause(_pause);
|
||||
}
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
bool _pause;
|
||||
};
|
||||
|
||||
void SlideEventHandler::resetUpdateCallbackActivity()
|
||||
{
|
||||
ActivityUpdateCallbacksVisitor aucv(_pause);
|
||||
_presentationSwitch->accept(aucv);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,9 @@ protected:
|
||||
bool _autoSteppingActive;
|
||||
bool _loopPresentation;
|
||||
bool _pause;
|
||||
|
||||
void resetUpdateCallbacks();
|
||||
void resetUpdateCallbackActivity();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -6,19 +6,23 @@
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/MatrixTransform>
|
||||
|
||||
#include <osgUtil/TransformCallback>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/FileUtils>
|
||||
|
||||
#include <osgText/Text>
|
||||
|
||||
|
||||
SlideShowConstructor::SlideShowConstructor()
|
||||
{
|
||||
_slideOrigin.set(0.0f,0.0f,0.0f);
|
||||
|
||||
_slideDistance = osg::DisplaySettings::instance()->getScreenDistance();
|
||||
_slideHeight = osg::DisplaySettings::instance()->getScreenHeight();
|
||||
|
||||
_slideWidth = _slideHeight*1280.0f/1024.f;
|
||||
|
||||
_slideOrigin.set(-_slideWidth*0.5f,_slideDistance,-_slideHeight*0.5f);
|
||||
|
||||
|
||||
_backgroundColor.set(0.0f,0.0f,0.0f,1.0f);
|
||||
_textColor.set(1.0f,1.0f,1.0f,1.0f);
|
||||
_textFont = "fonts/arial.ttf";
|
||||
@@ -77,11 +81,9 @@ void SlideShowConstructor::createPresentation()
|
||||
_root->addChild(_presentationSwitch.get());
|
||||
|
||||
osg::Vec3 slideCenter = _slideOrigin + osg::Vec3(_slideWidth*0.5f,0.0f,_slideHeight*0.5f);
|
||||
|
||||
float distanceToHeightRatio = osg::DisplaySettings::instance()->getScreenDistance()/osg::DisplaySettings::instance()->getScreenHeight();
|
||||
|
||||
|
||||
HomePosition* hp = new HomePosition;
|
||||
hp->eye = slideCenter+osg::Vec3(0.0f,-distanceToHeightRatio*_slideHeight,0.0f);
|
||||
hp->eye.set(0.0f,0.0f,0.0f);
|
||||
hp->center = slideCenter;
|
||||
hp->up.set(0.0f,0.0f,1.0f);
|
||||
|
||||
@@ -374,7 +376,7 @@ void SlideShowConstructor::addStereoImagePair(const std::string& filenameLeft,co
|
||||
_currentLayer->addChild(stereopair);
|
||||
}
|
||||
|
||||
void SlideShowConstructor::addModel(const std::string& filename,float scale,float rotation,float position)
|
||||
void SlideShowConstructor::addModel(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const osg::Vec4& rotation)
|
||||
{
|
||||
if (!_currentLayer) addLayer();
|
||||
|
||||
@@ -382,24 +384,232 @@ void SlideShowConstructor::addModel(const std::string& filename,float scale,floa
|
||||
|
||||
if (!model) return;
|
||||
|
||||
osg::Vec3 pos = _modelLeft*(1.0f-position) + _modelRight*position;
|
||||
float radius = scale*_slideHeight*0.7f;
|
||||
osg::Quat quat;
|
||||
quat.makeRotate(osg::DegreesToRadians(rotation),0.0f,0.0f,1.0f);
|
||||
if (coordinate_frame==SLIDE)
|
||||
{
|
||||
osg::Vec3 pos(_slideWidth*position.x(),
|
||||
_slideDistance*position.y(),
|
||||
_slideHeight*position.z());
|
||||
|
||||
const osg::BoundingSphere& bs = model->getBound();
|
||||
float model_scale = scale*_slideHeight*0.7f/bs.radius();
|
||||
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
|
||||
const osg::BoundingSphere& bs = model->getBound();
|
||||
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-bs.center())*
|
||||
osg::Matrix::scale(radius/bs.radius(),radius/bs.radius(),radius/bs.radius())*
|
||||
osg::Matrix::rotate(quat)*
|
||||
osg::Matrix::translate(pos));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
_currentLayer->addChild(transform);
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-bs.center())*
|
||||
osg::Matrix::scale(model_scale,model_scale,model_scale)*
|
||||
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3])*
|
||||
osg::Matrix::translate(pos));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
if (rotation[0]!=0.0)
|
||||
{
|
||||
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
|
||||
animation_transform->setDataVariance(osg::Object::DYNAMIC);
|
||||
animation_transform->setUpdateCallback(new osgUtil::TransformCallback(pos,osg::Vec3(rotation[1],rotation[2],rotation[3]),osg::DegreesToRadians(rotation[0])));
|
||||
animation_transform->addChild(transform);
|
||||
|
||||
_currentLayer->addChild(animation_transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentLayer->addChild(transform);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-position)*
|
||||
osg::Matrix::scale(scale,scale,scale)*
|
||||
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3]));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
if (rotation[0]!=0.0)
|
||||
{
|
||||
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
|
||||
animation_transform->setDataVariance(osg::Object::DYNAMIC);
|
||||
animation_transform->setUpdateCallback(new osgUtil::TransformCallback(osg::Vec3(0.0f,0.0f,0.0f),osg::Vec3(rotation[1],rotation[2],rotation[3]),osg::DegreesToRadians(rotation[0])));
|
||||
animation_transform->addChild(transform);
|
||||
|
||||
_currentLayer->addChild(animation_transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentLayer->addChild(transform);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SlideShowConstructor::addModelWithPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path)
|
||||
{
|
||||
if (!_currentLayer) addLayer();
|
||||
|
||||
osg::Node* model = osgDB::readNodeFile(filename);
|
||||
|
||||
if (!model) return;
|
||||
|
||||
osg::AnimationPath* animation = 0;
|
||||
if (!animation_path.empty())
|
||||
{
|
||||
std::string absolute_animation_file_path = osgDB::findDataFile(animation_path);
|
||||
if (!absolute_animation_file_path.empty())
|
||||
{
|
||||
std::ifstream animation_filestream(absolute_animation_file_path.c_str());
|
||||
if (!animation_filestream.eof())
|
||||
{
|
||||
animation = new osg::AnimationPath;
|
||||
animation->read(animation_filestream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (coordinate_frame==SLIDE)
|
||||
{
|
||||
osg::Vec3 pos(_slideWidth*position.x(),
|
||||
_slideDistance*position.y(),
|
||||
_slideHeight*position.z());
|
||||
|
||||
const osg::BoundingSphere& bs = model->getBound();
|
||||
float model_scale = scale*_slideHeight*0.7f/bs.radius();
|
||||
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-bs.center())*
|
||||
osg::Matrix::scale(model_scale,model_scale,model_scale)*
|
||||
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3])*
|
||||
osg::Matrix::translate(pos));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
_currentLayer->addChild(transform);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-position)*
|
||||
osg::Matrix::scale(scale,scale,scale)*
|
||||
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3]));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
if (animation)
|
||||
{
|
||||
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
|
||||
animation_transform->setDataVariance(osg::Object::DYNAMIC);
|
||||
|
||||
osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation);
|
||||
|
||||
animation_transform->setUpdateCallback(apc);
|
||||
animation_transform->addChild(transform);
|
||||
|
||||
_currentLayer->addChild(animation_transform);
|
||||
|
||||
//
|
||||
// osg::MatrixTransform* orientation_transform = new osg::MatrixTransform;
|
||||
// orientation_transform->setDataVariance(osg::Object::STATIC);
|
||||
// orientation_transform->addChild(animation_transform);
|
||||
//
|
||||
// //orientation_transform->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(-00.0f),0.0f,1.0f,0.0f));
|
||||
// //orientation_transform->setMatrix(osg::Matrix::inverse(osg::Matrix::lookAt(osg::Vec3(0.0,0.0,0.0),osg::Vec3(0.0,1.0,0.0),osg::Vec3(0.0,0.0,1.0))));
|
||||
//
|
||||
// _currentLayer->addChild(orientation_transform);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentLayer->addChild(transform);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SlideShowConstructor::addModelWithCameraPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path)
|
||||
{
|
||||
if (!_currentLayer) addLayer();
|
||||
|
||||
osg::Node* model = osgDB::readNodeFile(filename);
|
||||
|
||||
if (!model) return;
|
||||
|
||||
osg::AnimationPath* animation = 0;
|
||||
if (!animation_path.empty())
|
||||
{
|
||||
std::string absolute_animation_file_path = osgDB::findDataFile(animation_path);
|
||||
if (!absolute_animation_file_path.empty())
|
||||
{
|
||||
std::ifstream animation_filestream(absolute_animation_file_path.c_str());
|
||||
if (!animation_filestream.eof())
|
||||
{
|
||||
animation = new osg::AnimationPath;
|
||||
animation->read(animation_filestream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (coordinate_frame==SLIDE)
|
||||
{
|
||||
osg::Vec3 pos(_slideWidth*position.x(),
|
||||
_slideDistance*position.y(),
|
||||
_slideHeight*position.z());
|
||||
|
||||
const osg::BoundingSphere& bs = model->getBound();
|
||||
float model_scale = scale*_slideHeight*0.7f/bs.radius();
|
||||
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-bs.center())*
|
||||
osg::Matrix::scale(model_scale,model_scale,model_scale)*
|
||||
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3])*
|
||||
osg::Matrix::translate(pos));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
_currentLayer->addChild(transform);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->setMatrix(osg::Matrix::translate(-position)*
|
||||
osg::Matrix::scale(scale,scale,scale)*
|
||||
osg::Matrix::rotate(osg::DegreesToRadians(rotate[0]),rotate[1],rotate[2],rotate[3]));
|
||||
|
||||
transform->addChild(model);
|
||||
|
||||
if (animation)
|
||||
{
|
||||
osg::MatrixTransform* animation_transform = new osg::MatrixTransform;
|
||||
animation_transform->setDataVariance(osg::Object::DYNAMIC);
|
||||
|
||||
osg::AnimationPathCallback* apc = new osg::AnimationPathCallback(animation);
|
||||
apc->setUseInverseMatrix(true);
|
||||
|
||||
animation_transform->setUpdateCallback(apc);
|
||||
animation_transform->addChild(transform);
|
||||
|
||||
osg::MatrixTransform* orientation_transform = new osg::MatrixTransform;
|
||||
orientation_transform->setDataVariance(osg::Object::STATIC);
|
||||
orientation_transform->addChild(animation_transform);
|
||||
|
||||
//orientation_transform->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(-00.0f),0.0f,1.0f,0.0f));
|
||||
orientation_transform->setMatrix(osg::Matrix::inverse(osg::Matrix::lookAt(osg::Vec3(0.0,0.0,0.0),osg::Vec3(0.0,1.0,0.0),osg::Vec3(0.0,0.0,1.0))));
|
||||
|
||||
_currentLayer->addChild(orientation_transform);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentLayer->addChild(transform);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,11 @@ public:
|
||||
|
||||
void addStereoImagePair(const std::string& filenameLeft,const std::string& filenameRight,float height);
|
||||
|
||||
void addModel(const std::string& filename,float scale,float rotation,float position);
|
||||
enum CoordinateFrame { SLIDE, MODEL };
|
||||
|
||||
void addModel(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const osg::Vec4& rotation);
|
||||
void addModelWithPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path);
|
||||
void addModelWithCameraPath(const std::string& filename, CoordinateFrame coordinate_frame, const osg::Vec3& position, float scale, const osg::Vec4& rotate, const std::string& animation_path);
|
||||
|
||||
osg::ClearNode* takePresentation() { return _root.release(); }
|
||||
|
||||
@@ -88,6 +92,7 @@ protected:
|
||||
osg::Vec3 _slideOrigin;
|
||||
float _slideWidth;
|
||||
float _slideHeight;
|
||||
float _slideDistance;
|
||||
|
||||
osg::Vec4 _backgroundColor;
|
||||
osg::Vec4 _textColor;
|
||||
|
||||
@@ -63,7 +63,8 @@ class SG_EXPORT AnimationPath : public virtual osg::Object
|
||||
osg::Vec3 _position;
|
||||
osg::Quat _rotation;
|
||||
osg::Vec3 _scale;
|
||||
|
||||
|
||||
|
||||
inline void interpolate(float ratio,const ControlPoint& first, const ControlPoint& second)
|
||||
{
|
||||
float one_minus_ratio = 1.0f-ratio;
|
||||
@@ -89,15 +90,15 @@ class SG_EXPORT AnimationPath : public virtual osg::Object
|
||||
inline void getInverse(Matrixf& matrix) const
|
||||
{
|
||||
matrix.makeScale(1.0f/_scale.x(),1.0f/_scale.y(),1.0f/_scale.y());
|
||||
matrix.postMult(osg::Matrixf::rotate(_rotation.inverse()));
|
||||
matrix.postMult(osg::Matrixf::translate(-_position));
|
||||
matrix.preMult(osg::Matrixf::rotate(_rotation.inverse()));
|
||||
matrix.preMult(osg::Matrixf::translate(-_position));
|
||||
}
|
||||
|
||||
inline void getInverse(Matrixd& matrix) const
|
||||
{
|
||||
matrix.makeScale(1.0f/_scale.x(),1.0f/_scale.y(),1.0f/_scale.y());
|
||||
matrix.postMult(osg::Matrixd::rotate(_rotation.inverse()));
|
||||
matrix.postMult(osg::Matrixd::translate(-_position));
|
||||
matrix.preMult(osg::Matrixd::rotate(_rotation.inverse()));
|
||||
matrix.preMult(osg::Matrixd::translate(-_position));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -163,6 +164,12 @@ class SG_EXPORT AnimationPath : public virtual osg::Object
|
||||
TimeControlPointMap& getTimeControlPointMap() { return _timeControlPointMap; }
|
||||
|
||||
const TimeControlPointMap& getTimeControlPointMap() const { return _timeControlPointMap; }
|
||||
|
||||
/** read the anumation path from a flat ascii file stream.*/
|
||||
void read(std::istream& in);
|
||||
|
||||
/** write the anumation path to a flat ascii file stream.*/
|
||||
void write(std::ostream& out);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -182,47 +189,63 @@ class SG_EXPORT AnimationPathCallback : public NodeCallback
|
||||
_timeOffset(0.0),
|
||||
_timeMultiplier(1.0),
|
||||
_firstTime(0.0),
|
||||
_animationTime(0.0) {}
|
||||
_latestTime(0.0),
|
||||
_pause(false),
|
||||
_pauseTime(0.0) {}
|
||||
|
||||
|
||||
AnimationPathCallback(const AnimationPathCallback& apc,const CopyOp& copyop):
|
||||
NodeCallback(apc,copyop),
|
||||
_animationPath(apc._animationPath),
|
||||
_useInverseMatrix(apc._useInverseMatrix),
|
||||
_timeOffset(apc._timeOffset),
|
||||
_timeMultiplier(apc._timeMultiplier),
|
||||
_firstTime(apc._firstTime),
|
||||
_animationTime(apc._animationTime) {}
|
||||
_latestTime(apc._latestTime),
|
||||
_pause(apc._pause),
|
||||
_pauseTime(apc._pauseTime) {}
|
||||
|
||||
|
||||
META_Object(osg,AnimationPathCallback);
|
||||
|
||||
AnimationPathCallback(AnimationPath* ap,double timeOffset=0.0f,double timeMultiplier=1.0f):
|
||||
_animationPath(ap),
|
||||
_useInverseMatrix(false),
|
||||
_timeOffset(timeOffset),
|
||||
_timeMultiplier(timeMultiplier),
|
||||
_firstTime(0.0),
|
||||
_animationTime(0.0) {}
|
||||
|
||||
|
||||
_latestTime(0.0),
|
||||
_pause(false),
|
||||
_pauseTime(0.0) {}
|
||||
|
||||
void setAnimationPath(AnimationPath* path) { _animationPath = path; }
|
||||
|
||||
AnimationPath* getAnimationPath() { return _animationPath.get(); }
|
||||
|
||||
const AnimationPath* getAnimationPath() const { return _animationPath.get(); }
|
||||
|
||||
void setUseInverseMatrix(bool useInverseMatrix) { _useInverseMatrix = useInverseMatrix; }
|
||||
bool getUseInverseMatrix() const { return _useInverseMatrix; }
|
||||
|
||||
void reset();
|
||||
|
||||
void setPause(bool pause);
|
||||
|
||||
/** implements the callback*/
|
||||
virtual void operator()(Node* node, NodeVisitor* nv);
|
||||
|
||||
void update(osg::Node& node);
|
||||
|
||||
public:
|
||||
|
||||
ref_ptr<AnimationPath> _animationPath;
|
||||
bool _useInverseMatrix;
|
||||
double _timeOffset;
|
||||
double _timeMultiplier;
|
||||
double _firstTime;
|
||||
mutable double _animationTime;
|
||||
double _latestTime;
|
||||
bool _pause;
|
||||
double _pauseTime;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -28,8 +28,11 @@ class OSGUTIL_EXPORT TransformCallback : public osg::NodeCallback
|
||||
|
||||
TransformCallback(const osg::Vec3& pivot,const osg::Vec3& axis,float angularVelocity);
|
||||
|
||||
virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
|
||||
|
||||
void setPause(bool pause) { _pause = pause; }
|
||||
|
||||
/** implements the callback*/
|
||||
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
|
||||
|
||||
protected:
|
||||
|
||||
float _angular_velocity;
|
||||
@@ -38,6 +41,7 @@ class OSGUTIL_EXPORT TransformCallback : public osg::NodeCallback
|
||||
|
||||
int _previousTraversalNumber;
|
||||
double _previousTime;
|
||||
bool _pause;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -82,30 +82,72 @@ bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& contro
|
||||
}
|
||||
|
||||
|
||||
void AnimationPath::read(std::istream& in)
|
||||
{
|
||||
while (!in.eof())
|
||||
{
|
||||
double time;
|
||||
osg::Vec3 position;
|
||||
osg::Quat rotation;
|
||||
in >> time >> position.x() >> position.y() >> position.z() >> rotation.x() >> rotation.y() >> rotation.z() >> rotation.w();
|
||||
if(!in.eof())
|
||||
insert(time,osg::AnimationPath::ControlPoint(position,rotation));
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationPath::write(std::ostream& fout)
|
||||
{
|
||||
const TimeControlPointMap& tcpm = getTimeControlPointMap();
|
||||
for(TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
|
||||
tcpmitr!=tcpm.end();
|
||||
++tcpmitr)
|
||||
{
|
||||
const ControlPoint& cp = tcpmitr->second;
|
||||
fout<<tcpmitr->first<<" "<<cp._position<<" "<<cp._rotation<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
class AnimationPathCallbackVisitor : public NodeVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
AnimationPathCallbackVisitor(const AnimationPath::ControlPoint& cp):
|
||||
_cp(cp) {}
|
||||
AnimationPathCallbackVisitor(const AnimationPath::ControlPoint& cp, bool useInverseMatrix):
|
||||
_cp(cp),
|
||||
_useInverseMatrix(useInverseMatrix) {}
|
||||
|
||||
virtual void apply(MatrixTransform& mt)
|
||||
{
|
||||
Matrix matrix;
|
||||
_cp.getMatrix(matrix);
|
||||
if (_useInverseMatrix)
|
||||
_cp.getInverse(matrix);
|
||||
else
|
||||
_cp.getMatrix(matrix);
|
||||
|
||||
mt.setMatrix(matrix);
|
||||
}
|
||||
|
||||
virtual void apply(PositionAttitudeTransform& pat)
|
||||
{
|
||||
pat.setPosition(_cp._position);
|
||||
pat.setAttitude(_cp._rotation);
|
||||
if (_useInverseMatrix)
|
||||
{
|
||||
Matrix matrix;
|
||||
_cp.getInverse(matrix);
|
||||
pat.setPosition(matrix.getTrans());
|
||||
pat.setAttitude(_cp._rotation.inverse());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
pat.setPosition(_cp._position);
|
||||
pat.setAttitude(_cp._rotation);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationPath::ControlPoint _cp;
|
||||
|
||||
bool _useInverseMatrix;
|
||||
};
|
||||
|
||||
|
||||
void AnimationPathCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
{
|
||||
if (_animationPath.valid() &&
|
||||
@@ -113,19 +155,52 @@ void AnimationPathCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
nv->getFrameStamp())
|
||||
{
|
||||
double time = nv->getFrameStamp()->getReferenceTime();
|
||||
if (_firstTime==0.0) _firstTime = time;
|
||||
|
||||
_animationTime = ((time-_firstTime)-_timeOffset)*_timeMultiplier;
|
||||
|
||||
AnimationPath::ControlPoint cp;
|
||||
if (_animationPath->getInterpolatedControlPoint(_animationTime,cp))
|
||||
_latestTime = time;
|
||||
|
||||
if (!_pause)
|
||||
{
|
||||
AnimationPathCallbackVisitor apcv(cp);
|
||||
node->accept(apcv);
|
||||
if (_firstTime==0.0) _firstTime = time;
|
||||
update(*node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// must call any nested node callbacks and continue subgraph traversal.
|
||||
NodeCallback::traverse(node,nv);
|
||||
}
|
||||
|
||||
void AnimationPathCallback::update(osg::Node& node)
|
||||
{
|
||||
double animationTime = ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier;
|
||||
|
||||
AnimationPath::ControlPoint cp;
|
||||
if (_animationPath->getInterpolatedControlPoint(animationTime,cp))
|
||||
{
|
||||
AnimationPathCallbackVisitor apcv(cp,_useInverseMatrix);
|
||||
node.accept(apcv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AnimationPathCallback::reset()
|
||||
{
|
||||
_firstTime = _latestTime;
|
||||
_pauseTime = _latestTime;
|
||||
}
|
||||
|
||||
void AnimationPathCallback::setPause(bool pause)
|
||||
{
|
||||
if (_pause==pause)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_pause = pause;
|
||||
if (_pause)
|
||||
{
|
||||
_pauseTime = _latestTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
_firstTime += (_latestTime-_pauseTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ Registry::Registry()
|
||||
// comment out because it was causing problems under OSX - causing it to crash osgconv when constucting ostream in osg::notify().
|
||||
// notify(INFO) << "Constructing osg::Registry"<<std::endl;
|
||||
|
||||
_createNodeFromImage = true;
|
||||
_createNodeFromImage = false;
|
||||
_openingLibrary = false;
|
||||
|
||||
_useObjectCacheHint = false;
|
||||
|
||||
@@ -37,15 +37,7 @@ AnimationPathManipulator::AnimationPathManipulator( const std::string& filename
|
||||
return;
|
||||
}
|
||||
|
||||
while (!in.eof())
|
||||
{
|
||||
double time;
|
||||
osg::Vec3 position;
|
||||
osg::Quat rotation;
|
||||
in >> time >> position.x() >> position.y() >> position.z() >> rotation.x() >> rotation.y() >> rotation.z() >> rotation.w();
|
||||
if(!in.eof())
|
||||
_animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
|
||||
}
|
||||
_animationPath->read(in);
|
||||
|
||||
in.close();
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ void AnimationPathCallback::write(DataOutputStream* out){
|
||||
out->writeDouble(_timeOffset);
|
||||
out->writeDouble(_timeMultiplier);
|
||||
out->writeDouble(_firstTime);
|
||||
out->writeDouble(_animationTime);
|
||||
out->writeDouble(_pauseTime);
|
||||
// Write animationpath if any
|
||||
if(getAnimationPath())
|
||||
{
|
||||
@@ -64,7 +64,7 @@ void AnimationPathCallback::read(DataInputStream* in){
|
||||
_timeOffset = in->readDouble();
|
||||
_timeMultiplier = in->readDouble();
|
||||
_firstTime = in->readDouble();
|
||||
_animationTime = in->readDouble();
|
||||
_pauseTime = in->readDouble();
|
||||
// Read animationpath if any
|
||||
if(in->readInt())
|
||||
{
|
||||
|
||||
@@ -829,14 +829,7 @@ bool ViewerEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActio
|
||||
if (viewer->getAnimationPath())
|
||||
{
|
||||
std::ofstream fout("saved_animation.path");
|
||||
const osg::AnimationPath::TimeControlPointMap& tcpm = viewer->getAnimationPath()->getTimeControlPointMap();
|
||||
for(osg::AnimationPath::TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
|
||||
tcpmitr!=tcpm.end();
|
||||
++tcpmitr)
|
||||
{
|
||||
const osg::AnimationPath::ControlPoint& cp = tcpmitr->second;
|
||||
fout<<tcpmitr->first<<" "<<cp._position<<" "<<cp._rotation<<std::endl;
|
||||
}
|
||||
viewer->getAnimationPath()->write(fout);
|
||||
fout.close();
|
||||
|
||||
osg::notify(osg::NOTICE) << "Saved camera animation to 'saved_animation.path'"<< std::endl;
|
||||
|
||||
@@ -24,6 +24,8 @@ TransformCallback::TransformCallback(const osg::Vec3& pivot,const osg::Vec3& axi
|
||||
|
||||
_previousTraversalNumber = -1;
|
||||
_previousTime = -1.0;
|
||||
|
||||
_pause = false;
|
||||
}
|
||||
|
||||
void TransformCallback::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
||||
@@ -34,14 +36,14 @@ void TransformCallback::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
||||
|
||||
const osg::FrameStamp* fs = nv->getFrameStamp();
|
||||
if (!fs) return; // not frame stamp, no handle on the time so can't move.
|
||||
|
||||
|
||||
double newTime = fs->getReferenceTime();
|
||||
|
||||
// ensure that we do not operate on this node more than
|
||||
// once during this traversal. This is an issue since node
|
||||
// can be shared between multiple parents.
|
||||
if (nv->getTraversalNumber()!=_previousTraversalNumber)
|
||||
if (!_pause && nv->getTraversalNumber()!=_previousTraversalNumber)
|
||||
{
|
||||
double newTime = fs->getReferenceTime();
|
||||
float delta_angle = _angular_velocity*(newTime-_previousTime);
|
||||
|
||||
osg::Matrix mat = osg::Matrix::translate(-_pivot)*
|
||||
@@ -53,8 +55,10 @@ void TransformCallback::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
||||
transform->preMult(mat);
|
||||
|
||||
_previousTraversalNumber = nv->getTraversalNumber();
|
||||
_previousTime = newTime;
|
||||
}
|
||||
|
||||
_previousTime = newTime;
|
||||
|
||||
}
|
||||
|
||||
// must call any nested node callbacks and continue subgraph traversal.
|
||||
|
||||
Reference in New Issue
Block a user