osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_droam/Diamond.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include "Diamond"
00020 #include "MeshManager"
00021 #include <osgEarth/Cube>
00022 #include <iterator>
00023 
00024 #ifdef USE_DEBUG_TEXTURES
00025 
00026 static osg::Image* createDebugImage()
00027 {
00028     osg::Image* image = new osg::Image();
00029     image->allocateImage( 4, 4, 1, GL_RGBA, GL_UNSIGNED_BYTE );
00030     *(unsigned int*)(image->data( 1, 0 )) = 0xff0000ff;
00031     *(unsigned int*)(image->data( 2, 0 )) = 0xff0000ff;
00032     return image;
00033 }
00034 
00035 #endif // USE_DEBUG_TEXTURES
00036 
00037 // --------------------------------------------------------------------------
00038 
00039 static int s_numDiamonds = 0;
00040 
00041 Diamond::Diamond( MeshManager* mesh, const osgEarth::TileKey& key, Level level, const std::string& name ) :
00042 osg::Referenced(true),
00043 _mesh( mesh ),
00044 _key( key ),
00045 _level( level ),
00046 _name( name ),
00047 _status( ACTIVE ),
00048 _childValence( 4 ),
00049 //_color(1,1,1,1),
00050 _lastCullFrame( 0 ),
00051 _queuedForSplit( false ),
00052 _queuedForMerge( false ),
00053 _queuedForImage( false ),
00054 _drawableDirty( false ),
00055 _bsComputed( false ),
00056 _isSplit( false ),
00057 _hasGeometry( level % 2 == 1 ),
00058 _currentStateSetOwner( 0L ),
00059 _targetStateSetOwner( 0L ),
00060 _targetStateSetRevision( -1 ),
00061 _hasFinalImage( false )
00062 {
00063     this->setThreadSafeRefUnref(true);
00064 
00065     // only ODD-numbered levels have actual geometry.
00066     if ( _hasGeometry )
00067     {
00068         _stateSet = new RevisionedStateSet();
00069         _amrDrawable = new AMRDrawable();
00070     }
00071 
00072     s_numDiamonds++;
00073     //OE_NOTICE << s_numDiamonds << " ... " << std::endl;
00074 
00075     //if ( _key.valid() )
00076     //    OE_NOTICE << "New Diamond: " << _key->str() << std::endl;
00077 
00078     //if ( _key.valid() )
00079     //    OE_NOTICE << _name << ": " << _key->str() << " : " << _key->getGeoExtent().toString() << std::endl;
00080 
00081 }
00082 
00083 Diamond::~Diamond()
00084 {
00085     s_numDiamonds--;
00086     //OE_NOTICE << s_numDiamonds << " ... " << std::endl;
00087 }
00088 
00089 const MeshNode&
00090 Diamond::node() const
00091 {
00092     return _mesh->node( _vi );
00093 }
00094 
00095 void
00096 Diamond::activate()
00097 {
00098     // this can only be called once all ancestors are established
00099 
00100     _status = ACTIVE;
00101     computeBound();
00102 
00103     if ( _hasGeometry )
00104     {
00105         // assign this diamond the stateset of the appropriate quadtree ancestor:
00106         int stateSetLevel = (int)_level;
00107         if ( stateSetLevel < (int)_mesh->_minActiveLevel )
00108             stateSetLevel = _mesh->_minActiveLevel;
00109 
00110         // obtain a pointer to the Diamond that owns the StateSet we wish to use:
00111         _targetStateSetOwner = this;
00112         while( _targetStateSetOwner->_level > stateSetLevel )
00113             _targetStateSetOwner = _targetStateSetOwner->_a[QUADTREE].get();
00114 
00115         // since that StateSet might not be populated yet, backtrack from there to find the
00116         // first available populated StateSet. This will serve as a temporary "placeholder"
00117         // until our target stateset is ready (i.e. the textures etc are loaded).
00118         _currentStateSetOwner = _targetStateSetOwner;
00119         while( !_currentStateSetOwner->_hasFinalImage && _currentStateSetOwner->_level > _mesh->_minActiveLevel )
00120         {
00121             _currentStateSetOwner = _currentStateSetOwner->_a[QUADTREE].get();
00122         }
00123 
00124         // assign the stateset to this Diamond's geometry.
00125         _amrDrawable->_stateSet = _currentStateSetOwner->_stateSet.get();
00126 
00127         // synchronize with the target state set. By doing this, we will detect when the target stateset
00128         // does finally get populated, and at that point we can replace the placeholder stateset with
00129         // the final stateset. (This check occurs in Diamond::cull.)
00130         _targetStateSetOwner->_stateSet->sync( _targetStateSetRevision );
00131 
00132 #ifdef USE_TEXTURES
00133 
00134         // finally, queue up a request to populate the stateset if necessary.
00135         if ( !_targetStateSetOwner->_hasFinalImage )
00136         {
00137             _mesh->queueForImage( _targetStateSetOwner, 1.0f );
00138         }    
00139 
00140 #endif
00141     }
00142 }
00143 
00144 
00145 //const osg::BoundingSphere&
00146 //Diamond::getBound()
00147 //{
00148 //    if ( !_bsComputed )
00149 //    {
00150 //        computeBound();
00151 //    }
00152 //    return _bs;
00153 //}
00154 
00155 void
00156 Diamond::setCoord( const osg::Vec3d& coord )
00157 {
00158     _vi = _mesh->addNode( coord );
00159 }
00160 
00161 void
00162 Diamond::seed( Level maxLevel )
00163 {
00164     if ( maxLevel > _level )
00165     {
00166         for( ChildIndex c = 0; c < _childValence; ++c )
00167         {
00168             getOrCreateChild( c )->seed( maxLevel );
00169         }
00170     }
00171 }
00172 
00173 void
00174 Diamond::split()
00175 {
00176     // mark as split, and mark the primitive set as needing a refesh:
00177     _isSplit = true;
00178 
00179     if ( _hasGeometry )
00180     {
00181         // for geometry diamonds, a split means we must regenerate this diamond
00182         // AND its quadtree ancestor.
00183         this->dirty();
00184         _a[QUADTREE]->dirty();
00185     }
00186     else
00187     {
00188         // for intermediate diamonds, splitting means we must rebuild each immediate parent.
00189         _a[PARENT_L]->dirty();
00190         _a[PARENT_R]->dirty();
00191     }
00192 
00193     _queuedForSplit = false;
00194 
00195     // check to see whether any of our neighbors are split. If a neighbor is also
00196     // split, spawn a common child.
00197     for( ChildIndex c = 0; c < _childValence; ++c )
00198     {
00199         // debugging assertion:
00200         if ( _c[c].valid() )
00201         {
00202             OE_WARN << "ILLEGAL STATE: diamond just split but has kids!" << std::endl;
00203         }
00204 
00205         Diamond* d0 = getNeighbor( c );
00206         if ( d0 && d0->_isSplit )
00207         {
00208             getOrCreateChild( c );
00209         }
00210     }
00211 }
00212 
00213 void
00214 Diamond::merge()
00215 {
00216     // have to remove/merge all the children before we can merge.
00217     for( ChildIndex c = 0; c < _childValence; ++c )
00218     {
00219         if ( _c[c].valid() )
00220             removeChild( c );
00221     }
00222     _isSplit = false;
00223 
00224     if ( _hasGeometry )
00225     {
00226         this->dirty();
00227         _a[QUADTREE]->dirty();
00228     }
00229     else
00230     {
00231         // for intermediate diamonds, merging means we must rebuild each immediate parent.
00232         _a[PARENT_L]->dirty();
00233         _a[PARENT_R]->dirty();
00234     }
00235 
00236     _queuedForMerge = false;
00237 }
00238 
00239 #define DEVIATION 0
00240 
00241 unsigned int
00242 Diamond::cull( osgUtil::CullVisitor* cv )
00243 {
00244     // NOTE:
00245     // the problem here is that if a diamond gets culled, none of its decendents are 
00246     // considered for merging. Perhaps a CULL-OUT means immediate merge-queueing? Or,
00247     // maybe we should check the traversal-number-delta. And if it's more than X,
00248     // queueForMerge.
00249 
00250     // if this diamond if maked INACTIVE, we have a problem
00251     if ( _status == INACTIVE )
00252     {
00253         OE_WARN << "ILLEGAL STATE: " << _name << " is marked INACTIVE but is being tested for cull!" << std::endl;
00254         return 0;
00255     }
00256 
00257     // trivial rejection: already traversed this diamond (multiple parenting)
00258     if ( cv->getTraversalNumber() <= _lastCullFrame )
00259         return 0;
00260 
00261     // record the framestamp so we don't cull more than once
00262     _lastCullFrame = cv->getTraversalNumber();
00263     
00264     const osg::Vec3d& eye = cv->getEyePoint();
00265     float range = (eye - visibleBound().center()).length();
00266 
00267     // NOTE: we never cull intermediate (non-geometry) diamonds.
00268 
00269     // if this geometry diamond is outside the extended bounds, it is eligible for merge AND
00270     // the diamond is not visible.
00271     if ( _hasGeometry && cv->isCulled( extendedBound() ) )
00272     {
00273         // start merging the children if this diamond fails the visibility tests.
00274         if (_level >= _mesh->_minActiveLevel && 
00275             _level <  _mesh->_maxActiveLevel && 
00276             _isSplit && 
00277             !_queuedForMerge && 
00278             !_queuedForSplit )
00279         {
00280             _mesh->queueForMerge( this, range );
00281             //OE_NOTICE << std::fixed << "isCUlled=false, range=" << range << ", radius=" << _bs.radius() << std::endl;
00282         }
00283         return 0;
00284     }
00285 
00286     // Back-face culling:
00287     // If the dot product of the eyepoint with each of the four ancestors is negative, then the
00288     // entire diamond is facing away from the camera and can be culled.
00289     if ( _hasGeometry )
00290     {
00291         int i;
00292         for( i=0; i<4; ++i )
00293         {
00294             osg::Vec3d eye_vec = eye - _a[i]->node()._vertex;
00295             double len = eye_vec.length();
00296             if ( len <= visibleBound().radius() ) break; // if we're inside the radius, bail
00297             double dev = ( eye_vec * _a[i]->node()._normal ) / len;
00298             if ( dev >= DEVIATION ) break;
00299         }
00300         if ( i == 4 )
00301             return 0;
00302     }
00303 
00304     // this will determine whether we actually add this diamond to the draw list later. we still
00305     // have to traverse children that are in the extended bounds (even if they're not in the view
00306     // frustum) in order to satifsy split requirements.
00307     bool inVisibleFrustum =
00308         _hasGeometry && !cv->isCulled( visibleBound() );
00309 
00310     // at this point, culling is now complete for this diamond.
00311 
00312 #ifdef USE_TEXTURES
00313 
00314     // check to see whether the target stateset is "dirty".
00315     if ( _hasGeometry && _targetStateSetOwner->_stateSet->outOfSyncWith( _targetStateSetRevision ) )
00316     {
00317         // flags the primitive set for regeneration
00318         this->dirty();
00319     }
00320 
00321 #endif
00322 
00323     // traverse the diamond's children.
00324     unsigned short numChildren = 0;
00325     for( ChildIndex c = 0; c < _childValence; ++c )
00326     {
00327         if ( _c[c].valid() )
00328         {
00329             ++numChildren;
00330             _c[c]->cull( cv );
00331         }
00332     }
00333 
00334     if ( _hasGeometry && _amrDrawable->_triangles.size() == 0 && numChildren < _childValence )
00335         OE_WARN << "BOOGER" << std::endl;
00336 
00337     //if ( _hasGeometry && _amrDrawable->_triangles.size() > 0 )
00338     if ( inVisibleFrustum )
00339     {
00340         _mesh->_amrDrawList.push_back( _amrDrawable.get() );
00341     }
00342     
00343     // culling is complete. next we will check to see if we need to split this diamond
00344     // based on LOD range.
00345     // FUTURE: splitting will depend on a couple factors: max split level (resolution),
00346     // available data, frame rate, etc.
00347     if ( _level >= _mesh->_minActiveLevel && _level < _mesh->_maxActiveLevel )
00348     {
00349         if (!_isSplit && 
00350             range < extendedBound().radius() * CULL_RANGE_FACTOR &&
00351             !_queuedForSplit &&
00352             !_queuedForMerge &&
00353             numChildren < _childValence )
00354         {
00355             _mesh->queueForSplit( this, -range );
00356             _queuedForMerge = false;
00357         }
00358 
00359         else if (
00360             _isSplit &&
00361             range > extendedBound().radius() * CULL_RANGE_FACTOR &&
00362             !_queuedForSplit &&
00363             !_queuedForMerge &&
00364             numChildren > 0 )
00365         {
00366             _mesh->queueForMerge( this, range );
00367             _queuedForSplit = false;
00368         }
00369     }
00370 
00371     return 0;
00372     //return _numGeometriesAdded;
00373 }
00374 
00375 void
00376 Diamond::computeBound()
00377 {
00378     // in vert space.
00379     _visibleBound = osg::BoundingSphere( node()._vertex, 1.0 );
00380     for(int i=0; i<4; i++) 
00381         _visibleBound.expandRadiusBy( _a[i]->node()._vertex );
00382 
00383     _extendedBound = _visibleBound;
00384     _extendedBound.radius() = _extendedBound.radius() * sqrt(2.0) * 2.0;
00385 
00386     _bsComputed = true;
00387 }
00388 
00389 const osg::BoundingSphere&
00390 Diamond::visibleBound() const
00391 {
00392     if ( !_bsComputed )
00393         const_cast<Diamond*>(this)->computeBound();
00394     return _visibleBound;
00395 }
00396 
00397 const osg::BoundingSphere&
00398 Diamond::extendedBound() const
00399 {
00400     if ( !_bsComputed )
00401         const_cast<Diamond*>(this)->computeBound();
00402     return _extendedBound;
00403 }
00404 
00405 void
00406 Diamond::dump()
00407 {
00408     OE_NOTICE
00409         << "Diamond " << _name << "\n" //" (" << _v.x() << "," << _v.y() << "," << _v.z() << ") :\n"
00410         << "  level    = " << _level << "\n"
00411         << "  parent_R = " << _a[PARENT_R]->_name << "\n"
00412         << "  parent_L = " << _a[PARENT_L]->_name << "\n"
00413         << "  quadtree = " << _a[QUADTREE]->_name << "\n"
00414         << "  gdparent = " << _a[GDPARENT]->_name << "\n"
00415         << "  children = ";
00416     
00417     for( int i=0; i<_childValence; ++i )
00418         OE_NOTICE << i << ":<" << ( _c[i].valid()? _c[i]->_name : "") << ">  ";
00419 
00420     OE_NOTICE << std::endl << std::endl;
00421 }
00422 
00423 void
00424 Diamond::setChild( ChildIndex index, Diamond* child )
00425 {
00426     _c[index] = child;
00427 
00428     if ( child->_hasGeometry )
00429     {
00430         // if this is a geometry diamond, invalidate the quadtree ancestor so it can include it.
00431         child->_a[QUADTREE]->dirty();
00432         child->dirty();
00433     }
00434     else
00435     {
00436         this->_a[PARENT_L]->dirty();
00437         this->_a[PARENT_R]->dirty();
00438     }
00439 }
00440 
00441 void
00442 Diamond::dirty()
00443 {
00444     // queue this diamond for a primitive set refresh .. but only if it actually has geometry.
00445     if ( _hasGeometry && _level >= _mesh->_minGeomLevel )
00446     {
00447         if ( !_drawableDirty )
00448         {
00449             _drawableDirty = true;
00450 #ifdef USE_DIRTY_QUEUE
00451             _mesh->queueForRefresh( this );
00452 #else
00453             refreshDrawable();
00454 #endif
00455         }
00456     }
00457     else
00458     {
00459         //OE_WARN << "ILLEGAL: dirty(): _hasGeometry = " << _hasGeometry << ", _level = " << _level << std::endl;
00460     }
00461 }
00462 
00463 // texture coordinate for each orientation.
00464 #define T_QUADTREE 0
00465 #define T_CHILD_0  1
00466 #define T_PARENT_R 2
00467 #define T_CHILD_1  3
00468 #define T_GDPARENT 4
00469 #define T_CHILD_2  5
00470 #define T_PARENT_L 6
00471 #define T_CHILD_3  7
00472 
00473 static osg::Vec2f otex[8] =
00474 {
00475     osg::Vec2f(0.0,0.0), // T_QUADTREE
00476     osg::Vec2f(0.5,0.0), // T_CHILD_0
00477     osg::Vec2f(1.0,0.0), // T_PARENT_R
00478     osg::Vec2f(1.0,0.5), // T_CHILD_1
00479     osg::Vec2f(1.0,1.0), // T_GDPARENT
00480     osg::Vec2f(0.5,1.0), // T_CHILD_2
00481     osg::Vec2f(0.0,1.0), // T_PARENT_L
00482     osg::Vec2f(0.0,0.5)  // T_CHILD_3
00483 };
00484 
00485 #define OT(I,R) otex[ ( I + R ) % 8 ]
00486 
00487 #define ADD_TRI( COORDS, TEX, C1, T1, C2, T2, C3, T3, OFFSET, SPAN ) { \
00488     COORDS->push_back(C1); \
00489     COORDS->push_back(C2); \
00490     COORDS->push_back(C3); \
00491     TEX->push_back( OFFSET + (T1*SPAN) ); \
00492     TEX->push_back( OFFSET + (T2*SPAN) ); \
00493     TEX->push_back( OFFSET + (T3*SPAN) );
00494 
00495 void
00496 Diamond::refreshDrawable()
00497 {
00498     // the primitive set may have already been refreshed (due to double-parenting)
00499     if ( !_drawableDirty )
00500         return;
00501 
00502     // this level does not generate primitive sets
00503     if ( _level < _mesh->_minGeomLevel )
00504         return;
00505 
00506     if ( !_hasGeometry )
00507     {
00508         OE_WARN << "ILLEGAL: refreshPrimitiveSet called on Diamond at no-geom level " << _level << std::endl;
00509         return;
00510     }
00511 
00512     // figure out the subrange transformation.
00513     osg::Vec2f offset( 0.0, 0.0 );
00514     double span = 1.0;
00515 
00516     const TileKey& ssaKey = _currentStateSetOwner->_key;
00517     if ( _level > _currentStateSetOwner->_level ) //_currentStateSetOwner != _targetStateSetOwner )
00518     {
00519         span = 1.0/(double)(1 << ((_level-_currentStateSetOwner->_level)/2));
00520         offset.x() = (_key.getExtent().xMin()-ssaKey.getExtent().xMin())/ssaKey.getExtent().width();
00521         offset.y() = (_key.getExtent().yMin()-ssaKey.getExtent().yMin())/ssaKey.getExtent().height();
00522     }
00523 
00524     int o = _orientation;
00525     
00526     // Start by clearing out the old primitive set:
00527     _amrDrawable->_triangles.clear();
00528 
00529     //if ( false ) //!_isSplit ) // took this out to preserve the diamond center point.
00530     //{
00531     //    // if the diamond is not split, simply draw the two triangles.
00532     //    _amrDrawable->add( new AMRTriangle(
00533     //        _a[GDPARENT]->coord(), _a[GDPARENT]->vert(), offset + OT(T_GDPARENT,o) * span,
00534     //        _a[QUADTREE]->coord(), _a[QUADTREE]->vert(), offset + OT(T_QUADTREE,o) * span,
00535     //        _a[PARENT_R]->coord(), _a[PARENT_R]->vert(), offset + OT(T_PARENT_R,o) * span ) );
00536 
00537     //    _amrDrawable->add( new AMRTriangle(
00538     //        _a[GDPARENT]->coord(), _a[GDPARENT]->vert(), offset + OT(T_GDPARENT,o) * span,
00539     //        _a[PARENT_L]->coord(), _a[PARENT_L]->vert(), offset + OT(T_PARENT_L,o) * span,
00540     //        _a[QUADTREE]->coord(), _a[QUADTREE]->vert(), offset + OT(T_QUADTREE,o) * span ) );
00541     //}
00542     //else
00543     {
00544         // find this diamond's four quadtree descendants:
00545         Diamond* q0 = _c[0].valid() ? _c[0]->_c[1].get() : 0L;
00546         Diamond* q1 = _c[1].valid() ? _c[1]->_c[3].get() : 0L;
00547         Diamond* q2 = _c[2].valid() ? _c[2]->_c[1].get() : 0L;
00548         Diamond* q3 = _c[3].valid() ? _c[3]->_c[3].get() : 0L;
00549 
00550         osg::Vec2f center = osg::Vec2f(.5,.5);
00551 
00552         if ( !_c[0].valid() || !_c[0]->_isSplit )
00553         {
00554             _amrDrawable->add( new AMRTriangle(
00555                 node(),               offset + center * span,
00556                 _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span,
00557                 _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span ) );
00558         }
00559         else
00560         {
00561             if ( !q0 )
00562             {
00563                 _amrDrawable->add( new AMRTriangle(
00564                     node(),               offset + center * span,
00565                     _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span,
00566                     _c[0]->node(),        offset + OT(T_CHILD_0,o) * span ) );
00567             }
00568             if ( !q1 )
00569             {
00570                 _amrDrawable->add( new AMRTriangle(
00571                     node(),               offset + center * span,
00572                     _c[0]->node(),        offset + OT(T_CHILD_0,o) * span,
00573                     _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span ) );
00574             }
00575         }
00576 
00577         if ( !_c[1].valid() || !_c[1]->_isSplit )
00578         {
00579             _amrDrawable->add( new AMRTriangle(
00580                 node(),               offset + center * span,
00581                 _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span,
00582                 _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span ) );
00583         }
00584         else
00585         {
00586             if ( !q1 )
00587             {
00588                 _amrDrawable->add( new AMRTriangle(
00589                     node(),               offset + center * span,
00590                     _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span,
00591                     _c[1]->node(),        offset + OT(T_CHILD_1,o) * span ) );
00592             }
00593             if ( !q2 )
00594             {
00595                 _amrDrawable->add( new AMRTriangle(
00596                     node(),               offset + center * span,
00597                     _c[1]->node(),        offset + OT(T_CHILD_1,o) * span,
00598                     _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span ) );
00599             }
00600         }
00601 
00602         if ( !_c[2].valid() || !_c[2]->_isSplit )
00603         {
00604             _amrDrawable->add( new AMRTriangle(
00605                 node(),               offset + center * span,
00606                 _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span,
00607                 _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span ) );
00608         }
00609         else
00610         {
00611             if ( !q2 )
00612             {
00613                 _amrDrawable->add( new AMRTriangle(
00614                     node(),               offset + center * span,
00615                     _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span,
00616                     _c[2]->node(),        offset + OT(T_CHILD_2,o) * span ) );
00617             }
00618             if ( !q3 )
00619             {
00620                 _amrDrawable->add( new AMRTriangle(
00621                     node(),               offset + center * span,
00622                     _c[2]->node(),        offset + OT(T_CHILD_2,o) * span,
00623                     _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span ) );
00624             }
00625         }
00626 
00627         if ( !_c[3].valid() || !_c[3]->_isSplit )
00628         {
00629             _amrDrawable->add( new AMRTriangle(
00630                 node(),               offset + center * span,
00631                 _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span,
00632                 _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span ) );
00633         }
00634         else
00635         {
00636             if ( !q3 )
00637             {
00638                 _amrDrawable->add( new AMRTriangle(
00639                     node(),               offset + center * span,
00640                     _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span,
00641                     _c[3]->node(),        offset + OT(T_CHILD_3,o) * span ) );
00642             }
00643             if ( !q0 )
00644             {
00645                 _amrDrawable->add( new AMRTriangle(
00646                     node(),               offset + center * span,
00647                     _c[3]->node(),        offset + OT(T_CHILD_3,o) * span,
00648                     _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span ) );
00649             }
00650         }        
00651     }
00652 
00653     // dirty the underlying element buffer object
00654     _drawableDirty = false;
00655 }
00656 
00657 bool
00658 Diamond::hasChildren() const
00659 {
00660     for( unsigned short c = 0; c < _childValence; ++c )
00661     {
00662         if ( _c[c].valid() )
00663             return true;
00664     }
00665     return false;
00666 }
00667 
00668 bool
00669 Diamond::hasAllChildren() const
00670 {
00671     for( unsigned short c = 0; c < _childValence; ++c )
00672     {
00673         if ( !_c[c].valid() )
00674             return false;
00675     }
00676     return true;
00677 }
00678 
00679 ChildIndex
00680 Diamond::getIndexOfChild( Diamond* child )
00681 {
00682     for( ChildIndex c = 0; c < _childValence; ++c )
00683     {
00684         if ( _c[c].get() == child )
00685             return c;
00686     }
00687     return -1;
00688 }
00689 
00690 Diamond*
00691 Diamond::getNeighbor( ChildIndex c )
00692 {   
00693     unsigned short parent = c <= 1 ? PARENT_R : PARENT_L;
00694     ChildIndex myIndexInParent = _a[parent]->getIndexOfChild( this );
00695     ChildIndex i = ( myIndexInParent + (c==0 || c==2? 1 : 3) ) % _a[parent]->_childValence;
00696     return _a[parent]->_c[i].get();
00697 }
00698 
00699 Diamond*
00700 Diamond::getOrCreateNeighbor( ChildIndex c )
00701 {   
00702     //OE_NOTICE << "Looking up neighbor (" << c << ") of " << _name << std::endl;
00703     unsigned short parent = c <= 1 ? PARENT_R : PARENT_L;
00704     ChildIndex myIndexInParent = _a[parent]->getIndexOfChild( this );
00705     ChildIndex i = ( myIndexInParent + (c==0 || c==2? 1 : 3) ) % _a[parent]->_childValence;
00706     //if ( !_a[parent]->_c[i].valid() )
00707     //    OE_NOTICE << "...doesn't exist, creating:" << std::endl;
00708     return _a[parent]->getOrCreateChild( i );
00709 }
00710 
00711 ChildIndex 
00712 Diamond::getIndexOfChildEdgeStartingAt( NodeIndex vi )
00713 {
00714     if ( vi == _a[QUADTREE]->_vi ) return 0;
00715     else if ( vi == _a[PARENT_R]->_vi ) return 1;
00716     else if ( vi == _a[GDPARENT]->_vi ) return 2;
00717     else return 3;
00718 }
00719 
00720 Diamond*
00721 Diamond::getOrCreateChild( ChildIndex c )
00722 {
00723     if ( _c[c].valid() )
00724         return _c[c].get();
00725 
00726     // must force a split before creating children. dont' need to call dirty() because
00727     // that gets called later by setChild()
00728     _isSplit = true;
00729 
00730     //OE_NOTICE << "Creating child of " << _name << " at " << c << std::endl;
00731     //dump();
00732 
00733     Diamond* d  = this;
00734     osg::ref_ptr<Diamond> d0 = getOrCreateNeighbor( c );
00735 
00736     unsigned short whichParent = c <= 1 ? PARENT_R : PARENT_L;
00737     osg::ref_ptr<Diamond> qa = d->_a[whichParent].get(); // the common parent
00738 
00739     Diamond* child = new Diamond( _mesh, TileKey(), d->_level+1 );
00740     //Diamond* child = new Diamond( _mesh, 0L, d->_level+1,  " ("+_name+" + "+d0->_name+") " );
00741 
00742     //OE_NOTICE << "...neighbor: " << d0->_name << std::endl;   
00743     //OE_NOTICE << "...common parent: " << commonParent->_name << std::endl;
00744     
00745     // assign child's quadtree ansector to d and d0's common parent.
00746     child->_a[QUADTREE] = qa.get();
00747 
00748     // assign child's grandparent ansector pointer:
00749     child->_a[GDPARENT] = c == 0 || c == 3 ? d->_a[QUADTREE].get() : d->_a[GDPARENT].get();
00750 
00751     // determine the child index of child in d0:
00752     unsigned short p = c==0 || c==2 ? QUADTREE : GDPARENT;
00753     ChildIndex c_d0 = d0->getIndexOfChildEdgeStartingAt( child->_a[p]->_vi );
00754     if ( c_d0 < 0 )
00755     {
00756         OE_WARN << "Diamond: getOrCreateChild: illegal state, cannot find neighbor's child edge...crash immiment\n";
00757     }
00758 
00759     // assign the child's parent pointers
00760     child->_a[PARENT_R] = (c == 0 || c == 2) ? d : d0.get();
00761     child->_a[PARENT_L] = (c == 0 || c == 2) ? d0.get() : d;
00762 
00763     // how that we know the QUADTREE & GDPARENT ancestors, create the diamond vertex.
00764     osg::Vec3d newCoord = _mesh->_manifold->midpoint(
00765         child->_a[QUADTREE]->node()._manifoldCoord,
00766         child->_a[GDPARENT]->node()._manifoldCoord );
00767 
00768     child->setCoord( newCoord );
00769 
00770     // assign the new child in both d and d0:
00771     d->setChild( c, child );
00772     d0->setChild( c_d0, child );
00773 
00774     if ( child->_hasGeometry )
00775     {
00776         // if this is a intermediate diamond, make a new key for the parent's quadtree descendant.
00777         // if this is a geometry diamond, the new intermediate child gets no key.
00778         int quadrant = -1;
00779 
00780         if ( qa->_orientation == 0 )
00781         {
00782             quadrant = 
00783                 qa->q(0) == child ? 2 :
00784                 qa->q(1) == child ? 3 :
00785                 qa->q(2) == child ? 1 : 0;
00786         }
00787         else if ( qa->_orientation == 2 )
00788         {
00789             quadrant =
00790                 qa->q(0) == child ? 3 :
00791                 qa->q(1) == child ? 1 :
00792                 qa->q(2) == child ? 0 : 2;
00793         }
00794         else if ( qa->_orientation == 4 )
00795         {
00796             quadrant =
00797                 qa->q(0) == child ? 1 :
00798                 qa->q(1) == child ? 0 :
00799                 qa->q(2) == child ? 2 : 3;
00800         }
00801         else // if ( qa->_orientation == 6 )
00802         {
00803             quadrant =
00804                 qa->q(0) == child ? 0 :
00805                 qa->q(1) == child ? 2 :
00806                 qa->q(2) == child ? 3 : 1;
00807         }
00808 
00809         child->_key = qa->_key.createChildKey( quadrant );
00810 
00811         child->_orientation = 
00812             quadrant == 1 ? 0 :
00813             quadrant == 0 ? 2 :
00814             quadrant == 2 ? 4 : 6;
00815     }
00816 
00817     child->activate();
00818 
00819     return child;
00820 }
00821 
00822 void
00823 Diamond::removeChild( ChildIndex c )
00824 {
00825     osg::ref_ptr<Diamond> child = _c[c].get();
00826     if ( !child.valid() ) return;
00827 
00828     // first we must merge the child (i.e. remove all of ITS children recursively).
00829     // TODO: this probably needs to queue up another merge operation with a higher priority.
00830     // that should probably happen in the mesh manager.
00831     child->merge();
00832 
00833     // deactivate the child. it's possible that the child is in a queue somewhere. this
00834     // will prevent it from being processed after it's been removed.
00835     child->_status = INACTIVE;
00836 
00837     // remove it from its other parent as well.
00838     osg::ref_ptr<Diamond> d0 = getNeighbor( c );
00839     if ( d0.valid() )
00840     {
00841         ChildIndex c_d0 = d0->getIndexOfChild( child.get() );
00842         if ( c_d0 >= 0 )
00843         {
00844             d0->_c[c_d0] = 0L;
00845         }
00846     }
00847 
00848     // now clear out the child slot and invalidate the primitive set.
00849     this->_c[c] = 0L;
00850 
00851     // notify the common ancestry of the change
00852     if ( child->_hasGeometry )
00853     {
00854         child->_a[QUADTREE]->dirty();
00855         this->dirty();
00856     }
00857     else
00858     {
00859         // probably not strictly necessary since a split() will take care of this.. gw
00860         child->_a[PARENT_L]->dirty();
00861         child->_a[PARENT_R]->dirty();
00862     }
00863 
00864     // zero out the child's ancestor pointers.
00865     for( AncestorIndex i = 0; i < 4; ++i )
00866         child->_a[i] = 0L;
00867     for( ChildIndex i = 0; i < 4; ++i )
00868         child->_c[i] = 0L;
00869 
00870     // remove the child's vertex from the VBO.
00871     _mesh->removeNode( child->_vi );
00872 }
00873 
00874 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines