OpenSceneGraph/include/osgTerrain/TerrainTile

294 lines
11 KiB
Plaintext
Raw Normal View History

/* -*-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.
*/
2008-03-27 18:55:39 +08:00
#ifndef OSGTERRAIN_TERRAINTILE
#define OSGTERRAIN_TERRAINTILE 1
#include <osg/Group>
#include <osg/CoordinateSystemNode>
#include <osgDB/ReaderWriter>
#include <osgTerrain/TerrainTechnique>
2007-03-19 18:54:39 +08:00
#include <osgTerrain/Layer>
#include <osgTerrain/Locator>
namespace osgTerrain {
class Terrain;
class OSGTERRAIN_EXPORT TileID
{
public:
TileID();
TileID(int in_level, int in_x, int in_y);
bool operator == (const TileID& rhs) const
{
2008-09-20 23:43:38 +08:00
return (level==rhs.level) && (x==rhs.x) && (y==rhs.y);
}
bool operator != (const TileID& rhs) const
{
2008-09-20 23:43:38 +08:00
return (level!=rhs.level) || (x!=rhs.x) || (y!=rhs.y);
}
bool operator < (const TileID& rhs) const
{
2008-09-20 23:43:38 +08:00
if (level<rhs.level) return true;
if (level>rhs.level) return false;
if (x<rhs.x) return true;
if (x>rhs.x) return false;
return y<rhs.y;
}
2008-09-20 23:43:38 +08:00
bool valid() const { return level>=0; }
2008-09-20 23:43:38 +08:00
int level;
int x;
int y;
};
/** Terrain provides a framework for loosely coupling height field data with height rendering algorithms.
* This allows TerrainTechnique's to be plugged in at runtime.*/
2008-03-27 18:55:39 +08:00
class OSGTERRAIN_EXPORT TerrainTile : public osg::Group
{
public:
2008-03-27 18:55:39 +08:00
TerrainTile();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
2008-03-27 18:55:39 +08:00
TerrainTile(const TerrainTile&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
2008-03-27 18:55:39 +08:00
META_Node(osgTerrain, TerrainTile);
virtual void traverse(osg::NodeVisitor& nv);
/** Call init on any attached TerrainTechnique.*/
void init(int dirtyMask, bool assumeMultiThreaded);
/** Set the Terrain that this Terrain tile is a member of.*/
void setTerrain(Terrain* ts);
/** Get the Terrain that this Terrain tile is a member of.*/
Terrain* getTerrain() { return _terrain; }
/** Get the const Terrain that this Terrain tile is a member of.*/
const Terrain* getTerrain() const { return _terrain; }
/** Set the TileID (layer, x,y) of the TerrainTile.
* The TileID is used so it can be located by its neighbours
* via the enclosing Terrain node that manages a map of TileID to TerraiTiles.*/
void setTileID(const TileID& tileID);
/** Get the TileID (layer, x,y) of the TerrainTile.*/
const TileID& getTileID() const { return _tileID; }
2007-03-19 18:54:39 +08:00
/** Set the TerrainTechnique*/
void setTerrainTechnique(TerrainTechnique* terrainTechnique);
2007-03-19 18:54:39 +08:00
/** Get the TerrainTechnique*/
TerrainTechnique* getTerrainTechnique() { return _terrainTechnique.get(); }
2007-03-19 18:54:39 +08:00
/** Get the const TerrainTechnique*/
const TerrainTechnique* getTerrainTechnique() const { return _terrainTechnique.get(); }
/** Set the coordinate frame locator of the terrain node.
* The locator takes non-dimensional s,t coordinates into the X,Y,Z world coords and back.*/
void setLocator(Locator* locator) { _locator = locator; }
/** Get the coordinate frame locator of the terrain node.*/
Locator* getLocator() { return _locator.get(); }
/** Get the const coordinate frame locator of the terrain node.*/
const Locator* getLocator() const { return _locator.get(); }
/** Set the layer to use to define the elevations of the terrain.*/
void setElevationLayer(Layer* layer);
/** Get the layer to use to define the elevations of the terrain.*/
Layer* getElevationLayer() { return _elevationLayer.get(); }
/** Get the const layer to use to define the elevations of the terrain.*/
const Layer* getElevationLayer() const { return _elevationLayer.get(); }
/** Set a color layer with specified layer number.*/
2008-03-27 18:55:39 +08:00
void setColorLayer(unsigned int i, Layer* layer);
/** Get color layer with specified layer number.*/
Layer* getColorLayer(unsigned int i) { return i<_colorLayers.size() ? _colorLayers[i].get() : 0; }
/** Set const color layer with specified layer number.*/
const Layer* getColorLayer(unsigned int i) const { return i<_colorLayers.size() ? _colorLayers[i].get() : 0; }
/** Get the number of colour layers.*/
unsigned int getNumColorLayers() const { return static_cast<unsigned int>(_colorLayers.size()); }
/** Set hint to whether the TerrainTechnique should create per vertex normals for lighting purposes.*/
void setRequiresNormals(bool flag) { _requiresNormals = flag; }
/** Get whether the TerrainTechnique should create per vertex normals for lighting purposes.*/
bool getRequiresNormals() const { return _requiresNormals; }
/** Set the hint to whether the TerrainTechnique should treat the invalid Layer entries that at are neighbours to valid entries with the default value.*/
void setTreatBoundariesToValidDataAsDefaultValue(bool flag) { _treatBoundariesToValidDataAsDefaultValue = flag; }
/** Get whether the TeatBoundariesToValidDataAsDefaultValue hint.*/
bool getTreatBoundariesToValidDataAsDefaultValue() const { return _treatBoundariesToValidDataAsDefaultValue; }
enum BlendingPolicy
{
INHERIT, /** Default - check for the any BlendingPolicy set on the enclosing osgTerrain::Terrain node, and if it's also INHERIT then assume ENABLE_BLENDING_WHEN_ALPHA_PRESENT. */
DO_NOT_SET_BLENDING,
ENABLE_BLENDING,
ENABLE_BLENDING_WHEN_ALPHA_PRESENT /** check colour layers for alpha value and if present enable blending. */
};
/** Set the policy to use when deciding whether to enable/disable blending and use of transparent bin.*/
void setBlendingPolicy(BlendingPolicy policy) { _blendingPolicy = policy; }
/** Get the policy to use when deciding whether to enable/disable blending and use of transparent bin.*/
BlendingPolicy getBlendingPolicy() const { return _blendingPolicy; }
enum DirtyMask
{
NOT_DIRTY = 0,
IMAGERY_DIRTY = 1<<0,
ELEVATION_DIRTY = 1<<1,
LEFT_EDGE_DIRTY = 1<<2,
RIGHT_EDGE_DIRTY = 1<<3,
TOP_EDGE_DIRTY = 1<<4,
TOP_LEFT_CORNER_DIRTY = 1<<5,
TOP_RIGHT_CORNER_DIRTY = 1<<6,
BOTTOM_EDGE_DIRTY = 1<<7,
BOTTOM_LEFT_CORNER_DIRTY = 1<<8,
BOTTOM_RIGHT_CORNER_DIRTY = 1<<9,
EDGES_DIRTY = LEFT_EDGE_DIRTY | RIGHT_EDGE_DIRTY | TOP_EDGE_DIRTY | BOTTOM_EDGE_DIRTY |
TOP_LEFT_CORNER_DIRTY | TOP_RIGHT_CORNER_DIRTY | BOTTOM_LEFT_CORNER_DIRTY | BOTTOM_RIGHT_CORNER_DIRTY,
ALL_DIRTY = IMAGERY_DIRTY | ELEVATION_DIRTY | EDGES_DIRTY
};
/** Set the dirty flag on/off.*/
void setDirty(bool dirty) { setDirtyMask(dirty ? ALL_DIRTY : NOT_DIRTY); }
/** return true if the any of the DirtyMask are set.*/
int getDirty() const { return _dirtyMask!=NOT_DIRTY; }
/** Set the dirty flag on/off.*/
void setDirtyMask(int dirtyMask);
/** return true if the tile is dirty and needs to be updated,*/
int getDirtyMask() const { return _dirtyMask; }
/** Compute the bounding volume of the terrain by computing the union of the bounding volumes of all layers.*/
virtual osg::BoundingSphere computeBound() const;
/** Callback for post processing loaded TerrainTile, and for filling in missing elements such as external external imagery.*/
struct TileLoadedCallback : public osg::Referenced
{
virtual bool deferExternalLayerLoading() const = 0;
virtual void loaded(osgTerrain::TerrainTile* tile, const osgDB::ReaderWriter::Options* options) const = 0;
};
static void setTileLoadedCallback(TileLoadedCallback* lc);
static osg::ref_ptr<TileLoadedCallback>& getTileLoadedCallback();
From Jason Beverage, "I posted a question on osg users about resources not being properly released when using osgTerrain databases and multiple viewers are used a few weeks ago and I've found that at least part of the problem comes down to the fact that the nodes that are traversed by the GeometryTechnique are never actually added to the scene graph, and thus don't have releaseGLObjects called on them. I'm submitting a few changes that takes care of this by allowing the TerrainTechnique to provide a releaseGLObjects implementation. I've applied these changes in osgEarth and this example program no longer crashes on the second run, although I get corrupt geometry (see attached shot) which could be down to a driver issue. If I increment the context ID for the second viewer, I no longer get the corrupt geometry. The attached changes are against OpenSceneGraph 2.8.2. //Sample program. Run against an osgEarth or VPB database based on osgTerrain. #include <osgDB/ReadFile> #include <osgViewer/Viewer> int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); osgViewer::Viewer* viewer = new osgViewer::Viewer(); viewer->setUpViewInWindow(100, 100,500,500); osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments); viewer->setSceneData( loadedModel.get() ); viewer->run(); delete viewer; viewer = new osgViewer::Viewer(); viewer->setUpViewInWindow(100,100,500,500); loadedModel = osgDB::readNodeFiles(arguments); viewer->setSceneData( loadedModel.get() ); viewer->run(); delete viewer; }"
2009-11-20 19:08:40 +08:00
/** If State is non-zero, this function releases any associated OpenGL objects for
* the specified graphics context. Otherwise, releases OpenGL objects
* for all graphics contexts. */
virtual void releaseGLObjects(osg::State* = 0) const;
protected:
2008-03-27 18:55:39 +08:00
virtual ~TerrainTile();
typedef std::vector< osg::ref_ptr<Layer> > Layers;
friend class Terrain;
Terrain* _terrain;
int _dirtyMask;
bool _hasBeenTraversal;
TileID _tileID;
osg::ref_ptr<TerrainTechnique> _terrainTechnique;
osg::ref_ptr<Locator> _locator;
osg::ref_ptr<Layer> _elevationLayer;
Layers _colorLayers;
bool _requiresNormals;
bool _treatBoundariesToValidDataAsDefaultValue;
BlendingPolicy _blendingPolicy;
};
/** Helper callback for managing optional sets of layers, that loading of is deffered to this callback,
* with this callback working out which layers to load, and how to create fallback versions of the layers.
*/
class OSGTERRAIN_EXPORT WhiteListTileLoadedCallback : public TerrainTile::TileLoadedCallback
{
public:
WhiteListTileLoadedCallback();
void allow(const std::string& setname) { _setWhiteList.insert(setname); }
void setMinimumNumOfLayers(unsigned int numLayers) { _minumumNumberOfLayers = numLayers; }
unsigned int getMinimumNumOfLayers() const { return _minumumNumberOfLayers; }
void setReplaceSwitchLayer(bool replaceSwitchLayer) { _replaceSwitchLayer = replaceSwitchLayer; }
bool getReplaceSwitchLayer() const { return _replaceSwitchLayer; }
void setAllowAll(bool allowAll) { _allowAll = allowAll; }
bool getAllowAll() const { return _allowAll; }
bool layerAcceptable(const std::string& setname) const;
bool readImageLayer(osgTerrain::ImageLayer* imageLayer, const osgDB::ReaderWriter::Options* options) const;
virtual bool deferExternalLayerLoading() const;
virtual void loaded(osgTerrain::TerrainTile* tile, const osgDB::ReaderWriter::Options* options) const;
protected:
virtual ~WhiteListTileLoadedCallback();
typedef std::set<std::string> SetWhiteList;
SetWhiteList _setWhiteList;
unsigned int _minumumNumberOfLayers;
bool _replaceSwitchLayer;
bool _allowAll;
};
}
#endif