From 21033536a73bfffb4683f1a509e1f5645803b61a Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 13 Jun 2007 20:34:16 +0000 Subject: [PATCH] From Jeremy Moles & Robert Osfield, Added support for playback of animation paths using 'Z' key --- include/osgViewer/ViewerEventHandlers | 26 ++++++----- src/osgViewer/ViewerEventHandlers.cpp | 67 ++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 18 deletions(-) diff --git a/include/osgViewer/ViewerEventHandlers b/include/osgViewer/ViewerEventHandlers index 4c67808bc..aec2ba108 100644 --- a/include/osgViewer/ViewerEventHandlers +++ b/include/osgViewer/ViewerEventHandlers @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -218,17 +219,14 @@ protected: Event handler allowing the user to record the animation "path" of a camera. In it's current implementation, this handler cannot guarantee the final view matrix is correct; it is conceivable that the matrix may be one frame off. Eh--not a big deal! :) -TODO: Find the good filename. -TODO: Write as we go, not when it's all done. -TODO: Create osgviewer on-screen indication that animation is taking place. -TODO: Explore multi-cameras thing. -TODO: Investigate crash if non-focused camera? +TODO: Write the file as we go, not when it's all done. +TODO: Create an osgviewer on-screen indication that animation is taking place. */ class OSGVIEWER_EXPORT RecordCameraPathHandler : public osgGA::GUIEventHandler { public: - RecordCameraPathHandler(); + RecordCameraPathHandler(const std::string &filename = "saved_animation.path"); virtual void getUsage(osg::ApplicationUsage &usage) const; @@ -236,12 +234,16 @@ public: protected: - bool _currentlyRecording; - double _interval; - double _delta; - osg::Timer_t _animStartTime; - osg::Timer_t _lastFrameTime; - osg::ref_ptr _animPath; + std::string _filename; + bool _currentlyRecording; + bool _currentlyPlaying; + double _interval; + double _delta; + osg::Timer_t _animStartTime; + osg::Timer_t _lastFrameTime; + osg::ref_ptr _animPath; + osg::ref_ptr _animPathManipulator; + osg::ref_ptr _oldManipulator; }; } diff --git a/src/osgViewer/ViewerEventHandlers.cpp b/src/osgViewer/ViewerEventHandlers.cpp index 86c0fde88..f77e17786 100644 --- a/src/osgViewer/ViewerEventHandlers.cpp +++ b/src/osgViewer/ViewerEventHandlers.cpp @@ -343,17 +343,19 @@ bool ThreadingHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIAction return false; } -RecordCameraPathHandler::RecordCameraPathHandler(): +RecordCameraPathHandler::RecordCameraPathHandler(const std::string& filename): + _filename(filename), _currentlyRecording(false), + _currentlyPlaying(false), _delta(0.0f), _lastFrameTime(osg::Timer::instance()->tick()), _animStartTime(0) { _animPath = new osg::AnimationPath(); - const char* str = getenv("OSG_CAMERA_ANIMATION_FPS"); + const char* str = getenv("OSG_RECORD_CAMERA_PATH_FPS"); - if(str) _interval = 1.0f / atof(str); + if (str) _interval = 1.0f / atof(str); else _interval = 1.0f / 25.0f; } @@ -361,6 +363,7 @@ RecordCameraPathHandler::RecordCameraPathHandler(): void RecordCameraPathHandler::getUsage(osg::ApplicationUsage &usage) const { usage.addKeyboardMouseBinding("z", "Toggle camera path recording."); + usage.addKeyboardMouseBinding("Z", "Load local camera path recording."); } bool RecordCameraPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) @@ -376,6 +379,7 @@ bool RecordCameraPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GU { case(osgGA::GUIEventAdapter::KEYUP): { + // The user has requested to toggle recording. if (ea.getKey() == 'z') { // The user has requested to BEGIN recording. @@ -383,6 +387,7 @@ bool RecordCameraPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GU { _currentlyRecording = true; _animStartTime = osg::Timer::instance()->tick(); + _animPath->clear(); osg::notify(osg::NOTICE)<<"Recording camera path."<write(out); out.close(); } @@ -405,6 +409,57 @@ bool RecordCameraPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GU return true; } + // The user has requested to toggle playback. You'll notice in the code below that + // we take over the current manipulator; it was originally recommended that we + // check for a KeySwitchManipulator, create one if not present, and then add this + // to either the newly created one or the existing one. However, the code do that was + // EXTREMELY dirty, so I opted for a simpler solution. At a later date, someone may + // want to implement the original recomendation (which is in a mailing list reply + // from June 1st by Robert in a thread called "osgviewer Camera Animation (preliminary)". + else if (ea.getKey() == 'Z') + { + if (_currentlyRecording) + { + _currentlyRecording = false; + _delta = 0.0f; + + // In the future this will need to be written continuously, rather + // than all at once. + std::ofstream out(_filename.c_str()); + osg::notify(osg::NOTICE)<<"Writing camera file: "<<_filename<write(out); + out.close(); + } + + // The user has requested to BEGIN playback. + if (!_currentlyPlaying) + { + _animPathManipulator = new osgGA::AnimationPathManipulator(_animPath.get()); + _animPathManipulator->home(ea,aa); + + + // If we succesfully found our _filename file, set it and keep a copy + // around of the original MatrixManipulator to restore later. + if (_animPathManipulator.valid() && _animPathManipulator->valid()) + { + _oldManipulator = viewer->getCameraManipulator(); + viewer->setCameraManipulator(_animPathManipulator.get()); + _currentlyPlaying = true; + } + } + + // The user has requested to STOP playback. + else + { + // Restore the old manipulator if necessary and stop playback. + if(_oldManipulator.valid()) viewer->setCameraManipulator(_oldManipulator.get()); + _currentlyPlaying = false; + _oldManipulator = 0; + } + + return true; + } + break; } case(osgGA::GUIEventAdapter::FRAME):