281 lines
9.7 KiB
C++
281 lines
9.7 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) Sketchfab */
|
|
|
|
#ifndef SUB_GEOMETRY
|
|
#define SUB_GEOMETRY
|
|
|
|
#include <map>
|
|
|
|
#include <osg/Object>
|
|
#include <osg/Array>
|
|
#include <osg/Geometry>
|
|
#include <osg/StateSet>
|
|
#include <osg/ref_ptr>
|
|
|
|
#include <osgAnimation/MorphGeometry>
|
|
|
|
|
|
class SubGeometry {
|
|
public:
|
|
typedef std::map<osg::Array*, const osg::Array*>::iterator BufferIterator;
|
|
typedef std::map<unsigned int, unsigned int> IndexMapping;
|
|
|
|
SubGeometry(const osg::Geometry& source,
|
|
const std::vector<unsigned int>& triangles,
|
|
const std::vector<unsigned int>& lines,
|
|
const std::vector<unsigned int>& wireframe,
|
|
const std::vector<unsigned int>& 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<const osgAnimation::MorphGeometry*>(&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<osg::StateSet*>(source.getStateSet()));
|
|
}
|
|
|
|
addSourceBuffers(_geometry.get(), source);
|
|
|
|
// process morph targets if needed
|
|
if(const osgAnimation::MorphGeometry* morphSource = dynamic_cast<const osgAnimation::MorphGeometry*>(&source)) {
|
|
osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(_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<osg::Array*>(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<typename C>
|
|
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<const T*>(&src)) \
|
|
{ return copyValues<T>(dynamic_cast<const T&>(src), dynamic_cast<T&>(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<osg::Geometry> _geometry;
|
|
std::map<osg::Array*, const osg::Array*> _bufferMap;
|
|
std::map<unsigned int, unsigned int> _indexMap;
|
|
std::map<std::string, osg::DrawElements*> _primitives;
|
|
};
|
|
|
|
|
|
#endif
|