osgEarth 2.1.1
Public Member Functions | Public Attributes

Diamond Struct Reference

Inheritance diagram for Diamond:
Collaboration diagram for Diamond:

List of all members.

Public Member Functions

 Diamond (MeshManager *mesh, const osgEarth::TileKey &key, Level level, const std::string &name="")
 ~Diamond ()
void activate ()
const osg::BoundingSphere & visibleBound () const
const osg::BoundingSphere & extendedBound () const
void dump ()
void setCoord (double x, double y, double z)
void setCoord (const osg::Vec3d &coord)
DiamondgetOrCreateNeighbor (ChildIndex c)
DiamondgetNeighbor (ChildIndex c)
DiamondgetOrCreateChild (ChildIndex c)
void removeChild (ChildIndex c)
ChildIndex getIndexOfChild (Diamond *child)
ChildIndex getIndexOfChildEdgeStartingAt (NodeIndex vi)
void seed (Level maxLevel)
void split ()
void merge ()
bool hasChildren () const
bool hasAllChildren () const
void computeBound ()
unsigned int cull (osgUtil::CullVisitor *cv)
void setChild (ChildIndex index, Diamond *child)
void refreshDrawable ()
void dirty ()
Diamondq (ChildIndex c)
const MeshNodenode () const

Public Attributes

osgEarth::TileKey _key
std::string _name
Level _level
Orientation _orientation
DiamondStatus _status
MeshManager_mesh
osg::ref_ptr< Diamond_a [4]
osg::ref_ptr< Diamond_c [4]
unsigned short _childValence
bool _isSplit
bool _hasGeometry
NodeIndex _vi
TravNumber _lastCullFrame
bool _drawableDirty
bool _queuedForSplit
bool _queuedForMerge
bool _queuedForImage
bool _bsComputed
bool _imageRequested
osg::ref_ptr< RevisionedStateSet_stateSet
osg::ref_ptr< AMRDrawable_amrDrawable
Diamond_targetStateSetOwner
Diamond_currentStateSetOwner
osgEarth::Revision _targetStateSetRevision
bool _hasFinalImage
osg::BoundingSphere _visibleBound
osg::BoundingSphere _extendedBound
osg::ref_ptr
< osgEarth::TaskRequest
_imageRequest

Detailed Description

A diamond is the basic unit object for the terrain mesh. There are two types of diamonds: Geometry diamonds reside at odd levels and contain actual geometry. Intermediate diamonds reside at even levels and serve to connect the continuous mesh between geometry levels, but contain no visible geometry themselves.

Definition at line 57 of file Diamond.


Constructor & Destructor Documentation

Diamond::Diamond ( MeshManager mesh,
const osgEarth::TileKey key,
Level  level,
const std::string &  name = "" 
)

Definition at line 41 of file Diamond.cpp.

                                                                                                    :
osg::Referenced(true),
_mesh( mesh ),
_key( key ),
_level( level ),
_name( name ),
_status( ACTIVE ),
_childValence( 4 ),
//_color(1,1,1,1),
_lastCullFrame( 0 ),
_queuedForSplit( false ),
_queuedForMerge( false ),
_queuedForImage( false ),
_drawableDirty( false ),
_bsComputed( false ),
_isSplit( false ),
_hasGeometry( level % 2 == 1 ),
_currentStateSetOwner( 0L ),
_targetStateSetOwner( 0L ),
_targetStateSetRevision( -1 ),
_hasFinalImage( false )
{
    this->setThreadSafeRefUnref(true);

    // only ODD-numbered levels have actual geometry.
    if ( _hasGeometry )
    {
        _stateSet = new RevisionedStateSet();
        _amrDrawable = new AMRDrawable();
    }

    s_numDiamonds++;
    //OE_NOTICE << s_numDiamonds << " ... " << std::endl;

    //if ( _key.valid() )
    //    OE_NOTICE << "New Diamond: " << _key->str() << std::endl;

    //if ( _key.valid() )
    //    OE_NOTICE << _name << ": " << _key->str() << " : " << _key->getGeoExtent().toString() << std::endl;

}

