Initial revision

This commit is contained in:
Don BURNS
2001-01-10 16:32:10 +00:00
parent 7c12eb9361
commit 70208ebc06
461 changed files with 70936 additions and 0 deletions

View 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;
}

View 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;
}
}

View 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;
}

View 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;
}

View 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
View File

43
src/osgUtil/Makefile Normal file
View 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

View 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
View 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;
}
}

View 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
View File

@@ -0,0 +1,12 @@
#include "osgUtil/Version"
const char* osgUtilGetVersion()
{
return "0.8.34";
}
const char* osgUtilGetLibraryName()
{
return "Open Scene Graph Utility Library";
}