From Stephan Huber, New OscSendingDevice and OscReceivingDevice classes

This commit is contained in:
Robert Osfield
2012-11-28 13:28:20 +00:00
parent 8b231ba8e3
commit 7ffde8abce
4 changed files with 1295 additions and 0 deletions

View File

@@ -0,0 +1,858 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include "OscReceivingDevice.hpp"
#include <OpenThreads/Thread>
#include <osg/UserDataContainer>
#include <osg/ValueObject>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgPresentation/PropertyManager>
#include "osc/OscPrintReceivedElements.h"
#include "osc/OscHostEndianness.h"
template <class T, int SIZE>
struct NativeTypeTraits {
typedef T type;
static T create(const std::vector<T>& t) { return type(t); }
};
template<>
struct NativeTypeTraits<float,2> {
typedef osg::Vec2f type;
static type create(const std::vector<float>& t) { return type(t[0], t[1]); }
};
template<>
struct NativeTypeTraits<float,3> {
typedef osg::Vec3f type;
static type create(const std::vector<float>& t) { return type(t[0], t[1], t[2]); }
};
template<>
struct NativeTypeTraits<float,4> {
typedef osg::Vec4f type;
static type create(const std::vector<float>& t) { return type(t[0], t[1], t[2], t[3]); }
};
template<>
struct NativeTypeTraits<float,16> {
typedef osg::Matrixf type;
static type create(const std::vector<float>& t) { return type(&t.front()); }
};
template<>
struct NativeTypeTraits<double,2> {
typedef osg::Vec2d type;
static type create(const std::vector<double>& t) { return type(t[0], t[1]); }
};
template<>
struct NativeTypeTraits<double,3> {
typedef osg::Vec3d type;
static type create(const std::vector<double>& t) { return type(t[0], t[1], t[2]); }
};
template<>
struct NativeTypeTraits<double,4> {
typedef osg::Vec4d type;
static type create(const std::vector<double>& t) { return type(t[0], t[1], t[2], t[3]); }
};
template<>
struct NativeTypeTraits<double,16> {
typedef osg::Matrixd type;
static type create(const std::vector<double>& t) { return type(&t.front()); }
};
class StandardRequestHandler : public OscReceivingDevice::RequestHandler {
public:
StandardRequestHandler(const std::string& request_handler, bool treat_first_argument_as_value_name)
: OscReceivingDevice::RequestHandler(request_handler)
, _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 void describeTo(std::ostream& out) const
{
out << getRequestPath() << ": add all transmitted arguments as ValueObjects to an USER-event";
if (_treatFirstArgumentAsValueName)
out << ", the first argument is used as the name of the value, if it's a string";
}
private:
void addArgumentToUdc(osg::UserDataContainer* udc, const std::string& key, const osc::ReceivedMessageArgumentIterator& itr);
template <class T>
bool addNativeTypeFromVector(osg::UserDataContainer* udc, const std::string& key, const std::vector<T>& arr)
{
switch (arr.size()) {
case 2:
udc->setUserValue(key, NativeTypeTraits<T,2>::create(arr));
return true;
break;
case 3:
udc->setUserValue(key, NativeTypeTraits<T,3>::create(arr));
return true;
break;
case 4:
udc->setUserValue(key, NativeTypeTraits<T,4>::create(arr));
return true;
break;
case 16:
udc->setUserValue(key, NativeTypeTraits<T,16>::create(arr));
return true;
break;
default:
return false;
}
return false;
}
bool _treatFirstArgumentAsValueName;
};
bool StandardRequestHandler::operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try
{
std::string path = osgDB::getFilePath(full_request_path);
std::string last_elem = osgDB::getSimpleFileName(full_request_path);
osg::ref_ptr<osgGA::GUIEventAdapter> ea = getDevice()->getOrCreateUserDataEvent();
osg::UserDataContainer* udc = ea->getOrCreateUserDataContainer();
ea->setName(_treatFirstArgumentAsValueName ? full_request_path : path);
udc->setName(ea->getName());
if (m.ArgumentCount() == 0) {
return true;
}
// if we have only one argument, get it and save it to the udc
else if (m.ArgumentCount() == 1)
{
addArgumentToUdc(udc, last_elem, m.ArgumentsBegin());
return true;
}
else
{
unsigned int i(0);
osc::ReceivedMessageArgumentIterator start = m.ArgumentsBegin();
if ((_treatFirstArgumentAsValueName) && (start->TypeTag() == osc::STRING_TYPE_TAG))
{
last_elem = start->AsString();
++start;
// if we hav only 2 arguments, then save the value and return
if (m.ArgumentCount() == 2)
{
addArgumentToUdc(udc, last_elem, start);
return true;
}
}
std::vector<float> float_vec;
std::vector<double> double_vec;
bool mixed_arguments(false);
for(osc::ReceivedMessageArgumentIterator itr = start; itr != m.ArgumentsEnd(); ++itr, ++i)
{
if(itr->TypeTag() == osc::FLOAT_TYPE_TAG)
{
float_vec.push_back(itr->AsFloat());
}
else if(itr->TypeTag() == osc::DOUBLE_TYPE_TAG)
{
double_vec.push_back(itr->AsDouble());
}
else if(itr->TypeTag() == osc::INT32_TYPE_TAG)
{
float_vec.push_back(itr->AsInt32());
}
else {
mixed_arguments = true;
break;
}
}
if (!mixed_arguments)
{
unsigned int sum = float_vec.size() + double_vec.size();
if (sum == float_vec.size())
{
if (addNativeTypeFromVector(udc, last_elem, float_vec))
return true;
}
else if (sum == double_vec.size())
{
if (addNativeTypeFromVector(udc, last_elem, double_vec))
return true;
}
}
for(osc::ReceivedMessageArgumentIterator itr = start; itr != m.ArgumentsEnd(); ++itr, ++i)
{
std::ostringstream ss;
ss << last_elem << "_" << i;
addArgumentToUdc(udc, ss.str(), itr);
}
}
return true;
}
catch(osc::Exception& e)
{
handleException(e);
return false;
}
return false;
}
void StandardRequestHandler::addArgumentToUdc(osg::UserDataContainer* udc, const std::string& key, const osc::ReceivedMessageArgumentIterator& itr)
{
switch((*itr).TypeTag())
{
case osc::TRUE_TYPE_TAG:
udc->setUserValue(key, true);
break;
case osc::FALSE_TYPE_TAG:
udc->setUserValue(key, false);
break;
case osc::INT32_TYPE_TAG:
udc->setUserValue(key, (int)((*itr).AsInt32Unchecked()));
break;
case osc::FLOAT_TYPE_TAG:
udc->setUserValue(key, (*itr).AsFloatUnchecked());
break;
case osc::CHAR_TYPE_TAG:
udc->setUserValue(key, (*itr).AsCharUnchecked());
break;
case osc::RGBA_COLOR_TYPE_TAG:
// TODO: should we convert the color to an osg::Vec4?
udc->setUserValue(key, static_cast<unsigned int>((*itr).AsRgbaColorUnchecked()));
break;
case osc::INT64_TYPE_TAG:
// TODO 64bit ints not supported by ValueObject
udc->setUserValue(key, static_cast<double>((*itr).AsInt64Unchecked()));
break;
case osc::TIME_TAG_TYPE_TAG:
// TODO 64bit ints not supported by ValueObject
udc->setUserValue(key, static_cast<double>((*itr).AsTimeTagUnchecked()));
break;
case osc::DOUBLE_TYPE_TAG:
udc->setUserValue(key, (*itr).AsDoubleUnchecked());
break;
case osc::STRING_TYPE_TAG:
udc->setUserValue(key, std::string((*itr).AsStringUnchecked()));
break;
case osc::SYMBOL_TYPE_TAG:
udc->setUserValue(key, std::string((*itr).AsSymbol()));
break;
default:
break;
}
}
class SetMouseInputRangeRequestHandler : public OscReceivingDevice::RequestHandler {
public:
SetMouseInputRangeRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/mouse/set_input_range")
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
float x_min(-1.0f), y_min(-1.0f), x_max(1.0f), y_max(1.0f);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> x_min >> y_min >> x_max >> y_max >> osc::EndMessage;
getDevice()->getEventQueue()->setMouseInputRange(x_min, y_min, x_max, y_max);
return true;
}
catch(osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float x_min, float y_min, float x_max, float y_max): sets the mouse-input-range" << std::dec;
}
};
class SetMouseOrientationRequestHandler : public OscReceivingDevice::RequestHandler {
public:
SetMouseOrientationRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/mouse/y_orientation_increasing_upwards")
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
bool increasing_upwards(false);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >>increasing_upwards >> osc::EndMessage;
getDevice()->getEventQueue()->getCurrentEventState()->setMouseYOrientation(
increasing_upwards ? osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS : osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
return true;
}
catch(osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float x_min, float y_min, float x_max, float y_max): sets the mouse-input-range" << std::dec;
}
};
class KeyCodeRequestHandler : public OscReceivingDevice::RequestHandler {
public:
KeyCodeRequestHandler(bool handle_key_press)
: OscReceivingDevice::RequestHandler(std::string("/osgga/key/") + ((handle_key_press) ? "press" : "release"))
, _handleKeyPress(handle_key_press)
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
osc::int32 keycode(0);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> keycode >> osc::EndMessage;
if (_handleKeyPress)
getDevice()->getEventQueue()->keyPress(keycode, getLocalTime());
else
getDevice()->getEventQueue()->keyRelease(keycode, getLocalTime());
return true;
}
catch(osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(int keycode): send KEY_" << (_handleKeyPress ? "DOWN" : "UP");
}
private:
bool _handleKeyPress;
};
class KeyPressAndReleaseRequestHandler : public OscReceivingDevice::RequestHandler {
public:
KeyPressAndReleaseRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/key/press_and_release")
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
osc::int32 keycode(0);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> keycode >> osc::EndMessage;
getDevice()->getEventQueue()->keyPress(keycode, getLocalTime());
getDevice()->getEventQueue()->keyRelease(keycode, getLocalTime());
return true;
}
catch(osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(int keycode): send KEY_DOWN and KEY_UP";
}
private:
bool _handleKeyPress;
};
class MouseMotionRequestHandler : public OscReceivingDevice::RequestHandler {
public:
MouseMotionRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/mouse/motion")
, _lastX(0.0f)
, _lastY(0.0f)
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> _lastX >> _lastY >> osc::EndMessage;
getDevice()->getEventQueue()->mouseMotion(_lastX, _lastY, getLocalTime());
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float x, float y): send mouse motion";
}
float getLastX() const { return _lastX; }
float getLastY() const { return _lastY; }
private:
float _lastX, _lastY;
};
class MouseScrollRequestHandler : public OscReceivingDevice::RequestHandler {
public:
MouseScrollRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/mouse/scroll")
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
osc::int32 sm(osgGA::GUIEventAdapter::SCROLL_NONE);
float delta_x(0.0f), delta_y(0.0f);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> sm >> delta_x >> delta_y >> osc::EndMessage;
if (sm != osgGA::GUIEventAdapter::SCROLL_NONE)
getDevice()->getEventQueue()->mouseScroll((osgGA::GUIEventAdapter::ScrollingMotion)sm, getLocalTime());
if ((delta_x != 0.0f) || (delta_y != 0.0f))
getDevice()->getEventQueue()->mouseScroll2D(delta_x, delta_y, getLocalTime());
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(int scroll_motion, float x, float y): send mouse scroll-motion";
}
};
class MouseButtonToggleRequestHandler : public OscReceivingDevice::RequestHandler {
public:
MouseButtonToggleRequestHandler(const std::string& btn_name, MouseMotionRequestHandler* mm_handler)
: OscReceivingDevice::RequestHandler("/osgga/mouse/toggle/"+btn_name)
, _mmHandler(mm_handler)
, _btnNum(atoi(btn_name.c_str()))
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
float down(0.0f);
try {
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> down >> osc::EndMessage;
if (down > 0)
getDevice()->getEventQueue()->mouseButtonPress(_mmHandler->getLastX(), _mmHandler->getLastY(), _btnNum, getLocalTime());
else
getDevice()->getEventQueue()->mouseButtonRelease(_mmHandler->getLastX(), _mmHandler->getLastY(), _btnNum, getLocalTime());
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float down): toggle mouse button";
}
private:
osg::observer_ptr<MouseMotionRequestHandler> _mmHandler;
int _btnNum;
};
class MouseButtonRequestHandler : public OscReceivingDevice::RequestHandler {
public:
enum Mode { PRESS, RELEASE, DOUBLE_PRESS};
MouseButtonRequestHandler(Mode mode)
: OscReceivingDevice::RequestHandler("")
, _mode(mode)
{
switch(mode) {
case PRESS:
setRequestPath("/osgga/mouse/press");
break;
case RELEASE:
setRequestPath("/osgga/mouse/release");
break;
case DOUBLE_PRESS:
setRequestPath("/osgga/mouse/doublepress");
break;
}
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
float x(0.0f), y(0.0f);
osc::int32 btn(0);
try {
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> x >> y >> btn >> osc::EndMessage;
switch (_mode) {
case PRESS:
getDevice()->getEventQueue()->mouseButtonPress(x,y, btn, getLocalTime());
break;
case RELEASE:
getDevice()->getEventQueue()->mouseButtonRelease(x,y, btn, getLocalTime());
break;
case DOUBLE_PRESS:
getDevice()->getEventQueue()->mouseDoubleButtonPress(x,y, btn, getLocalTime());
break;
}
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float x, float y, int btn): send mouse ";
switch (_mode) {
case PRESS:
out << "press"; break;
case RELEASE:
out << "release"; break;
case DOUBLE_PRESS:
out << "double press"; break;
}
}
private:
Mode _mode;
};
class PenPressureRequestHandler : public OscReceivingDevice::RequestHandler {
public:
PenPressureRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/pen/pressure")
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
float pressure(0.0f);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> pressure >> osc::EndMessage;
getDevice()->getEventQueue()->penPressure(pressure, getLocalTime());
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float pressure): send pen pressure";
}
};
class PenProximityRequestHandler : public OscReceivingDevice::RequestHandler {
public:
PenProximityRequestHandler(bool handle_enter)
: OscReceivingDevice::RequestHandler(std::string("/osgga/pen/proximity/") + ((handle_enter) ? std::string("enter") : std::string("leave")))
, _handleEnter(handle_enter)
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
osc::int32 pt(osgGA::GUIEventAdapter::UNKNOWN);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> pt >> osc::EndMessage;
getDevice()->getEventQueue()->penProximity((osgGA::GUIEventAdapter::TabletPointerType)pt, _handleEnter, getLocalTime());
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(int table_pointer_type): send pen proximity " << (_handleEnter ? "enter":"leave");
}
private:
bool _handleEnter;
};
class PenOrientationRequestHandler : public OscReceivingDevice::RequestHandler {
public:
PenOrientationRequestHandler()
: OscReceivingDevice::RequestHandler("/osgga/pen/orientation")
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m)
{
try {
float rotation(0.0f), tilt_x(0.0f), tilt_y(0.0f);
osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
args >> rotation >> tilt_x >> tilt_y >> osc::EndMessage;
getDevice()->getEventQueue()->penOrientation(tilt_x, tilt_y, rotation, getLocalTime());
return true;
}
catch (osc::Exception e) {
handleException(e);
}
return false;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << "(float rotation, float tilt_x, float tilt_y): send pen orientation";
}
};
OscReceivingDevice::OscReceivingDevice(const std::string& server_address, int listening_port)
: osgGA::Device()
, OpenThreads::Thread()
, osc::OscPacketListener()
, _listeningAddress(server_address)
, _listeningPort(listening_port)
, _socket(NULL)
, _map()
{
setCapabilities(RECEIVE_EVENTS);
OSG_NOTICE << "OscDevice :: listening on " << server_address << ":" << listening_port << " ";
#ifdef OSC_HOST_LITTLE_ENDIAN
OSG_NOTICE << "(little endian)";
#elif OSC_HOST_BIG_ENDIAN
OSG_NOTICE << "(big endian)";
#endif
OSG_NOTICE << std::endl;
_socket = new UdpListeningReceiveSocket(IpEndpointName( server_address.c_str(), listening_port ), this);
addRequestHandler(new KeyCodeRequestHandler(false));
addRequestHandler(new KeyCodeRequestHandler(true));
addRequestHandler(new KeyPressAndReleaseRequestHandler());
addRequestHandler(new SetMouseInputRangeRequestHandler());
addRequestHandler(new SetMouseOrientationRequestHandler());
MouseMotionRequestHandler* mm_handler = new MouseMotionRequestHandler();
addRequestHandler(mm_handler);
addRequestHandler(new MouseButtonRequestHandler(MouseButtonRequestHandler::PRESS));
addRequestHandler(new MouseButtonRequestHandler(MouseButtonRequestHandler::RELEASE));
addRequestHandler(new MouseButtonRequestHandler(MouseButtonRequestHandler::DOUBLE_PRESS));
addRequestHandler(new MouseScrollRequestHandler());
addRequestHandler(new MouseButtonToggleRequestHandler("1", mm_handler));
addRequestHandler(new MouseButtonToggleRequestHandler("2", mm_handler));
addRequestHandler(new MouseButtonToggleRequestHandler("3", mm_handler));
addRequestHandler(new PenPressureRequestHandler());
addRequestHandler(new PenOrientationRequestHandler());
addRequestHandler(new PenProximityRequestHandler(true));
addRequestHandler(new PenProximityRequestHandler(false));
addRequestHandler(new StandardRequestHandler("/osg/set_user_value", true));
addRequestHandler(new StandardRequestHandler("", false));
start();
}
OscReceivingDevice::~OscReceivingDevice()
{
_socket->AsynchronousBreak();
join();
delete _socket;
}
void OscReceivingDevice::run()
{
_socket->Run();
}
void OscReceivingDevice::ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
{
std::string in_request_path(m.AddressPattern());
std::string request_path = in_request_path + "/";
std::size_t pos(std::string::npos);
bool handled(false);
do {
pos = request_path.find_last_of('/', pos-1);
if (pos != std::string::npos)
{
std::string mangled_path = request_path.substr(0, pos);
std::pair<RequestHandlerMap::iterator,RequestHandlerMap::iterator> range = _map.equal_range(mangled_path);
for(RequestHandlerMap::iterator i = range.first; i != range.second; ++i)
{
// OSG_INFO << "OscDevice :: handling " << mangled_path << " with " << i->second << std::endl;
if (i->second->operator()(mangled_path, in_request_path, m) && !handled)
handled = true;
}
}
} while ((pos != std::string::npos) && (pos > 0) && !handled);
}
void OscReceivingDevice::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint )
{
OSG_INFO << "OscDevice :: receiving " << size << " bytes of data ..." << std::endl;
try {
osc::OscPacketListener::ProcessPacket(data, size, remoteEndpoint);
}
catch(const osc::Exception& e) {
OSG_WARN << "OscDevice :: could not process UDP-packet: " << e.what() << std::endl;
}
catch(...) {
OSG_WARN << "OscDevice :: could not process UDP-packet because of an exception!" << std::endl;
}
if (_userDataEvent.valid())
{
char address[IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH];
remoteEndpoint.AddressAndPortAsString(address);
_userDataEvent->setUserValue("osc/remote_end_point", std::string(address));
getEventQueue()->addEvent(_userDataEvent.get());
_userDataEvent = NULL;
}
}
void OscReceivingDevice::addRequestHandler(RequestHandler* handler)
{
if (handler)
{
_map.insert(std::make_pair(handler->getRequestPath(), handler));
handler->setDevice(this);
}
}
void OscReceivingDevice::describeTo(std::ostream& out) const
{
out << "OscDevice :: listening on " << _listeningAddress << ":" << _listeningPort << std::endl;
out << std::endl;
for(RequestHandlerMap::const_iterator i = _map.begin(); i != _map.end(); ++i)
{
const RequestHandler* handler(i->second.get());
out << "OscDevice :: ";
handler->describeTo(out);
out << std::endl;
}
}

