1 /* OpenSceneGraph example, osgcluster.
2 *
3 *  Permission is hereby granted, free of charge, to any person obtaining a copy
4 *  of this software and associated documentation files (the "Software"), to deal
5 *  in the Software without restriction, including without limitation the rights
6 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 *  copies of the Software, and to permit persons to whom the Software is
8 *  furnished to do so, subject to the following conditions:
9 *
10 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 *  THE SOFTWARE.
17 */
18 
19 #ifdef USE_MEM_CHECK
20 #include <mcheck.h>
21 #endif
22 
23 #include <osg/Group>
24 #include <osg/Notify>
25 
26 #include <osgDB/Registry>
27 #include <osgDB/ReadFile>
28 
29 #include <osgGA/TrackballManipulator>
30 #include <osgGA/StateSetManipulator>
31 #include <osgViewer/Viewer>
32 #include <osgViewer/ViewerEventHandlers>
33 
34 #include <osg/Quat>
35 #include <osg/io_utils>
36 
37 #include <iostream>
38 
39 #if defined (WIN32) && !defined(__CYGWIN__)
40 #include <winsock.h>
41 #endif
42 
43 #include "receiver.h"
44 #include "broadcaster.h"
45 
46 
47 const unsigned int SWAP_BYTES_COMPARE = 0x12345678;
48 class CameraPacket {
49     public:
50 
51 
CameraPacket()52         CameraPacket():_masterKilled(false)
53         {
54             _byte_order = SWAP_BYTES_COMPARE;
55         }
56 
setPacket(const osg::Matrix & matrix,const osg::FrameStamp * frameStamp)57         void setPacket(const osg::Matrix& matrix,const osg::FrameStamp* frameStamp)
58         {
59             _matrix = matrix;
60             if (frameStamp)
61             {
62                 _frameStamp    = *frameStamp;
63             }
64         }
65 
getModelView(osg::Matrix & matrix,float angle_offset=0.0f)66         void getModelView(osg::Matrix& matrix,float angle_offset=0.0f)
67         {
68 
69             matrix = _matrix * osg::Matrix::rotate(osg::DegreesToRadians(angle_offset),0.0f,1.0f,0.0f);
70         }
71 
72         void readEventQueue(osgViewer::Viewer& viewer);
73 
74         void writeEventQueue(osgViewer::Viewer& viewer);
75 
setMasterKilled(const bool flag)76         void setMasterKilled(const bool flag) { _masterKilled = flag; }
getMasterKilled() const77         bool getMasterKilled() const { return _masterKilled; }
78 
79         unsigned int    _byte_order;
80         bool            _masterKilled;
81         osg::Matrix     _matrix;
82 
83         // note don't use a ref_ptr as used elsewhere for FrameStamp
84         // since we don't want to copy the pointer - but the memory.
85         // FrameStamp doesn't have a private destructor to allow
86         // us to do this, even though its a reference counted object.
87         osg::FrameStamp  _frameStamp;
88 
89         osgGA::EventQueue::Events _events;
90 
91 };
92 
93 class DataConverter
94 {
95     public:
96 
DataConverter(unsigned int numBytes)97         DataConverter(unsigned int numBytes):
98             _startPtr(0),
99             _endPtr(0),
100             _swapBytes(false),
101             _currentPtr(0)
102         {
103             _currentPtr = _startPtr = new char[numBytes];
104             _endPtr = _startPtr+numBytes;
105             _numBytes = numBytes;
106         }
107 
108         char* _startPtr;
109         char* _endPtr;
110         unsigned int _numBytes;
111         bool _swapBytes;
112 
113         char* _currentPtr;
114 
reset()115         void reset()
116         {
117             _currentPtr = _startPtr;
118         }
119 
write1(char * ptr)120         inline void write1(char* ptr)
121         {
122             if (_currentPtr+1>=_endPtr) return;
123 
124             *(_currentPtr++) = *(ptr);
125         }
126 
read1(char * ptr)127         inline void read1(char* ptr)
128         {
129             if (_currentPtr+1>=_endPtr) return;
130 
131             *(ptr) = *(_currentPtr++);
132         }
133 
write2(char * ptr)134         inline void write2(char* ptr)
135         {
136             if (_currentPtr+2>=_endPtr) return;
137 
138             *(_currentPtr++) = *(ptr++);
139             *(_currentPtr++) = *(ptr);
140         }
141 
read2(char * ptr)142         inline void read2(char* ptr)
143         {
144             if (_currentPtr+2>=_endPtr) return;
145 
146             if (_swapBytes)
147             {
148                 *(ptr+1) = *(_currentPtr++);
149                 *(ptr) = *(_currentPtr++);
150             }
151             else
152             {
153                 *(ptr++) = *(_currentPtr++);
154                 *(ptr) = *(_currentPtr++);
155             }
156         }
157 
write4(char * ptr)158         inline void write4(char* ptr)
159         {
160             if (_currentPtr+4>=_endPtr) return;
161 
162             *(_currentPtr++) = *(ptr++);
163             *(_currentPtr++) = *(ptr++);
164             *(_currentPtr++) = *(ptr++);
165             *(_currentPtr++) = *(ptr);
166         }
167 
read4(char * ptr)168         inline void read4(char* ptr)
169         {
170             if (_currentPtr+4>=_endPtr) return;
171 
172             if (_swapBytes)
173             {
174                 *(ptr+3) = *(_currentPtr++);
175                 *(ptr+2) = *(_currentPtr++);
176                 *(ptr+1) = *(_currentPtr++);
177                 *(ptr) = *(_currentPtr++);
178             }
179             else
180             {
181                 *(ptr++) = *(_currentPtr++);
182                 *(ptr++) = *(_currentPtr++);
183                 *(ptr++) = *(_currentPtr++);
184                 *(ptr) = *(_currentPtr++);
185             }
186         }
187 
write8(char * ptr)188         inline void write8(char* ptr)
189         {
190             if (_currentPtr+8>=_endPtr) return;
191 
192             *(_currentPtr++) = *(ptr++);
193             *(_currentPtr++) = *(ptr++);
194             *(_currentPtr++) = *(ptr++);
195             *(_currentPtr++) = *(ptr++);
196 
197             *(_currentPtr++) = *(ptr++);
198             *(_currentPtr++) = *(ptr++);
199             *(_currentPtr++) = *(ptr++);
200             *(_currentPtr++) = *(ptr);
201         }
202 
read8(char * ptr)203         inline void read8(char* ptr)
204         {
205             char* endPtr = _currentPtr+8;
206             if (endPtr>=_endPtr) return;
207 
208             if (_swapBytes)
209             {
210                 *(ptr+7) = *(_currentPtr++);
211                 *(ptr+6) = *(_currentPtr++);
212                 *(ptr+5) = *(_currentPtr++);
213                 *(ptr+4) = *(_currentPtr++);
214 
215                 *(ptr+3) = *(_currentPtr++);
216                 *(ptr+2) = *(_currentPtr++);
217                 *(ptr+1) = *(_currentPtr++);
218                 *(ptr) = *(_currentPtr++);
219             }
220             else
221             {
222                 *(ptr++) = *(_currentPtr++);
223                 *(ptr++) = *(_currentPtr++);
224                 *(ptr++) = *(_currentPtr++);
225                 *(ptr++) = *(_currentPtr++);
226 
227                 *(ptr++) = *(_currentPtr++);
228                 *(ptr++) = *(_currentPtr++);
229                 *(ptr++) = *(_currentPtr++);
230                 *(ptr) = *(_currentPtr++);
231             }
232         }
233 
writeChar(char c)234         inline void writeChar(char c)               { write1(&c); }
writeUChar(unsigned char c)235         inline void writeUChar(unsigned char c)     { write1((char*)&c); }
writeShort(short c)236         inline void writeShort(short c)             { write2((char*)&c); }
writeUShort(unsigned short c)237         inline void writeUShort(unsigned short c)   { write2((char*)&c); }
writeInt(int c)238         inline void writeInt(int c)                 { write4((char*)&c); }
writeUInt(unsigned int c)239         inline void writeUInt(unsigned int c)       { write4((char*)&c); }
writeFloat(float c)240         inline void writeFloat(float c)             { write4((char*)&c); }
writeDouble(double c)241         inline void writeDouble(double c)           { write8((char*)&c); }
242 
readChar()243         inline char readChar() { char c=0; read1(&c); return c; }
readUChar()244         inline unsigned char readUChar() { unsigned char c=0; read1((char*)&c); return c; }
readShort()245         inline short readShort() { short c=0; read2((char*)&c); return c; }
readUShort()246         inline unsigned short readUShort() { unsigned short c=0; read2((char*)&c); return c; }
readInt()247         inline int readInt() { int c=0; read4((char*)&c); return c; }
readUInt()248         inline unsigned int readUInt() { unsigned int c=0; read4((char*)&c); return c; }
readFloat()249         inline float readFloat() { float c=0.0f; read4((char*)&c); return c; }
readDouble()250         inline double readDouble() { double c=0.0; read8((char*)&c); return c; }
251 
write(const osg::FrameStamp & fs)252         void write(const osg::FrameStamp& fs)
253         {
254             osg::notify(osg::NOTICE)<<"writeFramestamp = "<<fs.getFrameNumber()<<" "<<fs.getReferenceTime()<<std::endl;
255 
256             writeUInt(fs.getFrameNumber());
257             writeDouble(fs.getReferenceTime());
258             writeDouble(fs.getSimulationTime());
259         }
260 
read(osg::FrameStamp & fs)261         void read(osg::FrameStamp& fs)
262         {
263             fs.setFrameNumber(readUInt());
264             fs.setReferenceTime(readDouble());
265             fs.setSimulationTime(readDouble());
266 
267             osg::notify(osg::NOTICE)<<"readFramestamp = "<<fs.getFrameNumber()<<" "<<fs.getReferenceTime()<<std::endl;
268         }
269 
write(const osg::Matrix & matrix)270         void write(const osg::Matrix& matrix)
271         {
272             writeDouble(matrix(0,0));
273             writeDouble(matrix(0,1));
274             writeDouble(matrix(0,2));
275             writeDouble(matrix(0,3));
276 
277             writeDouble(matrix(1,0));
278             writeDouble(matrix(1,1));
279             writeDouble(matrix(1,2));
280             writeDouble(matrix(1,3));
281 
282             writeDouble(matrix(2,0));
283             writeDouble(matrix(2,1));
284             writeDouble(matrix(2,2));
285             writeDouble(matrix(2,3));
286 
287             writeDouble(matrix(3,0));
288             writeDouble(matrix(3,1));
289             writeDouble(matrix(3,2));
290             writeDouble(matrix(3,3));
291 
292             osg::notify(osg::NOTICE)<<"writeMatrix = "<<matrix<<std::endl;
293 
294         }
295 
read(osg::Matrix & matrix)296         void read(osg::Matrix& matrix)
297         {
298             matrix(0,0) = readDouble();
299             matrix(0,1) = readDouble();
300             matrix(0,2) = readDouble();
301             matrix(0,3) = readDouble();
302 
303             matrix(1,0) = readDouble();
304             matrix(1,1) = readDouble();
305             matrix(1,2) = readDouble();
306             matrix(1,3) = readDouble();
307 
308             matrix(2,0) = readDouble();
309             matrix(2,1) = readDouble();
310             matrix(2,2) = readDouble();
311             matrix(2,3) = readDouble();
312 
313             matrix(3,0) = readDouble();
314             matrix(3,1) = readDouble();
315             matrix(3,2) = readDouble();
316             matrix(3,3) = readDouble();
317 
318             osg::notify(osg::NOTICE)<<"readMatrix = "<<matrix<<std::endl;
319 
320         }
321 
write(const osgGA::GUIEventAdapter & event)322         void write(const osgGA::GUIEventAdapter& event)
323         {
324             writeUInt(event.getEventType());
325             writeUInt(event.getKey());
326             writeUInt(event.getButton());
327             writeInt(event.getWindowX());
328             writeInt(event.getWindowY());
329             writeUInt(event.getWindowWidth());
330             writeUInt(event.getWindowHeight());
331             writeFloat(event.getXmin());
332             writeFloat(event.getYmin());
333             writeFloat(event.getXmax());
334             writeFloat(event.getYmax());
335             writeFloat(event.getX());
336             writeFloat(event.getY());
337             writeUInt(event.getButtonMask());
338             writeUInt(event.getModKeyMask());
339             writeDouble(event.getTime());
340         }
341 
read(osgGA::GUIEventAdapter & event)342         void read(osgGA::GUIEventAdapter& event)
343         {
344             event.setEventType((osgGA::GUIEventAdapter::EventType)readUInt());
345             event.setKey(readUInt());
346             event.setButton(readUInt());
347             int x = readInt();
348             int y = readInt();
349             int width = readUInt();
350             int height = readUInt();
351             event.setWindowRectangle(x,y,width,height);
352             float xmin = readFloat();
353             float ymin = readFloat();
354             float xmax = readFloat();
355             float ymax = readFloat();
356             event.setInputRange(xmin,ymin,xmax,ymax);
357             event.setX(readFloat());
358             event.setY(readFloat());
359             event.setButtonMask(readUInt());
360             event.setModKeyMask(readUInt());
361             event.setTime(readDouble());
362         }
363 
write(CameraPacket & cameraPacket)364         void write(CameraPacket& cameraPacket)
365         {
366             writeUInt(cameraPacket._byte_order);
367 
368             writeUInt(cameraPacket._masterKilled);
369 
370             write(cameraPacket._matrix);
371             write(cameraPacket._frameStamp);
372 
373             writeUInt(cameraPacket._events.size());
374             for(osgGA::EventQueue::Events::iterator itr = cameraPacket._events.begin();
375                 itr != cameraPacket._events.end();
376                 ++itr)
377             {
378                 osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
379                 if (event) write(*event);
380             }
381         }
382 
read(CameraPacket & cameraPacket)383         void read(CameraPacket& cameraPacket)
384         {
385             cameraPacket._byte_order = readUInt();
386             if (cameraPacket._byte_order != SWAP_BYTES_COMPARE)
387             {
388                 _swapBytes = !_swapBytes;
389             }
390 
391             cameraPacket._masterKilled = readUInt()!=0;
392 
393             read(cameraPacket._matrix);
394             read(cameraPacket._frameStamp);
395 
396             cameraPacket._events.clear();
397             unsigned int numEvents = readUInt();
398             for(unsigned int i=0;i<numEvents;++i)
399             {
400                 osgGA::GUIEventAdapter* event = new osgGA::GUIEventAdapter;
401                 read(*(event));
402                 cameraPacket._events.push_back(event);
403             }
404         }
405 };
406 
readEventQueue(osgViewer::Viewer & viewer)407 void CameraPacket::readEventQueue(osgViewer::Viewer& viewer)
408 {
409     _events.clear();
410 
411     osgViewer::ViewerBase::Contexts contexts;
412     viewer.getContexts(contexts);
413 
414     for(osgViewer::ViewerBase::Contexts::iterator citr =contexts.begin();  citr != contexts.end(); ++citr)
415     {
416         osgGA::EventQueue::Events gw_events;
417 
418         osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
419         if (gw)
420         {
421             gw->checkEvents();
422             gw->getEventQueue()->copyEvents(gw_events);
423         }
424         _events.insert(_events.end(), gw_events.begin(), gw_events.end());
425     }
426 
427     viewer.getEventQueue()->copyEvents(_events);
428 
429     osg::notify(osg::INFO)<<"written events = "<<_events.size()<<std::endl;
430 }
431 
writeEventQueue(osgViewer::Viewer & viewer)432 void CameraPacket::writeEventQueue(osgViewer::Viewer& viewer)
433 {
434     osg::notify(osg::INFO)<<"received events = "<<_events.size()<<std::endl;
435 
436     viewer.getEventQueue()->appendEvents(_events);
437 }
438 
439 
440 
441 enum ViewerMode
442 {
443     STAND_ALONE,
444     SLAVE,
445     MASTER
446 };
447 
main(int argc,char ** argv)448 int main( int argc, char **argv )
449 {
450     // use an ArgumentParser object to manage the program arguments.
451     osg::ArgumentParser arguments(&argc,argv);
452 
453     // set up the usage document, in case we need to print out how to use this program.
454     arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates how to approach implementation of clustering.");
455     arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
456     arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
457     arguments.getApplicationUsage()->addCommandLineOption("-m","Set viewer to MASTER mode, sending view via packets.");
458     arguments.getApplicationUsage()->addCommandLineOption("-s","Set viewer to SLAVE mode, receiving view via packets.");
459     arguments.getApplicationUsage()->addCommandLineOption("-n <int>","Socket number to transmit packets");
460     arguments.getApplicationUsage()->addCommandLineOption("-f <float>","Field of view of camera");
461     arguments.getApplicationUsage()->addCommandLineOption("-o <float>","Offset angle of camera");
462 
463     // construct the viewer.
464     osgViewer::Viewer viewer(arguments);
465 
466 
467     // read up the osgcluster specific arguments.
468     ViewerMode viewerMode = STAND_ALONE;
469     while (arguments.read("-m")) viewerMode = MASTER;
470     while (arguments.read("-s")) viewerMode = SLAVE;
471 
472     unsigned int messageSize = 1024;
473     while (arguments.read("--size", messageSize)) {}
474 
475 
476     bool readWriteFrame = false;
477     while (arguments.read("--frame")) readWriteFrame = true;
478 
479     int socketNumber=8100;
480     while (arguments.read("-n",socketNumber)) ;
481 
482     float camera_fov=-1.0f;
483     while (arguments.read("-f",camera_fov))
484     {
485     }
486 
487     float camera_offset=45.0f;
488     while (arguments.read("-o",camera_offset)) ;
489 
490 
491     // if user request help write it out to cout.
492     if (arguments.read("-h") || arguments.read("--help"))
493     {
494         arguments.getApplicationUsage()->write(std::cout);
495         return 1;
496     }
497 
498     // objects for managing the broadcasting and receiving of camera packets.
499     Broadcaster     bc;
500     Receiver        rc;
501 
502     std::string ifrName;
503     if (arguments.read("--ifr-name", ifrName)) { bc.setIFRName(ifrName); }
504 
505     bc.setPort(static_cast<short int>(socketNumber));
506     rc.setPort(static_cast<short int>(socketNumber));
507 
508 
509     // any option left unread are converted into errors to write out later.
510     arguments.reportRemainingOptionsAsUnrecognized();
511 
512     // report any errors if they have occurred when parsing the program arguments.
513     if (arguments.errors())
514     {
515         arguments.writeErrorMessages(std::cout);
516         return 1;
517     }
518 
519     if (arguments.argc()<=1)
520     {
521         arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
522         return 1;
523     }
524 
525     // load model.
526     osg::ref_ptr<osg::Node> rootnode = osgDB::readRefNodeFiles(arguments);
527 
528     // set the scene to render
529     viewer.setSceneData(rootnode.get());
530 
531     if (camera_fov>0.0f)
532     {
533         double fovy, aspectRatio, zNear, zFar;
534         viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,zNear, zFar);
535 
536         double original_fov = atan(tan(osg::DegreesToRadians(fovy)*0.5)*aspectRatio)*2.0;
537         std::cout << "setting lens perspective : original "<<original_fov<<"  "<<fovy<<std::endl;
538 
539         fovy = atan(tan(osg::DegreesToRadians(camera_fov)*0.5)/aspectRatio)*2.0;
540         viewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspectRatio,zNear, zFar);
541 
542         viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,zNear, zFar);
543         original_fov = atan(tan(osg::DegreesToRadians(fovy)*0.5)*aspectRatio)*2.0;
544         std::cout << "setting lens perspective : new "<<original_fov<<"  "<<fovy<<std::endl;
545     }
546 
547     viewer.setCameraManipulator(new osgGA::TrackballManipulator());
548 
549     // add the stats handler
550     viewer.addEventHandler(new osgViewer::StatsHandler);
551 
552     // add the state manipulator
553     viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
554 
555 
556     // create the windows and run the threads.
557     viewer.realize();
558 
559     osg::ref_ptr<osg::Image> image;
560     if (readWriteFrame)
561     {
562         osgViewer::Viewer::Windows windows;
563         viewer.getWindows(windows);
564 
565         if (windows.empty())
566         {
567             return 1;
568         }
569         unsigned int width = windows.front()->getTraits()->width;
570         unsigned int height = windows.front()->getTraits()->height;
571         image = new osg::Image;
572 
573         if (windows.front()->getTraits()->alpha)
574         {
575             OSG_NOTICE<<"Setting up RGBA osg::Image, width = "<<width<<", height = "<<height<<std::endl;
576             image->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
577         }
578         else
579         {
580             OSG_NOTICE<<"Setting up RGB osg::Image, width = "<<width<<", height = "<<height<<std::endl;
581             image->allocateImage(width, height, 1, GL_RGB, GL_UNSIGNED_BYTE);
582         }
583 
584         // if (image->getImageStepInBytes()>messageSize) messageSize = image->getImageStepInBytes();
585     }
586 
587     CameraPacket *cp = new CameraPacket;
588 
589 
590     bool masterKilled = false;
591 
592     DataConverter scratchPad(messageSize);
593 
594     while( !viewer.done() && !masterKilled )
595     {
596         osg::Timer_t startTick = osg::Timer::instance()->tick();
597 
598         viewer.advance();
599 
600         // special handling for working as a cluster.
601         switch (viewerMode)
602         {
603         case(MASTER):
604             {
605 
606                 // take camera zero as the guide.
607                 osg::Matrix modelview(viewer.getCamera()->getViewMatrix());
608 
609                 cp->setPacket(modelview,viewer.getFrameStamp());
610 
611                 cp->readEventQueue(viewer);
612 
613                 scratchPad.reset();
614                 scratchPad.write(*cp);
615 
616                 scratchPad.reset();
617                 scratchPad.read(*cp);
618 
619                 bc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);
620 
621                 bc.sync();
622 
623                 if (image.valid())
624                 {
625                     bc.setBuffer(image->data(), image->getImageStepInBytes());
626                     bc.sync();
627                 }
628 
629 
630             }
631             break;
632         case(SLAVE):
633             {
634 
635                 rc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);
636 
637                 unsigned int readsize = rc.sync();
638 
639                 if (readsize) std::cout<<std::endl<<"readsize = "<<readsize<<std::endl;
640 
641                 scratchPad.reset();
642                 scratchPad.read(*cp);
643 
644                 cp->writeEventQueue(viewer);
645 
646                 if (cp->getMasterKilled())
647                 {
648                     std::cout << "Received master killed."<<std::endl;
649                     // break out of while (!done) loop since we've now want to shut down.
650                     masterKilled = true;
651                 }
652 
653                 if (image)
654                 {
655                     rc.setBuffer(image->data(), image->getImageStepInBytes());
656                     readsize = rc.sync();
657                     if (readsize) std::cout<<"image readsize = "<<readsize<<std::endl;
658                 }
659 
660             }
661             break;
662         default:
663             // no need to anything here, just a normal interactive viewer.
664             break;
665         }
666 
667         osg::Timer_t endTick = osg::Timer::instance()->tick();
668 
669         osg::notify(osg::INFO)<<"Time to do cluster sync "<<osg::Timer::instance()->delta_m(startTick,endTick)<<std::endl;
670 
671         // update the scene by traversing it with the update visitor which will
672         // call all node update callbacks and animations.
673         viewer.eventTraversal();
674         viewer.updateTraversal();
675 
676         if (viewerMode==SLAVE)
677         {
678             osg::Matrix modelview;
679             cp->getModelView(modelview,camera_offset);
680 
681             viewer.getCamera()->setViewMatrix(modelview);
682         }
683 
684         // fire off the cull and draw traversals of the scene.
685         if(!masterKilled)
686             viewer.renderingTraversals();
687 
688     }
689 
690     // if we are master clean up by telling all slaves that we're going down.
691     if (viewerMode==MASTER)
692     {
693         // need to broadcast my death.
694         cp->setPacket(osg::Matrix::identity(),viewer.getFrameStamp());
695         cp->setMasterKilled(true);
696 
697         scratchPad.reset();
698         scratchPad.write(*cp);
699 
700         bc.setBuffer(scratchPad._startPtr, scratchPad._numBytes);
701         bc.sync();
702 
703         std::cout << "Broadcasting death."<<std::endl;
704 
705     }
706 
707     return 0;
708 }
709