Added new osgGA - GUI Adapter library submitted by Neil Salter. This will

replace the current GUI adapter code inside osgUtil.
This commit is contained in:
Robert Osfield
2002-05-09 10:31:03 +00:00
parent e58b79c997
commit cf4a3500ec
28 changed files with 2617 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
#include <osg/GL>
#include <osg/Matrix>
#include <osgGA/CameraManipulator>
using namespace osg;
using namespace osgGA;
CameraManipulator::CameraManipulator(): _camera(NULL)
{
}
CameraManipulator::~CameraManipulator()
{
}
void CameraManipulator::setCamera(Camera *camera)
{
_camera=camera;
}
const Camera *CameraManipulator::getCamera() const
{
return _camera.get();
}
Camera *CameraManipulator::getCamera()
{
return _camera.get();
}
bool CameraManipulator::handle(const GUIEventAdapter&,GUIActionAdapter&)
{
return false;
}

View File

@@ -0,0 +1,565 @@
#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <osgGA/DriveManipulator>
#include <osgUtil/IntersectVisitor>
#include <osg/Notify>
using namespace osg;
using namespace osgGA;
DriveManipulator::DriveManipulator()
{
_modelScale = 0.01f;
_velocity = 0.0f;
//_speedMode = USE_MOUSE_Y_FOR_SPEED;
_speedMode = USE_MOUSE_BUTTONS_FOR_SPEED;
}
DriveManipulator::~DriveManipulator()
{
}
void DriveManipulator::setNode(osg::Node* node)
{
_node = node;
if (_node.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_modelScale = boundingSphere._radius;
_height = sqrtf(_modelScale)*0.03f;
_buffer = sqrtf(_modelScale)*0.05f;
}
}
const osg::Node* DriveManipulator::getNode() const
{
return _node.get();
}
osg::Node* DriveManipulator::getNode()
{
return _node.get();
}
void DriveManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
if(_node.get() && _camera.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
osg::Vec3 ep = boundingSphere._center;
osg::Vec3 bp = ep;
ep.z() -= _modelScale*0.0001f;
bp.z() -= _modelScale;
// check to see if any obstruction in front.
osgUtil::IntersectVisitor iv;
bool cameraSet = false;
osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
segDown->set(ep,bp);
iv.addLineSegment(segDown.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
osg::Vec3 uv;
if (np.z()>0.0f) uv = np;
else uv = -np;
float lookDistance = _modelScale*0.1f;
ep = ip;
ep.z() += _height;
osg::Vec3 lv = uv^osg::Vec3(1.0f,0.0f,0.0f);
osg::Vec3 cp = ep+lv*lookDistance;
_camera->setLookAt(ep,cp,uv);
cameraSet = true;
}
}
if (!cameraSet)
{
bp = ep;
bp.z() += _modelScale;
osg::ref_ptr<osg::LineSegment> segUp = new osg::LineSegment;
segUp->set(ep,bp);
iv.addLineSegment(segUp.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
osg::Vec3 uv;
if (np.z()>0.0f) uv = np;
else uv = -np;
float lookDistance = _modelScale*0.1f;
ep = ip;
ep.z() += _height;
osg::Vec3 lv = uv^osg::Vec3(1.0f,0.0f,0.0f);
osg::Vec3 cp = ep+lv*lookDistance;
_camera->setLookAt(ep,cp,uv);
cameraSet = true;
}
}
}
if (!cameraSet)
{
// eye
_camera->setLookAt(boundingSphere._center+osg::Vec3( 0.0,-2.0f * boundingSphere._radius,0.0f),
// look
boundingSphere._center,
// up
osg::Vec3(0.0f,0.0f,1.0f));
}
}
_velocity = 0.0f;
us.requestRedraw();
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
flushMouseEventStack();
}
void DriveManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
flushMouseEventStack();
us.requestContinuousUpdate(false);
_velocity = 0.0f;
osg::Vec3 ep = _camera->getEyePoint();
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 bp = ep;
bp.z() -= _modelScale;
// check to see if any obstruction in front.
osgUtil::IntersectVisitor iv;
bool cameraSet = false;
osg::ref_ptr<osg::LineSegment> segDown = new osg::LineSegment;
segDown->set(ep,bp);
iv.addLineSegment(segDown.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
osg::Vec3 uv;
if (np.z()>0.0f) uv = np;
else uv = -np;
float lookDistance = _modelScale*0.1f;
ep = ip+uv*_height;
osg::Vec3 lv = uv^sv;
osg::Vec3 lp = ep+lv*lookDistance;
_camera->setLookAt(ep,lp,uv);
_camera->ensureOrthogonalUpVector();
cameraSet = true;
}
}
if (!cameraSet)
{
bp = ep;
bp.z() += _modelScale;
osg::ref_ptr<osg::LineSegment> segUp = new osg::LineSegment;
segUp->set(ep,bp);
iv.addLineSegment(segUp.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
osg::Vec3 uv;
if (np.z()>0.0f) uv = np;
else uv = -np;
float lookDistance = _modelScale*0.1f;
ep = ip+uv*_height;
osg::Vec3 lv = uv^sv;
osg::Vec3 lp = ep+lv*lookDistance;
_camera->setLookAt(ep,lp,uv);
_camera->ensureOrthogonalUpVector();
cameraSet = true;
}
}
}
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
}
bool DriveManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
if(!_camera.get()) return false;
switch(ea.getEventType())
{
case(GUIEventAdapter::PUSH):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::RELEASE):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::DRAG):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::MOVE):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::KEYBOARD):
{
if (ea.getKey()==' ')
{
flushMouseEventStack();
home(ea,us);
us.requestRedraw();
us.requestContinuousUpdate(false);
return true;
}
else if (ea.getKey()=='q')
{
_speedMode = USE_MOUSE_Y_FOR_SPEED;
return true;
}
else if (ea.getKey()=='a')
{
_speedMode = USE_MOUSE_BUTTONS_FOR_SPEED;
return true;
}
else if (ea.getKey()=='+')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f);
return true;
}
else if (ea.getKey()=='-')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f);
return true;
}
return false;
}
case(GUIEventAdapter::FRAME):
{
addMouseEvent(ea);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::RESIZE):
{
init(ea,us);
us.requestRedraw();
return true;
}
default:
return false;
}
}
void DriveManipulator::flushMouseEventStack()
{
_ga_t1 = NULL;
_ga_t0 = NULL;
}
void DriveManipulator::addMouseEvent(const GUIEventAdapter& ea)
{
_ga_t1 = _ga_t0;
_ga_t0 = &ea;
}
bool DriveManipulator::calcMovement()
{
_camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_SCREEN_DISTANCE);
// return if less then two events have been added.
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
float dt = _ga_t0->time()-_ga_t1->time();
if (dt<0.0f)
{
notify(WARN) << "warning dt = "<<dt<< std::endl;
dt = 0.0f;
}
switch(_speedMode)
{
case(USE_MOUSE_Y_FOR_SPEED):
{
float my = (_ga_t0->getYmin()+_ga_t0->getYmax())/2.0f;
float dy = _ga_t0->getY()-my;
_velocity = -_modelScale*0.0002f*dy;
break;
}
case(USE_MOUSE_BUTTONS_FOR_SPEED):
{
unsigned int buttonMask = _ga_t1->getButtonMask();
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
// pan model.
_velocity += dt*_modelScale*0.02f;
}
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
{
_velocity = 0.0f;
}
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
_velocity -= dt*_modelScale*0.02f;
}
break;
}
}
// rotate the camera.
osg::Vec3 center = _camera->getEyePoint();
osg::Vec3 uv = _camera->getUpVector();
float mx = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f;
float dx = _ga_t0->getX()-mx;
float yaw = -inDegrees(dx*0.1f*dt);
osg::Matrix mat;
mat.makeTranslate(-center.x(),-center.y(),-center.z());
mat *= Matrix::rotate(yaw,uv.x(),uv.y(),uv.z());
mat *= Matrix::translate(center.x(),center.y(),center.z());
center = _camera->getEyePoint();
uv = _camera->getUpVector();
_camera->transformLookAt(mat);
// get the new forward (look) vector.
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 lv = _camera->getCenterPoint()-_camera->getEyePoint();
float lookDistance = lv.length();
lv.normalize();
// movement is big enough the move the eye point along the look vector.
if (fabsf(_velocity*dt)>1e-8)
{
osg::Vec3 ep = _camera->getEyePoint();
float distanceToMove = _velocity*dt;
float signedBuffer;
if (distanceToMove>=0.0f) signedBuffer=_buffer;
else signedBuffer=-_buffer;
// check to see if any obstruction in front.
osgUtil::IntersectVisitor iv;
osg::ref_ptr<osg::LineSegment> segForward = new osg::LineSegment;
segForward->set(ep,ep+lv*(signedBuffer+distanceToMove));
iv.addLineSegment(segForward.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segForward.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit obstruction"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
distanceToMove = (ip-ep).length()-_buffer;
_velocity = 0.0f;
}
}
// check to see if forward point is correct height above terrain.
osg::Vec3 fp = ep+lv*distanceToMove;
osg::Vec3 lfp = fp-uv*_height*5;
iv.reset();
osg::ref_ptr<osg::LineSegment> segNormal = new osg::LineSegment;
segNormal->set(fp,lfp);
iv.addLineSegment(segNormal.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segNormal.get());
if (!hitList.empty())
{
// notify(INFO) << "Hit terrain ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
if (uv*np>0.0f) uv = np;
else uv = -np;
ep = ip+uv*_height;
lv = uv^sv;
osg::Vec3 lp = ep+lv*lookDistance;
_camera->setLookAt(ep,lp,uv);
_camera->ensureOrthogonalUpVector();
return true;
}
}
// no hit on the terrain found therefore resort to a fall under
// under the influence of gravity.
osg::Vec3 dp = lfp;
dp.z() -= 2*_modelScale;
iv.reset();
osg::ref_ptr<osg::LineSegment> segFall = new osg::LineSegment;
segFall->set(lfp,dp);
iv.addLineSegment(segFall.get());
_node->accept(iv);
if (iv.hits())
{
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segFall.get());
if (!hitList.empty())
{
notify(INFO) << "Hit terrain on decent ok"<< std::endl;
osg::Vec3 ip = hitList.front().getWorldIntersectPoint();
osg::Vec3 np = hitList.front().getWorldIntersectNormal();
if (uv*np>0.0f) uv = np;
else uv = -np;
ep = ip+uv*_height;
lv = uv^sv;
osg::Vec3 lp = ep+lv*lookDistance;
_camera->setLookAt(ep,lp,uv);
_camera->ensureOrthogonalUpVector();
return true;
}
}
// no collision with terrain has been found therefore track horizontally.
lv *= (_velocity*dt);
ep += lv;
osg::Vec3 lp = _camera->getCenterPoint()+lv;
_camera->setLookAt(ep,lp,uv);
_camera->ensureOrthogonalUpVector();
}
return true;
}

