/* -*-c++-*- */ /* osgEarth - Geospatial SDK for OpenSceneGraph * Copyright 2008-2012 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_OBJECT_INDEX_H #define OSGEARTH_OBJECT_INDEX_H #include #include #include #include #include #include #include #include #define OSGEARTH_OBJECTID_EMPTY (ObjectID)0 #define OSGEARTH_OBJECTID_TERRAIN (ObjectID)1 namespace osgEarth { typedef unsigned ObjectID; typedef osg::UIntArray ObjectIDArray; using namespace Util; /** * Virutal interface class for building an object index. */ template class ObjectIndexBuilder { public: /** * Inserts the object into the index, and tags the drawable with its object id. * Returns the ID of the object. */ virtual ObjectID tagDrawable(osg::Drawable* drawable, T* object) =0; /** * Inserts the object into the index, and tags all the drawalbes under the * specified node with the object ID. Returns the Object ID. */ virtual ObjectID tagAllDrawables(osg::Node* node, T* object) =0; /** * Inserts the object into the index, and tags the Node with a uniform containing * the object id. Returns the Object ID. */ virtual ObjectID tagNode(osg::Node* node, T* object) =0; /** * Inserts the object into the index, and tags the drawable's range with its object id. * Use this if you are already creating merged geometries in a single drawable. * Returns the ID of the object. */ virtual ObjectID tagRange(osg::Drawable* drawable, T* object, unsigned int start, unsigned int count) = 0; }; /** * Index for tracking objects in the scene graph using vertex * attributes and uniforms. */ class OSGEARTH_EXPORT ObjectIndex : public osg::Referenced, public ObjectIndexBuilder { public: /** constructs a new index */ ObjectIndex(); /** * Adds an object to the index, and returns a new globally unique * ID for that object. You can then use that UID to tag scene elements * with one of the tag* functions. If the object already exists in the * index, this method will return the UID assigned to it. */ ObjectID insert(osg::Referenced* object); /** * Finds the object corresponding to a unique ID and places it in "output"; * Returns true if found, false if not. */ template osg::ref_ptr get(ObjectID id) const { std::lock_guard lock(_mutex); return dynamic_cast( getImpl(id) ); } /** * Removes the object corresponding the the unique ID form the index. */ void remove(ObjectID id); /** * Removes a collection of objects from the index all at once. */ template void remove(ForwardIter i0, ForwardIter i1) { _mutex.lock(); for(ForwardIter i = i0; i != i1; ++i) removeImpl( *i ); _mutex.unlock(); } /** * The vertex attribute binding location to use when indexing geoemtry. * Warning: Changing this after tagging objects will cause undefined results. */ void setObjectIDAtrribLocation(int value); int getObjectIDAttribLocation() const { return _attribLocation; } /** * The name of the uniform used to tag nodes when tagNode() is called. */ const std::string& getObjectIDUniformName() const { return _oidUniformName; } /** * The name of the ObjectID vertex attribute in the ObjectIndex shaders. */ const std::string& getObjectIDAttribName() const { return _attribName; } /** * Convenience fuction to install shader components that will set the vertex-stage * ObjectID variable whenever detected in the geometry. This will automatically use * the ObjectID AttribLocation as set in this object. * * Returns false if the method fails for any reason (e.g., vp is NULL) */ bool loadShaders(VirtualProgram* vp) const; /** * The ShaderPackage that includes the index initialization shaders. installShaders() * calls this internally to get the virtual program components. */ const ShaderPackage& getShaderPackage() const { return _shaders; } /** * Returns a set of ObjectIDs used in a drawable. Returns false is none are found */ bool getObjectIDs(const osg::Drawable* drawable, std::set& output) const; /** * Returns an ObjectID set on a node. Returns false if none is found */ bool getObjectID(osg::Node* node, ObjectID& output) const; public: // ObjectIndexBuilder /** * Inserts the object into the index, and tags the drawable with its object id. * Returns the ID of the object. */ ObjectID tagDrawable(osg::Drawable* drawable, osg::Referenced* object); /** * Inserts the object into the index, and tags all the drawalbes under the * specified node with the object ID. Returns the Object ID. */ ObjectID tagAllDrawables(osg::Node* node, osg::Referenced* object); /** * Inserts the object into the index, and tags the Node with a uniform containing * the object id. Returns the Object ID. */ ObjectID tagNode(osg::Node* node, osg::Referenced* object); /** * Inserts the object into the index, and tags the drawable's range with its object id. * Use this if you are already creating merged geometries in a single drawable. * Returns the ID of the object. */ ObjectID tagRange(osg::Drawable* drawable, osg::Referenced* object, unsigned int start, unsigned int count); public: // Raw tagging methods. /** * Tags the vertices in a drawable with the object identifier. */ void tagDrawable(osg::Drawable* drawable, ObjectID id) const; /** * Tags the vertices in all Drawables until a node with the object identifier. */ void tagAllDrawables(osg::Node* node, ObjectID id) const; /** * Tags a node with an object identifier. This simply puts a uniform on the * node and does NOT tag any actual vertices. This is only useful if you want * to tag an entire model and are not planning to merge geometries. */ void tagNode(osg::Node* node, ObjectID id) const; /** * Tags the drawable's range with its object id. * Use this if you are already creating merged geometries in a single drawable. */ void tagRange(osg::Drawable* drawable, ObjectID id, unsigned int start, unsigned int count) const; /** * For each ObjectID found in a drawable, update it with a new Object ID and * populate an output table that maps the old ID to the new ID. Internal function * used for serialization support. */ bool updateObjectIDs(osg::Drawable* drawable, std::unordered_map& oldNewTable, osg::Referenced* obj); /** * On a node, replace an existing objectID with a new one and return the mapping. * Internal function used for serialization support. */ bool updateObjectID(osg::Node* node, std::unordered_map& oldNewTable, osg::Referenced* obj); protected: virtual ~ObjectIndex() { } using IndexMap = std::unordered_map>; IndexMap _index; int _attribLocation; std::string _oidUniformName; mutable std::mutex _mutex; std::atomic_int _idGen; ShaderPackage _shaders; std::string _attribName; ObjectID insertImpl(osg::Referenced*); void removeImpl(ObjectID id); osg::Referenced* getImpl(ObjectID id) const; }; } // namespace osgEarth #endif // OSGEARTH_OBJECT_INDEX_H