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.
This commit is contained in:
Robert Osfield
2002-06-28 22:42:02 +00:00
parent 4e81711ef7
commit 48e7679e78
5 changed files with 324 additions and 320 deletions

View File

@@ -5,13 +5,20 @@
#ifndef OSGUTIL_Tesselator
#define OSGUTIL_Tesselator
#include <osg/Types>
#include <osg/Vec3>
#include <osg/Geometry>
#include <osgUtil/Export>
#include <osg/GLU>
#include <vector>
/* 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<osg::uint> IndexVec;
const IndexVec& getResult() const { return _tesselated_indices; }
typedef std::vector<osg::Vec3*> VertexPointList;
struct Prim : public osg::Referenced
{
Prim(GLenum mode):_mode(mode) {}
typedef std::vector<osg::Vec3*> 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<Prim> > 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<VertexIndexSet> CoordVec;
typedef std::vector<Vec3d*> Vec3dList;
void init();
void do_it();
GLUtesselator* _tobj;
PrimList _primList;
Vec3dList _coordData;
GLenum _errorCode;
CoordVec _coordVec;
IndexVec _tesselated_indices;
int _currentPrimtiveType;
IndexVec _acummulated_indices;
};
}

View File

@@ -24,6 +24,8 @@
#include <osg/Point>
#include <osg/Notify>
#include <osgUtil/Tesselator>
#include <map>
#include <algorithm>
@@ -308,6 +310,13 @@ osg::Geode* GeoSetBuilder::createOsgGeoSets(osg::Geode* geode)
}
}
osgUtil::Tesselator tesselator;
for(int i=0;i<geode->getNumDrawables();++i)
{
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode->getDrawable(i));
if (geom) tesselator.retesselatePolygons(*geom);
}
//Old GeoSet code.
// for(itr=_dynGeoSetList.begin();
// itr!=_dynGeoSetList.end();

View File

@@ -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; i<m->points; ++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; i<m->texels; ++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; i<noVertex; ++i)
{
(*osg_normals)[i].set(0.0f,0.0f,0.0f);
}
for (fitr=faceList.begin();
fitr!=faceList.end();
++fitr)
{
Lib3dsFace& face = m->faceL[*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; i<noVertex; ++i)
{
(*osg_normals)[i].normalize();
}
geom->setNormalArray(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; i<noVertex; ++i)
{
(*osg_normals)[i].normalize();
}
geom->setNormalArray(osg_normals);
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
else
{
geom->setNormalArray(osg_normals);
geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
}
return geom;
}

View File

@@ -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);
}

View File

@@ -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<numIndices;++i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
gluTessBeginContour(_tobj);
}
else
}
void Tesselator::addVertex(osg::Vec3* vertex)
{
if (_tobj)
{
for(int i=numIndices-1;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<numIndices;++i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
else
if (_tobj)
{
for(int i=numIndices-1;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<numIndices;++i)
if (_tobj)
{
gluTessEndPolygon(_tobj);
gluDeleteTess(_tobj);
_tobj = 0;
if (_errorCode!=0)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
const GLubyte *estring = gluErrorString((GLenum)_errorCode);
osg::notify(osg::WARN)<<"Tessellation Error: "<<estring<< std::endl;
}
}
else
{
for(int i=numIndices-1;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<noPrimitiveAtStart;++primNo)
{
gluTessVertex(tobj,itr->_vertex,itr->_vertex);
}
gluTessEndContour(tobj);
gluTessEndPolygon(tobj);
gluDeleteTess(tobj);
if (_errorCode!=0)
{
const GLubyte *estring = gluErrorString((GLenum)_errorCode);
osg::notify(osg::WARN)<<"Tessellation Error: "<<estring<< std::endl;
osg::notify(osg::WARN)<<" Num indices created = "<<_tesselated_indices.size()<< std::endl;
}
}
#else
// old style glu tesseleation.
void Tesselator::do_it()
{
GLUtriangulatorObj *tobj = gluNewTess();
gluTessCallback(tobj, (GLenum)GLU_VERTEX,
(GLvoid (CALLBACK*) ()) (&vertexCallback));
gluTessCallback(tobj, (GLenum)GLU_BEGIN,
(GLvoid (CALLBACK*) ()) (&beginCallback));
gluTessCallback(tobj, (GLenum)GLU_END,
(GLvoid (CALLBACK*) ()) (&endCallback));
gluTessCallback(tobj, (GLenum)GLU_ERROR,
(GLvoid (CALLBACK*) ()) (&errorCallback));
s_tesselator = this;
gluBeginPolygon(tobj);
for(CoordVec::iterator itr=_coordVec.begin();
itr!=_coordVec.end();
++itr)
{
gluTessVertex(tobj,itr->_vertex,itr->_vertex);
}
gluEndPolygon(tobj);
gluDeleteTess(tobj);
if (_errorCode!=0)
{
const GLubyte *estring = gluErrorString((GLenum)_errorCode);
osg::notify(osg::WARN)<<"Tessellation Error: "<<estring<< std::endl;
osg::notify(osg::WARN)<<" Num indices created = "<<_tesselated_indices.size()<< std::endl;
}
}
#endif
void Tesselator::beginPrimitive(int primitiveType)
{
_currentPrimtiveType = primitiveType;
}
void Tesselator::endPrimitive()
{
if (_acummulated_indices.size()>=3)
{
switch(_currentPrimtiveType)
osg::Primitive* primitive = geom.getPrimitiveList()[primNo].get();
if (primitive->getMode()==osg::Primitive::POLYGON)
{
case(GL_TRIANGLE_FAN):
beginTesselation();
beginContour();
switch(primitive->getType())
{
osg::uint first = _acummulated_indices[0];
for(unsigned int i=2;i<_acummulated_indices.size();++i)
case(osg::Primitive::DrawArraysPrimitiveType):
{
_tesselated_indices.push_back(first);
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i]);
osg::DrawArrays* drawArray = static_cast<osg::DrawArrays*>(primitive);
unsigned int first = drawArray->getFirst();
unsigned int last = first+drawArray->getCount();
for(unsigned int i=first;i<last;++i)
{
addVertex(&((*vertices)[i]));
}
break;
}
case(osg::Primitive::UByteDrawElementsPrimitiveType):
{
osg::UByteDrawElements* drawElements = static_cast<osg::UByteDrawElements*>(primitive);
for(osg::UByteDrawElements::iterator indexItr=drawElements->begin();
indexItr!=drawElements->end();
++indexItr)
{
addVertex(&((*vertices)[*indexItr]));
}
break;
}
case(osg::Primitive::UShortDrawElementsPrimitiveType):
{
osg::UShortDrawElements* drawElements = static_cast<osg::UShortDrawElements*>(primitive);
for(osg::UShortDrawElements::iterator indexItr=drawElements->begin();
indexItr!=drawElements->end();
++indexItr)
{
addVertex(&((*vertices)[*indexItr]));
}
break;
}
case(osg::Primitive::UIntDrawElementsPrimitiveType):
{
osg::UIntDrawElements* drawElements = static_cast<osg::UIntDrawElements*>(primitive);
for(osg::UIntDrawElements::iterator indexItr=drawElements->begin();
indexItr!=drawElements->end();
++indexItr)
{
addVertex(&((*vertices)[*indexItr]));
}
break;
}
}
break;
case(GL_TRIANGLE_STRIP):
endContour();
endTesselation();
Vec3* vbase = &(vertices->front());
Vec3* vtop = &(vertices->back());
for(PrimList::iterator primItr=_primList.begin();
primItr!=_primList.end();
++primItr)
{
for(unsigned int i=2;i<_acummulated_indices.size();++i)
Prim* prim = primItr->get();
osg::UShortDrawElements* elements = new osg::UShortDrawElements(prim->_mode);
for(Prim::VecList::iterator vitr=prim->_vertices.begin();
vitr!=prim->_vertices.end();
++vitr)
{
if (i%2)
if (*vitr<vbase || *vitr>vtop)
{
// i == 3,5,7 etc
// add in order.
_tesselated_indices.push_back(_acummulated_indices[i-2]);
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i]);
// new vertex.
std::cout<<"Ooohhh we're getting funky, extra vertices need to be inserted"<<std::endl;
}
else
{
// i == 2,4,6 etc
// add in flipping orde to preserve anticlockwise direction.
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i-2]);
_tesselated_indices.push_back(_acummulated_indices[i]);
// old vertex.
unsigned int i=*vitr-vbase;
elements->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);
}