Hi,

in osgManipulator, the current way of handling mouse movements is to do an 
intersection test at the mouse coordinates and check if the first intersection 
is a dragger. Only the first intersection is checked, all other are ignored. 

For my app, I disable depth tests for draggers so that they are always visible. 
 
I modified osgManipulator to iterate through ALL intersections until a dragger 
is found. When I look at the dragger.cpp code it seems that this was a planned 
behavior, but somehow got forgotten or thrown out for some reason.

Changes in dragger behavior after the patch: The osgManipulator example works 
as before, the only difference is that it is now possible to pick the 1d and 2d 
draggers through the geometry attached to them. While this is a change from 
before I think this is reasonable behavior.

Thank you!

Cheers,
Martin

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=44030#44030



/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
//osgManipulator - Copyright (C) 2007 Fugro-Jason B.V.

#include <osgManipulator/Dragger>
#include <osgManipulator/Command>
#include <osg/Material>
#include <osgGA/EventVisitor>
#include <osgViewer/View>

using namespace osgManipulator;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// computeNodePathToRoot
//
void osgManipulator::computeNodePathToRoot(osg::Node& node, osg::NodePath& np)
{
    np.clear();

    osg::NodePathList nodePaths = node.getParentalNodePaths();

    if (!nodePaths.empty())
    {
        np = nodePaths.front();
        if (nodePaths.size()>1)
        {
            OSG_NOTICE<<"osgManipulator::computeNodePathToRoot(,) taking first parent path, ignoring others."<<std::endl;
        }
    }
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// DraggerTransformCallback
//
DraggerTransformCallback::DraggerTransformCallback(osg::MatrixTransform* transform):
    _transform(transform)
{
}

bool DraggerTransformCallback::receive(const MotionCommand& command)
{
    if (!_transform) return false;

    switch (command.getStage())
    {
        case MotionCommand::START:
        {
            // Save the current matrix
            _startMotionMatrix = _transform->getMatrix();

            // Get the LocalToWorld and WorldToLocal matrix for this node.
            osg::NodePath nodePathToRoot;
            computeNodePathToRoot(*_transform,nodePathToRoot);
            _localToWorld = osg::computeLocalToWorld(nodePathToRoot);
            _worldToLocal = osg::Matrix::inverse(_localToWorld);

            return true;
        }
        case MotionCommand::MOVE:
        {
            // Transform the command's motion matrix into local motion matrix.
            osg::Matrix localMotionMatrix = _localToWorld * command.getWorldToLocal()
                                            * command.getMotionMatrix()
                                            * command.getLocalToWorld() * _worldToLocal;

            // Transform by the localMotionMatrix
            _transform->setMatrix(localMotionMatrix * _startMotionMatrix);

            return true;
        }
        case MotionCommand::FINISH:
        {
            return true;
        }
        case MotionCommand::NONE:
        default:
            return false;
    }
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PointerInfo
//
PointerInfo::PointerInfo():
    _nearPoint(osg::Vec3d()),
    _farPoint(osg::Vec3d()),
    _eyeDir(osg::Vec3d(0,0,1))
{
    _hitIter = _hitList.begin();
}

bool PointerInfo::contains(const osg::Node* node) const
{
    if (node && _hitIter!=_hitList.end()) return std::find((*_hitIter).first.begin(), (*_hitIter).first.end(), node) != (*_hitIter).first.end();
    else return false;
}

bool PointerInfo::projectWindowXYIntoObject(const osg::Vec2d& windowCoord, osg::Vec3d& nearPoint, osg::Vec3d& farPoint) const
{
    nearPoint = osg::Vec3d(windowCoord.x(),windowCoord.y(),0.0)*_inverseMVPW;
    farPoint = osg::Vec3d(windowCoord.x(),windowCoord.y(),1.0)*_inverseMVPW;

    return true;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Dragger
//
Dragger::Dragger() :
    _handleEvents(false),
    _draggerActive(false),
    _activationModKeyMask(0),
    _activationKeyEvent(0),
    _activationPermittedByModKeyMask(false),
    _activationPermittedByKeyEvent(false)
{
    _parentDragger = this;
    getOrCreateStateSet()->setDataVariance(osg::Object::DYNAMIC);

    _selfUpdater = new DraggerTransformCallback(this);

}

Dragger::Dragger(const Dragger& rhs, const osg::CopyOp& copyop):
    osg::MatrixTransform(rhs, copyop),
    _handleEvents(rhs._handleEvents),
    _draggerActive(false),
    _activationModKeyMask(rhs._activationModKeyMask),
    _activationKeyEvent(rhs._activationKeyEvent),
    _activationPermittedByModKeyMask(false),
    _activationPermittedByKeyEvent(false)
{
    OSG_NOTICE<<"CompositeDragger::CompositeDragger(const CompositeDragger& rhs, const osg::CopyOp& copyop) not Implemented yet."<<std::endl;
}

Dragger::~Dragger()
{
}

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 recieves 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)
{
    addDraggerCallback(new DraggerTransformCallback(transform));
}

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)
{
}


void Dragger::traverse(osg::NodeVisitor& nv)
{
    if (_handleEvents && nv.getVisitorType()==osg::NodeVisitor::EVENT_VISITOR)
    {
        osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(&nv);
        if (ev)
        {
            for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin();
                itr != ev->getEvents().end();
                ++itr)
            {
                osgGA::GUIEventAdapter* ea = itr->get();
                if (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 || _activationKeyEvent!=0)
    {
        _activationPermittedByModKeyMask = (_activationModKeyMask!=0) ?
            ((ea.getModKeyMask() & _activationModKeyMask)!=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 || _activationPermittedByKeyEvent;

    }

    if (activationPermitted || _draggerActive)
    {
        switch (ea.getEventType())
        {
            case osgGA::GUIEventAdapter::PUSH:
            {
                osgUtil::LineSegmentIntersector::Intersections intersections;

                _pointer.reset();

                if (view->computeIntersections(ea.getX(),ea.getY(),intersections))
                {
                    for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();
                        hitr != intersections.end();
                        ++hitr)
                    {
                        _pointer.addIntersection(hitr->nodePath, hitr->getLocalIntersectPoint());
                    }

                    while(!_pointer.completed())
                    {
                       osg::NodePath nodePath = _pointer.getNodePath();

                        for (osg::NodePath::iterator itr = nodePath.begin();
                                handled != true && itr != nodePath.end();
                                ++itr)
                        {
                           osgManipulator::Dragger* dragger = dynamic_cast<osgManipulator::Dragger*>(*itr);
                           if (dragger && dragger == this)
                           {

                                osg::Camera *rootCamera = view->getCamera();
                                osg::NodePath nodePath = _pointer._hitList.front().first;
                                osg::NodePath::reverse_iterator ritr;
                                for(ritr = nodePath.rbegin();
                                    ritr != nodePath.rend();
                                    ++ritr)
                                {
                                    osg::Camera* camera = dynamic_cast<osg::Camera*>(*ritr);
                                    if (camera && (camera->getReferenceFrame()!=osg::Transform::RELATIVE_RF || camera->getParents().empty()))
                                    {
                                         rootCamera = camera;
                                         break;
                                    }
                                }

                                _pointer.setCamera(rootCamera);
                                _pointer.setMousePosition(ea.getX(), ea.getY());

                                dragger->handle(_pointer, ea, aa);
                                dragger->setDraggerActive(true);
                                handled = true;

                           }
                        }
                        if(handled)
                        {
                           break;
                        }
                        _pointer.next();
                    }
                }
            }
            case osgGA::GUIEventAdapter::DRAG:
            case osgGA::GUIEventAdapter::RELEASE:
            {
                if (_draggerActive)
                {
                    _pointer.setMousePosition(ea.getX(), ea.getY());

                    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)
    {
        (*itr)->constrain(command);
    }

    // move self
    getParentDragger()->receive(command);


    for(DraggerCallbacks::iterator itr = getParentDragger()->getDraggerCallbacks().begin();
        itr != getParentDragger()->getDraggerCallbacks().end();
        ++itr)
    {
        (*itr)->receive(command);
    }
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// CompositeDragger
//
CompositeDragger::CompositeDragger(const CompositeDragger& rhs, const osg::CopyOp& copyop):
    Dragger(rhs, copyop)
{
    OSG_NOTICE<<"CompositeDragger::CompositeDragger(const CompositeDragger& rhs, const osg::CopyOp& copyop) not Implemented yet."<<std::endl;
}

bool CompositeDragger::handle(const PointerInfo& pi, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    // Check if the dragger node is in the nodepath.
    if (!pi.contains(this))
        return false;

    for (DraggerList::iterator itr=_draggerList.begin(); itr!=_draggerList.end(); ++itr)
    {
        if ((*itr)->handle(pi, ea, aa))
            return true;
    }
    return false;
}
bool CompositeDragger::containsDragger( const Dragger* dragger ) const
{
    for (DraggerList::const_iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr)
    {
        if (itr->get() == dragger) return true;
    }
    return false;
}

CompositeDragger::DraggerList::iterator CompositeDragger::findDragger( const Dragger* dragger )
{
    for (DraggerList::iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr)
    {
        if (itr->get() == dragger) return itr;
    }
    return _draggerList.end();
}

bool CompositeDragger::addDragger(Dragger *dragger)
{
    if (dragger && !containsDragger(dragger))
    {
        _draggerList.push_back(dragger);
        return true;
    }
    else return false;

}

bool CompositeDragger::removeDragger(Dragger *dragger)
{
    DraggerList::iterator itr = findDragger(dragger);
    if (itr != _draggerList.end())
    {
        _draggerList.erase(itr);
        return true;
    }
    else return false;

}

void CompositeDragger::setParentDragger(Dragger* dragger)
{
    for (DraggerList::iterator itr = _draggerList.begin(); itr != _draggerList.end(); ++itr)
    {
        (*itr)->setParentDragger(dragger);
    }
    Dragger::setParentDragger(dragger);
}

class ForceCullCallback : public osg::Drawable::CullCallback
{
    public:
        virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const
        {
            return true;
        }
};

void osgManipulator::setDrawableToAlwaysCull(osg::Drawable& drawable)
{
    ForceCullCallback* cullCB = new ForceCullCallback;
    drawable.setCullCallback (cullCB);    
}

void osgManipulator::setMaterialColor(const osg::Vec4& color, osg::Node& node)
{
    osg::Material* mat = dynamic_cast<osg::Material*>(node.getOrCreateStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
    if (! mat)
    {
        mat = new osg::Material;
        mat->setDataVariance(osg::Object::DYNAMIC);
        node.getOrCreateStateSet()->setAttribute(mat);
    }
    mat->setDiffuse(osg::Material::FRONT_AND_BACK, color);
}

Attachment: Dragger
Description: Binary data

_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to