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