osgEarth 2.1.1
|
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 "Tile" 00020 #include "Terrain" 00021 #include "CustomTerrainTechnique" 00022 #include "TransparentLayer" 00023 00024 #include <osgEarth/Registry> 00025 #include <osgEarth/Locators> 00026 #include <osgEarth/Map> 00027 #include <osgEarth/FindNode> 00028 00029 #include <osg/NodeCallback> 00030 #include <osg/NodeVisitor> 00031 #include <osg/Node> 00032 #include <osg/Texture2D> 00033 #include <osgGA/EventVisitor> 00034 00035 #include <OpenThreads/ScopedLock> 00036 00037 00038 using namespace osgEarth; 00039 using namespace OpenThreads; 00040 00041 #define LC "[Tile] " 00042 00043 //---------------------------------------------------------------------------- 00044 00045 Tile::Tile( const TileKey& key, GeoLocator* keyLocator, bool quickReleaseGLObjects ) : 00046 _key( key ), 00047 _locator( keyLocator ), 00048 _quickReleaseGLObjects( quickReleaseGLObjects ), 00049 _hasBeenTraversed( false ), 00050 _verticalScale( 1.0f ), 00051 _parentTileSet( false ), 00052 _tileId( key.getTileId() ), 00053 _dirty( true ) 00054 { 00055 this->setThreadSafeRefUnref( true ); 00056 this->setName( key.str() ); 00057 00058 // initially bump the update requirement so that this tile will receive an update 00059 // traversal the first time through. It is on the first update traversal that we 00060 // know the tile is in the scene graph and that it can be registered with the terrain. 00061 ADJUST_UPDATE_TRAV_COUNT( this, 1 ); 00062 } 00063 00064 Tile::~Tile() 00065 { 00066 //nop 00067 } 00068 00069 void 00070 Tile::init() 00071 { 00072 if ( _tech.valid() ) 00073 { 00074 _tech->init(); 00075 _dirty = false; 00076 } 00077 } 00078 00079 void 00080 Tile::setTerrainTechnique( TerrainTechnique* tech ) 00081 { 00082 tech->_tile = this; 00083 _tech = tech; 00084 _dirty = true; 00085 } 00086 00087 void 00088 Tile::attachToTerrain( Terrain* terrain ) 00089 { 00090 _terrain = terrain; 00091 if ( terrain ) 00092 terrain->registerTile( this ); 00093 } 00094 00095 void 00096 Tile::setVerticalScale (float verticalScale ) 00097 { 00098 if (_verticalScale != verticalScale) 00099 { 00100 _verticalScale = verticalScale; 00101 dirtyBound(); 00102 } 00103 } 00104 00105 void 00106 Tile::setCustomColorLayer( const CustomColorLayer& layer, bool writeLock ) 00107 { 00108 if ( writeLock ) 00109 { 00110 Threading::ScopedWriteLock exclusiveTileLock( _tileLayersMutex ); 00111 setCustomColorLayer( layer, false ); 00112 } 00113 else 00114 { 00115 int delta = 0; 00116 ColorLayersByUID::const_iterator i = _colorLayers.find( layer.getUID() ); 00117 if ( i != _colorLayers.end() && i->second.getMapLayer()->isDynamic() ) 00118 --delta; 00119 00120 _colorLayers[layer.getUID()] = layer; 00121 00122 if ( layer.getMapLayer()->isDynamic() ) 00123 ++delta; 00124 00125 if ( delta != 0 ) 00126 ADJUST_UPDATE_TRAV_COUNT( this, delta ); 00127 } 00128 } 00129 00130 void 00131 Tile::removeCustomColorLayer( UID layerUID, bool writeLock ) 00132 { 00133 if ( writeLock ) 00134 { 00135 Threading::ScopedWriteLock exclusiveTileLock( _tileLayersMutex ); 00136 removeCustomColorLayer( layerUID, false ); 00137 } 00138 else 00139 { 00140 ColorLayersByUID::iterator i = _colorLayers.find(layerUID); 00141 if ( i != _colorLayers.end() ) 00142 { 00143 if ( i->second.getMapLayer()->isDynamic() ) 00144 ADJUST_UPDATE_TRAV_COUNT( this, -1 ); 00145 00146 _colorLayers.erase( i ); 00147 } 00148 } 00149 } 00150 00151 bool 00152 Tile::getCustomColorLayer( UID layerUID, CustomColorLayer& out, bool readLock ) const 00153 { 00154 if ( readLock ) 00155 { 00156 Threading::ScopedReadLock sharedTileLock( const_cast<Tile*>(this)->_tileLayersMutex ); 00157 return getCustomColorLayer( layerUID, out, false ); 00158 } 00159 else 00160 { 00161 ColorLayersByUID::const_iterator i = _colorLayers.find( layerUID ); 00162 if ( i != _colorLayers.end() ) 00163 { 00164 out = i->second; 00165 return true; 00166 } 00167 } 00168 return false; 00169 } 00170 00171 void 00172 Tile::getCustomColorLayers( ColorLayersByUID& out, bool readLock ) const 00173 { 00174 if ( readLock ) 00175 { 00176 Threading::ScopedReadLock sharedTileLock( const_cast<Tile*>(this)->_tileLayersMutex ); 00177 return getCustomColorLayers( out, false ); 00178 } 00179 else 00180 out = _colorLayers; 00181 } 00182 00183 void 00184 Tile::setCustomColorLayers( const ColorLayersByUID& in, bool writeLock ) 00185 { 00186 if ( writeLock ) 00187 { 00188 Threading::ScopedWriteLock exclusiveLock( _tileLayersMutex ); 00189 setCustomColorLayers( in, false ); 00190 } 00191 else 00192 { 00193 int delta = 0; 00194 for( ColorLayersByUID::const_iterator i = _colorLayers.begin(); i != _colorLayers.end(); ++i ) 00195 if ( i->second.getMapLayer()->isDynamic() ) 00196 --delta; 00197 00198 _colorLayers = in; 00199 00200 for( ColorLayersByUID::const_iterator i = _colorLayers.begin(); i != _colorLayers.end(); ++i ) 00201 if ( i->second.getMapLayer()->isDynamic() ) 00202 ++delta; 00203 00204 if ( delta != 0 ) 00205 ADJUST_UPDATE_TRAV_COUNT( this, delta ); 00206 } 00207 } 00208 00209 osg::BoundingSphere 00210 Tile::computeBound() const 00211 { 00212 //Overriden computeBound that takes into account the vertical scale. 00213 //OE_NOTICE << "Tile::computeBound verticalScale = " << _verticalScale << std::endl; 00214 00215 osg::BoundingSphere bs; 00216 00217 if (_elevationLayer.valid()) 00218 { 00219 if (!_elevationLayer->getLocator()) return bs; 00220 00221 osg::BoundingBox bb; 00222 unsigned int numColumns = _elevationLayer->getNumColumns(); 00223 unsigned int numRows = _elevationLayer->getNumRows(); 00224 for(unsigned int r=0;r<numRows;++r) 00225 { 00226 for(unsigned int c=0;c<numColumns;++c) 00227 { 00228 float value = 0.0f; 00229 bool validValue = _elevationLayer->getValidValue(c,r, value); 00230 if (validValue) 00231 { 00232 //Multiply by the vertical scale. 00233 value *= _verticalScale; 00234 osg::Vec3d ndc, v; 00235 ndc.x() = ((double)c)/(double)(numColumns-1), 00236 ndc.y() = ((double)r)/(double)(numRows-1); 00237 ndc.z() = value; 00238 00239 if (_elevationLayer->getLocator()->convertLocalToModel(ndc, v)) 00240 { 00241 bb.expandBy(v); 00242 } 00243 } 00244 } 00245 } 00246 bs.expandBy(bb); 00247 00248 } 00249 else 00250 { 00251 for(ColorLayersByUID::const_iterator i = _colorLayers.begin(); i != _colorLayers.end(); ++i ) 00252 { 00253 bs.expandBy( i->second.computeBound() ); 00254 } 00255 } 00256 00257 return bs; 00258 } 00259 00260 void 00261 Tile::queueTileUpdate( TileUpdate::Action action, int value ) 00262 { 00263 _dirty = true; 00264 } 00265 00266 void 00267 Tile::applyImmediateTileUpdate( TileUpdate::Action action, int value ) 00268 { 00269 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( _tech.get() ); 00270 if ( tech ) 00271 { 00272 tech->compile( TileUpdate(action, value), 0L ); 00273 tech->applyTileUpdates(); 00274 } 00275 else 00276 { 00277 queueTileUpdate( action, value ); 00278 } 00279 } 00280 00281 void 00282 Tile::traverse( osg::NodeVisitor& nv ) 00283 { 00284 // set the parent tile in the technique: 00285 if ( !_parentTileSet && _terrain.valid() ) 00286 { 00287 osg::ref_ptr<Tile> parentTile; 00288 //Take a reference 00289 osg::ref_ptr< Terrain > terrain = _terrain.get(); 00290 if (terrain.valid()) 00291 { 00292 terrain->getTile( _key.createParentKey().getTileId(), parentTile ); 00293 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( _tech.get() ); 00294 if ( tech ) 00295 tech->setParentTile( parentTile.get() ); 00296 _parentTileSet = true; 00297 } 00298 } 00299 00300 // this block runs the first time the tile is traversed while in the scene graph. 00301 if ( !_hasBeenTraversed ) 00302 { 00303 if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR ) 00304 { 00305 Threading::ScopedWriteLock lock( this->_tileLayersMutex ); 00306 { 00307 if ( !_hasBeenTraversed && _terrain.valid() ) 00308 { 00309 _hasBeenTraversed = true; 00310 00311 // we constructed this tile with an update traversal count of 1 so it would get 00312 // here and we could register the tile. Now we can decrement it back to normal. 00313 // this MUST be called from the UPDATE traversal. 00314 ADJUST_UPDATE_TRAV_COUNT( this, -1 ); 00315 } 00316 } 00317 } 00318 } 00319 00320 // code copied from osgTerrain::TerrainTile... TODO: evaluate this... -gw 00321 if ( nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR ) 00322 { 00323 osg::ClusterCullingCallback* ccc = dynamic_cast<osg::ClusterCullingCallback*>(getCullCallback()); 00324 if (ccc) 00325 { 00326 if (ccc->cull(&nv,0,static_cast<osg::State *>(0))) return; 00327 } 00328 } 00329 00330 if ( _dirty ) 00331 { 00332 init(); 00333 } 00334 00335 if ( _tech.valid() ) 00336 { 00337 _tech->traverse( nv ); 00338 } 00339 } 00340 00341 void 00342 Tile::releaseGLObjects(osg::State* state) const 00343 { 00344 osg::Node::releaseGLObjects( state ); 00345 00346 if ( _tech.valid() ) 00347 { 00348 //NOTE: crashes sometimes if OSG_RELEASE_DELAY is set -gw 00349 _tech->releaseGLObjects( state ); 00350 } 00351 } 00352 00353 //------------------------------------------------------------------------ 00354 00355 TileFrame::TileFrame( Tile* tile ) : 00356 _tileKey(tile->getKey()) 00357 { 00358 Threading::ScopedReadLock sharedLock( tile->_tileLayersMutex ); 00359 _colorLayers = tile->_colorLayers; 00360 _elevationLayer = tile->getElevationLayer(); 00361 _locator = tile->getLocator(); 00362 osg::ref_ptr< Terrain > terrain = tile->getTerrain(); 00363 if (terrain.valid()) 00364 { 00365 _sampleRatio = terrain->getSampleRatio(); 00366 } 00367 _masks = MaskLayerVector(tile->getTerrainMasks()); 00368 }