From 48e7679e78a4a77e7425b0de9a0fa3a1a80c497f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 28 Jun 2002 22:42:02 +0000 Subject: [PATCH] Rewrote the osgUtil::Tesselator so that it is easier to use, and can also easily retesselate osg::Primitive::POLYGONS found in Geometry objects. Added calls to the tesselate to the lwo and flt loaders. --- include/osgUtil/Tesselator | 128 +++---- src/osgPlugins/flt/GeoSetBuilder.cpp | 9 + src/osgPlugins/lib3ds/ReaderWriter3DS.cpp | 97 +++--- src/osgPlugins/lwo/ReaderWriterLWO.cpp | 6 + src/osgUtil/Tesselator.cpp | 404 +++++++++++----------- 5 files changed, 324 insertions(+), 320 deletions(-) diff --git a/include/osgUtil/Tesselator b/include/osgUtil/Tesselator index 200866543..c92fd0f23 100644 --- a/include/osgUtil/Tesselator +++ b/include/osgUtil/Tesselator @@ -5,13 +5,20 @@ #ifndef OSGUTIL_Tesselator #define OSGUTIL_Tesselator -#include -#include +#include #include +#include + #include +/* Win32 calling conventions. (or a least thats what the GLUT example tess.c uses.)*/ +#ifndef CALLBACK +#define CALLBACK +#endif + + namespace osgUtil { /** A simple class for tessellating a single polygon boundary. @@ -31,86 +38,65 @@ class OSGUTIL_EXPORT Tesselator COUNTER_CLOCK_WISE }; - void tesselate(osg::Vec3* coords,int numIndices, int* indices,InputBoundaryDirection ibd=COUNTER_CLOCK_WISE); - void tesselate(osg::Vec3* coords,int numIndices, osg::ushort* indices,InputBoundaryDirection ibd=COUNTER_CLOCK_WISE); - void tesselate(osg::Vec3* coords,int numIndices, osg::uint* indices,InputBoundaryDirection ibd=COUNTER_CLOCK_WISE); - - typedef std::vector IndexVec; - - const IndexVec& getResult() const { return _tesselated_indices; } + typedef std::vector VertexPointList; + struct Prim : public osg::Referenced + { + Prim(GLenum mode):_mode(mode) {} + + typedef std::vector VecList; - void beginPrimitive(int primitiveType); - void endPrimitive(); + GLenum _mode; + VecList _vertices; + }; + + void beginTesselation(); + + void beginContour(); + void addVertex(osg::Vec3* vertex); + void endContour(); + + void endTesselation(); - int _errorCode; + typedef std::vector< osg::ref_ptr > PrimList; + + PrimList& getPrimList() { return _primList; } + + void retesselatePolygons(osg::Geometry& geom); + + void reset(); + + protected: + + void begin(GLenum mode); + void vertex(osg::Vec3* vertex); + void combine(osg::Vec3* vertex); + void end(); + void error(GLenum errorCode); - struct VertexIndexSet + static void beginCallback(GLenum which, void* userData); + static void vertexCallback(GLvoid *data, void* userData); + static void combineCallback(GLdouble coords[3], void* vertex_data[4], + GLfloat weight[4], void** outData, + void* useData); + static void endCallback(void* userData); + static void errorCallback(GLenum errorCode, void* userData); + + + struct Vec3d { - VertexIndexSet() {} - - VertexIndexSet(Tesselator* tess,const osg::Vec3& vec,osg::uint index) - { - set(tess,vec,index); - } - - VertexIndexSet(const VertexIndexSet& vip) - { - _Tesselator = vip._Tesselator; - _vertex[0] = vip._vertex[0]; - _vertex[1] = vip._vertex[1]; - _vertex[2] = vip._vertex[2]; - _index = vip._index; - - } - - VertexIndexSet& operator = (const VertexIndexSet& vip) - { - if (&vip==this) return *this; - _Tesselator = vip._Tesselator; - _vertex[0] = vip._vertex[0]; - _vertex[1] = vip._vertex[1]; - _vertex[2] = vip._vertex[2]; - _index = vip._index; - return *this; - } - - void set(Tesselator* tess,const osg::Vec3& vec,osg::uint index) - { - _Tesselator = tess; - _vertex[0] = vec[0]; - _vertex[1] = vec[1]; - _vertex[2] = vec[2]; - _index = index; - } - - void accumulate() - { - _Tesselator->_acummulated_indices.push_back(_index); - } - // note,_vertex must be first so that callbacks can use a pointer - // to it to dereference the VertexIndexSet for it. - double _vertex[3]; - Tesselator* _Tesselator; - osg::uint _index; + double _v[3]; }; - protected: - - friend struct VertexIndexSet; - typedef std::vector CoordVec; + typedef std::vector Vec3dList; - void init(); - void do_it(); - + GLUtesselator* _tobj; + PrimList _primList; + Vec3dList _coordData; + GLenum _errorCode; - CoordVec _coordVec; - IndexVec _tesselated_indices; - int _currentPrimtiveType; - IndexVec _acummulated_indices; - }; } diff --git a/src/osgPlugins/flt/GeoSetBuilder.cpp b/src/osgPlugins/flt/GeoSetBuilder.cpp index ccc7827f8..12598fa38 100644 --- a/src/osgPlugins/flt/GeoSetBuilder.cpp +++ b/src/osgPlugins/flt/GeoSetBuilder.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include @@ -308,6 +310,13 @@ osg::Geode* GeoSetBuilder::createOsgGeoSets(osg::Geode* geode) } } + osgUtil::Tesselator tesselator; + for(int i=0;igetNumDrawables();++i) + { + osg::Geometry* geom = dynamic_cast(geode->getDrawable(i)); + if (geom) tesselator.retesselatePolygons(*geom); + } + //Old GeoSet code. // for(itr=_dynGeoSetList.begin(); // itr!=_dynGeoSetList.end(); diff --git a/src/osgPlugins/lib3ds/ReaderWriter3DS.cpp b/src/osgPlugins/lib3ds/ReaderWriter3DS.cpp index 57991c42d..aa2f42e56 100644 --- a/src/osgPlugins/lib3ds/ReaderWriter3DS.cpp +++ b/src/osgPlugins/lib3ds/ReaderWriter3DS.cpp @@ -497,12 +497,16 @@ osg::Drawable* ReaderWriter3DS::createDrawable(Lib3dsMesh *m,FaceList& faceLis } + // create vertices. osg::Vec3Array* osg_coords = new osg::Vec3Array(noVertex); + geom->setVertexArray(osg_coords); + Lib3dsVector c; for (i=0; ipoints; ++i) { - if (orig2NewMapping[i]>=0) { + if (orig2NewMapping[i]>=0) + { if (matrix) { lib3ds_vector_transform(c,*matrix, m->pointL[i].pos); @@ -516,12 +520,13 @@ osg::Drawable* ReaderWriter3DS::createDrawable(Lib3dsMesh *m,FaceList& faceLis } } - osg::Vec2Array* osg_tcoords = NULL; + // create texture coords if needed. if (m->texels>0) { if (m->texels==m->points) { - osg_tcoords = new osg::Vec2Array(noVertex); + osg::Vec2Array* osg_tcoords = new osg::Vec2Array(noVertex); + geom->setTexCoordArray(0,osg_tcoords); for (i=0; itexels; ++i) { if (orig2NewMapping[i]>=0) (*osg_tcoords)[orig2NewMapping[i]].set(m->texelL[i][0],m->texelL[i][1]); @@ -533,27 +538,56 @@ osg::Drawable* ReaderWriter3DS::createDrawable(Lib3dsMesh *m,FaceList& faceLis } } - - // handle normals. - osg::Vec3Array* osg_normals=0; - osg::Vec3Array::iterator normal_itr = 0; + // create normals. if (_usePerVertexNormals) { - osg_normals = new osg::Vec3Array(noVertex); + osg::Vec3Array* osg_normals=osg_normals = new osg::Vec3Array(noVertex); // initialize normal list to zero's. for (i=0; ifaceL[*fitr]; + + (*osg_normals)[orig2NewMapping[face.points[0]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);; + (*osg_normals)[orig2NewMapping[face.points[1]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);; + (*osg_normals)[orig2NewMapping[face.points[2]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);; + + } + + // normalize the normal list to unit length normals. + for (i=0; isetNormalArray(osg_normals); + geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + } else { - osg_normals = new osg::Vec3Array(faceList.size()); - normal_itr = osg_normals->begin(); + osg::Vec3Array* osg_normals = new osg::Vec3Array(faceList.size()); + osg::Vec3Array::iterator normal_itr = osg_normals->begin(); + for (fitr=faceList.begin(); + fitr!=faceList.end(); + ++fitr) + { + Lib3dsFace& face = m->faceL[*fitr]; + *(normal_itr++) = osg::Vec3(face.normal[0],face.normal[1],face.normal[2]); + } + geom->setNormalArray(osg_normals); + geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); } - + + // create primitives int numIndices = faceList.size()*3; UShortDrawElements* elements = new osg::UShortDrawElements(osg::Primitive::TRIANGLES,numIndices); UShortDrawElements::iterator index_itr = elements->begin(); @@ -567,49 +601,10 @@ osg::Drawable* ReaderWriter3DS::createDrawable(Lib3dsMesh *m,FaceList& faceLis *(index_itr++) = orig2NewMapping[face.points[0]]; *(index_itr++) = orig2NewMapping[face.points[1]]; *(index_itr++) = orig2NewMapping[face.points[2]]; - - if (_usePerVertexNormals) - { - (*osg_normals)[orig2NewMapping[face.points[0]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);; - (*osg_normals)[orig2NewMapping[face.points[1]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);; - (*osg_normals)[orig2NewMapping[face.points[2]]] += osg::Vec3(face.normal[0],face.normal[1],face.normal[2]);; - } - else - { - *(normal_itr++) = osg::Vec3(face.normal[0],face.normal[1],face.normal[2]); - } - } - + geom->addPrimitive(elements); - geom->setVertexArray(osg_coords); - - if (osg_tcoords) - { - geom->setTexCoordArray(0,osg_tcoords); - } - - if (_usePerVertexNormals) - { - // normalize the normal list to unit length normals. - for (i=0; isetNormalArray(osg_normals); - geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); - - } - else - { - geom->setNormalArray(osg_normals); - geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE); - } - - - return geom; } diff --git a/src/osgPlugins/lwo/ReaderWriterLWO.cpp b/src/osgPlugins/lwo/ReaderWriterLWO.cpp index 975c386d6..267e9b130 100644 --- a/src/osgPlugins/lwo/ReaderWriterLWO.cpp +++ b/src/osgPlugins/lwo/ReaderWriterLWO.cpp @@ -198,6 +198,8 @@ osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode(const std::string& fil osg::Geode* geode = new osg::Geode; + osgUtil::Tesselator tesselator; + // add everthing into the Geode. osgUtil::SmoothingVisitor smoother; for(itr=mtgcm.begin(); @@ -207,7 +209,11 @@ osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode(const std::string& fil GeometryCollection& gc = itr->second; if (gc._geom) { + + tesselator.retesselatePolygons(*gc._geom); + smoother.smooth(*gc._geom); + geode->addDrawable(gc._geom); } diff --git a/src/osgUtil/Tesselator.cpp b/src/osgUtil/Tesselator.cpp index 2ce0e48a7..f2842f79a 100644 --- a/src/osgUtil/Tesselator.cpp +++ b/src/osgUtil/Tesselator.cpp @@ -7,255 +7,263 @@ using namespace osg; using namespace osgUtil; -/* Win32 calling conventions. (or a least thats what the GLUT example tess.c uses.)*/ -#ifndef CALLBACK -#define CALLBACK -#endif - -static Tesselator* s_tesselator = NULL; - -void CALLBACK beginCallback(GLenum which) -{ - s_tesselator->beginPrimitive(which); -} - -void CALLBACK errorCallback(GLenum errorCode) -{ - s_tesselator->_errorCode = errorCode; -} - -void CALLBACK endCallback() -{ - s_tesselator->endPrimitive(); -} - -void CALLBACK vertexCallback(GLvoid *data) -{ - Tesselator::VertexIndexSet* vip = (Tesselator::VertexIndexSet*)data; - vip->accumulate(); -} +static Tesselator* s_currentTesselator=0; Tesselator::Tesselator() { + _tobj = 0; + _errorCode = 0; } Tesselator::~Tesselator() { + if (_tobj) gluDeleteTess(_tobj); } -void Tesselator::tesselate(osg::Vec3* coords,int numIndices, int* indices,InputBoundaryDirection ibd) +void Tesselator::beginTesselation() { - init(); - _coordVec.reserve(numIndices); - if (ibd==COUNTER_CLOCK_WISE) + reset(); + + if (!_tobj) _tobj = gluNewTess(); + + gluTessCallback(_tobj, GLU_TESS_VERTEX_DATA, (GLvoid (CALLBACK*)()) vertexCallback); + gluTessCallback(_tobj, GLU_TESS_BEGIN_DATA, (GLvoid (CALLBACK*)()) beginCallback); + gluTessCallback(_tobj, GLU_TESS_END_DATA, (GLvoid (CALLBACK*)()) endCallback); + gluTessCallback(_tobj, GLU_TESS_COMBINE, (GLvoid (CALLBACK*)()) combineCallback); + gluTessCallback(_tobj, GLU_TESS_ERROR_DATA, (GLvoid (CALLBACK*)()) errorCallback); + + gluTessBeginPolygon(_tobj,this); + + s_currentTesselator = this; + +} + +void Tesselator::beginContour() +{ + if (_tobj) { - for(int i=0;i=0;--i) - { - _coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i])); - } + Vec3d* data = new Vec3d; + _coordData.push_back(data); + (*data)._v[0]=(*vertex)[0]; + (*data)._v[1]=(*vertex)[1]; + (*data)._v[2]=(*vertex)[2]; + gluTessVertex(_tobj,data->_v,vertex); } - do_it(); } -void Tesselator::tesselate(osg::Vec3* coords,int numIndices, osg::ushort* indices,InputBoundaryDirection ibd) +void Tesselator::endContour() { - init(); - _coordVec.reserve(numIndices); - if (ibd==COUNTER_CLOCK_WISE) - { - for(int i=0;i=0;--i) - { - _coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i])); - } - } - do_it(); + gluTessEndContour(_tobj); + } } -void Tesselator::tesselate(osg::Vec3* coords,int numIndices, osg::uint* indices,InputBoundaryDirection ibd) +void Tesselator::endTesselation() { - init(); - _coordVec.reserve(numIndices); - if (ibd==COUNTER_CLOCK_WISE) - { - for(int i=0;i=0;--i) - { - _coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i])); - } - } - do_it(); } -void Tesselator::init() +void Tesselator::reset() { + if (_tobj) + { + gluDeleteTess(_tobj); + _tobj = 0; + } + _primList.clear(); + _coordData.clear(); _errorCode = 0; - _coordVec.clear(); - _acummulated_indices.clear(); - _tesselated_indices.clear(); - _currentPrimtiveType=0; } -#ifdef GLU_VERSION_1_2 -void Tesselator::do_it() +void Tesselator::retesselatePolygons(osg::Geometry& geom) { - GLUtesselator *tobj = gluNewTess(); - - gluTessCallback(tobj, (GLenum)GLU_TESS_VERTEX, - (GLvoid (CALLBACK*) ()) (&vertexCallback)); - gluTessCallback(tobj, (GLenum)GLU_TESS_BEGIN, - (GLvoid (CALLBACK*) ()) (&beginCallback)); - gluTessCallback(tobj, (GLenum)GLU_TESS_END, - (GLvoid (CALLBACK*) ()) (&endCallback)); - gluTessCallback(tobj, (GLenum)GLU_TESS_ERROR, - (GLvoid (CALLBACK*) ()) (&errorCallback)); + Vec3Array* vertices = geom.getVertexArray(); + if (!vertices || vertices->empty() || geom.getPrimitiveList().empty()) return; - s_tesselator = this; - - gluTessBeginPolygon(tobj,NULL); - gluTessBeginContour(tobj); - - for(CoordVec::iterator itr=_coordVec.begin(); - itr!=_coordVec.end(); - ++itr) + int noPrimitiveAtStart = geom.getPrimitiveList().size(); + for(int primNo=0;primNo_vertex,itr->_vertex); - } - - gluTessEndContour(tobj); - gluTessEndPolygon(tobj); - - gluDeleteTess(tobj); - - if (_errorCode!=0) - { - const GLubyte *estring = gluErrorString((GLenum)_errorCode); - osg::notify(osg::WARN)<<"Tessellation Error: "<push_back(i); } } - } - break; - case(GL_TRIANGLES): - { - - for(unsigned int i=2;i<_acummulated_indices.size();i+=3) + + if (primItr==_primList.begin()) { - _tesselated_indices.push_back(_acummulated_indices[i-2]); - _tesselated_indices.push_back(_acummulated_indices[i-1]); - _tesselated_indices.push_back(_acummulated_indices[i]); + // first new primitive so overwrite the previous polygon. + geom.getPrimitiveList()[primNo] = elements; + } + else + { + // subsequence primtives add to the back of the primitive list. + geom.addPrimitive(elements); } } - break; + } + } - - _acummulated_indices.clear(); } +void Tesselator::begin(GLenum mode) +{ + _primList.push_back(new Prim(mode)); +} + +void Tesselator::vertex(osg::Vec3* vertex) +{ + if (!_primList.empty()) + { + Prim* prim = _primList.back().get(); + prim->_vertices.push_back(vertex); + } +} + +void Tesselator::combine(osg::Vec3* vertex) +{ + if (!_primList.empty()) + { + Prim* prim = _primList.back().get(); + prim->_vertices.push_back(vertex); + } +} + +void Tesselator::end() +{ + // no need to do anything right now... +} + +void Tesselator::error(GLenum errorCode) +{ + _errorCode = errorCode; +} + +void CALLBACK Tesselator::beginCallback(GLenum which, void* userData) +{ + ((Tesselator*)userData)->begin(which); +} + +void CALLBACK Tesselator::endCallback(void* userData) +{ + ((Tesselator*)userData)->end(); +} + +void CALLBACK Tesselator::vertexCallback(GLvoid *data, void* userData) +{ + ((Tesselator*)userData)->vertex((Vec3*)data); +} + +void CALLBACK Tesselator::combineCallback(GLdouble coords[3], void* /*vertex_data*/[4], + GLfloat /*weight*/[4], void** outData, + void* userData) +{ + Vec3* newData = new osg::Vec3(coords[0],coords[2],coords[3]); + *outData = newData; + //((Tesselator*)userData)->combine(newData); + s_currentTesselator->combine(newData); +} + +void CALLBACK Tesselator::errorCallback(GLenum errorCode, void* userData) +{ + ((Tesselator*)userData)->error(errorCode); +}