/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include #include "TriStrip_tri_stripper.h" using namespace osg; using namespace osgUtil; typedef std::vector IndexList; class WriteValue : public osg::ConstValueVisitor { public: WriteValue(std::ostream& o):_o(o) {} std::ostream& _o; virtual void apply(const GLbyte& v) { _o << v; } virtual void apply(const GLshort& v) { _o << v; } virtual void apply(const GLint& v) { _o << v; } virtual void apply(const GLushort& v) { _o << v; } virtual void apply(const GLubyte& v) { _o << v; } virtual void apply(const GLuint& v) { _o << v; } virtual void apply(const GLfloat& v) { _o << v; } virtual void apply(const Vec4ub& v) { _o << v; } virtual void apply(const Vec2& v) { _o << v; } virtual void apply(const Vec3& v) { _o << v; } virtual void apply(const Vec4& v) { _o << v; } }; struct VertexAttribComparitor { VertexAttribComparitor(osg::Geometry& geometry) { add(geometry.getVertexArray(),osg::Geometry::BIND_PER_VERTEX); add(geometry.getNormalArray(),geometry.getNormalBinding()); add(geometry.getColorArray(),geometry.getColorBinding()); add(geometry.getSecondaryColorArray(),geometry.getSecondaryColorBinding()); add(geometry.getFogCoordArray(),geometry.getFogCoordBinding()); unsigned int i; for(i=0;i ArrayList; ArrayList _arrayList; bool operator() (unsigned int lhs, unsigned int rhs) const { for(ArrayList::const_iterator itr=_arrayList.begin(); itr!=_arrayList.end(); ++itr) { int compare = (*itr)->compare(lhs,rhs); if (compare==-1) return true; if (compare==1) return false; } return false; } int compare(unsigned int lhs, unsigned int rhs) { for(ArrayList::iterator itr=_arrayList.begin(); itr!=_arrayList.end(); ++itr) { int compare = (*itr)->compare(lhs,rhs); if (compare==-1) return -1; if (compare==1) return 1; } // // WriteValue wv(std::cout); // // std::cout<<"Values equal"<getMode()) { case(PrimitiveSet::TRIANGLES): case(PrimitiveSet::TRIANGLE_STRIP): case(PrimitiveSet::TRIANGLE_FAN): case(PrimitiveSet::QUADS): case(PrimitiveSet::QUAD_STRIP): case(PrimitiveSet::POLYGON): ++numSurfacePrimitives; break; default: ++numNonSurfacePrimitives; break; } } // nothitng to tri strip leave. if (!numSurfacePrimitives) return; // compute duplicate vertices typedef std::vector IndexList; unsigned int numVertices = geom.getVertexArray()->getNumElements(); IndexList indices(numVertices); unsigned int i,j; for(i=0;igetMode()) { case(PrimitiveSet::TRIANGLES): case(PrimitiveSet::TRIANGLE_STRIP): case(PrimitiveSet::TRIANGLE_FAN): case(PrimitiveSet::QUADS): case(PrimitiveSet::QUAD_STRIP): case(PrimitiveSet::POLYGON): (*itr)->accept(taf); break; default: new_primitives.push_back(*itr); break; } } float minimum_ratio_of_indices_to_unique_vertices = 1; float ratio_of_indices_to_unique_vertices = ((float)taf._in_indices.size()/(float)numUnique); osg::notify(osg::INFO)<<"TriStripVisitor::stripify(Geometry&): Number of indices"<=minimum_ratio_of_indices_to_unique_vertices) { osg::notify(osg::INFO)<<"TriStripVisitor::stripify(Geometry&): doing tri strip"<< std::endl; unsigned int in_numVertices = 0; for(triangle_stripper::tri_stripper::indices::iterator itr=taf._in_indices.begin(); itr!=taf._in_indices.end(); ++itr) { if (*itr>in_numVertices) in_numVertices=*itr; } // the largest indice is in_numVertices, but indices start at 0 // so increment to give to the corrent number of verticies. ++in_numVertices; // remap any shared vertex attributes RemapArray ra(copyMapping); arrayComparitor.accept(ra); try { triangle_stripper::tri_stripper stripifier(taf._in_indices); stripifier.SetCacheSize(_cacheSize); stripifier.SetMinStripSize(_minStripSize); triangle_stripper::tri_stripper::primitives_vector outPrimitives; stripifier.Strip(&outPrimitives); triangle_stripper::tri_stripper::primitives_vector::iterator pitr; if (_generateFourPointPrimitivesQuads) { osg::notify(osg::WARN)<<"Collecting all quads"< QuadMap; QuadMap quadMap; // pick out quads and place them in the quadMap, and also look for the max for(pitr=outPrimitives.begin(); pitr!=outPrimitives.end(); ++pitr) { if (pitr->m_Indices.size()==4) { std::swap(pitr->m_Indices[2],pitr->m_Indices[3]); unsigned int minValue = *(std::max_element(pitr->m_Indices.begin(),pitr->m_Indices.end())); quadMap.insert(QuadMap::value_type(minValue,pitr)); } } // handle the quads if (!quadMap.empty()) { IndexList indices; indices.reserve(4*quadMap.size()); // adds all the quads into the quad primitive, in ascending order // and the QuadMap stores the quad's in ascending order. for(QuadMap::iterator qitr=quadMap.begin(); qitr!=quadMap.end(); ++qitr) { pitr = qitr->second; unsigned int min_pos = 0; for(i=1;i<4;++i) { if (pitr->m_Indices[min_pos]>pitr->m_Indices[i]) min_pos = i; } indices.push_back(pitr->m_Indices[min_pos]); indices.push_back(pitr->m_Indices[(min_pos+1)%4]); indices.push_back(pitr->m_Indices[(min_pos+2)%4]); indices.push_back(pitr->m_Indices[(min_pos+3)%4]); } bool inOrder = true; unsigned int previousValue = indices.front(); for(IndexList::iterator qi_itr=indices.begin()+1; qi_itr!=indices.end() && inOrder; ++qi_itr) { inOrder = (previousValue+1)==*qi_itr; previousValue = *qi_itr; } if (inOrder) { new_primitives.push_back(new osg::DrawArrays(GL_QUADS,indices.front(),indices.size())); } else { unsigned int maxValue = *(std::max_element(indices.begin(),indices.end())); if (maxValue>=65536) { osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(GL_QUADS); std::copy(indices.begin(),indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } else { osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_QUADS); std::copy(indices.begin(),indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } } } } // handle non quad primitives for(pitr=outPrimitives.begin(); pitr!=outPrimitives.end(); ++pitr) { if (!_generateFourPointPrimitivesQuads || pitr->m_Indices.size()!=4) { bool inOrder = true; unsigned int previousValue = pitr->m_Indices.front(); for(triangle_stripper::tri_stripper::indices::iterator qi_itr=pitr->m_Indices.begin()+1; qi_itr!=pitr->m_Indices.end() && inOrder; ++qi_itr) { inOrder = (previousValue+1)==*qi_itr; previousValue = *qi_itr; } if (inOrder) { new_primitives.push_back(new osg::DrawArrays(pitr->m_Type,pitr->m_Indices.front(),pitr->m_Indices.size())); } else { unsigned int maxValue = *(std::max_element(pitr->m_Indices.begin(),pitr->m_Indices.end())); if (maxValue>=65536) { osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(pitr->m_Type); elements->reserve(pitr->m_Indices.size()); std::copy(pitr->m_Indices.begin(),pitr->m_Indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } else { osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(pitr->m_Type); elements->reserve(pitr->m_Indices.size()); std::copy(pitr->m_Indices.begin(),pitr->m_Indices.end(),std::back_inserter(*elements)); new_primitives.push_back(elements); } } } } geom.setPrimitiveSetList(new_primitives); #if 0 // debugging code for indentifying the tri-strips. osg::Vec4Array* colors = new osg::Vec4Array(new_primitives.size()); for(i=0;isize();++i) { (*colors)[i].set(((float)rand()/(float)RAND_MAX), ((float)rand()/(float)RAND_MAX), ((float)rand()/(float)RAND_MAX), 1.0f); } geom.setColorArray(colors); geom.setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET); #endif } catch(const char* errorMessage) { osg::notify(osg::WARN)<<"Warning: '"<(geode.getDrawable(i)); if (geom) _geometryList.insert(geom); } }