I want to implement drag and drop zooming with the screen when I rewrite module osgManipulator.
* Base class for draggers. Concrete draggers implement the pick event handler
* command to all the DraggerCallbacks & Transforms that are connected to the Dragger that generates the
* commands.
* Set/Get parent dragger. For simple draggers parent points to itself.
* this dragger.
virtual void setParentDragger(Dragger* parent) { _parentDragger = parent; }
/** Returns 0 if this Dragger is not a CompositeDragger. */
/** Returns 0 if this Dragger is not a CompositeDragger. */
void setActivationModKeyMask(unsigned int mask) { _activationModKeyMask = mask; }
unsigned int getActivationModKeyMask() const { return _activationModKeyMask; }
void setActivationMouseButtonMask(unsigned int mask) { _activationMouseButtonMask = mask; }
unsigned int getActivationMouseButtonMask() const { return _activationMouseButtonMask; }
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
virtual bool handle(const PointerInfo&, const osgGA::GUIEventAdapter&, osgGA::GUIActionAdapter&) { return false; }
template<class T> void addConstraint(const osg::ref_ptr<T>& c) { addConstraint(c.get()); }
template<class T> void removeConstraint(const osg::ref_ptr<T>& c) { removeConstraint(c.get()); }
template<class T> void addDraggerCallback(const osg::ref_ptr<T>& dc) { addDraggerCallback(dc.get()); }
template<class T> void removeDraggerCallback(const osg::ref_ptr<T>& dc) { removeDraggerCallback(dc.get()); }
const DraggerCallbacks& getDraggerCallbacks() const { return _draggerCallbacks; }
void addTransformUpdating(MatrixTransform* transform, int handleCommandMask = DraggerTransformCallback::HANDLE_ALL);
/** Setup default geometry for dragger. */
* Set/Get the traversal mask used by this dragger when looking for intersections during event handling.
* This is useful to "hide" some geometry during event handling.
virtual void setIntersectionMask(osg::Node::NodeMask intersectionMask) { _intersectionMask = intersectionMask; }
osg::Node::NodeMask getIntersectionMask() const { return _intersectionMask; }
/** Return true if the axis of the Locator are inverted requiring the faces of any cubes used from rendering to be flipped to ensure the correct front/back face is used.*/
/** apply the appropriate FrontFace setting to provided StateSet to ensure that the rendering of hull of the volume is the correct orientation.*/
Dragger(const Dragger& rhs, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
---------------------------------------------------------------------------------------------
#include <osg/Material>
#include <osg/FrontFace>
#include <osgGA/EventVisitor>
#include <osgViewer/View>
#include <osg/io_utils>
#include "Dragger.h"
#include "Command.h"
using namespace osgManipulatorEx;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Dragger
//
Dragger::Dragger() :
_handleEvents(false),
_draggerActive(false),
_activationModKeyMask(0),
_activationMouseButtonMask(0),
_activationKeyEvent(0),
_activationPermittedByModKeyMask(false),
_activationPermittedByMouseButtonMask(false),
_activationPermittedByKeyEvent(false),
_parentDragger(0),
_intersectionMask(0xffffffff)
{
_parentDragger = this;
getOrCreateStateSet()->setDataVariance(osg::Object::DYNAMIC);
_selfUpdater = new DraggerTransformCallback(this);
//
setCullingActive(false);
}
Dragger::Dragger(const Dragger& rhs, const osg::CopyOp& copyop):
osg::MatrixTransform(rhs, copyop),
_handleEvents(rhs._handleEvents),
_draggerActive(false),
_activationModKeyMask(rhs._activationModKeyMask),
_activationMouseButtonMask(rhs._activationMouseButtonMask),
_activationKeyEvent(rhs._activationKeyEvent),
_activationPermittedByModKeyMask(false),
_activationPermittedByMouseButtonMask(false),
_activationPermittedByKeyEvent(false),
_parentDragger(0),
_intersectionMask(0xffffffff)
{
}
Dragger::~Dragger()
{
}
bool Dragger::inverted() const
{
osg::Vec3d xAxis(_matrix(0,0), _matrix(1,0), _matrix(2,0));
osg::Vec3d yAxis(_matrix(0,1), _matrix(1,1), _matrix(2,1));
osg::Vec3d zAxis(_matrix(0,2), _matrix(1,2), _matrix(2,2));
double volume = (xAxis^yAxis)*zAxis;
return volume<0.0;
}
void Dragger::applyAppropriateFrontFace(osg::StateSet* ss) const
{
osg::StateAttribute* sa = ss->getAttribute(osg::StateAttribute::FRONTFACE);
osg::FrontFace* ff = dynamic_cast<osg::FrontFace*>(sa);
if (!ff)
{
ff = new osg::FrontFace;
ss->setAttribute(ff);
}
ff->setMode( inverted() ? osg::FrontFace::CLOCKWISE : osg::FrontFace::COUNTER_CLOCKWISE);
}
void Dragger::setHandleEvents(bool flag)
{
if (_handleEvents == flag) return;
_handleEvents = flag;
// update the number of children that require an event traversal to make sure this dragger receives events.
if (_handleEvents) setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()+1);
else if (getNumChildrenRequiringEventTraversal()>=1) setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()-1);
}
void Dragger::addConstraint(Constraint* constraint)
{
// check to make sure constaint hasn't already been attached.
for(Constraints::iterator itr = _constraints.begin();
itr != _constraints.end();
++itr)
{
if (*itr == constraint) return;
}
_constraints.push_back(constraint);
}
void Dragger::removeConstraint(Constraint* constraint)
{
for(Constraints::iterator itr = _constraints.begin();
itr != _constraints.end();
)
{
if (*itr == constraint)
{
_constraints.erase(itr);
return;
} else
{
++itr;
}
}
}
void Dragger::addTransformUpdating(osg::MatrixTransform* transform, int handleCommandMask)
{
addDraggerCallback(new DraggerTransformCallback(transform, handleCommandMask));
}
void Dragger::removeTransformUpdating(osg::MatrixTransform* transform)
{
for(Dragger::DraggerCallbacks::iterator itr = _draggerCallbacks.begin();
itr != _draggerCallbacks.end();
)
{
DraggerCallback* dc = itr->get();
DraggerTransformCallback* dtc = dynamic_cast<DraggerTransformCallback*>(dc);
if (dtc && dtc->getTransform()==transform)
{
itr = _draggerCallbacks.erase(itr);
}
else
{
++itr;
}
}
}
void Dragger::addDraggerCallback(DraggerCallback* dc)
{
for(DraggerCallbacks::iterator itr = _draggerCallbacks.begin();
itr != _draggerCallbacks.end();
++itr)
{
if (*itr == dc) return;
}
_draggerCallbacks.push_back(dc);
}
void Dragger::removeDraggerCallback(DraggerCallback* dc)
{
for(Dragger::DraggerCallbacks::iterator itr = _draggerCallbacks.begin();
itr != _draggerCallbacks.end();
)
{
if (dc==itr->get())
{
itr = _draggerCallbacks.erase(itr);
}
else
{
++itr;
}
}
}
void Dragger::traverse(osg::NodeVisitor& nv)
{
if (_handleEvents && nv.getVisitorType()==osg::NodeVisitor::EVENT_VISITOR)
{
osgGA::EventVisitor* ev = nv.asEventVisitor();
if (ev)
{
for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin();
itr != ev->getEvents().end();
++itr)
{
osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter();
if (ea && handle(*ea, *(ev->getActionAdapter()))) ea->setHandled(true);
}
}
return;
}
MatrixTransform::traverse(nv);
}
bool Dragger::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getHandled()) return false;
osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
if (!view) return false;
bool handled = false;
bool activationPermitted = true;
if (_activationModKeyMask!=0 || _activationMouseButtonMask!=0 || _activationKeyEvent!=0)
{
_activationPermittedByModKeyMask = (_activationModKeyMask!=0) ?
((ea.getModKeyMask() & _activationModKeyMask)!=0) :
false;
_activationPermittedByMouseButtonMask = (_activationMouseButtonMask!=0) ?
((ea.getButtonMask() & _activationMouseButtonMask)!=0) :
false;
if (_activationKeyEvent!=0)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
if (ea.getKey()==_activationKeyEvent) _activationPermittedByKeyEvent = true;
break;
}
case osgGA::GUIEventAdapter::KEYUP:
{
if (ea.getKey()==_activationKeyEvent) _activationPermittedByKeyEvent = false;
break;
}
default:
break;
}
}
activationPermitted = _activationPermittedByModKeyMask || _activationPermittedByMouseButtonMask || _activationPermittedByKeyEvent;
}
if (activationPermitted || _draggerActive)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::PUSH:
{
osgUtil::LineSegmentIntersector::Intersections intersections;
_pointer.reset();
double mx = ea.getXnormalized();
double my = ea.getYnormalized();
// half width, height.
double w = 0.005;
double h = 0.005;
osg::ref_ptr<osgUtil::PolytopeIntersector> picker = new osgUtil::PolytopeIntersector(osgUtil::Intersector::PROJECTION, mx - w, my - h, mx + w, my + h);
picker->setPrecisionHint(osgUtil::Intersector::USE_DOUBLE_CALCULATIONS);
picker->setPrimitiveMask(osgUtil::PolytopeIntersector::LINE_PRIMITIVES);
picker->setIntersectionLimit(osgUtil::Intersector::NO_LIMIT);
//
osgUtil::IntersectionVisitor iv(picker.get());
view->getCamera()->accept(iv);
if (picker->containsIntersections())
{
bool isGet = false;
osgUtil::PolytopeIntersector::Intersections intersections = picker->getIntersections();
osgUtil::PolytopeIntersector::Intersections::iterator intersection = intersections.begin();
for (intersection; intersection != intersections.end(); intersection++)
{
osg::NodePath nodePath = intersection->nodePath;
for (int i = 0; i < nodePath.size(); i++)
{
osgManipulatorEx::Dragger* dragger = dynamic_cast<osgManipulatorEx::Dragger*>(nodePath[i]);
if (dragger)
{
_pointer.addIntersection(intersection->nodePath, intersection->localIntersectionPoint);
isGet = true;
break;
}
}
if (isGet)
{
break;
}
}
if (!_pointer._hitList.size())
break;
for (osg::NodePath::iterator itr = _pointer._hitList.front().first.begin();
itr != _pointer._hitList.front().first.end();
++itr)
{
osgManipulatorEx::Dragger* dragger = dynamic_cast<osgManipulatorEx::Dragger*>(*itr);
if (dragger)
{
if (dragger==this)
{
osg::Camera *rootCamera = view->getCamera();
osg::NodePath nodePath = _pointer._hitList.front().first;
osg::NodePath::iterator ritr;
for(ritr = nodePath.begin();
ritr != nodePath.end();
++ritr)
{
osg::Camera* camera = (*ritr)->asCamera();
if (camera && (camera->getReferenceFrame()!=osg::Transform::RELATIVE_RF || camera->getParents().empty()))
{
rootCamera = camera;
break;
}
}
_pointer.setCamera(rootCamera);
_pointer.setMousePosition(ea.getX(), ea.getY());
if(dragger->handle(_pointer, ea, aa))
{
dragger->setDraggerActive(true);
handled = true;
}
}
}
}
}
break;
}
case osgGA::GUIEventAdapter::DRAG:
case osgGA::GUIEventAdapter::RELEASE:
{
if (_draggerActive)
{
_pointer._hitIter = _pointer._hitList.begin();
// _pointer.setCamera(view->getCamera());
_pointer.setMousePosition(ea.getX(), ea.getY());
if(handle(_pointer, ea, aa))
{
handled = true;
}
}
break;
}
default:
break;
}
if (_draggerActive && ea.getEventType() == osgGA::GUIEventAdapter::RELEASE)
{
setDraggerActive(false);
_pointer.reset();
}
}
return handled;
}
bool Dragger::receive(const MotionCommand& command)
{
if (_selfUpdater.valid()) return _selfUpdater->receive(command);
else return false;
}
void Dragger::dispatch(MotionCommand& command)
{
// apply any constraints
for(Constraints::iterator itr = _constraints.begin();
itr != _constraints.end();
++itr)
{
command.accept(*(*itr));
}
// apply any constraints of parent dragger.
if (getParentDragger()!=this)
{
for(Constraints::iterator itr = getParentDragger()->getConstraints().begin();
itr != getParentDragger()->getConstraints().end();
++itr)
{
command.accept(*(*itr));
}
}
// move self
getParentDragger()->receive(command);
// pass on movement to any dragger callbacks
for(DraggerCallbacks::iterator itr = getParentDragger()->getDraggerCallbacks().begin();
itr != getParentDragger()->getDraggerCallbacks().end();
++itr)
{
command.accept(*(*itr));
}
}
bool Dragger::computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const
{
if (_referenceFrame == RELATIVE_RF)
{
matrix.preMult(computeMatrix(nv));
}
else // absolute
{
matrix = computeMatrix(nv);
}
return true;
}
bool Dragger::computeWorldToLocalMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const
{
if (_referenceFrame == RELATIVE_RF)
{
matrix.postMult(osg::Matrix::inverse(computeMatrix(nv)));
}
else // absolute
{
matrix = osg::Matrix::inverse(computeMatrix(nv));
}
return true;
}
osg::Matrixd Dragger::computeMatrix(const osg::NodeVisitor* nv) const
{
osg::Matrixd mt = getMatrix();
//
osg::Vec3d pos,scale;
osg::Quat q;
osg::Quat quat;
mt.decompose(pos, quat, scale, q);
//
const osg::CullStack* cs = nv ? nv->asCullStack() : 0;
if (cs)
{
osg::Vec3d eyePoint = cs->getEyeLocal();
osg::Vec3d localUp = cs->getUpLocal();
double size = 1.0 / cs->pixelSize(pos, 0.48f);
//
{
double j = 0.0;
double i = 0.0*(1.0 + 0.25);
double c = 1.0 / (4.0*(i - j));
double b = 1.0 - 2.0*c*i;
double a = j + b*b / (4.0*c);
double k = -b / (2.0*c);
if (size < k) size = 0.0;
else if (size < i) size = a + b*size + c*(size*size);
}
// TODO setScale(size);
scale.set(size, size, size);
}
//
osg::Matrixd matrix;
matrix.makeRotate(quat);
matrix.postMultTranslate(pos);
matrix.preMultScale(scale);
matrix.preMultTranslate(-osg::Vec3d(0,0,0));
return matrix;
}