fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Cluster / Window / SortFirst / OSGTileGeometryLoad.cpp
blob8bc60d41ccb872d20bcb755d584aba8819b6b9bf
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
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. *
18 * *
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. *
23 * *
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. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
40 // Includes
41 //---------------------------------------------------------------------------
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <math.h>
47 #include "OSGConfig.h"
48 #include "OSGBaseFunctions.h"
49 #include "OSGTriangleIterator.h"
50 #include "OSGTileGeometryLoad.h"
52 OSG_USING_NAMESPACE
54 /** \class OSG::TileGeometryLoad
55 * \ingroup Cluster
56 * \brief TileGeometryLoad holds the load caused by geometry rendering
58 **/
60 /*-------------------------------------------------------------------------*/
61 /* Constructors */
63 /*! Constructor
66 TileGeometryLoad::TileGeometryLoad(UInt32 nodeId,
67 bool useFaceDistribution):
68 _nodeId (nodeId ),
69 _geometry (NULL ),
70 _faces (0 ),
71 _faceDistribution ( ),
72 _faceDistDirX (0 ),
73 _faceDistDirY (0 ),
74 _visible (true ),
75 _useFaceDistribution(useFaceDistribution),
76 _areaSize (0.f ),
77 _valid (false )
79 if(_directions.size()==0)
81 // create directions for face distribution
82 _directions.push_back(
83 Plane(Vec3f( 1, 0, 0) ,Pnt3f(0,0,0)));
84 _directions.push_back(
85 Plane(Vec3f( 0, 1, 0) ,Pnt3f(0,0,0)));
86 _directions.push_back(
87 Plane(Vec3f( 0, 0, 1) ,Pnt3f(0,0,0)));
89 _directions.push_back(
90 Plane(Vec3f( 1, 1, 1)*(1/osgSqrt(3.0f)),Pnt3f(0,0,0)));
91 _directions.push_back(
92 Plane(Vec3f(-1, 1, 1)*(1/osgSqrt(3.0f)),Pnt3f(1,0,0)));
93 _directions.push_back(
94 Plane(Vec3f( 1,-1, 1)*(1/osgSqrt(3.0f)),Pnt3f(0,1,0)));
95 _directions.push_back(
96 Plane(Vec3f( 1, 1,-1)*(1/osgSqrt(3.0f)),Pnt3f(0,0,1)));
98 _directions.push_back(
99 Plane(Vec3f( 1, 1, 0)*(1/osgSqrt(2.0f)),Pnt3f(0,0,0)));
100 _directions.push_back(
101 Plane(Vec3f( 1,-1, 0)*(1/osgSqrt(2.0f)),Pnt3f(0,1,0)));
102 _directions.push_back(
103 Plane(Vec3f( 0, 1, 1)*(1/osgSqrt(2.0f)),Pnt3f(0,0,0)));
104 _directions.push_back(
105 Plane(Vec3f( 0,-1, 1)*(1/osgSqrt(2.0f)),Pnt3f(0,1,0)));
106 _directions.push_back(
107 Plane(Vec3f( 1, 0, 1)*(1/osgSqrt(2.0f)),Pnt3f(0,0,0)));
108 _directions.push_back(
109 Plane(Vec3f(-1, 0, 1)*(1/osgSqrt(2.0f)),Pnt3f(1,0,0)));
113 updateGeometry();
116 /*! copy Constructor
119 TileGeometryLoad::TileGeometryLoad(const TileGeometryLoad &source):
121 _nodeId (source._nodeId ),
122 _geometry (source._geometry ),
123 _faces (source._faces ),
124 _faceDistribution (source._faceDistribution ),
125 _faceDistDirX (source._faceDistDirX ),
126 _faceDistDirY (source._faceDistDirY ),
127 _visible (source._visible ),
128 _useFaceDistribution(source._useFaceDistribution),
129 _areaSize (source._areaSize ),
130 _valid (source._valid )
132 _min[0] = source._min[0];
133 _min[1] = source._min[1];
134 _max[0] = source._max[0];
135 _max[1] = source._max[1];
138 /*-------------------------------------------------------------------------*/
139 /* Destructor */
141 /** Destructor documentation
143 TileGeometryLoad::~TileGeometryLoad(void)
147 /** Update the view dependend load parameters
150 void TileGeometryLoad::updateView(Matrix &viewing,
151 Matrix &projection,
152 Real32 rNear,
153 UInt32 width,
154 UInt32 height)
156 Vec3f vol[2];
157 Pnt3f pnt;
158 Real32 minx = 0.0,miny = 0.0;
159 Real32 maxx = 0.0,maxy = 0.0;
160 Matrix *p;
161 Real32 bestScalX;
162 UInt32 bestDirX = 0;
163 Real32 bestScalY;
164 UInt32 bestDirY = 0;
166 Node *node = dynamic_cast<Node *>(
167 FieldContainerFactory::the()->getContainer(_nodeId));
169 if(node == NULL)
170 return;
172 // get whole transformation
173 Matrix m=node->getToWorld();
174 m.multLeft(viewing);
175 // get transformed volume
176 node->updateVolume();
177 BoxVolume volume = node->getVolume();
178 // bug in osg base
180 if(volume.isEmpty())
182 _visible=false;
183 return;
186 volume.transform(m);
187 // get min,max
188 volume.getBounds(vol[0], vol[1]);
189 // min < rNear
190 if(vol[0][2] > -rNear)
192 _visible=false;
193 return;
196 // find best directon for face distribution
197 if(_useFaceDistribution)
199 Real32 scal;
200 Vec3f xdir(m[0][0],m[1][0],m[2][0]);
201 Vec3f ydir(m[0][1],m[1][1],m[2][1]);
202 xdir.normalize();
203 ydir.normalize();
204 bestScalX=bestScalY=0;
205 for(UInt32 dir=0;dir<_directions.size();++dir)
207 scal=_directions[dir].getNormal()*xdir;
208 if(scal>bestScalX)
210 bestScalX=scal;
211 bestDirX =dir*2;
213 if((-scal)>bestScalX)
215 bestScalX=-scal;
216 bestDirX =dir*2+1;
218 scal=_directions[dir].getNormal()*ydir;
219 if(scal>bestScalY)
221 bestScalY=scal;
222 bestDirY =dir*2;
224 if((-scal)>bestScalY)
226 bestScalY=-scal;
227 bestDirY =dir*2+1;
230 // cout << "x " << xdir << " " << _directions[bestDirX>>1].getNormal() << endl;
231 // cout << "y " << ydir << " " << _directions[bestDirY>>1].getNormal() << endl;
232 _faceDistDirX=bestDirX;
233 _faceDistDirY=bestDirY;
234 // cout << "best X:" << bestDirX << endl;
235 // cout << "best Y:" << bestDirY << endl;
238 if(vol[1][2] > -rNear)
240 // volume lays on the fron clipping plane
241 vol[1][2] = -rNear;
242 p=&projection;
244 else
246 // volume lays on the visible side of the clipping plane
247 node->getVolume().getBounds(vol[0], vol[1]);
248 m.multLeft(projection);
249 p=&m;
251 // create corners of a bounding box
252 for(int i=0;i<8;++i)
254 p->multFull(Pnt3f( vol[ (i )&1 ][0] ,
255 vol[ (i>>1)&1 ][1] ,
256 vol[ (i>>2)&1 ][2]) , pnt);
257 if(i>0)
259 if(minx > pnt[0]) minx = pnt[0];
260 if(miny > pnt[1]) miny = pnt[1];
261 if(maxx < pnt[0]) maxx = pnt[0];
262 if(maxy < pnt[1]) maxy = pnt[1];
264 else
266 maxx = minx = pnt[0];
267 maxy = miny = pnt[1];
270 // visible ?
271 if(maxx<-1 || maxy<-1 ||
272 minx> 1 || miny> 1)
274 _visible = false;
276 else
278 minx=width * ( minx + 1.0f ) / 2.0f - .5f;
279 maxx=width * ( maxx + 1.0f ) / 2.0f + .5f;
280 miny=height * ( miny + 1.0f ) / 2.0f - .5f;
281 maxy=height * ( maxy + 1.0f ) / 2.0f + .5f;
282 _min[0]=Int32(minx);
283 _max[0]=Int32(maxx);
284 _min[1]=Int32(miny);
285 _max[1]=Int32(maxy);
287 _areaSize =
288 Real32( _max[0] - _min[0] + 1 ) *
289 Real32( _max[1] - _min[1] + 1 );
290 /* Don't clip!
291 if(_min[0]<0) _min[0]=0;
292 if(_min[1]<0) _min[1]=0;
293 if(_max[0]>=width ) _max[0]=width-1;
294 if(_max[1]>=height) _max[1]=height-1;
296 _visible = true;
300 /** Update geometry dependend load parameters
302 * This funciton should only be called when geometies have changed.
304 * todo: Use a simple cost estimation mechanism for rapidly changeing
305 * geometries.
308 void TileGeometryLoad::updateGeometry()
310 Node *node =
311 dynamic_cast<Node *>(
312 FieldContainerFactory::the()->getContainer(_nodeId));
314 if(node == NULL)
315 return;
317 const OSG::Volume &volume = node->getVolume();
318 TriangleIterator f;
319 int p,s;
320 Vec3f vmin,vmax;
321 Pnt3f pos;
322 Real32 min = 0.0,max = 0.0;
323 PrimitiveIterator it;
324 NodeCore *core;
325 Geometry *geo;
326 const Real32 sq2 = osgSqrt(2.0f);
327 const Real32 sq3 = osgSqrt(3.0f);
329 _faces = 0;
330 core=node->getCore();
331 if(node->getCore() == NULL)
332 return;
333 geo=dynamic_cast<Geometry *>(core);
334 if(geo == NULL)
335 return;
337 // get volume min,max
338 volume.getBounds(vmin,vmax);
340 // count faces
341 for(f=geo->beginTriangles() ; f!=geo->endTriangles() ; ++f)
343 ++_faces;
345 if(_useFaceDistribution)
347 _faceDistribution.resize(_directions.size()*2);
348 // loop through all directions
349 for(UInt32 d=0;d<_directions.size();++d)
351 // init dist
352 _faceDistribution[d*2 ].resize(FACE_DISTRIBUTION_SAMPLING_COUNT);
353 _faceDistribution[d*2+1].resize(FACE_DISTRIBUTION_SAMPLING_COUNT);
354 for(s=0;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
356 _faceDistribution[d*2 ][s]=0;
357 _faceDistribution[d*2+1][s]=0;
359 // loop over all faces
360 for(f=geo->beginTriangles() ;
361 f!=geo->endTriangles() ;
362 ++f)
364 for(p=0;p<3;++p)
366 // get point and rescale
367 pos=(f.getPosition(p) - vmin);
368 pos[0]/=vmax[0]-vmin[0];
369 pos[1]/=vmax[1]-vmin[1];
370 pos[2]/=vmax[2]-vmin[2];
371 if(p==0)
373 max=min=_directions[d].distance(pos);
375 else
377 max=osgMax(max,_directions[d].distance(pos));
378 min=osgMin(min,_directions[d].distance(pos));
381 if(d>=7)
383 min/=sq2;
384 max/=sq2;
386 else if(d>=3)
388 min/=sq3;
389 max/=sq3;
391 _faceDistribution
392 [d*2 ]
393 [Int32(ceil(min*
394 (FACE_DISTRIBUTION_SAMPLING_COUNT-1)))]++;
395 _faceDistribution
396 [d*2+1]
397 [Int32(ceil((1-max)*
398 (FACE_DISTRIBUTION_SAMPLING_COUNT-1)))]++;
401 for(UInt32 d=0;d<_directions.size();++d)
403 _faceDistribution[d*2 ][0]/=_faces;
404 _faceDistribution[d*2+1][0]/=_faces;
405 for(s=1;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
407 _faceDistribution[d*2 ][s]/=_faces;
408 _faceDistribution[d*2+1][s]/=_faces;
409 _faceDistribution[d*2 ][s]+=_faceDistribution[d*2 ][s-1];
410 _faceDistribution[d*2+1][s]+=_faceDistribution[d*2+1][s-1];
412 #if 0
413 printf("--> ");
414 for(s=0;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
415 printf("%4.3f ",_faceDistribution[d*2 ][s]);
416 printf("\n<-- ");
417 for(s=0;s<FACE_DISTRIBUTION_SAMPLING_COUNT;++s)
418 printf("%4.3f ",_faceDistribution[d*2+1][s]);
419 printf("\n");
420 #endif
425 /*-------------------------------------------------------------------------*/
426 /* Assignment */
428 /*! assignment
430 TileGeometryLoad& TileGeometryLoad::operator=(const TileGeometryLoad &source)
432 if(this == &source)
433 return *this;
434 _min[0] = source._min[0];
435 _min[1] = source._min[1];
436 _max[0] = source._max[0];
437 _max[1] = source._max[1];
438 _faces = source._faces;
439 _visible = source._visible;
440 _faceDistribution = source._faceDistribution;
441 _faceDistDirX = source._faceDistDirX;
442 _faceDistDirY = source._faceDistDirY;
443 _nodeId = source._nodeId;
444 _useFaceDistribution = source._useFaceDistribution;
445 _areaSize = source._areaSize;
447 return *this;
450 /*-------------------------------------------------------------------------*/
451 /* dump */
453 void TileGeometryLoad::dump(void)
455 if(_visible)
457 SLOG << "Min/Max :"
458 << _min[0] << " " << _min[1] << " / "
459 << _max[0] << " " << _max[1] << std::endl;
461 else
463 SLOG << "invisible " << std::endl;
465 SLOG << "Faces :" << _faces << std::endl;
468 /*-------------------------------------------------------------------------*/
469 /* get */
471 /** Return min valuse in window coordinates
473 const Int32 *TileGeometryLoad::getMin()
475 return _min;
478 /** Return max valuse in window coordinates
480 const Int32 *TileGeometryLoad::getMax()
482 return _max;
485 /** Is the geometry visible in the current viewport
487 bool TileGeometryLoad::isVisible() const
489 return _visible;
492 /** Get Node ptr
494 Node *TileGeometryLoad::getNode() const
496 return
497 dynamic_cast<Node *>(
498 FieldContainerFactory::the()->getContainer(_nodeId));
501 /** Get number of faces in the geometry
503 UInt32 TileGeometryLoad::getFaces()
505 return _faces;
508 /** Which part of the faces are visible
510 Real32 TileGeometryLoad::getVisibleFraction( const Int32 wmin[2],
511 const Int32 wmax[2],
512 Int32 viswmin[2],
513 Int32 viswmax[2] )
515 Real32 x,y;
517 if(_visible==false)
518 return 0;
520 // get visible area
521 if(!getVisibleArea(wmin,wmax,viswmin,viswmax))
523 // not in region
524 return 0;
526 // geometry complete in region?
527 if(viswmin[0] == _min[0] &&
528 viswmin[1] == _min[1] &&
529 viswmax[0] == _max[0] &&
530 viswmax[1] == _max[1])
532 return 1;
535 if(_useFaceDistribution)
537 x=1.0f/(_max[0]-_min[0]+1);
538 y=1.0f/(_max[1]-_min[1]+1);
539 return
540 (getFaceDistribution(_faceDistDirX^1,
541 1.0f - (viswmin[0] - _min[0] ) * x) +
542 getFaceDistribution(_faceDistDirX,
543 (viswmax[0] - _min[0] + 1) * x) - 1)
545 (getFaceDistribution(_faceDistDirY^1,
546 1.0f - (viswmin[1] - _min[1] ) * y) +
547 getFaceDistribution(_faceDistDirY,
548 (viswmax[1] - _min[1] + 1) * y) - 1);
550 else
552 return
553 (Real32(viswmax[0] - viswmin[0] + 1) *
554 Real32(viswmax[1] - viswmin[1] + 1)) / _areaSize;
558 /** Which area overlaps the given region
560 bool TileGeometryLoad::getVisibleArea( const Int32 wmin[2],
561 const Int32 wmax[2],
562 Int32 viswmin[2],
563 Int32 viswmax[2] )
565 viswmin[0] = osgMax(wmin[0],_min[0]);
566 viswmin[1] = osgMax(wmin[1],_min[1]);
567 viswmax[0] = osgMin(wmax[0],_max[0]);
568 viswmax[1] = osgMin(wmax[1],_max[1]);
569 // not in region
570 if(viswmin[0] > viswmax[0] ||
571 viswmin[1] > viswmax[1])
572 return false;
573 else
574 return true;
577 /** Check if one part of the geometry lays in the given region
579 * \param min [ minx, miny ]
580 * \param max [ maxx, maxy ]
583 bool TileGeometryLoad::checkRegion( Int32 min[2],
584 Int32 max[2] )
586 if(min[0] > _max[0] ||
587 max[0] < _min[0] ||
588 min[1] > _max[1] ||
589 max[1] < _min[1])
590 return false;
591 else
592 return true;
595 void TileGeometryLoad::setValid(bool s)
597 _valid = s;
600 bool TileGeometryLoad::isInvalid(void)
602 return !_valid;
605 /*-------------------------------------------------------------------------*/
606 /* static */
608 std::vector<Plane> TileGeometryLoad::_directions;