/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2020 Pelican Mapping * http://osgearth.org * * osgEarth is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #ifndef OSGEARTH_OVERLAY_DECORATOR #define OSGEARTH_OVERLAY_DECORATOR #include #include #include #include #include #include #include #include #include namespace osgEarth { class TerrainEngineNode; } namespace osgEarth { namespace Util { class OverlayDecorator; class OverlayTechnique; /** * Overlays geometry onto the terrain using various techniques. */ class OSGEARTH_EXPORT OverlayDecorator : public osg::Group { public: OverlayDecorator(); /** * Adds a new overlay technique to the decorator. */ void addTechnique( OverlayTechnique* technique ); /** * Gets the group for nodes that are to be overlaid with * the specified Technique. */ template osg::Group* getGroup() { for(unsigned i=0; i<_techniques.size(); ++i ) { if ( dynamic_cast(_techniques[i].get()) ) return _overlayGroups[i].get(); } return 0L; } /** * The traversal mask to use when traversing the overlay groups. */ void setOverlayGraphTraversalMask( unsigned mask ); /** * Sets the maximum horizon distance to enforce when calculating * the draping extents. Constraining the distance will mean that you won't * see draped geometry past a certain point, but you will potentially get * higher quality for the geometry you do see (with fewer aliasing artifacts). */ double getMaxHorizonDistance() const; void setMaxHorizonDistance( double horizonDistance ); /** * Maximum height (above and below) the terrain MSL/ellipsoid at which * to drape geometry. Geometry above the max or below the -max will not * appear. This is only important to maintain Z buffering precision in the * draped geometry; however, it is usually a better idea to draw draped * geometry without blending or z-testing anyway. * Default is 500,000 meters. */ void setMaximumHeight(double value) { _maxHeight = value; } double getMaximumHeight() const { return _maxHeight; } /** * Initializes the decorator with a terrain engine */ void setTerrainEngine(TerrainEngineNode*); public: // osg::Node void traverse( osg::NodeVisitor& nv ); public: // osg::Object void resizeGLObjectBuffers(unsigned maxSize); void releaseGLObjects(osg::State* state) const; public: // NotiferGroup listener interface void onGroupChanged(osg::Group* group); protected: virtual ~OverlayDecorator() { } public: // RTT camera parameters for an overlay technique. There will be // one of these per technique, per view. struct TechRTTParams { osg::Camera* _mainCamera; // Camera to which this per-view data is attached osg::ref_ptr _rttCamera; // RTT camera. osg::Matrixd _rttViewMatrix; // View matrix of RTT camera osg::Matrixd _rttProjMatrix; // Projection matrix of RTT camera osg::Group* _group; // contains the overlay graphics osg::StateSet* _terrainStateSet; // same object as in PerViewData (shared across techniques) osg::ref_ptr _techniqueData; // technique sets this if needed const double* _horizonDistance; // points to the PVD horizon distance TerrainResources* _terrainResources; // for accessing image units osg::Vec3d _eyeWorld; // eyepoint in world coords osgShadow::ConvexPolyhedron _visibleFrustumPH; // polyhedron representing the frustum osg::ref_ptr _rttToPrimaryMatrixUniform; // xform from RTT cam to primary cam }; // One of these per view (camera). The terrain state set // if Shared almong all the techniques under a view. struct PerViewData { osg::Camera* _camera; // Camera to which this per-view data is attached std::vector _techParams; // Pre-view data for each technique osg::ref_ptr _sharedTerrainStateSet; // shared state set to apply to the terrain traversal double _sharedHorizonDistance; // horizon distnace (not used?) osg::Matrix _prevViewMatrix; // last frame's view matrix }; private: optional _explicitTextureUnit; optional _textureUnit; optional _textureSize; bool _isGeocentric; unsigned _rttTraversalMask; double _maxHeight; double _maxHorizonDistance; unsigned _totalOverlayChildren; osg::ref_ptr _srs; Ellipsoid _ellipsoid; osg::observer_ptr _engine; // Mapping of each RTT camera params vector to a Camera (per view data) using PerViewDataMap = std::unordered_map; PerViewDataMap _perViewData; mutable Threading::ReadWriteMutex _perViewDataMutex; typedef std::vector< osg::ref_ptr > Techniques; Techniques _techniques; Techniques _unsupportedTechniques; typedef std::vector< osg::ref_ptr > Groups; Groups _overlayGroups; private: void cullTerrainAndCalculateRTTParams( osgUtil::CullVisitor* cv, PerViewData& pvd ); void initializePerViewData( PerViewData&, osg::Camera* ); PerViewData& getPerViewData( osg::Camera* key ); public: // marker class for DrapeableNode support. struct InternalNodeVisitor : public osg::NodeVisitor { InternalNodeVisitor(const osg::NodeVisitor::TraversalMode& mode =osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) : osg::NodeVisitor(mode) { } }; //debugging: void requestDump() { _dumpRequested = true; } osg::Node* getDump() { osg::Node* r = _dump.release(); _dump = 0L; return r; } osg::ref_ptr _dump; bool _dumpRequested; }; /** * Abstract interface for an overlay technique implementation */ class OverlayTechnique : public osg::Referenced { protected: bool _supported; OverlayTechnique() : _supported(true) { } virtual ~OverlayTechnique() { } public: virtual bool supported() { return _supported; } virtual bool constrainOrthoZ() const { return false; } virtual bool hasData( OverlayDecorator::TechRTTParams& params) const { return true; } virtual const osg::BoundingSphere& getBound( OverlayDecorator::TechRTTParams& params) const { return params._group->getBound(); } virtual bool optimizeToVisibleBound() const { return false; } virtual void onInstall( TerrainEngineNode* engine ) { } virtual void onUninstall( TerrainEngineNode* engine ) { } virtual void reestablish( TerrainEngineNode* engine ) { } virtual void preCullTerrain( OverlayDecorator::TechRTTParams& params, osgUtil::CullVisitor* cv ) { } virtual void cullOverlayGroup( OverlayDecorator::TechRTTParams& params, osgUtil::CullVisitor* cv ) { } virtual void resizeGLObjectBuffers(unsigned maxSize) { } virtual void releaseGLObjects(osg::State* state) const { } }; } } // namespace osgEarth #endif //OSGEARTH_OVERLAY_DECORATOR