/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include using namespace osg; using namespace osgTerrain; ///////////////////////////////////////////////////////////////////////////////// // // TileID // TileID::TileID(): level(-1), x(-1), y(-1) { } TileID::TileID(int in_level, int in_x, int in_y): level(in_level), x(in_x), y(in_y) { } ///////////////////////////////////////////////////////////////////////////////// // // TerrainTile // void TerrainTile::setTileLoadedCallback(TerrainTile::TileLoadedCallback* lc) { getTileLoadedCallback() = lc; } osg::ref_ptr& TerrainTile::getTileLoadedCallback() { static osg::ref_ptr s_TileLoadedCallback; return s_TileLoadedCallback; } TerrainTile::TerrainTile(): _terrain(0), _dirtyMask(NOT_DIRTY), _hasBeenTraversal(false), _requiresNormals(true), _treatBoundariesToValidDataAsDefaultValue(false), _blendingPolicy(INHERIT) { setThreadSafeRefUnref(true); } TerrainTile::TerrainTile(const TerrainTile& terrain,const osg::CopyOp& copyop): Group(terrain,copyop), _terrain(0), _dirtyMask(NOT_DIRTY), _hasBeenTraversal(false), _elevationLayer(terrain._elevationLayer), _colorLayers(terrain._colorLayers), _requiresNormals(terrain._requiresNormals), _treatBoundariesToValidDataAsDefaultValue(terrain._treatBoundariesToValidDataAsDefaultValue), _blendingPolicy(terrain._blendingPolicy) { if (terrain.getTerrainTechnique()) { setTerrainTechnique(dynamic_cast(terrain.getTerrainTechnique()->clone(osg::CopyOp::SHALLOW_COPY))); } } TerrainTile::~TerrainTile() { if (_terrainTechnique.valid()) { _terrainTechnique->setTerrainTile(0); } if (_terrain) setTerrain(0); } void TerrainTile::setTerrain(Terrain* ts) { if (_terrain == ts) return; if (_terrain) _terrain->unregisterTerrainTile(this); _terrain = ts; if (_terrain) _terrain->registerTerrainTile(this); } void TerrainTile::setTileID(const TileID& tileID) { if (_tileID == tileID) return; if (_terrain) _terrain->unregisterTerrainTile(this); _tileID = tileID; if (_terrain) _terrain->registerTerrainTile(this); } void TerrainTile::traverse(osg::NodeVisitor& nv) { if (!_hasBeenTraversal) { if (!_terrain) { osg::NodePath& nodePath = nv.getNodePath(); if (!nodePath.empty()) { for(osg::NodePath::reverse_iterator itr = nodePath.rbegin(); itr != nodePath.rend() && !_terrain; ++itr) { osgTerrain::Terrain* ts = dynamic_cast(*itr); if (ts) { OSG_INFO<<"Assigning terrain system "<(getCullCallback()); if (ccc) { if (ccc->cull(&nv,0,static_cast(0))) return; } } if (_terrainTechnique.valid()) { _terrainTechnique->traverse(nv); } else { osg::Group::traverse(nv); } } void TerrainTile::init(int dirtyMask, bool assumeMultiThreaded) { if (!_terrainTechnique) { if (_terrain && _terrain->getTerrainTechniquePrototype()) { osg::ref_ptr object = _terrain->getTerrainTechniquePrototype()->clone(osg::CopyOp::DEEP_COPY_ALL); setTerrainTechnique(dynamic_cast(object.get())); } else { setTerrainTechnique(new GeometryTechnique); } } if (_terrainTechnique.valid()) { _terrainTechnique->init(dirtyMask|getDirtyMask(), assumeMultiThreaded); } } void TerrainTile::setTerrainTechnique(TerrainTechnique* terrainTechnique) { if (_terrainTechnique == terrainTechnique) return; if (_terrainTechnique.valid()) { _terrainTechnique->setTerrainTile(0); } _terrainTechnique = terrainTechnique; if (_terrainTechnique.valid()) { _terrainTechnique->setTerrainTile(this); setDirtyMask(ALL_DIRTY); } } void TerrainTile::setDirtyMask(int dirtyMask) { if (_dirtyMask==dirtyMask) return; int dirtyDelta = (_dirtyMask==NOT_DIRTY) ? 0 : -1; _dirtyMask = dirtyMask; if (_dirtyMask!=NOT_DIRTY) dirtyDelta += 1; // setNumChildrenRequeingUpdateTraversal() isn't thread safe so should avoid using it. if (dirtyDelta>0) { setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1); } else if (dirtyDelta<0 && getNumChildrenRequiringUpdateTraversal()>0) { setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()-1); } } void TerrainTile::setElevationLayer(Layer* layer) { _elevationLayer = layer; } void TerrainTile::setColorLayer(unsigned int i, Layer* layer) { if (_colorLayers.size() <= i) _colorLayers.resize(i+1); _colorLayers[i] = layer; } osg::BoundingSphere TerrainTile::computeBound() const { osg::BoundingSphere bs; if (_elevationLayer.valid()) { bs.expandBy(_elevationLayer->computeBound(true)); } else { for(Layers::const_iterator itr = _colorLayers.begin(); itr != _colorLayers.end(); ++itr) { if (itr->valid()) bs.expandBy((*itr)->computeBound(false)); } } return bs; } ///////////////////////////////////////////////////////////////////////////////// // // WhiteListTileLoadedCallback // WhiteListTileLoadedCallback::WhiteListTileLoadedCallback() { _minumumNumberOfLayers = 0; _replaceSwitchLayer = false; _allowAll = false; } WhiteListTileLoadedCallback::~WhiteListTileLoadedCallback() { } bool WhiteListTileLoadedCallback::layerAcceptable(const std::string& setname) const { if (_allowAll) return true; if (setname.empty()) return true; return _setWhiteList.count(setname)!=0; } bool WhiteListTileLoadedCallback::readImageLayer(osgTerrain::ImageLayer* imageLayer, const osgDB::ReaderWriter::Options* options) const { if (!imageLayer->getImage() && !imageLayer->getFileName().empty()) { if (layerAcceptable(imageLayer->getSetName())) { osg::ref_ptr image = osgDB::readRefImageFile(imageLayer->getFileName(), options); imageLayer->setImage(image.get()); } } return imageLayer->getImage()!=0; } bool WhiteListTileLoadedCallback::deferExternalLayerLoading() const { return true; } void WhiteListTileLoadedCallback::loaded(osgTerrain::TerrainTile* tile, const osgDB::ReaderWriter::Options* options) const { // read any external layers for(unsigned int i=0; igetNumColorLayers(); ++i) { osgTerrain::Layer* layer = tile->getColorLayer(i); osgTerrain::ImageLayer* color_imageLayer = dynamic_cast(layer); if (color_imageLayer) { readImageLayer(color_imageLayer, options); continue; } osgTerrain::SwitchLayer* switchLayer = dynamic_cast(layer); if (switchLayer) { for(unsigned int si=0; sigetNumLayers(); ++si) { osgTerrain::ImageLayer* imageLayer = dynamic_cast(switchLayer->getLayer(si)); if (imageLayer) { if (readImageLayer(imageLayer, options)) { // replace SwitchLayer by if (_replaceSwitchLayer) tile->setColorLayer(i, imageLayer); else if (switchLayer->getActiveLayer()<0) switchLayer->setActiveLayer(si); continue; } } } continue; } osgTerrain::CompositeLayer* compositeLayer = dynamic_cast(layer); if (compositeLayer) { for(unsigned int ci=0; cigetNumLayers(); ++ci) { osgTerrain::ImageLayer* imageLayer = dynamic_cast(compositeLayer->getLayer(ci)); if (imageLayer) { readImageLayer(imageLayer, options); } } continue; } } // assign colour layers over missing layers osgTerrain::Layer* validLayer = 0; for(unsigned int i=0; igetNumColorLayers(); ++i) { osgTerrain::Layer* layer = tile->getColorLayer(i); osgTerrain::ImageLayer* color_imageLayer = dynamic_cast(layer); if (color_imageLayer) { if (color_imageLayer->getImage()!=0) { validLayer = color_imageLayer; } continue; } osgTerrain::SwitchLayer* switchLayer = dynamic_cast(layer); if (switchLayer) { for(unsigned int si=0; sigetNumLayers(); ++si) { osgTerrain::ImageLayer* imageLayer = dynamic_cast(switchLayer->getLayer(si)); if (imageLayer && imageLayer->getImage()!=0) { validLayer = imageLayer; } } continue; } osgTerrain::CompositeLayer* compositeLayer = dynamic_cast(layer); if (compositeLayer) { for(unsigned int ci=0; cigetNumLayers(); ++ci) { osgTerrain::ImageLayer* imageLayer = dynamic_cast(switchLayer->getLayer(ci)); if (imageLayer && imageLayer->getImage()!=0) { validLayer = imageLayer; } } continue; } } if (validLayer) { // fill in any missing layers for(unsigned int i=0; igetNumColorLayers(); ++i) { osgTerrain::Layer* layer = tile->getColorLayer(i); osgTerrain::ImageLayer* color_imageLayer = dynamic_cast(layer); if (color_imageLayer) { if (color_imageLayer->getImage()==0) { tile->setColorLayer(i, validLayer); break; } continue; } osgTerrain::SwitchLayer* switchLayer = dynamic_cast(layer); if (switchLayer) { for(unsigned int si=0; sigetNumLayers(); ++si) { osgTerrain::ImageLayer* imageLayer = dynamic_cast(switchLayer->getLayer(si)); if (imageLayer && imageLayer->getImage()==0) { if (_replaceSwitchLayer) tile->setColorLayer(i, imageLayer); else { switchLayer->setLayer(si, validLayer); if (switchLayer->getActiveLayer()<0) switchLayer->setActiveLayer(si); } break; } } if (switchLayer->getNumLayers()==0) { if (_replaceSwitchLayer) tile->setColorLayer(i, validLayer); else { switchLayer->setLayer(0, validLayer); switchLayer->setActiveLayer(0); } } } osgTerrain::CompositeLayer* compositeLayer = dynamic_cast(layer); if (compositeLayer) { for(unsigned int ci=0; cigetNumLayers(); ++ci) { osgTerrain::ImageLayer* imageLayer = dynamic_cast(switchLayer->getLayer(ci)); if (imageLayer && imageLayer->getImage()==0) { tile->setColorLayer(i, validLayer); break; } } continue; } } if (_minumumNumberOfLayers>tile->getNumColorLayers()) { for(unsigned int i=tile->getNumColorLayers(); i<_minumumNumberOfLayers; ++i) { tile->setColorLayer(i, validLayer); } } } } void TerrainTile::releaseGLObjects(osg::State* state) const { Group::releaseGLObjects(state); if (_terrainTechnique.valid()) { _terrainTechnique->releaseGLObjects( state ); } }