00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
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
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
00091
00094 TileLoadBalancer::~TileLoadBalancer(void)
00095 {
00096 }
00097
00098
00099
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
00122 for(TileGeometryLoadLstT::iterator gI=_tileGeometryLoad.begin();gI!=_tileGeometryLoad.end();++gI)
00123 {
00124 loadMap[gI->getNode().getFieldContainerId()] = gI;
00125 }
00126 updateSubtree(node,loadMap);
00127
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
00161 l->updateView(viewing,
00162 projection,
00163 rNear,
00164 width,
00165 height);
00166
00167 if(l->isVisible())
00168 {
00169
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
00187 if(wmax[0]<wmin[0] ||
00188 wmax[1]<wmin[1] )
00189 wmin[0]=wmax[0]=wmin[1]=wmax[1]=0;
00190
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
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
00344 if(node->getCore() != NullFC &&
00345 GeometryPtr::dcast(node->getCore()) != NullFC)
00346 {
00347
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
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
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
00415 if(_cutBestDirection)
00416 axis=-1;
00417 else
00418 axis=depth&1;
00419
00420 findBestCut(*renderNodeA,*renderNodeB,
00421 visible,wmin,wmax,axis,cut);
00422
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
00431 if(rnFrom != rnToA || rnFromB != rnTo)
00432 {
00433
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
00497 checkAxisFrom=checkAxisTo=bestAxis;
00498 }
00499 else
00500 {
00501
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
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
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 }