View File

@@ -0,0 +1,245 @@
#include <osgGA/FlightManipulator>
#include <osg/Types>
#include <osg/Notify>
using namespace osg;
using namespace osgGA;
FlightManipulator::FlightManipulator()
{
_modelScale = 0.01f;
_velocity = 0.0f;
_yawMode = YAW_AUTOMATICALLY_WHEN_BANKED;
}
FlightManipulator::~FlightManipulator()
{
}
void FlightManipulator::setNode(osg::Node* node)
{
_node = node;
if (_node.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_modelScale = boundingSphere._radius;
}
}
const osg::Node* FlightManipulator::getNode() const
{
return _node.get();
}
osg::Node* FlightManipulator::getNode()
{
return _node.get();
}
void FlightManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
if(_node.get() && _camera.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_camera->setLookAt(
boundingSphere._center+osg::Vec3( 0.0,-3.0f * boundingSphere._radius,0.0f),
boundingSphere._center,
osg::Vec3(0.0f,0.0f,1.0f));
_velocity = 0.0f;
us.requestRedraw();
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
flushMouseEventStack();
}
}
void FlightManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
flushMouseEventStack();
us.requestContinuousUpdate(false);
_velocity = 0.0f;
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
}
bool FlightManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
if(!_camera.get()) return false;
switch(ea.getEventType())
{
case(GUIEventAdapter::PUSH):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::RELEASE):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::DRAG):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::MOVE):
{
addMouseEvent(ea);
us.requestContinuousUpdate(true);
if (calcMovement()) us.requestRedraw();
return true;
}
case(GUIEventAdapter::KEYBOARD):
if (ea.getKey()==' ')
{
flushMouseEventStack();
home(ea,us);
us.requestRedraw();
us.requestContinuousUpdate(false);
return true;
}
else if (ea.getKey()=='+')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f);
return true;
}
else if (ea.getKey()=='-')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f);
return true;
}
return false;
case(GUIEventAdapter::FRAME):
addMouseEvent(ea);
if (calcMovement()) us.requestRedraw();
return true;
case(GUIEventAdapter::RESIZE):
init(ea,us);
us.requestRedraw();
return true;
default:
return false;
}
}
void FlightManipulator::flushMouseEventStack()
{
_ga_t1 = NULL;
_ga_t0 = NULL;
}
void FlightManipulator::addMouseEvent(const GUIEventAdapter& ea)
{
_ga_t1 = _ga_t0;
_ga_t0 = &ea;
}
bool FlightManipulator::calcMovement()
{
_camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_SCREEN_DISTANCE);
// return if less then two events have been added.
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
float dt = _ga_t0->time()-_ga_t1->time();
if (dt<0.0f)
{
notify(WARN) << "warning dt = "<<dt<< std::endl;
dt = 0.0f;
}
unsigned int buttonMask = _ga_t1->getButtonMask();
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
// pan model.
_velocity += dt*_modelScale*0.05f;
}
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
{
_velocity = 0.0f;
}
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
_velocity -= dt*_modelScale*0.05f;
}
float mx = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f;
float my = (_ga_t0->getYmin()+_ga_t0->getYmax())/2.0f;
float dx = _ga_t0->getX()-mx;
float dy = _ga_t0->getY()-my;
osg::Vec3 center = _camera->getEyePoint();
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 lv = _camera->getLookVector();
float pitch = inDegrees(dy*0.15f*dt);
float roll = inDegrees(dx*0.1f*dt);
osg::Matrix mat;
mat.makeTranslate(-center);
mat *= Matrix::rotate(pitch,sv.x(),sv.y(),sv.z());
mat *= Matrix::rotate(roll,lv.x(),lv.y(),lv.z());
if (_yawMode==YAW_AUTOMATICALLY_WHEN_BANKED)
{
float bank = asinf(sv.z());
float yaw = inRadians(bank)*dt;
mat *= Matrix::rotate(yaw,0.0f,0.0f,1.0f);
}
lv *= (_velocity*dt);
mat *= Matrix::translate(center+lv);
_camera->transformLookAt(mat);
return true;
}

