// redraw the window
void display(void)
{
    // redraw the client window
    _mgr->redraw();


    OSG::commitChanges();

    try
    {
        if(_cluster_win != NULL)
        {
            OSG::Thread::getCurrentChangeList()->dump();

            // redraw the server windows
            _cluster_win->render((OSG::RenderAction *) _mgr->getRenderAction());
        }
    }
    
    catch(OSG_STDEXCEPTION_NAMESPACE::exception &e)
    {
        //printf("error: '%s'\n", e.what());
        printf("ClusterServer was killed!\n");

        _cluster_win = NULL;
    } 
    
    OSG::commitChanges();
    OSG::clearChangeList();
}
static void connectCluster(void)
{
    if(_cluster_win != NULL)
        return;

    OSG::Viewport *clientvp = _client_win->getPort(0);
    
    // create the viewports for the cluster just a simple one ...
    OSG::ViewportUnrecPtr vp = OSG::Viewport::create();

    vp->setCamera    (_mgr->getCamera());
    vp->setBackground(clientvp->getBackground());
    vp->setRoot      (clientvp->getRoot());
    vp->setSize      (0,0, 1,1);

    // the connection between this client and the servers
    _cluster_win = OSG::MultiDisplayWindow::create();

    // all changes must be enclosed in beginEditCP and endEditCP
    // otherwise the changes will not be transfered over the network.

    for(OSG::UInt32 i=0;i<_pipenames.size();++i)
        _cluster_win->editMFServers()->push_back(_pipenames[i]);
    // dummy size for navigator
    _cluster_win->setSize(300,300);
    _cluster_win->addPort(vp);

    OSG::Thread::getCurrentChangeList()->commitChangesAndClear();
    OSG::Thread::getCurrentChangeList()->fillFromCurrentState();
    OSG::Thread::getCurrentChangeList()->dump();
    // create from the current state a changelist.

    // initialize window
    _cluster_win->init();

    // apply changelist to the servers
    _cluster_win->render((OSG::RenderAction *) _mgr->getRenderAction());

    // clear changelist
    OSG::Thread::getCurrentChangeList()->clear();

    glutPostRedisplay();
}
int main(int argc, char **argv)
{
    OSG::osgInit(argc,argv);

    {
        int winid = setupGLUT(&argc, argv);
        
        //this time we'll have not a GLUTWindow here, but this one
        OSG::MultiDisplayWindowRecPtr multiWindow = 
            OSG::MultiDisplayWindow::create();
        
        //set some necessary values
        // we connect via multicast
        multiWindow->setConnectionType("Multicast");
        //multiWindow->setServiceAddress("192.168.2.142");
        // we want to rendering servers... 
        multiWindow->editMFServers()->push_back("Server1");
        multiWindow->editMFServers()->push_back("Server2");	
        
        //any scene here
        scene = OSG::makeTorus(.5, 2, 16, 16);
        
        // and the ssm as always
        mgr = new OSG::SimpleSceneManager;
        
        mgr->setWindow(multiWindow);
        mgr->setRoot  (scene);
        mgr->showAll();
        
        multiWindow->init();
        
        OSG::commitChanges();
    }
    
    glutMainLoop();
    
    return 0;
}
int doMain(int argc,char **argv)
{
    int                      i;
    char                    *opt;
    std::vector<std::string> filenames;
    std::vector<std::string> servers;
    std::string              connectionType = "StreamSock";
    std::string              connectionParameters;
    int                      rows=1;
    int                      cols=-1;
    char                     type='M';
    bool                     clientRendering=true;
    bool                     compose=false;

    std::string              composerType="";
    std::string              autostart;
    
    for(i=1;i<argc;i++)
    {
        if(strlen(argv[i])>1 && argv[i][0]=='-')
        {
            switch(argv[i][1])
            {
                case 'o':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    connectionParameters = opt;
                    printf("connectionParameters: '%s'\n", connectionParameters.c_str());
                    break;
                case 'A':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    autostart = opt;
                    break;
                case 'D':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    if(sscanf(opt,"%f,%f,%f",&ca,&cb,&cc)!=3)
                    {
                        std::cout << "Copy opton -D x,y,z" << std::endl;
                        return 1;
                    }
                    break;
                case 'b':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    serviceInterface.assign(opt);
                    serviceInterfaceValid = true;
                    break;
                case 'B':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    serviceAddress.assign(opt);
                    serviceAddressValid = true;
                    break;
                case 'f':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    filenames.push_back(opt);
                    printf("<%s>\n",opt);
                    break;
                case 'm':
                    connectionType="Multicast";
                    break;
                case 'r':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    if(sscanf(opt,"%d,%d",&rows,&cols) != 2)
                        sscanf(opt,"%d",&rows);
                    break;
                case 't':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    subtilesize=atoi(opt);
                    break;
#ifdef FRAMEINTERLEAVE
                case 'i':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    interleave=atoi(opt);
                    break;
#endif
                case 'C':
                    compose=true;
                    break;
                case 'F':
                    type='F';
                    break;
                case 'X':
                    type='X';
                    break;
                case 'P':
                    type='P';
                    break;
                case 'L':
                {
                    type='L';
                    int lpos=2;
                    while(argv[i][lpos])
                    {
                        if(argv[i][lpos] == 'B') 
                            composerType = "BinarySwapComposer";
                        if(argv[i][lpos] == 'P')
                            composerType = "PipelineComposer";
                        if(argv[i][lpos] == 'S')
                            composerType = "SepiaComposer";
                        if(argv[i][lpos] == 'p')
                            pipelinedBufferRead = true;
                        ++lpos;
                    }
                    break;
                }
                case 'M':
                    type='M';
                    break;
                case 'I':
                    type='I';
                    break;
                case 's':
                    stereoMode=1;
                    break;
                case 'c':
                    stereoMode=2;
                    break;
                case 'S':
                    info=true;
                    break;
                case 'e':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    sscanf(opt,"%f",&eyedistance);
                    break;
                case 'z':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    sscanf(opt,"%f",&zeroparallax);
                    break;
                case 'd':
                    clientRendering=false;
                    break;
                case 'v':
                    multiport=true;
                    break;
                case 'x':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    sscanf(opt,"%d",&serverx);
                    break;
                case 'y':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    sscanf(opt,"%d",&servery);
                    break;
                case 'a':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    animName=opt;
                    loadAnim();
                    animate=true;
                    break;
                case 'l':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    if(sscanf(opt,"%d,%d",&animLoops,&animLength) != 2)
                    {
                        animLength = 30;
                        if(sscanf(opt,"%d",&animLoops) != 1)
                        {
                            animLoops = -1;
                        }
                    }
                    break;
                case 'g':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    if(sscanf(opt,"%d,%d,%d,%d",
                              &winwidth,&winheight,&winx,&winy) != 4)
                        sscanf(opt,"%d,%d",&winwidth,&winheight);
                    break;
                case 'G':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    connectionDestination = opt;
                    break;
                case 'i':
                    opt = argv[i][2] ? argv[i]+2 : argv[++i];
                    connectionInterface = opt;
                    break;
                default:
                    std::cout << argv[0] 
                              << "-ffile -m -rrows[,cols] -C -M"
                              << std::endl;
                    std::cout << "-m  use multicast" << std::endl
                              << "-G  multicast group" << std::endl
                              << "-i  interface" << std::endl
                              << "-b  service interface" << std::endl
                              << "-M  multi display" << std::endl
#ifdef FRAMEINTERLEAVE
                              << "-I  frame interleave" << std::endl
#endif
                              << "-r  number of display rows" << std::endl
                              << "-C  compose" << std::endl
                              << "-F  sort-first" << std::endl
                              << "-L  sort-last" << std::endl
                              << "-h  this msg" << std::endl
                              << "-s  stereo" << std::endl
                              << "-c  red/cyan stereo" << std::endl
                              << "-e  eye distance" << std::endl
                              << "-z  zero parallax" << std::endl
                              << "-d  disable client rendering"<<std::endl
                              << "-v  use two viewports" << std::endl
                              << "-x  server x resolution" << std::endl
                              << "-y  server y resolution" << std::endl
                              << "-t  subtile size for img composition" << std::endl
                              << "-D  x,y,z duplicate geometry" << std::endl
                              << "-A  Autostart command" << std::endl
                              << "-o  connection parameter string e.g. \"TTL=8\"" << std::endl;
                    return 0;
            }
        }
        else
        {
            servers.push_back(argv[i]);
        }
    }

    OSG::ChangeList::setReadWriteDefault(true);
    OSG::osgInit(argc, argv);
    glutInit(&argc, argv);
    glutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );
    if(winx >=0 && winy >=0)
        glutInitWindowPosition(winx,winy);
    glutInitWindowSize(winwidth,winheight);
    winid = glutCreateWindow("OpenSG Cluster Client");
    glutKeyboardFunc(key);
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);     
    if(animate)
        glutIdleFunc(display);       
    glutMouseFunc(mouse);   
    glutMotionFunc(motion); 
    ract = OSG::RenderAction::create();
