1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
51 #include "OSGConfig.h"
52 #include "OSGGeometry.h"
53 #include "OSGSimpleGeometry.h"
55 #include "OSGTileLoadBalancer.h"
59 /** \class OSG::TileLoadBalancer
61 * \brief Manages geometry load
69 /*-------------------------------------------------------------------------*/
74 TileLoadBalancer::TileLoadBalancer(bool useFaceDistribution
,
75 bool cutBestDirection
):
76 _tileGeometryLoad ( ),
78 _useFaceDistribution(useFaceDistribution
),
79 _cutBestDirection (cutBestDirection
)
85 TileLoadBalancer::TileLoadBalancer(const TileLoadBalancer
&source
):
86 _tileGeometryLoad (source
._tileGeometryLoad
),
87 _renderNode (source
._renderNode
),
88 _useFaceDistribution(source
._useFaceDistribution
),
89 _cutBestDirection (source
._cutBestDirection
)
93 /*-------------------------------------------------------------------------*/
96 /*! Destructor documentation
98 TileLoadBalancer::~TileLoadBalancer(void)
102 /*-------------------------------------------------------------------------*/
107 TileLoadBalancer
& TileLoadBalancer::operator = (const TileLoadBalancer
&source
)
111 _tileGeometryLoad
= source
._tileGeometryLoad
;
112 _renderNode
= source
._renderNode
;
113 _useFaceDistribution
= source
._useFaceDistribution
;
114 _cutBestDirection
= source
._cutBestDirection
;
119 /** Update the load balancing information
121 void TileLoadBalancer::update(Node
*node
)
123 TileGeometryLoadMapT loadMap
;
125 // collect old load objects
126 for(TileGeometryLoadLstT::iterator gI
=_tileGeometryLoad
.begin();gI
!=_tileGeometryLoad
.end();++gI
)
128 if(gI
->getNode() != NULL
)
129 loadMap
[gI
->getNode()->getId()] = gI
;
134 updateSubtree(node
,loadMap
);
136 // mark unused load objects as invalid.
137 for(TileGeometryLoadMapT::iterator mI
=loadMap
.begin();mI
!=loadMap
.end();++mI
)
138 mI
->second
->setValid(false);
140 // remove all invalid objects.
141 _tileGeometryLoad
.erase(std::remove_if(_tileGeometryLoad
.begin(), _tileGeometryLoad
.end(),
142 std::mem_fun_ref(&TileGeometryLoad::isInvalid
)), _tileGeometryLoad
.end());
147 * \param vp current viewport
148 * \param shrink shrink to max area of visible objects
149 * \param result resulting regions
152 void TileLoadBalancer::balance(Viewport
*vp
,
156 Matrix projection
,viewing
;
157 RegionLoadVecT visible
;
158 RegionLoadVecT::iterator vi
;
159 Int32 width
=vp
->calcPixelWidth();
160 Int32 height
=vp
->calcPixelHeight();
161 Int32 wmin
[2]={width
,height
};
162 Int32 wmax
[2]={0 ,0 };
163 Real32 rNear
=vp
->getCamera()->getNear();
166 vp
->getCamera()->getViewing ( viewing
,width
,height
);
167 vp
->getCamera()->getProjection( projection
,width
,height
);
168 visible
.reserve(_tileGeometryLoad
.size());
169 for(TileGeometryLoadLstT::iterator l
=_tileGeometryLoad
.begin() ; l
!=_tileGeometryLoad
.end() ; ++l
)
171 // update view dependent values
172 l
->updateView(viewing
,
177 // sort by min values
180 // collect visible geometries
181 visible
.push_back(RegionLoad(&(*l
)));
184 if(l
->getMin()[0] < wmin
[0])
185 wmin
[0]=l
->getMin()[0];
186 if(l
->getMin()[1] < wmin
[1])
187 wmin
[1]=l
->getMin()[1];
188 if(l
->getMax()[0] > wmax
[0])
189 wmax
[0]=l
->getMax()[0];
190 if(l
->getMax()[1] > wmax
[1])
191 wmax
[1]=l
->getMax()[1];
197 // handle invisible area
198 if(wmax
[0]<wmin
[0] ||
200 wmin
[0]=wmax
[0]=wmin
[1]=wmax
[1]=0;
201 // clamp to viewable area
217 // calculate region cost
218 for(vi
=visible
.begin();vi
!=visible
.end();vi
++)
220 vi
->updateCost(wmin
,wmax
);
222 if(_renderNode
.size()>1)
224 splitRegion(0, UInt32(_renderNode
.size()) - 1,
238 result
.push_back(region
);
242 void TileLoadBalancer::setRegionStatistics(Viewport
*vp
,
245 Matrix projection
,viewing
;
246 Int32 width
=vp
->calcPixelWidth();
247 Int32 height
=vp
->calcPixelHeight();
248 Real32 rNear
=vp
->getCamera()->getNear();
249 ResultT::iterator resultI
;
250 TileGeometryLoadLstT::iterator l
;
252 vp
->getCamera()->getViewing ( viewing
,width
,height
);
253 vp
->getCamera()->getProjection( projection
,width
,height
);
254 for(resultI
=result
.begin();
255 resultI
!=result
.end();
258 resultI
->culledNodes
=0;
260 resultI
->culledFaces
=0;
263 for(l
=_tileGeometryLoad
.begin() ;
264 l
!=_tileGeometryLoad
.end() ;
267 l
->updateView(viewing
,
272 for(resultI
=result
.begin();
273 resultI
!=result
.end();
277 resultI
->culledNodes
++;
288 Real32 visible
=l
->getVisibleFraction(wmin
,wmax
,vismin
,vismax
)*
291 resultI
->culledNodes
++;
294 resultI
->faces
+=visible
;
295 resultI
->culledFaces
+= l
->getFaces()-visible
;
297 (vismax
[0] - vismin
[0] + 1)*
298 (vismax
[1] - vismin
[1] + 1);
305 /** Add new render node
308 void TileLoadBalancer::addRenderNode(const RenderNode
&rn
,UInt32 id
)
310 while(_renderNode
.size()<=id
)
311 _renderNode
.push_back(RenderNode());
315 /** Draw recangular volume projection
318 void TileLoadBalancer::drawVolumes(Window
*win
)
322 glMatrixMode(GL_PROJECTION
);
325 glViewport(0,0,win
->getWidth(),win
->getHeight());
326 gluOrtho2D(0,win
->getWidth(),
328 glDisable(GL_DEPTH_TEST
);
329 glEnable(GL_COLOR_MATERIAL
);
330 for(TileGeometryLoadLstT::iterator l
=_tileGeometryLoad
.begin() ; l
!=_tileGeometryLoad
.end() ; ++l
)
334 glBegin(GL_LINE_LOOP
);
336 glVertex3i(l
->getMin()[0],l
->getMin()[1],0);
337 glVertex3i(l
->getMax()[0],l
->getMin()[1],0);
338 glVertex3i(l
->getMax()[0],l
->getMax()[1],0);
339 glVertex3i(l
->getMin()[0],l
->getMax()[1],0);
343 glDisable(GL_COLOR_MATERIAL
);
344 glEnable(GL_DEPTH_TEST
);
346 glMatrixMode(GL_MODELVIEW
);
350 /** Add all geometry nodes in the given tree
352 void TileLoadBalancer::updateSubtree(Node
* const node
,
353 TileGeometryLoadMapT
&loadMap
)
355 // is nodecore a geometry?
356 if(node
->getCore() != NULL
&&
357 dynamic_cast<Geometry
*>(node
->getCore()) != NULL
)
359 // is this a new node
360 TileGeometryLoadMapT::iterator mI
=loadMap
.find(node
->getId());
361 if(mI
==loadMap
.end())
363 _tileGeometryLoad
.push_back(TileGeometryLoad(node
->getId(),
364 _useFaceDistribution
));
372 for(MFUnrecChildNodePtr::const_iterator n
= node
->getMFChildren()->begin();
373 n
!=node
->getMFChildren()->end();
376 updateSubtree(*n
,loadMap
);
382 void TileLoadBalancer::splitRegion(UInt32 rnFrom
,
384 RegionLoadVecT
&visible
,
393 RegionLoadVecT visibleA
;
394 RegionLoadVecT visibleB
;
395 RegionLoadVecT::iterator vi
;
396 UInt32 rnToA
,rnFromB
;
397 RenderNode groupRegionA
,groupRegionB
;
398 RenderNode
*renderNodeA
,*renderNodeB
;
400 // create group render node if neccessary
401 rnToA
=(rnTo
+rnFrom
)>>1;
405 groupRegionA
.setGroup(&_renderNode
[rnFrom
],&_renderNode
[rnToA
+1]);
406 renderNodeA
=&groupRegionA
;
410 renderNodeA
=&_renderNode
[rnFrom
];
414 groupRegionB
.setGroup(&_renderNode
[rnFromB
],&_renderNode
[rnTo
+1]);
415 renderNodeB
=&groupRegionB
;
419 renderNodeB
=&_renderNode
[rnFromB
];
422 if((rnToA
-rnFrom
) != (rnTo
-rnFromB
))
424 renderNodeB
->setInvisibleFaceCost(renderNodeA
->getInvisibleFaceCost());
427 // do we check both axis?
428 if(_cutBestDirection
)
432 // search for best cut
433 findBestCut(*renderNodeA
,*renderNodeB
,
434 visible
,wmin
,wmax
,axis
,cut
);
435 // create new regions
437 maxA
[axis
^1]=wmax
[axis
^1];
439 minB
[axis
^1]=wmin
[axis
^1];
440 visibleA
.reserve(visible
.size());
441 visibleB
.reserve(visible
.size());
444 if(rnFrom
!= rnToA
|| rnFromB
!= rnTo
)
446 // split visible regions
447 for(vi
=visible
.begin();vi
!=visible
.end();vi
++)
449 if(vi
->getLoad()->getMax()[axis
] <= cut
)
450 visibleA
.push_back(*vi
);
452 if(vi
->getLoad()->getMin()[axis
] > cut
)
453 visibleB
.push_back(*vi
);
456 visibleA
.push_back(*vi
);
457 visibleB
.push_back(*vi
);
458 visibleA
.rbegin()->updateCost(wmin
,maxA
);
459 visibleB
.rbegin()->updateCost(minB
,wmax
);
464 splitRegion(rnFrom
,rnToA
,visibleA
,wmin
,maxA
,depth
+1,result
);
472 result
.push_back(region
);
475 splitRegion(rnFromB
,rnTo
,visibleB
,minB
,wmax
,depth
+1,result
);
483 result
.push_back(region
);
487 /** Find best cut through the geometries
489 Real32
TileLoadBalancer::findBestCut (const RenderNode
&renderNodeA
,
490 const RenderNode
&renderNodeB
,
491 RegionLoadVecT
&visible
,
497 RegionLoadVecT::iterator vi
;
501 Real32 costA
=0,costB
=0;
504 Int32 checkAxisFrom
,checkAxisTo
;
509 // only check given axis
510 checkAxisFrom
=checkAxisTo
=bestAxis
;
518 for(a
=checkAxisFrom
;a
<=checkAxisTo
;++a
)
532 for(vi
=visible
.begin();vi
!=visible
.end();vi
++)
534 if(vi
->getLoad()->getMax()[a
] <= newCut
)
536 costA
+=vi
->getCost(renderNodeA
);
539 if(vi
->getLoad()->getMin()[a
] > newCut
)
541 costB
+=vi
->getCost(renderNodeB
);
545 costA
+=vi
->getCost(renderNodeA
,wmin
,maxA
);
546 costB
+=vi
->getCost(renderNodeB
,minB
,wmax
);
550 newCost
= osgMax( costA
, costB
);
557 // walk into direction of inbalance