View File

@@ -0,0 +1,127 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#pragma once
#include <osg/Referenced>
#include <OpenThreads/Thread>
#include <osgGA/Device>
#include <osc/OscPacketListener.h>
#include <ip/UdpSocket.h>
class OscReceivingDevice : public osgGA::Device, OpenThreads::Thread, osc::OscPacketListener {
public:
class RequestHandler : public osg::Referenced {
public:
RequestHandler(const std::string& request_path)
: osg::Referenced()
, _requestPath(request_path)
, _device(NULL)
{
}
virtual bool operator()(const std::string& request_path, const std::string& full_request_path, const osc::ReceivedMessage& m) = 0;
const std::string& getRequestPath() const { return _requestPath; }
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << ": no description available";
}
protected:
void setDevice(OscReceivingDevice* device) { _device = device; }
OscReceivingDevice* getDevice() const { return _device; }
/// set the request-path, works only from the constructor
void setRequestPath(const std::string& request_path) { _requestPath = request_path; }
void handleException(const osc::Exception& e)
{
OSG_WARN << "OscDevice :: error while handling " << getRequestPath() << ": " << e.what() << std::endl;
}
double getLocalTime() const { return getDevice()->getEventQueue()->getTime(); }
private:
std::string _requestPath;
OscReceivingDevice* _device;
friend class OscReceivingDevice;
};
typedef std::multimap<std::string, osg::ref_ptr<RequestHandler> > RequestHandlerMap;
OscReceivingDevice(const std::string& server_address, int listening_port);
~OscReceivingDevice();
virtual void checkEvents() {}
virtual void run();
virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint );
virtual void ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint );
void addRequestHandler(RequestHandler* handler);
void describeTo(std::ostream& out) const;
friend std::ostream& operator<<(std::ostream& out, const OscReceivingDevice& device)
{
device.describeTo(out);
return out;
}
osgGA::GUIEventAdapter* getOrCreateUserDataEvent()
{
if (!_userDataEvent.valid())
{
_userDataEvent = new osgGA::GUIEventAdapter();
_userDataEvent->setEventType(osgGA::GUIEventAdapter::USER);
}
return _userDataEvent.get();
}
private:
std::string _listeningAddress;
unsigned int _listeningPort;
UdpListeningReceiveSocket* _socket;
RequestHandlerMap _map;
osg::ref_ptr<osgGA::GUIEventAdapter> _userDataEvent;
};
class SendKeystrokeRequestHandler : public OscReceivingDevice::RequestHandler {
public:
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)
{
getDevice()->getEventQueue()->keyPress(_key);
getDevice()->getEventQueue()->keyRelease(_key);
return true;
}
virtual void describeTo(std::ostream& out) const
{
out << getRequestPath() << ": send KEY_DOWN + KEY_UP, code: 0x" << std::hex << _key << std::dec;
}
private:
int _key;
};