Here is the caller graph for this function:

Diamond::~Diamond ( )

Definition at line 83 of file Diamond.cpp.

{
    s_numDiamonds--;
    //OE_NOTICE << s_numDiamonds << " ... " << std::endl;
}

Member Function Documentation

void Diamond::activate ( )

Definition at line 96 of file Diamond.cpp.

{
    // this can only be called once all ancestors are established

    _status = ACTIVE;
    computeBound();

    if ( _hasGeometry )
    {
        // assign this diamond the stateset of the appropriate quadtree ancestor:
        int stateSetLevel = (int)_level;
        if ( stateSetLevel < (int)_mesh->_minActiveLevel )
            stateSetLevel = _mesh->_minActiveLevel;

        // obtain a pointer to the Diamond that owns the StateSet we wish to use:
        _targetStateSetOwner = this;
        while( _targetStateSetOwner->_level > stateSetLevel )
            _targetStateSetOwner = _targetStateSetOwner->_a[QUADTREE].get();

        // since that StateSet might not be populated yet, backtrack from there to find the
        // first available populated StateSet. This will serve as a temporary "placeholder"
        // until our target stateset is ready (i.e. the textures etc are loaded).
        _currentStateSetOwner = _targetStateSetOwner;
        while( !_currentStateSetOwner->_hasFinalImage && _currentStateSetOwner->_level > _mesh->_minActiveLevel )
        {
            _currentStateSetOwner = _currentStateSetOwner->_a[QUADTREE].get();
        }

        // assign the stateset to this Diamond's geometry.
        _amrDrawable->_stateSet = _currentStateSetOwner->_stateSet.get();

        // synchronize with the target state set. By doing this, we will detect when the target stateset
        // does finally get populated, and at that point we can replace the placeholder stateset with
        // the final stateset. (This check occurs in Diamond::cull.)
        _targetStateSetOwner->_stateSet->sync( _targetStateSetRevision );

#ifdef USE_TEXTURES

        // finally, queue up a request to populate the stateset if necessary.
        if ( !_targetStateSetOwner->_hasFinalImage )
        {
            _mesh->queueForImage( _targetStateSetOwner, 1.0f );
        }    

#endif
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::computeBound ( )

recalcuates the squared radius of thid diamond.

Definition at line 376 of file Diamond.cpp.

{
    // in vert space.
    _visibleBound = osg::BoundingSphere( node()._vertex, 1.0 );
    for(int i=0; i<4; i++) 
        _visibleBound.expandRadiusBy( _a[i]->node()._vertex );

    _extendedBound = _visibleBound;
    _extendedBound.radius() = _extendedBound.radius() * sqrt(2.0) * 2.0;

    _bsComputed = true;
}

Here is the call graph for this function:

Here is the caller graph for this function:

unsigned int Diamond::cull ( osgUtil::CullVisitor *  cv)

update the culling status of the diamond and its children based on a new eyepoint.

Definition at line 242 of file Diamond.cpp.

{
    // NOTE:
    // the problem here is that if a diamond gets culled, none of its decendents are 
    // considered for merging. Perhaps a CULL-OUT means immediate merge-queueing? Or,
    // maybe we should check the traversal-number-delta. And if it's more than X,
    // queueForMerge.

    // if this diamond if maked INACTIVE, we have a problem
    if ( _status == INACTIVE )
    {
        OE_WARN << "ILLEGAL STATE: " << _name << " is marked INACTIVE but is being tested for cull!" << std::endl;
        return 0;
    }

    // trivial rejection: already traversed this diamond (multiple parenting)
    if ( cv->getTraversalNumber() <= _lastCullFrame )
        return 0;

    // record the framestamp so we don't cull more than once
    _lastCullFrame = cv->getTraversalNumber();
    
    const osg::Vec3d& eye = cv->getEyePoint();
    float range = (eye - visibleBound().center()).length();

    // NOTE: we never cull intermediate (non-geometry) diamonds.

    // if this geometry diamond is outside the extended bounds, it is eligible for merge AND
    // the diamond is not visible.
    if ( _hasGeometry && cv->isCulled( extendedBound() ) )
    {
        // start merging the children if this diamond fails the visibility tests.
        if (_level >= _mesh->_minActiveLevel && 
            _level <  _mesh->_maxActiveLevel && 
            _isSplit && 
            !_queuedForMerge && 
            !_queuedForSplit )
        {
            _mesh->queueForMerge( this, range );
            //OE_NOTICE << std::fixed << "isCUlled=false, range=" << range << ", radius=" << _bs.radius() << std::endl;
        }
        return 0;
    }

    // Back-face culling:
    // If the dot product of the eyepoint with each of the four ancestors is negative, then the
    // entire diamond is facing away from the camera and can be culled.
    if ( _hasGeometry )
    {
        int i;
        for( i=0; i<4; ++i )
        {
            osg::Vec3d eye_vec = eye - _a[i]->node()._vertex;
            double len = eye_vec.length();
            if ( len <= visibleBound().radius() ) break; // if we're inside the radius, bail
            double dev = ( eye_vec * _a[i]->node()._normal ) / len;
            if ( dev >= DEVIATION ) break;
        }
        if ( i == 4 )
            return 0;
    }

    // this will determine whether we actually add this diamond to the draw list later. we still
    // have to traverse children that are in the extended bounds (even if they're not in the view
    // frustum) in order to satifsy split requirements.
    bool inVisibleFrustum =
        _hasGeometry && !cv->isCulled( visibleBound() );

    // at this point, culling is now complete for this diamond.

#ifdef USE_TEXTURES

    // check to see whether the target stateset is "dirty".
    if ( _hasGeometry && _targetStateSetOwner->_stateSet->outOfSyncWith( _targetStateSetRevision ) )
    {
        // flags the primitive set for regeneration
        this->dirty();
    }

#endif

    // traverse the diamond's children.
    unsigned short numChildren = 0;
    for( ChildIndex c = 0; c < _childValence; ++c )
    {
        if ( _c[c].valid() )
        {
            ++numChildren;
            _c[c]->cull( cv );
        }
    }

    if ( _hasGeometry && _amrDrawable->_triangles.size() == 0 && numChildren < _childValence )
        OE_WARN << "BOOGER" << std::endl;

    //if ( _hasGeometry && _amrDrawable->_triangles.size() > 0 )
    if ( inVisibleFrustum )
    {
        _mesh->_amrDrawList.push_back( _amrDrawable.get() );
    }
    
    // culling is complete. next we will check to see if we need to split this diamond
    // based on LOD range.
    // FUTURE: splitting will depend on a couple factors: max split level (resolution),
    // available data, frame rate, etc.
    if ( _level >= _mesh->_minActiveLevel && _level < _mesh->_maxActiveLevel )
    {
        if (!_isSplit && 
            range < extendedBound().radius() * CULL_RANGE_FACTOR &&
            !_queuedForSplit &&
            !_queuedForMerge &&
            numChildren < _childValence )
        {
            _mesh->queueForSplit( this, -range );
            _queuedForMerge = false;
        }

        else if (
            _isSplit &&
            range > extendedBound().radius() * CULL_RANGE_FACTOR &&
            !_queuedForSplit &&
            !_queuedForMerge &&
            numChildren > 0 )
        {
            _mesh->queueForMerge( this, range );
            _queuedForSplit = false;
        }
    }

    return 0;
    //return _numGeometriesAdded;
}

Here is the call graph for this function:

void Diamond::dirty ( )

marks this diamond's primitive set as needing a refresh.

Definition at line 442 of file Diamond.cpp.

{
    // queue this diamond for a primitive set refresh .. but only if it actually has geometry.
    if ( _hasGeometry && _level >= _mesh->_minGeomLevel )
    {
        if ( !_drawableDirty )
        {
            _drawableDirty = true;
#ifdef USE_DIRTY_QUEUE
            _mesh->queueForRefresh( this );
#else
            refreshDrawable();
#endif
        }
    }
    else
    {
        //OE_WARN << "ILLEGAL: dirty(): _hasGeometry = " << _hasGeometry << ", _level = " << _level << std::endl;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::dump ( )

print debugging info

Definition at line 406 of file Diamond.cpp.

{
    OE_NOTICE
        << "Diamond " << _name << "\n" //" (" << _v.x() << "," << _v.y() << "," << _v.z() << ") :\n"
        << "  level    = " << _level << "\n"
        << "  parent_R = " << _a[PARENT_R]->_name << "\n"
        << "  parent_L = " << _a[PARENT_L]->_name << "\n"
        << "  quadtree = " << _a[QUADTREE]->_name << "\n"
        << "  gdparent = " << _a[GDPARENT]->_name << "\n"
        << "  children = ";
    
    for( int i=0; i<_childValence; ++i )
        OE_NOTICE << i << ":<" << ( _c[i].valid()? _c[i]->_name : "") << ">  ";

    OE_NOTICE << std::endl << std::endl;
}
const osg::BoundingSphere & Diamond::extendedBound ( ) const

Definition at line 398 of file Diamond.cpp.

{
    if ( !_bsComputed )
        const_cast<Diamond*>(this)->computeBound();
    return _extendedBound;
}

Here is the call graph for this function:

Here is the caller graph for this function:

ChildIndex Diamond::getIndexOfChild ( Diamond child)

gets the index of a child diamond in teh children array, or return _numChildren if not found

Definition at line 680 of file Diamond.cpp.

{
    for( ChildIndex c = 0; c < _childValence; ++c )
    {
        if ( _c[c].get() == child )
            return c;
    }
    return -1;
}
ChildIndex Diamond::getIndexOfChildEdgeStartingAt ( NodeIndex  vi)

Gets the child index of the diamond edge that begins at the specified vertex.

Definition at line 712 of file Diamond.cpp.

{
    if ( vi == _a[QUADTREE]->_vi ) return 0;
    else if ( vi == _a[PARENT_R]->_vi ) return 1;
    else if ( vi == _a[GDPARENT]->_vi ) return 2;
    else return 3;
}
Diamond * Diamond::getNeighbor ( ChildIndex  c)

Gets this diamond's neighbor across child-c boundary, returning NULL if it does not exist.

Definition at line 691 of file Diamond.cpp.

{   
    unsigned short parent = c <= 1 ? PARENT_R : PARENT_L;
    ChildIndex myIndexInParent = _a[parent]->getIndexOfChild( this );
    ChildIndex i = ( myIndexInParent + (c==0 || c==2? 1 : 3) ) % _a[parent]->_childValence;
    return _a[parent]->_c[i].get();
}

Here is the caller graph for this function:

Diamond * Diamond::getOrCreateChild ( ChildIndex  c)

Gets this diamond's child at index c, creating it if it does not exist.

Definition at line 721 of file Diamond.cpp.

{
    if ( _c[c].valid() )
        return _c[c].get();

    // must force a split before creating children. dont' need to call dirty() because
    // that gets called later by setChild()
    _isSplit = true;

    //OE_NOTICE << "Creating child of " << _name << " at " << c << std::endl;
    //dump();

    Diamond* d  = this;
    osg::ref_ptr<Diamond> d0 = getOrCreateNeighbor( c );

    unsigned short whichParent = c <= 1 ? PARENT_R : PARENT_L;
    osg::ref_ptr<Diamond> qa = d->_a[whichParent].get(); // the common parent

    Diamond* child = new Diamond( _mesh, TileKey(), d->_level+1 );
    //Diamond* child = new Diamond( _mesh, 0L, d->_level+1,  " ("+_name+" + "+d0->_name+") " );

    //OE_NOTICE << "...neighbor: " << d0->_name << std::endl;   
    //OE_NOTICE << "...common parent: " << commonParent->_name << std::endl;
    
    // assign child's quadtree ansector to d and d0's common parent.
    child->_a[QUADTREE] = qa.get();

    // assign child's grandparent ansector pointer:
    child->_a[GDPARENT] = c == 0 || c == 3 ? d->_a[QUADTREE].get() : d->_a[GDPARENT].get();

    // determine the child index of child in d0:
    unsigned short p = c==0 || c==2 ? QUADTREE : GDPARENT;
    ChildIndex c_d0 = d0->getIndexOfChildEdgeStartingAt( child->_a[p]->_vi );
    if ( c_d0 < 0 )
    {
        OE_WARN << "Diamond: getOrCreateChild: illegal state, cannot find neighbor's child edge...crash immiment\n";
    }

    // assign the child's parent pointers
    child->_a[PARENT_R] = (c == 0 || c == 2) ? d : d0.get();
    child->_a[PARENT_L] = (c == 0 || c == 2) ? d0.get() : d;

    // how that we know the QUADTREE & GDPARENT ancestors, create the diamond vertex.
    osg::Vec3d newCoord = _mesh->_manifold->midpoint(
        child->_a[QUADTREE]->node()._manifoldCoord,
        child->_a[GDPARENT]->node()._manifoldCoord );

    child->setCoord( newCoord );

    // assign the new child in both d and d0:
    d->setChild( c, child );
    d0->setChild( c_d0, child );

    if ( child->_hasGeometry )
    {
        // if this is a intermediate diamond, make a new key for the parent's quadtree descendant.
        // if this is a geometry diamond, the new intermediate child gets no key.
        int quadrant = -1;

        if ( qa->_orientation == 0 )
        {
            quadrant = 
                qa->q(0) == child ? 2 :
                qa->q(1) == child ? 3 :
                qa->q(2) == child ? 1 : 0;
        }
        else if ( qa->_orientation == 2 )
        {
            quadrant =
                qa->q(0) == child ? 3 :
                qa->q(1) == child ? 1 :
                qa->q(2) == child ? 0 : 2;
        }
        else if ( qa->_orientation == 4 )
        {
            quadrant =
                qa->q(0) == child ? 1 :
                qa->q(1) == child ? 0 :
                qa->q(2) == child ? 2 : 3;
        }
        else // if ( qa->_orientation == 6 )
        {
            quadrant =
                qa->q(0) == child ? 0 :
                qa->q(1) == child ? 2 :
                qa->q(2) == child ? 3 : 1;
        }

        child->_key = qa->_key.createChildKey( quadrant );

        child->_orientation = 
            quadrant == 1 ? 0 :
            quadrant == 0 ? 2 :
            quadrant == 2 ? 4 : 6;
    }

    child->activate();

    return child;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Diamond * Diamond::getOrCreateNeighbor ( ChildIndex  c)

Gets this diamond's neibghor across child-c boundary, creating it if it does not exist

Definition at line 700 of file Diamond.cpp.

{   
    //OE_NOTICE << "Looking up neighbor (" << c << ") of " << _name << std::endl;
    unsigned short parent = c <= 1 ? PARENT_R : PARENT_L;
    ChildIndex myIndexInParent = _a[parent]->getIndexOfChild( this );
    ChildIndex i = ( myIndexInParent + (c==0 || c==2? 1 : 3) ) % _a[parent]->_childValence;
    //if ( !_a[parent]->_c[i].valid() )
    //    OE_NOTICE << "...doesn't exist, creating:" << std::endl;
    return _a[parent]->getOrCreateChild( i );
}

Here is the caller graph for this function:

bool Diamond::hasAllChildren ( ) const

returns true if this diamond is "split", i.e. it has all possible children.

Definition at line 669 of file Diamond.cpp.

{
    for( unsigned short c = 0; c < _childValence; ++c )
    {
        if ( !_c[c].valid() )
            return false;
    }
    return true;
}
bool Diamond::hasChildren ( ) const

returns true is this diamond has at least one child.

Definition at line 658 of file Diamond.cpp.

{
    for( unsigned short c = 0; c < _childValence; ++c )
    {
        if ( _c[c].valid() )
            return true;
    }
    return false;
}
void Diamond::merge ( )

merges a split diamond (and removes all children).

Definition at line 214 of file Diamond.cpp.

{
    // have to remove/merge all the children before we can merge.
    for( ChildIndex c = 0; c < _childValence; ++c )
    {
        if ( _c[c].valid() )
            removeChild( c );
    }
    _isSplit = false;

    if ( _hasGeometry )
    {
        this->dirty();
        _a[QUADTREE]->dirty();
    }
    else
    {
        // for intermediate diamonds, merging means we must rebuild each immediate parent.
        _a[PARENT_L]->dirty();
        _a[PARENT_R]->dirty();
    }

    _queuedForMerge = false;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const MeshNode & Diamond::node ( ) const

Definition at line 90 of file Diamond.cpp.

{
    return _mesh->node( _vi );
}

Here is the call graph for this function:

Here is the caller graph for this function:

Diamond* Diamond::q ( ChildIndex  c) [inline]

access a quadtree decendant

Definition at line 157 of file Diamond.

                                    {
        ChildIndex c2 = c == 0 || c == 2 ? 1 : 3;
        return _c[c].valid() ? _c[c]->_c[c2].get() : 0L;
    }

Here is the caller graph for this function:

void Diamond::refreshDrawable ( )

rebuilds this diamond's draw list if necessary (and updates its precense in the mesh)

Definition at line 496 of file Diamond.cpp.

{
    // the primitive set may have already been refreshed (due to double-parenting)
    if ( !_drawableDirty )
        return;

    // this level does not generate primitive sets
    if ( _level < _mesh->_minGeomLevel )
        return;

    if ( !_hasGeometry )
    {
        OE_WARN << "ILLEGAL: refreshPrimitiveSet called on Diamond at no-geom level " << _level << std::endl;
        return;
    }

    // figure out the subrange transformation.
    osg::Vec2f offset( 0.0, 0.0 );
    double span = 1.0;

    const TileKey& ssaKey = _currentStateSetOwner->_key;
    if ( _level > _currentStateSetOwner->_level ) //_currentStateSetOwner != _targetStateSetOwner )
    {
        span = 1.0/(double)(1 << ((_level-_currentStateSetOwner->_level)/2));
        offset.x() = (_key.getExtent().xMin()-ssaKey.getExtent().xMin())/ssaKey.getExtent().width();
        offset.y() = (_key.getExtent().yMin()-ssaKey.getExtent().yMin())/ssaKey.getExtent().height();
    }

    int o = _orientation;
    
    // Start by clearing out the old primitive set:
    _amrDrawable->_triangles.clear();

    //if ( false ) //!_isSplit ) // took this out to preserve the diamond center point.
    //{
    //    // if the diamond is not split, simply draw the two triangles.
    //    _amrDrawable->add( new AMRTriangle(
    //        _a[GDPARENT]->coord(), _a[GDPARENT]->vert(), offset + OT(T_GDPARENT,o) * span,
    //        _a[QUADTREE]->coord(), _a[QUADTREE]->vert(), offset + OT(T_QUADTREE,o) * span,
    //        _a[PARENT_R]->coord(), _a[PARENT_R]->vert(), offset + OT(T_PARENT_R,o) * span ) );

    //    _amrDrawable->add( new AMRTriangle(
    //        _a[GDPARENT]->coord(), _a[GDPARENT]->vert(), offset + OT(T_GDPARENT,o) * span,
    //        _a[PARENT_L]->coord(), _a[PARENT_L]->vert(), offset + OT(T_PARENT_L,o) * span,
    //        _a[QUADTREE]->coord(), _a[QUADTREE]->vert(), offset + OT(T_QUADTREE,o) * span ) );
    //}
    //else
    {
        // find this diamond's four quadtree descendants:
        Diamond* q0 = _c[0].valid() ? _c[0]->_c[1].get() : 0L;
        Diamond* q1 = _c[1].valid() ? _c[1]->_c[3].get() : 0L;
        Diamond* q2 = _c[2].valid() ? _c[2]->_c[1].get() : 0L;
        Diamond* q3 = _c[3].valid() ? _c[3]->_c[3].get() : 0L;

        osg::Vec2f center = osg::Vec2f(.5,.5);

        if ( !_c[0].valid() || !_c[0]->_isSplit )
        {
            _amrDrawable->add( new AMRTriangle(
                node(),               offset + center * span,
                _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span,
                _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span ) );
        }
        else
        {
            if ( !q0 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span,
                    _c[0]->node(),        offset + OT(T_CHILD_0,o) * span ) );
            }
            if ( !q1 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _c[0]->node(),        offset + OT(T_CHILD_0,o) * span,
                    _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span ) );
            }
        }

        if ( !_c[1].valid() || !_c[1]->_isSplit )
        {
            _amrDrawable->add( new AMRTriangle(
                node(),               offset + center * span,
                _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span,
                _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span ) );
        }
        else
        {
            if ( !q1 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _a[PARENT_R]->node(), offset + OT(T_PARENT_R,o) * span,
                    _c[1]->node(),        offset + OT(T_CHILD_1,o) * span ) );
            }
            if ( !q2 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _c[1]->node(),        offset + OT(T_CHILD_1,o) * span,
                    _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span ) );
            }
        }

        if ( !_c[2].valid() || !_c[2]->_isSplit )
        {
            _amrDrawable->add( new AMRTriangle(
                node(),               offset + center * span,
                _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span,
                _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span ) );
        }
        else
        {
            if ( !q2 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _a[GDPARENT]->node(), offset + OT(T_GDPARENT,o) * span,
                    _c[2]->node(),        offset + OT(T_CHILD_2,o) * span ) );
            }
            if ( !q3 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _c[2]->node(),        offset + OT(T_CHILD_2,o) * span,
                    _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span ) );
            }
        }

        if ( !_c[3].valid() || !_c[3]->_isSplit )
        {
            _amrDrawable->add( new AMRTriangle(
                node(),               offset + center * span,
                _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span,
                _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span ) );
        }
        else
        {
            if ( !q3 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _a[PARENT_L]->node(), offset + OT(T_PARENT_L,o) * span,
                    _c[3]->node(),        offset + OT(T_CHILD_3,o) * span ) );
            }
            if ( !q0 )
            {
                _amrDrawable->add( new AMRTriangle(
                    node(),               offset + center * span,
                    _c[3]->node(),        offset + OT(T_CHILD_3,o) * span,
                    _a[QUADTREE]->node(), offset + OT(T_QUADTREE,o) * span ) );
            }
        }        
    }

    // dirty the underlying element buffer object
    _drawableDirty = false;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::removeChild ( ChildIndex  c)

