332 lines
12 KiB
C++
332 lines
12 KiB
C++
/* -*-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.
|
|
*
|
|
* This program 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
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
*/
|
|
#ifndef OSGEARTH_LINEDRAWABLE_H
|
|
#define OSGEARTH_LINEDRAWABLE_H 1
|
|
|
|
#include <osgEarth/Common>
|
|
#include <osgEarth/Threading>
|
|
#include <osg/Array>
|
|
#include <osg/Geometry>
|
|
|
|
namespace osgEarth
|
|
{
|
|
/**
|
|
* Drawable that renders lines using the GPU. It will fall back on rendering
|
|
* OpenGL lines when shader-based rendering is unavailable.
|
|
*
|
|
* Note: If you use this class you must have the oe_Camera
|
|
* uniform set. MapNode sets it automatically so any LineDrawable under
|
|
* a MapNode is fine. Otherwise, use the osgEarth::InstallCameraUniform
|
|
* callback on your scene graph.
|
|
*/
|
|
class OSGEARTH_EXPORT LineDrawable : public osg::Drawable
|
|
{
|
|
public:
|
|
|
|
//! Create a new LineDrawable.
|
|
//! @param[in ] mode GL line mode: GL_LINE_STRIP or GL_LINE_LOOP
|
|
LineDrawable(GLenum mode =GL_LINE_STRIP);
|
|
|
|
//! Copy constructor
|
|
LineDrawable(const LineDrawable& rhs, const osg::CopyOp& copy);
|
|
|
|
//! Width in pixels of the line
|
|
void setLineWidth(float width_pixels);
|
|
float getLineWidth() const { return _width; }
|
|
|
|
//! Stippling pattern for the line (default is 0xFFFF)
|
|
void setStipplePattern(GLushort pattern);
|
|
GLushort getStipplePattern() const { return _pattern; }
|
|
|
|
//! Stippling factor for the line (default is 1)
|
|
void setStippleFactor(GLint factor);
|
|
GLint getStippleFactor() const { return _factor; }
|
|
|
|
//! Stippling quantization factor (default is 8.0)
|
|
void setStippleQuantize(GLfloat factor);
|
|
GLfloat getStippleQuantize() const { return _quantize; }
|
|
|
|
//! Line smoothing (antialiasing)
|
|
void setLineSmooth(bool value);
|
|
bool getLineSmooth() const { return _smooth; }
|
|
|
|
//! Sets the overall color of the line
|
|
void setColor(const osg::Vec4& color);
|
|
const osg::Vec4& getColor() const { return _color; }
|
|
|
|
//! Append a vertex to the line
|
|
void pushVertex(const osg::Vec3& vert);
|
|
|
|
//! Set the value of a vertex at index i
|
|
void setVertex(unsigned i, const osg::Vec3& vert);
|
|
|
|
//! Gets the vertex at index i
|
|
const osg::Vec3& getVertex(unsigned i) const;
|
|
|
|
//! Sets the color of a vertex at index i
|
|
void setColor(unsigned i, const osg::Vec4& color);
|
|
|
|
//! Sets whether to use a GPU shader to draw lines. Default=true.
|
|
//! Set this to false to invoke legacy OpenGL line drawing, which
|
|
//! may be a bit faster but will not support GL CORE profile or GLES.
|
|
//! NOTE: Calling this will remove any data you've added to the LineDrawable!
|
|
void setUseGPU(bool value);
|
|
bool getUseGPU() const { return _useGPU; }
|
|
|
|
//! Copy a vertex array into the drawable
|
|
void importVertexArray(const osg::Vec3Array* verts);
|
|
|
|
//! Copy a vertex attribute array into the drawable
|
|
template<typename T>
|
|
void importVertexAttribArray(unsigned location, const T* data);
|
|
|
|
//! Allocate space for vertices
|
|
void allocate(unsigned numVerts);
|
|
|
|
//! Clears all data
|
|
void clear();
|
|
|
|
//! Whether the size is zero.
|
|
bool empty() const { return size() == 0; }
|
|
|
|
//! Number of vertices in the drawable
|
|
unsigned getNumVerts() const;
|
|
|
|
//! Number of vertices in the drawable
|
|
unsigned size() const { return getNumVerts(); }
|
|
|
|
//! Appends a vertex to an attribute array. Use this instead of adding
|
|
//! to the array directly!
|
|
template<typename T>
|
|
void pushVertexAttrib(T* vaa, const typename T::ElementDataType& value);
|
|
|
|
//! Gets the value of the vertex attribute from an array at index i
|
|
template<typename T>
|
|
const typename T::ElementDataType& getVertexAttrib(const T* vaa, unsigned i) const;
|
|
|
|
//! Pre-allocate space for vertices
|
|
void reserve(unsigned size);
|
|
|
|
//! Index of the first vertex to draw (default = 0)
|
|
void setFirst(unsigned index);
|
|
unsigned getFirst() const;
|
|
|
|
//! Number of vertices to draw (default = 0, which means draw to the
|
|
//! end of the line
|
|
void setCount(unsigned count);
|
|
unsigned getCount() const;
|
|
|
|
//! Rebuild the primitive sets for this drawable. You MUST call this
|
|
//! after adding new data to the drawable!
|
|
void dirty();
|
|
void finish() { dirty(); }
|
|
|
|
//! Sets a vertex attribute array at the designated index.
|
|
//! The array must be EMPTY.
|
|
void setVertexAttribArray(unsigned i, osg::Array* a);
|
|
|
|
//! Sets a line width on a custom stateset that will apply to
|
|
//! all LineDrawables used with that state set.
|
|
static void setLineWidth(osg::StateSet* stateSet, float value, int overrideFlags=osg::StateAttribute::ON);
|
|
|
|
public:
|
|
|
|
//! Binding location for "previous" vertex attribute (default = 9)
|
|
static int PreviousVertexAttrLocation;
|
|
|
|
//! Binding location for "next" vertex attribute (default = 10)
|
|
static int NextVertexAttrLocation;
|
|
|
|
public: // osg::Node
|
|
|
|
//! Replace methods from META_Node so we can override accept
|
|
virtual osg::Object* cloneType() const override { return new LineDrawable(); }
|
|
virtual osg::Object* clone(const osg::CopyOp& copyop) const override { return new LineDrawable(*this,copyop); }
|
|
virtual bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const LineDrawable*>(obj)!=nullptr; }
|
|
virtual const char* className() const override { return "LineDrawable"; }
|
|
virtual const char* libraryName() const override { return "osgEarth"; }
|
|
|
|
//! Override Node::accept to include the singleton GPU statset
|
|
void accept(osg::NodeVisitor& nv) override;
|
|
|
|
public: // osg::Object
|
|
|
|
virtual void resizeGLObjectBuffers(unsigned maxSize) override;
|
|
virtual void releaseGLObjects(osg::State* state) const override;
|
|
|
|
public:
|
|
|
|
//! GL mode (for serializer only; do not use)
|
|
void setMode(GLenum mode);
|
|
GLenum getMode() const { return _mode; }
|
|
|
|
osg::StateSet* getGPUStateSet() const { return _gpuStateSet.get(); }
|
|
|
|
protected:
|
|
|
|
//! destructor
|
|
virtual ~LineDrawable();
|
|
|
|
private:
|
|
GLenum _mode;
|
|
bool _useGPU;
|
|
osg::Vec4 _color;
|
|
GLint _factor;
|
|
GLushort _pattern;
|
|
GLfloat _quantize;
|
|
float _width;
|
|
bool _smooth;
|
|
unsigned _first;
|
|
unsigned _count;
|
|
osg::Vec3Array* _current;
|
|
osg::Vec3Array* _previous;
|
|
osg::Vec3Array* _next;
|
|
osg::Vec4Array* _colors;
|
|
|
|
void initialize();
|
|
void setupShaders();
|
|
|
|
friend class LineGroup;
|
|
|
|
unsigned actualVertsPerVirtualVert(unsigned) const;
|
|
unsigned numVirtualVerts(const osg::Array*) const;
|
|
unsigned getRealIndex(unsigned) const;
|
|
void updateFirstCount();
|
|
|
|
//static osg::observer_ptr<osg::StateSet> s_gpuStateSet;
|
|
osg::ref_ptr<osg::StateSet> _gpuStateSet;
|
|
mutable std::mutex _mutex;
|
|
osg::ref_ptr<osg::Geometry> _geom;
|
|
|
|
public: // osg::Drawable pass thrus
|
|
|
|
virtual void drawImplementation(osg::RenderInfo& ri) const override;
|
|
|
|
void traverse(osg::NodeVisitor& nv) override;
|
|
|
|
virtual osg::BoundingSphere computeBound() const override {
|
|
return _geom->computeBound();
|
|
}
|
|
virtual osg::BoundingBox computeBoundingBox() const override {
|
|
return _geom->computeBoundingBox();
|
|
}
|
|
virtual bool supports(const AttributeFunctor& f) const override {
|
|
return _geom->supports(f);
|
|
}
|
|
virtual void accept(AttributeFunctor& f) override {
|
|
return _geom->accept(f);
|
|
}
|
|
virtual bool supports(const ConstAttributeFunctor& f) const override {
|
|
return _geom->supports(f);
|
|
}
|
|
virtual void accept(ConstAttributeFunctor& f) const override {
|
|
return _geom->accept(f);
|
|
}
|
|
virtual bool supports(const osg::PrimitiveFunctor& f) const override {
|
|
return _geom->supports(f);
|
|
}
|
|
virtual void accept(osg::PrimitiveFunctor& f) const override {
|
|
return _geom->accept(f);
|
|
}
|
|
virtual bool supports(const osg::PrimitiveIndexFunctor& f) const override {
|
|
return _geom->supports(f);
|
|
}
|
|
virtual void accept(osg::PrimitiveIndexFunctor& f) const {
|
|
return _geom->accept(f);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Group for importing LineDrawables from osg::Geometry or for
|
|
* optimizing multiple LineDrawables for performance.
|
|
*
|
|
* Note: LineGroup inherits from Geode (for now) to maintain support for
|
|
* the OSG 3.4 MergeGeometryVisitor (which only works on Geodes). Once we
|
|
* make OSG 3.6 the minimum supported version, we can change this to Group.
|
|
*/
|
|
class OSGEARTH_EXPORT LineGroup : public osg::Group
|
|
{
|
|
public:
|
|
META_Node(osgEarth, LineGroup);
|
|
|
|
//! Construct a new line group
|
|
LineGroup();
|
|
|
|
//! Copy constructor
|
|
LineGroup(const LineGroup& rhs, const osg::CopyOp& copy);
|
|
|
|
//! Imports any GL line drawables from a node graph, converts them
|
|
//! to LineDrawables, and adds them to this LineGroup. If will detect
|
|
//! and set any LineWidth or LineStipple attributes it finds, but will not
|
|
//! find any attributes that occur in the graph above the imported node.
|
|
//!
|
|
//! If you set removePrimitiveSets to true, it will remove all line-based
|
|
//! primitive sets from the node after import.
|
|
//!
|
|
//! This method is for quickly importing legacy scene graphs; if you are
|
|
//! writing new code, use the LineDrawable API directly instead!
|
|
void import(osg::Node* node, bool removePrimitiveSets =false);
|
|
|
|
//! Optimize the LineDrawables under this group for performance.
|
|
//! Only call this after you finish adding drawables to your group.
|
|
//! It will attempt to combine drawables and state sets, but it will also
|
|
//! render the graph henceforth immutable.
|
|
void optimize();
|
|
|
|
//! Get child i as a LineDrawable
|
|
LineDrawable* getLineDrawable(unsigned i);
|
|
|
|
protected:
|
|
//! destructor
|
|
virtual ~LineGroup();
|
|
};
|
|
|
|
|
|
// Template implementations ..........................................
|
|
|
|
template<typename T>
|
|
void LineDrawable::pushVertexAttrib(T* vaa, const typename T::ElementDataType& value)
|
|
{
|
|
unsigned nvv = numVirtualVerts(vaa);
|
|
unsigned num = actualVertsPerVirtualVert(nvv);
|
|
for (unsigned i = 0; i<num; ++i)
|
|
vaa->push_back(value);
|
|
}
|
|
|
|
template<typename T>
|
|
const typename T::ElementDataType& LineDrawable::getVertexAttrib(const T* vaa, unsigned i) const
|
|
{
|
|
return (*vaa)[getRealIndex(i)];
|
|
}
|
|
|
|
template<typename T>
|
|
void LineDrawable::importVertexAttribArray(unsigned location, const T* data)
|
|
{
|
|
T* vaa = osg::cloneType(data);
|
|
_geom->setVertexAttribArray(location, vaa);
|
|
for (unsigned i=0; i < data->getNumElements(); ++i)
|
|
pushVertexAttrib(vaa, (*data)[i]);
|
|
}
|
|
|
|
} // namespace osgEarth
|
|
|
|
#endif // OSGEARTH_LINEDRAWABLE_H
|