View File

@@ -0,0 +1,43 @@
#include <osgGA/GUIEventHandler>
using osgGA::CompositeGUIEventHandler;
bool CompositeGUIEventHandler::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa)
{
bool result=false;
for (ChildList::iterator itr=_children.begin();
itr!=_children.end();
++itr)
{
result |= (*itr)->handle(ea,aa);
}
return result;
}
bool CompositeGUIEventHandler::addChild(GUIEventHandler *child)
{
if (child && !containsNode(child))
{
// note ref_ptr<> automatically handles incrementing child's reference count.
_children.push_back(child);
return true;
}
else return false;
}
bool CompositeGUIEventHandler::removeChild(GUIEventHandler *child)
{
ChildList::iterator itr = findChild(child);
if (itr!=_children.end())
{
// note ref_ptr<> automatically handles decrementing child's reference count.
_children.erase(itr);
return true;
}
else return false;
}

View File

@@ -0,0 +1,9 @@
#include <osgGA/GUIEventHandlerVisitor>
#include <osgGA/GUIEventHandler>
void osgGA::GUIEventHandlerVisitor::visit(osgGA::CompositeGUIEventHandler& cgeh)
{
for(int i=0; i<cgeh.getNumChildren(); i++){
cgeh.getChild(i)->accept(*this);
}
}

