Files
OpenSceneGraph/src/osgTerrain/Terrain.cpp

218 lines
6.7 KiB
C++

/* -*-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 <osgTerrain/Terrain>
#include <osgUtil/UpdateVisitor>
#include <iterator>
#include <OpenThreads/ScopedLock>
using namespace osg;
using namespace osgTerrain;
Terrain::Terrain():
_sampleRatio(1.0),
_verticalScale(1.0),
_blendingPolicy(TerrainTile::INHERIT),
_equalizeBoundaries(false)
{
setNumChildrenRequiringUpdateTraversal(1);
_geometryPool = new GeometryPool;
}
Terrain::Terrain(const Terrain& ts, const osg::CopyOp& copyop):
osg::CoordinateSystemNode(ts,copyop),
_sampleRatio(ts._sampleRatio),
_verticalScale(ts._verticalScale),
_blendingPolicy(ts._blendingPolicy),
_equalizeBoundaries(ts._equalizeBoundaries),
_geometryPool(ts._geometryPool),
_terrainTechnique(ts._terrainTechnique)
{
setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1);
}
Terrain::~Terrain()
{
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
for(TerrainTileSet::iterator itr = _terrainTileSet.begin();
itr != _terrainTileSet.end();
++itr)
{
const_cast<TerrainTile*>(*itr)->_terrain = 0;
}
_terrainTileSet.clear();
_terrainTileMap.clear();
}
void Terrain::setSampleRatio(float ratio)
{
if (_sampleRatio == ratio) return;
_sampleRatio = ratio;
dirtyRegisteredTiles();
}
void Terrain::setVerticalScale(float scale)
{
if (_verticalScale == scale) return;
_verticalScale = scale;
dirtyRegisteredTiles();
}
void Terrain::setEqualizeBoundaries(bool equalizeBoundaries)
{
if(_equalizeBoundaries == equalizeBoundaries) return;
_equalizeBoundaries = equalizeBoundaries;
dirtyRegisteredTiles();
}
void Terrain::setBlendingPolicy(TerrainTile::BlendingPolicy policy)
{
if (_blendingPolicy == policy) return;
_blendingPolicy = policy;
dirtyRegisteredTiles();
}
void Terrain::traverse(osg::NodeVisitor& nv)
{
if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR)
{
// need to check if any TerrainTechniques need to have their update called on them.
osgUtil::UpdateVisitor* uv = nv.asUpdateVisitor();
if (uv)
{
typedef std::list< osg::ref_ptr<TerrainTile> > TerrainTileList;
TerrainTileList tiles;
{
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
for(TerrainTileSet::iterator itr = _updateTerrainTileSet.begin(); itr !=_updateTerrainTileSet.end(); ++itr)
{
// take a reference first to make sure that the referenceCount can be safely read without another thread decrementing it to zero.
(*itr)->ref();
// only if referenceCount is 2 or more indicating there is still a reference held elsewhere is it safe to add it to list of tiles to be updated
if ((*itr)->referenceCount()>1) tiles.push_back(*itr);
// use unref_nodelete to avoid any issues when the *itr TerrainTile has been deleted by another thread while this for loop has been running.
(*itr)->unref_nodelete();
}
_updateTerrainTileSet.clear();
}
for(TerrainTileList::iterator itr = tiles.begin();
itr != tiles.end();
++itr)
{
TerrainTile* tile = itr->get();
tile->traverse(nv);
}
}
}
if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
{
osgUtil::CullVisitor* cv = nv.asCullVisitor();
osg::StateSet* ss = _geometryPool.valid() ? _geometryPool->getRootStateSetForTerrain(this) : 0;
if (cv && ss)
{
cv->pushStateSet(ss);
Group::traverse(nv);
cv->popStateSet();
return;
}
}
Group::traverse(nv);
}
void Terrain::updateTerrainTileOnNextFrame(TerrainTile* terrainTile)
{
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
_updateTerrainTileSet.insert(terrainTile);
}
TerrainTile* Terrain::getTile(const TileID& tileID)
{
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
// OSG_NOTICE<<"Terrain::getTile("<<tileID.level<<", "<<tileID.x<<", "<<tileID.y<<")"<<std::endl;
TerrainTileMap::iterator itr = _terrainTileMap.find(tileID);
if (itr == _terrainTileMap.end()) return 0;
return itr->second;
}
const TerrainTile* Terrain::getTile(const TileID& tileID) const
{
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
TerrainTileMap::const_iterator itr = _terrainTileMap.find(tileID);
if (itr == _terrainTileMap.end()) return 0;
return itr->second;
}
void Terrain::dirtyRegisteredTiles(int dirtyMask)
{
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
for(TerrainTileSet::iterator itr = _terrainTileSet.begin();
itr != _terrainTileSet.end();
++itr)
{
(const_cast<TerrainTile*>(*itr))->setDirtyMask(dirtyMask);
}
}
static unsigned int s_maxNumTiles = 0;
void Terrain::registerTerrainTile(TerrainTile* tile)
{
if (!tile) return;
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
if (tile->getTileID().valid())
{
_terrainTileMap[tile->getTileID()] = tile;
}
_terrainTileSet.insert(tile);
if (_terrainTileSet.size() > s_maxNumTiles) s_maxNumTiles = _terrainTileSet.size();
// OSG_NOTICE<<"Terrain::registerTerrainTile "<<tile<<" total number of tile "<<_terrainTileSet.size()<<" max = "<<s_maxNumTiles<<std::endl;
// OSG_NOTICE<<" tileID("<<tile->getTileID().level<<", "<<tile->getTileID().x<<", "<<tile->getTileID().y<<")"<<std::endl;
}
void Terrain::unregisterTerrainTile(TerrainTile* tile)
{
if (!tile) return;
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_mutex);
if (tile->getTileID().valid())
{
_terrainTileMap.erase(tile->getTileID());
}
_terrainTileSet.erase(tile);
_updateTerrainTileSet.erase(tile);
// OSG_NOTICE<<"Terrain::unregisterTerrainTile "<<tile<<" total number of tile "<<_terrainTileSet.size()<<" max = "<<s_maxNumTiles<<std::endl;
}