From 45c6ba0b738c006b8e65b23a63dfa064cfc689a5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 20 Apr 2012 10:01:50 +0000 Subject: [PATCH] From Mathias Froehlich,"Attached is a change to the ac3d model loader as of rev 11498, that uses indexed draws instead of plain array draws to save some amount of main memory. Draw performance does not change with the nvidia binary blob as well as with the open source drivers." --- src/osgPlugins/ac/ac3d.cpp | 104 ++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 25 deletions(-) diff --git a/src/osgPlugins/ac/ac3d.cpp b/src/osgPlugins/ac/ac3d.cpp index 7f46cda63..575a045a8 100644 --- a/src/osgPlugins/ac/ac3d.cpp +++ b/src/osgPlugins/ac/ac3d.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -804,6 +805,11 @@ class SurfaceBin : public PrimitiveBin { std::vector _polygons; std::vector _toTessellatePolygons; + typedef std::pair VertexNormalPair; + typedef std::pair VertexNormalTexTuple; + typedef std::map VertexIndexMap; + VertexIndexMap _vertexIndexMap; + public: SurfaceBin(unsigned flags, VertexSet *vertexSet) : PrimitiveBin(flags, vertexSet) @@ -912,13 +918,65 @@ class SurfaceBin : public PrimitiveBin { return true; } - void pushVertex(const VertexIndex& vertexIndex, osg::Vec3Array* vertexArray, - osg::Vec3Array* normalArray, osg::Vec2Array* texcoordArray) + unsigned pushVertex(const VertexIndex& vertexIndex, osg::Vec3Array* vertexArray, + osg::Vec3Array* normalArray, osg::Vec2Array* texcoordArray) { - vertexArray->push_back(_vertexSet->getVertex(vertexIndex)); - normalArray->push_back(_vertexSet->getNormal(vertexIndex)); + VertexNormalTexTuple vertexNormalTexTuple; + vertexNormalTexTuple.first.first = _vertexSet->getVertex(vertexIndex); + vertexNormalTexTuple.first.second = _vertexSet->getNormal(vertexIndex); if (texcoordArray) - texcoordArray->push_back(_vertexSet->getTexCoord(vertexIndex)); + vertexNormalTexTuple.second = _vertexSet->getTexCoord(vertexIndex); + else + vertexNormalTexTuple.second = osg::Vec2(0, 0); + + VertexIndexMap::iterator i = _vertexIndexMap.find(vertexNormalTexTuple); + if (i != _vertexIndexMap.end()) + return i->second; + + unsigned index = vertexArray->size(); + vertexArray->push_back(vertexNormalTexTuple.first.first); + normalArray->push_back(vertexNormalTexTuple.first.second); + if (texcoordArray) + texcoordArray->push_back(vertexNormalTexTuple.second); + + _vertexIndexMap.insert(VertexIndexMap::value_type(vertexNormalTexTuple, index)); + + return index; + } + + osg::DrawElements* createOptimalDrawElements(osg::DrawElementsUInt* drawElements) + { + unsigned num = drawElements->getNumIndices(); + unsigned maxIndex = 0; + for (unsigned i = 0; i < num; ++i) + { + maxIndex = osg::maximum(maxIndex, drawElements->getElement(i)); + } + + if (maxIndex <= std::numeric_limits::max()) + { + osg::DrawElementsUByte* drawElementsUByte = new osg::DrawElementsUByte(drawElements->getMode()); + drawElementsUByte->reserveElements(num); + for (unsigned i = 0; i < num; ++i) + { + drawElementsUByte->addElement(drawElements->getElement(i)); + } + return drawElementsUByte; + } + else if (maxIndex <= std::numeric_limits::max()) + { + osg::DrawElementsUShort* drawElementsUShort = new osg::DrawElementsUShort(drawElements->getMode()); + drawElementsUShort->reserveElements(num); + for (unsigned i = 0; i < num; ++i) + { + drawElementsUShort->addElement(drawElements->getElement(i)); + } + return drawElementsUShort; + } + else + { + return drawElements; + } } virtual osg::Geode* finalize(const MaterialData& material, const TextureData& textureData) @@ -972,18 +1030,16 @@ class SurfaceBin : public PrimitiveBin { // At first handle the the polygons to tessellate, fix them and append the other polygons later if (!_toTessellatePolygons.empty()) { - unsigned start = vertexArray->size(); - osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON, start); - drawArrayLengths->reserve(_toTessellatePolygons.size()); for (unsigned i = 0; i < _toTessellatePolygons.size(); ++i) { + osg::ref_ptr drawElements = new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON); for (unsigned j = 0; j < _toTessellatePolygons[i].index.size(); ++j) { - pushVertex(_toTessellatePolygons[i].index[j], vertexArray, normalArray, texcoordArray); + unsigned index = pushVertex(_toTessellatePolygons[i].index[j], vertexArray, normalArray, texcoordArray); + drawElements->addElement(index); } - drawArrayLengths->push_back(_toTessellatePolygons[i].index.size()); + geometry->addPrimitiveSet(createOptimalDrawElements(drawElements.get())); } - geometry->addPrimitiveSet(drawArrayLengths); osgUtil::Tessellator Tessellator; Tessellator.retessellatePolygons(*geometry); @@ -992,48 +1048,46 @@ class SurfaceBin : public PrimitiveBin { // handle triangles if (!_triangles.empty()) { - unsigned start = vertexArray->size(); + osg::ref_ptr drawElements = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES); for (unsigned i = 0; i < _triangles.size(); ++i) { for (unsigned j = 0; j < 3; ++j) { - pushVertex(_triangles[i].index[j], vertexArray, normalArray, texcoordArray); + unsigned index = pushVertex(_triangles[i].index[j], vertexArray, normalArray, texcoordArray); + drawElements->addElement(index); } } - osg::DrawArrays* drawArray = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, start, 3*_triangles.size()); - geometry->addPrimitiveSet(drawArray); + geometry->addPrimitiveSet(createOptimalDrawElements(drawElements.get())); } // handle quads if (!_quads.empty()) { - unsigned start = vertexArray->size(); + osg::ref_ptr drawElements = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS); for (unsigned i = 0; i < _quads.size(); ++i) { for (unsigned j = 0; j < 4; ++j) { - pushVertex(_quads[i].index[j], vertexArray, normalArray, texcoordArray); + unsigned index = pushVertex(_quads[i].index[j], vertexArray, normalArray, texcoordArray); + drawElements->addElement(index); } } - osg::DrawArrays* drawArray = new osg::DrawArrays(osg::PrimitiveSet::QUADS, start, 4*_quads.size()); - geometry->addPrimitiveSet(drawArray); + geometry->addPrimitiveSet(createOptimalDrawElements(drawElements.get())); } // handle polygons if (!_polygons.empty()) { - unsigned start = vertexArray->size(); - osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(osg::PrimitiveSet::POLYGON, start); - drawArrayLengths->reserve(_polygons.size()); for (unsigned i = 0; i < _polygons.size(); ++i) { + osg::ref_ptr drawElements = new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON); for (unsigned j = 0; j < _polygons[i].index.size(); ++j) { - pushVertex(_polygons[i].index[j], vertexArray, normalArray, texcoordArray); + unsigned index = pushVertex(_polygons[i].index[j], vertexArray, normalArray, texcoordArray); + drawElements->addElement(index); } - drawArrayLengths->push_back(_polygons[i].index.size()); + geometry->addPrimitiveSet(createOptimalDrawElements(drawElements.get())); } - geometry->addPrimitiveSet(drawArrayLengths); } return _geode.get();