View File

@@ -0,0 +1,45 @@
#include <osgGA/KeySwitchCameraManipulator>
#include <osg/Notify>
using namespace osgGA;
void KeySwitchCameraManipulator::addCameraManipulator(int key, std::string name, CameraManipulator *cm)
{
if(!cm) return;
_manips[key]=std::make_pair(name,osg::ref_ptr<CameraManipulator>(cm));
if(!_current.valid()){
_current=cm;
}
}
bool KeySwitchCameraManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa)
{
if(ea.getEventType()==GUIEventAdapter::KEYBOARD){
KeyManipMap::iterator it=_manips.find(ea.getKey());
if(it != _manips.end()){
osg::notify(osg::INFO)<<"Switching to manipulator: "<<(*it).second.first<<endl;
cout<<"***Switching to manipulator: "<<(*it).second.first<<endl;
it->second.second->setNode(_current->getNode());
it->second.second->setCamera(_current->getCamera());
it->second.second->init(ea,aa);
_current = it->second.second;
//_cameraManipChangeCallbacks.notify(this);
}
}
return _current->handle(ea,aa);
}
// void KeySwitchCameraManipulator::addCallback(Callback* c)
// {
// _cameraManipChangeCallbacks.addCallback(c);
// }
//
// void KeySwitchCameraManipulator::removeCallback(Callback* c)
// {
// _cameraManipChangeCallbacks.removeCallback(c);
// }

