/* -*-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_GEOMETRY_CLOUD #define OSGEARTH_GEOMETRY_CLOUD 1 #include #include #include #include #include #include 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 _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 _geom; private: bool pushStateSet(osg::Node&); void popStateSet(); osg::ref_ptr _texarena; osg::DrawElementsUShort* _primset; osg::Vec3Array* _verts; osg::Vec4Array* _colors; osg::Vec3Array* _normals; osg::Vec2Array* _texcoords; osg::ShortArray* _albedoArenaIndices; osg::ShortArray* _normalArenaIndices; std::vector _vertexOffsets; std::vector _elementOffsets; std::vector _elementCounts; //traversal data - must be cleared before each traversal using ArenaIndexLUT = std::unordered_map; ArenaIndexLUT _arenaIndexLUT; unsigned _numElements; std::stack _albedoArenaIndexStack; std::stack _normalArenaIndexStack; std::stack _matrixStack; int _normalMapTextureImageUnit; }; } #endif // OSGEARTH_INSTANCE_CLOUD