Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGTileLoadBalancer.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 <stdlib.h>
00044 #include <stdio.h>
00045 #include <OSGGLU.h>
00046 
00047 #include <algorithm>
00048 #include <OSGConfig.h>
00049 #include <OSGDrawAction.h>
00050 #include <OSGGeometry.h>
00051 #include <OSGSimpleGeometry.h>
00052 
00053 #include "OSGTileLoadBalancer.h"
00054 
00055 OSG_USING_NAMESPACE
00056 
00067 /*-------------------------------------------------------------------------*/
00068 /*                            Constructors                                 */
00069 
00072 TileLoadBalancer::TileLoadBalancer(bool useFaceDistribution,
00073                                    bool cutBestDirection):
00074     _useFaceDistribution(useFaceDistribution),
00075     _cutBestDirection(cutBestDirection)
00076 {
00077 }
00078 
00081 TileLoadBalancer::TileLoadBalancer(const TileLoadBalancer &source):
00082     _tileGeometryLoad(source._tileGeometryLoad),
00083     _renderNode(source._renderNode),
00084     _useFaceDistribution(source._useFaceDistribution),
00085     _cutBestDirection(source._cutBestDirection)
00086 {
00087 }
00088 
00089 /*-------------------------------------------------------------------------*/
00090 /*                             Destructor                                  */
00091 
00094 TileLoadBalancer::~TileLoadBalancer(void)
00095 {
00096 }
00097 
00098 /*-------------------------------------------------------------------------*/
00099 /*                             Assignment                                  */
00100 
00103 TileLoadBalancer& TileLoadBalancer::operator = (const TileLoadBalancer &source)
00104 {
00105     if(this == &source)
00106         return *this;
00107     _tileGeometryLoad = source._tileGeometryLoad;
00108     _renderNode = source._renderNode;
00109     _useFaceDistribution = source._useFaceDistribution;
00110     _cutBestDirection = source._cutBestDirection;
00111     return *this;
00112 }
00113 
00114 
00117 void TileLoadBalancer::update(NodePtr node)
00118 {
00119     TileGeometryLoadMapT loadMap;
00120 
00121     // collect old load obects
00122     for(TileGeometryLoadLstT::iterator gI=_tileGeometryLoad.begin();gI!=_tileGeometryLoad.end();++gI)
00123     {
00124         loadMap[gI->getNode().getFieldContainerId()] = gI;
00125     }
00126     updateSubtree(node,loadMap);
00127     // remove unused load objects
00128     for(TileGeometryLoadMapT::iterator mI=loadMap.begin();mI!=loadMap.end();++mI)
00129     {
00130         _tileGeometryLoad.erase(mI->second);
00131     }
00132 }
00133 
00141 void TileLoadBalancer::balance(ViewportPtr    vp,
00142                                bool           shrink,
00143                                ResultT       &result)
00144 {
00145     Matrix                   projection,viewing;
00146     RegionLoadVecT           visible;
00147     RegionLoadVecT::iterator vi;
00148     Int32                    width =vp->getPixelWidth();
00149     Int32                    height=vp->getPixelHeight();
00150     Int32                    wmin[2]={width,height};
00151     Int32                    wmax[2]={0    ,0     };
00152     Real32                   rNear=vp->getCamera()->getNear();
00153 
00154     result.clear();
00155     vp->getCamera()->getViewing   ( viewing   ,width,height );
00156     vp->getCamera()->getProjection( projection,width,height );
00157     visible.reserve(_tileGeometryLoad.size());
00158     for(TileGeometryLoadLstT::iterator l=_tileGeometryLoad.begin() ; l!=_tileGeometryLoad.end() ; ++l)
00159     {
00160         // update view dependent values
00161         l->updateView(viewing,
00162                       projection,
00163                       rNear,
00164                       width,
00165                       height);
00166         // sort by min values
00167         if(l->isVisible())
00168         {
00169             // collect visible geometries
00170             visible.push_back(RegionLoad(&(*l)));
00171             if(shrink)
00172             {
00173                 if(l->getMin()[0] < wmin[0]) 
00174                     wmin[0]=l->getMin()[0];
00175                 if(l->getMin()[1] < wmin[1]) 
00176                     wmin[1]=l->getMin()[1];
00177                 if(l->getMax()[0] > wmax[0]) 
00178                     wmax[0]=l->getMax()[0];
00179                 if(l->getMax()[1] > wmax[1]) 
00180                     wmax[1]=l->getMax()[1];
00181             }
00182         }
00183     }
00184     if(shrink)
00185     {
00186         // handle invisible area
00187         if(wmax[0]<wmin[0] || 
00188            wmax[1]<wmin[1] )
00189             wmin[0]=wmax[0]=wmin[1]=wmax[1]=0;
00190         // clamp to viewable area
00191         if(wmin[0]<0) 
00192             wmin[0]=0;
00193         if(wmin[1]<0) 
00194             wmin[1]=0;
00195         if(wmax[0]>=width ) 
00196             wmax[0]=width -1;
00197         if(wmax[1]>=height) 
00198             wmax[1]=height-1;
00199     }
00200     else
00201     {
00202         wmin[0]=wmin[1]=0;
00203         wmax[0]=width-1;
00204         wmax[1]=height-1;
00205     }
00206     // calculate region cost
00207     for(vi=visible.begin();vi!=visible.end();vi++)
00208     {
00209         vi->updateCost(wmin,wmax);
00210     }
00211     if(_renderNode.size()>1)
00212     {
00213         splitRegion(0,_renderNode.size()-1,
00214                     visible,
00215                     wmin,
00216                     wmax,
00217                     0,
00218                     result);
00219     }
00220     else
00221     {
00222         Region region;
00223         region.x1=wmin[0];
00224         region.y1=wmin[1];
00225         region.x2=wmax[0];
00226         region.y2=wmax[1];
00227         result.push_back(region);
00228     }
00229 }
00230 
00231 void TileLoadBalancer::setRegionStatistics(ViewportPtr     vp,
00232                                            ResultT        &result)
00233 {
00234     Matrix                         projection,viewing;
00235     Int32                          width =vp->getPixelWidth();
00236     Int32                          height=vp->getPixelHeight();
00237     Real32                         rNear=vp->getCamera()->getNear();
00238     ResultT::iterator              resultI;
00239     TileGeometryLoadLstT::iterator l;
00240 
00241     vp->getCamera()->getViewing   ( viewing   ,width,height );
00242     vp->getCamera()->getProjection( projection,width,height );
00243     for(resultI=result.begin();
00244         resultI!=result.end();
00245         ++resultI)
00246     {
00247         resultI->culledNodes=0;
00248         resultI->faces=0;
00249         resultI->culledFaces=0;
00250         resultI->pixel=0;
00251     }
00252     for(l=_tileGeometryLoad.begin() ; 
00253         l!=_tileGeometryLoad.end() ;
00254         ++l)
00255     {
00256         l->updateView(viewing,
00257                       projection,
00258                       rNear,
00259                       width,
00260                       height);
00261         for(resultI=result.begin();
00262             resultI!=result.end();
00263             ++resultI)
00264         {
00265             if(!l->isVisible())
00266                 resultI->culledNodes++;
00267             else
00268             {
00269                 Int32 wmin[2];
00270                 Int32 wmax[2];
00271                 Int32 vismin[2];
00272                 Int32 vismax[2];
00273                 wmin[0]=resultI->x1;
00274                 wmin[1]=resultI->y1;
00275                 wmax[0]=resultI->x2;
00276                 wmax[1]=resultI->y2;
00277                 Real32 visible=l->getVisibleFraction(wmin,wmax,vismin,vismax)*
00278                     l->getFaces();
00279                 if(visible==0)
00280                     resultI->culledNodes++;
00281                 else
00282                 {
00283                     resultI->faces+=visible;
00284                     resultI->culledFaces+= l->getFaces()-visible;
00285                     resultI->pixel+=
00286                         (vismax[0] - vismin[0] + 1)*
00287                         (vismax[1] - vismin[1] + 1);
00288                 }
00289             }
00290         }
00291     }
00292 }
00293 
00297 void TileLoadBalancer::addRenderNode(const RenderNode &rn,UInt32 id)
00298 {
00299     while(_renderNode.size()<=id)
00300         _renderNode.push_back(RenderNode());
00301     _renderNode[id]=rn;
00302 }
00303 
00307 void TileLoadBalancer::drawVolumes(WindowPtr win)
00308 {
00309     glPushMatrix();
00310     glLoadIdentity();
00311     glMatrixMode(GL_PROJECTION);
00312     glPushMatrix();
00313     glLoadIdentity();
00314     glViewport(0,0,win->getWidth(),win->getHeight());
00315     gluOrtho2D(0,win->getWidth(),
00316                0,win->getHeight());
00317     glDisable(GL_DEPTH_TEST);
00318     glEnable(GL_COLOR_MATERIAL);
00319     for(TileGeometryLoadLstT::iterator l=_tileGeometryLoad.begin() ; l!=_tileGeometryLoad.end() ; ++l)
00320     {
00321         if(l->isVisible())
00322         {
00323             glBegin(GL_LINE_LOOP);
00324             glColor3f(0, 1, 0);
00325             glVertex3i(l->getMin()[0],l->getMin()[1],0);
00326             glVertex3i(l->getMax()[0],l->getMin()[1],0);
00327             glVertex3i(l->getMax()[0],l->getMax()[1],0);
00328             glVertex3i(l->getMin()[0],l->getMax()[1],0);
00329             glEnd();
00330         }
00331     }
00332     glDisable(GL_COLOR_MATERIAL);
00333     glEnable(GL_DEPTH_TEST);
00334     glPopMatrix();
00335     glMatrixMode(GL_MODELVIEW);
00336     glPopMatrix();
00337 }
00338 
00341 void TileLoadBalancer::updateSubtree(NodePtr &node,TileGeometryLoadMapT &loadMap)
00342 {
00343     // is nodecore a geometry?
00344     if(node->getCore() != NullFC &&
00345        GeometryPtr::dcast(node->getCore()) != NullFC)
00346     {
00347         // is this a new node
00348         TileGeometryLoadMapT::iterator mI=loadMap.find(node.getFieldContainerId());
00349         if(mI==loadMap.end())
00350         {
00351             _tileGeometryLoad.push_back(TileGeometryLoad(node,_useFaceDistribution));
00352         }
00353         else
00354         {
00355             loadMap.erase(mI);
00356         }
00357     }
00358     // handle all childs
00359     for(MFNodePtr::iterator n=node->getMFChildren()->begin();
00360         n!=node->getMFChildren()->end();
00361         ++n)
00362     {
00363         updateSubtree(*n,loadMap);
00364     }
00365 }
00366 
00369 void TileLoadBalancer::splitRegion(UInt32          rnFrom,
00370                                    UInt32          rnTo,
00371                                    RegionLoadVecT &visible,
00372                                    Int32           wmin[2],
00373                                    Int32           wmax[2],
00374                                    UInt32          depth,
00375                                    ResultT        &result)
00376 {
00377     Int32  axis,cut;
00378     Int32  maxA[2];
00379     Int32  minB[2];
00380     RegionLoadVecT visibleA;
00381     RegionLoadVecT visibleB;
00382     RegionLoadVecT::iterator vi;
00383     UInt32 rnToA,rnFromB;
00384     RenderNode groupRegionA,groupRegionB;
00385     RenderNode *renderNodeA,*renderNodeB;
00386 
00387     // create group render node if neccessary
00388     rnToA  =(rnTo+rnFrom)>>1;
00389     rnFromB=rnToA+1;
00390     if(rnFrom != rnToA)
00391     {
00392         groupRegionA.setGroup(&_renderNode[rnFrom],&_renderNode[rnToA+1]);
00393         renderNodeA=&groupRegionA;
00394     }
00395     else
00396     {
00397         renderNodeA=&_renderNode[rnFrom];
00398     }
00399     if(rnFromB != rnTo)
00400     {
00401         groupRegionB.setGroup(&_renderNode[rnFromB],&_renderNode[rnTo+1]);
00402         renderNodeB=&groupRegionB;
00403     }
00404     else
00405     {
00406         renderNodeB=&_renderNode[rnFromB];
00407     }
00408 #if 0
00409     if((rnToA-rnFrom) != (rnTo-rnFromB))
00410     {
00411         renderNodeB->setInvisibleFaceCost(renderNodeA->getInvisibleFaceCost());
00412     }
00413 #endif
00414     // do we check both axis?
00415     if(_cutBestDirection)
00416         axis=-1;
00417     else
00418         axis=depth&1;
00419     // search for best cut
00420     findBestCut(*renderNodeA,*renderNodeB,
00421                 visible,wmin,wmax,axis,cut);
00422     // create new regions
00423     maxA[axis  ]=cut;
00424     maxA[axis^1]=wmax[axis^1];
00425     minB[axis  ]=cut+1;
00426     minB[axis^1]=wmin[axis^1];
00427     visibleA.reserve(visible.size());
00428     visibleB.reserve(visible.size());
00429 
00430     // split regions
00431     if(rnFrom != rnToA || rnFromB != rnTo)
00432     {
00433         // split visible regions
00434         for(vi=visible.begin();vi!=visible.end();vi++)
00435         {
00436             if(vi->getLoad()->getMax()[axis] <= cut)
00437                 visibleA.push_back(*vi);
00438             else
00439                 if(vi->getLoad()->getMin()[axis] > cut)
00440                     visibleB.push_back(*vi);
00441                 else
00442                 {
00443                     visibleA.push_back(*vi);
00444                     visibleB.push_back(*vi);
00445                     visibleA.rbegin()->updateCost(wmin,maxA);
00446                     visibleB.rbegin()->updateCost(minB,wmax);
00447                 }
00448         }
00449     }
00450     if(rnFrom != rnToA)
00451         splitRegion(rnFrom,rnToA,visibleA,wmin,maxA,depth+1,result);
00452     else
00453     {
00454         Region region;
00455         region.x1=wmin[0];
00456         region.y1=wmin[1];
00457         region.x2=maxA[0];
00458         region.y2=maxA[1];
00459         result.push_back(region);
00460     }
00461     if(rnFromB != rnTo)
00462         splitRegion(rnFromB,rnTo,visibleB,minB,wmax,depth+1,result);
00463     else
00464     {
00465         Region region;
00466         region.x1=minB[0];
00467         region.y1=minB[1];
00468         region.x2=wmax[0];
00469         region.y2=wmax[1];
00470         result.push_back(region);
00471     }
00472 }
00473 
00476 Real32 TileLoadBalancer::findBestCut (const RenderNode &renderNodeA,
00477                                       const RenderNode &renderNodeB,
00478                                       RegionLoadVecT &visible,
00479                                       Int32           wmin[2],
00480                                       Int32           wmax[2],
00481                                       Int32          &bestAxis,
00482                                       Int32          &bestCut)
00483 {
00484     RegionLoadVecT::iterator vi;
00485     Int32 a,f,t,newCut;
00486     Int32 minB[2];
00487     Int32 maxA[2];
00488     Real32 costA=0,costB=0;
00489     Real32 newCost;
00490     Real32 bestCost;
00491     Int32 checkAxisFrom,checkAxisTo;
00492     bestCost=1e22;
00493 
00494     if(bestAxis>=0)
00495     {
00496         // only check given axis
00497         checkAxisFrom=checkAxisTo=bestAxis;
00498     }
00499     else
00500     {
00501         // check x and y cut
00502         checkAxisFrom=0;
00503         checkAxisTo=1;
00504     }
00505     for(a=checkAxisFrom;a<=checkAxisTo;++a)
00506     {
00507         f=wmin[a];
00508         t=wmax[a];
00509         maxA[0]=wmax[0];;
00510         maxA[1]=wmax[1];;
00511         minB[0]=wmin[0];;
00512         minB[1]=wmin[1];;
00513         do
00514         {
00515             newCut=(f+t)/2;
00516             maxA[a]=newCut;
00517             minB[a]=newCut+1;
00518             costA=costB=0;
00519             for(vi=visible.begin();vi!=visible.end();vi++)
00520             {
00521                 if(vi->getLoad()->getMax()[a] <= newCut)
00522                 {
00523                     costA+=vi->getCost(renderNodeA);
00524                 }
00525                 else
00526                     if(vi->getLoad()->getMin()[a] > newCut)
00527                     {
00528                         costB+=vi->getCost(renderNodeB);
00529                     }
00530                     else
00531                     {
00532                         costA+=vi->getCost(renderNodeA,wmin,maxA);
00533                         costB+=vi->getCost(renderNodeB,minB,wmax);
00534                     }
00535                 
00536             }
00537             newCost= osgMax( costA, costB );
00538             if(newCost<bestCost)
00539             {
00540                 bestCut=newCut;
00541                 bestCost=newCost;
00542                 bestAxis=a;
00543             }
00544             // walk into direction of inbalance
00545             if(costA>costB)
00546                 t=newCut;
00547             else
00548                 f=newCut;
00549         }
00550         while(t-f > 2);
00551     }
00552     return bestCost;
00553 }    
00554 
00555 
00556 /*-------------------------------------------------------------------------*/
00557 /*                              cvs id's                                   */
00558 
00559 #ifdef __sgi
00560 #pragma set woff 1174
00561 #endif
00562 
00563 #ifdef OSG_LINUX_ICC
00564 #pragma warning( disable : 177 )
00565 #endif
00566 
00567 namespace
00568 {
00569     static Char8 cvsid_cpp[] = "@(#)$Id:$";
00570     static Char8 cvsid_hpp[] = OSG_TILE_LOAD_BALANCER_HEADER_CVSID;
00571     static Char8 cvsid_inl[] = OSG_TILE_LOAD_BALANCER_INLINE_CVSID;
00572 }

Generated on Thu Aug 25 04:11:43 2005 for OpenSG by  doxygen 1.4.3