1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 */
13
14
15
16 #include "OscSendingDevice.hpp"
17 #include "osc/OscHostEndianness.h"
18 #include <osg/UserDataContainer>
19 #include <osg/ValueObject>
20 #include <osg/Math>
21 #include <osg/Version>
22
23 static const unsigned long BUFFER_SIZE = 2048;
24
OscSendingDevice(const std::string & address,int port,unsigned int num_messages_per_event,unsigned int delay_between_sends_in_millisecs)25 OscSendingDevice::OscSendingDevice(const std::string& address, int port, unsigned int num_messages_per_event, unsigned int delay_between_sends_in_millisecs)
26 : osgGA::Device()
27 , _transmitSocket(IpEndpointName(address.c_str(), port))
28 , _buffer(new char[BUFFER_SIZE])
29 , _oscStream(_buffer, BUFFER_SIZE)
30 , _numMessagesPerEvent(osg::maximum(1u,num_messages_per_event))
31 , _delayBetweenSendsInMilliSecs( (_numMessagesPerEvent > 1) ? delay_between_sends_in_millisecs : 0)
32 , _msgId(0)
33 , _lastEvent(NULL)
34 , _finishMultiTouchSequence(false)
35 {
36 setCapabilities(SEND_EVENTS);
37
38 OSG_NOTICE << "OscDevice :: sending events to " << address << ":" << port << " ";
39 #ifdef OSC_HOST_LITTLE_ENDIAN
40 OSG_NOTICE << "(little endian)";
41 #elif OSC_HOST_BIG_ENDIAN
42 OSG_NOTICE << "(big endian)";
43 #endif
44 OSG_NOTICE << " (" << _numMessagesPerEvent << "msgs/event, " << _delayBetweenSendsInMilliSecs << "ms delay between msgs)";
45 OSG_NOTICE << std::endl;
46
47 }
48
49
~OscSendingDevice()50 OscSendingDevice::~OscSendingDevice()
51 {
52 delete[] (_buffer);
53 }
54
sendEvent(const osgGA::Event & ea)55 void OscSendingDevice::sendEvent(const osgGA::Event &ea)
56 {
57 bool msg_sent(false);
58 unsigned int num_messages = _numMessagesPerEvent;
59
60 const osgGA::GUIEventAdapter* ui_event(ea.asGUIEventAdapter());
61
62 if(ui_event && ((ui_event->getEventType() == osgGA::GUIEventAdapter::DRAG) || (ui_event->getEventType() == osgGA::GUIEventAdapter::MOVE)))
63 num_messages = 1;
64
65 for(unsigned int i = 0; i < num_messages; ++i) {
66 msg_sent = ui_event ? sendUIEventImpl(*ui_event, _msgId) : sendEventImpl(ea, _msgId);
67 if ((_delayBetweenSendsInMilliSecs > 0) && (i < num_messages-1))
68 OpenThreads::Thread::microSleep(1000 * _delayBetweenSendsInMilliSecs);
69 }
70 if (_finishMultiTouchSequence)
71 {
72 // if the last touch-point ended we'll need to send an empty tuio-bundle, so the receiver gets a chance to clean up
73
74 _msgId++;
75 for(unsigned int i = 0; i < num_messages; ++i) {
76 beginBundle(_msgId);
77 beginMultiTouchSequence();
78 _oscStream << osc::EndBundle;
79 _transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
80 _oscStream.Clear();
81 }
82 _finishMultiTouchSequence = false;
83 }
84
85 if (msg_sent)
86 _msgId++;
87 }
88
89
sendEventImpl(const osgGA::Event & ea,MsgIdType msg_id)90 bool OscSendingDevice::sendEventImpl(const osgGA::Event &ea, MsgIdType msg_id)
91 {
92 bool do_send(false);
93 if (ea.getUserDataContainer())
94 {
95 std::string key = ea.getUserDataContainer()->getName();
96 if (key.empty()) key = ea.getName();
97 if (key.empty()) key = "user_data";
98
99 sendUserDataContainer(transliterateKey(key), ea.getUserDataContainer(), true, msg_id);
100
101 do_send = true;
102 }
103
104 if (do_send)
105 {
106 OSG_INFO << "OscDevice :: sending event per OSC " << std::endl;
107
108 _transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
109 _oscStream.Clear();
110 }
111
112 return do_send;
113 }
114
115
116
sendUIEventImpl(const osgGA::GUIEventAdapter & ea,MsgIdType msg_id)117 bool OscSendingDevice::sendUIEventImpl(const osgGA::GUIEventAdapter &ea, MsgIdType msg_id)
118 {
119 bool do_send(false);
120 switch(ea.getEventType())
121 {
122 case osgGA::GUIEventAdapter::RESIZE:
123 beginBundle(msg_id);
124 _oscStream << osc::BeginMessage("/osgga/resize") << ea.getWindowX() << ea.getWindowY() << ea.getWindowWidth() << ea.getWindowHeight() << osc::EndMessage;
125 _oscStream << osc::EndBundle;
126 do_send = true;
127 break;
128
129 case osgGA::GUIEventAdapter::SCROLL:
130 beginSendInputRange(ea, msg_id);
131 _oscStream << osc::BeginMessage("/osgga/mouse/scroll") << ea.getScrollingMotion() << ea.getScrollingDeltaX() << ea.getScrollingDeltaY() << osc::EndMessage;
132 _oscStream << osc::EndBundle;
133 do_send = true;
134 break;
135
136 case osgGA::GUIEventAdapter::PEN_PRESSURE:
137 beginBundle(msg_id);
138 _oscStream
139 << osc::BeginMessage("/osgga/pen/pressure")
140 << ea.getPenPressure()
141 << osc::EndMessage;
142 _oscStream << osc::EndBundle;
143
144 do_send = true;
145 break;
146
147 case osgGA::GUIEventAdapter::PEN_ORIENTATION:
148 beginBundle(msg_id);
149 _oscStream
150 << osc::BeginMessage("/osgga/pen/orientation")
151 << ea.getPenRotation()
152 << ea.getPenTiltX()
153 << ea.getPenTiltY()
154 << osc::EndMessage;
155 do_send = true;
156 _oscStream << osc::EndBundle;
157 break;
158
159 case osgGA::GUIEventAdapter::PEN_PROXIMITY_ENTER:
160 beginBundle(msg_id);
161 _oscStream
162 << osc::BeginMessage("/osgga/pen/proximity/enter")
163 << ea.getTabletPointerType()
164 << osc::EndMessage;
165 do_send = true;
166 break;
167
168 case osgGA::GUIEventAdapter::PEN_PROXIMITY_LEAVE:
169 beginBundle(msg_id);
170 _oscStream
171 << osc::BeginMessage("/osgga/pen/proximity/leave")
172 << ea.getTabletPointerType()
173 << osc::EndMessage;
174 _oscStream << osc::EndBundle;
175 do_send = true;
176 break;
177
178 case osgGA::GUIEventAdapter::PUSH:
179 beginSendInputRange(ea, msg_id);
180 if (!sendMultiTouchData(ea))
181 _oscStream << osc::BeginMessage("/osgga/mouse/press") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
182 _oscStream << osc::EndBundle;
183 do_send = true;
184 break;
185
186 case osgGA::GUIEventAdapter::RELEASE:
187 beginSendInputRange(ea, msg_id);
188 if (!sendMultiTouchData(ea))
189 _oscStream << osc::BeginMessage("/osgga/mouse/release") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
190 _oscStream << osc::EndBundle;
191 do_send = true;
192 break;
193
194 case osgGA::GUIEventAdapter::DOUBLECLICK:
195 beginSendInputRange(ea, msg_id);
196 if (!sendMultiTouchData(ea))
197 _oscStream << osc::BeginMessage("/osgga/mouse/doublepress") << ea.getX() << ea.getY() << getButtonNum(ea) << osc::EndMessage;
198 _oscStream << osc::EndBundle;
199 do_send = true;
200 break;
201
202 case osgGA::GUIEventAdapter::MOVE:
203 case osgGA::GUIEventAdapter::DRAG:
204 beginSendInputRange(ea, msg_id);
205 if (!sendMultiTouchData(ea))
206 _oscStream << osc::BeginMessage("/osgga/mouse/motion") << ea.getX() << ea.getY() << osc::EndMessage;
207 _oscStream << osc::EndBundle;
208 do_send = true;
209 break;
210
211 case osgGA::GUIEventAdapter::KEYDOWN:
212 beginBundle(msg_id);
213 _oscStream << osc::BeginMessage("/osgga/key/press") << ea.getKey() << osc::EndMessage;
214 _oscStream << osc::EndBundle;
215 do_send = true;
216 break;
217
218 case osgGA::GUIEventAdapter::KEYUP:
219 beginBundle(msg_id);
220 _oscStream << osc::BeginMessage("/osgga/key/release") << ea.getKey() << osc::EndMessage;
221 _oscStream << osc::EndBundle;
222 do_send = true;
223 break;
224
225 case osgGA::GUIEventAdapter::USER:
226 if (ea.getUserDataContainer())
227 {
228 std::string key = ea.getUserDataContainer()->getName();
229 if (key.empty()) key = ea.getName();
230 if (key.empty()) key = "user_data";
231
232 sendUserDataContainer(transliterateKey(key), ea.getUserDataContainer(), true, msg_id);
233
234 do_send = true;
235 }
236
237 default:
238 break;
239
240 }
241
242 if (do_send)
243 {
244 _transmitSocket.Send( _oscStream.Data(), _oscStream.Size() );
245 _oscStream.Clear();
246 }
247
248 return do_send;
249 }
250
getButtonNum(const osgGA::GUIEventAdapter & ea)251 int OscSendingDevice::getButtonNum(const osgGA::GUIEventAdapter& ea)
252 {
253 switch(ea.getButton())
254 {
255 case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
256 return 1;
257 break;
258 case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
259 return 2;
260 break;
261 case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
262 return 3;
263 break;
264 default:
265 return -1;
266 }
267 return -1;
268 }
269
270
271
beginBundle(MsgIdType msg_id)272 void OscSendingDevice::beginBundle(MsgIdType msg_id)
273 {
274 _oscStream << osc::BeginBundle();
275 _oscStream << osc::BeginMessage("/osc/msg_id") << msg_id << osc::EndMessage;
276 }
277
278
279
beginSendInputRange(const osgGA::GUIEventAdapter & ea,MsgIdType msg_id)280 void OscSendingDevice::beginSendInputRange(const osgGA::GUIEventAdapter &ea, MsgIdType msg_id)
281 {
282 beginBundle(msg_id);
283 _oscStream << osc::BeginMessage("/osgga/mouse/set_input_range") << ea.getXmin() << ea.getYmin() << ea.getXmax() << ea.getYmax() << osc::EndMessage;
284 _oscStream << osc::BeginMessage("/osgga/mouse/y_orientation_increasing_upwards") << (bool)(ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) << osc::EndMessage;
285 }
286
287
beginMultiTouchSequence()288 void OscSendingDevice::beginMultiTouchSequence() {
289
290 std::string application_name;
291 getUserValue("tuio_application_name", application_name);
292
293 if (application_name.empty())
294 application_name = std::string("OpenSceneGraph ") + osgGetVersion() + "@127.0.0.1";
295
296 _oscStream << osc::BeginMessage("/tuio/2Dcur") << "source" << application_name.c_str() << osc::EndMessage;
297 _oscStream << osc::BeginMessage("/tuio/2Dcur") << "fseq" << static_cast<osc::int32>(_msgId) << osc::EndMessage;
298
299 }
300
301
sendMultiTouchData(const osgGA::GUIEventAdapter & ea)302 bool OscSendingDevice::sendMultiTouchData(const osgGA::GUIEventAdapter &ea)
303 {
304 if(!ea.isMultiTouchEvent())
305 return false;
306
307 beginMultiTouchSequence();
308
309 osgGA::GUIEventAdapter::TouchData* touch_data = ea.getTouchData();
310
311 _oscStream << osc::BeginMessage("/tuio/2Dcur") << "alive";
312 for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i)
313 _oscStream << static_cast<osc::int32>(i->id);
314 _oscStream << osc::EndMessage;
315
316 unsigned int j(0);
317 unsigned int num_ended(0);
318 for(osgGA::GUIEventAdapter::TouchData::iterator i = touch_data->begin(); i != touch_data->end(); ++i, ++j)
319 {
320 float x = (ea.getTouchPointNormalizedX(j) + 1.0) / 2.0;
321 float y =(ea.getTouchPointNormalizedY(j) + 1.0) / 2.0;
322
323 // flip y if origin is not top/left
324 if(ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
325 y *= -1;
326
327 float vel_x(0), vel_y(0), accel(0);
328 if (_lastEvent.valid())
329 {
330 // TODO: add velocity + acceleration
331 }
332
333 _oscStream << osc::BeginMessage("/tuio/2Dcur") << "set" << static_cast<osc::int32>(i->id) << x << y << vel_x << vel_y << accel << osc::EndMessage;
334 if(i->phase == osgGA::GUIEventAdapter::TOUCH_ENDED)
335 num_ended++;
336 }
337
338 _lastEvent = new osgGA::GUIEventAdapter(ea);
339
340 _finishMultiTouchSequence = (num_ended == touch_data->getNumTouchPoints());
341
342
343 return true;
344 }
345
346
347 class OscSendingDeviceGetValueVisitor : public osg::ValueObject::GetValueVisitor {
348 public:
OscSendingDeviceGetValueVisitor(osc::OutboundPacketStream & stream)349 OscSendingDeviceGetValueVisitor(osc::OutboundPacketStream& stream)
350 : osg::ValueObject::GetValueVisitor()
351 , _stream(stream)
352 {
353 }
354
apply(bool value)355 virtual void apply(bool value) { _stream << value; }
apply(char value)356 virtual void apply(char value) { _stream << value; }
apply(unsigned char value)357 virtual void apply(unsigned char value) { _stream << value; }
apply(short value)358 virtual void apply(short value) { _stream << value; }
apply(unsigned short value)359 virtual void apply(unsigned short value) { _stream << value; }
apply(int value)360 virtual void apply(int value) { _stream << value; }
apply(unsigned int value)361 virtual void apply(unsigned int value) { _stream << static_cast<osc::int32>(value); }
apply(float value)362 virtual void apply(float value) { _stream << value; }
apply(double value)363 virtual void apply(double value) { _stream << value; }
apply(const std::string & value)364 virtual void apply(const std::string& value) { _stream << value.c_str(); }
apply(const osg::Vec2f & value)365 virtual void apply(const osg::Vec2f& value) { _stream << value[0] << value[1]; }
apply(const osg::Vec3f & value)366 virtual void apply(const osg::Vec3f& value) { _stream << value[0] << value[1] << value[2]; }
apply(const osg::Vec4f & value)367 virtual void apply(const osg::Vec4f& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
apply(const osg::Vec2d & value)368 virtual void apply(const osg::Vec2d& value) { _stream << value[0] << value[1]; }
apply(const osg::Vec3d & value)369 virtual void apply(const osg::Vec3d& value) { _stream << value[0] << value[1] << value[2]; }
apply(const osg::Vec4d & value)370 virtual void apply(const osg::Vec4d& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
apply(const osg::Quat & value)371 virtual void apply(const osg::Quat& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
apply(const osg::Plane & value)372 virtual void apply(const osg::Plane& value) { _stream << value[0] << value[1] << value[2] << value[3]; }
apply(const osg::Matrixf & value)373 virtual void apply(const osg::Matrixf& value) { for(unsigned int i=0; i<16; ++i) _stream << (value.ptr())[i]; }
apply(const osg::Matrixd & value)374 virtual void apply(const osg::Matrixd& value) { for(unsigned int i=0; i<16; ++i) _stream << (value.ptr())[i]; }
375
~OscSendingDeviceGetValueVisitor()376 virtual ~OscSendingDeviceGetValueVisitor() {}
377
378 private:
379 osc::OutboundPacketStream& _stream;
380
381 };
382
transliterateKey(const std::string & key) const383 std::string OscSendingDevice::transliterateKey(const std::string& key) const
384 {
385 std::string result;
386 result.reserve(key.size());
387 for(std::string::const_iterator itr=key.begin();
388 itr!=key.end();
389 ++itr)
390 {
391 if ((*itr == ' ') || (*itr == 9))
392 result += "-";
393 else if ((*itr >= 'A') && (*itr <= 'Z'))
394 result += tolower(*itr);
395 else if (((*itr >= '0') && (*itr <= '9')) || ((*itr >= 'a') && (*itr <= 'z')) || (*itr == '-') || (*itr == '/') || (*itr == '_'))
396 result += *itr;
397 }
398 return result;
399 }
400
sendUserDataContainer(const std::string & key,const osg::UserDataContainer * udc,bool asBundle,MsgIdType msg_id)401 void OscSendingDevice::sendUserDataContainer(const std::string& key, const osg::UserDataContainer* udc, bool asBundle, MsgIdType msg_id)
402 {
403 if (asBundle) {
404 beginBundle(msg_id);
405 }
406
407 OscSendingDeviceGetValueVisitor gvv(_oscStream);
408
409 unsigned int num_objects = udc->getNumUserObjects();
410 for(unsigned int i = 0; i < num_objects; ++i)
411 {
412 const osg::Object* o = udc->getUserObject(i);
413 const osg::UserDataContainer* child_udc = dynamic_cast<const osg::UserDataContainer*>(o);
414 if (child_udc)
415 {
416 std::string new_key = key + "/" + (child_udc->getName().empty() ? "user_data" : child_udc->getName());
417 sendUserDataContainer(transliterateKey(key), child_udc, false, msg_id);
418 }
419 else if (const osg::ValueObject* vo = dynamic_cast<const osg::ValueObject*>(o))
420 {
421 _oscStream << osc::BeginMessage(std::string("/" + key + "/" + transliterateKey(vo->getName())).c_str());
422 vo->get(gvv);
423 _oscStream << osc::EndMessage;
424 }
425 }
426
427 if (asBundle)
428 _oscStream << osc::EndBundle;
429
430 }
431