24
src/osgGA/Makefile Normal file
View File

@@ -0,0 +1,24 @@
TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES = \
CameraManipulator.cpp\
DriveManipulator.cpp\
FlightManipulator.cpp\
GUIEventHandler.cpp\
GUIEventHandlerVisitor.cpp\
KeySwitchCameraManipulator.cpp\
SetSceneViewVisitor.cpp\
StateSetManipulator.cpp\
TrackballManipulator.cpp\
Version.cpp\
DEF += -DOSGGA_LIBRARY
LIBS += -losgUtil -losg $(GL_LIBS) $(OTHER_LIBS)
TARGET_BASENAME = osgGA
LIB = $(LIB_PREFIX)$(TARGET_BASENAME).$(LIB_EXT)
include $(TOPDIR)/Make/makerules

View File

@@ -0,0 +1,16 @@
#include <osgGA/SetSceneViewVisitor>
#include <osgGA/CameraManipulator>
#include <osgGA/StateSetManipulator>
void osgGA::SetSceneViewVisitor::visit(osgGA::CameraManipulator& cm)
{
cm.setNode(_sceneView->getSceneData());
cm.setCamera(_sceneView->getCamera());
cm.init(*getGUIEventAdapter(),*getGUIActionAdapter());
cm.home(*getGUIEventAdapter(),*getGUIActionAdapter());
}
void osgGA::SetSceneViewVisitor::visit(osgGA::StateSetManipulator& ssm)
{
ssm.setStateSet(_sceneView->getGlobalStateSet());
}

View File

@@ -0,0 +1,73 @@
#include <osgGA/StateSetManipulator>
using namespace osg;
using namespace osgGA;
StateSetManipulator::StateSetManipulator(): _drawState(NULL)
{
}
StateSetManipulator::~StateSetManipulator()
{
}
void StateSetManipulator::setStateSet(StateSet *drawState)
{
_drawState=drawState;
if(!_drawState.valid()) return;
_backface = (_drawState->getMode(GL_CULL_FACE)==osg::StateAttribute::ON);
_lighting =(_drawState->getMode(GL_LIGHTING)==osg::StateAttribute::ON);
_texture =(_drawState->getMode(GL_TEXTURE_2D)==osg::StateAttribute::ON);
}
StateSet *StateSetManipulator::getStateSet()
{
return _drawState.get();
}
const StateSet *StateSetManipulator::getStateSet() const
{
return _drawState.get();
}
bool StateSetManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa)
{
if(!_drawState.valid()) return false;
if(ea.getEventType()==GUIEventAdapter::KEYBOARD){
switch( ea.getKey() ){
case 'b' :
_backface = !_backface;
if( _backface ) _drawState->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
else _drawState->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE_OFF);
aa.requestRedraw();
return true;
break;
case 'l' :
_lighting = !_lighting ;
if( _lighting ) _drawState->setMode(GL_LIGHTING,osg::StateAttribute::ON);
else _drawState->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE_OFF);
aa.requestRedraw();
return true;
break;
case 't' :
_texture = !_texture;
if (_texture) _drawState->setMode(GL_TEXTURE_2D,osg::StateAttribute::INHERIT);
else _drawState->setMode(GL_TEXTURE_2D,osg::StateAttribute::OVERRIDE_OFF);
aa.requestRedraw();
return true;
break;
}
}
return false;
}
void StateSetManipulator::accept(GUIEventHandlerVisitor& gehv)
{
gehv.visit(*this);
}

View File

