/* OpenSceneGraph example, osgcluster. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef USE_MEM_CHECK #include #endif #include #include #include #include #include #include #include #include #include #include #include #if defined (WIN32) && !defined(__CYGWIN__) #include #endif #include "receiver.h" #include "broadcaster.h" const unsigned int MAX_NUM_EVENTS = 10; const unsigned int SWAP_BYTES_COMPARE = 0x12345678; class CameraPacket { public: CameraPacket():_masterKilled(false) { _byte_order = SWAP_BYTES_COMPARE; } void setPacket(const osg::Matrix& matrix,const osg::FrameStamp* frameStamp) { _matrix = matrix; if (frameStamp) { _frameStamp = *frameStamp; } } void getModelView(osg::Matrix& matrix,float angle_offset=0.0f) { matrix = _matrix * osg::Matrix::rotate(osg::DegreesToRadians(angle_offset),0.0f,1.0f,0.0f); } void readEventQueue(osgViewer::Viewer& viewer); void writeEventQueue(osgViewer::Viewer& viewer); void setMasterKilled(const bool flag) { _masterKilled = flag; } const bool getMasterKilled() const { return _masterKilled; } unsigned int _byte_order; bool _masterKilled; osg::Matrix _matrix; // note don't use a ref_ptr as used elsewhere for FrameStamp // since we don't want to copy the pointer - but the memory. // FrameStamp doesn't have a private destructor to allow // us to do this, even though its a reference counted object. osg::FrameStamp _frameStamp; osgGA::EventQueue::Events _events; }; class DataConverter { public: DataConverter(unsigned int numBytes): _startPtr(0), _endPtr(0), _swapBytes(false), _currentPtr(0) { _currentPtr = _startPtr = new char[numBytes]; _endPtr = _startPtr+numBytes; _numBytes = numBytes; } char* _startPtr; char* _endPtr; unsigned int _numBytes; bool _swapBytes; char* _currentPtr; void reset() { _currentPtr = _startPtr; } inline void write1(char* ptr) { if (_currentPtr+1>=_endPtr) return; *(_currentPtr++) = *(ptr); } inline void read1(char* ptr) { if (_currentPtr+1>=_endPtr) return; *(ptr) = *(_currentPtr++); } inline void write2(char* ptr) { if (_currentPtr+2>=_endPtr) return; *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr); } inline void read2(char* ptr) { if (_currentPtr+2>=_endPtr) return; if (_swapBytes) { *(ptr+1) = *(_currentPtr++); *(ptr) = *(_currentPtr++); } else { *(ptr++) = *(_currentPtr++); *(ptr) = *(_currentPtr++); } } inline void write4(char* ptr) { if (_currentPtr+4>=_endPtr) return; *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr); } inline void read4(char* ptr) { if (_currentPtr+4>=_endPtr) return; if (_swapBytes) { *(ptr+3) = *(_currentPtr++); *(ptr+2) = *(_currentPtr++); *(ptr+1) = *(_currentPtr++); *(ptr) = *(_currentPtr++); } else { *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr) = *(_currentPtr++); } } inline void write8(char* ptr) { if (_currentPtr+8>=_endPtr) return; *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr++); *(_currentPtr++) = *(ptr); } inline void read8(char* ptr) { char* endPtr = _currentPtr+8; if (endPtr>=_endPtr) return; if (_swapBytes) { *(ptr+7) = *(_currentPtr++); *(ptr+6) = *(_currentPtr++); *(ptr+5) = *(_currentPtr++); *(ptr+4) = *(_currentPtr++); *(ptr+3) = *(_currentPtr++); *(ptr+2) = *(_currentPtr++); *(ptr+1) = *(_currentPtr++); *(ptr) = *(_currentPtr++); } else { *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr++) = *(_currentPtr++); *(ptr) = *(_currentPtr++); } } inline void writeChar(char c) { write1(&c); } inline void writeUChar(unsigned char c) { write1((char*)&c); } inline void writeShort(short c) { write2((char*)&c); } inline void writeUShort(unsigned short c) { write2((char*)&c); } inline void writeInt(int c) { write4((char*)&c); } inline void writeUInt(unsigned int c) { write4((char*)&c); } inline void writeFloat(float c) { write4((char*)&c); } inline void writeDouble(double c) { write8((char*)&c); } inline char readChar() { char c=0; read1(&c); return c; } inline unsigned char readUChar() { unsigned char c=0; read1((char*)&c); return c; } inline short readShort() { short c=0; read2((char*)&c); return c; } inline unsigned short readUShort() { unsigned short c=0; read2((char*)&c); return c; } inline int readInt() { int c=0; read4((char*)&c); return c; } inline unsigned int readUInt() { unsigned int c=0; read4((char*)&c); return c; } inline float readFloat() { float c=0.0f; read4((char*)&c); return c; } inline double readDouble() { double c=0.0; read8((char*)&c); return c; } void write(const osg::FrameStamp& fs) { osg::notify(osg::NOTICE)<<"writeFramestamp = "<setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); arguments.getApplicationUsage()->addCommandLineOption("-m","Set viewer to MASTER mode, sending view via packets."); arguments.getApplicationUsage()->addCommandLineOption("-s","Set viewer to SLAVE mode, receiving view via packets."); arguments.getApplicationUsage()->addCommandLineOption("-n ","Socket number to transmit packets"); arguments.getApplicationUsage()->addCommandLineOption("-f ","Field of view of camera"); arguments.getApplicationUsage()->addCommandLineOption("-o ","Offset angle of camera"); // construct the viewer. osgViewer::Viewer viewer; // read up the osgcluster specific arguments. ViewerMode viewerMode = STAND_ALONE; while (arguments.read("-m")) viewerMode = MASTER; while (arguments.read("-s")) viewerMode = SLAVE; int socketNumber=8100; while (arguments.read("-n",socketNumber)) ; float camera_fov=-1.0f; while (arguments.read("-f",camera_fov)) { } float camera_offset=45.0f; while (arguments.read("-o",camera_offset)) ; // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { arguments.getApplicationUsage()->write(std::cout); return 1; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); // report any errors if they have occured when parsing the program aguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } if (arguments.argc()<=1) { arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); return 1; } // load model. osg::ref_ptr rootnode = osgDB::readNodeFiles(arguments); // set the scene to render viewer.setSceneData(rootnode.get()); if (camera_fov>0.0f) { double fovy, aspectRatio, zNear, zFar; viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,zNear, zFar); double original_fov = atan(tan(osg::DegreesToRadians(fovy)*0.5)*aspectRatio)*2.0; std::cout << "setting lens perspective : original "<setProjectionMatrixAsPerspective(fovy, aspectRatio,zNear, zFar); viewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio,zNear, zFar); original_fov = atan(tan(osg::DegreesToRadians(fovy)*0.5)*aspectRatio)*2.0; std::cout << "setting lens perspective : new "<getOrCreateStateSet()) ); // create the windows and run the threads. viewer.realize(); CameraPacket *cp = new CameraPacket; // objects for managing the broadcasting and recieving of camera packets. Broadcaster bc; Receiver rc; bc.setPort(static_cast(socketNumber)); rc.setPort(static_cast(socketNumber)); bool masterKilled = false; DataConverter scratchPad(1024); while( !viewer.done() && !masterKilled ) { osg::Timer_t startTick = osg::Timer::instance()->tick(); viewer.advance(); // special handling for working as a cluster. switch (viewerMode) { case(MASTER): { // take camera zero as the guide. osg::Matrix modelview(viewer.getCamera()->getViewMatrix()); cp->setPacket(modelview,viewer.getFrameStamp()); cp->readEventQueue(viewer); scratchPad.reset(); scratchPad.write(*cp); scratchPad.reset(); scratchPad.read(*cp); bc.setBuffer(scratchPad._startPtr, scratchPad._numBytes); std::cout << "bc.sync()"<writeEventQueue(viewer); if (cp->getMasterKilled()) { std::cout << "Received master killed."<tick(); osg::notify(osg::INFO)<<"Time to do cluster sync "<delta_m(startTick,endTick)<getModelView(modelview,camera_offset); viewer.getCamera()->setViewMatrix(modelview); } // fire off the cull and draw traversals of the scene. if(!masterKilled) viewer.renderingTraversals(); } // if we are master clean up by telling all slaves that we're going down. if (viewerMode==MASTER) { // need to broadcast my death. cp->setPacket(osg::Matrix::identity(),viewer.getFrameStamp()); cp->setMasterKilled(true); scratchPad.reset(); scratchPad.write(*cp); bc.setBuffer(scratchPad._startPtr, scratchPad._numBytes); bc.sync(); std::cout << "Broadcasting death."<