/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */ #ifndef SUB_GEOMETRY #define SUB_GEOMETRY #include #include #include #include #include #include #include class SubGeometry { public: typedef std::map::iterator BufferIterator; typedef std::map IndexMapping; SubGeometry(const osg::Geometry& source, const std::vector& triangles, const std::vector& lines, const std::vector& wireframe, const std::vector& points) { // Create new geometry as we will modify vertex arrays and primitives (the process is // equivalent to deep cloning). // As UserValues might be changed on a per-geometry basis afterwards, we deep clone userdata // We do *not* want to clone statesets as they reference a UniqueID that should be unique // (see #83056464). if(dynamic_cast(&source)) { _geometry = new osgAnimation::MorphGeometry; } else { _geometry = new osg::Geometry; } if(source.getUserDataContainer()) { _geometry->setUserDataContainer(osg::clone(source.getUserDataContainer(), osg::CopyOp::DEEP_COPY_ALL)); } if(source.getStateSet()) { _geometry->setStateSet(const_cast(source.getStateSet())); } addSourceBuffers(_geometry.get(), source); // process morph targets if needed if(const osgAnimation::MorphGeometry* morphSource = dynamic_cast(&source)) { osgAnimation::MorphGeometry* morph = dynamic_cast(_geometry.get()); const osgAnimation::MorphGeometry::MorphTargetList& morphTargetList = morphSource->getMorphTargetList(); osgAnimation::MorphGeometry::MorphTargetList::const_iterator targetSource; for(targetSource = morphTargetList.begin() ; targetSource != morphTargetList.end() ; ++ targetSource) { if(targetSource->getGeometry()) { osg::Geometry* target = new osg::Geometry; addSourceBuffers(target, *targetSource->getGeometry()); morph->addMorphTarget(target, targetSource->getWeight()); } } } // remap primitives indices by decreasing ordering (triangles > lines > wireframe > points) for(unsigned int i = 0 ; i < triangles.size() ; i += 3) { copyTriangle(triangles[i], triangles[i + 1], triangles[i + 2]); } for(unsigned int i = 0 ; i < lines.size() ; i += 2) { copyEdge(lines[i], lines[i + 1], false); } for(unsigned int i = 0 ; i < wireframe.size() ; i += 2) { copyEdge(wireframe[i], wireframe[i + 1], true); } for(unsigned int i = 0 ; i < points.size() ; ++ i) { copyPoint(points[i]); } // remap vertex buffers accordingly to primitives for(BufferIterator it = _bufferMap.begin() ; it != _bufferMap.end() ; ++ it) { if(it->first) { copyFrom(*(it->second), *(it->first)); } } } osg::Geometry* geometry() const { return _geometry.get(); } protected: void addSourceBuffers(osg::Geometry* geometry, const osg::Geometry& source) { // create necessary vertex containers const osg::Array* array = 0; geometry->setName(source.getName()); // collect all buffers that are BIND_PER_VERTEX for eventual vertex duplication if( (array = vertexArray(source.getVertexArray())) ) { geometry->setVertexArray(makeVertexBuffer(array)); } if( (array = vertexArray(source.getNormalArray())) ){ geometry->setNormalArray(makeVertexBuffer(array)); } if( (array = vertexArray(source.getColorArray())) ){ geometry->setColorArray(makeVertexBuffer(array)); } if( (array = vertexArray(source.getSecondaryColorArray())) ){ geometry->setSecondaryColorArray(makeVertexBuffer(array)); } if( (array = vertexArray(source.getFogCoordArray())) ){ geometry->setFogCoordArray(makeVertexBuffer(array)); } for(unsigned int i = 0; i < source.getNumVertexAttribArrays(); ++ i) { if( (array = vertexArray(source.getVertexAttribArray(i))) ){ geometry->setVertexAttribArray(i, makeVertexBuffer(array)); } } for(unsigned int i = 0; i < source.getNumTexCoordArrays(); ++ i) { if( (array = vertexArray(source.getTexCoordArray(i))) ){ geometry->setTexCoordArray(i, makeVertexBuffer(array)); } } } void copyTriangle(unsigned int v1, unsigned int v2, unsigned int v3) { osg::DrawElements* triangles = getOrCreateTriangles(); triangles->addElement(mapVertex(v1)); triangles->addElement(mapVertex(v2)); triangles->addElement(mapVertex(v3)); } void copyEdge(unsigned int v1, unsigned int v2, bool wireframe) { osg::DrawElements* edges = getOrCreateLines(wireframe); edges->addElement(mapVertex(v1)); edges->addElement(mapVertex(v2)); } void copyPoint(unsigned int v1) { osg::DrawElements* points = getOrCreatePoints(); points->addElement(mapVertex(v1)); } const osg::Array* vertexArray(const osg::Array* array) { // filter invalid vertex buffers if (array && array->getNumElements() && array->getBinding() == osg::Array::BIND_PER_VERTEX) { return array; } else { return 0; } } inline osg::Array* makeVertexBuffer(const osg::Array* array, bool copyUserData=true) { osg::Array* buffer = 0; if(array) { buffer = dynamic_cast(array->cloneType()); buffer->setBinding(osg::Array::BIND_PER_VERTEX); if(copyUserData && array->getUserDataContainer()) { buffer->setUserDataContainer(osg::clone(array->getUserDataContainer(), osg::CopyOp::DEEP_COPY_ALL)); } _bufferMap[buffer] = array; } return buffer; } template void copyValues(const C& src, C& dst) { dst.resize(_indexMap.size()); for(IndexMapping::const_iterator remapper = _indexMap.begin() ; remapper != _indexMap.end() ; ++ remapper) { dst[remapper->second] = src[remapper->first]; } } #define COPY_TEMPLATE(T) \ if (dynamic_cast(&src)) \ { return copyValues(dynamic_cast(src), dynamic_cast(dst)); } void copyFrom(const osg::Array& src, osg::Array& dst) { COPY_TEMPLATE(osg::Vec2Array); COPY_TEMPLATE(osg::Vec3Array); COPY_TEMPLATE(osg::Vec4Array); COPY_TEMPLATE(osg::Vec2dArray); COPY_TEMPLATE(osg::Vec3dArray); COPY_TEMPLATE(osg::Vec4dArray); COPY_TEMPLATE(osg::ByteArray); COPY_TEMPLATE(osg::ShortArray); COPY_TEMPLATE(osg::IntArray); COPY_TEMPLATE(osg::UByteArray); COPY_TEMPLATE(osg::UShortArray); COPY_TEMPLATE(osg::UIntArray); COPY_TEMPLATE(osg::FloatArray); COPY_TEMPLATE(osg::DoubleArray); COPY_TEMPLATE(osg::Vec2iArray); COPY_TEMPLATE(osg::Vec3iArray); COPY_TEMPLATE(osg::Vec4iArray); COPY_TEMPLATE(osg::Vec2uiArray); COPY_TEMPLATE(osg::Vec3uiArray); COPY_TEMPLATE(osg::Vec4uiArray); COPY_TEMPLATE(osg::Vec2sArray); COPY_TEMPLATE(osg::Vec3sArray); COPY_TEMPLATE(osg::Vec4sArray); COPY_TEMPLATE(osg::Vec2usArray); COPY_TEMPLATE(osg::Vec3usArray); COPY_TEMPLATE(osg::Vec4usArray); COPY_TEMPLATE(osg::Vec2bArray); COPY_TEMPLATE(osg::Vec3bArray); COPY_TEMPLATE(osg::Vec4bArray); COPY_TEMPLATE(osg::Vec2ubArray); COPY_TEMPLATE(osg::Vec3ubArray); COPY_TEMPLATE(osg::Vec4ubArray); COPY_TEMPLATE(osg::MatrixfArray); COPY_TEMPLATE(osg::QuatArray); } unsigned int mapVertex(unsigned int i) { if(_indexMap.find(i) == _indexMap.end()) { unsigned int index = _indexMap.size(); _indexMap[i] = index; } return _indexMap[i]; } osg::DrawElements* getOrCreateTriangles() { if(_primitives.find("triangles") == _primitives.end()) { _primitives["triangles"] = new osg::DrawElementsUInt(GL_TRIANGLES); _geometry->addPrimitiveSet(_primitives["triangles"]); } return _primitives["triangles"]; } osg::DrawElements* getOrCreateLines(bool wireframe) { std::string label = wireframe ? "wireframe" : "lines"; if(_primitives.find(label) == _primitives.end()) { _primitives[label] = new osg::DrawElementsUInt(GL_LINES); if(wireframe) { _primitives[label]->setUserValue("wireframe", true); } _geometry->addPrimitiveSet(_primitives[label]); } return _primitives[label]; } osg::DrawElements* getOrCreatePoints() { if(_primitives.find("points") == _primitives.end()) { _primitives["points"] = new osg::DrawElementsUInt(GL_POINTS); _geometry->addPrimitiveSet(_primitives["points"]); } return _primitives["points"]; } osg::ref_ptr _geometry; std::map _bufferMap; std::map _indexMap; std::map _primitives; }; #endif