@@ -0,0 +1,397 @@
#include <osgGA/TrackballManipulator>
#include <osg/Types>
#include <osg/Notify>
using namespace osg;
using namespace osgGA;
TrackballManipulator::TrackballManipulator()
{
_modelScale = 0.01f;
_minimumZoomScale = 0.05f;
_thrown = false;
}
TrackballManipulator::~TrackballManipulator()
{
}
void TrackballManipulator::setNode(osg::Node* node)
{
_node = node;
if (_node.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_modelScale = boundingSphere._radius;
}
}
const osg::Node* TrackballManipulator::getNode() const
{
return _node.get();
}
osg::Node* TrackballManipulator::getNode()
{
return _node.get();
}
/*ea*/
void TrackballManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us)
{
if(_node.get() && _camera.get())
{
const osg::BoundingSphere& boundingSphere=_node->getBound();
_camera->setView(boundingSphere._center+osg::Vec3( 0.0,-3.0f * boundingSphere._radius,0.0f),
boundingSphere._center,
osg::Vec3(0.0f,0.0f,1.0f));
us.requestRedraw();
}
}
void TrackballManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& )
{
flushMouseEventStack();
}
bool TrackballManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
{
if(!_camera.get()) return false;
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::KEYBOARD):
if (ea.getKey()==' ')
{
flushMouseEventStack();
_thrown = false;
home(ea,us);
us.requestRedraw();
us.requestContinuousUpdate(false);
return true;
} else if (ea.getKey()=='+')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()*1.25f);
return true;
}
else if (ea.getKey()=='-')
{
_camera->setFusionDistanceRatio(_camera->getFusionDistanceRatio()/1.25f);
return true;
}
return false;
case(GUIEventAdapter::FRAME):
_camera->setFusionDistanceMode(osg::Camera::PROPORTIONAL_TO_LOOK_DISTANCE);
if (_thrown)
{
if (calcMovement()) us.requestRedraw();
return true;
}
return false;
default:
return false;
}
}
bool TrackballManipulator::isMouseMoving()
{
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
static const float velocity = 100.0f;
float dx = _ga_t0->getX()-_ga_t1->getX();
float dy = _ga_t0->getY()-_ga_t1->getY();
float len = sqrtf(dx*dx+dy*dy);
float dt = _ga_t0->time()-_ga_t1->time();
return (len>dt*velocity);
}
void TrackballManipulator::flushMouseEventStack()
{
_ga_t1 = NULL;
_ga_t0 = NULL;
}
void TrackballManipulator::addMouseEvent(const GUIEventAdapter& ea)
{
_ga_t1 = _ga_t0;
_ga_t0 = &ea;
}
bool TrackballManipulator::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->getX()-_ga_t1->getX();
float dy = _ga_t0->getY()-_ga_t1->getY();
// return if there is no movement.
if (dx==0 && dy==0) return false;
float focalLength = (_camera->getCenterPoint()-_camera->getEyePoint()).length();
unsigned int buttonMask = _ga_t1->getButtonMask();
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
// rotate camera.
osg::Vec3 center = _camera->getCenterPoint();
osg::Vec3 axis;
float angle;
float mx0 = (_ga_t0->getXmin()+_ga_t0->getXmax())/2.0f;
float rx0 = (_ga_t0->getXmax()-_ga_t0->getXmin())/2.0f;
float my0 = (_ga_t0->getYmin()+_ga_t0->getYmax())/2.0f;
float ry0 = (_ga_t0->getYmax()-_ga_t0->getYmin())/2.0f;
float mx1 = (_ga_t0->getXmin()+_ga_t1->getXmax())/2.0f;
float rx1 = (_ga_t0->getXmax()-_ga_t1->getXmin())/2.0f;
float my1 = (_ga_t1->getYmin()+_ga_t1->getYmax())/2.0f;
float ry1 = (_ga_t1->getYmax()-_ga_t1->getYmin())/2.0f;
float px0 = (_ga_t0->getX()-mx0)/rx0;
float py0 = (my0-_ga_t0->getY())/ry0;
float px1 = (_ga_t1->getX()-mx1)/rx1;
float py1 = (my1-_ga_t1->getY())/ry1;
trackball(axis,angle,px1,py1,px0,py0);
osg::Matrix mat;
mat.makeTranslate(-center.x(),-center.y(),-center.z());
mat *= Matrix::rotate(angle,axis.x(),axis.y(),axis.z());
mat *= Matrix::translate(center.x(),center.y(),center.z());
_camera->transformLookAt(mat);
return true;
}
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
{
// pan model.
float scale = 0.0015f*focalLength;
osg::Vec3 uv = _camera->getUpVector();
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 dv = uv*(dy*scale)-sv*(dx*scale);
osg::Matrix mat;
mat.makeTranslate(dv.x(),dv.y(),dv.z());
_camera->transformLookAt(mat);
return true;
}
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
// zoom model.
float fd = focalLength;
float scale = 1.0f-dy*0.001f;
if (fd*scale>_modelScale*_minimumZoomScale)
{
// zoom camera in.
osg::Vec3 center = _camera->getCenterPoint();
osg::Matrix mat;
mat.makeTranslate(-center.x(),-center.y(),-center.z());
mat *= Matrix::scale(scale,scale,scale);
mat *= Matrix::translate(center.x(),center.y(),center.z());
_camera->transformLookAt(mat);
}
else
{
// notify(DEBUG_INFO) << "Pushing forward"<<std::endl;
// push the camera forward.
float scale = 0.0015f*fd;
osg::Vec3 dv = _camera->getLookVector()*(dy*scale);
osg::Matrix mat;
mat.makeTranslate(dv.x(),dv.y(),dv.z());
_camera->transformLookAt(mat);
}
return true;
}
return false;
}
/*
* This size should really be based on the distance from the center of
* rotation to the point on the object underneath the mouse. That
* point would then track the mouse as closely as possible. This is a
* simple example, though, so that is left as an Exercise for the
* Programmer.
*/
const float TRACKBALLSIZE = 0.8f;
/*
* Ok, simulate a track-ball. Project the points onto the virtual
* trackball, then figure out the axis of rotation, which is the cross
* product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
* Note: This is a deformed trackball-- is a trackball in the center,
* but is deformed into a hyperbolic sheet of rotation away from the
* center. This particular function was chosen after trying out
* several variations.
*
* It is assumed that the arguments to this routine are in the range
* (-1.0 ... 1.0)
*/
void TrackballManipulator::trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y)
{
/*
* First, figure out z-coordinates for projection of P1 and P2 to
* deformed sphere
*/
osg::Vec3 uv = _camera->getUpVector();
osg::Vec3 sv = _camera->getSideVector();
osg::Vec3 lv = _camera->getLookVector();
osg::Vec3 p1 = sv*p1x+uv*p1y-lv*tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y);
osg::Vec3 p2 = sv*p2x+uv*p2y-lv*tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y);
/*
* Now, we want the cross product of P1 and P2
*/
// Robert,
//
// This was the quick 'n' dirty fix to get the trackball doing the right
// thing after fixing the Quat rotations to be right-handed. You may want
// to do something more elegant.
// axis = p1^p2;
axis = p2^p1;
axis.normalize();
/*
* Figure out how much to rotate around that axis.
*/
float t = (p2-p1).length() / (2.0*TRACKBALLSIZE);
/*
* Avoid problems with out-of-control values...
*/
if (t > 1.0) t = 1.0;
if (t < -1.0) t = -1.0;
angle = inRadians(asin(t));
}
/*
* Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
* if we are away from the center of the sphere.
*/
float TrackballManipulator::tb_project_to_sphere(float r, float x, float y)
{
float d, t, z;
d = sqrt(x*x + y*y);
/* Inside sphere */
if (d < r * 0.70710678118654752440)
{
z = sqrt(r*r - d*d);
} /* On hyperbola */
else
{
t = r / 1.41421356237309504880;
z = t*t / d;
}
return z;
}

