I put this together during lunch today if anyone is interested in trying
it out (I'll submit formal files when it's done, Robert). Basically, it
tries to emulate the old osgProducer "camera animation" functionality
(which we've been discussing in another thread). It is a patch against
SVN as of a few minutes ago (May 31st, 16:30 EST)

It seems to be working okay for me at the moment. Usage is:

        # OSG_CAMERA_ANIMATION_FPS=25 osgviewer cow.osg
        ...press Z...
        ...move camera...
        ...press Z again...
        # vim camera-path.txt
        ...awesomeness!...
        # osgviewer -p camera-path.txt cow.osg

In the example above I explicitly set the FPS to 25, although this is
the default. It doesn't seem to need a high ControlPoint capture value,
since it appears to do smooth interpolation between them...
Index: include/osgViewer/ViewerEventHandlers
===================================================================
--- include/osgViewer/ViewerEventHandlers	(revision 6793)
+++ include/osgViewer/ViewerEventHandlers	(working copy)
@@ -14,6 +14,7 @@
 #ifndef OSGVIEWER_VIEWEREVENTHANDLER
 #define OSGVIEWER_VIEWEREVENTHANDLER 1
 
+#include <osg/AnimationPath>
 #include <osgGA/GUIEventHandler>
 #include <osgViewer/GraphicsWindow>
 
@@ -102,6 +103,36 @@
         bool            _done;
 };
 
+/**
+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?
+*/
+class AnimationPathHandler : public osgGA::GUIEventHandler
+{
+public:
+
+        AnimationPathHandler();
+
+        virtual void getUsage(osg::ApplicationUsage &usage) const;
+
+        bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa);
+
+protected:
+
+        bool                             _currentlyRecording;
+        double                           _interval;
+        double                           _delta;
+        osg::Timer_t                     _animStartTime;
+        osg::Timer_t                     _lastFrameTime;
+        osg::ref_ptr<osg::AnimationPath> _animPath;
+};
+
 }
 
 #endif
Index: applications/osgviewer/osgviewer.cpp
===================================================================
--- applications/osgviewer/osgviewer.cpp	(revision 6793)
+++ applications/osgviewer/osgviewer.cpp	(working copy)
@@ -117,6 +117,9 @@
     // add the help handler
     viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
 
+    // add the camera path handler
+    viewer.addEventHandler(new osgViewer::AnimationPathHandler);
+
     while (arguments.read("--SingleThreaded")) viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
     while (arguments.read("--CullDrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
     while (arguments.read("--DrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
Index: src/osgViewer/ViewerEventHandlers.cpp
===================================================================
--- src/osgViewer/ViewerEventHandlers.cpp	(revision 6793)
+++ src/osgViewer/ViewerEventHandlers.cpp	(working copy)
@@ -11,6 +11,7 @@
 * OpenSceneGraph Public License for more details.
 */
 
+#include <fstream>
 #include <osgViewer/Viewer>
 #include <osgViewer/ViewerEventHandlers>
 
@@ -342,4 +343,95 @@
     return false;
 }
 
+AnimationPathHandler::AnimationPathHandler():
+    _currentlyRecording(false),
+    _delta(0.0f),
+    _lastFrameTime(osg::Timer::instance()->tick()),
+    _animStartTime(0)
+{
+    _animPath = new osg::AnimationPath();
+
+    const char* str = getenv("OSG_CAMERA_ANIMATION_FPS");
+
+    if(str) _interval = 1.0f / atof(str);
+
+    else _interval = 1.0f / 25.0f;
 }
+
+void AnimationPathHandler::getUsage(osg::ApplicationUsage &usage) const
+{
+    usage.addKeyboardMouseBinding("z", "Toggle camera path recording.");
+}
+
+bool AnimationPathHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
+{
+    osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
+
+    if (viewer == NULL)
+    {
+        return false;
+    }
+
+    switch(ea.getEventType())
+    {
+    case(osgGA::GUIEventAdapter::KEYUP):
+        {
+            if (ea.getKey() == 'z')
+            {
+                // The user has requested to BEGIN recording. If there isn't a "focused"
+                // Camera, ignore the key press.
+                if (!_currentlyRecording && viewer->getCameraWithFocus() != NULL)
+                {
+                    _currentlyRecording = true;
+                    _animStartTime = osg::Timer::instance()->tick();
+                }
+
+                // THe user has requested to STOP recording, write the file!
+                else
+                {
+                    _currentlyRecording = false;
+                    _delta = 0.0f;
+
+                    // In the future this will need to be written continuously, rather
+                    // than all at once.
+                    std::ofstream out("camera-path.txt");
+                    osg::notify(osg::NOTICE)<<"Writing camera file: camera-path.txt"<<std::endl;
+                    _animPath->write(out);
+                    out.close();
+                }
+
+                return true;
+            }
+
+            break;
+        }
+    case(osgGA::GUIEventAdapter::FRAME):
+        {
+            // Calculate our current delta (difference) in time between the last frame and
+            // current frame, regardless of whether we actually store a ControlPoint...
+            osg::Timer_t time = osg::Timer::instance()->tick();
+            double delta = osg::Timer::instance()->delta_s(_lastFrameTime, time);
+            _lastFrameTime = time;
+
+            // If our internal _delta is finally large enough to warrant a ControlPoint
+            // insertion, do so now. Be sure and reset the internal _delta, so we can start
+            // calculating when the next insert should happen.
+            if (_currentlyRecording && _delta >= _interval)
+            {
+                const osg::Matrixd& m = viewer->getCameraWithFocus()->getInverseViewMatrix();
+                _animPath->insert(osg::Timer::instance()->delta_s(_animStartTime, time), osg::AnimationPath::ControlPoint(m.getTrans(), m.getRotate()));
+                _delta = 0.0f;
+            }
+
+            else _delta += delta;
+
+            break;
+        }
+    default:
+        break;
+    }
+
+    return false;
+}
+
+}
_______________________________________________
osg-users mailing list
osg-users@openscenegraph.net
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/

Reply via email to