142 lines
5.5 KiB
Plaintext
142 lines
5.5 KiB
Plaintext
|
/* -*-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 <http://www.gnu.org/licenses/>
|
||
|
*/
|
||
|
#ifndef OSGEARTH_GEOMETRY_CLOUD
|
||
|
#define OSGEARTH_GEOMETRY_CLOUD 1
|
||
|
|
||
|
#include <osgEarth/Common>
|
||
|
#include <osgEarth/GLUtils>
|
||
|
#include <osgEarth/TextureArena>
|
||
|
|
||
|
#include <osg/Geometry>
|
||
|
#include <osg/NodeVisitor>
|
||
|
|
||
|
#include <vector>
|
||
|
|
||
|
namespace osgEarth
|
||
|
{
|
||
|
/**
|
||
|
* Object that combines multiple models into a single GL_TRIANGLES geometry.
|
||
|
* This does two things:
|
||
|
*
|
||
|
* 1) Each time you call add(), the model is stripped down
|
||
|
* and transformed into a single primitive set. All state
|
||
|
* except for texture0 (and a normal map texture) will be lost.
|
||
|
* 2) The newly stripped geometry is appended to the One True
|
||
|
* Combined Geometry and its texture added to the combined
|
||
|
* atlas.
|
||
|
*
|
||
|
* You will end up with:
|
||
|
* - One GL_TRIANGLES geometry with one primitive set
|
||
|
* - One texture atlas
|
||
|
* - a DrawElementsIndirectCommand for each embedded model that you can
|
||
|
* use to call glDrawElementsIndirect or glMultiDrawElementsIndirect.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT GeometryCloud : public osg::NodeVisitor
|
||
|
{
|
||
|
public:
|
||
|
//! New geometry could that will store its textures in an arena.
|
||
|
//! @param arena Texture arena that will hold any textures
|
||
|
//! collected from node added to this cloud
|
||
|
GeometryCloud(TextureArena* arena);
|
||
|
|
||
|
//! Return from add()
|
||
|
struct AddResult
|
||
|
{
|
||
|
int _commandIndex;
|
||
|
//std::vector<Texture::Ptr> _textures;
|
||
|
};
|
||
|
|
||
|
//! Add a model to be incorporated into the cloud.
|
||
|
//! @param node Node whose geometry to add
|
||
|
//! @param texturesAdded Populated with any textures that were added
|
||
|
//! to the texture arena in the process of adding tis node
|
||
|
//! @param alignment If non-zero, pad the cloud's attribute arrays so
|
||
|
//! the index of the first vertex in this node is a multiple of the
|
||
|
//! alignment value. This is necessary for shaders that use gl_VertexID
|
||
|
//! as a modulus.
|
||
|
//! @param generateTextureHandles Whether to visit the node, add textures
|
||
|
//! to the arena, and generate texture handle vertex attribute. If false,
|
||
|
//! copy the pre-existing handles from the incoming geometry.
|
||
|
//! @param normalMapTextureImageUnit If the model contains normal map textures,
|
||
|
//! the TIU containing them. -1 = no normal maps.
|
||
|
//! @return Success: command number of the geometry; Failure: -1
|
||
|
AddResult add(
|
||
|
osg::Node* node,
|
||
|
unsigned alignment = 0,
|
||
|
int normalMapTextureImageUnit = -1);
|
||
|
|
||
|
//! The unified geometry
|
||
|
osg::Geometry* getGeometry() const { return _geom.get(); }
|
||
|
|
||
|
//! How many models were added
|
||
|
unsigned getNumDrawCommands() const { return _vertexOffsets.size(); }
|
||
|
|
||
|
//! Populates the i-th draw command from this cloud
|
||
|
//! @param[in] i Index of draw command to retrieve
|
||
|
//! @param[out] cmd Draw command output
|
||
|
//! @return True if [i] was in range, false if not
|
||
|
bool getDrawCommand(unsigned i, DrawElementsIndirectCommand& cmd) const;
|
||
|
|
||
|
//! Render the cloud
|
||
|
void draw(osg::RenderInfo& ri);
|
||
|
|
||
|
//! Whether this cloud contains any geometry
|
||
|
bool empty() const { return _vertexOffsets.empty(); }
|
||
|
|
||
|
//! Stateset supporting the geometry
|
||
|
osg::StateSet* getStateSet() { return _geom.valid() ? _geom->getStateSet() : nullptr; }
|
||
|
|
||
|
public: // osg::NodeVisitor
|
||
|
void apply(osg::Node& node) override;
|
||
|
void apply(osg::Transform& xform) override;
|
||
|
void apply(osg::Geometry& geom) override;
|
||
|
osg::ref_ptr<osg::Geometry> _geom;
|
||
|
|
||
|
private:
|
||
|
bool pushStateSet(osg::Node&);
|
||
|
void popStateSet();
|
||
|
|
||
|
osg::ref_ptr<TextureArena> _texarena;
|
||
|
osg::DrawElementsUShort* _primset;
|
||
|
osg::Vec3Array* _verts;
|
||
|
osg::Vec4Array* _colors;
|
||
|
osg::Vec3Array* _normals;
|
||
|
osg::Vec2Array* _texcoords;
|
||
|
osg::ShortArray* _albedoArenaIndices;
|
||
|
osg::ShortArray* _normalArenaIndices;
|
||
|
std::vector<unsigned> _vertexOffsets;
|
||
|
std::vector<unsigned> _elementOffsets;
|
||
|
std::vector<unsigned> _elementCounts;
|
||
|
|
||
|
//traversal data - must be cleared before each traversal
|
||
|
using ArenaIndexLUT = std::unordered_map<osg::Texture*, int>;
|
||
|
ArenaIndexLUT _arenaIndexLUT;
|
||
|
unsigned _numElements;
|
||
|
std::stack<int> _albedoArenaIndexStack;
|
||
|
std::stack<int> _normalArenaIndexStack;
|
||
|
std::stack<osg::Matrix> _matrixStack;
|
||
|
int _normalMapTextureImageUnit;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#endif // OSGEARTH_INSTANCE_CLOUD
|