12
src/osgGA/Version.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include <osgGA/Version>
const char* osgGAGetVersion()
{
return "0.8.45";
}
const char* osgGAGetLibraryName()
{
return "Open Scene Graph Gui Adapter Library";
}

View File

@@ -257,6 +257,12 @@ void SceneView::cull()
cullStage(projectionRight.get(),modelviewRight.get(),_cullVisitorRight.get(),_rendergraphRight.get(),_renderStageRight.get());
// if (_camera.valid())
// {
// // clamp the camera to the near/far computed in cull traversal.
// _camera->setNearFar(_cullVisitorRight->getCalculatedNearPlane(),_cullVisitorRight->getCalculatedFarPlane());
// }
}
else
{
@@ -278,8 +284,15 @@ void SceneView::cull()
_cullVisitor->setTraversalMask(_cullMask);
cullStage(projection.get(),modelview.get(),_cullVisitor.get(),_rendergraph.get(),_renderStage.get());
// if (_camera.valid())
// {
// // clamp the camera to the near/far computed in cull traversal.
// _camera->setNearFar(_cullVisitor->getCalculatedNearPlane(),_cullVisitor->getCalculatedFarPlane());
// }
}
}
void SceneView::cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::RenderGraph* rendergraph, osgUtil::RenderStage* renderStage)