OSGBalancedMultiWindow.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *               Copyright (C) 2000-2002 by the OpenSG Forum                 *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038
00039 //---------------------------------------------------------------------------
00040 //  Includes
00041 //---------------------------------------------------------------------------
00042
00043 #include "OSGConfig.h"
00044 #include "OSGBalancedMultiWindow.h"
00045
00046 #include "OSGClusterNetwork.h"
00047 #include "OSGTransform.h"
00048 #include "OSGPerspectiveCamera.h"
00049 #include "OSGSolidBackground.h"
00050 #include "OSGMatrixUtility.h"
00051 #include "OSGRenderAction.h"
00052
00053 #include "OSGChunkMaterial.h"
00054 #include "OSGProxyGroup.h"
00055 #include "OSGGeometry.h"
00056 #include "OSGSimpleSHLChunk.h"
00057 #include "OSGTileCameraDecorator.h"
00058
00059 #include "OSGGLU.h"
00060
00061 OSG_BEGIN_NAMESPACE
00062
00065 static void multFullMatrixPnt4 (Matrix m, Pnt4f &p)
00066 {
00067     Pnt4f tmp;
00068
00069     tmp[0] = m[0][0]*p[0] + m[1][0]*p[1] + m[2][0]*p[2] + m[3][0]*p[3];
00070     tmp[1] = m[0][1]*p[0] + m[1][1]*p[1] + m[2][1]*p[2] + m[3][1]*p[3];
00071     tmp[2] = m[0][2]*p[0] + m[1][2]*p[1] + m[2][2]*p[2] + m[3][2]*p[3];
00072     tmp[3] = m[0][3]*p[0] + m[1][3]*p[1] + m[2][3]*p[2] + m[3][3]*p[3];
00073
00074     p[0] = tmp[0];
00075     p[1] = tmp[1];
00076     p[2] = tmp[2];
00077     p[3] = tmp[3];
00078 }
00079
00080 /***************************************************************************\
00081  *                            Description                                  *
00082 \***************************************************************************/
00083
00088 /***************************************************************************\
00089  *                           Class variables                               *
00090 \***************************************************************************/
00091
00092 /***************************************************************************\
00093  *                           Class methods                                 *
00094 \***************************************************************************/
00095
00096 void BalancedMultiWindow::initMethod(InitPhase ePhase)
00097 {
00098     Inherited::initMethod(ePhase);
00099 }
00100
00101 /***************************************************************************\
00102  *                           Instance methods                              *
00103 \***************************************************************************/
00104
00105 /*-------------------------------------------------------------------------*\
00106  -  private                                                                 -
00107 \*-------------------------------------------------------------------------*/
00108
00109 /*----------------------- constructors & destructors ----------------------*/
00110
00111 BalancedMultiWindow::BalancedMultiWindow(void) :
00112      Inherited        (    ),
00113     _rebuildLoadGroups(true)
00114 {
00115 }
00116
00117 BalancedMultiWindow::BalancedMultiWindow(const BalancedMultiWindow &source) :
00118      Inherited        (source),
00119     _rebuildLoadGroups(true  )
00120 {
00121 }
00122
00123 BalancedMultiWindow::~BalancedMultiWindow(void)
00124 {
00125 }
00126
00127 void BalancedMultiWindow::resolveLinks(void)
00128 {
00129     for(UInt32 i = 0; i < _cluster.rootNodes.size(); ++i)
00130     {
00131         _cluster.rootNodes[i] = NULL;
00132     }
00133
00134     for(UInt32 i = 0; i < _cluster.loadGroups.size(); ++i)
00135     {
00136         _cluster.loadGroups[i].root = NULL;
00137         _cluster.loadGroups[i].node = NULL;
00138     }
00139
00140     for(UInt32 i = 0; i < _cluster.servers.size(); ++i)
00141     {
00142         for(UInt32 j = 0; j < _cluster.servers[i].viewports.size(); ++j)
00143         {
00144             _cluster.servers[i].viewports[j].serverPort = NULL;
00145             _cluster.servers[i].viewports[j].root       = NULL;
00146         }
00147     }
00148 }
00149
00150 /*----------------------------- class specific ----------------------------*/
00151
00152 void BalancedMultiWindow::changed(ConstFieldMaskArg whichField,
00153                                   UInt32            origin,
00154                                   BitVector         details)
00155 {
00156     Inherited::changed(whichField, origin, details);
00157 }
00158
00159 void BalancedMultiWindow::dump(      UInt32    ,
00160                          const BitVector ) const
00161 {
00162     SLOG << "Dump BalancedMultiWindow NI" << std::endl;
00163 }
00164
00165
00166 void BalancedMultiWindow::serverInit(Window *pServerWindow, UInt32 id)
00167 {
00168     Inherited::serverInit(pServerWindow,id);
00169 }
00170
00171 void BalancedMultiWindow::serverRender(Window           *pServerWindow,
00172                                        UInt32            id,
00173                                        RenderActionBase *action)
00174 {
00175     if(!getBalance())
00176     {
00177         _rebuildLoadGroups = true;
00178
00179         Inherited::serverRender(pServerWindow,id,action);
00180
00181         return;
00182     }
00183
00184     pServerWindow->activate ();
00185     pServerWindow->frameInit();
00186
00187     // clear background
00188     glDisable(GL_SCISSOR_TEST);
00189     glViewport(0,0,
00190                pServerWindow->getWidth(),
00191                pServerWindow->getHeight());
00192     glClearColor(0,0,0,0);
00193     glClear(GL_COLOR_BUFFER_BIT);
00194
00195     // initialize
00196     if(_cluster.servers.size() == 0)
00197     {
00198         // reset server list
00199         _cluster.servers.resize(getMFServers()->size() + 1);
00200         _cluster.servers[id].id = id;
00201
00202         getNetwork()->connectAllGroupToPoint(id,"StreamSock");
00203
00204         // do not buffer any data
00205         for(UInt32 i=0 ; i <= getMFServers()->size() ; ++i)
00206             getNetwork()->getConnection(i)->forceDirectIO();
00207
00208         _preloadCache = true;
00209     }
00210
00211     UInt32 count,vp,vpcount,wpcount;
00212     Server &server = _cluster.servers[id];
00213     std::vector<WorkPackage>::iterator wI;
00214     std::vector<Area>::iterator aI;
00215     std::vector<Tile>::iterator tI;
00216
00217     // set server window
00218     server.window = pServerWindow;
00219
00220     // create load groups for all root nodes
00221     createLoadGroups();
00222
00223     // preload texture and dlist cache
00224     preloadCache(pServerWindow,action);
00225
00226     _loadTime = -getSystemTime();
00227
00228     // collect visible viewports
00229     collectVisibleViewports(server);
00230
00231     // create bboxes
00232     createBBoxes(server);
00233
00234     _loadTime += getSystemTime();
00235
00236     // send bboxes of all viewports to client
00237     Connection *conn = getNetwork()->getMainConnection();
00238     vpcount = server.viewports.size();
00239     conn->putValue(id);
00240     conn->putValue(vpcount);
00241     for(vp=0 ; vp<vpcount ; ++vp)
00242     {
00243         VPort &port = server.viewports[vp];
00244         conn->putValue(port.id);
00245         conn->putValue(port.load);
00246         conn->putValues(port.loadCenter,2);
00247         conn->putValues(port.rect,4);
00248         count = port.bboxes.size();
00249         conn->putValue(count);
00250         if(count)
00251             conn->put(&port.bboxes[0],count*sizeof(BBox));
00252     }
00253     conn->flush();
00254
00255     // read workpackages
00256     conn->selectChannel();
00257     conn->getValue(wpcount);
00258     _cluster.workpackages.resize(wpcount);
00259     if(wpcount)
00260         conn->get(&_cluster.workpackages[0],wpcount*sizeof(WorkPackage));
00261
00262     _cluster.areas.clear();
00263     drawSendAndRecv(pServerWindow,action,id);
00264
00265     // send statistics
00266     if(getShowBalancing())
00267     {
00268         conn = getNetwork()->getMainConnection();
00269         conn->putValue(_triCount);
00270         conn->putValue(_drawTime);
00271         conn->putValue(_pixelTime);
00272         conn->putValue(_loadTime);
00273         conn->putValue(_netTime);
00274         conn->flush();
00275     }
00276
00277 #if 0
00278     // render bounding boxes
00279     glDisable(GL_SCISSOR_TEST);
00280     glViewport(0,0,
00281                pServerWindow->getWidth(),
00282                pServerWindow->getHeight());
00283     glPushMatrix();
00284       glLoadIdentity();
00285       glMatrixMode(GL_PROJECTION);
00286       glPushMatrix();
00287         glLoadIdentity();
00288         glOrtho(0, pServerWindow->getWidth(),
00289                 0, pServerWindow->getHeight(), -1, 1);
00290
00291         for(UInt32 v=0; v<_cluster.servers[id].viewports.size() ; ++v)
00292         {
00293             for(UInt32 b=0; b<_cluster.servers[id].viewports[v].bboxes.size() ; ++b)
00294             {
00295                 BBox &bbox = _cluster.servers[id].viewports[v].bboxes[b];
00296                 glBegin(GL_LINE_LOOP);
00297                 glColor3f(1, 1, 0);
00298                 glVertex2f(bbox.rect[LEFT],bbox.rect[BOTTOM]);
00299                 glVertex2f(bbox.rect[RIGHT],bbox.rect[BOTTOM]);
00300                 glVertex2f(bbox.rect[RIGHT],bbox.rect[TOP]);
00301                 glVertex2f(bbox.rect[LEFT],bbox.rect[TOP]);
00302                 glEnd();
00303             }
00304         }
00305
00306       glPopMatrix();
00307       glMatrixMode(GL_MODELVIEW);
00308     glPopMatrix();
00309 #endif
00310 }
00311
00312 void BalancedMultiWindow::clientInit(void)
00313 {
00314     Inherited::clientInit();
00315 }
00316
00317 void BalancedMultiWindow::clientPreSync(void)
00318 {
00319     if(getHServers() * getVServers() == 0 && getClientWindow() != NULL)
00320     {
00321         if(getWidth () != getClientWindow()->getWidth () ||
00322            getHeight() != getClientWindow()->getHeight())
00323         {
00324             setWidth (getClientWindow()->getWidth ());
00325             setHeight(getClientWindow()->getHeight());
00326         }
00327     }
00328     Inherited::clientPreSync();
00329 }
00330
00331 void BalancedMultiWindow::clientRender(RenderActionBase *action)
00332 {
00333     if(!getBalance())
00334     {
00335         _rebuildLoadGroups = true;
00336         Inherited::clientRender(action);
00337         return;
00338     }
00339     Connection::Channel channel;
00340     UInt32 bbcount,id,vp,vpcount,wpcount;
00341     double frameTime = -getSystemTime();
00342
00343     if(_cluster.servers.size() == 0)
00344     {
00345         // reset server list
00346         _cluster.servers.resize(getMFServers()->size()+1);
00347
00348         for(UInt32 id=0 ; id < getMFServers()->size()+1 ; ++id)
00349             _cluster.servers[id].id = id;
00350
00351         getNetwork()->connectAllGroupToPoint(getMFServers()->size(),
00352                                              "StreamSock");
00353
00354         // do not buffer any data
00355         for(UInt32 i=0 ; i <= getMFServers()->size() ; ++i)
00356             getNetwork()->getConnection(i)->forceDirectIO();
00357
00358         _preloadCache = true;
00359     }
00360
00361     // create load groups for all root nodes
00362     createLoadGroups();
00363
00364     // local visualization
00365     _loadTime = 0;
00366     if(getHServers() * getVServers() == 0 &&
00367         getClientWindow() != NULL)
00368     {
00369         _loadTime = -getSystemTime();
00370
00371         Server &server = _cluster.servers[getMFServers()->size()];
00372
00373         // set client window
00374         server.window = getClientWindow();
00375
00376         // collect visible viewports
00377         collectVisibleViewports(server);
00378
00379         // create bboxes
00380         createBBoxes(server);
00381         _loadTime += getSystemTime();
00382
00383         for(vp=0 ; vp < server.viewports.size() ; ++vp)
00384             server.load += server.viewports[vp].load;
00385
00386         // preload texture and dlist cache
00387         preloadCache(getClientWindow(),action);
00388     }
00389
00390     _netTime = 0;
00391     // read bboxes from all servers
00392     GroupConnection *conn = getNetwork()->getMainGroupConnection();
00393     while(conn->getSelectionCount())
00394     {
00395         channel = conn->selectChannel();
00396         conn->subSelection(channel);
00397         conn->getValue(id);
00398         conn->getValue(vpcount);
00399         Server &server = _cluster.servers[id];
00400         server.viewports.resize(vpcount);
00401         server.load = 0;
00402 //        printf("Server %d\n",id);
00403         for(vp=0 ; vp < vpcount ; ++vp)
00404         {
00405             VPort &port = server.viewports[vp];
00406             port.serverId = id;
00407             conn->getValue(port.id);
00408             conn->getValue(port.load);
00409             conn->getValues(port.loadCenter,2);
00410             conn->getValues(port.rect,4);
00411             conn->getValue(bbcount);
00412             port.bboxes.resize(bbcount);
00413 /*
00414             printf("Port %d %f\n",port.id,port.load);
00415             printf("%d %d %d %d\n",
00416                    port.rect[0],
00417                    port.rect[1],
00418                    port.rect[2],
00419                    port.rect[3]);
00420 */
00421             if(bbcount)
00422                 conn->get(&port.bboxes[0],bbcount*sizeof(BBox));
00423             server.load += port.load;
00424         }
00425     }
00426     conn->resetSelection();
00427     // do load balancing
00428     _balanceTime = -getSystemTime();
00429     balanceServer();
00430     _balanceTime += getSystemTime();
00431     // send work packages
00432     wpcount = _cluster.workpackages.size();
00433     conn->putValue(wpcount);
00434     conn->put(&_cluster.workpackages[0],wpcount*sizeof(WorkPackage));
00435     conn->flush();
00436     // client rendering ?
00437 //    if(getHServers() * getVServers() == 0)
00438
00439     drawSendAndRecv(getClientWindow(),action,getMFServers()->size());
00440
00441     // do local rendering if not switched off and no parallel 
00442     // rendering to local window
00443     if(getHServers() * getVServers() != 0 &&
00444        getClientWindow() != NULL)
00445     {
00446         getClientWindow()->renderAllViewports( action );
00447     }
00448
00449     // statistics
00450     UInt32 triCount;
00451     Real64 drawTime;
00452     Real64 pixelTime;
00453     Real64 loadTime;
00454     Real64 netTime;
00455     if(getShowBalancing())
00456     {
00457         printf("Statistics:\n");
00458         conn = getNetwork()->getMainGroupConnection();
00459         while(conn->getSelectionCount())
00460         {
00461             channel = conn->selectChannel();
00462             conn->subSelection(channel);
00463             conn->getValue(triCount);
00464             conn->getValue(drawTime);
00465             conn->getValue(pixelTime);
00466             conn->getValue(loadTime);
00467             conn->getValue(netTime);
00468             printf("Srv %4d L:%2.6lf T:%10d D:%2.6lf P:%2.6lf N:%2.6lf\n",channel,loadTime,triCount,drawTime,pixelTime,netTime);
00469         }
00470         conn->resetSelection();
00471         frameTime += getSystemTime();
00472         printf("Cli %4d L:%2.6lf T:%10d D:%2.6lf P:%2.6lf N:%2.6lf B:%2.6lf F:%2.6lf\n",
00473                getMFServers()->size(),
00474                _loadTime,
00475                _triCount,
00476                _drawTime,
00477                _pixelTime,
00478                _netTime,
00479                _balanceTime,
00480                frameTime);
00481         printf("end\n");
00482     }
00483 #if 0
00484     for(unsigned int p=0;p<_cluster.workpackages.size() ; ++p) {
00485         printf("from %d to %d    %d %d %d %d\n",
00486                _cluster.workpackages[p].drawServer,
00487                _cluster.workpackages[p].sendToServer,
00488                _cluster.workpackages[p].rect[0],
00489                _cluster.workpackages[p].rect[1],
00490                _cluster.workpackages[p].rect[2],
00491                _cluster.workpackages[p].rect[3]);
00492     }
00493 #endif
00494 }
00495
00496
00499 UInt32 BalancedMultiWindow::calcTileCount(Int32 const (&rect)[4])
00500 {
00501     UInt32 x = (rect[RIGHT] - rect[LEFT  ]) / MW_TILE_SIZE + 1;
00502     UInt32 y = (rect[TOP  ] - rect[BOTTOM]) / MW_TILE_SIZE + 1;
00503     return x*y;
00504 }
00505
00508 bool BalancedMultiWindow::calculateProjectedBBox(VPort &port,
00509                                                  LoadGroup &group,
00510                                                  BBox &bbox,
00511                                                  Matrix &proj)
00512 {
00513     Pnt3f vol[2];
00514     Pnt3f pnt3;
00515     Real32 minx=0,miny=0;
00516     Real32 maxx=0,maxy=0;
00517
00518     Int32 width = port.serverPort->getPixelWidth();
00519     Int32 height = port.serverPort->getPixelHeight();
00520 #if 1
00521     Matrix trans = group.node->getToWorld();
00522     trans.multLeft(proj);
00523
00524     Pnt4f pnt[8];
00525     Int32 cl=0, cb=0, cr=0, ct=0, cn=0, cf=0;
00526     Int32 bit = 1;
00527
00528     // get local volume
00529     BoxVolume volume = group.node->getVolume();
00530 #else
00531     Matrix trans = proj;
00532
00533     Pnt4f pnt[8];
00534     Int32 cl=0, cb=0, cr=0, ct=0, cn=0, cf=0;
00535     Int32 bit = 1;
00536
00537     // get local volume
00538     BoxVolume volume = group.node->getVolume();
00539     volume.transform(group.node->getToWorld());
00540
00541 #endif
00542     volume.getBounds (vol[0], vol[1]);
00543
00544     for(int i=0;i<8;++i)
00545     {
00546         pnt[i] = Pnt4f (vol[ (i   )&1 ][0],
00547                         vol[ (i>>1)&1 ][1],
00548                         vol[ (i>>2)&1 ][2],
00549                         1.0);
00550
00551         multFullMatrixPnt4 (trans, pnt[i]);
00552
00553         // fill bit fields with clipping data
00554         if (pnt[i][0] >= -pnt[i][3]) cl += bit;
00555         if (pnt[i][0] <=  pnt[i][3]) cr += bit;
00556         if (pnt[i][1] >= -pnt[i][3]) cb += bit;
00557         if (pnt[i][1] <=  pnt[i][3]) ct += bit;
00558         if (pnt[i][2] >= -pnt[i][3]) cn += bit;
00559         if (pnt[i][2] <=  pnt[i][3]) cf += bit;
00560
00561         bit *= 2;
00562     }
00563
00564     // whole bounding box clipped
00565     if ((cl == 0) || (cb == 0) || (cr == 0) ||
00566         (ct == 0) || (cn == 0) || (cf == 0))
00567     {
00568         return false;
00569     }
00570
00571     // bounding box on near plane !!!
00572     if (cn < 255)
00573     {
00574         bit = 1;
00575
00576         for (int i = 0; i < 8; ++i)
00577         {
00578             // point behind nearplane? -> point to corner
00579             if ((cn & bit) == 0)
00580             {
00581                 pnt[i][0] = pnt[i][0] < 0 ? -1 : 1;
00582                 pnt[i][1] = pnt[i][1] < 0 ? -1 : 1;
00583                 pnt[i][2] = -1;
00584                 pnt[i][3] = 1;
00585             }
00586
00587             bit *= 2;
00588         }
00589     }
00590
00591     for (int i = 0; i < 8; ++i)
00592     {
00593         // switch to normal coordinate system
00594         pnt[i][0] /= pnt[i][3];
00595         pnt[i][1] /= pnt[i][3];
00596
00597         // scale to window coordinates
00598         pnt[i][0] = (pnt[i][0] + 1) * width / 2.0;
00599         pnt[i][1] = (pnt[i][1] + 1) * height / 2.0;
00600
00601         if (i > 0)
00602         {
00603             if (minx > pnt[i][0]) minx = pnt[i][0];
00604             if (miny > pnt[i][1]) miny = pnt[i][1];
00605             if (maxx < pnt[i][0]) maxx = pnt[i][0];
00606             if (maxy < pnt[i][1]) maxy = pnt[i][1];
00607         }
00608         else
00609         {
00610             maxx = minx = pnt[i][0];
00611             maxy = miny = pnt[i][1];
00612         }
00613     }
00614 /*
00615     bbox.rect[LEFT]   = (Int32)osgfloor(minx + port.serverPort->getPixelLeft ());
00616     bbox.rect[RIGHT]  = (Int32)osgceil (maxx + port.serverPort->getPixelLeft ());
00617     bbox.rect[BOTTOM] = (Int32)osgfloor(miny + port.serverPort->getPixelBottom ());
00618     bbox.rect[TOP]    = (Int32)osgceil (maxy + port.serverPort->getPixelBottom ());
00619 */
00620     bbox.rect[LEFT]   = Int32(minx + port.serverPort->getPixelLeft ());
00621     bbox.rect[RIGHT]  = Int32(maxx + port.serverPort->getPixelLeft ());
00622     bbox.rect[BOTTOM] = Int32(miny + port.serverPort->getPixelBottom ());
00623     bbox.rect[TOP]    = Int32(maxy + port.serverPort->getPixelBottom ());
00624
00625 #if 0
00626     // draw bounding boxes
00627     glViewport(0,0,
00628                port.serverPort->getParent()->getWidth(),
00629                port.serverPort->getParent()->getHeight());
00630     glPushMatrix();
00631       glLoadIdentity();
00632       glMatrixMode(GL_PROJECTION);
00633       glPushMatrix();
00634         glLoadIdentity();
00635         glOrtho(0, port.serverPort->getParent()->getWidth(),
00636                 0, port.serverPort->getParent()->getHeight(), -1, 1);
00637         glBegin(GL_LINE_LOOP);
00638         glColor3f(1, 1, 0);
00639         glVertex2f(bbox.rect[LEFT],bbox.rect[BOTTOM]);
00640         glVertex2f(bbox.rect[RIGHT],bbox.rect[BOTTOM]);
00641         glVertex2f(bbox.rect[RIGHT],bbox.rect[TOP]);
00642         glVertex2f(bbox.rect[LEFT],bbox.rect[TOP]);
00643         glEnd();
00644       glPopMatrix();
00645       glMatrixMode(GL_MODELVIEW);
00646     glPopMatrix();
00647 #endif
00648     return true;
00649 }
00650
00651
00652
00657 void BalancedMultiWindow::createLoadGroups(void)
00658 {
00659     Viewport *viewport;
00660     Node     *root;
00661     UInt32    v;
00662
00663     if(!_rebuildLoadGroups)
00664     {
00665         // only if something changed
00666         ChangeList *changeList = OSG::Thread::getCurrentChangeList();
00667
00668         if(changeList->getNumCreated  () == 0 &&
00669            changeList->getNumDestroyed() == 0)
00670         {
00671             _rebuildLoadGroups = false;
00672         }
00673         else
00674         {
00675             _rebuildLoadGroups = true;
00676         }
00677     }
00678
00679     if(!_rebuildLoadGroups)
00680         return;
00681
00682     _preloadCache = true;
00683
00684     // reset all;
00685     _cluster.rootNodes.clear();
00686     _cluster.loadGroups.clear();
00687     // loop over all viewports
00688     for(v = 0 ; v  < getMFPort()->size() ; ++v )
00689     {
00690         viewport = getPort(v);
00691         root = viewport->getRoot();
00692
00693 #ifdef __sun
00694         UInt32 uiCount;
00695
00696         std::count(_cluster.rootNodes.begin(),
00697                    _cluster.rootNodes.end(),
00698                    root,
00699                    uiCount);
00700
00701         if(uiCount)
00702             continue;
00703 #else
00704         // ignore multiple viewports with same root 
00705         if(std::count(_cluster.rootNodes.begin(),
00706                       _cluster.rootNodes.end(),
00707                       root))
00708             continue;
00709 #endif
00710         _cluster.rootNodes.push_back(root);
00711         // recousiveley collect groups
00712         collectLoadGroups(root,root);
00713     }
00714     _rebuildLoadGroups = false;
00715 }
00716
00717
00722 void BalancedMultiWindow::collectLoadGroups(Node *node, Node *root)
00723 {
00724     LoadGroup load;
00725 #if 0    
00726     UInt32 lastSize;
00727 #endif    
00728 
00729     MFUnrecChildNodePtr::const_iterator child;
00730
00731     // ignore null node
00732     if(node == NULL)
00733         return;
00734
00735     NodeCore *core = node->getCore();
00736     if(core != NULL)
00737     {
00738         Geometry      *geo   = NULL;
00739         ProxyGroup    *proxy = NULL;
00740
00741         load.root = root;
00742         load.constant = 0;
00743         load.pixel = 0;
00744         load.ratio = 0;
00745         load.node = node;
00746
00747         // handle poxy groups
00748         proxy = dynamic_cast<ProxyGroup *>(core);
00749         if(proxy != NULL)
00750         {
00751             load.constant = proxy->getIndices() / MW_INDICES_PER_SEC;
00752             load.ratio    = proxy->getIndices() / MW_VISIBLE_INDICES_PER_SEC;
00753         }
00754         geo = dynamic_cast<Geometry *>(core);
00755         if(geo != NULL)
00756         {
00757             GeoIntegralProperty *indices =
00758                 geo->getIndex(Geometry::PositionsIndex);
00759
00760             GeoVectorProperty *positions = geo->getPositions();
00761
00762             ChunkMaterial *mat =
00763                 dynamic_cast<ChunkMaterial *> (geo->getMaterial ());
00764
00765             // constant geometry setup cost
00766             if ((indices != NULL))
00767             {
00768                 load.constant = indices->getSize() / MW_INDICES_PER_SEC;
00769                 load.ratio    = indices->getSize() / MW_VISIBLE_INDICES_PER_SEC;
00770             }
00771             else
00772                 if(positions != NULL)
00773                 {
00774                     load.constant = positions->getSize() / MW_INDICES_PER_SEC;
00775                     load.ratio    = positions->getSize() / MW_VISIBLE_INDICES_PER_SEC;
00776                 }
00777             // pixel cost for shaders
00778             if (mat != NULL && mat->find (SimpleSHLChunk::getClassType ()) != NULL)
00779                 load.pixel =  1.0f / Real32(MW_SHADED_PIXEL_PER_SEC);
00780             else
00781                 load.pixel = 1.0f / Real32(MW_PIXEL_PER_SEC);
00782 //                load.pixel = 0;
00783         }
00784         if(load.pixel > 0 || load.constant > 0)
00785             _cluster.loadGroups.push_back(load);
00786     }
00787
00788 #if 0    
00789     lastSize = _cluster.loadGroups.size();
00790 #endif
00791     // loop over all child nodes
00792     for(child = node->getMFChildren()->begin() ;
00793         child != node->getMFChildren()->end() ;
00794         ++child)
00795     {
00796         collectLoadGroups(*child,root);
00797     }
00798 #if 0
00799     if(lastSize + 1 < _cluster.loadGroups.size())
00800     {
00801         load.root = root;
00802         load.constant = 0;
00803         load.pixel = 0;
00804         load.node = node;
00805         // calculate summed group
00806         for(l = lastSize ; l < _cluster.loadGroups.size() ; ++l)
00807         {
00808             load.constant     += _cluster.loadGroups[l].constant;
00809             load.pixel        += _cluster.loadGroups[l].pixel;
00810             load.root          = root;
00811         }
00812         // merge small grops
00813         if(load.constant < 500.0 / MW_INDICES_PER_SEC &&
00814            load.pixel <= 1.0 / Real32(MW_PIXEL_PER_SEC))
00815         {
00816             _cluster.loadGroups.resize(lastSize);
00817             _cluster.loadGroups.push_back(load);
00818         }
00819     }
00820 #endif
00821 }
00822
00823
00826 void BalancedMultiWindow::collectVisibleViewports(Server &server)
00827 {
00828     UInt32 cv,sv=0;
00829
00830     for(cv = 0 ; cv < getMFPort()->size() ; cv++)
00831     {
00832         if(server.viewports.size() <= sv)
00833             server.viewports.resize(sv+1);
00834
00835         VPort &port = server.viewports[sv];
00836
00837         port.id = cv;
00838         port.serverId = server.id;
00839         port.root = getPort(cv)->getRoot();
00840         if(calculateServerPort(port,port.rect))
00841             sv++;
00842     }
00843
00844     server.viewports.resize(sv);
00845 }
00846
00847
00851 bool BalancedMultiWindow::calculateServerPort(VPort &port,
00852                                               Int32 const (&rect)[4])
00853 {
00854     Int32 cleft,cright,ctop,cbottom;
00855     Viewport *serverPort, *clientPort;
00856     TileCameraDecoratorUnrecPtr deco;
00857 //    UInt32 cv,sv=0;
00858
00859     // calculate visible area;
00860     UInt32 row;
00861     UInt32 column;
00862     UInt32 width;
00863     UInt32 height;
00864     UInt32 rows,cols;
00865
00866     if(getHServers() * getVServers() == 0)
00867     {
00868         if(port.serverId != getMFServers()->size())
00869             return false;
00870         // balanced client rendering
00871         rows = 1;
00872         cols = 1;
00873         row = 0;
00874         column = 0;
00875     }
00876     else
00877     {
00878         rows = getVServers();
00879         cols = getHServers();
00880         row = port.serverId/cols;
00881         column = port.serverId%cols;
00882     }
00883     width = getWidth() / cols;
00884     height = getHeight() / rows;
00885
00886     Int32 left   = column * width  - column * getXOverlap();
00887     Int32 bottom = row    * height - row    * getYOverlap();
00888     Int32 right  = left   + width  - 1;
00889     Int32 top    = bottom + height - 1;
00890     Real32 scaleCWidth  = ((width - getXOverlap()) * (cols - 1) + width) /
00891         Real32(getWidth());
00892     Real32 scaleCHeight = ((height - getYOverlap())* (rows - 1) + height)/
00893         Real32(getHeight());
00894
00895     clientPort = getPort(port.id);
00896     cleft   = Int32(clientPort->getPixelLeft()      * scaleCWidth)   ;
00897     cbottom = Int32(clientPort->getPixelBottom()    * scaleCHeight)  ;
00898     cright  = Int32((clientPort->getPixelRight()+1) * scaleCWidth) -1;
00899     ctop    = Int32((clientPort->getPixelTop()+1)   * scaleCHeight)-1;
00900
00901     if(cright  < left   ||
00902        cleft   > right  ||
00903        ctop    < bottom ||
00904        cbottom > top      )
00905     {
00906         // invisible on this server screen
00907         return false;
00908     }
00909     // visible rectangle on server window
00910     port.rect[LEFT]   = osgMax(cleft  ,left  ) - left;
00911     port.rect[BOTTOM] = osgMax(cbottom,bottom) - bottom;
00912     port.rect[RIGHT]  = osgMin(cright ,right ) - left;
00913     port.rect[TOP]    = osgMin(ctop   ,top   ) - bottom;
00914
00915     // verify if the viewport type has changed
00916     if(port.serverPort != NULL)
00917     {
00918         if(port.serverPort->getType().getId() != getPort(port.id)->getType().getId())
00919         {
00920             // this must not happen very frequently, otherwise, memory leak may occur
00921             //subRefX(port.serverPort->getCamera());
00922             //subRefX(port.serverPort);
00923             port.serverPort = NULL;
00924         }
00925
00926     }
00927
00928     // create port and deco for visualization, only if necessary
00929     if(port.serverPort == NULL)
00930     {
00931         ViewportUnrecPtr pTmpPort =
00932             dynamic_pointer_cast<Viewport>(getPort(port.id)->shallowCopy());
00933
00934         port.serverPort = pTmpPort;
00935
00936         deco = TileCameraDecorator::create();
00937         port.serverPort->setCamera(deco);
00938     }
00939     else
00940     {
00941         deco =
00942             dynamic_cast<TileCameraDecorator *>(port.serverPort->getCamera());
00943     }
00944     // decorate client camera
00945     deco->setDecoratee( clientPort->getCamera() );
00946
00947     serverPort = port.serverPort;
00948
00949     // duplicate values
00950     serverPort->setSize(Real32(rect[LEFT]),
00951                         Real32(rect[BOTTOM]),
00952                         Real32(rect[RIGHT]),
00953                         Real32(rect[TOP]));
00954     // use pixel even if pixel = 1
00955     if(serverPort->getLeft() == 1.0)
00956         serverPort->setLeft(1.0001f);
00957     if(serverPort->getRight() == 1.0)
00958         serverPort->setRight(1.0001f);
00959     if(serverPort->getTop() == 1.0)
00960         serverPort->setTop(1.0001f);
00961     if(serverPort->getBottom() == 1.0)
00962         serverPort->setBottom(1.0001f);
00963     serverPort->setRoot      ( clientPort->getRoot()       );
00964     serverPort->setBackground( clientPort->getBackground() );
00965     serverPort->assignForegrounds(*(clientPort->getMFForegrounds()) );
00966     serverPort->setTravMask  ( clientPort->getTravMask()   );
00967
00968     // calculate tile parameters
00969 #if 0
00970     deco->setFullWidth ( cright-cleft);
00971     deco->setFullHeight( ctop-cbottom);
00972     deco->setSize( ( rect[LEFT]+left-cleft       ) / (float)( cright-cleft ),
00973                    ( rect[BOTTOM]+bottom-cbottom ) / (float)( ctop-cbottom ),
00974                    ( rect[RIGHT]+left-cleft      ) / (float)( cright-cleft ),
00975                    ( rect[TOP]+bottom-cbottom    ) / (float)( ctop-cbottom ) );
00976 #else
00977     deco->setFullWidth ( cright-cleft + 1 );
00978     deco->setFullHeight( ctop-cbottom + 1 );
00979     deco->setSize( ( -(rect[LEFT]+left-cleft)       ),
00980                    ( -(rect[BOTTOM]+bottom-cbottom) ),
00981                    ( -(rect[RIGHT]+left-cleft+1)    ),
00982                    ( -(rect[TOP]+bottom-cbottom+1)  ) );
00983 #endif
00984     deco->setDecoratee( clientPort->getCamera() );
00985
00986     return true;
00987 }
00988
00989
00990
00993 void BalancedMultiWindow::createBBoxes(Server &server)
00994 {
00995     std::vector<VPort>::iterator vI;
00996     UInt32 gI;
00997     server.load = 0;
00998     UInt32 bbcount=0;
00999     Real32 load,sumLoad;
01000     Int32  bbmin[2];
01001     Int32  bbmax[2];
01002
01003     for(vI = server.viewports.begin() ; vI != server.viewports.end() ; ++vI)
01004     {
01005         bbmin[0] = vI->rect[RIGHT];
01006         bbmin[1] = vI->rect[TOP];
01007         bbmax[0] = vI->rect[LEFT];
01008         bbmax[1] = vI->rect[BOTTOM];
01009
01010         // add port to get pixel values
01011         server.window->addPort(vI->serverPort);
01012
01013         // projection matrix
01014         Matrix viewing,projection,projectionTrans;
01015         Int32 width = vI->serverPort->getPixelWidth();
01016         Int32 height = vI->serverPort->getPixelHeight();
01017         vI->serverPort->getCamera()->getViewing (viewing, width, height);
01018         vI->serverPort->getCamera()->getProjection (projection, width, height);
01019         vI->serverPort->getCamera()->getProjectionTranslation( projectionTrans, width, height);
01020         projection.mult(projectionTrans);
01021         projection.mult(viewing);
01022
01023         sumLoad = 0;
01024         vI->loadCenter[0] = vI->loadCenter[1] = 0;
01025         for(gI = 0 ; gI != _cluster.loadGroups.size() ; ++gI)
01026         {
01027             LoadGroup &group = _cluster.loadGroups[gI];
01028             if(group.root == vI->root)
01029             {
01030                 if(vI->bboxes.size() <= bbcount)
01031                     vI->bboxes.resize(bbcount+1);
01032                 // new group
01033                 BBox &bbox = vI->bboxes[bbcount];
01034                 bbox.groupId = gI;
01035                 // get bbox
01036                 if(calculateProjectedBBox(*vI,group,bbox,projection))
01037                 {
01038                     // calculate load
01039                     load = getVisibleLoad(vI->rect,bbox);
01040                     sumLoad += load;
01041                     vI->loadCenter[0] += load*(bbox.rect[0]+bbox.rect[2])/2;
01042                     vI->loadCenter[1] += load*(bbox.rect[1]+bbox.rect[3])/2;
01043                     bbcount++;
01044                     if(bbox.rect[LEFT] < bbmin[0])
01045                         bbmin[0] = bbox.rect[LEFT];
01046                     if(bbox.rect[BOTTOM] < bbmin[1])
01047                         bbmin[1] = bbox.rect[BOTTOM];
01048                     if(bbox.rect[RIGHT] > bbmax[0])
01049                         bbmax[0] = bbox.rect[RIGHT];
01050                     if(bbox.rect[TOP] > bbmax[1])
01051                         bbmax[1] = bbox.rect[TOP];
01052                 }
01053             }
01054         }
01055         vI->load = sumLoad;
01056         vI->bboxes.resize(bbcount);
01057         if(sumLoad)
01058         {
01059             vI->loadCenter[0] /= sumLoad;
01060             vI->loadCenter[1] /= sumLoad;
01061         }
01062
01063         if(bbmin[0] <= bbmax[0])
01064         {
01065             if(bbmin[0] > vI->rect[LEFT])
01066                 vI->rect[LEFT] = bbmin[0];
01067             if(bbmax[0] < vI->rect[RIGHT])
01068                 vI->rect[RIGHT] = bbmax[0];
01069         }
01070         if(bbmin[1] <= bbmax[1])
01071         {
01072             if(bbmin[1] > vI->rect[BOTTOM])
01073                 vI->rect[BOTTOM] = bbmin[1];
01074             if(bbmax[1] < vI->rect[TOP])
01075                 vI->rect[TOP] = bbmax[1];
01076         }
01077
01078         // sub port
01079         server.window->subPortByObj(vI->serverPort);
01080     }
01081 }
01082
01085 void BalancedMultiWindow::balanceServer(void)
01086 {
01087     Worker wo;
01088     Int32 low,heigh;
01089     UInt32 serverId;
01090     UInt32 vI;
01091     Real32 tooMuch,medLoad,load=0;
01092     std::vector<Server*> server;
01093     std::vector<Worker>  worker;
01094     ServerComp comp;
01095     Real32 tolerance;
01096     WorkPackage wp;
01097     UInt32 count;
01098
01099     if(getHServers()*getVServers() == 0)
01100         count = getMFServers()->size() + 1;
01101     else
01102         count = getMFServers()->size();
01103
01104     // clear work packages
01105     _cluster.workpackages.clear();
01106     // min 2 servers
01107 /*
01108     if(count < 2)
01109         return;
01110 */
01111     // collect and sort server load
01112     for(serverId = 0 ; serverId < count ; ++serverId)
01113     {
01114 //        printf("id %d load %f\n",serverId,_cluster.servers[serverId].load);
01115         server.push_back(&_cluster.servers[serverId]);
01116         load += _cluster.servers[serverId].load;
01117     }
01118     // sort
01119     std::sort(server.begin(),server.end(),comp);
01120     // median load
01121     medLoad = load / count;
01122     low = 0;
01123     heigh = server.size() - 1;
01124     tolerance = medLoad * 0.1;
01125 //    tolerance = medLoad * .8;
01126     while(low < heigh && server[heigh]->load - tolerance > medLoad)
01127     {
01128         worker.clear();
01129
01130         // find some servers to take load
01131         tooMuch = server[heigh]->load - medLoad;
01132 #if 0
01133         // client does no rendering TEST TEST
01134         if(server[heigh]->id == getServers().size())
01135             tooMuch = server[heigh]->load;
01136 #endif
01137         while(tooMuch > tolerance &&
01138               server[low]->load + tolerance < medLoad)
01139         {
01140             // create new worker
01141             wo.serverId = server[low]->id;
01142             wo.takeLoad = osgMin(tooMuch,medLoad - server[low]->load);
01143             worker.push_back(wo);
01144             tooMuch -= wo.takeLoad;
01145             server[heigh]->load -= wo.takeLoad;
01146             server[low]->load   += wo.takeLoad;
01147             if(server[low]->load + tolerance >= medLoad)
01148                 low++;
01149         }
01150         if(worker.size())
01151         {
01152             // remaining self rendering
01153             wo.serverId = server[heigh]->id;
01154             wo.takeLoad = server[heigh]->load;
01155             worker.push_back(wo);
01156             for(vI = 0 ; vI < _cluster.servers[wo.serverId].viewports.size() ; ++vI)
01157             {
01158                 VPort &port = _cluster.servers[wo.serverId].viewports[vI];
01159                 splitViewport(worker,port,port.rect,port.load);
01160 #if 0
01161                 for(int i=0 ; i<worker.size() ; ++i)
01162                 {
01163                     printf("%10.6f %10.6f\n",
01164                            worker[i].takeLoad,
01165                            worker[i].assignedLoad);
01166                     server[worker[i].serverId]->load -= worker[i].takeLoad;
01167                     server[worker[i].serverId]->load += worker[i].assignedLoad;
01168                 }
01169 #endif
01170             }
01171         } else {
01172             // stop no further spilt possible
01173             break;
01174         }
01175 #if 0
01176         if(server[low]->load + tolerance >= medLoad)
01177         {
01178             printf("Avoid overload\n");
01179             low++;
01180         }
01181 #endif
01182         heigh--;
01183     }
01184     // others should render there whole viewport
01185     while(heigh >= 0)
01186     {
01187         for(vI = 0 ; vI < _cluster.servers[server[heigh]->id].viewports.size() ; ++vI)
01188         {
01189             VPort &port = _cluster.servers[server[heigh]->id].viewports[vI];
01190             wp.viewportId   = port.id;
01191             wp.drawServer   = server[heigh]->id;
01192             wp.sendToServer = server[heigh]->id;
01193             for(int i=0 ; i<4 ; ++i)
01194                 wp.rect[i]  = port.rect[i];
01195             _cluster.workpackages.push_back(wp);
01196         }
01197         heigh--;
01198     }
01199 #if 0
01200     for(int j=0;j<_cluster.workpackages.size() ; ++j)
01201     {
01202         printf("vp          %d\n",_cluster.workpackages[j].viewportId);
01203         printf("render      %d\n",_cluster.workpackages[j].drawServer);
01204         printf("display     %d\n",_cluster.workpackages[j].sendToServer);
01205         printf("rect        %d %d %d %d\n",
01206                _cluster.workpackages[j].rect[0],
01207                _cluster.workpackages[j].rect[1],
01208                _cluster.workpackages[j].rect[2],
01209                _cluster.workpackages[j].rect[3]);
01210     }
01211 #endif
01212 }
01213
01214
01217 void BalancedMultiWindow::splitViewport(std::vector<Worker> &allWorker,
01218                                         VPort &port,
01219                                         Int32 const (&rect)[4],
01220                                         Real32 portLoad)
01221 {
01222     UInt32 i;
01223     WorkPackage wp;
01224     std::vector<Worker>::iterator wI;
01225     Real32 load[2] = {0,0};
01226     std::vector<Worker> worker[2];
01227     Int32  localWorkerSide,side;
01228     Int32  localWorkerSideTry[2];
01229     Real32 resultLoad[2];
01230     Int32  resultRect[2][4];
01231     Real32 resultLoadTry[2][2];
01232     Int32  resultRectTry[2][2][4];
01233     UInt32 axis;
01234 //    Real32 threshold;
01235 //    Real32 maxLoad1,maxLoad2;
01236     UInt32 fromAxis,toAxis;
01237     bool bestCut=getBestCut();
01238
01239     if(rect[2] - rect[0] == 0 ||
01240        rect[3] - rect[1] == 0)
01241     {
01242         bestCut = false;
01243     }
01244
01245     localWorkerSide = -1;
01246     for(wI = allWorker.begin() ; wI != allWorker.end() ; ++wI)
01247     {
01248         if(load[0] <= load[1])
01249             side = 0;
01250         else
01251             side = 1;
01252         // add load
01253         load[side] += wI->takeLoad;
01254         worker[side].push_back(*wI);
01255         // local worker
01256         if(wI->serverId == port.serverId)
01257         {
01258             localWorkerSide = side;
01259         }
01260     }
01261
01262     // scale load
01263     Real32 scale = portLoad / (load[0] + load[1]);
01264     load[0] *= scale;
01265     load[1] *= scale;
01266
01267     if(bestCut)
01268     {
01269         // check both axis for best cut
01270         fromAxis=0;
01271         toAxis=1;
01272     }
01273     else
01274     {
01275         // check for axis and split direction
01276         if(rect[RIGHT] - rect[LEFT  ] >
01277            rect[TOP  ] - rect[BOTTOM])
01278             fromAxis = toAxis = 0;
01279         else
01280             fromAxis = toAxis = 1;
01281     }
01282
01283     for(axis = fromAxis ; axis <= toAxis ; ++axis)
01284     {
01285         if(localWorkerSide >= 0)
01286         {
01287             if(fabs(port.loadCenter[axis] - rect[LEFT +axis]) >
01288                fabs(port.loadCenter[axis] - rect[RIGHT+axis]))
01289                 // most load is right, so do local rendering left
01290                 localWorkerSideTry[axis] = 0;
01291             else
01292                 // most load is left, so do local rendering right
01293                 localWorkerSideTry[axis] = 1;
01294             // change sides
01295             if(localWorkerSide != localWorkerSideTry[axis])
01296             {
01297                 std::vector<Worker> w = worker[1];
01298                 worker[1] = worker[0];
01299                 worker[0] = w;
01300                 Real32 l = load[1];
01301                 load[1] = load[0];
01302                 load[0] = l;
01303                 localWorkerSide = localWorkerSideTry[axis];
01304             }
01305         }
01306         else
01307             localWorkerSideTry[axis] = localWorkerSide;
01308         // split
01309         splitAxis(load,port,rect,axis,resultLoadTry[axis],resultRectTry[axis]);
01310     }
01311
01312     // find best cut
01313     if(bestCut)
01314     {
01315         if(osgMax(resultLoadTry[0][0],resultLoadTry[0][1]) <
01316            osgMax(resultLoadTry[1][0],resultLoadTry[1][1]))
01317             axis = 0;
01318         else
01319             axis = 1;
01320 /*
01321         printf("best %d: %f %f    %f %f\n",axis,
01322                resultLoadTry[0][0],resultLoadTry[0][1],
01323                resultLoadTry[1][0],resultLoadTry[1][1]);
01324 */
01325     }
01326     else
01327         axis = fromAxis;
01328
01329     // take best load
01330     if(localWorkerSideTry[axis] != localWorkerSide)
01331     {
01332         std::vector<Worker> w = worker[1];
01333         worker[1] = worker[0];
01334         worker[0] = w;
01335         Real32 l = load[1];
01336         load[1] = load[0];
01337         load[0] = l;
01338         localWorkerSide = localWorkerSideTry[axis];
01339     }
01340     resultLoad[0] = resultLoadTry[axis][0];
01341     resultLoad[1] = resultLoadTry[axis][1];
01342     for(i=0 ; i<4 ; ++i)
01343     {
01344         resultRect[0][i] = resultRectTry[axis][0][i];
01345         resultRect[1][i] = resultRectTry[axis][1][i];
01346     }
01347
01348     // dont cut if only 1 percent is taken from load
01349 //    threshold = (load[0] + load[1]) * 0.0001;
01350
01351     // take full viewport, if the split is not performance relevant
01352     // This makes only sense if one of the sides contain a local 
01353     // renderer
01354     if( (worker[0].size() == 1                             &&
01355          worker[1].size() == 1)                               &&
01356 #if 1
01357         (resultLoad[0] == 0.0 || resultLoad[1] == 0.0)
01358 #else
01359         ((resultLoad[0] + threshold) > (load[0] + load[1]) ||
01360          (resultLoad[1] + threshold) > (load[0] + load[1]))
01361 #endif
01362         )
01363     {
01364         bool toLeft  = false;
01365         bool toRight = false;
01366
01367         if(localWorkerSide == 0)
01368             toLeft  = true;
01369         else
01370             if(localWorkerSide == 1)
01371                 toRight = true;
01372             else
01373                 if(load[0] > load[1])
01374                     toLeft = true;
01375                 else
01376                     if(load[0] <= load[1])
01377                         toRight = true;
01378         if(toLeft)
01379         {
01380             resultLoad[0] = load[0] + load[1];
01381             resultLoad[1] = 0;
01382             resultRect[0][axis+2] = rect[axis+2];
01383             resultRect[1][axis]   = rect[axis+2] + 1;
01384         }
01385         if(toRight)
01386         {
01387             resultLoad[0] = 0;
01388             resultLoad[1] = load[0] + load[1];
01389             resultRect[0][axis+2] = rect[axis] - 1;
01390             resultRect[1][axis]   = rect[axis];
01391         }
01392     }
01393     // next recoursion stop
01394     for(int g=0 ; g<2 ; ++g)
01395     {
01396         // ignore nonsense cut
01397         if(resultRect[g][RIGHT] >= resultRect[g][LEFT] &&
01398            resultRect[g][TOP] >= resultRect[g][BOTTOM])
01399         {
01400             if(worker[g].size() > 1)
01401                 splitViewport(worker[g],port,resultRect[g],resultLoad[g]);
01402             else
01403             {
01404                 // assigned load
01405                 worker[g][0].assignedLoad = resultLoad[g];
01406                 // end of recoursion
01407                 wp.viewportId   = port.id;
01408                 wp.drawServer   = worker[g][0].serverId;
01409                 wp.sendToServer = port.serverId;
01410                 for(i=0 ; i<4 ; ++i)
01411                     wp.rect[i]  = resultRect[g][i];
01412                 _cluster.workpackages.push_back(wp);
01413 /*
01414                 printf("work server %d -> %d   %f\n",
01415                        worker[g][0].serverId,
01416                        port.serverId,resultLoad[g]);
01417 */
01418             }
01419         }
01420     }
01421
01422     allWorker.clear();
01423     allWorker.reserve(worker[0].size() + worker[1].size());
01424     allWorker.assign(worker[0].begin(), worker[0].end());
01425     std::copy(worker[1].begin(), worker[1].end(),
01426               std::back_insert_iterator<std::vector<Worker> >(allWorker));
01427
01428     /*
01429     allWorker.insert(allWorker.end(),worker[0].begin(),worker[0].end());
01430     allWorker.insert(allWorker.end(),worker[1].begin(),worker[1].end());
01431     */
01432 }
01433
01436 void BalancedMultiWindow::sortBBoxes(VPort &port,UInt32 axis,
01437                                      Int32 const (&rect)[4])
01438 {
01439     std::vector<BBox>::iterator     bI;
01440     BBoxList                       *freeList;
01441     Int32  pos,from,to;
01442     Real32 constant,pixel;
01443     UInt32 otherAxis = axis^1;
01444     Int32  t,b;
01445     Real32 area;
01446
01447     // list of opened groups
01448     if(Int32(_groupOpen.size()) < rect[axis+2] + 1)
01449         _groupOpen.resize(rect[axis+2] + 1);
01450
01451     // list of closed groups
01452     if(Int32(_groupClose.size()) < rect[axis+2] + 1)
01453         _groupClose.resize(rect[axis+2] + 1);
01454
01455     // free bboxlist nodes
01456     if(_bboxlist.size() < port.bboxes.size() * 2)
01457         _bboxlist.resize(port.bboxes.size() * 2);
01458
01459     // init lists
01460     for(pos = rect[axis] ; pos <= rect[axis+2] ; ++pos)
01461         _groupOpen[pos] = _groupClose[pos] = NULL;
01462
01463     freeList = &_bboxlist.front();
01464     for(bI = port.bboxes.begin() ; bI != port.bboxes.end() ; ++bI)
01465     {
01466         // ignore invisible groups
01467         if(bI->rect[LEFT  ] > rect[RIGHT ] ||
01468            bI->rect[BOTTOM] > rect[TOP   ] ||
01469            bI->rect[RIGHT ] < rect[LEFT  ] ||
01470            bI->rect[TOP   ] < rect[BOTTOM])
01471            continue;
01472         from = bI->rect[axis];
01473         to   = bI->rect[axis+2];
01474
01475         // orriginal bbox size
01476         area = ( bI->rect[2] - bI->rect[0] + 1 ) *
01477                ( bI->rect[3] - bI->rect[1] + 1 );
01478
01479         // clip to visible 
01480         if(from < rect[axis  ])
01481             from = rect[axis];
01482         if(to   > rect[axis+2])
01483             to   = rect[axis+2];
01484
01485         // size of other axis
01486         b = bI->rect[otherAxis];
01487         t = bI->rect[otherAxis+2];
01488         if(b < rect[otherAxis])
01489             b = rect[otherAxis];
01490         if(t > rect[otherAxis+2])
01491             t = rect[otherAxis+2];
01492
01493         // cost
01494         LoadGroup &group = _cluster.loadGroups[bI->groupId];
01495         constant = group.constant;
01496         pixel    = (t-b+1) * ( group.pixel + group.ratio / area );
01497
01498         // insert into open list
01499         freeList->next     = _groupOpen[from];
01500         freeList->constant = constant;
01501         freeList->pixel    = pixel;
01502         _groupOpen[from] = freeList++;
01503
01504         // insert into close list
01505         freeList->next     = _groupClose[to];
01506         freeList->constant = constant;
01507         freeList->pixel    = pixel;
01508         _groupClose[to] = freeList++;
01509
01510 //        printf("from %d to %d\n",from,to);
01511     }
01512 }
01513
01516 void BalancedMultiWindow::splitAxis(Real32 const (&load)[2],
01517                                     VPort &port,
01518                                     Int32 const (&rect)[4],
01519                                     int axis,
01520                                     Real32 (&resultLoad)[2],
01521                                     Int32 (&resultRect)[2][4])
01522 {
01523     Int32 from,to,cut; // ,lastCut;
01524     BBoxList *bl;
01525     Real64 leftLoad  = 0;
01526     Real64 rightLoad = load[0] + load[1];
01527     Real64 openPixel=0;
01528     UInt32 otherAxis = axis^1;
01529     Real64 scaleLeft  = 1 / load[0];
01530     Real64 scaleRight = 1 / load[1];
01531     Real64 lastLeft;
01532     Real64 lastRight;
01533 #if 0
01534     if(load[0] >= load[1] &&
01535        load[0] / load[1] < 1.4)
01536         scaleLeft = scaleRight = 1.0;
01537     if(load[1] >= load[0] &&
01538        load[1] / load[0] < 1.4)
01539         scaleLeft = scaleRight = 1.0;
01540 #endif
01541     // sort visible bboxes and calculate costs
01542     sortBBoxes(port,axis,rect);
01543
01544     for(from  = rect[axis] ;
01545         from <= rect[axis+2] &&
01546             _groupOpen[from] == NULL &&
01547             _groupClose[from] == NULL
01548             ; ++from) ;
01549     for(to  = rect[axis+2] ;
01550         to >= from &&
01551             _groupOpen[to] == NULL &&
01552             _groupClose[to] == NULL
01553             ; --to) ;
01554
01555     // loop through all points
01556     //lastCut = from-1;
01557     lastLeft = 0;
01558     lastRight = rightLoad;
01559     for(cut = from ; cut < to ; ++cut)
01560     {
01561         // loop through open list
01562         bl = _groupOpen[cut];
01563         while(bl)
01564         {
01565             openPixel += bl->pixel;
01566             leftLoad  += bl->constant;
01567             bl = bl->next;
01568         }
01569         leftLoad  += openPixel;
01570         rightLoad -= openPixel;
01571         // loop through open list
01572         bl = _groupClose[cut];
01573         while(bl)
01574         {
01575             openPixel -= bl->pixel;
01576             rightLoad -= bl->constant;
01577             bl = bl->next;
01578         }
01579 //        rightLoad -= openPixel;
01580 /*
01581         printf("A %d %.10f %.10f\n",cut,leftLoad,rightLoad);
01582         printf("B %d %.10f %.10f\n",cut,leftLoad*scaleLeft,rightLoad*scaleRight);
01583 */
01584
01585 //        if(leftLoad * scaleLeft + 1e-6 >= rightLoad * scaleRight)
01586         // take best ob last and current cut
01587         if(leftLoad * scaleLeft >= rightLoad * scaleRight)
01588         {
01589             break;
01590         }
01591
01592         lastLeft = leftLoad;
01593         lastRight = rightLoad;
01594     }
01595     if((osgMax(leftLoad*scaleLeft,rightLoad*scaleRight) >
01596         osgMax(lastLeft*scaleLeft,lastRight*scaleRight) &&
01597         cut > from) ||
01598        (cut > from && cut == to))
01599     {
01600         cut--;
01601         leftLoad = lastLeft;
01602         rightLoad = lastRight;
01603     }
01604
01605     // new left
01606     resultLoad[0] = leftLoad;
01607     resultRect[0][axis]        = from;
01608     resultRect[0][otherAxis]   = rect[otherAxis];
01609     resultRect[0][axis+2]      = cut;
01610     resultRect[0][otherAxis+2] = rect[otherAxis+2];
01611
01612     // new right
01613     resultLoad[1] = rightLoad;
01614     resultRect[1][axis]        = cut+1;
01615     resultRect[1][otherAxis]   = rect[otherAxis];
01616     resultRect[1][axis+2]      = to;
01617     resultRect[1][otherAxis+2] = rect[otherAxis+2];
01618
01619 //    printf("AA %d %d %d\n",rect[axis],resultRect[0][axis+2],rect[axis+2]);
01620 #if 0
01621     for(cut = rect[axis] ;
01622         cut <= rect[axis+2] &&
01623             _groupOpen[cut] == NULL &&
01624             _groupClose[cut] == NULL
01625             ; ++cut)
01626         resultRect[0][axis]++;
01627
01628     for(cut = rect[axis+2] ;
01629         cut >= rect[axis] &&
01630             _groupOpen[cut] == NULL &&
01631             _groupClose[cut] == NULL
01632             ; --cut)
01633         resultRect[1][axis+2]--;
01634 #endif
01635 }
01636
01637
01638
01641 void BalancedMultiWindow::renderViewport(Window           *serverWindow,
01642                                          UInt32            id,
01643                                          RenderActionBase *action,
01644                                          UInt32            portId,
01645                                          Int32 const (&rect)[4])
01646 {
01647     // create temporary viewport
01648     _foreignPort.id         = portId;
01649     _foreignPort.serverId   = id;
01650     _foreignPort.root       = getPort(portId)->getRoot();
01651     // calculate valid viewport
01652     calculateServerPort(_foreignPort,rect);
01653     // add to window
01654     serverWindow->addPort(_foreignPort.serverPort);
01655
01656     if(_foreignPort.serverPort->getPixelLeft() <=
01657        _foreignPort.serverPort->getPixelRight()   &&
01658        _foreignPort.serverPort->getPixelBottom() <=
01659        _foreignPort.serverPort->getPixelTop())
01660     {
01661         // do rendering
01662         action->setWindow(serverWindow);
01663         _foreignPort.serverPort->render(action);
01664 /*
01665         GLint glvp[4];
01666         glGetIntegerv( GL_VIEWPORT, glvp );
01667         printf("%d %d %d %d\n",glvp[0],
01668                glvp[1],
01669                glvp[2],
01670                glvp[3]);
01671 */
01672         action->setFrustumCulling(true);
01673     }
01674
01675     // sub viewport from window
01676     serverWindow->subPortByObj(_foreignPort.serverPort);
01677 }
01678
01681 // clear local ports
01682 void BalancedMultiWindow::clearViewports(Window           *serverWindow,
01683                                          UInt32            id,
01684                                          RenderActionBase *action)
01685 {
01686     UInt32 vp;
01687     UInt32 travMask;
01688
01689     // clear with black, if no local viewports
01690     if(_cluster.servers[id].viewports.size() == 0)
01691     {
01692         glViewport(0,0,
01693                    serverWindow->getWidth(),
01694                    serverWindow->getHeight());
01695         glClearColor(0,0,0,0);
01696         // glClear(GL_COLOR_BUFFER_BIT);
01697     }
01698
01699     for(vp=0 ; vp<_cluster.servers[id].viewports.size() ; ++vp)
01700     {
01701         VPort &port = _cluster.servers[id].viewports[vp];
01702
01703         // don't render scene
01704         travMask = port.root->getTravMask();
01705         port.root->setTravMask(0);
01706
01707         // calculate valid viewport
01708         calculateServerPort(port,port.rect);
01709
01710         // add to window
01711         serverWindow->addPort(port.serverPort);
01712
01713         // do rendering
01714         action->setWindow(serverWindow);
01715         port.serverPort->render(action);
01716
01717         // sub viewport from window
01718         serverWindow->subPortByObj(port.serverPort);
01719
01720         port.root->setTravMask(travMask);
01721     }
01722 }
01723
01724
01727 void BalancedMultiWindow::storeViewport(Area &area,Viewport *vp,
01728                                         Int32 const (&rect)[4])
01729 {
01730     Int32 x,y,w,h;
01731     UInt32 tI=0;
01732 /*
01733     printf("vport pos %d %d\n",vp->getPixelLeft(),vp->getPixelBottom());
01734     printf("rect  pos %d %d\n",rect[0],rect[1]);
01735 */
01736     vp->activate();
01737
01738     area.tiles.resize(calcTileCount(rect));
01739
01740     for(y = rect[BOTTOM] ; y <= rect[TOP] ; y += MW_TILE_SIZE)
01741     {
01742         for(x = rect[LEFT] ; x <= rect[RIGHT] ; x += MW_TILE_SIZE)
01743         {
01744             w = osgMin(Int32(MW_TILE_SIZE),rect[RIGHT] - x + 1);
01745             h = osgMin(Int32(MW_TILE_SIZE),rect[TOP]   - y + 1);
01746
01747             area.tiles[tI].header.x      = x;
01748             area.tiles[tI].header.y      = y;
01749             area.tiles[tI].header.width  = w;
01750             area.tiles[tI].header.height = h;
01751             area.tiles[tI].header.last  = false;
01752
01753             if(getShort())
01754             {
01755                 glReadPixels(area.tiles[tI].header.x,
01756                              area.tiles[tI].header.y,
01757                              w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
01758                              area.tiles[tI].pixel);
01759             }
01760             else
01761             {
01762                 glReadPixels(area.tiles[tI].header.x,
01763                              area.tiles[tI].header.y,
01764                              w, h, GL_RGB, GL_UNSIGNED_BYTE,
01765                              area.tiles[tI].pixel);
01766             }
01767             tI++;
01768         }
01769     }
01770     area.tiles[tI-1].header.last = true;
01771
01772     vp->deactivate();
01773 }
01774
01775
01776 void BalancedMultiWindow::drawSendAndRecv(Window           *window,
01777                                           RenderActionBase *action,
01778                                           UInt32            id)
01779 {
01780     UInt16 wpId;
01781     UInt32 sendCount;
01782     GroupConnection *groupConn;
01783 //    UInt32 count,vp,vpcount,wpcount;
01784 //    Server &server = _cluster.servers[id];
01785     std::vector<WorkPackage>::iterator wI;
01786     std::vector<Area>::iterator aI;
01787     std::vector<Tile>::iterator tI;
01788     Tile tile;
01789     Connection::Channel channel=0;
01790
01791     _triCount = 0;
01792     _drawTime = 0;
01793     _pixelTime = 0;
01794     _netTime = 0;
01795
01796 #ifdef CHECK
01797     // prepare statistics
01798     if(action->getStatistics() == NULL)
01799     {
01800         action->setStatistics(new StatCollector());
01801         action->getStatistics()->getElem( Drawable::statNTriangles )->getValue();
01802     }
01803 #endif
01804 
01805     Connection *conn = getNetwork()->getMainConnection();
01806
01807     // start rendering
01808     if(window != NULL)
01809     {
01810         window->activate ();
01811         window->frameInit();
01812
01813         // render viewport for others
01814         for(wI  = _cluster.workpackages.begin(), wpId=0;
01815             wI != _cluster.workpackages.end() ;
01816             ++wI, ++wpId)
01817         {
01818             if(wI->drawServer == id &&
01819                wI->sendToServer != id)
01820             {
01821                 // new area
01822                 _cluster.areas.resize(_cluster.areas.size()+1);
01823                 _cluster.areas.back().workpackageId = wpId;
01824                 renderViewport(window,
01825                                wI->sendToServer,
01826                                action,
01827                                wI->viewportId,
01828                                wI->rect);
01829                 glFinish();
01830                 _pixelTime -= getSystemTime();
01831                 storeViewport (_cluster.areas.back(),
01832                                getPort(wI->viewportId),
01833                                wI->rect);
01834                 _pixelTime += getSystemTime();
01835
01836 #ifdef CHECK
01837                 _triCount += (UInt32)action->getStatistics()->getElem( Drawable::statNTriangles )->getValue();
01838                 _drawTime += action->getStatistics()->getElem( RenderAction::statDrawTime )->getValue();
01839 #endif
01840             }
01841         }
01842
01843         // clear viewports with background
01844         clearViewports(window,id,action);
01845
01846         // render own viewports
01847         for(wI  = _cluster.workpackages.begin() ;
01848             wI != _cluster.workpackages.end() ;
01849             ++wI)
01850         {
01851             if(wI->drawServer == id &&
01852                wI->sendToServer == id)
01853             {
01854                 // render local viewport
01855                 renderViewport(window,
01856                                id,
01857                                action,
01858                                wI->viewportId,
01859                                wI->rect);
01860 #ifdef CHECK
01861                 _triCount += (UInt32)action->getStatistics()->getElem( Drawable::statNTriangles )->getValue();
01862                 _drawTime += action->getStatistics()->getElem( RenderAction::statDrawTime )->getValue();
01863 #endif
01864             }
01865         }
01866         // send tiles
01867         sendCount = _cluster.areas.size();
01868         groupConn = getNetwork()->getGroupConnection(id);
01869         while(sendCount)
01870         {
01871             groupConn->selectChannel();
01872             groupConn->getValue(wpId);
01873             for(aI = _cluster.areas.begin() ; aI != _cluster.areas.end() ; ++aI)
01874             {
01875                 if(wpId == aI->workpackageId)
01876                 {
01877                     conn = getNetwork()->getConnection(_cluster.workpackages[wpId].sendToServer);
01878                     for(tI = aI->tiles.begin() ; tI != aI->tiles.end() ; ++tI)
01879                     {
01880                         if(getShort())
01881                             conn->put(&(*tI),UInt32(osgAbs(tI->header.width)) * tI->header.height * 2 + sizeof(Tile::Header));
01882                         else
01883                             conn->put(&(*tI),UInt32(osgAbs(tI->header.width)) * tI->header.height * 3 + sizeof(Tile::Header));
01884                     }
01885                     conn->flush();
01886                     sendCount--;
01887                     break;
01888                 }
01889             }
01890         }
01891
01892         _netTime -= getSystemTime();
01893         // receive and paint tiles from others
01894         glPushMatrix();
01895         glLoadIdentity();
01896         glMatrixMode(GL_PROJECTION);
01897         glPushMatrix();
01898         glLoadIdentity();
01899         gluOrtho2D(0, window->getWidth(), 0, window->getHeight());
01900         glDisable(GL_DEPTH_TEST);
01901         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
01902         groupConn = getNetwork()->getGroupConnection(id);
01903         wpId = 0;
01904         wI = _cluster.workpackages.begin();
01905         while(wI != _cluster.workpackages.end() &&
01906               (wI->drawServer == id || wI->sendToServer != id))
01907         {
01908             ++wI; ++wpId;
01909         }
01910         if(wI != _cluster.workpackages.end())
01911         {
01912             conn = getNetwork()->getConnection(wI->drawServer);
01913             conn->putValue(wpId);
01914             conn->flush();
01915         }
01916         while(wI != _cluster.workpackages.end())
01917         {
01918             Viewport *vp = getPort(wI->viewportId);
01919             // the activate is only called for buffer activation.
01920             vp->activate();
01921
01922             // overwrite viewport activate dimension and scissor test.
01923             glViewport(0, 0,
01924                        window->getWidth(), window->getHeight());
01925             glDisable(GL_SCISSOR_TEST);
01926
01927             channel = groupConn->selectChannel();
01928             do
01929             {
01930                 groupConn->get(&tile,sizeof(Tile::Header));
01931                 if(tile.header.last)
01932                 {
01933                     ++wI; ++wpId;
01934                     // we got last tile, request from next server
01935                     while(wI != _cluster.workpackages.end() &&
01936                           (wI->drawServer == id || wI->sendToServer != id))
01937                     {
01938                         ++wI; ++wpId;
01939                     }
01940                     if(wI != _cluster.workpackages.end())
01941                     {
01942                         conn = getNetwork()->getConnection(wI->drawServer);
01943                         conn->putValue(wpId);
01944                         conn->flush();
01945                     }
01946                 }
01947                 if(getShort())
01948                     groupConn->get(&tile.pixel,tile.header.width*tile.header.height*2);
01949                 else
01950                     groupConn->get(&tile.pixel,tile.header.width*tile.header.height*3);
01951                 _netTime += getSystemTime();
01952                 _pixelTime -= getSystemTime();
01953                 glRasterPos2i (tile.header.x,tile.header.y);
01954                 if(getShort())
01955                     glDrawPixels(tile.header.width,tile.header.height,
01956                                  GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
01957                                  &(tile.pixel[0]));
01958                 else
01959                     glDrawPixels(tile.header.width,tile.header.height,
01960                                  GL_RGB, GL_UNSIGNED_BYTE,
01961                                  &(tile.pixel[0]));
01962
01963                 if(getShowBalancing())
01964                 {
01965 #if 1
01966                     static Real32 col[16][3] = {
01967                         {1,0,0},
01968                         {0,1,0},
01969                         {0,0,1},
01970                         {1,1,0},
01971                         {1,0,1},
01972                         {0,1,1},
01973                         {1,1,1},
01974                         {1,.5,0},
01975                         {.5,0,0},
01976                         {0,.5,0},
01977                         {0,0,.5},
01978                         {.5,.5,0},
01979                         {.5,0,1},
01980                         {0,.5,1},
01981                         {1,1,.5},
01982                         {.5,.5,0}
01983                     };
01984                     glEnable(GL_BLEND);
01985                     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
01986                     glBegin(GL_QUADS);
01987                     glColor4f(col[channel%16][0],
01988                               col[channel%16][1],
01989                               col[channel%16][2],
01990                               .3f);
01991                     glVertex2i(tile.header.x                  , tile.header.y);
01992                     glVertex2i(tile.header.x                  , tile.header.y+tile.header.height);
01993                     glVertex2i(tile.header.x+tile.header.width, tile.header.y+tile.header.height);
01994                     glVertex2i(tile.header.x+tile.header.width, tile.header.y);
01995                     glEnd();
01996                     glDisable(GL_BLEND);
01997 #endif
01998                 }
01999                 _pixelTime += getSystemTime();
02000                 _netTime -= getSystemTime();
02001             }
02002             while(!tile.header.last);
02003
02004             vp->deactivate();
02005 /*
02006             _pixelTime -= getSystemTime();
02007             glFinish();
02008             _pixelTime += getSystemTime();
02009 */
02010         }
02011         glPopMatrix();
02012         glMatrixMode(GL_MODELVIEW);
02013         glPopMatrix();
02014         glEnable(GL_DEPTH_TEST);
02015     }
02016     _netTime += getSystemTime();
02017 }
02018
02021 void BalancedMultiWindow::preloadCache(Window           *window,
02022                                        RenderActionBase *action)
02023 {
02024     Node   *root = NULL;
02025     UInt32  v;
02026
02027     if(!_preloadCache)
02028         return;
02029
02030     _preloadCache = false;
02031
02032     window->activate();
02033     window->frameInit();
02034
02035     // loop over all viewports
02036     for(v = 0 ; v  < getMFPort()->size() ; ++v )
02037     {
02038         Viewport *viewport = getPort(v);
02039
02040         if(root == viewport->getRoot())
02041             continue;
02042
02043         root = viewport->getRoot();
02044
02045         if(root == NULL)
02046             continue;
02047
02048         root->updateVolume();
02049         window->activate();
02050         window->frameInit();
02051
02052         // create cart
02053         NodeUnrecPtr      cartN = Node::create();
02054         TransformUnrecPtr cart = Transform::create();
02055
02056         cartN->setCore(cart);
02057
02058         root->addChild(cartN);
02059
02060         // create camera
02061         PerspectiveCameraUnrecPtr cam = PerspectiveCamera::create();
02062
02063         cam->setBeacon( cartN );
02064         cam->setFov   ( osgDegree2Rad( 60 ) );
02065
02066         // background
02067         SolidBackgroundUnrecPtr bkgnd = SolidBackground::create();
02068
02069         // create viewport
02070         ViewportUnrecPtr vp = Viewport::create();
02071
02072         vp->setCamera( cam );
02073         vp->setBackground( bkgnd );
02074         vp->setRoot( root );
02075         vp->setSize( 0,0, 1,1 );
02076
02077         // add to window
02078         window->addPort(vp);
02079
02080         // calc viewing matrix
02081         Vec3f min,max;
02082         root->getVolume().getBounds( min, max );
02083         Vec3f d = max - min;
02084         Real32 dist = osgMax(d[0],d[1]) / (2 * osgTan(cam->getFov() / 2.f));
02085         Vec3f up(0,1,0);
02086         Pnt3f at((min[0] + max[0]) * .5f,
02087                  (min[1] + max[1]) * .5f,
02088                  (min[2] + max[2]) * .5f);
02089         Pnt3f from=at;
02090         from[2]+=(dist*3);
02091
02092         Matrix &matrix = cart->editMatrix();
02093         MatrixLookAt(matrix, from, at, up);
02094
02095         // set the camera to go from 1% of the object to twice its size
02096         Real32 diag = osgMax(osgMax(d[0], d[1]), d[2]);
02097
02098         cam->setNear (diag / 100.f);
02099         cam->setFar  (10 * dist);
02100
02101         // do rendering
02102         action->setWindow(window);
02103         vp->render(action);
02104
02105         // remove port
02106         window->subPortByObj(vp);
02107         root->subChild(cartN);
02108     }
02109 }
02110
02111 OSG_END_NAMESPACE