Removes the child at the specified index.

Definition at line 823 of file Diamond.cpp.

{
    osg::ref_ptr<Diamond> child = _c[c].get();
    if ( !child.valid() ) return;

    // first we must merge the child (i.e. remove all of ITS children recursively).
    // TODO: this probably needs to queue up another merge operation with a higher priority.
    // that should probably happen in the mesh manager.
    child->merge();

    // deactivate the child. it's possible that the child is in a queue somewhere. this
    // will prevent it from being processed after it's been removed.
    child->_status = INACTIVE;

    // remove it from its other parent as well.
    osg::ref_ptr<Diamond> d0 = getNeighbor( c );
    if ( d0.valid() )
    {
        ChildIndex c_d0 = d0->getIndexOfChild( child.get() );
        if ( c_d0 >= 0 )
        {
            d0->_c[c_d0] = 0L;
        }
    }

    // now clear out the child slot and invalidate the primitive set.
    this->_c[c] = 0L;

    // notify the common ancestry of the change
    if ( child->_hasGeometry )
    {
        child->_a[QUADTREE]->dirty();
        this->dirty();
    }
    else
    {
        // probably not strictly necessary since a split() will take care of this.. gw
        child->_a[PARENT_L]->dirty();
        child->_a[PARENT_R]->dirty();
    }

    // zero out the child's ancestor pointers.
    for( AncestorIndex i = 0; i < 4; ++i )
        child->_a[i] = 0L;
    for( ChildIndex i = 0; i < 4; ++i )
        child->_c[i] = 0L;

    // remove the child's vertex from the VBO.
    _mesh->removeNode( child->_vi );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::seed ( Level  maxLevel)

recursively populate the diamond bintree up to a maximum depth level.

Definition at line 162 of file Diamond.cpp.

{
    if ( maxLevel > _level )
    {
        for( ChildIndex c = 0; c < _childValence; ++c )
        {
            getOrCreateChild( c )->seed( maxLevel );
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::setChild ( ChildIndex  index,
Diamond child 
)

assigns a new child to this diamond and invalidates the primitive set.

Definition at line 424 of file Diamond.cpp.

{
    _c[index] = child;

    if ( child->_hasGeometry )
    {
        // if this is a geometry diamond, invalidate the quadtree ancestor so it can include it.
        child->_a[QUADTREE]->dirty();
        child->dirty();
    }
    else
    {
        this->_a[PARENT_L]->dirty();
        this->_a[PARENT_R]->dirty();
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::setCoord ( const osg::Vec3d &  coord)

Definition at line 156 of file Diamond.cpp.

{
    _vi = _mesh->addNode( coord );
}

Here is the call graph for this function:

void Diamond::setCoord ( double  x,
double  y,
double  z 
) [inline]

Sets the diamond centroid coordinate and adds it to the mesh.

Definition at line 104 of file Diamond.

{ setCoord( osg::Vec3d(x,y,z) ); }

Here is the call graph for this function:

Here is the caller graph for this function:

void Diamond::split ( )

splits the diamond (making children possible).

Definition at line 174 of file Diamond.cpp.

{
    // mark as split, and mark the primitive set as needing a refesh:
    _isSplit = true;

    if ( _hasGeometry )
    {
        // for geometry diamonds, a split means we must regenerate this diamond
        // AND its quadtree ancestor.
        this->dirty();
        _a[QUADTREE]->dirty();
    }
    else
    {
        // for intermediate diamonds, splitting means we must rebuild each immediate parent.
        _a[PARENT_L]->dirty();
        _a[PARENT_R]->dirty();
    }

    _queuedForSplit = false;

    // check to see whether any of our neighbors are split. If a neighbor is also
    // split, spawn a common child.
    for( ChildIndex c = 0; c < _childValence; ++c )
    {
        // debugging assertion:
        if ( _c[c].valid() )
        {
            OE_WARN << "ILLEGAL STATE: diamond just split but has kids!" << std::endl;
        }

        Diamond* d0 = getNeighbor( c );
        if ( d0 && d0->_isSplit )
        {
            getOrCreateChild( c );
        }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

const osg::BoundingSphere & Diamond::visibleBound ( ) const

Definition at line 390 of file Diamond.cpp.

{
    if ( !_bsComputed )
        const_cast<Diamond*>(this)->computeBound();
    return _visibleBound;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

osg::ref_ptr<Diamond> Diamond::_a[4]

Definition at line 70 of file Diamond.

Definition at line 84 of file Diamond.

Definition at line 81 of file Diamond.

osg::ref_ptr<Diamond> Diamond::_c[4]

Definition at line 71 of file Diamond.

unsigned short Diamond::_childValence

Definition at line 72 of file Diamond.

Definition at line 86 of file Diamond.

Definition at line 77 of file Diamond.

osg::BoundingSphere Diamond::_extendedBound

Definition at line 93 of file Diamond.

Definition at line 88 of file Diamond.

Definition at line 74 of file Diamond.

Definition at line 96 of file Diamond.

Definition at line 82 of file Diamond.

Definition at line 73 of file Diamond.

Definition at line 64 of file Diamond.

Definition at line 76 of file Diamond.

Definition at line 66 of file Diamond.

Definition at line 69 of file Diamond.

std::string Diamond::_name

Definition at line 65 of file Diamond.

Definition at line 67 of file Diamond.

Definition at line 80 of file Diamond.

Definition at line 79 of file Diamond.

Definition at line 78 of file Diamond.

Definition at line 83 of file Diamond.

Definition at line 68 of file Diamond.

Definition at line 85 of file Diamond.

Definition at line 87 of file Diamond.

Definition at line 75 of file Diamond.

osg::BoundingSphere Diamond::_visibleBound

Definition at line 90 of file Diamond.


The documentation for this struct was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines