From Stephan Huber, "attached are some fixes to the osc-plugin and the touch-implementations for iOS and os x and other small bugfixes. These fixes will normalize the orientation of the touch points, and transmitting the touch points over osc via the TUIO-protocol works now more robustly between two osg-applications.

I added a new tag to p3d called forward_touch_event_to_device and renamed the existing forward_event_to_device to forward_mouse_event_to_device. This new tag will transmit touches to the virtual trackpad as touch events. I added the MultitouchTrackball to the p3d-app so zooming and moving a model remotely should now work, if you use forward_touch_event_to_device. I kept (and fixed) forward_mouse_event_to_device for background compatibility, so old presentations works as in previous versions, without the ability to zoom + scale. of course.

forward_touch_event_to_device needs some more testing, (e.g. with image-streams and keystone, afaik there’s no support for touch-events...) but for a first version it works nice.
"
This commit is contained in:
Robert Osfield 2014-01-23 15:37:48 +00:00
parent 09c09628ac
commit a96ad565c7
15 changed files with 368 additions and 145 deletions

View File

@ -36,6 +36,7 @@
#include <osgGA/TerrainManipulator> #include <osgGA/TerrainManipulator>
#include <osgGA/AnimationPathManipulator> #include <osgGA/AnimationPathManipulator>
#include <osgGA/StateSetManipulator> #include <osgGA/StateSetManipulator>
#include <osgGA/MultiTouchTrackballManipulator>
#include <osgPresentation/deprecated/SlideEventHandler> #include <osgPresentation/deprecated/SlideEventHandler>
#include <osgPresentation/Cursor> #include <osgPresentation/Cursor>
@ -50,6 +51,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <string.h> #include <string.h>
#ifdef USE_SDL #ifdef USE_SDL
@ -174,6 +176,58 @@ private:
}; };
class DumpEventHandler : public osgGA::GUIEventHandler {
public:
DumpEventHandler() : osgGA::GUIEventHandler() {}
virtual bool handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::FRAME:
return false;
break;
case osgGA::GUIEventAdapter::PUSH:
std::cout << "PUSH: ";
break;
case osgGA::GUIEventAdapter::RELEASE:
std::cout << "RELEASE: ";
break;
case osgGA::GUIEventAdapter::MOVE:
std::cout << "MOVE: ";
break;
case osgGA::GUIEventAdapter::DRAG:
std::cout << "DRAG: ";
break;
case osgGA::GUIEventAdapter::SCROLL:
std::cout << "SCROLL: ";
break;
break;
default:
std::cout << ea.getEventType() << " ";
break;
}
std::cout << ea.getX() << "/" << ea.getY() << " " << ea.isMultiTouchEvent() << std::endl;
return false;
}
bool handle(osgGA::Event* event, osg::Object* object, osg::NodeVisitor* nv)
{
if (event->asGUIEventAdapter())
return osgGA::GUIEventHandler::handle(event, object, nv);
else
{
return false;
}
}
private:
};
enum P3DApplicationType enum P3DApplicationType
{ {
@ -423,7 +477,7 @@ int main( int argc, char **argv )
{ {
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator; osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() ); keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::MultiTouchTrackballManipulator() );
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() ); keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() ); keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() ); keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
@ -445,6 +499,8 @@ int main( int argc, char **argv )
viewer.setCameraManipulator( keyswitchManipulator.get() ); viewer.setCameraManipulator( keyswitchManipulator.get() );
} }
//viewer.getEventHandlers().push_front(new DumpEventHandler());
// add the state manipulator // add the state manipulator
osg::ref_ptr<osgGA::StateSetManipulator> ssManipulator = new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()); osg::ref_ptr<osgGA::StateSetManipulator> ssManipulator = new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet());
ssManipulator->setKeyEventToggleTexturing('e'); ssManipulator->setKeyEventToggleTexturing('e');

View File

@ -13,6 +13,22 @@
#include <osgViewer/api/IOS/GraphicsWindowIOS> #include <osgViewer/api/IOS/GraphicsWindowIOS>
@interface MyViewController : UIViewController
- (BOOL)shouldAutorotate;
@end
@implementation MyViewController
- (BOOL)shouldAutorotate
{
return YES;
}
@end
@implementation iphoneViewerAppDelegate @implementation iphoneViewerAppDelegate
@synthesize _window; @synthesize _window;
@ -148,7 +164,11 @@ private:
for(osgGA::GUIEventAdapter::TouchData::iterator i = ea.getTouchData()->begin(); i != ea.getTouchData()->end(); ++i, ++j) for(osgGA::GUIEventAdapter::TouchData::iterator i = ea.getTouchData()->begin(); i != ea.getTouchData()->end(); ++i, ++j)
{ {
const osgGA::GUIEventAdapter::TouchData::TouchPoint& tp = (*i); const osgGA::GUIEventAdapter::TouchData::TouchPoint& tp = (*i);
_mats[j]->setMatrix(osg::Matrix::translate(tp.x, ea.getWindowHeight() - tp.y, 0)); if (ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
_mats[j]->setMatrix(osg::Matrix::translate(tp.x, ea.getWindowHeight() - tp.y, 0));
else
_mats[j]->setMatrix(osg::Matrix::translate(tp.x, tp.y, 0));
_mats[j]->setNodeMask(0xffff); _mats[j]->setNodeMask(0xffff);
std::ostringstream ss; std::ostringstream ss;
@ -227,55 +247,62 @@ private:
//get the screen size //get the screen size
CGRect lFrame = [[UIScreen mainScreen] bounds]; CGRect lFrame = [[UIScreen mainScreen] bounds];
unsigned int w = lFrame.size.width; unsigned int w = lFrame.size.width * [[UIScreen mainScreen] scale];
unsigned int h = lFrame.size.height; unsigned int h = lFrame.size.height * [[UIScreen mainScreen] scale];
//create the viewer //create the viewer
_viewer = new osgViewer::Viewer(); _viewer = new osgViewer::Viewer();
/* if(1) {
// If you want full control over the graphics context / window creation, please uncomment this section // If you want full control over the graphics context / window creation, please uncomment this section
// create the main window at screen size // create the main window at screen size
self._window = [[UIWindow alloc] initWithFrame: lFrame]; self._window = [[UIWindow alloc] initWithFrame: lFrame];
//show window //show window
[_window makeKeyAndVisible]; [_window makeKeyAndVisible];
UIView* parent_view = [[UIView alloc] initWithFrame: CGRectMake(0,0, w, h)];
parent_view.backgroundColor = [UIColor redColor];
[self._window addSubview: parent_view];
MyViewController* view_controller = [[MyViewController alloc] init];
view_controller.view = parent_view;
self._window.rootViewController = view_controller;
//create our graphics context directly so we can pass our own window //create our graphics context directly so we can pass our own window
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
// Init the Windata Variable that holds the handle for the Window to display OSG in. // Init the Windata Variable that holds the handle for the Window to display OSG in.
osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowIOS::WindowData(_window); osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowIOS::WindowData(parent_view);
// Setup the traits parameters // Setup the traits parameters
traits->x = 0; traits->x = 50;
traits->y = 0; traits->y = 50;
traits->width = w; traits->width = w-100;
traits->height = h; traits->height = h-100;
traits->depth = 16; //keep memory down, default is currently 24 traits->depth = 16; //keep memory down, default is currently 24
traits->windowDecoration = false; traits->windowDecoration = false;
traits->doubleBuffer = true; traits->doubleBuffer = true;
traits->sharedContext = 0; traits->sharedContext = 0;
traits->setInheritedWindowPixelFormat = true; traits->setInheritedWindowPixelFormat = true;
traits->samples = 4; traits->samples = 4;
traits->sampleBuffers = 1; traits->sampleBuffers = 1;
traits->inheritedWindowData = windata; traits->inheritedWindowData = windata;
// Create the Graphics Context // Create the Graphics Context
osg::ref_ptr<osg::GraphicsContext> graphicsContext = osg::GraphicsContext::createGraphicsContext(traits.get()); osg::ref_ptr<osg::GraphicsContext> graphicsContext = osg::GraphicsContext::createGraphicsContext(traits.get());
// if the context was created then attach to our viewer // if the context was created then attach to our viewer
if(graphicsContext) if(graphicsContext)
{ {
_viewer->getCamera()->setGraphicsContext(graphicsContext); _viewer->getCamera()->setGraphicsContext(graphicsContext);
_viewer->getCamera()->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); _viewer->getCamera()->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
}
} }
*/
//create root //create root

View File

@ -675,6 +675,7 @@ public:
void addTouchPoint(unsigned int id, TouchPhase phase, float x, float y, unsigned int tapCount = 0); void addTouchPoint(unsigned int id, TouchPhase phase, float x, float y, unsigned int tapCount = 0);
void setTouchData(TouchData* td) { _touchData = td; }
TouchData* getTouchData() const { return _touchData.get(); } TouchData* getTouchData() const { return _touchData.get(); }
bool isMultiTouchEvent() const { return (_touchData.valid()); } bool isMultiTouchEvent() const { return (_touchData.valid()); }

View File

@ -37,7 +37,8 @@ enum Operation
LOAD, LOAD,
EVENT, EVENT,
JUMP, JUMP,
FORWARD_EVENT FORWARD_MOUSE_EVENT,
FORWARD_TOUCH_EVENT
}; };
struct JumpData struct JumpData

View File

@ -67,8 +67,11 @@ GUIEventAdapter::GUIEventAdapter(const GUIEventAdapter& rhs,const osg::CopyOp& c
_mouseYOrientation(rhs._mouseYOrientation), _mouseYOrientation(rhs._mouseYOrientation),
_scrolling(rhs._scrolling), _scrolling(rhs._scrolling),
_tabletPen(rhs._tabletPen), _tabletPen(rhs._tabletPen),
_touchData(rhs._touchData) _touchData(NULL)
{} {
if(TouchData* td = rhs.getTouchData())
setTouchData(osg::clone(td, copyop));
}
GUIEventAdapter::~GUIEventAdapter() GUIEventAdapter::~GUIEventAdapter()
{ {

View File

@ -715,13 +715,13 @@ class TUIO2DCursorRequestHandler : public OscReceivingDevice::RequestHandler {
public: public:
struct Cursor { struct Cursor {
std::string source; std::string end_point;
unsigned int id, frameId; unsigned int id, frameId;
osg::Vec2f pos, vel; osg::Vec2f pos, vel;
float accel; float accel;
osgGA::GUIEventAdapter::TouchPhase phase; osgGA::GUIEventAdapter::TouchPhase phase;
Cursor() : source(), id(0), frameId(0), pos(), vel(), accel(), phase(osgGA::GUIEventAdapter::TOUCH_UNKNOWN) {} Cursor() : end_point(), id(0), frameId(0), pos(), vel(), accel(), phase(osgGA::GUIEventAdapter::TOUCH_UNKNOWN) {}
}; };
struct EndpointData { struct EndpointData {
@ -764,9 +764,12 @@ public:
if (what == "source") if (what == "source")
{ {
args >> str; args >> str;
_endpointData[end_point].source = std::string(str); _endpointData[end_point].source = std::string(str);
updateSourceIdMap(_endpointData[end_point].source); updateSourceIdMap(_endpointData[end_point].source);
_endpointData[end_point].unhandled.clear();
_endpointData[end_point].mayClearUnhandledPointer = true;
return true; return true;
} }
@ -786,10 +789,8 @@ public:
{ {
osc::int32 id; osc::int32 id;
args >> id; args >> id;
_endpointData[source].unhandled.insert(id); _endpointData[end_point].unhandled.insert(id);
} }
_endpointData[source].mayClearUnhandledPointer = true;
return true; return true;
} }
else if (what == "set") else if (what == "set")
@ -803,9 +804,9 @@ public:
Cursor& c(_alive[source][id]); Cursor& c(_alive[source][id]);
args >> c.pos.x() >> c.pos.y() >> c.vel.x() >> c.vel.y() >> c.accel >> osc::EndMessage; args >> c.pos.x() >> c.pos.y() >> c.vel.x() >> c.vel.y() >> c.accel >> osc::EndMessage;
c.source = source;
c.frameId = frame_id; c.frameId = frame_id;
_endpointData[source].unhandled.insert(id); c.end_point = end_point;
_endpointData[end_point].unhandled.insert(id);
return true; return true;
} }
@ -840,51 +841,50 @@ public:
// remove all touchpoints which are not transmitted via alive-message, dispatching TOUCH_ENDED // remove all touchpoints which are not transmitted via alive-message, dispatching TOUCH_ENDED
EndpointData& endpoint_data(_endpointData[source]); unsigned int source_id = getSourceId(source);
if (endpoint_data.mayClearUnhandledPointer)
std::vector<unsigned int> to_delete;
for(CursorMap::iterator k = i->second.begin(); k != i->second.end(); ++k)
{ {
unsigned int source_id = getSourceId(source); EndpointData& endpoint_data(_endpointData[k->second.end_point]);
/*if (!endpoint_data.mayClearUnhandledPointer)
std::vector<unsigned int> to_delete;
for(CursorMap::iterator k = i->second.begin(); k != i->second.end(); ++k)
{ {
//create a unique touchpoint-id continue;
unsigned int touch_id = (source_id << 16) + k->first; }*/
std::set<unsigned int>& unhandled(endpoint_data.unhandled); //create a unique touchpoint-id
if ((unhandled.find(k->first) == unhandled.end())) unsigned int touch_id = (source_id << 16) + k->first;
{
std::cout << "deleting: " << k->first << std::endl;
to_delete.push_back(k->first);
float win_x = k->second.pos.x(); std::set<unsigned int>& unhandled(endpoint_data.unhandled);
float win_y = k->second.pos.y(); if ((unhandled.find(k->first) == unhandled.end()))
if (!event)
event = queue->touchEnded(touch_id, osgGA::GUIEventAdapter::TOUCH_ENDED, win_x, win_y, 1);
else
event->addTouchPoint(touch_id, osgGA::GUIEventAdapter::TOUCH_ENDED, win_x, win_y, 1);
}
}
// remove "dead" cursors
for(std::vector<unsigned int>::iterator k = to_delete.begin(); k != to_delete.end(); ++k)
{ {
_alive[source].erase(i->second.find(*k)); // std::cout << "deleting: " << k->first << " from " << k->second.end_point << std::endl;
} to_delete.push_back(k->first);
endpoint_data.mayClearUnhandledPointer = false; float win_x = k->second.pos.x();
endpoint_data.unhandled.clear(); float win_y = k->second.pos.y();
if (!event)
event = queue->touchEnded(touch_id, osgGA::GUIEventAdapter::TOUCH_ENDED, win_x, win_y, 1);
else
event->addTouchPoint(touch_id, osgGA::GUIEventAdapter::TOUCH_ENDED, win_x, win_y, 1);
}
}
// remove "dead" cursors
for(std::vector<unsigned int>::iterator k = to_delete.begin(); k != to_delete.end(); ++k)
{
_alive[source].erase(i->second.find(*k));
} }
if (i->second.size() == 0) if (i->second.size() == 0)
{ {
// std::cout << "removing endpoint" << source << std::endl; // std::cout << "removing endpoint" << source << std::endl;
_endpointData.erase(_endpointData.find(source)); // _alive.erase(_alive.find(source));
_alive.erase(_alive.find(source));
} }
} }
// send all alive touchpoints // send all alive touchpoints
for(ApplicationCursorMap::iterator i = _alive.begin(); i != _alive.end(); ++i) for(ApplicationCursorMap::iterator i = _alive.begin(); i != _alive.end(); ++i)
{ {
@ -912,6 +912,7 @@ public:
{ {
event->addTouchPoint(touch_id, down ? osgGA::GUIEventAdapter::TOUCH_BEGAN : osgGA::GUIEventAdapter::TOUCH_MOVED, win_x, win_y); event->addTouchPoint(touch_id, down ? osgGA::GUIEventAdapter::TOUCH_BEGAN : osgGA::GUIEventAdapter::TOUCH_MOVED, win_x, win_y);
} }
c.phase = osgGA::GUIEventAdapter::TOUCH_MOVED; c.phase = osgGA::GUIEventAdapter::TOUCH_MOVED;
} }
} }
@ -921,6 +922,7 @@ public:
{ {
event->setInputRange(0, 0, 1.0, 1.0); event->setInputRange(0, 0, 1.0, 1.0);
event->setTime(queue->getTime()); event->setTime(queue->getTime());
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
} }
} }
@ -997,6 +999,9 @@ OscReceivingDevice::OscReceivingDevice(const std::string& server_address, int li
addRequestHandler(new OscDevice::StandardRequestHandler("/osg/set_user_value", true)); addRequestHandler(new OscDevice::StandardRequestHandler("/osg/set_user_value", true));
addRequestHandler(new OscDevice::StandardRequestHandler("", false)); addRequestHandler(new OscDevice::StandardRequestHandler("", false));
// getEventQueue()->setFirstTouchEmulatesMouse(false);
setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW); setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW);
start(); start();
} }