#ifdef OSG_OLD_RENDER_ACTION
    ract->setSortTrans(true);
    ract->setZWriteTrans(true);
    ract->setLocalLights(true);
    ract->setCorrectTwoSidedLighting(true);
#endif

    // clear changelist from prototypes
    OSG::Thread::getCurrentChangeList()->clear();
    
    // create cluster window
    switch(type)
    {
        case 'M': 
            multidisplay=OSG::MultiDisplayWindow::create();
            clusterWindow=multidisplay;
            break;
        case 'X': 
            balancedmultidisplay=OSG::BalancedMultiWindow::create();
            clusterWindow=balancedmultidisplay;
            break;
        case 'F':
            sortfirst=OSG::SortFirstWindow::create();
            if(compose)
                sortfirst->setCompose(true);
            else
                sortfirst->setCompose(false);
            clusterWindow=sortfirst;
            break;
        case 'L':
            sortlast=OSG::SortLastWindow::create();
            if(!composerType.empty())
            {
                OSG::FieldContainerUnrecPtr fcPtr = 
                    OSG::FieldContainerFactory::the()->
                    createContainer(composerType.c_str());
                OSG::ImageComposer *icPtr = 
                    dynamic_cast<OSG::ImageComposer *>(fcPtr.get());
                
                if(icPtr != NULL)
                {
                    if(dynamic_cast<OSG::PipelineComposer *>(icPtr) != NULL)
                    {
                        if(subtilesize>0)
                            dynamic_cast<OSG::PipelineComposer *>(icPtr)->setTileSize(subtilesize);
                        dynamic_cast<OSG::PipelineComposer *>(icPtr)->setPipelined(pipelinedBufferRead);
                    }
                    if(dynamic_cast<OSG::BinarySwapComposer *>(icPtr) != NULL)
                    {
                        if(subtilesize>0)
                            dynamic_cast<OSG::BinarySwapComposer *>(icPtr)->setTileSize(subtilesize);
                    }
                    icPtr->setStatistics(info);
//                        icPtr->setShort(false);
                    sortlast->setComposer(icPtr);
                }
            }
            clusterWindow=sortlast;
            break;
#ifdef FRAMEINTERLEAVE
        case 'I':
            frameinterleave=OSG::FrameInterleaveWindow::create();
            clusterWindow=frameinterleave;
            if(compose)
                frameinterleave->setCompose(true);
            else
                frameinterleave->setCompose(false);
            break;
#endif
        case 'P':
            sortfirst=OSG::SortFirstWindow::create();
            sortfirst->setCompose(false);
            clusterWindow=sortfirst;
            break;
    }
    
    if(!autostart.empty())
        clusterWindow->editMFAutostart()->push_back(autostart);
    
    for(i=0 ; i<int(servers.size()) ; ++i)
        clusterWindow->editMFServers()->push_back(servers[i]);
    if(cols < 0)
        cols = clusterWindow->getMFServers()->size32() / rows;
    switch(type)
    {
        case 'M': 
            multidisplay->setHServers(cols);
            multidisplay->setVServers(rows);
            break;
        case 'X': 
            balancedmultidisplay->setHServers(cols);
            balancedmultidisplay->setVServers(rows);
//                    balancedmultidisplay->setShowBalancing(true);
//            balancedmultidisplay->setShowBalancing(info);
            break;
    }
#ifdef FRAMEINTERLEAVE
    clusterWindow->setInterleave(interleave);
#endif
        
    // create client window
    clientWindow=OSG::GLUTWindow::create();
//        glutReshapeWindow(800,600);
    glutReshapeWindow(winwidth,winheight);
    clientWindow->setGlutId(winid);
    clientWindow->init();
    
    // init scene graph
    init(filenames);
    
    // init client
    clusterWindow->setConnectionType(connectionType);
    // needs to be called before init()!
    clusterWindow->setConnectionParams(connectionParameters);
    if(clientRendering)
    {
        clusterWindow->setClientWindow(clientWindow);
    }
    clusterWindow->setConnectionDestination(connectionDestination);
    clusterWindow->setConnectionInterface(connectionInterface);
    clusterWindow->init();
    if(serverx > 0)
        clusterWindow->resize(serverx,servery);
    else
        clusterWindow->resize(winwidth,winheight);
    clientWindow->resize(winwidth,winheight);

//    OSG::FieldContainerFactory::the()->dump();

    OSG::commitChanges();

    glutMainLoop();

    return 0;
}