diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2a0935cef..7b099dc80 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -68,6 +68,7 @@ IF(DYNAMIC_OPENSCENEGRAPH) ADD_SUBDIRECTORY(osggpx) ADD_SUBDIRECTORY(osggraphicscost) ADD_SUBDIRECTORY(osgmanipulator) + ADD_SUBDIRECTORY(osgimpostor) ADD_SUBDIRECTORY(osgmovie) ADD_SUBDIRECTORY(osgmultiplemovies) ADD_SUBDIRECTORY(osgmultiplerendertargets) diff --git a/examples/osgimpostor/CMakeLists.txt b/examples/osgimpostor/CMakeLists.txt new file mode 100644 index 000000000..c7b831313 --- /dev/null +++ b/examples/osgimpostor/CMakeLists.txt @@ -0,0 +1,8 @@ +#this file is automatically generated + + +SET(TARGET_SRC TestManipulator.cpp osgimpostor.cpp ) +SET(TARGET_H TestManipulator.h ) +SET(TARGET_ADDED_LIBRARIES osgSim ) +#### end var setup ### +SETUP_EXAMPLE(osgimpostor) diff --git a/examples/osgimpostor/TestManipulator.cpp b/examples/osgimpostor/TestManipulator.cpp new file mode 100644 index 000000000..e128617f0 --- /dev/null +++ b/examples/osgimpostor/TestManipulator.cpp @@ -0,0 +1,292 @@ +/* OpenSceneGraph example, osgimpostor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include "TestManipulator.h" +#include + +using namespace osg; +using namespace osgGA; + +TestManipulator::TestManipulator() +{ + _modelScale = 0.01f; + _minimumZoomScale = 0.05f; + _thrown = false; + + _distance = 1.0f; +} + + +TestManipulator::~TestManipulator() +{ +} + + +void TestManipulator::setNode(osg::Node* node) +{ + _node = node; + if (_node.get()) + { + const osg::BoundingSphere& boundingSphere=_node->getBound(); + _modelScale = boundingSphere._radius; + } +} + + +const osg::Node* TestManipulator::getNode() const +{ + return _node.get(); +} + + +osg::Node* TestManipulator::getNode() +{ + return _node.get(); +} + + + /*ea*/ +void TestManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us) +{ + if(_node.get()) + { + + const osg::BoundingSphere& boundingSphere=_node->getBound(); + + computePosition(boundingSphere.center()+osg::Vec3(0.0f, 0.0f, 20.0f), + osg::Vec3(0.0f, 1.0f, 0.0f), + osg::Vec3(0.0f, 0.0f, 1.0f)); + + us.requestRedraw(); + } +} + + +void TestManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& ) +{ + flushMouseEventStack(); +} + +bool TestManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) +{ + switch(ea.getEventType()) + { + case(GUIEventAdapter::PUSH): + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + return true; + } + + case(GUIEventAdapter::RELEASE): + { + if (ea.getButtonMask()==0) + { + + if (isMouseMoving()) + { + if (calcMovement()) + { + us.requestRedraw(); + us.requestContinuousUpdate(true); + _thrown = true; + } + } + else + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + } + + } + else + { + flushMouseEventStack(); + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + } + return true; + } + + case(GUIEventAdapter::DRAG): + { + addMouseEvent(ea); + if (calcMovement()) us.requestRedraw(); + us.requestContinuousUpdate(false); + _thrown = false; + return true; + } + + case(GUIEventAdapter::MOVE): + { + return false; + } + + case(GUIEventAdapter::KEYDOWN): + if (ea.getKey()==' ') + { + flushMouseEventStack(); + _thrown = false; + home(ea,us); + us.requestRedraw(); + us.requestContinuousUpdate(false); + return true; + } + return false; + case(GUIEventAdapter::FRAME): + if (_thrown) + { + if (calcMovement()) us.requestRedraw(); + return true; + } + return false; + default: + return false; + } +} + + +bool TestManipulator::isMouseMoving() +{ + if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; + + static const float velocity = 0.1f; + + float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); + float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); + float len = sqrtf(dx*dx+dy*dy); + float dt = _ga_t0->getTime()-_ga_t1->getTime(); + + return (len>dt*velocity); +} + + +void TestManipulator::flushMouseEventStack() +{ + _ga_t1 = NULL; + _ga_t0 = NULL; +} + + +void TestManipulator::addMouseEvent(const GUIEventAdapter& ea) +{ + _ga_t1 = _ga_t0; + _ga_t0 = &ea; +} + +void TestManipulator::setByMatrix(const osg::Matrixd& matrix) +{ + _center = matrix.getTrans(); + _rotation = matrix.getRotate(); + _distance = 1.0f; +} + +osg::Matrixd TestManipulator::getMatrix() const +{ + return osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_center); +} + +osg::Matrixd TestManipulator::getInverseMatrix() const +{ + return osg::Matrixd::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse()); +} + +void TestManipulator::computePosition(const osg::Vec3& eye,const osg::Vec3& lv,const osg::Vec3& up) +{ + osg::Vec3 f(lv); + f.normalize(); + osg::Vec3 s(f^up); + s.normalize(); + osg::Vec3 u(s^f); + u.normalize(); + + osg::Matrixd rotation_matrix(s[0], u[0], -f[0], 0.0f, + s[1], u[1], -f[1], 0.0f, + s[2], u[2], -f[2], 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + + _center = eye+lv; + _distance = lv.length(); + _rotation = rotation_matrix.getRotate().inverse(); +} + + +bool TestManipulator::calcMovement() +{ + + // return if less then two events have been added. + if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; + + float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); + float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); + + + // return if there is no movement. + if (dx==0 && dy==0) return false; + + unsigned int buttonMask = _ga_t1->getButtonMask(); + if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) + { + + // rotate camera. + + osg::Quat new_rotate; + new_rotate.makeRotate(dx / 3.0f, osg::Vec3(0.0f, 0.0f, 1.0f)); + + _rotation = _rotation*new_rotate; + + return true; + + } + else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON) + { + + // pan model. + + osg::Vec3 dv = osg::Vec3(0.0f, 0.0f, -500.0f) * dy; + + _center += dv; + + return true; + + } + else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) + { + osg::Matrixd rotation_matrix(_rotation); + + + osg::Vec3 uv = osg::Vec3(0.0f,1.0f,0.0f)*rotation_matrix; + osg::Vec3 sv = osg::Vec3(1.0f,0.0f,0.0f)*rotation_matrix; + osg::Vec3 fv = uv ^ sv; + osg::Vec3 dv = fv*(dy*-500.0f)-sv*(dx*500.0f); + + _center += dv; + + return true; + } + + return false; +} diff --git a/examples/osgimpostor/TestManipulator.h b/examples/osgimpostor/TestManipulator.h new file mode 100644 index 000000000..f4bfd8208 --- /dev/null +++ b/examples/osgimpostor/TestManipulator.h @@ -0,0 +1,103 @@ +/* -*-c++-*- +* +* OpenSceneGraph example, osgimpostor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#ifndef OSGGA_TESTMANIPULATOR +#define OSGGA_TESTMANIPULATOR 1 + +#include +#include + +class TestManipulator : public osgGA::CameraManipulator +{ + public: + + TestManipulator(); + virtual ~TestManipulator(); + + /** set the position of the matrix manipulator using a 4x4 Matrix.*/ + virtual void setByMatrix(const osg::Matrixd& matrix); + + /** set the position of the matrix manipulator using a 4x4 Matrix.*/ + virtual void setByInverseMatrix(const osg::Matrixd& matrix) { setByMatrix(osg::Matrixd::inverse(matrix)); } + + /** get the position of the manipulator as 4x4 Matrix.*/ + virtual osg::Matrixd getMatrix() const; + + /** get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ + virtual osg::Matrixd getInverseMatrix() const; + + /** Attach a node to the manipulator. + Automatically detaches previously attached node. + setNode(NULL) detaches previously nodes. + Is ignored by manipulators which do not require a reference model.*/ + virtual void setNode(osg::Node*); + + /** Return node if attached.*/ + virtual const osg::Node* getNode() const; + + /** Return node if attached.*/ + virtual osg::Node* getNode(); + + /** Move the camera to the default position. + May be ignored by manipulators if home functionality is not appropriate.*/ + virtual void home(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us); + + /** Start/restart the manipulator.*/ + virtual void init(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us); + + + /** handle events, return true if handled, false otherwise.*/ + virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us); + + private: + + /** Reset the internal GUIEvent stack.*/ + void flushMouseEventStack(); + /** Add the current mouse GUIEvent to internal stack.*/ + void addMouseEvent(const osgGA::GUIEventAdapter& ea); + + void computePosition(const osg::Vec3& eye,const osg::Vec3& lv,const osg::Vec3& up); + + /** For the give mouse movement calculate the movement of the camera. + Return true is camera has moved and a redraw is required.*/ + bool calcMovement(); + + /** Check the speed at which the mouse is moving. + If speed is below a threshold then return false, otherwise return true.*/ + bool isMouseMoving(); + + // Internal event stack comprising last three mouse events. + osg::ref_ptr _ga_t1; + osg::ref_ptr _ga_t0; + + osg::ref_ptr _node; + + float _modelScale; + float _minimumZoomScale; + + bool _thrown; + + osg::Vec3 _center; + osg::Quat _rotation; + float _distance; + +}; + +#endif diff --git a/examples/osgimpostor/osgimpostor.cpp b/examples/osgimpostor/osgimpostor.cpp new file mode 100644 index 000000000..29c944cd2 --- /dev/null +++ b/examples/osgimpostor/osgimpostor.cpp @@ -0,0 +1,171 @@ +/* OpenSceneGraph example, osgimpostor. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TestManipulator.h" + + +#include +#include + + +int main( int argc, char **argv ) +{ + // use an ArgumentParser object to manage the program arguments. + osg::ArgumentParser arguments(&argc,argv); + + // construct the viewer. + osgViewer::Viewer viewer; + + // set up the camera manipulators. + { + osg::ref_ptr keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator; + + // add local test manipulator more suitable for testing impostors. + keyswitchManipulator->addMatrixManipulator( '0', "Test", new TestManipulator); + + keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() ); + keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() ); + keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() ); + keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() ); + keyswitchManipulator->addMatrixManipulator( '5', "Orbit", new osgGA::OrbitManipulator() ); + keyswitchManipulator->addMatrixManipulator( '6', "FirstPerson", new osgGA::FirstPersonManipulator() ); + keyswitchManipulator->addMatrixManipulator( '7', "Spherical", new osgGA::SphericalManipulator() ); + + std::string pathfile; + double animationSpeed = 1.0; + while(arguments.read("--speed",animationSpeed) ) {} + char keyForAnimationPath = '8'; + while (arguments.read("-p",pathfile)) + { + osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile); + if (apm || !apm->valid()) + { + apm->setTimeScale(animationSpeed); + + unsigned int num = keyswitchManipulator->getNumMatrixManipulators(); + keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm ); + keyswitchManipulator->selectMatrixManipulator(num); + ++keyForAnimationPath; + } + } + + viewer.setCameraManipulator( keyswitchManipulator.get() ); + } + + viewer.addEventHandler(new osgViewer::StatsHandler); + viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet())); + + std::string output_filename; + arguments.read("-o", output_filename); + + + // load the nodes from the commandline arguments. + osg::ref_ptr model = osgDB::readRefNodeFiles(arguments); + if (!model) + { + OSG_NOTICE<<"No model loaded, please specify and model on the the command line"<(model.get())==0) + { + const osg::BoundingSphere& bs = model->getBound(); + if (bs.valid()) + { + + osgSim::Impostor* impostor = new osgSim::Impostor; + + // standard LOD settings + impostor->addChild(model.get()); + impostor->setRange(0,0.0f,1e7f); + impostor->setCenter(bs.center()); + + // impostor specfic settings. + impostor->setImpostorThresholdToBound(5.0f); + + model = impostor; + + } + } + + // we insert an impostor node above the model, so we keep a handle + // on the rootnode of the model, the is required since the + // InsertImpostorsVisitor can add a new root in automatically and + // we would know about it, other than by following the parent path + // up from model. This is really what should be done, but I'll pass + // on it right now as it requires a getRoots() method to be added to + // osg::Node, and we're about to make a release so no new features! + osg::ref_ptr rootnode = new osg::Group; + rootnode->addChild(model); + + + // now insert impostors in the model using the InsertImpostorsVisitor. + osgSim::InsertImpostorsVisitor ov; + + // traverse the model and collect all osg::Group's and osg::LOD's. + // however, don't traverse the rootnode since we want to keep it as + // the start of traversal, otherwise the insertImpostor could insert + // and Impostor above the current root, making it nolonger a root! + model->accept(ov); + + // insert the Impostors above groups and LOD's + ov.insertImpostors(); + + + if (!output_filename.empty()) + { + osgDB::writeNodeFile(*rootnode, output_filename); + return 1; + } + + + + // add model to viewer. + viewer.setSceneData(rootnode); + + return viewer.run(); +}