View File

@ -31,12 +31,10 @@ OscSendingDevice::OscSendingDevice(const std::string& address, int port, unsigne
, _delayBetweenSendsInMilliSecs( (_numMessagesPerEvent > 1) ? delay_between_sends_in_millisecs : 0) , _delayBetweenSendsInMilliSecs( (_numMessagesPerEvent > 1) ? delay_between_sends_in_millisecs : 0)
, _msgId(0) , _msgId(0)
, _lastEvent(NULL) , _lastEvent(NULL)
, _finishMultiTouchSequence(false)
{ {
setCapabilities(SEND_EVENTS); setCapabilities(SEND_EVENTS);
OSG_NOTICE << "OscDevice :: sending events to " << address << ":" << port << " "; OSG_NOTICE << "OscDevice :: sending events to " << address << ":" << port << " ";
#ifdef OSC_HOST_LITTLE_ENDIAN #ifdef OSC_HOST_LITTLE_ENDIAN
OSG_NOTICE << "(little endian)"; OSG_NOTICE << "(little endian)";
@ -164,23 +162,24 @@ bool OscSendingDevice::sendUIEventImpl(const osgGA::GUIEventAdapter &ea, MsgIdTy
case osgGA::GUIEventAdapter::PUSH: case osgGA::GUIEventAdapter::PUSH:
beginSendInputRange(ea, msg_id); beginSendInputRange(ea, msg_id);
sendMultiTouchData(ea); if (!sendMultiTouchData(ea))
_oscStream << osc::BeginMessage("/osgga/mouse/press") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage; _oscStream << osc::BeginMessage("/osgga/mouse/press") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
_oscStream << osc::EndBundle; _oscStream << osc::EndBundle;
do_send = true; do_send = true;
break; break;
case osgGA::GUIEventAdapter::RELEASE: case osgGA::GUIEventAdapter::RELEASE:
beginSendInputRange(ea, msg_id); beginSendInputRange(ea, msg_id);
sendMultiTouchData(ea); if (!sendMultiTouchData(ea))
_oscStream << osc::BeginMessage("/osgga/mouse/release") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage; _oscStream << osc::BeginMessage("/osgga/mouse/release") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
_oscStream << osc::EndBundle; _oscStream << osc::EndBundle;
do_send = true; do_send = true;
break; break;
case osgGA::GUIEventAdapter::DOUBLECLICK: case osgGA::GUIEventAdapter::DOUBLECLICK:
beginSendInputRange(ea, msg_id); beginSendInputRange(ea, msg_id);
_oscStream << osc::BeginMessage("/osgga/mouse/doublepress") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage; if (!sendMultiTouchData(ea))
_oscStream << osc::BeginMessage("/osgga/mouse/doublepress") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
_oscStream << osc::EndBundle; _oscStream << osc::EndBundle;
do_send = true; do_send = true;
break; break;
@ -188,8 +187,8 @@ bool OscSendingDevice::sendUIEventImpl(const osgGA::GUIEventAdapter &ea, MsgIdTy
case osgGA::GUIEventAdapter::MOVE: case osgGA::GUIEventAdapter::MOVE:
case osgGA::GUIEventAdapter::DRAG: case osgGA::GUIEventAdapter::DRAG:
beginSendInputRange(ea, msg_id); beginSendInputRange(ea, msg_id);
sendMultiTouchData(ea); if (!sendMultiTouchData(ea))
_oscStream << osc::BeginMessage("/osgga/mouse/motion") << ea.getX() << ea.getY() << osc::EndMessage; _oscStream << osc::BeginMessage("/osgga/mouse/motion") << ea.getX() << ea.getY() << osc::EndMessage;
_oscStream << osc::EndBundle; _oscStream << osc::EndBundle;
do_send = true; do_send = true;
break; break;
@ -227,10 +226,21 @@ bool OscSendingDevice::sendUIEventImpl(const osgGA::GUIEventAdapter &ea, MsgIdTy
if (do_send) if (do_send)
{ {
OSG_INFO << "OscDevice :: sending ui-event per OSC " << std::endl; // OSG_INFO << "OscDevice :: sending ui-event per OSC " << std::endl;
_transmitSocket.Send( _oscStream.Data(), _oscStream.Size() ); _transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
_oscStream.Clear(); _oscStream.Clear();
if (_finishMultiTouchSequence)
{
// if the last touch-point ended we'll need to send an empty tuio-bundle, so the receiver gets a chance to clean up
beginBundle(msg_id);
beginMultiTouchSequence();
_oscStream << osc::EndBundle;
_transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
_oscStream.Clear();
_finishMultiTouchSequence = false;
}
} }
return do_send; return do_send;
@ -273,11 +283,7 @@ void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea, Msg
} }
void OscSendingDevice::beginMultiTouchSequence() {
void OscSendingDevice::sendMultiTouchData(const osgGA::GUIEventAdapter &ea)
{
if(!ea.isMultiTouchEvent())
return;
std::string application_name; std::string application_name;
getUserValue("tuio_application_name", application_name); getUserValue("tuio_application_name", application_name);
@ -285,9 +291,20 @@ void OscSendingDevice::sendMultiTouchData(const osgGA::GUIEventAdapter &ea)
if (application_name.empty()) if (application_name.empty())
application_name = std::string("OpenSceneGraph ") + osgGetVersion() + "@127.0.0.1"; application_name = std::string("OpenSceneGraph ") + osgGetVersion() + "@127.0.0.1";
osgGA::GUIEventAdapter::TouchData* touch_data = ea.getTouchData();
_oscStream << osc::BeginMessage("/tuio/2Dcur") << "source" << application_name.c_str() << osc::EndMessage; _oscStream << osc::BeginMessage("/tuio/2Dcur") << "source" << application_name.c_str() << osc::EndMessage;
_oscStream << osc::BeginMessage("/tuio/2Dcur") << "fseq" << static_cast<osc::int32>(_msgId) << osc::EndMessage;
}
bool OscSendingDevice::sendMultiTouchData(const osgGA::GUIEventAdapter &ea)
{
if(!ea.isMultiTouchEvent())
return false;
beginMultiTouchSequence();
osgGA::GUIEventAdapter::TouchData* touch_data = ea.getTouchData();
_oscStream << osc::BeginMessage("/tuio/2Dcur") << "alive"; _oscStream << osc::BeginMessage("/tuio/2Dcur") << "alive";
for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i) for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i)
@ -295,23 +312,33 @@ void OscSendingDevice::sendMultiTouchData(const osgGA::GUIEventAdapter &ea)
_oscStream << osc::EndMessage; _oscStream << osc::EndMessage;
unsigned int j(0); unsigned int j(0);
unsigned int num_ended(0);
for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i, ++j) for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i, ++j)
{ {
float x = (ea.getTouchPointNormalizedX(j) + 1.0) / 2.0; float x = (ea.getTouchPointNormalizedX(j) + 1.0) / 2.0;
float y =(ea.getTouchPointNormalizedY(j) + 1.0) / 2.0; float y =(ea.getTouchPointNormalizedY(j) + 1.0) / 2.0;
// flip y if origin is not top/left
if(ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
y *= -1;
float vel_x(0), vel_y(0), accel(0); float vel_x(0), vel_y(0), accel(0);
if (_lastEvent.valid()) if (_lastEvent.valid())
{ {
// TODO: add velocity + acceleration
} }
_oscStream << osc::BeginMessage("/tuio/2Dcur") << "set" << static_cast<osc::int32>(i->id) << x << y << vel_x << vel_y << accel << osc::EndMessage; _oscStream << osc::BeginMessage("/tuio/2Dcur") << "set" << static_cast<osc::int32>(i->id) << x << y << vel_x << vel_y << accel << osc::EndMessage;
if(i->phase == osgGA::GUIEventAdapter::TOUCH_ENDED)
num_ended++;
} }
_oscStream << osc::BeginMessage("/tuio/2Dcur") << "fseq" << static_cast<osc::int32>(_msgId) << osc::EndMessage;
_lastEvent = new osgGA::GUIEventAdapter(ea); _lastEvent = new osgGA::GUIEventAdapter(ea);
_finishMultiTouchSequence = (num_ended == touch_data->getNumTouchPoints());
return true;
} }

View File

@ -65,7 +65,8 @@ private:
bool sendUIEventImpl(const osgGA::GUIEventAdapter &ea,MsgIdType msg_id); bool sendUIEventImpl(const osgGA::GUIEventAdapter &ea,MsgIdType msg_id);
void beginBundle(MsgIdType msg_id); void beginBundle(MsgIdType msg_id);
void beginSendInputRange(const osgGA::GUIEventAdapter& ea, MsgIdType msg_id); void beginSendInputRange(const osgGA::GUIEventAdapter& ea, MsgIdType msg_id);
void sendMultiTouchData(const osgGA::GUIEventAdapter& ea); void beginMultiTouchSequence();
bool sendMultiTouchData(const osgGA::GUIEventAdapter& ea);
int getButtonNum(const osgGA::GUIEventAdapter& ea); int getButtonNum(const osgGA::GUIEventAdapter& ea);
void sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle, MsgIdType msg_id); void sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle, MsgIdType msg_id);
std::string transliterateKey(const std::string& key) const; std::string transliterateKey(const std::string& key) const;
@ -76,6 +77,7 @@ private:
unsigned int _numMessagesPerEvent, _delayBetweenSendsInMilliSecs; unsigned int _numMessagesPerEvent, _delayBetweenSendsInMilliSecs;
osc::int64 _msgId; osc::int64 _msgId;
osg::ref_ptr<osgGA::GUIEventAdapter> _lastEvent; osg::ref_ptr<osgGA::GUIEventAdapter> _lastEvent;
bool _finishMultiTouchSequence;
}; };

