From Stephan Huber, * GUIEventAdapter: add support for getting normalized touch points
* MultiTouchTrackball: some code cleanup and support for normalized touch-points * oscdevice: receiving and sending multi-touch-events via the Cursor2D-profile from TUIO * added some documentation
This commit is contained in:
parent
d7442e7456
commit
e0d3ab4412
@ -98,9 +98,11 @@ osg::Camera* createHUD(unsigned int w, unsigned int h)
|
|||||||
|
|
||||||
class TestMultiTouchEventHandler : public osgGA::GUIEventHandler {
|
class TestMultiTouchEventHandler : public osgGA::GUIEventHandler {
|
||||||
public:
|
public:
|
||||||
TestMultiTouchEventHandler(osg::Group* parent_group)
|
TestMultiTouchEventHandler(osg::Group* parent_group, float w, float h)
|
||||||
: osgGA::GUIEventHandler(),
|
: osgGA::GUIEventHandler(),
|
||||||
_cleanupOnNextFrame(false)
|
_cleanupOnNextFrame(false),
|
||||||
|
_w(w),
|
||||||
|
_h(h)
|
||||||
{
|
{
|
||||||
createTouchRepresentations(parent_group, 10);
|
createTouchRepresentations(parent_group, 10);
|
||||||
}
|
}
|
||||||
@ -149,6 +151,18 @@ private:
|
|||||||
|
|
||||||
virtual bool handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *)
|
virtual bool handle (const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, osg::Object *, osg::NodeVisitor *)
|
||||||
{
|
{
|
||||||
|
if (ea.getEventType() != osgGA::GUIEventAdapter::FRAME) {
|
||||||
|
std::cout << ea.getTime() << ": ";
|
||||||
|
switch(ea.getEventType()) {
|
||||||
|
case osgGA::GUIEventAdapter::PUSH: std::cout << "PUSH"; break;
|
||||||
|
case osgGA::GUIEventAdapter::DRAG: std::cout << "DRAG"; break;
|
||||||
|
case osgGA::GUIEventAdapter::MOVE: std::cout << "MOVE"; break;
|
||||||
|
case osgGA::GUIEventAdapter::RELEASE: std::cout << "RELEASE"; break;
|
||||||
|
default: std::cout << ea.getEventType();
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
switch(ea.getEventType())
|
switch(ea.getEventType())
|
||||||
{
|
{
|
||||||
case osgGA::GUIEventAdapter::FRAME:
|
case osgGA::GUIEventAdapter::FRAME:
|
||||||
@ -174,7 +188,12 @@ 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));
|
float x = ea.getTouchPointNormalizedX(j);
|
||||||
|
float y = ea.getTouchPointNormalizedY(j);
|
||||||
|
|
||||||
|
// std::cout << j << ": " << tp.x << "/" << tp.y <<" "<< x << " " << y << " " << _w << " " << _h << std::endl;
|
||||||
|
|
||||||
|
_mats[j]->setMatrix(osg::Matrix::translate((1+x) * 0.5 * _w, (1+y) * 0.5 * _h, 0));
|
||||||
_mats[j]->setNodeMask(0xffff);
|
_mats[j]->setNodeMask(0xffff);
|
||||||
|
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
@ -239,6 +258,8 @@ private:
|
|||||||
std::vector<osgText::Text*> _texts;
|
std::vector<osgText::Text*> _texts;
|
||||||
bool _cleanupOnNextFrame;
|
bool _cleanupOnNextFrame;
|
||||||
|
|
||||||
|
float _w, _h;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -248,6 +269,20 @@ int main( int argc, char **argv )
|
|||||||
osg::ArgumentParser arguments(&argc,argv);
|
osg::ArgumentParser arguments(&argc,argv);
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int helpType = 0;
|
||||||
|
if ((helpType = arguments.readHelpType()))
|
||||||
|
{
|
||||||
|
arguments.getApplicationUsage()->write(std::cout, helpType);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// report any errors if they have occurred when parsing the program arguments.
|
||||||
|
if (arguments.errors())
|
||||||
|
{
|
||||||
|
arguments.writeErrorMessages(std::cout);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// read the scene from the list of file specified commandline args.
|
// read the scene from the list of file specified commandline args.
|
||||||
osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);
|
osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);
|
||||||
|
|
||||||
@ -265,7 +300,19 @@ int main( int argc, char **argv )
|
|||||||
|
|
||||||
|
|
||||||
// construct the viewer.
|
// construct the viewer.
|
||||||
osgViewer::Viewer viewer;
|
osgViewer::Viewer viewer(arguments);
|
||||||
|
|
||||||
|
|
||||||
|
//opening devices
|
||||||
|
std::string device;
|
||||||
|
while(arguments.read("--device", device))
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osgGA::Device> dev = osgDB::readFile<osgGA::Device>(device);
|
||||||
|
if (dev.valid())
|
||||||
|
{
|
||||||
|
viewer.addDevice(dev.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
@ -288,7 +335,7 @@ int main( int argc, char **argv )
|
|||||||
osg::Camera* hud_camera = createHUD(gc->getTraits()->width, gc->getTraits()->height);
|
osg::Camera* hud_camera = createHUD(gc->getTraits()->width, gc->getTraits()->height);
|
||||||
|
|
||||||
|
|
||||||
viewer.addEventHandler(new TestMultiTouchEventHandler(hud_camera));
|
viewer.addEventHandler(new TestMultiTouchEventHandler(hud_camera, gc->getTraits()->width, gc->getTraits()->height));
|
||||||
|
|
||||||
|
|
||||||
group->addChild(hud_camera);
|
group->addChild(hud_camera);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
#include <osg/ValueObject>
|
#include <osg/ValueObject>
|
||||||
#include <osg/FrontFace>
|
#include <osg/FrontFace>
|
||||||
|
#include <osg/ShapeDrawable>
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
|
|
||||||
#include <osgText/Text>
|
#include <osgText/Text>
|
||||||
@ -47,6 +48,8 @@
|
|||||||
|
|
||||||
#include <osg/io_utils>
|
#include <osg/io_utils>
|
||||||
|
|
||||||
|
#include <osgViewer/api/Cocoa/GraphicsWindowCocoa>
|
||||||
|
|
||||||
|
|
||||||
// class to handle events with a pick
|
// class to handle events with a pick
|
||||||
class PickHandler : public osgGA::GUIEventHandler {
|
class PickHandler : public osgGA::GUIEventHandler {
|
||||||
@ -404,8 +407,11 @@ int main( int argc, char **argv )
|
|||||||
|
|
||||||
if (!scene)
|
if (!scene)
|
||||||
{
|
{
|
||||||
std::cout << argv[0] << ": requires filename argument." << std::endl;
|
osg::Geode* geode = new osg::Geode();
|
||||||
return 1;
|
osg::ShapeDrawable* drawable = new osg::ShapeDrawable(new osg::Box());
|
||||||
|
geode->addDrawable(drawable);
|
||||||
|
|
||||||
|
scene = geode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_zeroconf(false);
|
bool use_zeroconf(false);
|
||||||
@ -492,6 +498,13 @@ int main( int argc, char **argv )
|
|||||||
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
|
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// as multitouch is disabled by default, enable it now
|
||||||
|
osgViewer::GraphicsWindowCocoa* win = dynamic_cast<osgViewer::GraphicsWindowCocoa*>(gc.get());
|
||||||
|
if (win) win->setMultiTouchEnabled(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
osgViewer::View* view = new osgViewer::View;
|
osgViewer::View* view = new osgViewer::View;
|
||||||
view->setName("View one");
|
view->setName("View one");
|
||||||
viewer.addView(view);
|
viewer.addView(view);
|
||||||
|
@ -678,6 +678,16 @@ public:
|
|||||||
TouchData* getTouchData() const { return _touchData.get(); }
|
TouchData* getTouchData() const { return _touchData.get(); }
|
||||||
bool isMultiTouchEvent() const { return (_touchData.valid()); }
|
bool isMultiTouchEvent() const { return (_touchData.valid()); }
|
||||||
|
|
||||||
|
inline float getTouchPointNormalizedX(unsigned int ndx) const {
|
||||||
|
return (getTouchData()->get(ndx).x-_Xmin)/(_Xmax-_Xmin)*2.0f-1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float getTouchPointNormalizedY(unsigned int ndx) const {
|
||||||
|
if (_mouseYOrientation==Y_INCREASING_UPWARDS)
|
||||||
|
return (getTouchData()->get(ndx).y-_Ymin)/(_Ymax-_Ymin)*2.0f-1.0f;
|
||||||
|
else
|
||||||
|
return -((getTouchData()->get(ndx).y-_Ymin)/(_Ymax-_Ymin)*2.0f-1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::vector< osg::ref_ptr<PointerData> > PointerDataList;
|
typedef std::vector< osg::ref_ptr<PointerData> > PointerDataList;
|
||||||
void setPointerDataList(const PointerDataList& pdl) { _pointerDataList = pdl; }
|
void setPointerDataList(const PointerDataList& pdl) { _pointerDataList = pdl; }
|
||||||
|
@ -36,9 +36,9 @@ class OSGGA_EXPORT MultiTouchTrackballManipulator : public TrackballManipulator
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void handleMultiTouchDrag(GUIEventAdapter::TouchData* now, GUIEventAdapter::TouchData* last, const double eventTimeDelta);
|
void handleMultiTouchDrag(const GUIEventAdapter* now, const GUIEventAdapter* last, const double eventTimeDelta);
|
||||||
|
|
||||||
osg::ref_ptr<GUIEventAdapter::TouchData> _lastTouchData;
|
osg::ref_ptr<GUIEventAdapter> _lastEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ MultiTouchTrackballManipulator::MultiTouchTrackballManipulator( const MultiTouch
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MultiTouchTrackballManipulator::handleMultiTouchDrag(GUIEventAdapter::TouchData* now, GUIEventAdapter::TouchData* last, const double eventTimeDelta)
|
void MultiTouchTrackballManipulator::handleMultiTouchDrag(const GUIEventAdapter* now, const GUIEventAdapter* last, const double eventTimeDelta)
|
||||||
{
|
{
|
||||||
const float zoom_threshold = 1.0f;
|
const float zoom_threshold = 0.0001f;
|
||||||
|
|
||||||
osg::Vec2 pt_1_now(now->get(0).x,now->get(0).y);
|
osg::Vec2 pt_1_now(now->getTouchPointNormalizedX(0),now->getTouchPointNormalizedY(0));
|
||||||
osg::Vec2 pt_2_now(now->get(1).x,now->get(1).y);
|
osg::Vec2 pt_2_now(now->getTouchPointNormalizedX(1),now->getTouchPointNormalizedY(1));
|
||||||
osg::Vec2 pt_1_last(last->get(0).x,last->get(0).y);
|
osg::Vec2 pt_1_last(last->getTouchPointNormalizedX(0),last->getTouchPointNormalizedY(0));
|
||||||
osg::Vec2 pt_2_last(last->get(1).x,last->get(1).y);
|
osg::Vec2 pt_2_last(last->getTouchPointNormalizedX(1),last->getTouchPointNormalizedY(1));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,21 +51,19 @@ void MultiTouchTrackballManipulator::handleMultiTouchDrag(GUIEventAdapter::Touch
|
|||||||
|
|
||||||
// osg::notify(osg::ALWAYS) << gap_now << " " << gap_last << std::endl;
|
// osg::notify(osg::ALWAYS) << gap_now << " " << gap_last << std::endl;
|
||||||
|
|
||||||
if (fabs(gap_last - gap_now) >= zoom_threshold)
|
|
||||||
{
|
// zoom gesture
|
||||||
// zoom gesture
|
if (fabs(gap_last - gap_now) > 0.02)
|
||||||
zoomModel( (gap_last - gap_now) * eventTimeDelta, true );
|
zoomModel( (gap_last - gap_now) , true );
|
||||||
}
|
|
||||||
|
|
||||||
// drag gesture
|
// drag gesture
|
||||||
|
|
||||||
osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f;
|
osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f;
|
||||||
|
|
||||||
float scale = 0.2f * _distance * eventTimeDelta;
|
float scale = _distance / 3.0f;
|
||||||
|
|
||||||
// osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl;
|
// osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl;
|
||||||
|
|
||||||
panModel( delta.x() * scale, delta.y() * scale * (-1)); // flip y-coord because of different origins.
|
panModel( delta.x() * scale, delta.y() * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,15 +99,15 @@ bool MultiTouchTrackballManipulator::handle( const GUIEventAdapter& ea, GUIActio
|
|||||||
|
|
||||||
else if (data->getNumTouchPoints() >= 2)
|
else if (data->getNumTouchPoints() >= 2)
|
||||||
{
|
{
|
||||||
if ((_lastTouchData.valid()) && (_lastTouchData->getNumTouchPoints() >= 2))
|
if ((_lastEvent.valid()) && (_lastEvent->getTouchData()->getNumTouchPoints() >= 2))
|
||||||
{
|
{
|
||||||
handleMultiTouchDrag(data, _lastTouchData.get(), eventTimeDelta);
|
handleMultiTouchDrag(&ea, _lastEvent, eventTimeDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastTouchData = data;
|
_lastEvent = new GUIEventAdapter(ea);
|
||||||
|
|
||||||
// check if all touches ended
|
// check if all touches ended
|
||||||
unsigned int num_touches_ended(0);
|
unsigned int num_touches_ended(0);
|
||||||
@ -121,7 +119,7 @@ bool MultiTouchTrackballManipulator::handle( const GUIEventAdapter& ea, GUIActio
|
|||||||
|
|
||||||
if(num_touches_ended == data->getNumTouchPoints())
|
if(num_touches_ended == data->getNumTouchPoints())
|
||||||
{
|
{
|
||||||
_lastTouchData = NULL;
|
_lastEvent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ public:
|
|||||||
, _treatFirstArgumentAsValueName(treat_first_argument_as_value_name)
|
, _treatFirstArgumentAsValueName(treat_first_argument_as_value_name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m);
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint);
|
||||||
|
|
||||||
virtual void describeTo(std::ostream& out) const
|
virtual void describeTo(std::ostream& out) const
|
||||||
{
|
{
|
||||||
@ -135,7 +135,7 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool StandardRequestHandler::operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
bool StandardRequestHandler::operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -298,7 +298,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
float x_min(-1.0f), y_min(-1.0f), x_max(1.0f), y_max(1.0f);
|
float x_min(-1.0f), y_min(-1.0f), x_max(1.0f), y_max(1.0f);
|
||||||
@ -330,7 +330,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
bool increasing_upwards(false);
|
bool increasing_upwards(false);
|
||||||
@ -364,7 +364,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
osc::int32 keycode(0);
|
osc::int32 keycode(0);
|
||||||
@ -401,7 +401,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
osc::int32 keycode(0);
|
osc::int32 keycode(0);
|
||||||
@ -440,7 +440,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -475,7 +475,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -516,7 +516,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
float down(0.0f);
|
float down(0.0f);
|
||||||
|
|
||||||
@ -568,7 +568,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
float x(0.0f), y(0.0f);
|
float x(0.0f), y(0.0f);
|
||||||
osc::int32 btn(0);
|
osc::int32 btn(0);
|
||||||
@ -621,7 +621,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
float pressure(0.0f);
|
float pressure(0.0f);
|
||||||
@ -652,7 +652,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
osc::int32 pt(osgGA::GUIEventAdapter::UNKNOWN);
|
osc::int32 pt(osgGA::GUIEventAdapter::UNKNOWN);
|
||||||
@ -686,7 +686,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
float rotation(0.0f), tilt_x(0.0f), tilt_y(0.0f);
|
float rotation(0.0f), tilt_x(0.0f), tilt_y(0.0f);
|
||||||
@ -710,6 +710,240 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TUIO2DCursorRequestHandler : public OscReceivingDevice::RequestHandler {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct Cursor {
|
||||||
|
std::string source;
|
||||||
|
unsigned int id, frameId;
|
||||||
|
osg::Vec2f pos, vel;
|
||||||
|
float accel;
|
||||||
|
osgGA::GUIEventAdapter::TouchPhase phase;
|
||||||
|
|
||||||
|
Cursor() : source(), id(0), frameId(0), pos(), vel(), accel(), phase(osgGA::GUIEventAdapter::TOUCH_UNKNOWN) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
struct EndpointData {
|
||||||
|
std::string source;
|
||||||
|
osc::int32 frameId;
|
||||||
|
bool mayClearUnhandledPointer;
|
||||||
|
std::set<unsigned int> unhandled;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, EndpointData> EndpointDataMap;
|
||||||
|
typedef std::map<unsigned int, Cursor> CursorMap;
|
||||||
|
typedef std::map<std::string, CursorMap> ApplicationCursorMap;
|
||||||
|
typedef std::map<std::string, unsigned int> SourceIdMap;
|
||||||
|
TUIO2DCursorRequestHandler()
|
||||||
|
: OscReceivingDevice::RequestHandler("/tuio/2Dcur")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setDevice(OscReceivingDevice* device) {
|
||||||
|
OscReceivingDevice::RequestHandler::setDevice(device);
|
||||||
|
device->addHandleOnCheckEvents(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint)
|
||||||
|
{
|
||||||
|
// std::cout << m << std::endl;
|
||||||
|
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
|
||||||
|
std::string end_point(' ', IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH);
|
||||||
|
remoteEndPoint.AddressAndPortAsString(&end_point[0]);
|
||||||
|
|
||||||
|
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
||||||
|
|
||||||
|
|
||||||
|
const char* str;
|
||||||
|
args >> str;
|
||||||
|
std::string what(str);
|
||||||
|
|
||||||
|
if (what == "source")
|
||||||
|
{
|
||||||
|
args >> str;
|
||||||
|
_endpointData[end_point].source = std::string(str);
|
||||||
|
updateSourceIdMap(_endpointData[end_point].source);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (what == "fseq")
|
||||||
|
{
|
||||||
|
args >> _endpointData[end_point].frameId;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string source = _endpointData[end_point].source;
|
||||||
|
unsigned int frame_id = _endpointData[end_point].frameId;
|
||||||
|
|
||||||
|
if (what == "alive")
|
||||||
|
{
|
||||||
|
while (!args.Eos())
|
||||||
|
{
|
||||||
|
osc::int32 id;
|
||||||
|
args >> id;
|
||||||
|
_endpointData[source].unhandled.insert(id);
|
||||||
|
}
|
||||||
|
_endpointData[source].mayClearUnhandledPointer = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (what == "set")
|
||||||
|
{
|
||||||
|
osc::int32 id;
|
||||||
|
args >> id;
|
||||||
|
if (_alive[source].find(id) == _alive[source].end())
|
||||||
|
{
|
||||||
|
_alive[source][id] = Cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor& c(_alive[source][id]);
|
||||||
|
args >> c.pos.x() >> c.pos.y() >> c.vel.x() >> c.vel.y() >> c.accel >> osc::EndMessage;
|
||||||
|
c.source = source;
|
||||||
|
c.frameId = frame_id;
|
||||||
|
_endpointData[source].unhandled.insert(id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(osgGA::EventQueue* queue)
|
||||||
|
{
|
||||||
|
// dispatch all touchpoints in one GUIEventAdapter
|
||||||
|
|
||||||
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||||
|
|
||||||
|
osg::ref_ptr<osgGA::GUIEventAdapter> event = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
for(ApplicationCursorMap::iterator i = _alive.begin(); i != _alive.end(); ++i)
|
||||||
|
{
|
||||||
|
const std::string& source(i->first);
|
||||||
|
|
||||||
|
/*
|
||||||
|
std::cout << source << ": ";
|
||||||
|
for(std::set<unsigned int>::iterator k = _endpointData[source].unhandled.begin();
|
||||||
|
k != _endpointData[source].unhandled.end();
|
||||||
|
++k)
|
||||||
|
{
|
||||||
|
std::cout << *k << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// remove all touchpoints which are not transmitted via alive-message, dispatching TOUCH_ENDED
|
||||||
|
|
||||||
|
EndpointData& endpoint_data(_endpointData[source]);
|
||||||
|
if (endpoint_data.mayClearUnhandledPointer)
|
||||||
|
{
|
||||||
|
unsigned int source_id = getSourceId(source);
|
||||||
|
|
||||||
|
std::vector<unsigned int> to_delete;
|
||||||
|
|
||||||
|
for(CursorMap::iterator k = i->second.begin(); k != i->second.end(); ++k)
|
||||||
|
{
|
||||||
|
//create a unique touchpoint-id
|
||||||
|
unsigned int touch_id = (source_id << 16) + k->first;
|
||||||
|
|
||||||
|
std::set<unsigned int>& unhandled(endpoint_data.unhandled);
|
||||||
|
if ((unhandled.find(k->first) == unhandled.end()))
|
||||||
|
{
|
||||||
|
std::cout << "deleting: " << k->first << std::endl;
|
||||||
|
to_delete.push_back(k->first);
|
||||||
|
|
||||||
|
float win_x = k->second.pos.x();
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint_data.mayClearUnhandledPointer = false;
|
||||||
|
endpoint_data.unhandled.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i->second.size() == 0)
|
||||||
|
{
|
||||||
|
// std::cout << "removing endpoint" << source << std::endl;
|
||||||
|
_endpointData.erase(_endpointData.find(source));
|
||||||
|
_alive.erase(_alive.find(source));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send all alive touchpoints
|
||||||
|
for(ApplicationCursorMap::iterator i = _alive.begin(); i != _alive.end(); ++i)
|
||||||
|
{
|
||||||
|
const std::string& source(i->first);
|
||||||
|
unsigned int source_id = getSourceId(source);
|
||||||
|
|
||||||
|
for(CursorMap::iterator k = i->second.begin(); k != i->second.end(); ++k)
|
||||||
|
{
|
||||||
|
unsigned int id = k->first;
|
||||||
|
unsigned int touch_id = (source_id << 16) + id;
|
||||||
|
|
||||||
|
Cursor& c(k->second);
|
||||||
|
float win_x = c.pos.x();
|
||||||
|
float win_y = c.pos.y();
|
||||||
|
|
||||||
|
bool down = c.phase != osgGA::GUIEventAdapter::TOUCH_MOVED && c.phase != osgGA::GUIEventAdapter::TOUCH_STATIONERY;
|
||||||
|
if(!event)
|
||||||
|
{
|
||||||
|
if(down)
|
||||||
|
event = queue->touchBegan(touch_id, osgGA::GUIEventAdapter::TOUCH_BEGAN, win_x, win_y);
|
||||||
|
else
|
||||||
|
event = queue->touchMoved(touch_id, osgGA::GUIEventAdapter::TOUCH_MOVED, win_x, win_y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->addTouchPoint(touch_id, down ? osgGA::GUIEventAdapter::TOUCH_BEGAN : osgGA::GUIEventAdapter::TOUCH_MOVED, win_x, win_y);
|
||||||
|
}
|
||||||
|
c.phase = osgGA::GUIEventAdapter::TOUCH_MOVED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust time + input range
|
||||||
|
if (event)
|
||||||
|
{
|
||||||
|
event->setInputRange(0, 0, 1.0, 1.0);
|
||||||
|
event->setTime(queue->getTime());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void updateSourceIdMap(const std::string& source)
|
||||||
|
{
|
||||||
|
if (_sourceIdMap.find(source) == _sourceIdMap.end())
|
||||||
|
_sourceIdMap[source] = _sourceIdMap.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int getSourceId(const std::string& source)
|
||||||
|
{
|
||||||
|
return _sourceIdMap[source];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
EndpointDataMap _endpointData;
|
||||||
|
ApplicationCursorMap _alive;
|
||||||
|
OpenThreads::Mutex _mutex;
|
||||||
|
SourceIdMap _sourceIdMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace
|
} // end of namespace
|
||||||
|
|
||||||
|
|
||||||
@ -758,6 +992,8 @@ OscReceivingDevice::OscReceivingDevice(const std::string& server_address, int li
|
|||||||
addRequestHandler(new OscDevice::PenProximityRequestHandler(true));
|
addRequestHandler(new OscDevice::PenProximityRequestHandler(true));
|
||||||
addRequestHandler(new OscDevice::PenProximityRequestHandler(false));
|
addRequestHandler(new OscDevice::PenProximityRequestHandler(false));
|
||||||
|
|
||||||
|
addRequestHandler(new OscDevice::TUIO2DCursorRequestHandler());
|
||||||
|
|
||||||
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));
|
||||||
@ -803,7 +1039,7 @@ void OscReceivingDevice::ProcessMessage( const osc::ReceivedMessage& m, const Ip
|
|||||||
{
|
{
|
||||||
// OSG_INFO << "OscDevice :: handling " << mangled_path << " with " << i->second << std::endl;
|
// OSG_INFO << "OscDevice :: handling " << mangled_path << " with " << i->second << std::endl;
|
||||||
|
|
||||||
if (i->second->operator()(mangled_path, in_request_path, m) && !handled)
|
if (i->second->operator()(mangled_path, in_request_path, m, remoteEndpoint) && !handled)
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,6 +1098,7 @@ void OscReceivingDevice::ProcessBundle( const osc::ReceivedBundle& b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OscReceivingDevice::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint )
|
void OscReceivingDevice::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint )
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -882,7 +1119,7 @@ void OscReceivingDevice::ProcessPacket( const char *data, int size, const IpEndp
|
|||||||
remoteEndpoint.AddressAndPortAsString(address);
|
remoteEndpoint.AddressAndPortAsString(address);
|
||||||
|
|
||||||
_userDataEvent->setUserValue("osc/remote_end_point", std::string(address));
|
_userDataEvent->setUserValue("osc/remote_end_point", std::string(address));
|
||||||
|
_userDataEvent->setTime(getEventQueue()->getTime());
|
||||||
getEventQueue()->addEvent(_userDataEvent.get());
|
getEventQueue()->addEvent(_userDataEvent.get());
|
||||||
_userDataEvent = NULL;
|
_userDataEvent = NULL;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,40 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OscReceivingDevice can be used to receive osg-events via OSC from other hosts/ applications
|
||||||
|
* It can even translate custom osc-message to user-events with attached user-data.
|
||||||
|
*
|
||||||
|
* It uses the TUIO 1.1 Cursor2D-profile to receive multitouch-events
|
||||||
|
*
|
||||||
|
* This device adds to every message-bundle a message-id, so you can check, if you miss events or similar.
|
||||||
|
*
|
||||||
|
* receiving custom osc-data:
|
||||||
|
* /my_user_event/value_1 23
|
||||||
|
* /my_user_event/value_2 42
|
||||||
|
*
|
||||||
|
* this will result in one osgGA:Event (when both messages are bundled) witht the name "/my_user_event",
|
||||||
|
* and two user-values (value_1 and value_2)
|
||||||
|
* To get value_1 you'll do something like event->getUserValue("value_1", my_int);
|
||||||
|
*
|
||||||
|
* Currently osg's user-data can not cast to different types, they have to match, so
|
||||||
|
* event->getUserValue("value_1", my_string) will fail.
|
||||||
|
*
|
||||||
|
* The receiving device will try to combine multiple osc arguments intelligently, multiple osc-arguments are
|
||||||
|
* bundled into Vec2, Vec3, Vec4 or Matrix, it depends on the number of arguments.
|
||||||
|
|
||||||
|
* TUIO-specific notes:
|
||||||
|
* If multiple TUIO-applications are transmitting their touch-points to one oscReceivingDevice, all
|
||||||
|
* touchpoints get multiplexed, so you'll get one event with x touchpoints.
|
||||||
|
* You can differentiate the specific applications by the touch_ids, the upper 16bits
|
||||||
|
* are specific to an application, the lower 16bits contain the touch-id for that application.
|
||||||
|
* If you need "better" separation, use multiple oscReceivingDevices listening on different ports.
|
||||||
|
*
|
||||||
|
* @TODO implement other TUIO-profiles
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <osg/Referenced>
|
#include <osg/Referenced>
|
||||||
#include <OpenThreads/Thread>
|
#include <OpenThreads/Thread>
|
||||||
#include <osgGA/Device>
|
#include <osgGA/Device>
|
||||||
@ -37,7 +71,8 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m) = 0;
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m, const IpEndpointName& remoteEndPoint) = 0;
|
||||||
|
virtual void operator()(osgGA::EventQueue* queue) {}
|
||||||
|
|
||||||
const std::string& getRequestPath() const { return _requestPath; }
|
const std::string& getRequestPath() const { return _requestPath; }
|
||||||
|
|
||||||
@ -47,7 +82,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setDevice(OscReceivingDevice* device) { _device = device; }
|
virtual void setDevice(OscReceivingDevice* device) { _device = device; }
|
||||||
OscReceivingDevice* getDevice() const { return _device; }
|
OscReceivingDevice* getDevice() const { return _device; }
|
||||||
|
|
||||||
/// set the request-path, works only from the constructor
|
/// set the request-path, works only from the constructor
|
||||||
@ -98,6 +133,17 @@ public:
|
|||||||
|
|
||||||
virtual const char* className() const { return "OSC receiving device"; }
|
virtual const char* className() const { return "OSC receiving device"; }
|
||||||
|
|
||||||
|
void addHandleOnCheckEvents(RequestHandler* handler) { _handleOnCheckEvents.push_back(handler); }
|
||||||
|
|
||||||
|
virtual bool checkEvents() {
|
||||||
|
osgGA::EventQueue* queue = getEventQueue();
|
||||||
|
|
||||||
|
for(std::vector<RequestHandler*>::iterator i = _handleOnCheckEvents.begin(); i != _handleOnCheckEvents.end(); ++i) {
|
||||||
|
(*i)->operator()(queue);
|
||||||
|
}
|
||||||
|
return osgGA::Device::checkEvents();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _listeningAddress;
|
std::string _listeningAddress;
|
||||||
unsigned int _listeningPort;
|
unsigned int _listeningPort;
|
||||||
@ -106,6 +152,7 @@ private:
|
|||||||
osg::ref_ptr<osgGA::Event> _userDataEvent;
|
osg::ref_ptr<osgGA::Event> _userDataEvent;
|
||||||
MsgIdType _lastMsgId;
|
MsgIdType _lastMsgId;
|
||||||
osg::Timer_t _lastMsgTimeStamp;
|
osg::Timer_t _lastMsgTimeStamp;
|
||||||
|
std::vector<RequestHandler*> _handleOnCheckEvents;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -113,7 +160,7 @@ private:
|
|||||||
class SendKeystrokeRequestHandler : public OscReceivingDevice::RequestHandler {
|
class SendKeystrokeRequestHandler : public OscReceivingDevice::RequestHandler {
|
||||||
public:
|
public:
|
||||||
SendKeystrokeRequestHandler(const std::string& request_path, int key) : OscReceivingDevice::RequestHandler(request_path), _key(key) {}
|
SendKeystrokeRequestHandler(const std::string& request_path, int key) : OscReceivingDevice::RequestHandler(request_path), _key(key) {}
|
||||||
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& arguments)
|
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& arguments, const IpEndpointName& remoteEndPoint)
|
||||||
{
|
{
|
||||||
getDevice()->getEventQueue()->keyPress(_key);
|
getDevice()->getEventQueue()->keyPress(_key);
|
||||||
getDevice()->getEventQueue()->keyRelease(_key);
|
getDevice()->getEventQueue()->keyRelease(_key);
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "OscSendingDevice.hpp"
|
#include "OscSendingDevice.hpp"
|
||||||
#include "osc/OscHostEndianness.h"
|
#include "osc/OscHostEndianness.h"
|
||||||
#include <osg/UserDataContainer>
|
#include <osg/UserDataContainer>
|
||||||
#include <osg/ValueObject>
|
#include <osg/ValueObject>
|
||||||
#include <osg/Math>
|
#include <osg/Math>
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
static const unsigned long BUFFER_SIZE = 2048;
|
static const unsigned long BUFFER_SIZE = 2048;
|
||||||
|
|
||||||
@ -27,9 +29,14 @@ OscSendingDevice::OscSendingDevice(const std::string& address, int port, unsigne
|
|||||||
, _oscStream(_buffer, BUFFER_SIZE)
|
, _oscStream(_buffer, BUFFER_SIZE)
|
||||||
, _numMessagesPerEvent(osg::maximum(1u,num_messages_per_event))
|
, _numMessagesPerEvent(osg::maximum(1u,num_messages_per_event))
|
||||||
, _delayBetweenSendsInMilliSecs( (_numMessagesPerEvent > 1) ? delay_between_sends_in_millisecs : 0)
|
, _delayBetweenSendsInMilliSecs( (_numMessagesPerEvent > 1) ? delay_between_sends_in_millisecs : 0)
|
||||||
|
, _msgId(0)
|
||||||
|
, _lastEvent(NULL)
|
||||||
{
|
{
|
||||||
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)";
|
||||||
@ -49,7 +56,6 @@ OscSendingDevice::~OscSendingDevice()
|
|||||||
|
|
||||||
void OscSendingDevice::sendEvent(const osgGA::Event &ea)
|
void OscSendingDevice::sendEvent(const osgGA::Event &ea)
|
||||||
{
|
{
|
||||||
static osc::int64 msg_id(0);
|
|
||||||
bool msg_sent(false);
|
bool msg_sent(false);
|
||||||
unsigned int num_messages = _numMessagesPerEvent;
|
unsigned int num_messages = _numMessagesPerEvent;
|
||||||
|
|
||||||
@ -59,12 +65,12 @@ void OscSendingDevice::sendEvent(const osgGA::Event &ea)
|
|||||||
num_messages = 1;
|
num_messages = 1;
|
||||||
|
|
||||||
for(unsigned int i = 0; i < num_messages; ++i) {
|
for(unsigned int i = 0; i < num_messages; ++i) {
|
||||||
msg_sent = ui_event ? sendUIEventImpl(*ui_event, msg_id) : sendEventImpl(ea, msg_id);
|
msg_sent = ui_event ? sendUIEventImpl(*ui_event, _msgId) : sendEventImpl(ea, _msgId);
|
||||||
if ((_delayBetweenSendsInMilliSecs > 0) && (i < num_messages-1))
|
if ((_delayBetweenSendsInMilliSecs > 0) && (i < num_messages-1))
|
||||||
OpenThreads::Thread::microSleep(1000 * _delayBetweenSendsInMilliSecs);
|
OpenThreads::Thread::microSleep(1000 * _delayBetweenSendsInMilliSecs);
|
||||||
}
|
}
|
||||||
if (msg_sent)
|
if (msg_sent)
|
||||||
msg_id++;
|
_msgId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -158,6 +164,7 @@ 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);
|
||||||
_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;
|
||||||
@ -165,6 +172,7 @@ bool OscSendingDevice::sendUIEventImpl(const osgGA::GUIEventAdapter &ea, MsgIdTy
|
|||||||
|
|
||||||
case osgGA::GUIEventAdapter::RELEASE:
|
case osgGA::GUIEventAdapter::RELEASE:
|
||||||
beginSendInputRange(ea, msg_id);
|
beginSendInputRange(ea, msg_id);
|
||||||
|
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;
|
||||||
@ -180,6 +188,7 @@ 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);
|
||||||
_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;
|
||||||
@ -246,12 +255,16 @@ int OscSendingDevice::getButtonNum(const osgGA::GUIEventAdapter& ea)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OscSendingDevice::beginBundle(MsgIdType msg_id)
|
void OscSendingDevice::beginBundle(MsgIdType msg_id)
|
||||||
{
|
{
|
||||||
_oscStream << osc::BeginBundle();
|
_oscStream << osc::BeginBundle();
|
||||||
_oscStream << osc::BeginMessage("/osc/msg_id") << msg_id << osc::EndMessage;
|
_oscStream << osc::BeginMessage("/osc/msg_id") << msg_id << osc::EndMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea, MsgIdType msg_id)
|
void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea, MsgIdType msg_id)
|
||||||
{
|
{
|
||||||
beginBundle(msg_id);
|
beginBundle(msg_id);
|
||||||
@ -260,6 +273,48 @@ void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea, Msg
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void OscSendingDevice::sendMultiTouchData(const osgGA::GUIEventAdapter &ea)
|
||||||
|
{
|
||||||
|
if(!ea.isMultiTouchEvent())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string application_name;
|
||||||
|
getUserValue("tuio_application_name", application_name);
|
||||||
|
|
||||||
|
if (application_name.empty())
|
||||||
|
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") << "alive";
|
||||||
|
for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i)
|
||||||
|
_oscStream << static_cast<osc::int32>(i->id);
|
||||||
|
_oscStream << osc::EndMessage;
|
||||||
|
|
||||||
|
unsigned int j(0);
|
||||||
|
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 y =(ea.getTouchPointNormalizedY(j) + 1.0) / 2.0;
|
||||||
|
|
||||||
|
float vel_x(0), vel_y(0), accel(0);
|
||||||
|
if (_lastEvent.valid())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_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") << "fseq" << static_cast<osc::int32>(_msgId) << osc::EndMessage;
|
||||||
|
|
||||||
|
_lastEvent = new osgGA::GUIEventAdapter(ea);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class OscSendingDeviceGetValueVisitor : public osg::ValueObject::GetValueVisitor {
|
class OscSendingDeviceGetValueVisitor : public osg::ValueObject::GetValueVisitor {
|
||||||
public:
|
public:
|
||||||
OscSendingDeviceGetValueVisitor(osc::OutboundPacketStream& stream)
|
OscSendingDeviceGetValueVisitor(osc::OutboundPacketStream& stream)
|
||||||
|
@ -14,6 +14,38 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OscSendingDevice can be used to send osg-events via OSC to other hosts/ applications
|
||||||
|
* It can even transmit user-events with attached user-data.
|
||||||
|
*
|
||||||
|
* It uses the TUIO 1.1 Cursor2D-profile to send multitouch-events
|
||||||
|
*
|
||||||
|
* This device adds to every message-bundle a message-id, so you can check, if you miss events or similar.
|
||||||
|
*
|
||||||
|
* sending custom data via an event's user-data:
|
||||||
|
* osgGA::Event* event = new osgGA::Event();
|
||||||
|
* event->setName("/my_user_event");
|
||||||
|
* event->setUserValue("value_1", 23);
|
||||||
|
* event->setUserValue("value_2", 42);
|
||||||
|
* device->sendEvent(event);
|
||||||
|
*
|
||||||
|
* The receiver gets a message-bundle with 2 messages:
|
||||||
|
* /my_user_event/value_1 23
|
||||||
|
* /my_user_event/value_2 42
|
||||||
|
*
|
||||||
|
* The sending device knows how to handle Vec2, Vec3, Vec4, Quat, Plane and Matrix values
|
||||||
|
*
|
||||||
|
* TUIO-specific notes:
|
||||||
|
* If you want to explicitely set the application-name when sending multi-touch-events, use
|
||||||
|
* osc_device->setUserValue("tuio_application_name", "<your application name>");
|
||||||
|
* You'll also have to add the address-part, e.g.
|
||||||
|
* osc_device->setUserValue("tuio_application_name", "my_tuio_application@192.168.1.1");
|
||||||
|
*
|
||||||
|
* @TODO get local address for a correct TUIO-application-name
|
||||||
|
* @TODO implement other TUIO-profiles
|
||||||
|
* @TODO compute velocity + acceleration for TUIO-messages
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <osgGA/Device>
|
#include <osgGA/Device>
|
||||||
@ -33,12 +65,17 @@ 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);
|
||||||
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;
|
||||||
|
|
||||||
UdpTransmitSocket _transmitSocket;
|
UdpTransmitSocket _transmitSocket;
|
||||||
char* _buffer;
|
char* _buffer;
|
||||||
osc::OutboundPacketStream _oscStream;
|
osc::OutboundPacketStream _oscStream;
|
||||||
unsigned int _numMessagesPerEvent, _delayBetweenSendsInMilliSecs;
|
unsigned int _numMessagesPerEvent, _delayBetweenSendsInMilliSecs;
|
||||||
|
osc::int64 _msgId;
|
||||||
|
osg::ref_ptr<osgGA::GUIEventAdapter> _lastEvent;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,12 +30,6 @@
|
|||||||
* dump all registered handlers to the console. The device registers some convenient
|
* dump all registered handlers to the console. The device registers some convenient
|
||||||
* handlers to remote control a p3d-presentation.
|
* handlers to remote control a p3d-presentation.
|
||||||
*
|
*
|
||||||
* you can feed a osgPresentation::PropertyManager into the plugin and set values on it via
|
|
||||||
* "/p3d/set_value key value" or "/p3d/set_value/key value"
|
|
||||||
* Additionally the plugin listens for
|
|
||||||
* "/osg/set_user_value key value" or "/osg/set_user_value/key value" and set the transmitted value on the
|
|
||||||
* UserDataContainer of the device.
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* The plugin supports forwarding most of the events per osc to another host.
|
* The plugin supports forwarding most of the events per osc to another host.
|
||||||
* It uses a special event-handler, which forwards the events. To get this
|
* It uses a special event-handler, which forwards the events. To get this
|
||||||
@ -48,7 +42,6 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - add multitouch support, preferably using the TUIO-protocol
|
|
||||||
* - be more tolerant with given filenames
|
* - be more tolerant with given filenames
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -876,7 +876,7 @@ 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, (1-pos.y) * bounds.size.height);
|
osg::Vec2 pixelPos(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());
|
osg_event = _win->getEventQueue()->touchBegan(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y());
|
||||||
@ -897,7 +897,7 @@ 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, (1 - pos.y) * bounds.size.height);
|
osg::Vec2 pixelPos(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());
|
osg_event = _win->getEventQueue()->touchMoved(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y());
|
||||||
@ -919,7 +919,7 @@ 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, (1 - pos.y) * bounds.size.height);
|
osg::Vec2 pixelPos(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);
|
osg_event = _win->getEventQueue()->touchEnded(touch_id, [self convertTouchPhase: [touch phase]], pixelPos.x(), pixelPos.y(), 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user