1/* -*-c++-*- */ 2/* osgEarth - Geospatial SDK for OpenSceneGraph 3* Copyright 2008-2014 Pelican Mapping 4* http://osgearth.org 5* 6* osgEarth is free software; you can redistribute it and/or modify 7* it under the terms of the GNU Lesser General Public License as published by 8* the Free Software Foundation; either version 2 of the License, or 9* (at your option) any later version. 10* 11* This program is distributed in the hope that it will be useful, 12* but WITHOUT ANY WARRANTY; without even the implied warranty of 13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14* GNU Lesser General Public License for more details. 15* 16* You should have received a copy of the GNU Lesser General Public License 17* along with this program. If not, see <http://www.gnu.org/licenses/> 18*/ 19#ifndef OSGEARTH_DRIVERS_REX_TERRAIN_ENGINE_GEOMETRY_POOL 20#define OSGEARTH_DRIVERS_REX_TERRAIN_ENGINE_GEOMETRY_POOL 1 21 22#include "Common" 23#include "MaskGenerator" 24#include "RexTerrainEngineOptions" 25#include <osgEarth/MapInfo> 26#include <osgEarth/TileKey> 27#include <osgEarth/ThreadingUtils> 28#include <osgEarth/ResourceReleaser> 29#include <osg/Geometry> 30 31#if OSG_MIN_VERSION_REQUIRED(3,5,9) 32#define SUPPORTS_VAO 1 33#endif 34 35namespace osgEarth { namespace Drivers { namespace RexTerrainEngine 36{ 37 using namespace osgEarth; 38 39 // Adapted from osgTerrain shared geometry class. 40 class /*internal*/ SharedGeometry : public osg::Drawable 41 { 42 public: 43 SharedGeometry(); 44 45 SharedGeometry(const SharedGeometry&, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); 46 47 META_Node(osgEarthRex, SharedGeometry); 48 49 void setVertexArray(osg::Array* array) { _vertexArray = array; } 50 osg::Array* getVertexArray() { return _vertexArray.get(); } 51 const osg::Array* getVertexArray() const { return _vertexArray.get(); } 52 53 void setNormalArray(osg::Array* array) { _normalArray = array; } 54 osg::Array* getNormalArray() { return _normalArray.get(); } 55 const osg::Array* getNormalArray() const { return _normalArray.get(); } 56 57 void setTexCoordArray(osg::Array* array) { _texcoordArray = array; } 58 osg::Array* getTexCoordArray() { return _texcoordArray.get(); } 59 const osg::Array* getTexCoordArray() const { return _texcoordArray.get(); } 60 61 void setNeighborArray(osg::Array* array) { _neighborArray = array; } 62 osg::Array* getNeighborArray() { return _neighborArray.get(); } 63 const osg::Array* getNeighborArray() const { return _neighborArray.get(); } 64 65 void setNeighborNormalArray(osg::Array* array) { _neighborNormalArray = array; } 66 osg::Array* getNeighborNormalArray() { return _neighborNormalArray.get(); } 67 const osg::Array* getNeighborNormalArray() const { return _neighborNormalArray.get(); } 68 69 void setDrawElements(osg::DrawElements* array) { _drawElements = array; } 70 osg::DrawElements* getDrawElements() { return _drawElements.get(); } 71 const osg::DrawElements* getDrawElements() const { return _drawElements.get(); } 72 73 void setMaskElements(osg::DrawElements* array) { _maskElements = array; } 74 osg::DrawElements* getMaskElements() { return _maskElements.get(); } 75 const osg::DrawElements* getMaskElements() const { return _maskElements.get(); } 76 77 // convert to a "real" geometry object 78 osg::Geometry* makeOsgGeometry(); 79 80 // whether this geometry contains anything 81 bool empty() const; 82 83 public: // osg::Drawable 84 85#ifdef SUPPORTS_VAO 86 osg::VertexArrayState* createVertexArrayStateImplementation(osg::RenderInfo& renderInfo) const; 87#endif 88 89 void drawImplementation(osg::RenderInfo& renderInfo) const; 90 91 void resizeGLObjectBuffers(unsigned int maxSize); 92 void releaseGLObjects(osg::State* state) const; 93 94 bool supports(const osg::Drawable::AttributeFunctor&) const { return true; } 95 void accept(osg::Drawable::AttributeFunctor&); 96 97 bool supports(const osg::Drawable::ConstAttributeFunctor&) const { return true; } 98 void accept(osg::Drawable::ConstAttributeFunctor&) const; 99 100 bool supports(const osg::PrimitiveFunctor&) const { return true; } 101 void accept(osg::PrimitiveFunctor&) const; 102 103 bool supports(const osg::PrimitiveIndexFunctor&) const { return true; } 104 void accept(osg::PrimitiveIndexFunctor&) const; 105 106 protected: 107 108 virtual ~SharedGeometry(); 109 110 osg::ref_ptr<osg::Array> _vertexArray; 111 osg::ref_ptr<osg::Array> _normalArray; 112 osg::ref_ptr<osg::Array> _colorArray; 113 osg::ref_ptr<osg::Array> _texcoordArray; 114 osg::ref_ptr<osg::Array> _neighborArray; 115 osg::ref_ptr<osg::Array> _neighborNormalArray; 116 osg::ref_ptr<osg::DrawElements> _drawElements; 117 osg::ref_ptr<osg::DrawElements> _maskElements; 118 119 private: 120 121 friend struct DrawTileCommand; 122 mutable osg::buffered_object<GLenum> _ptype; 123 }; 124 125 /** 126 * Pool of terrain tile geometries. 127 * 128 * In a geocentric map, every tile at a particular LOD and a particular latitudinal 129 * (north-south) extent shares exactly the same geometry; each tile is just shifted 130 * and rotated differently. Therefore we can use the same Geometry for all tiles that 131 * share the same LOD and same min/max latitude in a geocentric map. In a projected 132 * map, all tiles at a given LOD share the same geometry regardless of extent, so eve 133 * more sharing is possible. 134 * 135 * This object creates and returns geometries based on TileKeys, sharing instances 136 * whenever possible. Concept adapted from OSG's osgTerrain::GeometryPool. 137 */ 138 class GeometryPool : public osg::Group 139 { 140 public: 141 /** Construct the geometry pool */ 142 GeometryPool(const RexTerrainEngineOptions& options); 143 144 /** Sets an object to release unused GL resources */ 145 void setReleaser(ResourceReleaser* releaser); 146 147 public: 148 /** 149 * Hashtable key for unique (and therefore shareable) geometries. 150 */ 151 struct GeometryKey 152 { 153 GeometryKey() : 154 lod(-1), 155 tileY(0), 156 patch(false), 157 size(0u) 158 { 159 } 160 161 bool operator < (const GeometryKey& rhs) const 162 { 163 if (lod < rhs.lod) return true; 164 if (lod > rhs.lod) return false; 165 if (tileY < rhs.tileY) return true; 166 if (tileY > rhs.tileY) return false; 167 if (size < rhs.size) return true; 168 if (size > rhs.size) return false; 169 if (patch == false && rhs.patch == true) return true; 170 return false; 171 } 172 173 int lod; 174 int tileY; 175 bool patch; 176 unsigned size; 177 }; 178 179 typedef std::map<GeometryKey, osg::ref_ptr<SharedGeometry> > GeometryMap; 180 181 /** 182 * Gets the Geometry associated with a tile key, creating a new one if 183 * necessary and storing it in the pool. 184 */ 185 void getPooledGeometry( 186 const TileKey& tileKey, 187 const MapInfo& mapInfo, 188 unsigned tileSize, 189 MaskGenerator* maskSet, 190 osg::ref_ptr<SharedGeometry>& out); 191 192 /** 193 * The number of elements (incides) in the terrain skirt, if applicable 194 */ 195 int getNumSkirtElements(unsigned tileSize) const; 196 197 /** 198 * Are we doing pooling? 199 */ 200 bool isEnabled() const { return _enabled; } 201 202 /** 203 * Clear and reset the pool. 204 */ 205 void clear(); 206 207 208 public: // osg::Node 209 210 /** Perform an update traversal to check for unused resources. */ 211 void traverse(osg::NodeVisitor& nv); 212 213 protected: 214 virtual ~GeometryPool() { } 215 216 mutable Threading::Mutex _geometryMapMutex; 217 GeometryMap _geometryMap; 218 //unsigned _tileSize; 219 const RexTerrainEngineOptions& _options; 220 osg::ref_ptr<ResourceReleaser> _releaser; 221 222 mutable osg::ref_ptr<osg::Vec3Array> _sharedTexCoords; 223 224 void createKeyForTileKey( 225 const TileKey& tileKey, 226 unsigned size, 227 const MapInfo& mapInfo, 228 GeometryKey& out) const; 229 230 SharedGeometry* createGeometry( 231 const TileKey& tileKey, 232 const MapInfo& mapInfo, 233 unsigned tileSize, 234 MaskGenerator* maskSet ) const; 235 236 bool _enabled; 237 bool _debug; 238 }; 239 240} } } // namespace osgEarth::Drivers::RexTerrainEngine 241 242#endif // OSGEARTH_DRIVERS_REX_TERRAIN_ENGINE_GEOMETRY_POOL 243