View File

@ -2020,12 +2020,19 @@ void ReaderWriterP3DXML::parseLayer(osgPresentation::SlideShowConstructor& const
OSG_INFO<<"click_to_run ["<<cur->contents<<"]"<<std::endl; OSG_INFO<<"click_to_run ["<<cur->contents<<"]"<<std::endl;
constructor.layerClickToDoOperation(cur->contents,osgPresentation::RUN, jumpData); constructor.layerClickToDoOperation(cur->contents,osgPresentation::RUN, jumpData);
} }
else if (match(cur->name, "forward_mouse_event_to_device")) else if (match(cur->name,"forward_mouse_event_to_device") || match(cur->name,"forward_event_to_device"))
{ {
osgPresentation::JumpData jumpData; osgPresentation::JumpData jumpData;
OSG_ALWAYS<<"forward_mouse_event_to_device ["<<cur->contents<<"]"<<std::endl; OSG_INFO<<"forward_mouse_event_to_device ["<<cur->contents<<"]"<<std::endl;
constructor.layerClickToDoOperation(cur->contents,osgPresentation::FORWARD_EVENT, jumpData); constructor.layerClickToDoOperation(cur->contents,osgPresentation::FORWARD_MOUSE_EVENT, jumpData);
}
else if (match(cur->name,"forward_touch_event_to_device"))
{
osgPresentation::JumpData jumpData;
OSG_INFO<<"forward_touch_event_to_device ["<<cur->contents<<"]"<<std::endl;
constructor.layerClickToDoOperation(cur->contents,osgPresentation::FORWARD_TOUCH_EVENT, jumpData);
} }
else if (match(cur->name, "click_to_load")) else if (match(cur->name, "click_to_load"))
{ {

View File

@ -149,7 +149,8 @@ void KeyEventHandler::doOperation()
OSG_NOTICE<<"Requires jump "<<std::endl; OSG_NOTICE<<"Requires jump "<<std::endl;
break; break;
} }
case(osgPresentation::FORWARD_EVENT): case(osgPresentation::FORWARD_MOUSE_EVENT):
case(osgPresentation::FORWARD_TOUCH_EVENT):
break; break;
} }

View File

@ -72,9 +72,14 @@ bool PickEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionA
hitr!=intersections.end(); hitr!=intersections.end();
++hitr) ++hitr)
{ {
if (_operation == FORWARD_EVENT) if (_operation == FORWARD_MOUSE_EVENT)
{ {
osg::ref_ptr<osgGA::GUIEventAdapter> cloned_ea = osg::clone(&ea); osg::ref_ptr<osgGA::GUIEventAdapter> cloned_ea = osg::clone(&ea);
// clear touch-data as this prevents sending the event as mouse-event
cloned_ea->setTouchData(NULL);
// reproject mouse-coord
const osg::BoundingBox bb(hitr->drawable->getBound()); const osg::BoundingBox bb(hitr->drawable->getBound());
const osg::Vec3& p(hitr->localIntersectionPoint); const osg::Vec3& p(hitr->localIntersectionPoint);
@ -85,8 +90,53 @@ bool PickEventHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionA
cloned_ea->setY(ea.getYmin() + transformed_y * (ea.getYmax() - ea.getYmin())); cloned_ea->setY(ea.getYmin() + transformed_y * (ea.getYmax() - ea.getYmin()));
cloned_ea->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); cloned_ea->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
// std::cout << transformed_x << "/" << transformed_x << " -> " << cloned_ea->getX() << "/" <<cloned_ea->getY() << std::endl; // std::cout << transformed_x << "/" << transformed_x << " -> " << cloned_ea->getX() << "/" <<cloned_ea->getY() << std::endl;
SlideEventHandler::instance()->forwardEventToDevices(cloned_ea.get());
}
else if ((_operation == FORWARD_TOUCH_EVENT) && ea.isMultiTouchEvent())
{
osg::ref_ptr<osgGA::GUIEventAdapter> cloned_ea = osg::clone(&ea);
osgGA::GUIEventAdapter::TouchData* touch_data = cloned_ea->getTouchData();
// reproject touch-points
const osg::BoundingBox bb(hitr->drawable->getBound());
osg::Camera* camera = viewer->getCamera();
osg::Matrix matrix = osg::computeLocalToWorld(hitr->nodePath, false) * camera->getViewMatrix() * camera->getProjectionMatrix();
matrix.postMult(camera->getViewport()->computeWindowMatrix());
osg::Matrixd inverse;
inverse.invert(matrix);
// transform touch-points into local coord-system
unsigned int j(0);
for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i, ++j)
{
osg::Vec3 local = osg::Vec3(i->x, i->y, 0) * inverse;
// std::cout << local << " hit: " << hitr->localIntersectionPoint << std::endl;
local.x() = (local.x() - bb.xMin()) / (bb.xMax() - bb.xMin());
local.z() = (local.z() - bb.zMin()) / (bb.zMax() - bb.zMin());
local.x() = (ea.getXmin() + local.x() * (ea.getXmax() - ea.getXmin()));
local.z() = (ea.getYmin() + local.z() * (ea.getYmax() - ea.getYmin()));
// std::cout << ea.getX() << "/" << ea.getY() << " -- " << i->x << " " << i->y << " -> " << local.x() <<"/" << local.z() << std::endl;
i->x = local.x();
i->y = local.z();
}
// std::cout << transformed_x << "/" << transformed_x << " -> " << cloned_ea->getX() << "/" <<cloned_ea->getY() << std::endl;
SlideEventHandler::instance()->forwardEventToDevices(cloned_ea.get()); SlideEventHandler::instance()->forwardEventToDevices(cloned_ea.get());
} }
else else
@ -206,7 +256,8 @@ void PickEventHandler::doOperation()
OSG_INFO<<"Requires jump "<<std::endl; OSG_INFO<<"Requires jump "<<std::endl;
break; break;
} }
case(osgPresentation::FORWARD_EVENT): case(osgPresentation::FORWARD_MOUSE_EVENT):
case(osgPresentation::FORWARD_TOUCH_EVENT):
break; break;
} }