View File

@@ -0,0 +1,271 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include "OscSendingDevice.hpp"
#include "osc/OscHostEndianness.h"
#include <osg/UserDataContainer>
#include <osg/ValueObject>
static const unsigned long BUFFER_SIZE = 2048;
OscSendingDevice::OscSendingDevice(const std::string& address, int port)
: osgGA::Device()
, _transmitSocket(IpEndpointName(address.c_str(), port))
, _buffer(new char[BUFFER_SIZE])
, _oscStream(_buffer, BUFFER_SIZE)
, _firstRun(true)
{
setCapabilities(SEND_EVENTS);
OSG_NOTICE << "OscDevice :: sending events to " << address << ":" << port << " ";
#ifdef OSC_HOST_LITTLE_ENDIAN
OSG_NOTICE << "(little endian)";
#elif OSC_HOST_BIG_ENDIAN
OSG_NOTICE << "(big endian)";
#endif
OSG_NOTICE << std::endl;
}
OscSendingDevice::~OscSendingDevice()
{
delete[] (_buffer);
}
void OscSendingDevice::sendEvent(const osgGA::GUIEventAdapter &ea)
{
bool do_send(false);
switch(ea.getEventType())
{
case osgGA::GUIEventAdapter::RESIZE:
sendInit(ea);
do_send = true;
break;
case osgGA::GUIEventAdapter::SCROLL:
_oscStream << osc::BeginMessage("/osgga/mouse/scroll") << ea.getScrollingMotion() << ea.getScrollingDeltaX() << ea.getScrollingDeltaY() << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::PEN_PRESSURE:
_oscStream
<< osc::BeginMessage("/osgga/pen/pressure")
<< ea.getPenPressure()
<< osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::PEN_ORIENTATION:
_oscStream
<< osc::BeginMessage("/osgga/pen/orientation")
<< ea.getPenRotation()
<< ea.getPenTiltX()
<< ea.getPenTiltY()
<< osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::PEN_PROXIMITY_ENTER:
_oscStream
<< osc::BeginMessage("/osgga/pen/proximity/enter")
<< ea.getTabletPointerType()
<< osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::PEN_PROXIMITY_LEAVE:
_oscStream
<< osc::BeginMessage("/osgga/pen/proximity/leave")
<< ea.getTabletPointerType()
<< osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::PUSH:
_oscStream << osc::BeginMessage("/osgga/mouse/press") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::RELEASE:
_oscStream << osc::BeginMessage("/osgga/mouse/release") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::DOUBLECLICK:
_oscStream << osc::BeginMessage("/osgga/mouse/doublepress") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::MOVE:
if (_firstRun)
{
_firstRun = false;
sendInit(ea);
do_send = true;
break;
}
// break missing by intent;
case osgGA::GUIEventAdapter::DRAG:
_oscStream << osc::BeginMessage("/osgga/mouse/motion") << ea.getX() << ea.getY() << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::KEYDOWN:
_oscStream << osc::BeginMessage("/osgga/key/press") << ea.getKey() << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::KEYUP:
_oscStream << osc::BeginMessage("/osgga/key/release") << ea.getKey() << osc::EndMessage;
do_send = true;
break;
case osgGA::GUIEventAdapter::USER:
if (ea.getUserDataContainer())
{
std::string key = ea.getUserDataContainer()->getName();
if (key.empty()) key = ea.getName();
if (key.empty()) key = "user_data";
sendUserDataContainer(transliterateKey(key), ea.getUserDataContainer(), true);
do_send = true;
}
default:
break;
}
if (do_send)
{
OSG_INFO << "OscDevice :: sending event per OSC " << std::endl;
_transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
_oscStream.Clear();
}
}
int OscSendingDevice::getButtonNum(const osgGA::GUIEventAdapter& ea)
{
switch(ea.getButton())
{
case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
return 1;
break;
case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
return 2;
break;
case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
return 3;
break;
default:
return -1;
}
return -1;
}
void OscSendingDevice::sendInit(const osgGA::GUIEventAdapter &ea)
{
_oscStream << osc::BeginBundle();
_oscStream << osc::BeginMessage("/osgga/resize") << ea.getWindowX() << ea.getWindowY() << ea.getWindowWidth() << ea.getWindowHeight() << osc::EndMessage;
_oscStream << osc::BeginMessage("/osgga/mouse/set_input_range") << ea.getXmin() << ea.getYmin() << ea.getXmax() << ea.getYmax() << osc::EndMessage;
_oscStream << osc::BeginMessage("/osgga/mouse/y_orientation_increasing_upwards") << (bool)(ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) << osc::EndMessage;
_oscStream << osc::EndBundle;
}
class OscSendingDeviceGetValueVisitor : public osg::ValueObject::GetValueVisitor {
public:
OscSendingDeviceGetValueVisitor(osc::OutboundPacketStream& stream)
: osg::ValueObject::GetValueVisitor()
, _stream(stream)
{
}
virtual void apply(bool value) { _stream << value; }
virtual void apply(char value) { _stream << value; }
virtual void apply(unsigned char value) { _stream << value; }
virtual void apply(short value) { _stream << value; }
virtual void apply(unsigned short value) { _stream << value; }
virtual void apply(int value) { _stream << value; }
virtual void apply(unsigned int value) { _stream << static_cast<osc::int32>(value); }
virtual void apply(float value) { _stream << value; }
virtual void apply(double value) { _stream << value; }
virtual void apply(const std::string& value) { _stream << value.c_str(); }
virtual void apply(const osg::Vec2f& value) { _stream << value[0] << value[1]; }
virtual void apply(const osg::Vec3f& value) { _stream << value[0] << value[1] << value[2]; }
virtual void apply(const osg::Vec4f& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
virtual void apply(const osg::Vec2d& value) { _stream << value[0] << value[1]; }
virtual void apply(const osg::Vec3d& value) { _stream << value[0] << value[1] << value[2]; }
virtual void apply(const osg::Vec4d& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
virtual void apply(const osg::Quat& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
virtual void apply(const osg::Plane& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
virtual void apply(const osg::Matrixf& value) { for(unsigned int i=0; i<16; ++i) _stream << (value.ptr())[i]; }
virtual void apply(const osg::Matrixd& value) { for(unsigned int i=0; i<16; ++i) _stream << (value.ptr())[i]; }
private:
osc::OutboundPacketStream& _stream;
};
std::string OscSendingDevice::transliterateKey(const std::string& key) const
{
std::string result;
result.reserve(key.size());
for(std::string::const_iterator itr=key.begin();
itr!=key.end();
++itr)
{
if ((*itr == ' ') || (*itr == 9))
result += "-";
else if ((*itr >= 'A') && (*itr <= 'Z'))
result += tolower(*itr);
else if (((*itr >= '0') && (*itr <= '9')) || ((*itr >= 'a') && (*itr <= 'z')) || (*itr == '-') || (*itr == '/') || (*itr == '_'))
result += *itr;
}
return result;
}
void OscSendingDevice::sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle)
{
if (asBundle)
_oscStream << osc::BeginBundle();
OscSendingDeviceGetValueVisitor gvv(_oscStream);
unsigned int num_objects = udc->getNumUserObjects();
for(unsigned int i = 0; i < num_objects; ++i)
{
const osg::Object* o = udc->getUserObject(i);
const osg::UserDataContainer* child_udc = dynamic_cast<const osg::UserDataContainer*>(o);
if (child_udc)
{
std::string new_key = key + "/" + (child_udc->getName().empty() ? "user_data" : child_udc->getName());
sendUserDataContainer(transliterateKey(key), child_udc, false);
}
else if (const osg::ValueObject* vo = dynamic_cast<const osg::ValueObject*>(o))
{
_oscStream << osc::BeginMessage(std::string("/" + key + "/" + transliterateKey(vo->getName())).c_str());
vo->get(gvv);
_oscStream << osc::EndMessage;
}
}
if (asBundle)
_oscStream << osc::EndBundle;
}

View File

@@ -0,0 +1,39 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#pragma once
#include <osgGA/Device>
#include <ip/UdpSocket.h>
#include <osc/OscOutboundPacketStream.h>
class OscSendingDevice : public osgGA::Device {
public:
OscSendingDevice(const std::string& address, int port);
~OscSendingDevice();
virtual void sendEvent(const osgGA::GUIEventAdapter &ea);
private:
void sendInit(const osgGA::GUIEventAdapter& ea);
int getButtonNum(const osgGA::GUIEventAdapter& ea);
void sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle);
std::string transliterateKey(const std::string& key) const;
UdpTransmitSocket _transmitSocket;
char* _buffer;
osc::OutboundPacketStream _oscStream;
bool _firstRun;
};