int main( int argc, char **argv ) { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates how to approach implementation of clustering."); arguments.getApplicationUsage()->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 <int>","Socket number to transmit packets"); arguments.getApplicationUsage()->addCommandLineOption("-f <float>","Field of view of camera"); arguments.getApplicationUsage()->addCommandLineOption("-o <float>","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<osg::Node> 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 "<<original_fov<<" "<<fovy<<std::endl; fovy = atan(tan(osg::DegreesToRadians(camera_fov)*0.5)/aspectRatio)*2.0; viewer.getCamera()->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 "<<original_fov<<" "<<fovy<<std::endl; } viewer.setCameraManipulator(new osgGA::TrackballManipulator()); // add the stats handler viewer.addEventHandler(new osgViewer::StatsHandler); // add the state manipulator viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->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<short int>(socketNumber)); rc.setPort(static_cast<short int>(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()"<<scratchPad._numBytes<<std::endl; bc.sync(); } break; case(SLAVE): { rc.setBuffer(scratchPad._startPtr, scratchPad._numBytes); rc.sync(); scratchPad.reset(); scratchPad.read(*cp); cp->writeEventQueue(viewer); if (cp->getMasterKilled()) { std::cout << "Received master killed."<<std::endl; // break out of while (!done) loop since we've now want to shut down. masterKilled = true; } } break; default: // no need to anything here, just a normal interactive viewer. break; } osg::Timer_t endTick = osg::Timer::instance()->tick(); osg::notify(osg::INFO)<<"Time to do cluster sync "<<osg::Timer::instance()->delta_m(startTick,endTick)<<std::endl; // update the scene by traversing it with the update visitor which will // call all node update callbacks and animations. viewer.eventTraversal(); viewer.updateTraversal(); if (viewerMode==SLAVE) { osg::Matrix modelview; cp->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."<<std::endl; } return 0; }