osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_osgterrain/SinglePassTerrainTechnique.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 "SinglePassTerrainTechnique"
00020 #include "Terrain"
00021 #include "Tile"
00022 
00023 #include <osgEarth/Cube>
00024 #include <osgEarth/ImageUtils>
00025 
00026 #include <osg/Point>
00027 #include <osg/Program>
00028 #include <osg/io_utils>
00029 #include <osg/StateSet>
00030 #include <osg/Program>
00031 #include <osg/Math>
00032 #include <osg/Timer>
00033 #include <osg/Version>
00034 #include <osgUtil/Tessellator>
00035 #include <osgUtil/SmoothingVisitor>
00036 
00037 #include <osgEarthSymbology/Geometry>
00038 #include <osgEarthSymbology/MeshConsolidator>
00039 
00040 #include <sstream>
00041 
00042 using namespace osgEarth;
00043 using namespace osgEarth::Symbology;
00044 using namespace OpenThreads;
00045 
00046 #define LC "[SinglePassTechnique] "
00047 
00048 #define MATCH_TOLERANCE 0.000001
00049 
00050 // --------------------------------------------------------------------------
00051 
00052 namespace
00053 {
00054   struct MaskRecord
00055   {
00056     osg::ref_ptr<osg::Vec3dArray> _boundary;
00057     osg::Vec3d _ndcMin, _ndcMax;
00058     osg::Geometry* _geom;
00059 
00060     MaskRecord(osg::Vec3dArray* boundary, osg::Vec3d& ndcMin, osg::Vec3d& ndcMax, osg::Geometry* geom) : _boundary(boundary), _ndcMin(ndcMin), _ndcMax(ndcMax), _geom(geom) { }
00061   };
00062 
00063   typedef std::vector<MaskRecord> MaskRecordVector;
00064 }
00065 
00066 // --------------------------------------------------------------------------
00067 
00068 SinglePassTerrainTechnique::SinglePassTerrainTechnique( TextureCompositor* compositor ) :
00069 CustomTerrainTechnique(),
00070 _verticalScaleOverride(1.0f),
00071 _initCount(0),
00072 _pendingFullUpdate( false ),
00073 _pendingGeometryUpdate(false),
00074 _optimizeTriangleOrientation(true),
00075 _texCompositor( compositor ),
00076 _frontGeodeInstalled( false ),
00077 _debug( false )
00078 {
00079     this->setThreadSafeRefUnref(true);
00080 }
00081 
00082 SinglePassTerrainTechnique::SinglePassTerrainTechnique(const SinglePassTerrainTechnique& rhs, const osg::CopyOp& copyop):
00083 CustomTerrainTechnique( rhs, copyop ),
00084 _verticalScaleOverride( rhs._verticalScaleOverride ),
00085 _initCount( 0 ),
00086 _pendingFullUpdate( false ),
00087 _pendingGeometryUpdate( false ),
00088 _optimizeTriangleOrientation( rhs._optimizeTriangleOrientation ),
00089 _texCompositor( rhs._texCompositor.get() ),
00090 _frontGeodeInstalled( rhs._frontGeodeInstalled ),
00091 _debug( rhs._debug ),
00092 _parentTile( rhs._parentTile )
00093 {
00094     //NOP
00095 }
00096 
00097 SinglePassTerrainTechnique::~SinglePassTerrainTechnique()
00098 {
00099     //nop
00100 }
00101 
00102 void
00103 SinglePassTerrainTechnique::setVerticalScaleOverride( float value )
00104 {
00105     _verticalScaleOverride = value;
00106 }
00107 
00108 float
00109 SinglePassTerrainTechnique::getVerticalScaleOverride() const 
00110 {
00111     return _verticalScaleOverride;
00112 }
00113 
00114 void
00115 SinglePassTerrainTechnique::setOptimizeTriangleOrientation(bool optimizeTriangleOrientation)
00116 {
00117     _optimizeTriangleOrientation = optimizeTriangleOrientation;
00118 }
00119 
00120 bool
00121 SinglePassTerrainTechnique::getOptimizeTriangleOrientation() const
00122 {
00123     return _optimizeTriangleOrientation;
00124 }
00125 
00126 void 
00127 SinglePassTerrainTechnique::init()
00128 {
00129     compile( TileUpdate(TileUpdate::UPDATE_ALL), 0L );
00130     applyTileUpdates();
00131 }
00132 
00133 void
00134 SinglePassTerrainTechnique::compile( const TileUpdate& update, ProgressCallback* progress )
00135 {
00136     // safety check
00137     if ( !_tile ) 
00138     {
00139         OE_WARN << LC << "Illegal; terrain tile is null" << std::endl;
00140         return;
00141     }
00142 
00143     //if ( _debug )
00144     //{
00145     //    OE_NOTICE << LC << "compile() " << std::endl;
00146     //}
00147 
00148     // serialize access to the compilation procedure.
00149     OpenThreads::ScopedLock<Mutex> exclusiveLock( _compileMutex );
00150     
00151     // make a frame to use during compilation.
00152     TileFrame tilef( _tile );
00153 
00154     // establish the master tile locator if this is the first compilation:
00155     if ( !_masterLocator.valid() || !_transform.valid() )
00156     {
00157         _masterLocator = static_cast<GeoLocator*>( tilef._locator.get() );
00158         _masterLocator->convertLocalToModel( osg::Vec3(.5,.5,0), _centerModel );
00159 
00160         _transform = new osg::MatrixTransform( osg::Matrix::translate(_centerModel) );
00161         // this is a placeholder so that we can always just call setChild(0) later.
00162         _transform->addChild( new osg::Group );
00163     }
00164 
00165     // see whether a full update is required.
00166     bool partialUpdateOK = _texCompositor->supportsLayerUpdate() && _frontGeodeInstalled;
00167 
00168     // handle image layer addition or update:
00169     if (partialUpdateOK && 
00170         ( update.getAction() == TileUpdate::ADD_IMAGE_LAYER || update.getAction() == TileUpdate::UPDATE_IMAGE_LAYER ))
00171     {
00172         prepareImageLayerUpdate( update.getLayerUID(), tilef );
00173 
00174         // conditionally regenerate the texture coordinates for this layer.
00175         // TODO: optimize this with a method that ONLY regenerates the texture coordinates.
00176         if ( !_texCompositor->requiresUnitTextureSpace() )
00177         {
00178             osg::ref_ptr<osg::StateSet> stateSet = _backGeode.valid() ? _backGeode->getStateSet() : 0L;
00179             _backGeode = createGeometry( tilef );
00180             _backGeode->setStateSet( stateSet.get() );
00181 
00182             _pendingGeometryUpdate = true;
00183         }
00184     }
00185 
00186     else if (partialUpdateOK && update.getAction() == TileUpdate::MOVE_IMAGE_LAYER )
00187     {
00188         //nop - layer re-ordering happens entirely in the texture compositor.
00189     }
00190 
00191     //TODO: we should not need to check supportsLayerUpdate here, but it is not working properly in
00192     // multitexture mode (white tiles show up). Need to investigate and fix.
00193     else if ( partialUpdateOK && update.getAction() == TileUpdate::UPDATE_ELEVATION )
00194     {
00195         osg::ref_ptr<osg::StateSet> stateSet = _backGeode.valid() ? _backGeode->getStateSet() : 0L;
00196         _backGeode = createGeometry( tilef );
00197         _backGeode->setStateSet( stateSet.get() );
00198 
00199         _pendingGeometryUpdate = true;
00200     }
00201 
00202     else // all other update types
00203     {
00204         // give the engine a chance to bail out before generating geometry
00205         if ( progress && progress->isCanceled() )
00206         {
00207             _backGeode = 0L;
00208             return;
00209         }
00210     
00211         // create the geometry and texture coordinates for this tile in a new buffer
00212         _backGeode = createGeometry( tilef );
00213         if ( !_backGeode.valid() )
00214         {
00215             OE_WARN << LC << "createGeometry returned NULL" << std::endl;
00216             return;
00217         }
00218 
00219         // give the engine a chance to bail out before building the texture stateset:
00220         if ( progress && progress->isCanceled() )
00221         {
00222             _backGeode = 0L;
00223             return;
00224         }
00225 
00226         // create the stateset for this tile, which contains all the texture information.
00227         osg::StateSet* stateSet = createStateSet( tilef );
00228         if ( stateSet )
00229         {
00230             _backGeode->setStateSet( stateSet );
00231         }
00232 
00233         // give the engine a chance to bail out before swapping buffers
00234         if ( progress && progress->isCanceled() )
00235         {
00236             _backGeode = 0L;
00237             return;
00238         }
00239        
00240         _initCount++;
00241         if ( _initCount > 1 )
00242             OE_WARN << LC << "Tile was fully build " << _initCount << " times" << std::endl;
00243 
00244         if ( _backGeode.valid() && !_backGeode->getStateSet() )
00245             OE_WARN << LC << "ILLEGAL! no stateset in BackGeode!!" << std::endl;
00246 
00247         _pendingFullUpdate = true;
00248     }
00249 }
00250 
00251 // from the UPDATE traversal thread:
00252 bool
00253 SinglePassTerrainTechnique::applyTileUpdates()
00254 {
00255     bool applied = false;
00256 
00257     // serialize access to the compilation mechanism.
00258     OpenThreads::ScopedLock<Mutex> exclusiveLock( _compileMutex );
00259 
00260     // process a pending buffer swap:
00261     if ( _pendingFullUpdate )
00262     {
00263         if ( _backGeode->getStateSet() == 0L )
00264             OE_WARN << LC << "ILLEGAL: backGeode has no stateset" << std::endl;
00265 
00266         _transform->setChild( 0, _backGeode.get() );
00267         _frontGeodeInstalled = true;
00268         _backGeode = 0L;
00269         _pendingFullUpdate = false;
00270         _pendingGeometryUpdate = false;
00271         applied = true;
00272     }
00273 
00274     else
00275     {
00276         // process any pending LIVE geometry updates:
00277         if ( _pendingGeometryUpdate )
00278         {
00279             osg::Geode* frontGeode = getFrontGeode();
00280 
00281             if (frontGeode)
00282             {
00283 
00284                 if ( _texCompositor->requiresUnitTextureSpace() )
00285                 {
00286                     // in "unit-texture-space" mode, we can take the shortcut of just updating
00287                     // the geometry VBOs. The texture coordinates never change.
00288                     for( unsigned int i=0; i<_backGeode->getNumDrawables(); ++i )
00289                     {
00290                         osg::Geometry* backGeom = static_cast<osg::Geometry*>( _backGeode->getDrawable(i) );
00291                         osg::Vec3Array* backVerts = static_cast<osg::Vec3Array*>( backGeom->getVertexArray() );
00292 
00293                         osg::Geometry* frontGeom = static_cast<osg::Geometry*>( frontGeode->getDrawable(i) );
00294                         osg::Vec3Array* frontVerts = static_cast<osg::Vec3Array*>( frontGeom->getVertexArray() );
00295 
00296                         if ( backVerts->size() == frontVerts->size() )
00297                         {
00298                             // simple VBO update:
00299                             std::copy( backVerts->begin(), backVerts->end(), frontVerts->begin() );
00300                             frontVerts->dirty();
00301 
00302                             osg::Vec3Array* backNormals = static_cast<osg::Vec3Array*>( backGeom->getNormalArray() );
00303                             if ( backNormals )
00304                             {
00305                                 osg::Vec3Array* frontNormals = static_cast<osg::Vec3Array*>( frontGeom->getNormalArray() );
00306                                 std::copy( backNormals->begin(), backNormals->end(), frontNormals->begin() );
00307                                 frontNormals->dirty();
00308                             }
00309 
00310                             osg::Vec2Array* backTexCoords = static_cast<osg::Vec2Array*>( backGeom->getTexCoordArray(0) );
00311                             if ( backTexCoords )
00312                             {
00313                                 osg::Vec2Array* frontTexCoords = static_cast<osg::Vec2Array*>( frontGeom->getTexCoordArray(0) );
00314                                 std::copy( backTexCoords->begin(), backTexCoords->end(), frontTexCoords->begin() );
00315                                 frontTexCoords->dirty();
00316                             }
00317                         }
00318                         else
00319                         {
00320                             frontGeom->setVertexArray( backVerts );
00321                             frontGeom->setTexCoordArray( 0, backGeom->getTexCoordArray( 0 ) ); // TODO: un-hard-code
00322                             if ( backGeom->getNormalArray() )
00323                                 frontGeom->setNormalArray( backGeom->getNormalArray() );
00324                         }
00325                     }
00326                 }
00327                 else
00328                 {
00329                     // copy the drawables from the back buffer to the front buffer. By doing this,
00330                     // we don't touch the front geode's stateset (which contains the textures) and
00331                     // therefore they don't get re-applied.
00332                     for( unsigned int i=0; i<_backGeode->getNumDrawables(); ++i )
00333                     {
00334                         frontGeode->setDrawable( i, _backGeode->getDrawable( i ) );
00335                     }
00336                 }
00337             }
00338 
00339             _pendingGeometryUpdate = false;
00340             _backGeode = 0L;
00341             applied = true;
00342         }
00343 
00344         // process any pending LIVE per-layer updates:
00345         osg::StateSet* parentStateSet = 0;
00346 
00347         if ( !_pendingImageLayerUpdates.empty() )
00348         {
00349             parentStateSet = getParentStateSet();
00350         }
00351 
00352         while( _pendingImageLayerUpdates.size() > 0 )
00353         {
00354             const ImageLayerUpdate& update = _pendingImageLayerUpdates.front();
00355 
00356             osg::ref_ptr< osg::Geode > frontGeode = getFrontGeode();
00357             if (frontGeode.valid())
00358             {
00359                 _texCompositor->applyLayerUpdate(
00360                     frontGeode->getStateSet(),
00361                     update._layerUID,
00362                     update._image,
00363                     _tileKey,
00364                     update._isRealData ? parentStateSet : 0L );
00365             }
00366 
00367             _pendingImageLayerUpdates.pop();
00368             applied = true;
00369 
00370         }
00371     }
00372 
00373     if ( _debug )
00374     {
00375         OE_NOTICE << "applyTileUpdates()" << std::endl;
00376     }
00377 
00378     return applied;
00379 }
00380 
00381 void
00382 SinglePassTerrainTechnique::prepareImageLayerUpdate( UID layerUID, const TileFrame& tilef )
00383 {
00384     CustomColorLayer layer;
00385     if ( tilef.getCustomColorLayer( layerUID, layer ) )
00386     {
00387         GeoImage geoImage, secondaryImage;
00388 
00389         if ( createGeoImage( layer, geoImage ) )
00390         {
00391             ImageLayerUpdate update;
00392             
00393             update._image = _texCompositor->prepareImage( geoImage, _tileExtent );
00394             update._layerUID = layerUID;
00395             update._isRealData = !layer.isFallbackData();
00396 
00397             if ( update._image.valid() )
00398                 _pendingImageLayerUpdates.push( update );
00399         }
00400 
00401     }
00402 }
00403 
00404 bool
00405 SinglePassTerrainTechnique::createGeoImage( const CustomColorLayer& colorLayer,
00406                                             GeoImage& image) const
00407 {
00408     osg::ref_ptr<const GeoLocator> layerLocator = dynamic_cast<const GeoLocator*>( colorLayer.getLocator() );
00409     if ( layerLocator.valid() )
00410     {
00411         if ( layerLocator->getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC )
00412             layerLocator = layerLocator->getGeographicFromGeocentric();
00413 
00414         const GeoExtent& imageExtent = layerLocator->getDataExtent();
00415         image = GeoImage( colorLayer.getImage(), imageExtent ); //const_cast<osg::Image*>(colorLayer.getImage()), imageExtent );
00416         return true;
00417     }
00418     return false;
00419 }
00420 
00421 osg::StateSet*
00422 SinglePassTerrainTechnique::getActiveStateSet() const
00423 {
00424     OpenThreads::ScopedLock<Mutex> exclusiveLock( const_cast<SinglePassTerrainTechnique*>(this)->_compileMutex );
00425 
00426     osg::StateSet* result = 0L;
00427     osg::Geode* front = getFrontGeode();
00428     if ( front ) 
00429         result = front->getStateSet();
00430     if ( !result && _backGeode.valid() )
00431         result = _backGeode->getStateSet();
00432 
00433     return result;
00434 }
00435 
00436 osg::StateSet*
00437 SinglePassTerrainTechnique::getParentStateSet() const
00438 {
00439     osg::StateSet* parentStateSet = 0;
00440     osg::ref_ptr<Tile> parentTile_safe = _parentTile.get();
00441     if ( parentTile_safe.valid() )
00442     {
00443         return static_cast<SinglePassTerrainTechnique*>(_parentTile->getTerrainTechnique())->getActiveStateSet();
00444     }
00445     else return 0L;
00446 }
00447 
00448 osg::StateSet*
00449 SinglePassTerrainTechnique::createStateSet( const TileFrame& tilef )
00450 {
00451     // establish the tile extent. we will calculate texture coordinate offset/scale based on this
00452     if ( !_tileExtent.isValid() )
00453     {
00454         osg::ref_ptr<GeoLocator> tileLocator = dynamic_cast<GeoLocator*>( tilef._locator.get() ); // _terrainTile->getLocator() );
00455         if ( tileLocator.valid() )
00456         {
00457             if ( tileLocator->getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC )
00458                 tileLocator = tileLocator->getGeographicFromGeocentric();
00459 
00460             _tileExtent = tileLocator->getDataExtent();
00461         }
00462         _tileKey = tilef._tileKey;
00463     }
00464 
00465     osg::StateSet* stateSet = new osg::StateSet();
00466     osg::StateSet* parentStateSet = getParentStateSet();
00467 
00468     for( ColorLayersByUID::const_iterator i = tilef._colorLayers.begin(); i != tilef._colorLayers.end(); ++i )
00469     {
00470         const CustomColorLayer& colorLayer = i->second;
00471 
00472         bool isRealData = !colorLayer.isFallbackData();
00473 
00474         GeoImage image;
00475         if ( createGeoImage( colorLayer, image ) )
00476         {
00477             image = _texCompositor->prepareImage( image, _tileExtent );
00478 
00479             _texCompositor->applyLayerUpdate( 
00480                 stateSet, 
00481                 colorLayer.getUID(), 
00482                 image, 
00483                 _tileKey, 
00484                 isRealData ? parentStateSet : 0L );
00485         }
00486     }
00487 
00488     return stateSet;
00489 }
00490 
00491 void
00492 SinglePassTerrainTechnique::calculateSampling( unsigned int& out_rows, unsigned int& out_cols, double& out_i, double& out_j )
00493 {            
00494     osgTerrain::Layer* elevationLayer = _tile->getElevationLayer();
00495 
00496     out_rows = elevationLayer->getNumRows();
00497     out_cols = elevationLayer->getNumColumns();
00498     out_i = 1.0;
00499     out_j = 1.0;
00500 
00501     float sampleRatio = _tile->getTerrain() ? _tile->getTerrain()->getSampleRatio() : 1.0f;
00502     if ( sampleRatio != 1.0f )
00503     {
00504         unsigned int originalNumColumns = out_cols;
00505         unsigned int originalNumRows = out_rows;
00506 
00507         out_cols = osg::maximum((unsigned int) (float(originalNumColumns)*sqrtf(sampleRatio)), 4u);
00508         out_rows = osg::maximum((unsigned int) (float(originalNumRows)*sqrtf(sampleRatio)),4u);
00509 
00510         out_i = double(originalNumColumns-1)/double(out_cols-1);
00511         out_j = double(originalNumRows-1)/double(out_rows-1);
00512     }
00513 }
00514 
00515 namespace
00516 {
00517     struct GeoLocatorComp
00518     {
00519         bool operator()( const GeoLocator* lhs, const GeoLocator* rhs ) const
00520         {
00521             return rhs && lhs && lhs->isEquivalentTo( *rhs );
00522         }
00523     };
00524 
00525     typedef std::pair< const GeoLocator*, osg::Vec2Array* > LocatorTexCoordPair;
00526 
00527     struct LocatorToTexCoordTable : public std::list<LocatorTexCoordPair> {
00528         osg::Vec2Array* find( const GeoLocator* key ) const {
00529             for( const_iterator i = begin(); i != end(); ++i ) {
00530                 if ( i->first->isEquivalentTo( *key ) )
00531                     return i->second;
00532             }
00533             return 0L;
00534         }
00535     };
00536     
00537     struct RenderLayer {
00538         CustomColorLayer _layer;
00539         osg::ref_ptr<const GeoLocator> _locator;
00540         osg::ref_ptr<osg::Vec2Array> _texCoords;
00541         osg::ref_ptr<osg::Vec2Array> _skirtTexCoords;
00542         osg::ref_ptr<osg::Vec2Array> _stitchTexCoords;
00543         osg::ref_ptr<osg::Vec2Array> _stitchSkirtTexCoords;
00544         bool _ownsTexCoords;
00545         RenderLayer() : _ownsTexCoords(false) { }
00546     };
00547 
00548     typedef std::vector< RenderLayer > RenderLayerVector;
00549 }
00550 
00551 osg::Geode*
00552 SinglePassTerrainTechnique::createGeometry( const TileFrame& tilef )
00553 {
00554     osg::ref_ptr<GeoLocator> masterTextureLocator = _masterLocator.get();
00555     //GeoLocator* geoMasterLocator = dynamic_cast<GeoLocator*>(_masterLocator.get());
00556 
00557         bool isCube = dynamic_cast<CubeFaceLocator*>(_masterLocator.get()) != NULL;
00558 
00559     // If we have a geocentric locator, get a geographic version of it to avoid converting
00560     // to/from geocentric when computing texture coordinats
00561     if (!isCube && /*geoMasterLocator && */ _masterLocator->getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC)
00562     {
00563         masterTextureLocator = masterTextureLocator->getGeographicFromGeocentric();
00564     }
00565     
00566     osgTerrain::Layer* elevationLayer = _tile->getElevationLayer();
00567 
00568     // fire up a brand new geode.
00569     osg::Geode* geode = new osg::Geode();
00570     geode->setThreadSafeRefUnref(true);
00571     
00572     // setting the geometry to DYNAMIC means its draw will not overlap the next frame's update/cull
00573     // traversal - which could access the buffer without a mutex
00574 
00575     osg::Geometry* surface = new osg::Geometry();
00576     surface->setThreadSafeRefUnref(true); // TODO: probably unnecessary.
00577     surface->setDataVariance( osg::Object::DYNAMIC );
00578     surface->setUseDisplayList(false);
00579     surface->setUseVertexBufferObjects(true);
00580     geode->addDrawable( surface );
00581 
00582     osg::Geometry* skirt = new osg::Geometry();
00583     skirt->setThreadSafeRefUnref(true); // TODO: probably unnecessary.
00584     skirt->setDataVariance( osg::Object::DYNAMIC );
00585     skirt->setUseDisplayList(false);
00586     skirt->setUseVertexBufferObjects(true);
00587     geode->addDrawable( skirt );
00588 
00589         osg::ref_ptr<GeoLocator> geoLocator = _masterLocator;
00590         // Avoid coordinates conversion when GEOCENTRIC, so get a GEOGRAPHIC version of Locator 
00591         if (_masterLocator->getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC) {
00592                 geoLocator = _masterLocator->getGeographicFromGeocentric();
00593         }
00594 
00595         float scaleHeight = 
00596                 _verticalScaleOverride != 1.0? _verticalScaleOverride :
00597                 _tile->getTerrain() ? _tile->getTerrain()->getVerticalScale() :
00598                 1.0f;
00599 
00600     MaskRecordVector masks;
00601     for (MaskLayerVector::const_iterator it = tilef._masks.begin(); it != tilef._masks.end(); ++it)
00602     {
00603           // When displaying Plate Carre, Heights have to be converted from meters to degrees.
00604           // This is also true for mask feature
00605           // TODO: adjust this calculation based on the actual EllipsoidModel.
00606           float scale = scaleHeight;
00607           if (_masterLocator->getCoordinateSystemType() == osgEarth::GeoLocator::GEOGRAPHIC)
00608                 scale = scaleHeight / 111319.0f;
00609 
00610           // TODO: Get the map SRS if possible instead of masterLocator's one
00611           osg::Vec3dArray* boundary = (*it)->getOrCreateBoundary(scale, _masterLocator->getDataExtent().getSRS());
00612 
00613       if ( boundary )
00614       {
00615           osg::Vec3d min, max;
00616           min = max = boundary->front();
00617 
00618           for (osg::Vec3dArray::iterator it = boundary->begin(); it != boundary->end(); ++it)
00619           {
00620             if (it->x() < min.x())
00621               min.x() = it->x();
00622 
00623             if (it->y() < min.y())
00624               min.y() = it->y();
00625 
00626             if (it->x() > max.x())
00627               max.x() = it->x();
00628 
00629             if (it->y() > max.y())
00630               max.y() = it->y();
00631           }
00632 
00633           osg::Vec3d min_ndc, max_ndc;
00634           geoLocator->convertModelToLocal(min, min_ndc);
00635           geoLocator->convertModelToLocal(max, max_ndc);
00636 
00637           bool x_match = ((min_ndc.x() >= 0.0 && max_ndc.x() <= 1.0) ||
00638                           (min_ndc.x() <= 0.0 && max_ndc.x() > 0.0) ||
00639                           (min_ndc.x() < 1.0 && max_ndc.x() >= 1.0));
00640 
00641           bool y_match = ((min_ndc.y() >= 0.0 && max_ndc.y() <= 1.0) ||
00642                           (min_ndc.y() <= 0.0 && max_ndc.y() > 0.0) ||
00643                           (min_ndc.y() < 1.0 && max_ndc.y() >= 1.0));
00644 
00645           if (x_match && y_match)
00646           {
00647             osg::Geometry* mask_geom = new osg::Geometry();
00648             mask_geom->setThreadSafeRefUnref(true);
00649             mask_geom->setDataVariance( osg::Object::DYNAMIC );
00650             mask_geom->setUseDisplayList(false);
00651             mask_geom->setUseVertexBufferObjects(true);
00652             //mask_geom->getOrCreateStateSet()->setAttribute(new osg::Point( 5.0f ), osg::StateAttribute::ON);
00653             geode->addDrawable(mask_geom);
00654 
00655             masks.push_back(MaskRecord(boundary, min_ndc, max_ndc, mask_geom));
00656           }
00657        }
00658     }
00659 
00660     osg::Geometry* stitching_skirts = 0L;
00661     osg::Vec3Array* ss_verts = 0L;
00662     if (masks.size() > 0)
00663     {
00664       stitching_skirts = new osg::Geometry();
00665       stitching_skirts->setThreadSafeRefUnref(true);
00666       stitching_skirts->setDataVariance( osg::Object::DYNAMIC );
00667       stitching_skirts->setUseDisplayList(false);
00668       stitching_skirts->setUseVertexBufferObjects(true);
00669       //stitching_skirts->getOrCreateStateSet()->setAttribute(new osg::Point( 5.0f ), osg::StateAttribute::ON);
00670       geode->addDrawable( stitching_skirts);
00671 
00672       ss_verts = new osg::Vec3Array();
00673       stitching_skirts->setVertexArray(ss_verts);
00674     }
00675 
00676 
00677     unsigned int numRows = 20;
00678     unsigned int numColumns = 20;
00679     
00680     if (elevationLayer)
00681     {
00682         numColumns = elevationLayer->getNumColumns();
00683         numRows = elevationLayer->getNumRows();
00684     }
00685     
00686     double i_sampleFactor, j_sampleFactor;
00687     calculateSampling( numColumns, numRows, i_sampleFactor, j_sampleFactor );
00688     
00689     float skirtHeight = 0.0f;
00690     osgTerrain::HeightFieldLayer* hfl = dynamic_cast<osgTerrain::HeightFieldLayer*>(elevationLayer);
00691     if (hfl && hfl->getHeightField()) 
00692     {
00693         skirtHeight = hfl->getHeightField()->getSkirtHeight();
00694     }
00695     
00696     bool createSkirt = skirtHeight != 0.0f;
00697   
00698     unsigned int numVerticesInSurface = numColumns*numRows;
00699     unsigned int numVerticesInSkirt = createSkirt ? (2 * (numColumns*2 + numRows*2 - 4)) : 0;
00700     //unsigned int numVertices = numVerticesInBody+numVerticesInSkirt;
00701 
00702     // allocate and assign vertices
00703     osg::ref_ptr<osg::Vec3Array> surfaceVerts = new osg::Vec3Array;
00704     surfaceVerts->reserve( numVerticesInSurface );
00705     surface->setVertexArray( surfaceVerts.get() );
00706 
00707     // allocate and assign normals
00708     osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array();
00709     normals->reserve(numVerticesInSurface);
00710     surface->setNormalArray(normals.get());
00711     surface->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
00712 
00713     // skirt texture coordinates, if applicable:
00714     osg::Vec2Array* unifiedSkirtTexCoords = 0L;
00715 
00716     // stitching skirt texture coordinates, if applicable:
00717     osg::Vec2Array* unifiedStitchSkirtTexCoords = 0L;
00718 
00719     // allocate and assign texture coordinates
00720     osg::Vec2Array* unifiedSurfaceTexCoords = 0L;
00721 
00722     //int numColorLayers = _tile->getNumColorLayers();
00723     RenderLayerVector renderLayers;
00724 
00725     if ( _texCompositor->requiresUnitTextureSpace() )
00726     {
00727         // for a unified unit texture space, just make a single texture coordinate array.
00728         unifiedSurfaceTexCoords = new osg::Vec2Array();
00729         unifiedSurfaceTexCoords->reserve( numVerticesInSurface );
00730         surface->setTexCoordArray( 0, unifiedSurfaceTexCoords );
00731         if (createSkirt)
00732         {
00733             unifiedSkirtTexCoords = new osg::Vec2Array();
00734             unifiedSkirtTexCoords->reserve( numVerticesInSkirt );        
00735             skirt->setTexCoordArray( 0, unifiedSkirtTexCoords );
00736         }
00737 
00738         if (masks.size() > 0)
00739         {
00740             unifiedStitchSkirtTexCoords = new osg::Vec2Array();
00741             //unifiedStitchSkirtTexCoords->reserve( ? );        
00742             stitching_skirts->setTexCoordArray( 0, unifiedStitchSkirtTexCoords );
00743         }
00744     }
00745 
00746     else // if ( !_texCompositor->requiresUnitTextureSpace() )
00747     {
00748         LocatorToTexCoordTable locatorToTexCoordTable;
00749         renderLayers.reserve( tilef._colorLayers.size() );
00750 
00751         // build a list of "render layers", in slot order, sharing texture coordinate
00752         // arrays wherever possible.
00753         for( ColorLayersByUID::const_iterator i = tilef._colorLayers.begin(); i != tilef._colorLayers.end(); ++i )
00754         {
00755             const CustomColorLayer& colorLayer = i->second;
00756             RenderLayer r;
00757             r._layer = colorLayer;
00758 
00759             const GeoLocator* locator = dynamic_cast<const GeoLocator*>( r._layer.getLocator() );
00760             if ( locator )
00761             {
00762                 r._texCoords = locatorToTexCoordTable.find( locator );
00763                 if ( !r._texCoords.valid() )
00764                 {
00765                     r._texCoords = new osg::Vec2Array();
00766                     r._texCoords->reserve( numVerticesInSurface );
00767                     r._ownsTexCoords = true;
00768                     locatorToTexCoordTable.push_back( LocatorTexCoordPair(locator, r._texCoords.get()) );
00769                 }
00770 
00771                 r._skirtTexCoords = new osg::Vec2Array();
00772                 r._skirtTexCoords->reserve( numVerticesInSkirt );
00773 
00774                 if ( masks.size() > 0 )
00775                 {
00776                     r._stitchTexCoords = new osg::Vec2Array();
00777                     r._stitchSkirtTexCoords = new osg::Vec2Array();
00778                 }
00779 
00780                 r._locator = locator;
00781                 if ( locator->getCoordinateSystemType() == osgTerrain::Locator::GEOCENTRIC )
00782                 {
00783                     const GeoLocator* geo = dynamic_cast<const GeoLocator*>(locator);
00784                     if ( geo )
00785                         r._locator = geo->getGeographicFromGeocentric();
00786                 }
00787 
00788                 _texCompositor->assignTexCoordArray( surface, colorLayer.getUID(), r._texCoords.get() );
00789                 _texCompositor->assignTexCoordArray( skirt, colorLayer.getUID(), r._skirtTexCoords.get() );
00790 
00791                 for (MaskRecordVector::iterator mr = masks.begin(); mr != masks.end(); ++mr)
00792                     _texCompositor->assignTexCoordArray( (*mr)._geom, colorLayer.getUID(), r._stitchTexCoords.get() );
00793 
00794                 if (stitching_skirts)
00795                     _texCompositor->assignTexCoordArray( stitching_skirts, colorLayer.getUID(), r._stitchSkirtTexCoords.get() );
00796 
00797                 //surface->setTexCoordArray( renderLayers.size(), r._texCoords );
00798                 renderLayers.push_back( r );
00799             }
00800             else
00801             {
00802                 OE_WARN << LC << "Found a Locator, but it wasn't a GeoLocator." << std::endl;
00803             }
00804         }
00805     }
00806 
00807     osg::ref_ptr<osg::FloatArray> elevations = new osg::FloatArray;
00808     if (elevations.valid()) elevations->reserve(numVerticesInSurface);        
00809 
00810     // allocate and assign color
00811     osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(1);
00812     (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);
00813     
00814     surface->setColorArray(colors.get());
00815     surface->setColorBinding(osg::Geometry::BIND_OVERALL);
00816 
00817     typedef std::vector<int> Indices;
00818     Indices indices(numVerticesInSurface, -1);    
00819 
00820     // populate vertex and tex coord arrays    
00821     unsigned int i, j; //, k=0;
00822     for(j=0; j<numRows; ++j)
00823     {
00824         for(i=0; i<numColumns; ++i) // ++k)
00825         {
00826             unsigned int iv = j*numColumns + i;
00827             osg::Vec3d ndc( ((double)i)/(double)(numColumns-1), ((double)j)/(double)(numRows-1), 0.0);
00828      
00829             bool validValue = true;
00830             
00831             unsigned int i_equiv = i_sampleFactor==1.0 ? i : (unsigned int) (double(i)*i_sampleFactor);
00832 
00833             unsigned int j_equiv = j_sampleFactor==1.0 ? j : (unsigned int) (double(j)*j_sampleFactor);
00834 
00835             if (elevationLayer)
00836             {
00837                 float value = 0.0f;
00838                 validValue = elevationLayer->getValidValue(i_equiv,j_equiv, value);
00839                 ndc.z() = value*scaleHeight;
00840             }
00841 
00842             //Invalidate if point falls within mask bounding box
00843             if (validValue && masks.size() > 0)
00844             {
00845               for (MaskRecordVector::iterator mr = masks.begin(); mr != masks.end(); ++mr)
00846               {
00847                 if(ndc.x() >= (*mr)._ndcMin.x() && ndc.x() <= (*mr)._ndcMax.x() &&
00848                    ndc.y() >= (*mr)._ndcMin.y() && ndc.y() <= (*mr)._ndcMax.y())
00849                 {
00850                   validValue = false;
00851                   indices[iv] = -2;
00852                   break;
00853                 }
00854               }
00855             }
00856             
00857             if (validValue)
00858             {
00859                 //indices[iv] = k;
00860                 indices[iv] = surfaceVerts->size();
00861             
00862                 osg::Vec3d model;
00863                 _masterLocator->convertLocalToModel(ndc, model);
00864 
00865                 //(*surfaceVerts)[k] = model - centerModel;
00866                 (*surfaceVerts).push_back(model - _centerModel);
00867 
00868                 if ( _texCompositor->requiresUnitTextureSpace() )
00869                 {
00870                     // the unified unit texture space requires a single, untransformed unit coord [0..1]
00871                     (*unifiedSurfaceTexCoords).push_back( osg::Vec2( ndc.x(), ndc.y() ) );
00872                 }
00873                 else
00874                 {
00875                     // the separate texture space requires separate transformed texcoords for each layer.
00876                     for( RenderLayerVector::const_iterator r = renderLayers.begin(); r != renderLayers.end(); ++r )
00877                     {
00878                         if ( r->_ownsTexCoords )
00879                         {
00880                             //if ( r->_locator.get() != _masterLocator.get() )
00881                             //if ( r->_locator->isEr->_locator != masterTextureLocator _masterLocator.get() )
00882                             if ( !r->_locator->isEquivalentTo( *masterTextureLocator.get() ) )
00883                             {
00884                                 osg::Vec3d color_ndc;
00885                                 osgTerrain::Locator::convertLocalCoordBetween( *masterTextureLocator.get(), ndc, *r->_locator.get(), color_ndc );
00886                                 r->_texCoords->push_back( osg::Vec2( color_ndc.x(), color_ndc.y() ) );
00887                             }
00888                             else
00889                             {
00890                                 r->_texCoords->push_back( osg::Vec2( ndc.x(), ndc.y() ) );
00891                             }
00892                         }
00893                     }
00894                 }
00895 
00896                 if (elevations.valid())
00897                 {
00898                     (*elevations).push_back(ndc.z());
00899                 }
00900 
00901                 // compute the local normal
00902                 osg::Vec3d ndc_one = ndc; ndc_one.z() += 1.0;
00903                 osg::Vec3d model_one;
00904                 _masterLocator->convertLocalToModel(ndc_one, model_one);
00905                 model_one = model_one - model;
00906                 model_one.normalize();    
00907 
00908                 //(*normals)[k] = model_one;
00909                 (*normals).push_back(model_one);
00910             }
00911         }
00912     }
00913 
00914 
00915     for (MaskRecordVector::iterator mr = masks.begin(); mr != masks.end(); ++mr)
00916     {
00917       int min_i = (int)floor((*mr)._ndcMin.x() * (double)(numColumns-1));
00918       if (min_i < 0) min_i = 0;
00919       if (min_i >= numColumns) min_i = numColumns - 1;
00920 
00921       int min_j = (int)floor((*mr)._ndcMin.y() * (double)(numRows-1));
00922       if (min_j < 0) min_j = 0;
00923       if (min_j >= numColumns) min_j = numColumns - 1;
00924 
00925       int max_i = (int)ceil((*mr)._ndcMax.x() * (double)(numColumns-1));
00926       if (max_i < 0) max_i = 0;
00927       if (max_i >= numColumns) max_i = numColumns - 1;
00928 
00929       int max_j = (int)ceil((*mr)._ndcMax.y() * (double)(numRows-1));
00930       if (max_j < 0) max_j = 0;
00931       if (max_j >= numColumns) max_j = numColumns - 1;
00932 
00933       if (min_i >= 0 && max_i >= 0 && min_j >= 0 && max_j >= 0)
00934       {
00935         int num_i = max_i - min_i + 1;
00936         int num_j = max_j - min_j + 1;
00937 
00938         osg::ref_ptr<osgEarth::Symbology::Polygon> maskSkirtPoly = new osgEarth::Symbology::Polygon();
00939         maskSkirtPoly->resize(num_i * 2 + num_j * 2 - 4);
00940         for (int i = 0; i < num_i; i++)
00941         {
00942           //int index = indices[min_j*numColumns + i + min_i];
00943           {
00944             osg::Vec3d ndc( ((double)(i + min_i))/(double)(numColumns-1), ((double)min_j)/(double)(numRows-1), 0.0);
00945 
00946             if (elevationLayer)
00947             {
00948               unsigned int i_equiv = i_sampleFactor==1.0 ? i + min_i : (unsigned int) (double(i + min_i)*i_sampleFactor);
00949               unsigned int j_equiv = j_sampleFactor==1.0 ? min_j : (unsigned int) (double(min_j)*j_sampleFactor);
00950 
00951               float value = 0.0f;
00952               if (elevationLayer->getValidValue(i_equiv,j_equiv, value))
00953                 ndc.z() = value*scaleHeight;
00954             }
00955 
00956             (*maskSkirtPoly)[i] = ndc;
00957           }
00958 
00959           //index = indices[max_j*numColumns + i + min_i];
00960           {
00961             osg::Vec3d ndc( ((double)(i + min_i))/(double)(numColumns-1), ((double)max_j)/(double)(numRows-1), 0.0);
00962 
00963             if (elevationLayer)
00964             {
00965               unsigned int i_equiv = i_sampleFactor==1.0 ? i + min_i : (unsigned int) (double(i + min_i)*i_sampleFactor);
00966               unsigned int j_equiv = j_sampleFactor==1.0 ? max_j : (unsigned int) (double(max_j)*j_sampleFactor);
00967 
00968               float value = 0.0f;
00969               if (elevationLayer->getValidValue(i_equiv,j_equiv, value))
00970                 ndc.z() = value*scaleHeight;
00971             }
00972 
00973             (*maskSkirtPoly)[i + (2 * num_i + num_j - 3) - 2 * i] = ndc;
00974           }
00975         }
00976         for (int j = 0; j < num_j - 2; j++)
00977         {
00978           //int index = indices[(min_j + j + 1)*numColumns + max_i];
00979           {
00980             osg::Vec3d ndc( ((double)max_i)/(double)(numColumns-1), ((double)(min_j + j + 1))/(double)(numRows-1), 0.0);
00981 
00982             if (elevationLayer)
00983             {
00984               unsigned int i_equiv = i_sampleFactor==1.0 ? max_i : (unsigned int) (double(max_i)*i_sampleFactor);
00985               unsigned int j_equiv = j_sampleFactor==1.0 ? min_j + j + 1 : (unsigned int) (double(min_j + j + 1)*j_sampleFactor);
00986 
00987               float value = 0.0f;
00988               if (elevationLayer->getValidValue(i_equiv,j_equiv, value))
00989                 ndc.z() = value*scaleHeight;
00990             }
00991 
00992             (*maskSkirtPoly)[j + num_i] = ndc;
00993           }
00994 
00995           //index = indices[(min_j + j + 1)*numColumns + min_i];
00996           {
00997             osg::Vec3d ndc( ((double)min_i)/(double)(numColumns-1), ((double)(min_j + j + 1))/(double)(numRows-1), 0.0);
00998 
00999             if (elevationLayer)
01000             {
01001               unsigned int i_equiv = i_sampleFactor==1.0 ? min_i : (unsigned int) (double(min_i)*i_sampleFactor);
01002               unsigned int j_equiv = j_sampleFactor==1.0 ? min_j + j + 1 : (unsigned int) (double(min_j + j + 1)*j_sampleFactor);
01003 
01004               float value = 0.0f;
01005               if (elevationLayer->getValidValue(i_equiv,j_equiv, value))
01006                 ndc.z() = value*scaleHeight;
01007             }
01008 
01009             (*maskSkirtPoly)[j + (2 * num_i + 2 * num_j - 5) - 2 * j] = ndc;
01010           }
01011         }
01012 
01013         //Create local polygon representing mask
01014         osg::ref_ptr<osgEarth::Symbology::Polygon> maskPoly = new osgEarth::Symbology::Polygon();
01015         for (osg::Vec3dArray::iterator it = (*mr)._boundary->begin(); it != (*mr)._boundary->end(); ++it)
01016         {
01017           osg::Vec3d local;
01018           geoLocator->convertModelToLocal(*it, local);
01019           maskPoly->push_back(local);
01020         }
01021 
01022 
01023 //Change the following two #if statements to see mask skirt polygons
01024 //before clipping and adjusting
01025 #if 1
01026         //Do a diff on the polygons to get the actual mask skirt
01027         osg::ref_ptr<osgEarth::Symbology::Geometry> outPoly;
01028         maskSkirtPoly->difference(maskPoly.get(), outPoly);
01029 #else
01030         osg::ref_ptr<osgEarth::Symbology::Geometry> outPoly = maskSkirtPoly;
01031 #endif
01032 
01033         osg::Vec3Array* outVerts = new osg::Vec3Array();
01034 
01035         osg::Geometry* stitch_geom = (*mr)._geom;
01036         stitch_geom->setVertexArray(outVerts);
01037 
01038         bool multiParent = false;
01039         if (outPoly.valid())
01040           multiParent = outPoly->getType() == osgEarth::Symbology::Geometry::TYPE_MULTI;
01041         
01042         std::vector<int> skirtIndices;
01043 
01044         osgEarth::Symbology::GeometryIterator i( outPoly.get(), false );
01045         while( i.hasMore() )
01046         {
01047           osgEarth::Symbology::Geometry* part = i.next();
01048           if (!part)
01049             continue;
01050 
01051           if (part->getType() == osgEarth::Symbology::Geometry::TYPE_POLYGON)
01052           {
01053             osg::Vec3Array* partVerts = part->toVec3Array();
01054             outVerts->insert(outVerts->end(), partVerts->begin(), partVerts->end());
01055             stitch_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, outVerts->size() - partVerts->size(), partVerts->size()));
01056             skirtIndices.push_back(outVerts->size());
01057 
01058             if (!multiParent)
01059             {
01060               osg::ref_ptr<osgEarth::Symbology::Polygon> holePoly = static_cast<osgEarth::Symbology::Polygon*>(outPoly.get());
01061               if (holePoly)
01062               {
01063                 osgEarth::Symbology::RingCollection holes = holePoly->getHoles();
01064                 
01065                 for (osgEarth::Symbology::RingCollection::iterator hit = holes.begin(); hit != holes.end(); ++hit)
01066                 {
01067                   (*hit)->rewind(osgEarth::Symbology::Ring::ORIENTATION_CCW);
01068                   outVerts->insert(outVerts->end(), (*hit)->begin(), (*hit)->end());
01069                   stitch_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, outVerts->size() - (*hit)->size(), (*hit)->size()));
01070                   skirtIndices.push_back(outVerts->size());
01071                 }
01072               }
01073             }
01074           }
01075         }
01076 
01077         if (stitch_geom->getNumPrimitiveSets() > 0)
01078         {
01079 #if 1
01080           // Tessellate mask skirt
01081           osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator;
01082           tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
01083           tscx->setBoundaryOnly(false);
01084           tscx->setWindingType(osgUtil::Tessellator::TESS_WINDING_ODD);
01085           tscx->retessellatePolygons(*stitch_geom);
01086 
01087           // Assign normals to the stitching polygon: -gw
01088           osg::Vec3Array* sgVerts = dynamic_cast<osg::Vec3Array*>(stitch_geom->getVertexArray());
01089           osg::Vec3Array* sgNormals = new osg::Vec3Array(sgVerts->size());
01090           stitch_geom->setNormalArray( sgNormals );
01091           stitch_geom->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
01092           
01093           // calculate the normal and convert to model space.
01094           for( unsigned v=0; v<sgVerts->size(); ++v )
01095           {
01096               const osg::Vec3& vert = (*sgVerts)[v];
01097               osg::Vec3d local_one(vert);
01098               osg::Vec3d model;
01099               _masterLocator->convertLocalToModel( local_one, model );
01100               local_one.z() += 1.0;
01101               osg::Vec3d model_one;
01102               _masterLocator->convertLocalToModel( local_one, model_one );
01103               model_one = model_one - model;
01104               model_one.normalize();
01105               (*sgNormals)[v] = model_one;
01106           }
01107 
01108           //Initialize tex coords
01109           osg::Vec2Array* unifiedStitchTexCoords = 0L;
01110           if (_texCompositor->requiresUnitTextureSpace())
01111           {
01112             unifiedStitchTexCoords = new osg::Vec2Array();
01113             unifiedStitchTexCoords->reserve(outVerts->size());
01114             stitch_geom->setTexCoordArray(0, unifiedStitchTexCoords);
01115           }
01116           else if ( renderLayers.size() > 0 )
01117           {
01118             for (unsigned int i = 0; i < renderLayers.size(); ++i)
01119             {
01120               renderLayers[i]._stitchTexCoords->reserve(outVerts->size());
01121             }
01122           }
01123 
01124 
01125           //Retrieve z values for mask skirt verts
01126           std::vector<int> isZSet;
01127           for (osg::Vec3Array::iterator it = outVerts->begin(); it != outVerts->end(); ++it)
01128           {
01129             int zSet = 0;
01130 
01131             //Look for verts that belong to the original mask skirt polygon
01132             for (osgEarth::Symbology::Polygon::iterator mit = maskSkirtPoly->begin(); mit != maskSkirtPoly->end(); ++mit)
01133             {
01134               if (osg::absolute((*mit).x() - (*it).x()) < MATCH_TOLERANCE && osg::absolute((*mit).y() - (*it).y()) < MATCH_TOLERANCE)
01135               {
01136                 (*it).z() = (*mit).z();
01137                 zSet += 1;
01138                 break;
01139               }
01140             }
01141 
01142             //Look for verts that belong to the mask polygon
01143             for (osgEarth::Symbology::Polygon::iterator mit = maskPoly->begin(); mit != maskPoly->end(); ++mit)
01144             {
01145               if (osg::absolute((*mit).x() - (*it).x()) < MATCH_TOLERANCE && osg::absolute((*mit).y() - (*it).y()) < MATCH_TOLERANCE)
01146               {
01147                 (*it).z() = (*mit).z();
01148                 zSet += 2;
01149                 break;
01150               }
01151             }
01152 
01153             isZSet.push_back(zSet);
01154           }
01155 
01156           //Any mask skirt verts that are still unset are newly created verts where the skirt
01157           //meets the mask. Find the mask segment the point lies along and calculate the
01158           //appropriate z value for the point.
01159           //
01160           //Now that all the z values are set, convert each vert into model coords.
01161           //
01162           //Also, while we are iterating through the verts, set up tex coords.
01163           int count = 0;
01164           for (osg::Vec3Array::iterator it = outVerts->begin(); it != outVerts->end(); ++it)
01165           {
01166             //If the z-value was set from a mask vertex there is no need to change it.  If
01167             //it was set from a vertex from the stitching polygon it may need overriden if
01168             //the vertex lies along a mask edge.  Or if it is unset, it will need to be set.
01169             if (isZSet[count] < 2)
01170             {
01171               osg::Vec3d p2 = *it;
01172               double closestZ = 0.0;
01173               double closestRatio = DBL_MAX;
01174               for (osgEarth::Symbology::Polygon::iterator mit = maskPoly->begin(); mit != maskPoly->end(); ++mit)
01175               {
01176                 osg::Vec3d p1 = *mit;
01177                 osg::Vec3d p3 = mit == --maskPoly->end() ? maskPoly->front() : (*(mit + 1));
01178 
01179                 //Truncated vales to compensate for accuracy issues
01180                 double p1x = ((int)(p1.x() * 1000000)) / 1000000.0L;
01181                 double p3x = ((int)(p3.x() * 1000000)) / 1000000.0L;
01182                 double p2x = ((int)(p2.x() * 1000000)) / 1000000.0L;
01183 
01184                 double p1y = ((int)(p1.y() * 1000000)) / 1000000.0L;
01185                 double p3y = ((int)(p3.y() * 1000000)) / 1000000.0L;
01186                 double p2y = ((int)(p2.y() * 1000000)) / 1000000.0L;
01187 
01188                 if ((p1x < p3x ? p2x >= p1x && p2x <= p3x : p2x >= p3x && p2x <= p1x) &&
01189                     (p1y < p3y ? p2y >= p1y && p2y <= p3y : p2y >= p3y && p2y <= p1y))
01190                 {
01191                   double l1 =(osg::Vec2d(p2.x(), p2.y()) - osg::Vec2d(p1.x(), p1.y())).length();
01192                   double lt = (osg::Vec2d(p3.x(), p3.y()) - osg::Vec2d(p1.x(), p1.y())).length();
01193                   double zmag = p3.z() - p1.z();
01194 
01195                   double foundZ = (l1 / lt) * zmag + p1.z();
01196 
01197                   double mRatio = 1.0;
01198                   if (osg::absolute(p1x - p3x) < MATCH_TOLERANCE)
01199                   {
01200                     if (osg::absolute(p1x-p2x) < MATCH_TOLERANCE)
01201                       mRatio = 0.0;
01202                   }
01203                   else
01204                   {
01205                     double m1 = p1x == p2x ? 0.0 : (p2y - p1y) / (p2x - p1x);
01206                     double m2 = p1x == p3x ? 0.0 : (p3y - p1y) / (p3x - p1x);
01207                     mRatio = m2 == 0.0 ? m1 : osg::absolute(1.0L - m1 / m2);
01208                   }
01209 
01210                   if (mRatio < 0.01)
01211                   {
01212                     (*it).z() = foundZ;
01213                     isZSet[count] = 2;
01214                     break;
01215                   }
01216                   else if (mRatio < closestRatio)
01217                   {
01218                     closestRatio = mRatio;
01219                     closestZ = foundZ;
01220                   }
01221                 }
01222               }
01223 
01224               if (!isZSet[count] && closestRatio < DBL_MAX)
01225               {
01226                 (*it).z() = closestZ;
01227                 isZSet[count] = 2;
01228               }
01229             }
01230 
01231             if (!isZSet[count])
01232               OE_WARN << LC << "Z-value not set for stitching polygon vertex" << std::endl;
01233 
01234             count++;
01235 
01236             //Convert to model coords
01237             osg::Vec3d model;
01238             _masterLocator->convertLocalToModel(*it, model);
01239             model = model - _centerModel;
01240             (*it).set(model.x(), model.y(), model.z());
01241 
01242             //Setup tex coords
01243             osg::Vec3d ndc;
01244             _masterLocator->convertModelToLocal(*it + _centerModel, ndc);
01245 
01246             if (_texCompositor->requiresUnitTextureSpace())
01247             {
01248               unifiedStitchTexCoords->push_back(osg::Vec2(ndc.x(), ndc.y()));
01249             }
01250             else if (renderLayers.size() > 0)
01251             {
01252               for (unsigned int i = 0; i < renderLayers.size(); ++i)
01253               {
01254                 if (!renderLayers[i]._locator->isEquivalentTo(*masterTextureLocator.get()))
01255                 {
01256                   osg::Vec3d color_ndc;
01257                   osgTerrain::Locator::convertLocalCoordBetween(*masterTextureLocator.get(), ndc, *renderLayers[i]._locator.get(), color_ndc);
01258                   renderLayers[i]._stitchTexCoords->push_back(osg::Vec2(color_ndc.x(), color_ndc.y()));
01259                 }
01260                 else
01261                 {
01262                   renderLayers[i]._stitchTexCoords->push_back(osg::Vec2(ndc.x(), ndc.y()));
01263                 }
01264               }
01265             }
01266           }
01267 #else
01268           for (osg::Vec3Array::iterator it = outVerts->begin(); it != outVerts->end(); ++it)
01269           {
01270             //Convert to model coords
01271             osg::Vec3d model;
01272             _masterLocator->convertLocalToModel(*it, model);
01273             model = model - _centerModel;
01274             (*it).set(model.x(), model.y(), model.z());
01275           }
01276 #endif
01277       
01278           //Create stitching skirts
01279           if (createSkirt && skirtIndices.size() > 0)
01280           {
01281             ss_verts->reserve(ss_verts->size() + outVerts->size() * 4 + skirtIndices.size() * 2);
01282 
01283             //Add a primative set for each continuous skirt strip
01284             for (int p=0; p < skirtIndices.size(); p++)
01285             {
01286               int cursor = ss_verts->size();
01287 
01288               int outStart = p == 0 ? 0 : skirtIndices[p-1];
01289               for (int i=outStart; i < skirtIndices[p]; i++)
01290               {
01291                 ss_verts->push_back((*outVerts)[i]);
01292                 ss_verts->push_back((*outVerts)[i] - (*sgNormals)[i] * skirtHeight);
01293 
01294                 if ( _texCompositor->requiresUnitTextureSpace() )
01295                 {
01296                     unifiedStitchSkirtTexCoords->push_back( (*unifiedStitchTexCoords)[i] );
01297                     unifiedStitchSkirtTexCoords->push_back( (*unifiedStitchTexCoords)[i] );
01298                 }
01299                 else if ( renderLayers.size() > 0 )
01300                 {
01301                     for (unsigned int r = 0; r < renderLayers.size(); ++r)
01302                     {
01303                         const osg::Vec2& tc = (*renderLayers[r]._stitchTexCoords.get())[i];
01304                         renderLayers[r]._stitchSkirtTexCoords->push_back( tc );
01305                         renderLayers[r]._stitchSkirtTexCoords->push_back( tc );
01306                     }
01307                 }
01308               }
01309 
01310               //Add the first vert again to complete the loop
01311               ss_verts->push_back((*outVerts)[outStart]);
01312               ss_verts->push_back((*outVerts)[outStart] - (*sgNormals)[outStart] * skirtHeight);
01313 
01314               if ( _texCompositor->requiresUnitTextureSpace() )
01315               {
01316                   unifiedStitchSkirtTexCoords->push_back( (*unifiedStitchTexCoords)[outStart] );
01317                   unifiedStitchSkirtTexCoords->push_back( (*unifiedStitchTexCoords)[outStart] );
01318               }
01319               else if ( renderLayers.size() > 0 )
01320               {
01321                   for (unsigned int r = 0; r < renderLayers.size(); ++r)
01322                   {
01323                       const osg::Vec2& tc = (*renderLayers[r]._stitchTexCoords.get())[outStart];
01324                       renderLayers[r]._stitchSkirtTexCoords->push_back( tc );
01325                       renderLayers[r]._stitchSkirtTexCoords->push_back( tc );
01326                   }
01327               }
01328 
01329               //Now go back the opposite direction to create a skirt facing the other direction
01330               for (int i=skirtIndices[p] - 1; i >= outStart; i--)
01331               {
01332                 ss_verts->push_back((*outVerts)[i]);
01333                 ss_verts->push_back((*outVerts)[i] - (*sgNormals)[i] * skirtHeight);
01334 
01335                 if ( _texCompositor->requiresUnitTextureSpace() )
01336                 {
01337                     unifiedStitchSkirtTexCoords->push_back( (*unifiedStitchTexCoords)[i] );
01338                     unifiedStitchSkirtTexCoords->push_back( (*unifiedStitchTexCoords)[i] );
01339                 }
01340                 else if ( renderLayers.size() > 0 )
01341                 {
01342                     for (unsigned int r = 0; r < renderLayers.size(); ++r)
01343                     {
01344                         const osg::Vec2& tc = (*renderLayers[r]._stitchTexCoords.get())[i];
01345                         renderLayers[r]._stitchSkirtTexCoords->push_back( tc );
01346                         renderLayers[r]._stitchSkirtTexCoords->push_back( tc );
01347                     }
01348                 }
01349               }
01350 
01351               stitching_skirts->addPrimitiveSet(new osg::DrawArrays( GL_TRIANGLE_STRIP, cursor, ss_verts->size() - cursor));
01352             }
01353           }
01354         }
01355       }
01356     }
01357 
01358     // populate primitive sets
01359     bool swapOrientation = !(_masterLocator->orientationOpenGL());
01360 
01361     osg::ref_ptr<osg::DrawElementsUInt> elements = new osg::DrawElementsUInt(GL_TRIANGLES);
01362     elements->reserve((numRows-1) * (numColumns-1) * 6);
01363 
01364     surface->addPrimitiveSet(elements.get());
01365     
01366     osg::ref_ptr<osg::Vec3Array> skirtVectors = new osg::Vec3Array( *normals );
01367 
01368           if (!normals)
01369         createSkirt = false;
01370     
01371     // New separated skirts.
01372     if ( createSkirt )
01373     {        
01374         // build the verts first:
01375         osg::Vec3Array* skirtVerts = new osg::Vec3Array();
01376         osg::Vec3Array* skirtNormals = new osg::Vec3Array();
01377 
01378         skirtVerts->reserve( numVerticesInSkirt );
01379         skirtNormals->reserve( numVerticesInSkirt );
01380         
01381         Indices skirtBreaks;
01382         skirtBreaks.push_back(0);
01383 
01384         // bottom:
01385         for( unsigned int c=0; c<numColumns-1; ++c )
01386         {
01387             int orig_i = indices[c];
01388 
01389             //int offset = 0;
01390             //while (orig_i < 0 && offset < numRows - 1)
01391             //  orig_i = indices[c + ++offset * numColumns];
01392 
01393             if (orig_i < 0)
01394             {
01395               if (skirtBreaks.back() != skirtVerts->size())
01396                 skirtBreaks.push_back(skirtVerts->size());
01397             }
01398             else
01399             {
01400               skirtVerts->push_back( (*surfaceVerts)[orig_i] );
01401               skirtVerts->push_back( (*surfaceVerts)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight );
01402               skirtNormals->push_back( (*normals)[orig_i] );             
01403               skirtNormals->push_back( (*normals)[orig_i] );             
01404 
01405 
01406               if ( _texCompositor->requiresUnitTextureSpace() )
01407               {
01408                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01409                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01410               }
01411               else if ( renderLayers.size() > 0 )
01412               {
01413                   for (unsigned int i = 0; i < renderLayers.size(); ++i)
01414                   {
01415                       const osg::Vec2& tc = (*renderLayers[i]._texCoords.get())[orig_i];
01416                       renderLayers[i]._skirtTexCoords->push_back( tc );
01417                       renderLayers[i]._skirtTexCoords->push_back( tc );
01418                   }
01419               }
01420             }
01421         }
01422 
01423         // right:
01424         for( unsigned int r=0; r<numRows-1; ++r )
01425         {
01426             int orig_i = indices[r*numColumns+(numColumns-1)];
01427             if (orig_i < 0)
01428             {
01429               if (skirtBreaks.back() != skirtVerts->size())
01430                 skirtBreaks.push_back(skirtVerts->size());
01431             }
01432             else
01433             {
01434               skirtVerts->push_back( (*surfaceVerts)[orig_i] );
01435               skirtVerts->push_back( (*surfaceVerts)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight );
01436               skirtNormals->push_back( (*normals)[orig_i] );             
01437               skirtNormals->push_back( (*normals)[orig_i] );             
01438 
01439               if ( _texCompositor->requiresUnitTextureSpace() )
01440               {
01441                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01442                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01443               }
01444               else if ( renderLayers.size() > 0 )
01445               {
01446                   for (unsigned int i = 0; i < renderLayers.size(); ++i)
01447                   {
01448                       const osg::Vec2& tc = (*renderLayers[i]._texCoords.get())[orig_i];
01449                       renderLayers[i]._skirtTexCoords->push_back( tc );
01450                       renderLayers[i]._skirtTexCoords->push_back( tc );
01451                   }
01452               }
01453             }
01454         }
01455 
01456         // top:
01457         for( int c=numColumns-1; c>0; --c )
01458         {
01459             int orig_i = indices[(numRows-1)*numColumns+c];
01460             if (orig_i < 0)
01461             {
01462               if (skirtBreaks.back() != skirtVerts->size())
01463                 skirtBreaks.push_back(skirtVerts->size());
01464             }
01465             else
01466             {
01467               skirtVerts->push_back( (*surfaceVerts)[orig_i] );
01468               skirtVerts->push_back( (*surfaceVerts)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight );
01469               skirtNormals->push_back( (*normals)[orig_i] );             
01470               skirtNormals->push_back( (*normals)[orig_i] );             
01471 
01472               if ( _texCompositor->requiresUnitTextureSpace() )
01473               {
01474                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01475                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01476               }
01477               else if ( renderLayers.size() > 0 )
01478               {
01479                   for (unsigned int i = 0; i < renderLayers.size(); ++i)
01480                   {
01481                       const osg::Vec2& tc = (*renderLayers[i]._texCoords.get())[orig_i];
01482                       renderLayers[i]._skirtTexCoords->push_back( tc );
01483                       renderLayers[i]._skirtTexCoords->push_back( tc );
01484                   }
01485               }
01486             }
01487         }
01488 
01489         // left:
01490         for( int r=numRows-1; r>=0; --r )
01491         {
01492             int orig_i = indices[r*numColumns];
01493             if (orig_i < 0)
01494             {
01495               if (skirtBreaks.back() != skirtVerts->size())
01496                 skirtBreaks.push_back(skirtVerts->size());
01497             }
01498             else
01499             {
01500               skirtVerts->push_back( (*surfaceVerts)[orig_i] );
01501               skirtVerts->push_back( (*surfaceVerts)[orig_i] - ((*skirtVectors)[orig_i])*skirtHeight );              
01502               skirtNormals->push_back( (*normals)[orig_i] );             
01503               skirtNormals->push_back( (*normals)[orig_i] );             
01504 
01505               if ( _texCompositor->requiresUnitTextureSpace() )
01506               {
01507                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01508                   unifiedSkirtTexCoords->push_back( (*unifiedSurfaceTexCoords)[orig_i] );
01509               }
01510               else if ( renderLayers.size() > 0 )
01511               {
01512                   for (unsigned int i = 0; i < renderLayers.size(); ++i)
01513                   {
01514                       const osg::Vec2& tc = (*renderLayers[i]._texCoords.get())[orig_i];
01515                       renderLayers[i]._skirtTexCoords->push_back( tc );
01516                       renderLayers[i]._skirtTexCoords->push_back( tc );
01517                   }
01518               }
01519             }
01520         }
01521 
01522         skirt->setVertexArray( skirtVerts );
01523         skirt->setNormalArray( skirtNormals );
01524         skirt->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
01525 
01526         //Add a primative set for each continuous skirt strip
01527         skirtBreaks.push_back(skirtVerts->size());
01528         for (int p=1; p < skirtBreaks.size(); p++)
01529           skirt->addPrimitiveSet( new osg::DrawArrays( GL_TRIANGLE_STRIP, skirtBreaks[p-1], skirtBreaks[p] - skirtBreaks[p-1] ) );
01530     }
01531     
01532     bool recalcNormals = elevationLayer != NULL;
01533 
01534     //Clear out the normals
01535     if (recalcNormals)
01536     {
01537         osg::Vec3Array::iterator nitr;
01538         for(nitr = normals->begin();
01539             nitr!=normals->end();
01540             ++nitr)
01541         {
01542             nitr->set(0.0f,0.0f,0.0f);
01543         }
01544     }
01545     
01546     for(j=0; j<numRows-1; ++j)
01547     {
01548         for(i=0; i<numColumns-1; ++i)
01549         {
01550             int i00;
01551             int i01;
01552             if (swapOrientation)
01553             {
01554                 i01 = j*numColumns + i;
01555                 i00 = i01+numColumns;
01556             }
01557             else
01558             {
01559                 i00 = j*numColumns + i;
01560                 i01 = i00+numColumns;
01561             }
01562 
01563             int i10 = i00+1;
01564             int i11 = i01+1;
01565 
01566             // remap indices to final vertex positions
01567             i00 = indices[i00];
01568             i01 = indices[i01];
01569             i10 = indices[i10];
01570             i11 = indices[i11];
01571             
01572             unsigned int numValid = 0;
01573             if (i00>=0) ++numValid;
01574             if (i01>=0) ++numValid;
01575             if (i10>=0) ++numValid;
01576             if (i11>=0) ++numValid;
01577             
01578             if (numValid==4)
01579             {
01580 
01581                                 bool VALID = true;
01582                                 for (MaskRecordVector::iterator mr = masks.begin(); mr != masks.end(); ++mr) {
01583                                         float min_i = (*mr)._ndcMin.x() * (double)(numColumns-1);
01584                                         float min_j = (*mr)._ndcMin.y() * (double)(numRows-1);
01585                                         float max_i = (*mr)._ndcMax.x() * (double)(numColumns-1);
01586                                         float max_j = (*mr)._ndcMax.y() * (double)(numRows-1);
01587 
01588                                         // We test if mask is completely in square
01589                                         if(i+1 >= min_i && i <= max_i && j+1 >= min_j && j <= max_j) {
01590                                                 VALID = false;
01591                                                 break;
01592                                         }
01593                                 }
01594 
01595                                 if (VALID) {
01596                                         float e00 = (*elevations)[i00];
01597                                         float e10 = (*elevations)[i10];
01598                                         float e01 = (*elevations)[i01];
01599                                         float e11 = (*elevations)[i11];
01600 
01601                 osg::Vec3f &v00 = (*surfaceVerts)[i00];
01602                 osg::Vec3f &v10 = (*surfaceVerts)[i10];
01603                 osg::Vec3f &v01 = (*surfaceVerts)[i01];
01604                 osg::Vec3f &v11 = (*surfaceVerts)[i11];
01605 
01606                 if (!_optimizeTriangleOrientation || (e00-e11)<fabsf(e01-e10))
01607                 {
01608                     elements->push_back(i01);
01609                     elements->push_back(i00);
01610                     elements->push_back(i11);
01611 
01612                     elements->push_back(i00);
01613                     elements->push_back(i10);
01614                     elements->push_back(i11);
01615 
01616                     if (recalcNormals)
01617                     {                        
01618                         osg::Vec3 normal1 = (v00-v01) ^ (v11-v01);
01619                         (*normals)[i01] += normal1;
01620                         (*normals)[i00] += normal1;
01621                         (*normals)[i11] += normal1;
01622 
01623                         osg::Vec3 normal2 = (v10-v00)^(v11-v00);
01624                         (*normals)[i00] += normal2;
01625                         (*normals)[i10] += normal2;
01626                         (*normals)[i11] += normal2;
01627                     }
01628                 }
01629                 else
01630                 {
01631                     elements->push_back(i01);
01632                     elements->push_back(i00);
01633                     elements->push_back(i10);
01634 
01635                     elements->push_back(i01);
01636                     elements->push_back(i10);
01637                     elements->push_back(i11);
01638 
01639                     if (recalcNormals)
01640                     {                       
01641                         osg::Vec3 normal1 = (v00-v01) ^ (v10-v01);
01642                         (*normals)[i01] += normal1;
01643                         (*normals)[i00] += normal1;
01644                         (*normals)[i10] += normal1;
01645 
01646                         osg::Vec3 normal2 = (v10-v01)^(v11-v01);
01647                         (*normals)[i01] += normal2;
01648                         (*normals)[i10] += normal2;
01649                         (*normals)[i11] += normal2;
01650                     }
01651                 }
01652                                 }
01653             }
01654             // As skirtPoly is filling the mask bbox, we don't need to create isolated triangle
01655                         /*else if (numValid==3)
01656             {
01657                 int validIndices[3];
01658                 int indexPtr = 0;
01659                 if (i00>=0)
01660                 {
01661                     elements->push_back(i00);
01662                     validIndices[indexPtr++] = i00;
01663                 }
01664 
01665                 if (i01>=0)
01666                 {
01667                     elements->push_back(i01);
01668                     validIndices[indexPtr++] = i01;
01669                 }
01670 
01671                 if (i11>=0)
01672                 {
01673                     elements->push_back(i11);
01674                     validIndices[indexPtr++] = i11;
01675                 }
01676 
01677                 if (i10>=0)
01678                 {
01679                     elements->push_back(i10);
01680                     validIndices[indexPtr++] = i10;
01681                 }
01682 
01683                 if (recalcNormals)
01684                 {
01685                     osg::Vec3f &v1 = (*surfaceVerts)[validIndices[0]];
01686                     osg::Vec3f &v2 = (*surfaceVerts)[validIndices[1]];
01687                     osg::Vec3f &v3 = (*surfaceVerts)[validIndices[2]];
01688                     osg::Vec3f normal = (v2 - v1) ^ (v3 - v1);
01689                     (*normals)[validIndices[0]] += normal;
01690                     (*normals)[validIndices[1]] += normal;
01691                     (*normals)[validIndices[2]] += normal;
01692                 }
01693             } */
01694         }
01695     }
01696 
01697     //Normalize the normals
01698     if (recalcNormals)
01699     {
01700         osg::Vec3Array::iterator nitr;
01701         for(nitr = normals->begin();
01702             nitr!=normals->end();
01703             ++nitr)
01704         {
01705             nitr->normalize();
01706         }
01707     }
01708 
01709   
01710 
01711     MeshConsolidator::run( *surface );
01712 
01713     if ( skirt )
01714         MeshConsolidator::run( *skirt );
01715 
01716     for (MaskRecordVector::iterator mr = masks.begin(); mr != masks.end(); ++mr)
01717         MeshConsolidator::run( *((*mr)._geom) );
01718     
01719    
01720     if (osgDB::Registry::instance()->getBuildKdTreesHint()==osgDB::ReaderWriter::Options::BUILD_KDTREES &&
01721         osgDB::Registry::instance()->getKdTreeBuilder())
01722     {            
01723         osg::ref_ptr<osg::KdTreeBuilder> builder = osgDB::Registry::instance()->getKdTreeBuilder()->clone();
01724         geode->accept(*builder);
01725     }
01726 
01727     return geode;
01728 }
01729 
01730 void
01731 SinglePassTerrainTechnique::traverse(osg::NodeVisitor& nv)
01732 {
01733     if ( !_tile )
01734         return;
01735 
01736     if ( _transform.valid() )
01737     {
01738         _transform->accept( nv );
01739     }
01740 }
01741 
01742 void
01743 SinglePassTerrainTechnique::releaseGLObjects(osg::State* state) const
01744 {
01745     SinglePassTerrainTechnique* ncThis = const_cast<SinglePassTerrainTechnique*>(this);
01746 
01747     Threading::ScopedWriteLock lock( static_cast<Tile*>(ncThis->_tile)->getTileLayersMutex() );
01748 
01749     if ( _transform.valid() )
01750     {
01751         _transform->releaseGLObjects( state );
01752     }
01753 
01754     if ( _backGeode.valid() )
01755     {
01756         _backGeode->releaseGLObjects(state);
01757         ncThis->_backGeode = 0L;
01758     }
01759 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines