Files
OpenSceneGraph/src/osgPresentation/SlideEventHandler.cpp

1604 lines
45 KiB
C++

/* -*-c++-*- Present3D - Copyright (C) 1999-2006 Robert Osfield
*
* This software is open source and may be redistributed and/or modified under
* the terms of the GNU General Public License (GPL) version 2.0.
* The full license is in LICENSE.txt file included with this distribution,.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* include LICENSE.txt for more details.
*/
#include <osgPresentation/SlideEventHandler>
#include <osgPresentation/SlideShowConstructor>
#include <osg/AnimationPath>
#include <osg/Transform>
#include <osg/TexEnvCombine>
#include <osg/LightSource>
#include <osg/AlphaFunc>
#include <osg/io_utils>
#include <osgUtil/TransformCallback>
#include <osgUtil/GLObjectsVisitor>
#include <osgDB/WriteFile>
#include <osgGA/AnimationPathManipulator>
#include <osgPresentation/AnimationMaterial>
#include <iostream>
using namespace osgPresentation;
static osg::observer_ptr<SlideEventHandler> s_seh;
SlideEventHandler* SlideEventHandler::instance() { return s_seh.get(); }
bool JumpData::jump(SlideEventHandler* seh) const
{
OSG_INFO<<"Requires jump "<<relativeJump<<", "<<slideNum<<", "<<layerNum<<", "<<slideName<<", "<<layerName<<std::endl;
int slideNumToUse = slideNum;
int layerNumToUse = layerNum;
if (!slideName.empty())
{
osg::Switch* presentation = seh->getPresentationSwitch();
for(unsigned int i=0; i<presentation->getNumChildren(); ++i)
{
osg::Node* node = seh->getSlide(i);
std::string name;
if (node->getUserValue("name",name) && slideName==name)
{
slideNumToUse = i;
break;
}
}
}
else if (relativeJump)
{
slideNumToUse = seh->getActiveSlide() + slideNum;
}
if (!layerName.empty())
{
osg::Switch* slide = seh->getSlide(slideNumToUse);
if (slide)
{
unsigned int i;
for(i=0; i<slide->getNumChildren(); ++i)
{
osg::Node* node = slide->getChild(i);
std::string name;
if (node->getUserValue("name",name))
{
if (layerName==name)
{
layerNumToUse = i;
break;
}
}
}
if (i==slide->getNumChildren())
{
OSG_INFO<<"Could not find layer with "<<layerName<<std::endl;
}
}
else
{
OSG_INFO<<"No appropriate Slide found."<<std::endl;
}
}
else if (relativeJump)
{
layerNumToUse = seh->getActiveLayer() + layerNum;
}
if (slideNumToUse<0) slideNumToUse = 0;
if (layerNumToUse<0) layerNumToUse = 0;
OSG_INFO<<" jump to "<<slideNumToUse<<", "<<layerNumToUse<<std::endl;
return seh->selectSlide(slideNumToUse,layerNumToUse);
}
void LayerAttributes::callEnterCallbacks(osg::Node* node)
{
OSG_INFO<<"LayerAttributes::callEnterCallbacks("<<node<<")"<<std::endl;
for(LayerCallbacks::iterator itr = _enterLayerCallbacks.begin();
itr != _enterLayerCallbacks.end();
++itr)
{
(*(*itr))(node);
}
}
void LayerAttributes::callLeaveCallbacks(osg::Node* node)
{
OSG_INFO<<"LayerAttributes::callLeaveCallbacks("<<node<<")"<<std::endl;
for(LayerCallbacks::iterator itr = _leaveLayerCallbacks.begin();
itr != _leaveLayerCallbacks.end();
++itr)
{
(*(*itr))(node);
}
}
struct InteractiveImageSequenceOperator : public ObjectOperator
{
InteractiveImageSequenceOperator(osg::ImageSequence* imageSequence):
_imageSequence(imageSequence) {}
virtual void* ptr() const { return _imageSequence.get(); }
virtual void enter(SlideEventHandler* seh)
{
set(seh);
// need to pause till the load has been completed.
}
virtual void maintain(SlideEventHandler* /*seh*/)
{
}
virtual void leave(SlideEventHandler* /*seh*/)
{
}
virtual void setPause(SlideEventHandler* /*seh*/, bool /*pause*/)
{
}
virtual void reset(SlideEventHandler* seh)
{
set(seh);
}
void set(SlideEventHandler* /*seh*/)
{
//OSG_NOTICE<<"InteractiveImageSequenceOperator::set(..)"<<std::endl;
}
osg::ref_ptr<osg::ImageSequence> _imageSequence;
};
struct ImageStreamOperator : public ObjectOperator
{
ImageStreamOperator(osg::ImageStream* imageStream):
_imageStream(imageStream),
_delayTime(0.0),
_startTime(0.0),
_stopTime(-1.0),
_timeOfLastReset(0.0),
_started(false),
_stopped(false)
{
_imageStream->getUserValue("delay",_delayTime);
_imageStream->getUserValue("start",_startTime);
_imageStream->getUserValue("stop",_stopTime);
}
virtual void* ptr() const { return _imageStream.get(); }
virtual void enter(SlideEventHandler* seh)
{
OSG_NOTICE<<"enter() : _imageStream->rewind() + play"<<std::endl;
reset(seh);
}
virtual void frame(SlideEventHandler* seh)
{
if (_delayTime!=0.0 && !_started && !_stopped)
{
double timeSinceLastRest = seh->getReferenceTime()-_timeOfLastReset;
if (timeSinceLastRest>_delayTime)
{
OSG_NOTICE<<"ImageStreamOperator::frame("<<seh->getReferenceTime()<<") calling start"<<std::endl;
start(seh);
}
}
if (_stopTime>0.0 && _started && !_stopped)
{
double timeSinceLastReset = seh->getReferenceTime()-_timeOfLastReset;
double timeSinceStart = (timeSinceLastReset-_delayTime);
if ((timeSinceStart+_startTime)>_stopTime)
{
OSG_NOTICE<<"ImageStreamOperator::frame("<<seh->getReferenceTime()<<") calling stop"<<std::endl;
stop(seh);
}
}
}
virtual void maintain(SlideEventHandler*)
{
OSG_NOTICE<<"ImageStreamOperator::maintain()"<<std::endl;
}
virtual void leave(SlideEventHandler*)
{
OSG_NOTICE<<"leave() : _imageStream->pause()"<<std::endl;
_imageStream->pause();
}
virtual void setPause(SlideEventHandler*, bool pause)
{
OSG_INFO<<"_imageStream->setPause("<<pause<<")"<<std::endl;
if (_started)
{
if (pause) _imageStream->pause();
else _imageStream->play();
}
}
virtual void reset(SlideEventHandler* seh)
{
OSG_NOTICE<<"ImageStreamOperator::reset()"<<std::endl;
_timeOfLastReset = seh->getReferenceTime();
_stopped = false;
if (_delayTime==0.0)
{
start(seh);
}
}
void start(SlideEventHandler*)
{
if (_started) return;
_started = true;
_stopped = false;
if (_startTime!=0.0) _imageStream->seek(_startTime);
else _imageStream->rewind();
//_imageStream->setVolume(previousVolume);
_imageStream->play();
// add a delay so that movie thread has a chance to do the rewind
float microSecondsToDelay = SlideEventHandler::instance()->getTimeDelayOnNewSlideWithMovies() * 1000000.0f;
OpenThreads::Thread::microSleep(static_cast<unsigned int>(microSecondsToDelay));
}
void stop(SlideEventHandler* /*seh*/)
{
if (!_started) return;
_started = false;
_stopped = true;
_imageStream->pause();
}
osg::ref_ptr<osg::ImageStream> _imageStream;
double _delayTime;
double _startTime;
double _stopTime;
double _timeOfLastReset;
bool _started;
bool _stopped;
};
struct CallbackOperator : public ObjectOperator
{
CallbackOperator(osg::Node* node, osg::Referenced* callback):
_node(node),
_callback(callback) {}
virtual void* ptr() const { return _callback.get(); }
virtual void enter(SlideEventHandler* seh)
{
reset(seh);
}
virtual void maintain(SlideEventHandler*)
{
}
virtual void leave(SlideEventHandler*)
{
}
virtual void setPause(SlideEventHandler*, bool pause)
{
osg::NodeCallback* nc = dynamic_cast<osg::NodeCallback*>(_callback.get());
osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(_callback.get());
osgUtil::TransformCallback* tc = dynamic_cast<osgUtil::TransformCallback*>(_callback.get());
AnimationMaterialCallback* amc = dynamic_cast<AnimationMaterialCallback*>(_callback.get());
PropertyAnimation* pa = dynamic_cast<PropertyAnimation*>(_callback.get());
if (apc)
{
OSG_INFO<<"apc->setPause("<<pause<<")"<<std::endl;
apc->setPause(pause);
}
else if (tc)
{
OSG_INFO<<"tc->setPause("<<pause<<")"<<std::endl;
tc->setPause(pause);
}
else if (amc)
{
OSG_INFO<<"amc->setPause("<<pause<<")"<<std::endl;
amc->setPause(pause);
}
else if (pa)
{
pa->setPause(pause);
}
else if (nc)
{
OSG_NOTICE<<"Need to pause callback : "<<nc->className()<<std::endl;
}
}
virtual void reset(SlideEventHandler*)
{
osg::NodeCallback* nc = dynamic_cast<osg::NodeCallback*>(_callback.get());
osg::AnimationPathCallback* apc = dynamic_cast<osg::AnimationPathCallback*>(_callback.get());
osgUtil::TransformCallback* tc = dynamic_cast<osgUtil::TransformCallback*>(_callback.get());
AnimationMaterialCallback* amc = dynamic_cast<AnimationMaterialCallback*>(_callback.get());
PropertyAnimation* pa = dynamic_cast<PropertyAnimation*>(_callback.get());
if (apc)
{
apc->reset();
apc->update(*_node);
}
else if (tc)
{
}
else if (amc)
{
amc->reset();
amc->update(*_node);
}
else if (pa)
{
pa->reset();
pa->update(*_node);
}
else
{
OSG_NOTICE<<"Need to reset callback : "<<nc->className()<<std::endl;
}
}
osg::ref_ptr<osg::Node> _node;
osg::ref_ptr<osg::Referenced> _callback;
};
struct LayerAttributesOperator : public ObjectOperator
{
LayerAttributesOperator(osg::Node* node, LayerAttributes* la):
_node(node),
_layerAttribute(la)
{
}
virtual void* ptr() const { return _layerAttribute.get(); }
virtual void enter(SlideEventHandler*)
{
_layerAttribute->callEnterCallbacks(_node.get());
if (!_layerAttribute->_keys.empty())
{
OSG_INFO<<"applyKeys {"<<std::endl;
for(LayerAttributes::Keys::iterator itr = _layerAttribute->_keys.begin();
itr != _layerAttribute->_keys.end();
++itr)
{
SlideEventHandler::instance()->dispatchEvent(*itr);
}
OSG_INFO<<"}"<<std::endl;
}
if (!_layerAttribute->_runStrings.empty())
{
for(LayerAttributes::RunStrings::iterator itr = _layerAttribute->_runStrings.begin();
itr != _layerAttribute->_runStrings.end();
++itr)
{
OSG_NOTICE<<"Run "<<itr->c_str()<<std::endl;
osg::Timer_t startTick = osg::Timer::instance()->tick();
int result = system(itr->c_str());
OSG_INFO<<"system("<<*itr<<") result "<<result<<std::endl;
double timeForRun = osg::Timer::instance()->delta_s(startTick, osg::Timer::instance()->tick());
osgGA::EventQueue* eq = SlideEventHandler::instance()->getViewer()->getEventQueue();
if (eq)
{
osg::Timer_t new_startTick = eq->getStartTick() + osg::Timer_t(timeForRun / osg::Timer::instance()->getSecondsPerTick());
eq->setStartTick(new_startTick);
}
}
}
}
virtual void maintain(SlideEventHandler*)
{
}
virtual void leave(SlideEventHandler*)
{
OSG_INFO<<"LayerAttribute leave"<<std::endl;
_layerAttribute->callLeaveCallbacks(_node.get());
}
virtual void setPause(SlideEventHandler*, bool /*pause*/)
{
}
virtual void reset(SlideEventHandler*)
{
}
osg::ref_ptr<osg::Node> _node;
osg::ref_ptr<LayerAttributes> _layerAttribute;
};
class FindOperatorsVisitor : public osg::NodeVisitor
{
public:
FindOperatorsVisitor(ActiveOperators::OperatorList& operatorList, osg::NodeVisitor::TraversalMode tm):
osg::NodeVisitor(tm),
_operatorList(operatorList) {}
META_NodeVisitor(osgPresentation, FindOperatorsVisitor)
void apply(osg::Node& node)
{
if (node.getStateSet()) process(node.getStateSet());
if (node.getUpdateCallback())
{
_operatorList.insert(new CallbackOperator(&node, node.getUpdateCallback()));
}
LayerAttributes* la = dynamic_cast<LayerAttributes*>(node.getUserData());
if (la)
{
if ((_objectsHandled[la]++)==0)
{
OSG_NOTICE<<"LayerAttributeOperator for "<<la<<" required, assigning one."<<std::endl;
_operatorList.insert(new LayerAttributesOperator(&node, la));
}
else
{
OSG_NOTICE<<"LayerAttributeOperator for "<<la<<" not required, as one already assigned."<<std::endl;
}
}
traverse(node);
}
void apply(osg::Geode& node)
{
apply((osg::Node&)node);
for(unsigned int i=0;i<node.getNumDrawables();++i)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable->getStateSet()) process(drawable->getStateSet());
}
}
virtual void process(osg::StateSet* ss)
{
for(unsigned int i=0;i<ss->getTextureAttributeList().size();++i)
{
osg::Texture* texture = dynamic_cast<osg::Texture*>(ss->getTextureAttribute(i,osg::StateAttribute::TEXTURE));
osg::Image* image = texture ? texture->getImage(0) : 0;
osg::ImageSequence* imageSequence = dynamic_cast<osg::ImageSequence*>(image);
osg::ImageStream* imageStream = dynamic_cast<osg::ImageStream*>(image);
if (imageSequence && imageSequence->getName()=="USE_MOUSE_X_POSITION")
{
if ((_objectsHandled[image]++)==0)
{
OSG_INFO<<"ImageSequenceOperator for"<<imageSequence<<" required, assigning one, name = '"<<image->getName()<<"'"<<std::endl;
_operatorList.insert(new InteractiveImageSequenceOperator(imageSequence));
}
else
{
OSG_INFO<<"ImageSequenceOperator for"<<imageSequence<<" not required, as one already assigned"<<std::endl;
}
}
else if (imageStream)
{
if ((_objectsHandled[image]++)==0)
{
OSG_INFO<<"ImageStreamOperator for"<<imageStream<<" required, assigning one"<<std::endl;
_operatorList.insert(new ImageStreamOperator(imageStream));
}
else
{
OSG_INFO<<"ImageStreamOperator for"<<imageStream<<" not required, as one already assigned"<<std::endl;
}
}
}
}
typedef std::map<osg::Referenced*,unsigned int> ObjectsHandled;
ObjectsHandled _objectsHandled;
ActiveOperators::OperatorList& _operatorList;
};
ActiveOperators::ActiveOperators():
_pause(false)
{
}
ActiveOperators::~ActiveOperators()
{
}
void ActiveOperators::collect(osg::Node* incommingNode, osg::NodeVisitor::TraversalMode tm)
{
_previous.swap(_current);
_current.clear();
FindOperatorsVisitor fov(_current, tm);
if (incommingNode)
{
incommingNode->accept(fov);
}
else
{
OSG_NOTICE<<"ActiveOperators::collect() incommingNode="<<incommingNode<<std::endl;
}
OSG_INFO<<"ActiveOperators::collect("<<incommingNode<<")"<<std::endl;
OSG_INFO<<" _previous.size()="<<_previous.size()<<std::endl;
OSG_INFO<<" _current.size()="<<_current.size()<<std::endl;
_outgoing.clear();
_incomming.clear();
_maintained.clear();
for(OperatorList::iterator itr = _previous.begin();
itr != _previous.end();
++itr)
{
ObjectOperator* prev = itr->get();
if (_current.count(prev)==0) _outgoing.insert(prev);
else _maintained.insert(prev);
}
for(OperatorList::iterator itr = _current.begin();
itr != _current.end();
++itr)
{
ObjectOperator* curr = itr->get();
if (_previous.count(curr)==0) _incomming.insert(curr);
}
}
void ActiveOperators::frame(SlideEventHandler* seh)
{
for(OperatorList::iterator itr = _current.begin();
itr != _current.end();
++itr)
{
(*itr)->frame(seh);
}
}
void ActiveOperators::setPause(SlideEventHandler* seh, bool pause)
{
_pause = pause;
for(OperatorList::iterator itr = _current.begin();
itr != _current.end();
++itr)
{
(*itr)->setPause(seh, _pause);
}
}
void ActiveOperators::reset(SlideEventHandler* seh)
{
for(OperatorList::iterator itr = _current.begin();
itr != _current.end();
++itr)
{
(*itr)->reset(seh);
}
}
void ActiveOperators::process(SlideEventHandler* seh)
{
processOutgoing(seh);
processMaintained(seh);
processIncomming(seh);
}
void ActiveOperators::processOutgoing(SlideEventHandler* seh)
{
OSG_INFO<<" outgoing.size()="<<_outgoing.size()<<std::endl;
for(OperatorList::iterator itr = _outgoing.begin();
itr != _outgoing.end();
++itr)
{
(*itr)->leave(seh);
}
}
void ActiveOperators::processMaintained(SlideEventHandler* seh)
{
OSG_INFO<<" maintained.size()="<<_maintained.size()<<std::endl;
for(OperatorList::iterator itr = _maintained.begin();
itr != _maintained.end();
++itr)
{
(*itr)->maintain(seh);
}
}
void ActiveOperators::processIncomming(SlideEventHandler* seh)
{
OSG_INFO<<" incomming.size()="<<_incomming.size()<<std::endl;
for(OperatorList::iterator itr = _incomming.begin();
itr != _incomming.end();
++itr)
{
(*itr)->enter(seh);
(*itr)->setPause(seh, _pause);
}
}
class FindHomePositionVisitor : public osg::NodeVisitor
{
public:
FindHomePositionVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) {}
void apply(osg::Node& node)
{
HomePosition* homePosition = dynamic_cast<HomePosition*>(node.getUserData());
if (homePosition)
{
_homePosition = homePosition;
}
traverse(node);
}
osg::ref_ptr<HomePosition> _homePosition;
};
class FindNamedSwitchVisitor : public osg::NodeVisitor
{
public:
FindNamedSwitchVisitor(const std::string& name):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_name(name),
_switch(0) {}
void apply(osg::Switch& sw)
{
if (sw.getName().find(_name)!=std::string::npos)
{
_switch = &sw;
return; // note, no need to do traverse now we've located the relevant switch
}
traverse(sw);
}
std::string _name;
osg::Switch* _switch;
};
class FindFilePathDataVisitor : public osg::NodeVisitor
{
public:
FindFilePathDataVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) {}
void apply(osg::Node& node)
{
FilePathData* fdd = dynamic_cast<FilePathData*>(node.getUserData());
if (fdd)
{
OSG_INFO<<"Recorded FilePathData"<<std::endl;
osgDB::setDataFilePathList(fdd->filePathList);
}
traverse(node);
}
};
class UpdateLightVisitor : public osg::NodeVisitor
{
public:
UpdateLightVisitor(const osg::Matrixd& viewMatrix, float currentX, float currentY):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_viewMatrix(viewMatrix),
_currentX(currentX), _currentY(currentY) {}
void apply(osg::Node& node)
{
traverse(node);
}
void apply(osg::LightSource& lightsource)
{
if (lightsource.getLight())
{
if (lightsource.getReferenceFrame()==osg::LightSource::RELATIVE_RF)
{
apply( osg::Matrix::identity(), lightsource.getLight());
}
else
{
apply(osg::computeEyeToLocal(_viewMatrix,_nodePath), lightsource.getLight());
}
}
traverse(lightsource);
}
void apply(const osg::Matrixd& matrix, osg::Light* light)
{
// compute direction of light based on a projecting onto a hemi-sphere.
float sum_x2_y2 = _currentX*_currentX + _currentY*_currentY;
osg::Vec3 direction;
if (sum_x2_y2<1.0) direction.set(_currentX, _currentY, sqrtf(1.0-sum_x2_y2));
else direction.set(_currentX, _currentY, 0.0);
direction.normalize();
direction = osg::Matrixd::transform3x3(matrix, direction);
direction.normalize();
light->setPosition(osg::Vec4(direction,0.0f));
}
osg::Matrixd _viewMatrix;
float _currentX, _currentY;
};
class UpdateAlphaVisitor : public osg::NodeVisitor
{
public:
UpdateAlphaVisitor(bool modAlphaFunc, bool modMaterial, float currentX, float currentY):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
_modAlphaFunc(modAlphaFunc), _modMaterial(modMaterial),
_currentX(currentX), _currentY(currentY) {}
void apply(osg::Node& node)
{
if (node.getStateSet()) apply(*node.getStateSet());
traverse(node);
}
void apply(osg::StateSet& stateset)
{
if (_modAlphaFunc)
{
osg::AlphaFunc* alphaFunc = dynamic_cast<osg::AlphaFunc*>(stateset.getAttribute(osg::StateAttribute::ALPHAFUNC));
if (alphaFunc)
{
OSG_INFO<<"Adjusting alpha func"<<std::endl;
float alpha = alphaFunc->getReferenceValue();
alpha = osg::clampBetween((1.0f-_currentY)*0.5f,0.0f,1.0f);
alphaFunc->setReferenceValue(alpha);
}
}
if (_modMaterial)
{
osg::Material* material = dynamic_cast<osg::Material*>(stateset.getAttribute(osg::StateAttribute::MATERIAL));
if (material)
{
OSG_INFO<<"Adjusting material func"<<std::endl;
float alpha = osg::clampBetween((_currentY+1.0f)*0.5f,0.0f,1.0f);
material->setAlpha(osg::Material::FRONT_AND_BACK,alpha);
}
}
}
bool _modAlphaFunc, _modMaterial;
float _currentX, _currentY;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SlideEventHandler
//
SlideEventHandler::SlideEventHandler(osgViewer::Viewer* viewer):
_viewer(viewer),
_presentationSwitch(0),
_activeSlide(0),
_slideSwitch(0),
_activeLayer(0),
_firstTraversal(true),
_referenceTime(-1.0),
_previousTime(-1.0),
_timePerSlide(1.0),
_autoSteppingActive(false),
_loopPresentation(false),
_pause(false),
_hold(false),
_updateLightActive(false),
_updateOpacityActive(false),
_previousX(0), _previousY(0),
_cursorOn(true),
_releaseAndCompileOnEachNewSlide(false),
_firstSlideOrLayerChange(true),
_tickAtFirstSlideOrLayerChange(0),
_tickAtLastSlideOrLayerChange(0),
_timeDelayOnNewSlideWithMovies(0.25f),
_minimumTimeBetweenKeyPresses(0.25),
_timeLastKeyPresses(-1.0),
_requestReload(false)
{
s_seh = this;
}
double SlideEventHandler::getDuration(const osg::Node* node) const
{
const LayerAttributes* la = dynamic_cast<const LayerAttributes*>(node->getUserData());
return la ? la->_duration : -1.0;
}
void SlideEventHandler::set(osg::Node* model)
{
#if 0
// pause all slides, then just reenable the current slide.
ActivityUpdateCallbacksVisitor aucv(ALL_OBJECTS, true);
aucv.setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
model->accept(aucv);
#endif
_firstSlideOrLayerChange = true;
_tickAtFirstSlideOrLayerChange = 0;
_tickAtLastSlideOrLayerChange = 0;
_timeLastKeyPresses = -1;
ActiveOperators operators;
operators.collect(model, osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
operators.setPause(this, true);
FindNamedSwitchVisitor findPresentation("Presentation");
model->accept(findPresentation);
if (findPresentation._switch)
{
OSG_INFO<<"Presentation '"<<model->getName()<<"'"<<std::endl;
_presentationSwitch = findPresentation._switch;
double duration = getDuration(_presentationSwitch.get());
if (duration>=0.0)
{
OSG_INFO<<"Presentation time set to "<<duration<<std::endl;
_timePerSlide = duration;
}
//selectSlide(0);
}
else
{
OSG_INFO<<"No presentation present in scene."<<std::endl;
_presentationSwitch = 0;
_activeSlide = 0;
FindNamedSwitchVisitor findSlide("Slide");
model->accept(findSlide);
if (findSlide._switch)
{
OSG_INFO<<"Found presentation slide"<<findSlide._switch->getName()<<std::endl;
_slideSwitch = findSlide._switch;
//selectLayer(0);
}
else
{
OSG_INFO<<"No slides present in scene, unable to operate as a slideshow."<<std::endl;
}
}
}
double SlideEventHandler::getCurrentTimeDelayBetweenSlides() const
{
if (_slideSwitch.valid())
{
double duration = -1.0;
if (_activeLayer<static_cast<int>(_slideSwitch->getNumChildren()))
{
duration = getDuration(_slideSwitch->getChild(_activeLayer));
}
if (duration < 0.0)
{
duration = getDuration(_slideSwitch.get());
}
if (duration >=0 )
{
return duration;
}
}
return _timePerSlide;
}
void SlideEventHandler::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(nv);
if (ev)
{
if (node->getNumChildrenRequiringEventTraversal()>0) traverse(node,nv);
if (ev->getActionAdapter() && !ev->getEvents().empty())
{
for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin();
itr != ev->getEvents().end();
++itr)
{
handleWithCheckAgainstIgnoreHandledEventsMask(*(*itr), *(ev->getActionAdapter()), node, nv);
}
}
}
}
bool SlideEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
if (!_viewer)
{
_viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
selectSlide(0);
home();
OSG_NOTICE<<"Assigned viewer. to SlideEventHandler"<<std::endl;
}
//else OSG_NOTICE<<"SlideEventHandler::handle() "<<ea.getTime()<<std::endl;
if (ea.getHandled()) return false;
_referenceTime = ea.getTime();
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::FRAME):
{
if (_autoSteppingActive && !_pause)
{
double time = ea.time();
if (_firstTraversal)
{
_firstTraversal = false;
_previousTime = time;
}
else if (time-_previousTime>=getCurrentTimeDelayBetweenSlides())
{
// _previousTime = time;
if (!_hold)
{
// increment the previous by the required time delay, note relative to the current
// to keep the time relative to an absolute time signal, thus avoid drift of timing.
_previousTime += getCurrentTimeDelayBetweenSlides();
nextLayerOrSlide();
}
else
{
// we're holding of the move to next layer to slide, but we need slip the time forward accordingly
// componensate for the extra time that this frame is recieving.
_previousTime = time-getCurrentTimeDelayBetweenSlides();
}
}
}
_activeOperators.frame(this);
return false;
}
case(osgGA::GUIEventAdapter::KEYDOWN):
{
double time = ea.time();
double deltaTime = time - _timeLastKeyPresses;
if (deltaTime < _minimumTimeBetweenKeyPresses)
{
break;
}
_timeLastKeyPresses = time;
if (ea.getKey()=='g')
{
if (!_autoSteppingActive)
{
_autoSteppingActive = true;
_previousTime = ea.time();
}
return true;
}
else if (ea.getKey()=='h')
{
if (_autoSteppingActive)
{
_autoSteppingActive = false;
_previousTime = ea.time();
}
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Home ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Home)
{
_autoSteppingActive = false;
selectSlide(0);
home(ea,aa);
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_End ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_End)
{
_autoSteppingActive = false;
selectSlide(LAST_POSITION,LAST_POSITION);
home(ea,aa);
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Down ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Down)
{
_autoSteppingActive = false;
nextLayer();
return true;
}
else if (ea.getKey()=='n')
{
_autoSteppingActive = false;
nextLayerOrSlide();
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Up ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Up)
{
_autoSteppingActive = false;
previousLayer();
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Page_Down ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Page_Down)
{
_autoSteppingActive = false;
nextLayerOrSlide();
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Page_Up ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Page_Up)
{
_autoSteppingActive = false;
previousLayerOrSlide();
return true;
}
else if (ea.getKey()=='N' ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_Right ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Right)
{
_autoSteppingActive = false;
nextSlide();
home(ea,aa);
return true;
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Left ||
ea.getKey()==osgGA::GUIEventAdapter::KEY_KP_Left)
{
_autoSteppingActive = false;
previousSlide();
home(ea,aa);
return true;
}
else if (ea.getKey()=='p')
{
if (!_pause)
{
_pause = true;
#if 0
resetUpdateCallbackActivity(ALL_OBJECTS);
#endif
_activeOperators.setPause(this, _pause);
}
return true;
}
else if (ea.getKey()=='o')
{
if (_pause)
{
_pause = false;
#if 0
resetUpdateCallbackActivity(ALL_OBJECTS);
#endif
_activeOperators.setPause(this, _pause);
}
return true;
}
else if (ea.getKey()=='h')
{
_hold = true;
return true;
}
else if (ea.getKey()=='r')
{
#if 0
resetUpdateCallbacks(ALL_OBJECTS);
#endif
_activeOperators.reset(this);
return true;
}
/*
else if (ea.getKey()=='c')
{
_cursorOn = !_cursorOn;
for( unsigned int i = 0; i < _viewer->getCameraConfig()->getNumberOfCameras(); i++ )
{
Producer::Camera* cam = _viewer->getCameraConfig()->getCamera(i);
Producer::RenderSurface* rs = cam->getRenderSurface();
rs->useCursor(_cursorOn);
}
return true;
}
*/
else if (ea.getKey()=='u')
{
updateAlpha(true,false,ea.getXnormalized(),ea.getYnormalized());
return true;
}
else if (ea.getKey()=='i')
{
updateAlpha(false,true,ea.getXnormalized(),ea.getYnormalized());
return true;
}
else if (ea.getKey()=='k')
{
updateLight(ea.getXnormalized(),ea.getYnormalized());
return true;
}
return false;
}
case(osgGA::GUIEventAdapter::KEYUP):
{
if (ea.getKey()=='h')
{
_hold = false;
return true;
}
else if (ea.getKey()=='u')
{
setRequestReload(true);
return true;
}
return false;
}
default:
return false;
}
return false;
}
void SlideEventHandler::getUsage(osg::ApplicationUsage& usage) const
{
usage.addKeyboardMouseBinding("a","Toggle on/off the automatic advancement for image to image");
usage.addKeyboardMouseBinding("n","Advance to next layer or slide");
usage.addKeyboardMouseBinding("p","Move to previous layer or slide");
}
unsigned int SlideEventHandler::getNumSlides()
{
if (_presentationSwitch.valid()) return _presentationSwitch->getNumChildren();
else return 0;
}
osg::Switch* SlideEventHandler::getSlide(int slideNum)
{
if (slideNum<0 || slideNum>static_cast<int>(_presentationSwitch->getNumChildren())) return 0;
FindNamedSwitchVisitor findSlide("Slide");
_presentationSwitch->getChild(slideNum)->accept(findSlide);
return findSlide._switch;
}
osg::Node* SlideEventHandler::getLayer(int slideNum, int layerNum)
{
osg::Switch* slide = getSlide(slideNum);
return (slide && (layerNum>=0 && layerNum<static_cast<int>(slide->getNumChildren()))) ? slide->getChild(layerNum) : 0;
}
bool SlideEventHandler::selectSlide(int slideNum,int layerNum)
{
if (!_presentationSwitch) return false;
OSG_INFO<<"selectSlide("<<slideNum<<","<<layerNum<<")"<<std::endl;
if (slideNum>=static_cast<int>(_presentationSwitch->getNumChildren()))
{
slideNum = LAST_POSITION;
}
if (slideNum==LAST_POSITION && _presentationSwitch->getNumChildren()>0)
{
slideNum = _presentationSwitch->getNumChildren()-1;
}
if (slideNum>=static_cast<int>(_presentationSwitch->getNumChildren())) return false;
osg::Timer_t tick = osg::Timer::instance()->tick();
if (_firstSlideOrLayerChange)
{
_firstSlideOrLayerChange = false;
_tickAtFirstSlideOrLayerChange = tick;
_tickAtLastSlideOrLayerChange = tick;
}
OSG_INFO<<"selectSlide("<<slideNum<<","<<layerNum<<") at time "<<osg::Timer::instance()->delta_s(_tickAtFirstSlideOrLayerChange, tick)<<" seconds, length ="<<osg::Timer::instance()->delta_s(_tickAtLastSlideOrLayerChange, tick)<<" seconds"<<std::endl;
_tickAtLastSlideOrLayerChange = tick;
// dectivate movies etc on current active slide.
bool newSlide = _activeSlide!=slideNum;
if (newSlide)
{
if (_releaseAndCompileOnEachNewSlide)
{
releaseSlide(_activeSlide);
}
}
_activeSlide = slideNum;
_presentationSwitch->setSingleChildOn(_activeSlide);
//OSG_INFO<<"Selected slide '"<<_presentationSwitch->getChild(_activeSlide)->getName()<<"'"<<std::endl;
FindNamedSwitchVisitor findSlide("Slide");
_presentationSwitch->getChild(_activeSlide)->accept(findSlide);
bool result = false;
if (findSlide._switch)
{
//OSG_INFO<<"Found slide '"<<findSlide._switch->getName()<<"'"<<std::endl;
_slideSwitch = findSlide._switch;
result = selectLayer(layerNum);
}
else
{
//OSG_INFO<<"Not found slide"<<std::endl;
updateOperators();
}
// refersh the viewer.
//_viewer->getKeySwitchMatrixManipulator()->setMinimumDistance(0.001);
if (_viewer->getCameraManipulator())
{
_viewer->getCameraManipulator()->setNode(_slideSwitch.get());
_viewer->computeActiveCoordinateSystemNodePath();
}
// resetUpdateCallbacks(ALL_OBJECTS);
bool _useSlideFilePaths = false;
if (_useSlideFilePaths)
{
// set up the file paths
FindFilePathDataVisitor ffpdv;
_presentationSwitch->accept(ffpdv);
}
if (newSlide && _releaseAndCompileOnEachNewSlide)
{
compileSlide(slideNum);
}
return result;
}
bool SlideEventHandler::selectLayer(int layerNum)
{
if (!_slideSwitch) return false;
bool withinSlide = true;
if (layerNum>=static_cast<int>(_slideSwitch->getNumChildren()))
{
withinSlide = false;
layerNum = LAST_POSITION;
}
if (layerNum==LAST_POSITION && _slideSwitch->getNumChildren()>0)
{
layerNum = _slideSwitch->getNumChildren()-1;
}
if (layerNum>=static_cast<int>(_slideSwitch->getNumChildren())) return false;
_activeLayer = layerNum;
_slideSwitch->setSingleChildOn(_activeLayer);
updateOperators();
OSG_INFO<<"Selected layer '"<<_slideSwitch->getChild(_activeLayer)->getName()<<"' num="<<_activeLayer<< std::endl;
return withinSlide;
}
bool SlideEventHandler::nextLayerOrSlide()
{
if (nextLayer())
{
return true;
}
else
{
return nextSlide();
}
}
bool SlideEventHandler::previousLayerOrSlide()
{
OSG_INFO<<"previousLayerOrSlide()"<<std::endl;
if (previousLayer()) return true;
else return previousSlide();
}
bool SlideEventHandler::nextSlide()
{
OSG_INFO<<"nextSlide()"<<std::endl;
LayerAttributes* la = _slideSwitch.valid() ? dynamic_cast<LayerAttributes*>(_slideSwitch->getUserData()) : 0;
if (la && la->getJumpData().requiresJump())
{
return la->getJumpData().jump(this);
}
if (selectSlide(_activeSlide+1)) return true;
else if (_loopPresentation) return selectSlide(0);
else return false;
}
bool SlideEventHandler::previousSlide()
{
OSG_INFO<<"previousSlide()"<<std::endl;
#if 1
// start position when doing previous slide set to top of slide
if (_activeSlide>0) return selectSlide(_activeSlide-1);
else if (_loopPresentation && _presentationSwitch.valid()) return selectSlide(_presentationSwitch->getNumChildren()-1);
else return false;
#else
// start position when doing previous slide set to end of slide
if (_activeSlide>0) return selectSlide(_activeSlide-1,LAST_POSITION);
else if (_loopPresentation && _presentationSwitch.valid()) return selectSlide(_presentationSwitch->getNumChildren()-1,LAST_POSITION);
else return false;
#endif
}
bool SlideEventHandler::nextLayer()
{
LayerAttributes* la = (_slideSwitch.valid() && _activeLayer<static_cast<int>(_slideSwitch->getNumChildren())) ? dynamic_cast<LayerAttributes*>(_slideSwitch->getChild(_activeLayer)->getUserData()) : 0;
if (la)
{
la->callLeaveCallbacks(_slideSwitch->getChild(_activeLayer));
if (la->getJumpData().requiresJump())
{
return la->getJumpData().jump(this);
}
}
OSG_INFO<<"nextLayer() calling selectLayer("<<_activeLayer+1<<")"<<std::endl;
return selectLayer(_activeLayer+1);
}
bool SlideEventHandler::previousLayer()
{
OSG_INFO<<"previousLayer()"<<std::endl;
if (_activeLayer>0) return selectLayer(_activeLayer-1);
else return false;
}
void SlideEventHandler::updateOperators()
{
_activeOperators.collect(_slideSwitch.get());
_activeOperators.process(this);
if (_viewer.valid())
{
updateLight(0.0f,0.0f);
}
}
bool SlideEventHandler::home(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
FindHomePositionVisitor fhpv;
osg::Node* node = _viewer->getSceneData();
if (node) node->accept(fhpv);
if (_viewer->getCameraManipulator())
{
if (fhpv._homePosition.valid())
{
OSG_INFO<<"Doing home for stored home position."<<std::endl;
_viewer->getCameraManipulator()->setAutoComputeHomePosition(false);
_viewer->getCameraManipulator()->setHomePosition(
fhpv._homePosition->eye,
fhpv._homePosition->center,
fhpv._homePosition->up);
}
else
{
_viewer->getCameraManipulator()->setAutoComputeHomePosition(true);
}
_viewer->getCameraManipulator()->home(ea,aa);
}
return true;
}
bool SlideEventHandler::home()
{
osg::ref_ptr<osgGA::GUIEventAdapter> ea = new osgGA::GUIEventAdapter;
ea->setEventType(osgGA::GUIEventAdapter::FRAME);
ea->setTime(_viewer->getEventQueue()->getTime());
home(*ea,*_viewer);
return true;
}
void SlideEventHandler::updateAlpha(bool modAlphaFunc, bool modMaterial, float x, float y)
{
OSG_INFO<<"updateAlpha("<<x<<","<<y<<")"<<std::endl;
UpdateAlphaVisitor uav(modAlphaFunc, modMaterial, x,y);
if (_presentationSwitch.valid()) _presentationSwitch->accept(uav);
else if (_viewer->getSceneData()) _viewer->getSceneData()->accept(uav);
}
void SlideEventHandler::updateLight(float x, float y)
{
OSG_INFO<<"updateLight("<<x<<", "<<y<<")"<<std::endl;
UpdateLightVisitor uav(_viewer->getCamera()->getViewMatrix(),x,y);
_viewer->getSceneData()->accept(uav);
if (_viewer->getLightingMode()!= osg::View::NO_LIGHT && _viewer->getLight())
{
if (_viewer->getLightingMode()== osg::View::SKY_LIGHT)
{
uav.apply(_viewer->getCamera()->getViewMatrix(), _viewer->getLight());
}
else if (_viewer->getLightingMode()== osg::View::HEADLIGHT)
{
uav.apply(osg::Matrix::identity(), _viewer->getLight());
}
}
}
void SlideEventHandler::compileSlide(unsigned int slideNum)
{
if (!_compileSlideCallback)
{
_compileSlideCallback = new CompileSlideCallback();
osgViewer::Viewer::Cameras cameras;
_viewer->getCameras(cameras);
for(osgViewer::Viewer::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
(*itr)->setPreDrawCallback(_compileSlideCallback.get());
}
}
_compileSlideCallback->needCompile(_presentationSwitch->getChild(slideNum));
}
void SlideEventHandler::releaseSlide(unsigned int slideNum)
{
osgUtil::GLObjectsVisitor globjVisitor(osgUtil::GLObjectsVisitor::RELEASE_DISPLAY_LISTS|
osgUtil::GLObjectsVisitor::RELEASE_STATE_ATTRIBUTES);
globjVisitor.setNodeMaskOverride(0xffffffff);
_presentationSwitch->getChild(slideNum)->accept(globjVisitor);
}
void SlideEventHandler::dispatchEvent(const KeyPosition& keyPosition)
{
osgGA::EventQueue* eq = _viewer->getEventQueue();
// reset the time of the last key press to ensure that the event is disgarded as a key repeat.
_timeLastKeyPresses = -1.0;
if (keyPosition._x!=FLT_MAX)
{
float xRescaled = eq->getCurrentEventState()->getXmin() + (keyPosition._x+1.0f)*0.5f*(eq->getCurrentEventState()->getXmax()-eq->getCurrentEventState()->getXmin());
eq->getCurrentEventState()->setX(xRescaled);
}
if (keyPosition._y!=FLT_MAX)
{
float y = (eq->getCurrentEventState()->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) ?
keyPosition._y : -keyPosition._y;
float yRescaled = eq->getCurrentEventState()->getYmin() + (y+1.0f)*0.5f*(eq->getCurrentEventState()->getYmax()-eq->getCurrentEventState()->getYmin());
eq->getCurrentEventState()->setY(yRescaled);
}
eq->keyPress(keyPosition._key);
eq->keyRelease(keyPosition._key);
}
void SlideEventHandler::setRequestReload(bool flag)
{
_requestReload = flag;
}