void MultiDisplayWindow::serverRender(WindowPtr         serverWindow,
                                      UInt32            id,
                                      DrawActionBase *action )
{
    TileCameraDecoratorPtr deco;
    ViewportPtr serverPort;
    ViewportPtr clientPort;
    StereoBufferViewportPtr clientStereoPort;
    UInt32 sv,cv;
    Int32 l,r,t,b;
    Int32 cleft,cright,ctop,cbottom;

    // sync, otherwise viewports will be out of date

    if(!getHServers())
    {
        setHServers(getServers().size());
    }
    if(!getVServers())
    {
        setVServers(1);
    }

    UInt32 row   =id/getHServers();
    UInt32 column=id%getHServers();

    // calculate width and height from local width and height
    UInt32 width  = serverWindow->getWidth() ;
    UInt32 height = serverWindow->getHeight();

    if(getWidth()==0)
    {
        setWidth( width*getHServers() );
    }
    if(getHeight()==0)
    {
        setHeight( height*getVServers() );
    }

    Int32 left   = column * width  - column * getXOverlap();
    Int32 bottom = row    * height - row    * getYOverlap();
    Int32 right  = left   + width  - 1;
    Int32 top    = bottom + height - 1;
    Real64 scaleCWidth  =
        ((width - getXOverlap()) * (getHServers() - 1) + width) /
        (float)getWidth();
    Real64 scaleCHeight =
        ((height - getYOverlap())* (getVServers() - 1) + height)/
        (float)getHeight();

    bool   isVirtualPort = false;

    // duplicate viewports
    for(cv = 0, sv = 0; cv < getPort().size(); ++cv)
    {
        clientPort = getPort()[cv];

#if 0
        isVirtualPort = clientPort->getType().isDerivedFrom(FBOViewport::getClassType());

        if(isVirtualPort)
        {
            // TODO -- seems wrong to render this on all servers, though rendering
            // then transmitting the texture doesn't seem like a good idea either.
            if(serverWindow->getPort().size() <= sv)
            {
                serverPort = ViewportPtr::dcast(clientPort->shallowCopy());
                beginEditCP(serverWindow);
                serverWindow->addPort(serverPort);
                endEditCP(serverWindow);
            }
            else
            {
                serverPort = serverWindow->getPort()[sv];
                if(serverWindow->getPort()[sv]->getType() !=
                        clientPort->getType())
                {
                    // there is a viewport with the wrong type
                    subRefCP(serverWindow->getPort()[sv]);
                    serverPort = ViewportPtr::dcast(clientPort->shallowCopy());
                    beginEditCP(serverWindow);
                    {
                        serverWindow->getPort()[sv] = serverPort;
                    }
                    endEditCP(serverWindow);
                }
            }
            // update changed viewport fields
            updateViewport(serverPort,clientPort);
        }
        else
#endif
        {
            clientStereoPort =
                dynamic_cast<StereoBufferViewportPtr>(clientPort);

            cleft   = (Int32)(clientPort->getPixelLeft()      * scaleCWidth)   ;
            cbottom = (Int32)(clientPort->getPixelBottom()    * scaleCHeight)  ;
            cright  = (Int32)((clientPort->getPixelRight()+1) * scaleCWidth) -1;
            ctop    = (Int32)((clientPort->getPixelTop()+1)   * scaleCHeight)-1;

            if(cright  < left   ||
                    cleft   > right  ||
                    ctop    < bottom ||
                    cbottom > top      )
            {
                // invisible on this server screen
                continue;
            }

            // calculate overlapping viewport
            l = osgMax(cleft  ,left  ) - left;
            b = osgMax(cbottom,bottom) - bottom;
            r = osgMin(cright ,right ) - left;
            t = osgMin(ctop   ,top   ) - bottom;

            if(serverWindow->getPort().size() <= sv)
            {
                serverPort =
                    dynamic_cast<ViewportPtr>(clientPort->shallowCopy());

                deco = TileCameraDecorator::create();

                serverWindow->addPort(serverPort);

                serverPort->setCamera(deco);
            }
            else
            {
                serverPort = serverWindow->getPort()[sv];

                deco = dynamic_cast<TileCameraDecoratorPtr>(
                           serverPort->getCamera());

                if(serverWindow->getPort()[sv]->getType() !=
                        clientPort->getType())
                {
                    // there is a viewport with the wrong type
                    serverPort =
                        dynamic_cast<ViewportPtr>(clientPort->shallowCopy());

                    serverWindow->replacePort(sv,
                                              serverPort);//[sv] = serverPort;
                    serverPort->setCamera(deco);
                }
                else
                {
                    deco = dynamic_cast<TileCameraDecoratorPtr>(
                               serverPort->getCamera());
                }
            }

            // update changed viewport fields
            updateViewport(serverPort,clientPort);

            // set viewport size
            serverPort->setSize(Real32(l),Real32(b),Real32(r),Real32(t));

            // use pixel even if pixel = 1
            if(serverPort->getLeft() == 1.0)
                serverPort->setLeft(1.0001);

            if(serverPort->getRight() == 1.0)
                serverPort->setRight(1.0001);

            if(serverPort->getTop() == 1.0)
                serverPort->setTop(1.0001);

            if(serverPort->getBottom() == 1.0)
                serverPort->setBottom(1.0001);

            // calculate tile parameters
            deco->setFullWidth ( cright-cleft );
            deco->setFullHeight( ctop-cbottom );
            deco->setSize( ( l+left-cleft     ) / (float)( cright-cleft ),
                           ( b+bottom-cbottom ) / (float)( ctop-cbottom ),
                           ( r+left-cleft     ) / (float)( cright-cleft ),
                           ( t+bottom-cbottom ) / (float)( ctop-cbottom ) );
            deco->setDecoratee( clientPort->getCamera() );
        }
        sv++;
    }

    // remove unused ports
    while(serverWindow->getPort().size()>sv)
    {
        serverWindow->subPort(sv);
    }

    Inherited::serverRender(serverWindow,id,action);
}
    virtual void redraw( void ) {
        static bool first=true;
        static RenderNode rn;

        int i;
        double tbalance;
        GeoLoadManager::ResultT region;
        if (_internalRoot == NullFC)
        {
            initialize();
            showAll();
        }
        _cart->getSFMatrix()->setValue(_navigator.getMatrix());    
        updateHighlight();
        _win->activate();
        _win->frameInit();
        if(first)
        {
            loadManager=new GeoLoadManager(useFaceDistribution);
            first=false;
            rn.determinePerformance(_win);
        }
        if(_win->getPort().size() < (serverCount+1))
        {
            ViewportPtr vp,ovp=_win->getPort(0);
            addRefCP(ovp);
            addRefCP(ovp);
            TileCameraDecoratorPtr deco;
            for(int i=_win->getPort().size()-1;i<serverCount;i++)
            {
                cout << "Add new" << endl;
                loadManager->addRenderNode(rn,i);
                if(simulateRendering)
                {
                    beginEditCP(_win);
                    deco=TileCameraDecorator::create();
                    beginEditCP(deco);
                    deco->setFullWidth ( _win->getWidth() );
                    deco->setFullHeight( _win->getHeight() );
                    deco->setDecoratee( ovp->getCamera() );
                    vp=Viewport::create();
                    beginEditCP(vp);
                    vp->setRoot      ( ovp->getRoot()       );

                    /*
                    SkyBackgroundPtr sky = SkyBackground::create();
                    beginEditCP(sky);
                    sky->setSphereRes(16);
                    
                    sky->getMFSkyColor()->addValue(Color3f(0, 0, .2));
                    sky->getMFSkyAngle()->addValue(Pi / 2);
                    sky->getMFSkyColor()->addValue(Color3f(.6, .6, 1)); 
                    
                    sky->getMFGroundColor()->addValue(Color3f(0, .3, 1));
                    sky->getMFGroundAngle()->addValue(Pi / 2);
                    sky->getMFGroundColor()->addValue(Color3f(1, .3, 0));

                    endEditCP(sky);
                    vp->setBackground( sky );
                    */

                    vp->setBackground( ovp->getBackground() );
                    vp->getMFForegrounds()->setValues( ovp->getForegrounds() );
                    vp->setCamera(deco);
                    _win->addPort(vp);
                    endEditCP(_win);
                    endEditCP(vp);
                    endEditCP(deco);
                }
            }
        }
        tbalance = -getSystemTime();
        loadManager->update(_win->getPort()[0]->getRoot());
        loadManager->balance(_win->getPort()[0],false,region);
        tbalance += getSystemTime();
        if(simulateRendering)
        {
            ViewportPtr vp;
            TileCameraDecoratorPtr deco;
            for(i=0;i<region.size();i+=4)
            {
#if 1
                cout << "Region: " << i << " ";
                cout << region[i+0] << " ";
                cout << region[i+1] << " ";
                cout << region[i+2] << " ";
                cout << region[i+3] << endl;
                if(region[i+0] >= region[i+2]) {
                    cout << "!!!" << endl;
                    region[i+2]++;
                }
                if(region[i+1] >= region[i+3]) {
                    cout << "!!!" << endl;
                    region[i+3]++;
                }
#endif
                vp=_win->getPort()[i/4+1];
                deco=TileCameraDecoratorPtr::dcast(vp->getCamera());
                beginEditCP(deco);
                beginEditCP(vp);
                vp->setSize(region[i+0],
                            region[i+1],
                            region[i+2],
                            region[i+3]);
                deco->setSize(region[i+0]/(float)_win->getWidth(),
                              region[i+1]/(float)_win->getHeight(),
                              region[i+2]/(float)_win->getWidth(),
                              region[i+3]/(float)_win->getHeight());
                endEditCP(deco);
                endEditCP(vp);
            }
        }
        Time t,tmin,tmax;
        for(i=0;i<_win->getPort().size();++i)
        {
            t=-getSystemTime();
            _action->setWindow( _win.getCPtr() );
            _win->getPort(i)->render( _action );
            glFlush();
            t+=getSystemTime();
            if(i==0)
                continue;
            if(i==1)
            {
                tmin=tmax=t;
            }
            else
            {
                if(t<tmin) tmin=t;
                if(t>tmax) tmax=t;
            }
        }
        if(!cache)
            printf("speed %5d %10.6f %10.6f %10.6f\n",_win->getPort().size()-1,
                   tmin,
                   tmax,
                   tbalance);
        glPushAttrib(GL_ALL_ATTRIB_BITS);
        glDisable(GL_SCISSOR_TEST);
        glViewport(0,0,
                   _win->getWidth(),
                   _win->getHeight());
        if(viewVolume)
            loadManager->drawVolumes(_win);
        glPushMatrix();
        glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        gluOrtho2D(0,_win->getWidth(),
                   0,_win->getHeight());
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_COLOR_MATERIAL);
        for(i=0;i<region.size();i+=4)
        {
#if 0
            cout << "Region: ";
            cout << region[i+0] << " ";
            cout << region[i+1] << " ";
            cout << region[i+2] << " ";
            cout << region[i+3] << endl;
#endif
            glBegin(GL_LINE_LOOP);
            glColor3f(1, 1, 0);
            glVertex3f(region[i+0],region[i+1],0);
            glVertex3f(region[i+2],region[i+1],0);
            glVertex3f(region[i+2],region[i+3],0);
            glVertex3f(region[i+0],region[i+3],0);
            glEnd();
        }
        glDisable(GL_COLOR_MATERIAL);
        glEnable(GL_DEPTH_TEST);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
        glPopAttrib();

        if(doSave)
        {
            Int32 w,h;
            w=_win->getPort(0)->getPixelWidth();
            h=_win->getPort(0)->getPixelHeight();
            Image image(Image::OSG_RGB_PF,
                        w,h,1,
                        1,1,0.0,
                        NULL,true);
            ImageFileType *imgTransType=ImageFileHandler::the().getFileType("JPEG");
            char filename[256];
            if(imgTransType==NULL)
            {
                cerr << "Unknown image trans type" << endl;
                return;
            }
            sprintf(filename,"%s_%d.jpg",dumpImage,dumpImageNr++);
            // read buffer data into image
            glPixelStorei(GL_PACK_ALIGNMENT,1);
            glReadPixels(0,0,w,h,
                         GL_RGB,GL_UNSIGNED_BYTE,
                         image.getData());
            imgTransType->write(image,filename);
        }
        _win->swap();
        _win->frameExit();
    }