View File

@ -869,19 +869,25 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect)
NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self]; NSSet *allTouches = [event touchesMatchingPhase: NSTouchPhaseAny inView: self];
osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL); osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL);
NSRect bounds = [self bounds]; NSRect bounds = [self bounds];
for(unsigned int i=0; i<[allTouches count]; i++) for(unsigned int i=0; i<[allTouches count]; i++)
{ {
NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; NSTouch *touch = [[allTouches allObjects] objectAtIndex:i];
NSPoint pos = [touch normalizedPosition]; NSPoint pos = [touch normalizedPosition];
osg::Vec2 pixelPos(pos.x * bounds.size.width, (pos.y) * bounds.size.height); pos.x *= bounds.size.width;
pos.y *= bounds.size.height;
unsigned int touch_id = [self computeTouchId: touch mayCleanup:FALSE]; unsigned int touch_id = [self computeTouchId: touch mayCleanup:FALSE];
if (!osg_event) { if (!osg_event)
osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); {
} else { osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y);
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
osg_event->setInputRange(0, 0, bounds.size.width, bounds.size.height);
}
else
{
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y);
} }
} }
} }
@ -897,12 +903,18 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect)
{ {
NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; NSTouch *touch = [[allTouches allObjects] objectAtIndex:i];
NSPoint pos = [touch normalizedPosition]; NSPoint pos = [touch normalizedPosition];
osg::Vec2 pixelPos(pos.x * bounds.size.width, (pos.y) * bounds.size.height); pos.x *= bounds.size.width;
pos.y *= bounds.size.height;
unsigned int touch_id = [self computeTouchId: touch mayCleanup:FALSE]; unsigned int touch_id = [self computeTouchId: touch mayCleanup:FALSE];
if (!osg_event) { if (!osg_event)
osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); {
} else { osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y);
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
osg_event->setInputRange(0, 0, bounds.size.width, bounds.size.height);
}
else
{
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y);
} }
} }
} }
@ -915,16 +927,23 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect)
osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL); osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL);
NSRect bounds = [self bounds]; NSRect bounds = [self bounds];
for(unsigned int i=0; i<[allTouches count]; i++) for(unsigned int i=0; i<[allTouches count]; i++)
{ {
NSTouch *touch = [[allTouches allObjects] objectAtIndex:i]; NSTouch *touch = [[allTouches allObjects] objectAtIndex:i];
NSPoint pos = [touch normalizedPosition]; NSPoint pos = [touch normalizedPosition];
osg::Vec2 pixelPos(pos.x * bounds.size.width, (pos.y) * bounds.size.height); pos.x *= bounds.size.width;
pos.y *= bounds.size.height;
unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE];
if (!osg_event) { if (!osg_event)
osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), 1); {
} else { osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y, 1);
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), 1); osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
osg_event->setInputRange(0, 0, bounds.size.width, bounds.size.height);
}
else
{
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pos.x, pos.y, 1);
} }
} }

