Hi smas,

The same has happened to me. Scenario: CompositeViewer with 2 or more View. At 
least an GUIEventHandler on each of the View. Behavior:
- Every event but DRAG or RELEASE goes to the last View's Event Handler
- DRAG and RELEASE events go to the first View's Event Handler.

I think it's a bug, so I have overloaded CompositeViewer to receive every event 
in every View. Code (based on OSG 3.2.1rc3 and a little from SVN trunk):


Code:

#include <osgViewer/CompositeViewer>

namespace osgViewer
{

class CMyCompositeViewer : public CompositeViewer
{
public:
    CMyCompositeViewer();
    virtual ~CMyCompositeViewer();

    virtual void eventTraversal();

protected:
    void reprojectPointerData(osgGA::GUIEventAdapter& source_event, 
osgGA::GUIEventAdapter& dest_event);
};

}

using namespace osgViewer;

CMyCompositeViewer::CMyCompositeViewer()
{
}


CMyCompositeViewer::~CMyCompositeViewer()
{
}

void CMyCompositeViewer::reprojectPointerData(osgGA::GUIEventAdapter& 
source_event, osgGA::GUIEventAdapter& dest_event)
{
    osgViewer::GraphicsWindow* gw = 
dynamic_cast<osgViewer::GraphicsWindow*>(dest_event.getGraphicsContext());
    if (!gw) return;

    float x = dest_event.getX();
    float y = dest_event.getY();

    bool invert_y = 
dest_event.getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS;
    if (invert_y && gw->getTraits()) y = gw->getTraits()->height - y;

    dest_event.addPointerData(new osgGA::PointerData(gw, x, 0, 
gw->getTraits()->width,
                                                         y, 0, 
gw->getTraits()->height));

    for (unsigned int iCam = 1U; iCam < source_event.getNumPointerData(); 
iCam++)
    {
        osg::Camera* camera = 
dynamic_cast<osg::Camera*>(source_event.getPointerData(iCam)->object.get());
        osg::Viewport* viewport = camera ? camera->getViewport() : 0;

        if (!viewport) continue;

        dest_event.addPointerData(new osgGA::PointerData(camera, 
(x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0,
                                                                 
(y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0));

        osgViewer::View* view = 
dynamic_cast<osgViewer::View*>(camera->getView());
        osg::Camera* view_masterCamera = view ? view->getCamera() : 0;

        // if camera isn't the master it must be a slave and could need 
reprojecting.
        if (view && camera!=view_masterCamera)
        {
            generateSlavePointerData(camera, dest_event);
        }
    }
}

struct SortEvents
{
    bool operator() (const osg::ref_ptr<osgGA::GUIEventAdapter>& lhs,const 
osg::ref_ptr<osgGA::GUIEventAdapter>& rhs) const
    {
        return lhs->getTime() < rhs->getTime();
    }
};

void CMyCompositeViewer::eventTraversal()
{
    if (_done) return;

    if (_views.empty()) return;

    double cutOffTime = _frameStamp->getReferenceTime();

    double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, 
osg::Timer::instance()->tick());

    // need to copy events from the GraphicsWindow's into local EventQueue for 
each view;
    typedef std::map<osgViewer::View*, osgGA::EventQueue::Events> ViewEventsMap;
    ViewEventsMap viewEventsMap;

    Contexts contexts;
    getContexts(contexts);

    // set done if there are no windows
    checkWindowStatus(contexts);
    if (_done) return;

    osgGA::EventQueue::Events all_events;

    for(Contexts::iterator citr = contexts.begin();
        citr != contexts.end();
        ++citr)
    {
        osgViewer::GraphicsWindow* gw = 
dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
        if (gw)
        {
            gw->checkEvents();

            osgGA::EventQueue::Events gw_events;
            gw->getEventQueue()->takeEvents(gw_events, cutOffTime);

            for(osgGA::EventQueue::Events::iterator itr = gw_events.begin();
                itr != gw_events.end();
                ++itr)
            {
                (*itr)->setGraphicsContext(gw);
            }

            all_events.insert(all_events.end(), gw_events.begin(), 
gw_events.end());
        }
    }

    // sort all the events in time order so we can make sure we pass them all 
on in the correct order.
    all_events.sort(SortEvents());

    // pass on pointer data onto non mouse events to keep the position data 
usable by all recipients of all events.
    for(osgGA::EventQueue::Events::iterator itr = all_events.begin();
        itr != all_events.end();
        ++itr)
    {
        osgGA::GUIEventAdapter* event = itr->get();

        switch(event->getEventType())
        {
            case(osgGA::GUIEventAdapter::PUSH):
            case(osgGA::GUIEventAdapter::RELEASE):
            case(osgGA::GUIEventAdapter::DOUBLECLICK):
            case(osgGA::GUIEventAdapter::MOVE):
            case(osgGA::GUIEventAdapter::DRAG):
            {
                if ((event->getEventType()!=osgGA::GUIEventAdapter::DRAG && 
event->getEventType()!=osgGA::GUIEventAdapter::RELEASE) ||
                    !_previousEvent ||
                    
_previousEvent->getGraphicsContext()!=event->getGraphicsContext() ||
                    _previousEvent->getNumPointerData()<2)
                {
                    generatePointerData(*event);
                }
                else
                {
                    reprojectPointerData(*_previousEvent, *event);
                }

#if 0
                // assign topmost PointeData settings as the events X,Y and 
InputRange
                osgGA::PointerData* pd = 
event->getPointerData(event->getNumPointerData()-1);
                event->setX(pd->x);
                event->setY(pd->y);
                event->setInputRange(pd->xMin, pd->yMin, pd->xMax, pd->yMax);
                
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
#else
                if 
(event->getMouseYOrientation()!=osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
                {
                    
event->setY((event->getYmax()-event->getY())+event->getYmin());
                    
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
                }
#endif

                _previousEvent = event;

                break;
            }
            default:
                if (_previousEvent.valid()) 
event->copyPointerDataFrom(*_previousEvent);
                break;
        }

                unsigned int iPointerData = event->getNumPointerData() > 1 ? 1 
: 0;
                do
                {
                        osgGA::PointerData* pd = event->getNumPointerData()>0 ? 
event->getPointerData(iPointerData) : 0;
                        osg::Camera* camera = pd ? 
dynamic_cast<osg::Camera*>(pd->object.get()) : 0;
                        osgViewer::View* view = camera ? 
dynamic_cast<osgViewer::View*>(camera->getView()) : 0;

                        if (!view)
                        {
                                if (_viewWithFocus.valid())
                                {
                                        // OSG_NOTICE<<"Falling back to using 
_viewWithFocus"<<std::endl;
                                        view = _viewWithFocus.get();
                                }
                                else if (!_views.empty())
                                {
                                        // OSG_NOTICE<<"Falling back to using 
first view as one with focus"<<std::endl;
                                        view = _views[0].get();
                                }
                        }

                        // reassign view with focus
                        if (_viewWithFocus != view)  _viewWithFocus = view;

                        if (view)
                        {
                                viewEventsMap[view].push_back( event );

                                osgGA::GUIEventAdapter* eventState = 
view->getEventQueue()->getCurrentEventState();
                                eventState->copyPointerDataFrom(*event);
                        }

                        ++iPointerData;
                } while ( iPointerData < event->getNumPointerData() );

        _previousEvent = event;
    }

    // handle any close windows
    for(osgGA::EventQueue::Events::iterator itr = all_events.begin();
        itr != all_events.end();
        ++itr)
    {
        osgGA::GUIEventAdapter* event = itr->get();
        switch(event->getEventType())
        {
            case(osgGA::GUIEventAdapter::CLOSE_WINDOW):
            {
                bool wasThreading = areThreadsRunning();
                if (wasThreading) stopThreading();

                if (event->getGraphicsContext())
                {
                    event->getGraphicsContext()->close();
                }

                if (wasThreading) startThreading();

                break;
            }
            default:
                break;
        }
    }


    for(RefViews::iterator vitr = _views.begin();
        vitr != _views.end();
        ++vitr)
    {
        View* view = vitr->get();

        // get events from user Devices attached to Viewer.
        for(osgViewer::View::Devices::iterator eitr = 
view->getDevices().begin();
            eitr != view->getDevices().end();
            ++eitr)
        {
            osgGA::Device* es = eitr->get();
            if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS)
                es->checkEvents();

            // open question, will we need to reproject mouse coordinates into 
current view's coordinate frame as is down for GraphicsWindow provided events?
            // for now assume now and just get the events directly without any 
reprojection.
            es->getEventQueue()->takeEvents(viewEventsMap[view], cutOffTime);
        }

        // generate frame event
        view->getEventQueue()->frame( getFrameStamp()->getReferenceTime() );

        view->getEventQueue()->takeEvents(viewEventsMap[view], cutOffTime);
    }

    if ((_keyEventSetsDone!=0) || _quitEventSetsDone)
    {
        for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
            veitr != viewEventsMap.end();
            ++veitr)
        {
            for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
                itr != veitr->second.end();
                ++itr)
            {
                osgGA::GUIEventAdapter* event = itr->get();
                // ignore event if it's already been handled.
                if (event->getHandled()) continue;

                switch(event->getEventType())
                {
                    case(osgGA::GUIEventAdapter::KEYUP):
                        if (_keyEventSetsDone && 
event->getKey()==_keyEventSetsDone) _done = true;
                        break;

                    case(osgGA::GUIEventAdapter::QUIT_APPLICATION):
                        if (_quitEventSetsDone) _done = true;
                        break;

                    default:
                        break;
                }
            }
        }
    }

    if (_done) return;

    if (_eventVisitor.valid())
    {
        _eventVisitor->setFrameStamp(getFrameStamp());
        _eventVisitor->setTraversalNumber(getFrameStamp()->getFrameNumber());

        for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
            veitr != viewEventsMap.end();
            ++veitr)
        {
            View* view = veitr->first;
            _eventVisitor->setActionAdapter(view);

            if (view && view->getSceneData())
            {
                for(osgGA::EventQueue::Events::iterator itr = 
veitr->second.begin();
                    itr != veitr->second.end();
                    ++itr)
                {
                    osgGA::GUIEventAdapter* event = itr->get();

                    _eventVisitor->reset();
                    _eventVisitor->addEvent( event );

                    view->getSceneData()->accept(*_eventVisitor);

                    // Do EventTraversal for slaves with their own subgraph
                    for(unsigned int i=0; i<view->getNumSlaves(); ++i)
                    {
                        osg::View::Slave& slave = view->getSlave(i);
                        osg::Camera* camera = slave._camera.get();
                        if(camera && !slave._useMastersSceneData)
                        {
                            camera->accept(*_eventVisitor);
                        }
                    }

                    // call any camera event callbacks, but only traverse that 
callback, don't traverse its subgraph
                    // leave that to the scene update traversal.
                    osg::NodeVisitor::TraversalMode tm = 
_eventVisitor->getTraversalMode();
                    
_eventVisitor->setTraversalMode(osg::NodeVisitor::TRAVERSE_NONE);

                    if (view->getCamera() && 
view->getCamera()->getEventCallback()) 
view->getCamera()->accept(*_eventVisitor);

                    for(unsigned int i=0; i<view->getNumSlaves(); ++i)
                    {
                        osg::View::Slave& slave = view->getSlave(i);
                        osg::Camera* camera = view->getSlave(i)._camera.get();
                        if (camera && slave._useMastersSceneData && 
camera->getEventCallback())
                        {
                            camera->accept(*_eventVisitor);
                        }
                    }

                    _eventVisitor->setTraversalMode(tm);

                }
            }
        }

    }

    for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
        veitr != viewEventsMap.end();
        ++veitr)
    {
        View* view = veitr->first;
        _eventVisitor->setActionAdapter(view);

        for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
            itr != veitr->second.end();
            ++itr)
        {
            osgGA::GUIEventAdapter* event = itr->get();

            for(View::EventHandlers::iterator hitr = 
view->getEventHandlers().begin();
                hitr != view->getEventHandlers().end();
                ++hitr)
            {
                (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, 
*view, 0, _eventVisitor.get());
            }
        }
    }

    for(ViewEventsMap::iterator veitr = viewEventsMap.begin();
        veitr != viewEventsMap.end();
        ++veitr)
    {
        View* view = veitr->first;
        _eventVisitor->setActionAdapter(view);

        for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin();
            itr != veitr->second.end();
            ++itr)
        {
            osgGA::GUIEventAdapter* event = itr->get();

            if (view->getCameraManipulator())
            {
                
view->getCameraManipulator()->handleWithCheckAgainstIgnoreHandledEventsMask( 
*event, *view);
            }
        }
    }

    if (getViewerStats() && getViewerStats()->collectStats("event"))
    {
        double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, 
osg::Timer::instance()->tick());

        // update current frames stats
        getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event 
traversal begin time", beginEventTraversal);
        getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event 
traversal end time", endEventTraversal);
        getViewerStats()->setAttribute(_frameStamp->getFrameNumber(), "Event 
traversal time taken", endEventTraversal-beginEventTraversal);
    }
}





If someone else thinks it's a bug, I will submit the changes to fix 
CompositeViewer itself.

Cheers,
Ignacio

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





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

Reply via email to