Initial revision
This commit is contained in:
29
src/osgUtil/CameraManipulator.cpp
Normal file
29
src/osgUtil/CameraManipulator.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <osg/GL>
|
||||
#include <osg/Matrix>
|
||||
#include <osgUtil/CameraManipulator>
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
CameraManipulator::CameraManipulator(): _camera(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CameraManipulator::~CameraManipulator()
|
||||
{
|
||||
}
|
||||
|
||||
void CameraManipulator::setCamera(Camera *camera)
|
||||
{
|
||||
_camera=camera;
|
||||
}
|
||||
|
||||
Camera *CameraManipulator::getCamera() const
|
||||
{
|
||||
return _camera.get();
|
||||
}
|
||||
|
||||
bool CameraManipulator::update(GUIEventAdapter&,GUIActionAdapter&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
37
src/osgUtil/DisplayListVisitor.cpp
Normal file
37
src/osgUtil/DisplayListVisitor.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "osgUtil/DisplayListVisitor"
|
||||
#include "osg/GeoSet"
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
DisplayListVisitor::DisplayListVisitor(DisplayListMode mode)
|
||||
{
|
||||
setTraverseMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
|
||||
_displayListMode = mode;
|
||||
}
|
||||
|
||||
void DisplayListVisitor::apply(osg::Geode& node)
|
||||
{
|
||||
switch(_displayListMode)
|
||||
{
|
||||
case(SWITCH_OFF_DISPLAY_LISTS):
|
||||
{
|
||||
for(int i=0;i<node.getNumGeosets();++i)
|
||||
{
|
||||
node.getGeoSet(i)->setUseDisplayList(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case(SWITCH_ON_DISPLAY_LISTS):
|
||||
{
|
||||
for(int i=0;i<node.getNumGeosets();++i)
|
||||
{
|
||||
node.getGeoSet(i)->setUseDisplayList(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case(SWITCH_ON_AND_COMPILE_DISPLAY_LISTS):
|
||||
node.compileGeoSets();
|
||||
break;
|
||||
}
|
||||
}
|
||||
535
src/osgUtil/DriveManipulator.cpp
Normal file
535
src/osgUtil/DriveManipulator.cpp
Normal file
@@ -0,0 +1,535 @@
|
||||
#include "osgUtil/DriveManipulator"
|
||||
#include "osgUtil/IntersectVisitor"
|
||||
#include "osg/Notify"
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
DriveManipulator::DriveManipulator()
|
||||
{
|
||||
_modelScale = 0.01f;
|
||||
_velocity = 0.0f;
|
||||
_speedMode = USE_MOUSE_Y_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;
|
||||
}
|
||||
}
|
||||
|
||||
osg::Node* DriveManipulator::getNode() const
|
||||
{
|
||||
return _node.get();
|
||||
}
|
||||
|
||||
void DriveManipulator::home(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.
|
||||
IntersectVisitor iv;
|
||||
|
||||
bool cameraSet = false;
|
||||
|
||||
osg::ref_ptr<osg::Seg> segDown = new osg::Seg;
|
||||
segDown->set(ep,bp);
|
||||
iv.addSeg(segDown.get());
|
||||
|
||||
_node->accept(iv);
|
||||
|
||||
if (iv.hits())
|
||||
{
|
||||
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
|
||||
if (!hitList.empty())
|
||||
{
|
||||
// notify(INFO) << "Hit terrain ok"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
osg::Vec3 np = hitList.front()._intersectNormal;
|
||||
|
||||
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 lp = ep+lv*lookDistance;
|
||||
|
||||
_camera->setView(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
|
||||
cameraSet = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!cameraSet)
|
||||
{
|
||||
bp = ep;
|
||||
bp.z() += _modelScale;
|
||||
|
||||
osg::ref_ptr<osg::Seg> segUp = new osg::Seg;
|
||||
segUp->set(ep,bp);
|
||||
iv.addSeg(segUp.get());
|
||||
|
||||
_node->accept(iv);
|
||||
|
||||
if (iv.hits())
|
||||
{
|
||||
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get());
|
||||
if (!hitList.empty())
|
||||
{
|
||||
// notify(INFO) << "Hit terrain ok"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
osg::Vec3 np = hitList.front()._intersectNormal;
|
||||
|
||||
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 lp = ep+lv*lookDistance;
|
||||
|
||||
_camera->setView(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
|
||||
cameraSet = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!cameraSet)
|
||||
{
|
||||
_camera->setView(boundingSphere._center+osg::Vec3( 0.0,-2.0f * boundingSphere._radius,0.0f), // eye
|
||||
boundingSphere._center, // look
|
||||
osg::Vec3(0.0f,0.0f,1.0f)); // up
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
us.needRedraw();
|
||||
|
||||
us.needWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
flushMouseEventStack();
|
||||
|
||||
}
|
||||
|
||||
void DriveManipulator::init(GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
flushMouseEventStack();
|
||||
|
||||
us.needContinuousUpdate(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.
|
||||
IntersectVisitor iv;
|
||||
|
||||
bool cameraSet = false;
|
||||
|
||||
osg::ref_ptr<osg::Seg> segDown = new osg::Seg;
|
||||
segDown->set(ep,bp);
|
||||
iv.addSeg(segDown.get());
|
||||
|
||||
_node->accept(iv);
|
||||
|
||||
if (iv.hits())
|
||||
{
|
||||
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segDown.get());
|
||||
if (!hitList.empty())
|
||||
{
|
||||
// notify(INFO) << "Hit terrain ok"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
osg::Vec3 np = hitList.front()._intersectNormal;
|
||||
|
||||
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->setView(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
|
||||
cameraSet = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!cameraSet)
|
||||
{
|
||||
bp = ep;
|
||||
bp.z() += _modelScale;
|
||||
|
||||
osg::ref_ptr<osg::Seg> segUp = new osg::Seg;
|
||||
segUp->set(ep,bp);
|
||||
iv.addSeg(segUp.get());
|
||||
|
||||
_node->accept(iv);
|
||||
|
||||
if (iv.hits())
|
||||
{
|
||||
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segUp.get());
|
||||
if (!hitList.empty())
|
||||
{
|
||||
// notify(INFO) << "Hit terrain ok"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
osg::Vec3 np = hitList.front()._intersectNormal;
|
||||
|
||||
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->setView(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
|
||||
cameraSet = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
us.needWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
}
|
||||
|
||||
bool DriveManipulator::update(GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
if(!_camera.get()) return false;
|
||||
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case(GUIEventAdapter::PUSH):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::RELEASE):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::DRAG):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::MOVE):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
case(GUIEventAdapter::KEYBOARD):
|
||||
if (ea.getKey()==' ')
|
||||
{
|
||||
flushMouseEventStack();
|
||||
home(ea,us);
|
||||
us.needRedraw();
|
||||
us.needContinuousUpdate(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;
|
||||
}
|
||||
|
||||
return false;
|
||||
case(GUIEventAdapter::FRAME):
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
return true;
|
||||
case(GUIEventAdapter::RESIZE):
|
||||
{
|
||||
init(ea,us);
|
||||
us.needRedraw();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DriveManipulator::flushMouseEventStack()
|
||||
{
|
||||
_ga_t1 = NULL;
|
||||
_ga_t0 = NULL;
|
||||
}
|
||||
|
||||
void DriveManipulator::addMouseEvent(GUIEventAdapter& ea)
|
||||
{
|
||||
_ga_t1 = _ga_t0;
|
||||
_ga_t0 = &ea;
|
||||
}
|
||||
|
||||
|
||||
bool DriveManipulator::calcMovement()
|
||||
{
|
||||
// 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<<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_BUTTON)
|
||||
{
|
||||
// pan model.
|
||||
|
||||
_velocity += dt*_modelScale*0.02f;
|
||||
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::MIDDLE_BUTTON ||
|
||||
buttonMask==(GUIEventAdapter::LEFT_BUTTON|GUIEventAdapter::RIGHT_BUTTON))
|
||||
{
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::RIGHT_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 = dx*0.1f*dt;
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTrans(-center.x(),-center.y(),-center.z());
|
||||
mat.postRot(yaw,uv.x(),uv.y(),uv.z());
|
||||
mat.postTrans(center.x(),center.y(),center.z());
|
||||
|
||||
center = _camera->getEyePoint();
|
||||
uv = _camera->getUpVector();
|
||||
|
||||
_camera->mult(*_camera,mat);
|
||||
|
||||
|
||||
// get the new forward (look) vector.
|
||||
osg::Vec3 sv = _camera->getSideVector();
|
||||
osg::Vec3 lv = _camera->getLookPoint()-_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.
|
||||
IntersectVisitor iv;
|
||||
osg::ref_ptr<osg::Seg> segForward = new osg::Seg;
|
||||
segForward->set(ep,ep+lv*(signedBuffer+distanceToMove));
|
||||
iv.addSeg(segForward.get());
|
||||
|
||||
_node->accept(iv);
|
||||
|
||||
if (iv.hits())
|
||||
{
|
||||
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segForward.get());
|
||||
if (!hitList.empty())
|
||||
{
|
||||
// notify(INFO) << "Hit obstruction"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
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::Seg> segNormal = new osg::Seg;
|
||||
segNormal->set(fp,lfp);
|
||||
iv.addSeg(segNormal.get());
|
||||
|
||||
_node->accept(iv);
|
||||
|
||||
if (iv.hits())
|
||||
{
|
||||
osgUtil::IntersectVisitor::HitList& hitList = iv.getHitList(segNormal.get());
|
||||
if (!hitList.empty())
|
||||
{
|
||||
// notify(INFO) << "Hit terrain ok"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
osg::Vec3 np = hitList.front()._intersectNormal;
|
||||
|
||||
if (uv*np>0.0f) uv = np;
|
||||
else uv = -np;
|
||||
|
||||
ep = ip+uv*_height;
|
||||
lv = uv^sv;
|
||||
osg::Vec3 lp = ep+lv*lookDistance;
|
||||
|
||||
_camera->setView(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::Seg> segFall = new osg::Seg;
|
||||
segFall->set(lfp,dp);
|
||||
iv.addSeg(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"<<endl;
|
||||
osg::Vec3 ip = hitList.front()._intersectPoint;
|
||||
osg::Vec3 np = hitList.front()._intersectNormal;
|
||||
|
||||
if (uv*np>0.0f) uv = np;
|
||||
else uv = -np;
|
||||
|
||||
ep = ip+uv*_height;
|
||||
lv = uv^sv;
|
||||
osg::Vec3 lp = ep+lv*lookDistance;
|
||||
|
||||
_camera->setView(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->getLookPoint()+lv;
|
||||
|
||||
_camera->setView(ep,lp,uv);
|
||||
_camera->ensureOrthogonalUpVector();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
217
src/osgUtil/FlightManipulator.cpp
Normal file
217
src/osgUtil/FlightManipulator.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "osgUtil/FlightManipulator"
|
||||
#include "osg/Notify"
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
osg::Node* FlightManipulator::getNode() const
|
||||
{
|
||||
return _node.get();
|
||||
}
|
||||
|
||||
void FlightManipulator::home(GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
if(_node.get() && _camera.get())
|
||||
{
|
||||
|
||||
const osg::BoundingSphere& boundingSphere=_node->getBound();
|
||||
|
||||
_camera->setView(boundingSphere._center+osg::Vec3( 0.0,-2.0f * boundingSphere._radius,0.0f), // eye
|
||||
boundingSphere._center, // look
|
||||
osg::Vec3(0.0f,0.0f,1.0f)); // up
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
us.needRedraw();
|
||||
|
||||
us.needWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
flushMouseEventStack();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FlightManipulator::init(GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
flushMouseEventStack();
|
||||
|
||||
us.needContinuousUpdate(false);
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
us.needWarpPointer((ea.getXmin()+ea.getXmax())/2,(ea.getYmin()+ea.getYmax())/2);
|
||||
|
||||
}
|
||||
|
||||
bool FlightManipulator::update(GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
if(!_camera.get()) return false;
|
||||
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case(GUIEventAdapter::PUSH):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::RELEASE):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::DRAG):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::MOVE):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.needContinuousUpdate(true);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
case(GUIEventAdapter::KEYBOARD):
|
||||
if (ea.getKey()==' ')
|
||||
{
|
||||
flushMouseEventStack();
|
||||
home(ea,us);
|
||||
us.needRedraw();
|
||||
us.needContinuousUpdate(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case(GUIEventAdapter::FRAME):
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
return true;
|
||||
case(GUIEventAdapter::RESIZE):
|
||||
{
|
||||
init(ea,us);
|
||||
us.needRedraw();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FlightManipulator::flushMouseEventStack()
|
||||
{
|
||||
_ga_t1 = NULL;
|
||||
_ga_t0 = NULL;
|
||||
}
|
||||
|
||||
void FlightManipulator::addMouseEvent(GUIEventAdapter& ea)
|
||||
{
|
||||
_ga_t1 = _ga_t0;
|
||||
_ga_t0 = &ea;
|
||||
}
|
||||
|
||||
bool FlightManipulator::calcMovement()
|
||||
{
|
||||
// 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<<endl;
|
||||
dt = 0.0f;
|
||||
}
|
||||
|
||||
unsigned int buttonMask = _ga_t1->getButtonMask();
|
||||
if (buttonMask==GUIEventAdapter::LEFT_BUTTON)
|
||||
{
|
||||
// pan model.
|
||||
|
||||
_velocity += dt*_modelScale*0.05f;
|
||||
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::MIDDLE_BUTTON ||
|
||||
buttonMask==(GUIEventAdapter::LEFT_BUTTON|GUIEventAdapter::RIGHT_BUTTON))
|
||||
{
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::RIGHT_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 = -dy*0.15f*dt;
|
||||
float roll = -dx*0.1f*dt;
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTrans(-center.x(),-center.y(),-center.z());
|
||||
mat.postRot(pitch,sv.x(),sv.y(),sv.z());
|
||||
mat.postRot(roll,lv.x(),lv.y(),lv.z());
|
||||
if (_yawMode==YAW_AUTOMATICALLY_WHEN_BANKED)
|
||||
{
|
||||
float bank = asinf(sv.z());
|
||||
float yaw = (-bank*180.0f/M_PI)*dt;
|
||||
mat.postRot(yaw,0.0f,0.0f,1.0f);
|
||||
}
|
||||
mat.postTrans(center.x(),center.y(),center.z());
|
||||
|
||||
|
||||
lv *= (_velocity*dt);
|
||||
|
||||
mat.postTrans(lv.x(),lv.y(),lv.z());
|
||||
|
||||
_camera->mult(*_camera,mat);
|
||||
|
||||
return true;
|
||||
}
|
||||
591
src/osgUtil/IntersectVisitor.cpp
Normal file
591
src/osgUtil/IntersectVisitor.cpp
Normal file
@@ -0,0 +1,591 @@
|
||||
#include "osgUtil/IntersectVisitor"
|
||||
#include "osg/DCS"
|
||||
#include "osg/Geode"
|
||||
#include "osg/LOD"
|
||||
#include "osg/Billboard"
|
||||
#include "osg/Notify"
|
||||
|
||||
#include <float.h>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
#ifndef OSG_USE_IO_DOT_H
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
IntersectState::IntersectState()
|
||||
{
|
||||
_matrix = NULL;
|
||||
_inverse = NULL;
|
||||
_segmentMaskStack.push_back(0xffffffff);
|
||||
}
|
||||
|
||||
IntersectState::~IntersectState()
|
||||
{
|
||||
if (_matrix) _matrix->unref();
|
||||
if (_inverse) _inverse->unref();
|
||||
for(SegList::iterator itr=_segList.begin();
|
||||
itr!=_segList.end();
|
||||
++itr)
|
||||
{
|
||||
itr->first->unref();
|
||||
itr->second->unref();
|
||||
}
|
||||
|
||||
_matrix = (osg::Matrix *)0xffffffff;
|
||||
_inverse = (osg::Matrix *)0xffffffff;
|
||||
}
|
||||
|
||||
bool IntersectState::isCulled(const BoundingSphere& bs,SegmentMask& segMaskOut)
|
||||
{
|
||||
bool hit = false;
|
||||
SegmentMask mask = 0x00000001;
|
||||
segMaskOut = 0x00000000;
|
||||
SegmentMask segMaskIn = _segmentMaskStack.back();
|
||||
// notify(INFO) << << "IntersectState::isCulled() mask in "<<segMaskIn<<" ";
|
||||
for(IntersectState::SegList::iterator sitr=_segList.begin();
|
||||
sitr!=_segList.end();
|
||||
++sitr)
|
||||
{
|
||||
if ((segMaskIn & mask) && (sitr->second)->intersect(bs))
|
||||
{
|
||||
// notify(INFO) << << "Hit ";
|
||||
segMaskOut = segMaskOut| mask;
|
||||
hit = true;
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
// notify(INFO) << << "mask = "<<segMaskOut<<endl;
|
||||
return !hit;
|
||||
}
|
||||
|
||||
bool IntersectState::isCulled(const BoundingBox& bb,SegmentMask& segMaskOut)
|
||||
{
|
||||
bool hit = false;
|
||||
SegmentMask mask = 0x00000001;
|
||||
segMaskOut = 0x00000000;
|
||||
SegmentMask segMaskIn = _segmentMaskStack.back();
|
||||
for(IntersectState::SegList::iterator sitr=_segList.begin();
|
||||
sitr!=_segList.end();
|
||||
++sitr)
|
||||
{
|
||||
if ((segMaskIn & mask) && (sitr->second)->intersect(bb))
|
||||
{
|
||||
segMaskOut = segMaskOut| mask;
|
||||
hit = true;
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
return !hit;
|
||||
}
|
||||
|
||||
Hit::Hit()
|
||||
{
|
||||
_originalSeg=NULL;
|
||||
_localSeg=NULL;
|
||||
_geode=NULL;
|
||||
_geoset=NULL;
|
||||
_matrix=NULL;
|
||||
}
|
||||
|
||||
Hit::Hit(const Hit& hit):Referenced()
|
||||
{
|
||||
// copy data across.
|
||||
_ratio = hit._ratio;
|
||||
_originalSeg = hit._originalSeg;
|
||||
_localSeg = hit._localSeg;
|
||||
_nodePath = hit._nodePath;
|
||||
_geode = hit._geode;
|
||||
_geoset = hit._geoset;
|
||||
_matrix = hit._matrix;
|
||||
|
||||
_vecIndexList = hit._vecIndexList;
|
||||
_primitiveIndex = hit._primitiveIndex;
|
||||
_intersectPoint = hit._intersectPoint;
|
||||
_intersectNormal = hit._intersectNormal;
|
||||
|
||||
if (_matrix) _matrix->ref();
|
||||
if (_originalSeg) _originalSeg->ref();
|
||||
if (_localSeg) _localSeg->ref();
|
||||
}
|
||||
|
||||
|
||||
Hit::~Hit()
|
||||
{
|
||||
if (_matrix) _matrix->unref();
|
||||
if (_originalSeg) _originalSeg->unref();
|
||||
if (_localSeg) _localSeg->unref();
|
||||
_matrix = (osg::Matrix*)0xffffffff;
|
||||
_localSeg = (osg::Seg*)0xffffffff;
|
||||
_localSeg = (osg::Seg*)0xffffffff;
|
||||
_geode = (osg::Geode*)0xffffffff;
|
||||
}
|
||||
|
||||
Hit& Hit::operator = (const Hit& hit)
|
||||
{
|
||||
if (&hit==this) return *this;
|
||||
|
||||
// free old memory.
|
||||
if (_matrix!=hit._matrix)
|
||||
{
|
||||
if (_matrix) _matrix->unref();
|
||||
_matrix = hit._matrix;
|
||||
if (_matrix) _matrix->ref();
|
||||
}
|
||||
if (_originalSeg!=hit._originalSeg)
|
||||
{
|
||||
if (_originalSeg) _originalSeg->unref();
|
||||
_originalSeg = hit._originalSeg;
|
||||
if (_originalSeg) _originalSeg->ref();
|
||||
}
|
||||
if (_localSeg!=hit._localSeg)
|
||||
{
|
||||
if (_localSeg) _localSeg->unref();
|
||||
_localSeg = hit._localSeg;
|
||||
if (_localSeg) _localSeg->ref();
|
||||
}
|
||||
|
||||
// copy data across.
|
||||
_ratio = hit._ratio;
|
||||
_originalSeg = hit._originalSeg;
|
||||
_localSeg = hit._localSeg;
|
||||
_nodePath = hit._nodePath;
|
||||
_geode = hit._geode;
|
||||
_geoset = hit._geoset;
|
||||
|
||||
_vecIndexList = hit._vecIndexList;
|
||||
_primitiveIndex = hit._primitiveIndex;
|
||||
_intersectPoint = hit._intersectPoint;
|
||||
_intersectNormal = hit._intersectNormal;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntersectVisitor::IntersectVisitor()
|
||||
{
|
||||
// overide the default node visitor mode.
|
||||
setTraverseMode(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
|
||||
reset();
|
||||
}
|
||||
|
||||
IntersectVisitor::~IntersectVisitor()
|
||||
{
|
||||
std::for_each(_intersectStateStack.begin(),_intersectStateStack.end(),UnrefOp<IntersectState>());
|
||||
_intersectStateStack.erase(_intersectStateStack.begin(),_intersectStateStack.end());
|
||||
}
|
||||
|
||||
void IntersectVisitor::reset()
|
||||
{
|
||||
|
||||
//
|
||||
// first unref all referenced objects and then empty the containers.
|
||||
//
|
||||
std::for_each(_intersectStateStack.begin(),_intersectStateStack.end(),UnrefOp<IntersectState>());
|
||||
_intersectStateStack.erase(_intersectStateStack.begin(),_intersectStateStack.end());
|
||||
|
||||
|
||||
// create a empty IntersectState on the the intersectStateStack.
|
||||
IntersectState* nis = new IntersectState;
|
||||
nis->_matrix = NULL;
|
||||
nis->_inverse = NULL;
|
||||
|
||||
_intersectStateStack.push_back(nis);
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool IntersectVisitor::hits()
|
||||
{
|
||||
for(SegHitListMap::iterator itr = _segHitList.begin();
|
||||
itr != _segHitList.end();
|
||||
++itr)
|
||||
{
|
||||
if (!(itr->second.empty())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntersectVisitor::addSeg(Seg* seg)
|
||||
{
|
||||
// first check to see if segment has already been added.
|
||||
for(SegHitListMap::iterator itr = _segHitList.begin();
|
||||
itr != _segHitList.end();
|
||||
++itr)
|
||||
{
|
||||
if (itr->first == seg) return;
|
||||
}
|
||||
|
||||
// create a new segment transformed to local coordintes.
|
||||
IntersectState* cis = _intersectStateStack.back();
|
||||
Seg* ns = new Seg;
|
||||
if (cis->_inverse) ns->mult(*seg,*(cis->_inverse));
|
||||
else *ns = *seg;
|
||||
cis->_segList.push_back(std::pair<Seg*,Seg*>(seg,ns));
|
||||
seg->ref();
|
||||
ns->ref();
|
||||
|
||||
}
|
||||
|
||||
void IntersectVisitor::pushMatrix(const Matrix& matrix)
|
||||
{
|
||||
IntersectState* nis = new IntersectState;
|
||||
nis->ref();
|
||||
|
||||
IntersectState* cis = _intersectStateStack.back();
|
||||
|
||||
if (cis->_matrix)
|
||||
{
|
||||
nis->_matrix = new Matrix;
|
||||
nis->_matrix->mult(matrix,*(cis->_matrix));
|
||||
}
|
||||
else
|
||||
{
|
||||
nis->_matrix = new Matrix(matrix);
|
||||
}
|
||||
nis->_matrix->ref();
|
||||
|
||||
Matrix* inverse_world = new Matrix;
|
||||
inverse_world->ref();
|
||||
inverse_world->invert(*(nis->_matrix));
|
||||
nis->_inverse = inverse_world;
|
||||
|
||||
IntersectState::SegmentMask segMaskIn = cis->_segmentMaskStack.back();
|
||||
IntersectState::SegmentMask mask = 0x00000001;
|
||||
for(IntersectState::SegList::iterator sitr=cis->_segList.begin();
|
||||
sitr!=cis->_segList.end();
|
||||
++sitr)
|
||||
{
|
||||
if ((segMaskIn & mask))
|
||||
{
|
||||
Seg* seg = new Seg;
|
||||
seg->mult(*(sitr->first),*inverse_world);
|
||||
nis->_segList.push_back(std::pair<Seg*,Seg*>(sitr->first,seg));
|
||||
seg->ref();
|
||||
sitr->first->ref();
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
|
||||
_intersectStateStack.push_back(nis);
|
||||
|
||||
// notify(INFO) << << "IntersectVisitor::pushMatrix()"<<endl;
|
||||
}
|
||||
|
||||
void IntersectVisitor::popMatrix()
|
||||
{
|
||||
if (!_intersectStateStack.empty())
|
||||
{
|
||||
IntersectState* pvs = _intersectStateStack.back();
|
||||
pvs->unref();
|
||||
_intersectStateStack.pop_back();
|
||||
}
|
||||
// notify(INFO) << << "IntersectVisitor::popMatrix()"<<endl;
|
||||
}
|
||||
|
||||
bool IntersectVisitor::enterNode(Node& node)
|
||||
{
|
||||
const BoundingSphere& bs = node.getBound();
|
||||
if (bs.isValid())
|
||||
{
|
||||
IntersectState* cis = _intersectStateStack.back();
|
||||
IntersectState::SegmentMask sm=0xffffffff;
|
||||
if (cis->isCulled(bs,sm)) return false;
|
||||
cis->_segmentMaskStack.push_back(sm);
|
||||
_nodePath.push_back(&node);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void IntersectVisitor::leaveNode()
|
||||
{
|
||||
IntersectState* cis = _intersectStateStack.back();
|
||||
cis->_segmentMaskStack.pop_back();
|
||||
}
|
||||
|
||||
void IntersectVisitor::apply(Node& node)
|
||||
{
|
||||
if (!enterNode(node)) return;
|
||||
|
||||
traverse(node);
|
||||
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
struct TriangleIntersect
|
||||
{
|
||||
Seg _seg;
|
||||
|
||||
Vec3 _s;
|
||||
Vec3 _d;
|
||||
float _length;
|
||||
|
||||
int _index;
|
||||
float _ratio;
|
||||
bool _hit;
|
||||
|
||||
typedef std::multimap<float,std::pair<int,osg::Vec3> > TriangleHitList;
|
||||
TriangleHitList _thl;
|
||||
|
||||
|
||||
TriangleIntersect(const Seg& seg,float ratio=FLT_MAX)
|
||||
{
|
||||
_seg=seg;
|
||||
_hit=false;
|
||||
_index = 0;
|
||||
_ratio = ratio;
|
||||
|
||||
_s = _seg.start();
|
||||
_d = _seg.end()-_seg.start();
|
||||
_length = _d.length();
|
||||
_d /= _length;
|
||||
|
||||
}
|
||||
|
||||
// void operator () (const Vec3& v1,const Vec3& v2,const Vec3& v3)
|
||||
// {
|
||||
// float r;
|
||||
// if (_seg.intersect(v1,v2,v3,r))
|
||||
// {
|
||||
// _thl.insert(std::pair<float,int>(r,_index));
|
||||
// _hit = true;
|
||||
// }
|
||||
// ++_index;
|
||||
// }
|
||||
|
||||
// bool intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r)
|
||||
void operator () (const Vec3& v1,const Vec3& v2,const Vec3& v3)
|
||||
{
|
||||
++_index;
|
||||
|
||||
if (v1==v2 || v2==v3 || v1==v3) return;
|
||||
|
||||
Vec3 v12 = v2-v1;
|
||||
Vec3 n12 = v12^_d;
|
||||
float ds12 = (_s-v1)*n12;
|
||||
float d312 = (v3-v1)*n12;
|
||||
if (d312>=0.0f)
|
||||
{
|
||||
if (ds12<0.0f) return;
|
||||
if (ds12>d312) return;
|
||||
}
|
||||
else // d312 < 0
|
||||
{
|
||||
if (ds12>0.0f) return;
|
||||
if (ds12<d312) return;
|
||||
}
|
||||
|
||||
|
||||
Vec3 v23 = v3-v2;
|
||||
Vec3 n23 = v23^_d;
|
||||
float ds23 = (_s-v2)*n23;
|
||||
float d123 = (v1-v2)*n23;
|
||||
if (d123>=0.0f)
|
||||
{
|
||||
if (ds23<0.0f) return;
|
||||
if (ds23>d123) return;
|
||||
}
|
||||
else // d123 < 0
|
||||
{
|
||||
if (ds23>0.0f) return;
|
||||
if (ds23<d123) return;
|
||||
}
|
||||
|
||||
|
||||
Vec3 v31 = v1-v3;
|
||||
Vec3 n31 = v31^_d;
|
||||
float ds31 = (_s-v3)*n31;
|
||||
float d231 = (v2-v3)*n31;
|
||||
if (d231>=0.0f)
|
||||
{
|
||||
if (ds31<0.0f) return;
|
||||
if (ds31>d231) return;
|
||||
}
|
||||
else // d231 < 0
|
||||
{
|
||||
if (ds31>0.0f) return;
|
||||
if (ds31<d231) return;
|
||||
}
|
||||
|
||||
float r3 = ds12/d312;
|
||||
float r1 = ds23/d123;
|
||||
float r2 = ds31/d231;
|
||||
|
||||
//float rt = r1+r2+r3;
|
||||
|
||||
Vec3 in = v1*r1+v2*r2+v3*r3;
|
||||
|
||||
float d = (in-_s)*_d;
|
||||
|
||||
|
||||
if (d<0.0f) return;
|
||||
if (d>_length) return;
|
||||
|
||||
osg::Vec3 normal = v12^v23;
|
||||
normal.normalize();
|
||||
|
||||
float r = d/_length;
|
||||
|
||||
_thl.insert(std::pair<float,std::pair<int,osg::Vec3> >
|
||||
(r,std::pair<int,osg::Vec3>(_index-1,normal)));
|
||||
_hit = true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
bool IntersectVisitor::intersect(GeoSet& gset)
|
||||
{
|
||||
bool hitFlag = false;
|
||||
|
||||
IntersectState* cis = _intersectStateStack.back();
|
||||
|
||||
const BoundingBox& bb = gset.getBound();
|
||||
|
||||
for(IntersectState::SegList::iterator sitr=cis->_segList.begin();
|
||||
sitr!=cis->_segList.end();
|
||||
++sitr)
|
||||
{
|
||||
if (sitr->second->intersect(bb))
|
||||
{
|
||||
TriangleIntersect ti(*sitr->second);
|
||||
for_each_triangle(gset,ti);
|
||||
if (ti._hit)
|
||||
{
|
||||
|
||||
for(TriangleIntersect::TriangleHitList::iterator thitr=ti._thl.begin();
|
||||
thitr!=ti._thl.end();
|
||||
++thitr)
|
||||
{
|
||||
Hit hit;
|
||||
hit._nodePath = _nodePath;
|
||||
hit._matrix = cis->_matrix;
|
||||
if (hit._matrix) hit._matrix->ref();
|
||||
hit._geoset = &gset;
|
||||
if (_nodePath.empty()) hit._geode = NULL;
|
||||
else hit._geode = dynamic_cast<Geode*>(_nodePath.back());
|
||||
|
||||
hit._ratio = thitr->first;
|
||||
hit._primitiveIndex = thitr->second.first;
|
||||
hit._originalSeg = sitr->first;
|
||||
if (hit._originalSeg) hit._originalSeg->ref();
|
||||
hit._localSeg = sitr->second;
|
||||
if (hit._localSeg) hit._localSeg->ref();
|
||||
|
||||
hit._intersectPoint = sitr->second->start()*(1.0f-hit._ratio)+
|
||||
sitr->second->end()*hit._ratio;
|
||||
|
||||
hit._intersectNormal = thitr->second.second;
|
||||
|
||||
// _segHitList[sitr->first].insert(hit);
|
||||
_segHitList[sitr->first].push_back(hit);
|
||||
std::sort(_segHitList[sitr->first].begin(),_segHitList[sitr->first].end());
|
||||
|
||||
hitFlag = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// else notify(INFO) << << "no BB hit"<<endl;
|
||||
}
|
||||
|
||||
return hitFlag;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void IntersectVisitor::apply(Geode& node)
|
||||
{
|
||||
if (!enterNode(node)) return;
|
||||
|
||||
|
||||
for(int i=0;i<node.getNumGeosets();++i)
|
||||
{
|
||||
|
||||
intersect(*node.getGeoSet(i));
|
||||
|
||||
}
|
||||
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
void IntersectVisitor::apply(Billboard& node)
|
||||
{
|
||||
if (!enterNode(node)) return;
|
||||
// Vec3 eye_local = getEyeLocal();
|
||||
// for(int i=0;i<node.getNumGeosets();++i)
|
||||
// {
|
||||
// Vec3 pos;
|
||||
// node.getPos(i,pos);
|
||||
//
|
||||
// GeoSet* gset = node.getGeoSet(i);
|
||||
//
|
||||
// Matrix local_mat;
|
||||
// node.calcTransform(eye_local,pos,local_mat);
|
||||
//
|
||||
// Matrix* matrix = NULL;
|
||||
// Matrix* currMatrix = getCurrentMatrix();
|
||||
// if (currMatrix)
|
||||
// {
|
||||
// matrix = new Matrix();
|
||||
// matrix->mult(local_mat,*(currMatrix));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// matrix = new Matrix(local_mat);
|
||||
// }
|
||||
//
|
||||
// matrix->ref();
|
||||
// matrix->unref();
|
||||
//
|
||||
// }
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
void IntersectVisitor::apply(Group& node)
|
||||
{
|
||||
if (!enterNode(node)) return;
|
||||
|
||||
traverse(node);
|
||||
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
void IntersectVisitor::apply(DCS& node)
|
||||
{
|
||||
if (!enterNode(node)) return;
|
||||
|
||||
pushMatrix(*node.getMatrix());
|
||||
|
||||
traverse(node);
|
||||
|
||||
popMatrix();
|
||||
|
||||
leaveNode();
|
||||
}
|
||||
|
||||
|
||||
void IntersectVisitor::apply(Switch& node)
|
||||
{
|
||||
apply((Group&)node);
|
||||
}
|
||||
|
||||
|
||||
void IntersectVisitor::apply(LOD& node)
|
||||
{
|
||||
apply((Group&)node);
|
||||
}
|
||||
|
||||
|
||||
void IntersectVisitor::apply(Scene& node)
|
||||
{
|
||||
apply((Group&)node);
|
||||
}
|
||||
0
src/osgUtil/Makedepend
Normal file
0
src/osgUtil/Makedepend
Normal file
43
src/osgUtil/Makefile
Normal file
43
src/osgUtil/Makefile
Normal file
@@ -0,0 +1,43 @@
|
||||
#!smake
|
||||
include ../../Make/makedefs
|
||||
|
||||
C++FILES = \
|
||||
DisplayListVisitor.cpp\
|
||||
RenderVisitor.cpp\
|
||||
SceneView.cpp\
|
||||
IntersectVisitor.cpp\
|
||||
CameraManipulator.cpp\
|
||||
TrackballManipulator.cpp\
|
||||
FlightManipulator.cpp\
|
||||
DriveManipulator.cpp\
|
||||
Version.cpp\
|
||||
|
||||
|
||||
TARGET_BASENAME = osgUtil
|
||||
|
||||
|
||||
LIBS = -ldl
|
||||
|
||||
LIB = ../../lib/lib$(TARGET_BASENAME).so
|
||||
#LIB = ../../lib/lib$(TARGET_BASENAME).a
|
||||
|
||||
TARGET_LIB_FILES = lib$(TARGET_BASENAME).so
|
||||
TARGET_INCLUDE_FILES = \
|
||||
osgUtil/CameraManipulator\
|
||||
osgUtil/DisplayListVisitor\
|
||||
osgUtil/DriveManipulator\
|
||||
osgUtil/Export\
|
||||
osgUtil/GUIActionAdapter\
|
||||
osgUtil/GUIEventAdapter\
|
||||
osgUtil/IntersectVisitor\
|
||||
osgUtil/RenderVisitor\
|
||||
osgUtil/SceneView\
|
||||
osgUtil/TrackballManipulator\
|
||||
osgUtil/FlightManipulator\
|
||||
osgUtil/Version\
|
||||
|
||||
|
||||
C++FLAGS += -I ../../include
|
||||
|
||||
include ../../Make/makerules
|
||||
|
||||
799
src/osgUtil/RenderVisitor.cpp
Normal file
799
src/osgUtil/RenderVisitor.cpp
Normal file
@@ -0,0 +1,799 @@
|
||||
#include "osgUtil/RenderVisitor"
|
||||
#include "osg/DCS"
|
||||
#include "osg/Geode"
|
||||
#include "osg/LOD"
|
||||
#include "osg/Billboard"
|
||||
#include "osg/LightSource"
|
||||
#include "osg/Notify"
|
||||
|
||||
#include <float.h>
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef OSG_USE_IO_DOT_H
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
static bool g_debugging = false;
|
||||
|
||||
ViewState::ViewState()
|
||||
{
|
||||
_matrix = NULL;
|
||||
_inverse = NULL;
|
||||
_ratio = 0.002f;
|
||||
_viewFrustumCullingActive=true;
|
||||
_smallFeatureCullingActive=true;
|
||||
}
|
||||
|
||||
ViewState::~ViewState()
|
||||
{
|
||||
if (_matrix) _matrix->unref();
|
||||
if (_inverse) _inverse->unref();
|
||||
}
|
||||
|
||||
|
||||
bool ViewState::isCulled(const BoundingSphere& sp)
|
||||
{
|
||||
if (!sp.isValid()) return true;
|
||||
|
||||
|
||||
Vec3 delta = sp._center-_eyePoint;
|
||||
if (_smallFeatureCullingActive)
|
||||
{
|
||||
if (sp._radius<delta.length()*_ratio)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_viewFrustumCullingActive)
|
||||
{
|
||||
if (delta*_frustumTopNormal>sp._radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (delta*_frustumBottomNormal>sp._radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (delta*_frustumLeftNormal>sp._radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (delta*_frustumRightNormal>sp._radius)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ViewState::isCulled(const BoundingBox& bb)
|
||||
{
|
||||
if (!bb.isValid()) return true;
|
||||
|
||||
if (_viewFrustumCullingActive)
|
||||
{
|
||||
unsigned int c;
|
||||
for(c=0;c<8;++c)
|
||||
{
|
||||
if ((bb.corner(c)-_eyePoint)*_frustumLeftNormal<=0.0f) break;
|
||||
}
|
||||
// if all corners have been checked, therefore all points are
|
||||
// and the far side of the left clipping plane and hence should be culled.
|
||||
if (c==8) return true;
|
||||
|
||||
for(c=0;c<8;++c)
|
||||
{
|
||||
if ((bb.corner(c)-_eyePoint)*_frustumRightNormal<=0.0f) break;
|
||||
}
|
||||
// if all corners have been checked, therefore all points are
|
||||
// and the far side of the right clipping plane and hence should be culled.
|
||||
if (c==8) return true;
|
||||
|
||||
for(c=0;c<8;++c)
|
||||
{
|
||||
if ((bb.corner(c)-_eyePoint)*_frustumTopNormal<=0.0f) break;
|
||||
}
|
||||
// if all corners have been checked, therefore all points are
|
||||
// and the far side of the top clipping plane and hence should be culled.
|
||||
if (c==8) return true;
|
||||
|
||||
|
||||
for(c=0;c<8;++c)
|
||||
{
|
||||
if ((bb.corner(c)-_eyePoint)*_frustumBottomNormal<=0.0f) break;
|
||||
}
|
||||
// if all corners have been checked, therefore all points are
|
||||
// and the far side of the bottom clipping plane and hence should be culled.
|
||||
if (c==8) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderVisitor::RenderVisitor()
|
||||
{
|
||||
// overide the default node visitor mode.
|
||||
setTraverseMode(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
|
||||
|
||||
_globalState=NULL;
|
||||
_LODBias = 1.0f;
|
||||
|
||||
_fovy=60.0f;
|
||||
_aspect=1.0f;
|
||||
_znear=1.0f;
|
||||
_zfar=1000.0f;
|
||||
|
||||
_tvs = new ViewState;
|
||||
_tvs->_eyePoint.set(0.0f,0.0f,1.0f);
|
||||
_tvs->_centerPoint.set(0.0f,0.0f,0.0f);
|
||||
_tvs->_lookVector.set(0.0f,0.0f,-1.0f);
|
||||
_tvs->_upVector.set(0.0f,1.0f,0.0f);
|
||||
_tvs->ref();
|
||||
|
||||
_cvs = _tvs;
|
||||
_cvs->ref();
|
||||
|
||||
_tsm = LOOK_VECTOR_DISTANCE;
|
||||
_tsm = OBJECT_EYE_POINT_DISTANCE;
|
||||
|
||||
_viewFrustumCullingActive=true;
|
||||
_smallFeatureCullingActive=true;
|
||||
|
||||
calculateClippingPlanes();
|
||||
}
|
||||
|
||||
RenderVisitor::~RenderVisitor()
|
||||
{
|
||||
reset();
|
||||
// if a global geostate is attached simply unref it.
|
||||
if (_globalState)
|
||||
{
|
||||
_globalState->unref();
|
||||
_globalState = NULL;
|
||||
}
|
||||
if (_tvs) _tvs->unref();
|
||||
if (_cvs) _cvs->unref();
|
||||
}
|
||||
|
||||
void RenderVisitor::reset()
|
||||
{
|
||||
|
||||
//
|
||||
// first unref all referenced objects and then empty the containers.
|
||||
//
|
||||
std::for_each(_viewStateStack.begin(),_viewStateStack.end(),UnrefOp<ViewState>());
|
||||
_viewStateStack.erase(_viewStateStack.begin(),_viewStateStack.end());
|
||||
if (_cvs!=_tvs)
|
||||
{
|
||||
if (_cvs) _cvs->unref();
|
||||
_cvs = _tvs;
|
||||
_cvs->ref();
|
||||
}
|
||||
|
||||
for(std::multimap<float,MatrixGeoSet>::iterator titr= _transparentGeoSets.begin();
|
||||
titr!= _transparentGeoSets.end();
|
||||
++titr)
|
||||
{
|
||||
if ((*titr).second.first) (*titr).second.first->unref();
|
||||
}
|
||||
_transparentGeoSets.erase(_transparentGeoSets.begin(),_transparentGeoSets.end());
|
||||
|
||||
for(std::multimap<GeoState*,MatrixGeoSet>::iterator oitr= _opaqueGeoSets.begin();
|
||||
oitr!= _opaqueGeoSets.end();
|
||||
++oitr)
|
||||
{
|
||||
if ((*oitr).second.first) (*oitr).second.first->unref();
|
||||
}
|
||||
_opaqueGeoSets.erase(_opaqueGeoSets.begin(),_opaqueGeoSets.end());
|
||||
|
||||
_lights.erase(_lights.begin(),_lights.end());
|
||||
|
||||
}
|
||||
|
||||
void RenderVisitor::setGlobalState(GeoState* global)
|
||||
{
|
||||
if (global==_globalState) return;
|
||||
if (_globalState) _globalState->unref();
|
||||
_globalState = global;
|
||||
_globalState->ref();
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::setPerspective(const osg::Camera& camera)
|
||||
{
|
||||
_fovy=camera.getFieldOfViewY();
|
||||
_aspect=camera.getAspectRatio();
|
||||
_znear=camera.getNearPlane();
|
||||
_zfar=camera.getFarPlane();
|
||||
|
||||
calculateClippingPlanes();
|
||||
}
|
||||
|
||||
void RenderVisitor::setPerspective(float fovy,float aspect,float znear,float zfar)
|
||||
{
|
||||
_fovy=fovy;
|
||||
_aspect=aspect;
|
||||
_znear=znear;
|
||||
_zfar=zfar;
|
||||
|
||||
calculateClippingPlanes();
|
||||
}
|
||||
|
||||
void RenderVisitor::setLookAt(const Camera& camera)
|
||||
{
|
||||
setLookAt(camera.getEyePoint(),camera.getLookPoint(),camera.getUpVector());
|
||||
}
|
||||
|
||||
void RenderVisitor::setLookAt(const Vec3& eye,const Vec3& center,const Vec3& upVector)
|
||||
{
|
||||
_tvs->_eyePoint = eye;
|
||||
|
||||
_tvs->_centerPoint = center;
|
||||
|
||||
_tvs->_lookVector = center-eye;
|
||||
_tvs->_lookVector.normalize();
|
||||
|
||||
_tvs->_upVector = upVector;
|
||||
|
||||
calculateClippingPlanes();
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::setLookAt(double eyeX,double eyeY,double eyeZ,
|
||||
double centerX,double centerY,double centerZ,
|
||||
double upX,double upY,double upZ)
|
||||
{
|
||||
_tvs->_eyePoint[0] = eyeX;
|
||||
_tvs->_eyePoint[1] = eyeY;
|
||||
_tvs->_eyePoint[2] = eyeZ;
|
||||
|
||||
_tvs->_centerPoint[0] = centerX;
|
||||
_tvs->_centerPoint[1] = centerY;
|
||||
_tvs->_centerPoint[2] = centerZ;
|
||||
|
||||
_tvs->_lookVector[0] = centerX-eyeX;
|
||||
_tvs->_lookVector[1] = centerY-eyeY;
|
||||
_tvs->_lookVector[2] = centerZ-eyeZ;
|
||||
_tvs->_lookVector.normalize();
|
||||
|
||||
_tvs->_upVector[0] = upX;
|
||||
_tvs->_upVector[1] = upY;
|
||||
_tvs->_upVector[2] = upZ;
|
||||
|
||||
calculateClippingPlanes();
|
||||
}
|
||||
|
||||
void RenderVisitor::setCullingActive(CullingType ct,bool active)
|
||||
{
|
||||
switch(ct)
|
||||
{
|
||||
case(VIEW_FRUSTUM_CULLING):_viewFrustumCullingActive=active;break;
|
||||
case(SMALL_FEATURE_CULLING):_smallFeatureCullingActive=active;break;
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderVisitor::getCullingActive(CullingType ct)
|
||||
{
|
||||
switch(ct)
|
||||
{
|
||||
case(VIEW_FRUSTUM_CULLING):return _viewFrustumCullingActive;
|
||||
case(SMALL_FEATURE_CULLING):return _smallFeatureCullingActive;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderVisitor::calculateClippingPlanes()
|
||||
{
|
||||
float half_fovy = _fovy*0.5f;
|
||||
float s = sinf(half_fovy*M_PI/180.0f);
|
||||
float c = cosf(half_fovy*M_PI/180.0f);
|
||||
|
||||
Vec3 lv = _tvs->_lookVector;
|
||||
Vec3 up = _tvs->_upVector;
|
||||
Vec3 sv = lv ^ up;
|
||||
sv.normalize();
|
||||
|
||||
_tvs->_frustumTopNormal = -lv*s + up*c;
|
||||
_tvs->_frustumTopNormal.normalize();
|
||||
|
||||
_tvs->_frustumBottomNormal = -lv*s - up*c;
|
||||
_tvs->_frustumBottomNormal.normalize();
|
||||
|
||||
_tvs->_frustumLeftNormal = -sv*c - lv*(s*_aspect);
|
||||
_tvs->_frustumLeftNormal.normalize();
|
||||
|
||||
_tvs->_frustumRightNormal = sv*c - lv*(s*_aspect);
|
||||
_tvs->_frustumRightNormal.normalize();
|
||||
|
||||
// notify(INFO) << "_frustumTopNormal = "<<_tvs->_frustumTopNormal[0]<<"\t"<<_tvs->_frustumTopNormal[1]<<"\t"<<_tvs->_frustumTopNormal[2]<<endl;
|
||||
// notify(INFO) << "_frustumBottomNormal = "<<_tvs->_frustumBottomNormal[0]<<"\t"<<_tvs->_frustumBottomNormal[1]<<"\t"<<_tvs->_frustumBottomNormal[2]<<endl;
|
||||
// notify(INFO) << "_frustumLeftNormal = "<<_tvs->_frustumLeftNormal[0]<<"\t"<<_tvs->_frustumLeftNormal[1]<<"\t"<<_tvs->_frustumLeftNormal[2]<<endl;
|
||||
// notify(INFO) << "_frustumRightNormal = "<<_tvs->_frustumRightNormal[0]<<"\t"<<_tvs->_frustumRightNormal[1]<<"\t"<<_tvs->_frustumRightNormal[2]<<endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::pushMatrix(const Matrix& matrix)
|
||||
{
|
||||
|
||||
ViewState* nvs = new ViewState;
|
||||
nvs->ref();
|
||||
nvs->_viewFrustumCullingActive=_viewFrustumCullingActive;
|
||||
nvs->_smallFeatureCullingActive=_smallFeatureCullingActive;
|
||||
|
||||
if (_cvs && _cvs->_matrix)
|
||||
{
|
||||
nvs->_matrix = new Matrix;
|
||||
nvs->_matrix->mult(matrix,*(_cvs->_matrix));
|
||||
}
|
||||
else
|
||||
{
|
||||
nvs->_matrix = new Matrix(matrix);
|
||||
}
|
||||
nvs->_matrix->ref();
|
||||
|
||||
Matrix* inverse_world = new Matrix;
|
||||
inverse_world->ref();
|
||||
inverse_world->invert(*(nvs->_matrix));
|
||||
nvs->_inverse = inverse_world;
|
||||
|
||||
nvs->_eyePoint = _tvs->_eyePoint*(*inverse_world);
|
||||
nvs->_centerPoint = _tvs->_centerPoint*(*inverse_world);
|
||||
|
||||
nvs->_lookVector = nvs->_centerPoint - nvs->_eyePoint;
|
||||
nvs->_lookVector.normalize();
|
||||
|
||||
nvs->_frustumTopNormal = (_tvs->_eyePoint + _tvs->_frustumTopNormal)*(*inverse_world)-nvs->_eyePoint;
|
||||
nvs->_frustumTopNormal.normalize();
|
||||
|
||||
nvs->_frustumBottomNormal = (_tvs->_eyePoint + _tvs->_frustumBottomNormal)*(*inverse_world)-nvs->_eyePoint;
|
||||
nvs->_frustumBottomNormal.normalize();
|
||||
|
||||
nvs->_frustumLeftNormal = (_tvs->_eyePoint + _tvs->_frustumLeftNormal)*(*inverse_world)-nvs->_eyePoint;
|
||||
nvs->_frustumLeftNormal.normalize();
|
||||
|
||||
nvs->_frustumRightNormal = (_tvs->_eyePoint + _tvs->_frustumRightNormal)*(*inverse_world)-nvs->_eyePoint;
|
||||
nvs->_frustumRightNormal.normalize();
|
||||
|
||||
if (_cvs) _cvs->unref();
|
||||
|
||||
_cvs = nvs;
|
||||
|
||||
if (_cvs) _cvs->ref();
|
||||
_viewStateStack.push_back(nvs);
|
||||
}
|
||||
|
||||
void RenderVisitor::popMatrix()
|
||||
{
|
||||
// pop the top of the view stack and unref it.
|
||||
ViewState* pvs = _viewStateStack.back();
|
||||
_viewStateStack.pop_back();
|
||||
pvs->unref();
|
||||
|
||||
// unref previous cvs
|
||||
if (_cvs) _cvs->unref();
|
||||
|
||||
// to new cvs and ref it.
|
||||
if (_viewStateStack.empty())
|
||||
{
|
||||
_cvs = _tvs;
|
||||
if (_cvs) _cvs->ref();
|
||||
}
|
||||
else
|
||||
{
|
||||
_cvs = _viewStateStack.back();
|
||||
if (_cvs) _cvs->ref();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Matrix* RenderVisitor::getCurrentMatrix()
|
||||
{
|
||||
return _cvs->_matrix;
|
||||
}
|
||||
|
||||
Matrix* RenderVisitor::getInverseCurrentMatrix()
|
||||
{
|
||||
return _cvs->_inverse;
|
||||
}
|
||||
|
||||
const Vec3& RenderVisitor::getEyeLocal()
|
||||
{
|
||||
return _cvs->_eyePoint;
|
||||
}
|
||||
|
||||
const Vec3& RenderVisitor::getCenterLocal()
|
||||
{
|
||||
return _cvs->_centerPoint;
|
||||
}
|
||||
|
||||
const Vec3& RenderVisitor::getLookVectorLocal()
|
||||
{
|
||||
return _cvs->_lookVector;
|
||||
}
|
||||
|
||||
bool RenderVisitor::isCulled(const BoundingSphere& sp)
|
||||
{
|
||||
return _cvs->isCulled(sp);
|
||||
}
|
||||
|
||||
bool RenderVisitor::isCulled(const BoundingBox& bb)
|
||||
{
|
||||
return _cvs->isCulled(bb);
|
||||
}
|
||||
|
||||
void RenderVisitor::apply(Node& node)
|
||||
{
|
||||
if (isCulled(node.getBound())) return;
|
||||
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
void RenderVisitor::apply(Geode& node)
|
||||
{
|
||||
if (isCulled(node.getBound())) return;
|
||||
|
||||
Matrix* matrix = getCurrentMatrix();
|
||||
for(int i=0;i<node.getNumGeosets();++i)
|
||||
{
|
||||
GeoSet* gset = node.getGeoSet(i);
|
||||
if (isCulled(gset->getBound())) continue;
|
||||
|
||||
GeoState* gstate = gset->getGeoState();
|
||||
bool isTransparent = gstate && gstate->isTransparent();
|
||||
if (isTransparent)
|
||||
{
|
||||
|
||||
Vec3 center;
|
||||
if (matrix)
|
||||
{
|
||||
center = (gset->getBound().center())*(*matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
center = gset->getBound().center();
|
||||
}
|
||||
Vec3 delta_center = center-_tvs->_eyePoint;
|
||||
|
||||
if (g_debugging)
|
||||
{
|
||||
notify(INFO) << "center ["<<center.x()<<","<<center.y()<<","<<center.z()<<"]"<<endl;
|
||||
notify(INFO) << "delta_center ["<<delta_center.x()<<","<<delta_center.y()<<","<<delta_center.z()<<"]"<<endl;
|
||||
notify(INFO) << "_lookVector ["<<_tvs->_lookVector.x()<<","<<_tvs->_lookVector.y()<<","<<_tvs->_lookVector.z()<<"]"<<endl;
|
||||
}
|
||||
|
||||
float depth;
|
||||
switch(_tsm)
|
||||
{
|
||||
case(LOOK_VECTOR_DISTANCE):depth = _tvs->_lookVector*delta_center;break;
|
||||
case(OBJECT_EYE_POINT_DISTANCE):
|
||||
default: depth = delta_center.length2();break;
|
||||
}
|
||||
|
||||
if (matrix) matrix->ref();
|
||||
_transparentGeoSets.insert(
|
||||
std::pair<float,MatrixGeoSet>(depth,MatrixGeoSet(matrix,gset))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (matrix) matrix->ref();
|
||||
_opaqueGeoSets.insert(
|
||||
std::pair<GeoState*,MatrixGeoSet>(gstate,MatrixGeoSet(matrix,gset))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderVisitor::apply(Billboard& node)
|
||||
{
|
||||
if (isCulled(node.getBound())) return;
|
||||
|
||||
Vec3 eye_local = getEyeLocal();
|
||||
|
||||
for(int i=0;i<node.getNumGeosets();++i)
|
||||
{
|
||||
Vec3 pos;
|
||||
node.getPos(i,pos);
|
||||
|
||||
GeoSet* gset = node.getGeoSet(i);
|
||||
// need to modify isCulled to handle the billboard offset.
|
||||
// if (isCulled(gset->getBound())) continue;
|
||||
|
||||
Matrix local_mat;
|
||||
node.calcTransform(eye_local,pos,local_mat);
|
||||
|
||||
Matrix* matrix = NULL;
|
||||
if (_cvs->_matrix)
|
||||
{
|
||||
matrix = new Matrix();
|
||||
matrix->mult(local_mat,*(_cvs->_matrix));
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix = new Matrix(local_mat);
|
||||
}
|
||||
|
||||
GeoState* gstate = gset->getGeoState();
|
||||
bool isTransparent = gstate && gstate->isTransparent();
|
||||
if (isTransparent)
|
||||
{
|
||||
|
||||
Vec3 center;
|
||||
if (matrix)
|
||||
{
|
||||
center = (gset->getBound().center())*(*matrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
center = gset->getBound().center();
|
||||
}
|
||||
Vec3 delta_center = center-_tvs->_eyePoint;
|
||||
|
||||
if (g_debugging)
|
||||
{
|
||||
notify(INFO) << "center ["<<center.x()<<","<<center.y()<<","<<center.z()<<"]"<<endl;
|
||||
notify(INFO) << "delta_center ["<<delta_center.x()<<","<<delta_center.y()<<","<<delta_center.z()<<"]"<<endl;
|
||||
notify(INFO) << "_lookVector ["<<_tvs->_lookVector.x()<<","<<_tvs->_lookVector.y()<<","<<_tvs->_lookVector.z()<<"]"<<endl;
|
||||
}
|
||||
|
||||
float depth;
|
||||
switch(_tsm)
|
||||
{
|
||||
case(LOOK_VECTOR_DISTANCE):depth = _tvs->_lookVector*delta_center;break;
|
||||
case(OBJECT_EYE_POINT_DISTANCE):
|
||||
default: depth = delta_center.length2();break;
|
||||
}
|
||||
|
||||
if (matrix) matrix->ref();
|
||||
_transparentGeoSets.insert(
|
||||
std::pair<float,MatrixGeoSet>(depth,MatrixGeoSet(matrix,gset))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (matrix) matrix->ref();
|
||||
_opaqueGeoSets.insert(
|
||||
std::pair<GeoState*,MatrixGeoSet>(gstate,MatrixGeoSet(matrix,gset))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RenderVisitor::apply(LightSource& node)
|
||||
{
|
||||
Matrix* matrix = getCurrentMatrix();
|
||||
Light* light = node.getLight();
|
||||
if (light)
|
||||
{
|
||||
if (matrix) matrix->ref();
|
||||
_lights.insert(std::pair<Matrix*,Light*>(matrix,light));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderVisitor::apply(Group& node)
|
||||
{
|
||||
if (isCulled(node.getBound())) return;
|
||||
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::apply(DCS& node)
|
||||
{
|
||||
if (isCulled(node.getBound())) return;
|
||||
|
||||
pushMatrix(*node.getMatrix());
|
||||
|
||||
traverse(node);
|
||||
|
||||
popMatrix();
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::apply(Switch& node)
|
||||
{
|
||||
apply((Group&)node);
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::apply(LOD& node)
|
||||
{
|
||||
if (isCulled(node.getBound())) return;
|
||||
|
||||
int eval = node.evaluate(getEyeLocal(),_LODBias);
|
||||
if (eval<0)
|
||||
{
|
||||
//notify(INFO) << "culled LOD"<<endl;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//notify(INFO) << "selecting child "<<eval<<endl;
|
||||
node.getChild(eval)->accept(*this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void RenderVisitor::apply(Scene& node)
|
||||
{
|
||||
apply((Group&)node);
|
||||
}
|
||||
|
||||
|
||||
bool RenderVisitor::calcNearFar(double& near_plane,double& far_plane)
|
||||
{
|
||||
if (_opaqueGeoSets.empty() && _transparentGeoSets.empty()) return false;
|
||||
|
||||
near_plane = FLT_MAX;
|
||||
far_plane = -FLT_MAX;
|
||||
|
||||
Vec3 eyePoint = getEyeLocal();
|
||||
Vec3 lookVector = getLookVectorLocal();
|
||||
|
||||
for(OpaqueList::iterator oitr = _opaqueGeoSets.begin();
|
||||
oitr != _opaqueGeoSets.end();
|
||||
++oitr)
|
||||
{
|
||||
Matrix* matrix = (oitr->second).first;
|
||||
GeoSet* gset = (oitr->second).second;
|
||||
const BoundingBox& bb = gset->getBound();
|
||||
for(int c=0;c<8;++c)
|
||||
{
|
||||
float d;
|
||||
if (matrix) d = ((bb.corner(c)*(*matrix))-eyePoint)*lookVector;
|
||||
else d = (bb.corner(c)-eyePoint)*lookVector;
|
||||
if (d<near_plane) near_plane = d;
|
||||
if (d>far_plane) far_plane = d;
|
||||
}
|
||||
}
|
||||
|
||||
for(TransparentList::iterator titr = _transparentGeoSets.begin();
|
||||
titr != _transparentGeoSets.end();
|
||||
++titr)
|
||||
{
|
||||
Matrix* matrix = (titr->second).first;
|
||||
GeoSet* gset = (titr->second).second;
|
||||
const BoundingBox& bb = gset->getBound();
|
||||
for(int c=0;c<8;++c)
|
||||
{
|
||||
float d;
|
||||
if (matrix) d = ((bb.corner(c)*(*matrix))-eyePoint)*lookVector;
|
||||
else d = (bb.corner(c)-eyePoint)*lookVector;
|
||||
if (d<near_plane) near_plane = d;
|
||||
if (d>far_plane) far_plane = d;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderVisitor::render()
|
||||
{
|
||||
|
||||
Matrix* prevMatrix = NULL;
|
||||
Matrix* currMatrix = NULL;
|
||||
|
||||
GeoState* currGeoState = NULL;
|
||||
GeoState* prevGeoState = NULL;
|
||||
|
||||
if (g_debugging) notify(INFO) << "start of render"<<endl;
|
||||
|
||||
if (_globalState)
|
||||
{
|
||||
_globalState->apply();
|
||||
prevGeoState=_globalState;
|
||||
}
|
||||
|
||||
|
||||
// apply the lists.
|
||||
for(LightList::iterator litr=_lights.begin();
|
||||
litr!=_lights.end();
|
||||
++litr)
|
||||
{
|
||||
currMatrix = litr->first;
|
||||
if (currMatrix!=prevMatrix)
|
||||
{
|
||||
if (prevMatrix) glPopMatrix();
|
||||
if (currMatrix)
|
||||
{
|
||||
glPushMatrix();
|
||||
glMultMatrixf( (GLfloat *)(currMatrix->_mat) );
|
||||
}
|
||||
prevMatrix = currMatrix;
|
||||
}
|
||||
(litr->second)->apply();
|
||||
}
|
||||
|
||||
// draw the opaque bin.
|
||||
for(std::multimap<GeoState*,MatrixGeoSet>::iterator oitr= _opaqueGeoSets.begin();
|
||||
oitr!= _opaqueGeoSets.end();
|
||||
++oitr)
|
||||
{
|
||||
if (g_debugging)
|
||||
{
|
||||
notify(INFO) << " drawing opaque matrix["<<(*oitr).second.first<<"]"
|
||||
<< " geoset["<<(*oitr).second.second<<"]"
|
||||
<< " geostate["<<(*oitr).second.second->getGeoState()<<"]"<<endl;
|
||||
}
|
||||
|
||||
currMatrix = (*oitr).second.first;
|
||||
if (currMatrix!=prevMatrix)
|
||||
{
|
||||
if (prevMatrix) glPopMatrix();
|
||||
if (currMatrix)
|
||||
{
|
||||
glPushMatrix();
|
||||
glMultMatrixf( (GLfloat *)(currMatrix->_mat) );
|
||||
}
|
||||
prevMatrix = currMatrix;
|
||||
}
|
||||
|
||||
currGeoState = (*oitr).first;
|
||||
if (currGeoState!=prevGeoState)
|
||||
{
|
||||
if (currGeoState) currGeoState->apply(_globalState,prevGeoState);
|
||||
prevGeoState = currGeoState;
|
||||
}
|
||||
|
||||
(*oitr).second.second->draw();
|
||||
}
|
||||
|
||||
|
||||
// glPushAttrib( GL_DEPTH_TEST );
|
||||
// glDisable( GL_DEPTH_TEST );
|
||||
|
||||
// render the transparent geoset in reverse order, so to render the
|
||||
// deepest transparent objects, relative to the look vector, first.
|
||||
for(std::multimap<float,MatrixGeoSet>::reverse_iterator titr= _transparentGeoSets.rbegin();
|
||||
titr!= _transparentGeoSets.rend();
|
||||
++titr)
|
||||
{
|
||||
if (g_debugging)
|
||||
{
|
||||
notify(INFO) << " drawing transparent matrix["<<(*titr).second.first<<"]"
|
||||
<< " geoset["<<(*titr).second.second<<"]"
|
||||
<< " geostate["<<(*titr).second.second->getGeoState()<<"]"
|
||||
<< " depth["<<(*titr).first<<"]"<<endl;
|
||||
}
|
||||
|
||||
currMatrix = (*titr).second.first;
|
||||
if (currMatrix!=prevMatrix)
|
||||
{
|
||||
if (prevMatrix) glPopMatrix();
|
||||
if (currMatrix)
|
||||
{
|
||||
glPushMatrix();
|
||||
glMultMatrixf( (GLfloat *)(currMatrix->_mat) );
|
||||
}
|
||||
prevMatrix = currMatrix;
|
||||
}
|
||||
|
||||
currGeoState = (*titr).second.second->getGeoState();
|
||||
if (currGeoState!=prevGeoState)
|
||||
{
|
||||
if (currGeoState) currGeoState->apply(_globalState,prevGeoState);
|
||||
prevGeoState = currGeoState;
|
||||
}
|
||||
|
||||
(*titr).second.second->draw();
|
||||
}
|
||||
|
||||
// glPopAttrib();
|
||||
|
||||
|
||||
if (currMatrix) glPopMatrix();
|
||||
|
||||
if (g_debugging)
|
||||
{
|
||||
notify(INFO) << "end of render"<<endl<<endl;
|
||||
notify(INFO).flush();
|
||||
}
|
||||
}
|
||||
208
src/osgUtil/SceneView.cpp
Normal file
208
src/osgUtil/SceneView.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
#include "osgUtil/SceneView"
|
||||
#include "osg/Notify"
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
SceneView::SceneView()
|
||||
{
|
||||
_calc_nearfar = true;
|
||||
|
||||
_backgroundColor.set(0.2f, 0.2f, 0.4f, 1.0f);
|
||||
|
||||
_near_plane = 1.0f;
|
||||
_far_plane = 1.0f;
|
||||
|
||||
_lodBias = 1.0f;
|
||||
|
||||
_lightingMode=HEADLIGHT;
|
||||
}
|
||||
|
||||
SceneView::~SceneView()
|
||||
{
|
||||
}
|
||||
|
||||
void SceneView::setDefaults()
|
||||
{
|
||||
_globalState = new osg::GeoState;
|
||||
|
||||
_lightingMode=HEADLIGHT;
|
||||
_light = new osg::Light;
|
||||
|
||||
_camera = new osg::Camera;
|
||||
|
||||
_renderVisitor = new osgUtil::RenderVisitor;
|
||||
|
||||
_globalState->setGlobalDefaults();
|
||||
_globalState->setMode(osg::GeoState::LIGHTING, osg::GeoState::ON);
|
||||
|
||||
_backgroundColor.set(0.2f, 0.2f, 0.4f, 1.0f);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SceneView::cull()
|
||||
{
|
||||
if (!_renderVisitor) return;
|
||||
if (!_sceneData) return;
|
||||
|
||||
_camera->setAspectRatio((GLfloat)_view[2]/(GLfloat) _view[3]);
|
||||
|
||||
_renderVisitor->reset();
|
||||
|
||||
_renderVisitor->setGlobalState(_globalState.get());
|
||||
_renderVisitor->setLODBias(_lodBias);
|
||||
// _renderVisitor->setPerspective(60.0f, (GLfloat)_view[2]/(GLfloat) _view[3], _near_plane, _far_plane );
|
||||
_renderVisitor->setPerspective(*_camera);
|
||||
_renderVisitor->setLookAt(*_camera);
|
||||
|
||||
_sceneData->accept(*_renderVisitor);
|
||||
|
||||
if (_calc_nearfar)
|
||||
{
|
||||
if (_renderVisitor->calcNearFar(_near_plane,_far_plane))
|
||||
{
|
||||
// shift the far plane slight further away from the eye point.
|
||||
// and shift the near plane slightly near the eye point, this
|
||||
// will give a little space betwenn the near and far planes
|
||||
// and the model, crucial when the naer and far planes are
|
||||
// coincedent.
|
||||
_far_plane *= 1.05;
|
||||
_near_plane *= 0.95;
|
||||
|
||||
// if required clamp the near plane to prevent negative or near zero
|
||||
// near planes.
|
||||
float min_near_plane = _far_plane*0.0005f;
|
||||
if (_near_plane<min_near_plane) _near_plane=min_near_plane;
|
||||
}
|
||||
else
|
||||
{
|
||||
_near_plane = 1.0f;
|
||||
_far_plane = 1000.0f;
|
||||
}
|
||||
|
||||
_camera->setNearPlane(_near_plane);
|
||||
_camera->setFarPlane(_far_plane);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneView::draw()
|
||||
{
|
||||
if (!_renderVisitor) return;
|
||||
if (!_sceneData) return;
|
||||
|
||||
glViewport( _view[0], _view[1], _view[2], _view[3] );
|
||||
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
glClearColor( _backgroundColor[0], _backgroundColor[1], _backgroundColor[2], _backgroundColor[3]);
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// glMatrixMode( GL_PROJECTION );
|
||||
// glLoadIdentity();
|
||||
// gluPerspective( 60.0f, (GLfloat)_view[2]/(GLfloat) _view[3], _near_plane, _far_plane );
|
||||
|
||||
_camera->draw_PROJECTION();
|
||||
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity();
|
||||
|
||||
if (_lightingMode==HEADLIGHT)
|
||||
{
|
||||
_light->apply();
|
||||
}
|
||||
|
||||
_camera->draw_MODELVIEW();
|
||||
|
||||
// gluLookAt( _camera->getEyePoint().x(), _camera->getEyePoint().y(), _camera->getEyePoint().z(),
|
||||
// _camera->getLookPoint().x(), _camera->getLookPoint().y(), _camera->getLookPoint().z(),
|
||||
// _camera->getUpVector().x(), _camera->getUpVector().y(), _camera->getUpVector().z());
|
||||
|
||||
if (_lightingMode==SKY_LIGHT)
|
||||
{
|
||||
_light->apply();
|
||||
}
|
||||
|
||||
|
||||
// glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,_two_sided_lighting);
|
||||
|
||||
|
||||
glGetDoublev(GL_MODELVIEW_MATRIX,_model);
|
||||
glGetDoublev(GL_PROJECTION_MATRIX,_proj);
|
||||
|
||||
|
||||
_renderVisitor->render();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** Calculate, via glUnProject, the object coordinates of a window point.
|
||||
Note, current implementation requires that SceneView::draw() has been previously called
|
||||
for projectWindowIntoObject to produce valid values. As per OpenGL
|
||||
windows coordinates are calculated relative to the bottom left of the window.*/
|
||||
bool SceneView::projectWindowIntoObject(const osg::Vec3& window,osg::Vec3& object) const
|
||||
{
|
||||
GLdouble sX,sY,sZ;
|
||||
GLint result_start = gluUnProject((GLdouble)window[0],(GLdouble)window[1],(GLdouble)window[2],
|
||||
_model,_proj,_view,
|
||||
&sX,&sY,&sZ);
|
||||
if (result_start)
|
||||
{
|
||||
object.set(sX,sY,sZ);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Calculate, via glUnProject, the object coordinates of a window x,y
|
||||
when projected onto the near and far planes.
|
||||
Note, current implementation requires that SceneView::draw() has been previously called
|
||||
for projectWindowIntoObject to produce valid values. As per OpenGL
|
||||
windows coordinates are calculated relative to the bottom left of the window.*/
|
||||
bool SceneView::projectWindowXYIntoObject(int x,int y,osg::Vec3& near_point,osg::Vec3& far_point) const
|
||||
{
|
||||
GLdouble nX,nY,nZ;
|
||||
GLint result_near = gluUnProject((GLdouble)x,(GLdouble)y,(GLdouble)0.0,
|
||||
_model,_proj,_view,
|
||||
&nX,&nY,&nZ);
|
||||
|
||||
|
||||
if (result_near==0) return false;
|
||||
|
||||
GLdouble fX,fY,fZ;
|
||||
GLint result_far = gluUnProject((GLdouble)x,(GLdouble)y,(GLdouble)1.0,
|
||||
_model,_proj,_view,
|
||||
&fX,&fY,&fZ);
|
||||
|
||||
if (result_far==0) return false;
|
||||
|
||||
near_point.set(nX,nY,nZ);
|
||||
far_point.set(fX,fY,fZ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Calculate, via glProject, the object coordinates of a window.
|
||||
Note, current implementation requires that SceneView::draw() has been previously called
|
||||
for projectWindowIntoObject to produce valid values. As per OpenGL
|
||||
windows coordinates are calculated relative to the bottom left of the window.*/
|
||||
bool SceneView::projectObjectIntoWindow(const osg::Vec3& object,osg::Vec3& window) const
|
||||
{
|
||||
GLdouble sX,sY,sZ;
|
||||
GLint result_start = gluProject((GLdouble)object[0],(GLdouble)object[1],(GLdouble)object[2],
|
||||
_model,_proj,_view,
|
||||
&sX,&sY,&sZ);
|
||||
if (result_start)
|
||||
{
|
||||
window.set(sX,sY,sZ);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
348
src/osgUtil/TrackballManipulator.cpp
Normal file
348
src/osgUtil/TrackballManipulator.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
#include "osgUtil/TrackballManipulator"
|
||||
#include "osg/Notify"
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
osg::Node* TrackballManipulator::getNode() const
|
||||
{
|
||||
return _node.get();
|
||||
}
|
||||
|
||||
void TrackballManipulator::home(GUIEventAdapter& /*ea*/,GUIActionAdapter& us)
|
||||
{
|
||||
if(_node.get() && _camera.get())
|
||||
{
|
||||
|
||||
const osg::BoundingSphere& boundingSphere=_node->getBound();
|
||||
|
||||
_camera->setView(boundingSphere._center+osg::Vec3( 0.0,-2.0f * boundingSphere._radius,0.0f), // eye
|
||||
boundingSphere._center, // look
|
||||
osg::Vec3(0.0f,0.0f,1.0f)); // up
|
||||
|
||||
us.needRedraw();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TrackballManipulator::init(GUIEventAdapter& /*ea*/,GUIActionAdapter& /*us*/)
|
||||
{
|
||||
flushMouseEventStack();
|
||||
}
|
||||
|
||||
bool TrackballManipulator::update(GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
if(!_camera.get()) return false;
|
||||
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case(GUIEventAdapter::PUSH):
|
||||
{
|
||||
flushMouseEventStack();
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
us.needContinuousUpdate(false);
|
||||
_thrown = false;
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::RELEASE):
|
||||
{
|
||||
if (ea.getButtonMask()==0) {
|
||||
|
||||
if (isMouseMoving())
|
||||
{
|
||||
if (calcMovement())
|
||||
{
|
||||
us.needRedraw();
|
||||
us.needContinuousUpdate(true);
|
||||
_thrown = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
flushMouseEventStack();
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
us.needContinuousUpdate(false);
|
||||
_thrown = false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
flushMouseEventStack();
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
us.needContinuousUpdate(false);
|
||||
_thrown = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::DRAG):
|
||||
{
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.needRedraw();
|
||||
us.needContinuousUpdate(false);
|
||||
_thrown = false;
|
||||
}
|
||||
return true;
|
||||
case(GUIEventAdapter::MOVE):
|
||||
{
|
||||
}
|
||||
return false;
|
||||
case(GUIEventAdapter::KEYBOARD):
|
||||
if (ea.getKey()==' ')
|
||||
{
|
||||
flushMouseEventStack();
|
||||
_thrown = false;
|
||||
home(ea,us);
|
||||
us.needRedraw();
|
||||
us.needContinuousUpdate(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case(GUIEventAdapter::FRAME):
|
||||
if (_thrown)
|
||||
{
|
||||
if (calcMovement()) us.needRedraw();
|
||||
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(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 = 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;
|
||||
|
||||
unsigned int buttonMask = _ga_t1->getButtonMask();
|
||||
if (buttonMask==GUIEventAdapter::LEFT_BUTTON)
|
||||
{
|
||||
|
||||
// rotate camera.
|
||||
|
||||
osg::Vec3 center = _camera->getLookPoint();
|
||||
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.makeTrans(-center.x(),-center.y(),-center.z());
|
||||
mat.postRot(angle,axis.x(),axis.y(),axis.z());
|
||||
mat.postTrans(center.x(),center.y(),center.z());
|
||||
|
||||
_camera->mult(*_camera,mat);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::MIDDLE_BUTTON ||
|
||||
buttonMask==(GUIEventAdapter::LEFT_BUTTON|GUIEventAdapter::RIGHT_BUTTON))
|
||||
{
|
||||
|
||||
// pan model.
|
||||
|
||||
float scale = 0.0015f*_camera->getFocalDistance();
|
||||
|
||||
osg::Vec3 uv = _camera->getUpVector();
|
||||
osg::Vec3 sv = _camera->getSideVector();
|
||||
osg::Vec3 dv = uv*(dy*scale)-sv*(dx*scale);
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTrans(dv.x(),dv.y(),dv.z());
|
||||
|
||||
_camera->mult(*_camera,mat);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::RIGHT_BUTTON)
|
||||
{
|
||||
|
||||
// zoom model.
|
||||
|
||||
float fd = _camera->getFocalDistance();
|
||||
float scale = 1.0f-dy*0.001f;
|
||||
if (fd*scale>_modelScale*_minimumZoomScale)
|
||||
{
|
||||
// zoom camera in.
|
||||
osg::Vec3 center = _camera->getLookPoint();
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTrans(-center.x(),-center.y(),-center.z());
|
||||
mat.postScale(scale,scale,scale);
|
||||
mat.postTrans(center.x(),center.y(),center.z());
|
||||
|
||||
_camera->mult(*_camera,mat);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// notify(DEBUG) << "Pushing forward"<<endl;
|
||||
// push the camera forward.
|
||||
float scale = 0.0015f*fd;
|
||||
osg::Vec3 dv = _camera->getLookVector()*(dy*scale);
|
||||
|
||||
osg::Matrix mat;
|
||||
mat.makeTrans(dv.x(),dv.y(),dv.z());
|
||||
|
||||
_camera->mult(*_camera,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
|
||||
*/
|
||||
axis = p1^p2;
|
||||
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 = asin(t) * 180.0f/M_PI;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
if (d < r * 0.70710678118654752440) { /* Inside sphere */
|
||||
z = sqrt(r*r - d*d);
|
||||
} else { /* On hyperbola */
|
||||
t = r / 1.41421356237309504880;
|
||||
z = t*t / d;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
12
src/osgUtil/Version.cpp
Normal file
12
src/osgUtil/Version.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "osgUtil/Version"
|
||||
|
||||
|
||||
const char* osgUtilGetVersion()
|
||||
{
|
||||
return "0.8.34";
|
||||
}
|
||||
|
||||
const char* osgUtilGetLibraryName()
|
||||
{
|
||||
return "Open Scene Graph Utility Library";
|
||||
}
|
||||
Reference in New Issue
Block a user