View File

@ -580,11 +580,17 @@ typedef std::map<void*, unsigned int> TouchPointsIdMapping;
osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)];
unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE];
if (!osg_event) { if (!osg_event)
{
osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y());
} else { osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
}
else
{
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y());
} }
} }
[super touchesBegan:touches withEvent:event]; [super touchesBegan:touches withEvent:event];
@ -603,11 +609,17 @@ typedef std::map<void*, unsigned int> TouchPointsIdMapping;
osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)];
unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: FALSE];
if (!osg_event) { if (!osg_event)
{
osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y());
} else { osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
}
else
{
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y()); osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y());
} }
} }
[super touchesMoved:touches withEvent:event]; [super touchesMoved:touches withEvent:event];
@ -626,11 +638,17 @@ typedef std::map<void*, unsigned int> TouchPointsIdMapping;
CGPoint pos = [touch locationInView:self]; CGPoint pos = [touch locationInView:self];
osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)]; osg::Vec2 pixelPos = [self convertPointToPixel: osg::Vec2(pos.x,pos.y)];
unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE]; unsigned int touch_id = [self computeTouchId: touch mayCleanup: TRUE];
if (!osg_event) { if (!osg_event)
{
osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]); osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]);
} else { osg_event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
}
else
{
osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]); osg_event->addTouchPoint(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), [touch tapCount]);
} }
} }
[super touchesEnded:touches withEvent:event]; [super touchesEnded:touches withEvent:event];

View File

@ -927,6 +927,11 @@ void Viewer::eventTraversal()
{ {
event->setY((event->getYmax()-event->getY())+event->getYmin()); event->setY((event->getYmax()-event->getY())+event->getYmin());
event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
if(event->isMultiTouchEvent()) {
for(osgGA::GUIEventAdapter::TouchData::iterator itr = event->getTouchData()->begin(); itr != event->getTouchData()->end(); itr++) {
itr->y = event->getYmax() - itr->y + event->getYmin();
}
}
} }
#endif #endif