/* -*-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. */ #ifndef OSGTERRAIN_TERRAINTILE #define OSGTERRAIN_TERRAINTILE 1 #include #include #include #include #include #include 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 { return (level==rhs.level) && (x==rhs.x) && (y==rhs.y); } bool operator != (const TileID& rhs) const { return (level!=rhs.level) || (x!=rhs.x) || (y!=rhs.y); } bool operator < (const TileID& rhs) const { if (levelrhs.level) return false; if (xrhs.x) return false; return y=0; } 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.*/ class OSGTERRAIN_EXPORT TerrainTile : public osg::Group { public: TerrainTile(); /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ TerrainTile(const TerrainTile&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); 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; } /** Set the TerrainTechnique*/ void setTerrainTechnique(TerrainTechnique* terrainTechnique); /** Get the TerrainTechnique*/ TerrainTechnique* getTerrainTechnique() { return _terrainTechnique.get(); } /** 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.*/ 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 _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 neigbours 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& getTileLoadedCallback(); /** 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: virtual ~TerrainTile(); typedef std::vector< osg::ref_ptr > Layers; friend class Terrain; Terrain* _terrain; int _dirtyMask; bool _hasBeenTraversal; TileID _tileID; osg::ref_ptr _terrainTechnique; osg::ref_ptr _locator; osg::ref_ptr _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 SetWhiteList; SetWhiteList _setWhiteList; unsigned int _minumumNumberOfLayers; bool _replaceSwitchLayer; bool _allowAll; }; } #endif