TerrainTile 11.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
/* -*-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 <osg/Group>
#include <osg/CoordinateSystemNode>

#include <osgDB/ReaderWriter>

#include <osgTerrain/TerrainTechnique>
#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        
        {
            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 (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;
        }
        
        bool valid() const { return level>=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<TileLoadedCallback>& 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<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