OpenSceneGraph/src/osgUtil/Tesselator.cpp

272 lines
7.6 KiB
C++
Raw Normal View History

2001-09-20 05:19:47 +08:00
#include <osg/GL>
#include <osg/GLU>
2001-09-20 05:19:47 +08:00
#include <osg/Notify>
#include <osgUtil/Tesselator>
using namespace osg;
using namespace osgUtil;
static Tesselator* s_currentTesselator=0;
2001-09-20 05:19:47 +08:00
Tesselator::Tesselator()
2001-09-20 05:19:47 +08:00
{
_tobj = 0;
_errorCode = 0;
2001-09-20 05:19:47 +08:00
}
Tesselator::~Tesselator()
2001-09-20 05:19:47 +08:00
{
if (_tobj) gluDeleteTess(_tobj);
2001-09-20 05:19:47 +08:00
}
void Tesselator::beginTesselation()
2001-09-20 05:19:47 +08:00
{
reset();
2001-09-20 05:19:47 +08:00
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);
2001-09-20 05:19:47 +08:00
gluTessBeginPolygon(_tobj,this);
s_currentTesselator = this;
}
void Tesselator::beginContour()
2001-09-20 05:19:47 +08:00
{
if (_tobj)
{
gluTessBeginContour(_tobj);
2001-09-20 05:19:47 +08:00
}
}
void Tesselator::addVertex(osg::Vec3* vertex)
2001-09-20 05:19:47 +08:00
{
if (_tobj)
2001-09-20 05:19:47 +08:00
{
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);
2001-09-20 05:19:47 +08:00
}
}
void Tesselator::endContour()
2001-09-20 05:19:47 +08:00
{
if (_tobj)
{
gluTessEndContour(_tobj);
}
2001-09-20 05:19:47 +08:00
}
void Tesselator::endTesselation()
2001-09-20 05:19:47 +08:00
{
if (_tobj)
2001-09-20 05:19:47 +08:00
{
gluTessEndPolygon(_tobj);
gluDeleteTess(_tobj);
_tobj = 0;
2001-09-20 05:19:47 +08:00
if (_errorCode!=0)
{
const GLubyte *estring = gluErrorString((GLenum)_errorCode);
osg::notify(osg::WARN)<<"Tessellation Error: "<<estring<< std::endl;
}
2001-09-20 05:19:47 +08:00
}
}
void Tesselator::reset()
2001-09-20 05:19:47 +08:00
{
if (_tobj)
2001-09-20 05:19:47 +08:00
{
gluDeleteTess(_tobj);
_tobj = 0;
2001-09-20 05:19:47 +08:00
}
_primList.clear();
_coordData.clear();
_errorCode = 0;
2001-09-20 05:19:47 +08:00
}
void Tesselator::retesselatePolygons(osg::Geometry& geom)
2001-09-20 05:19:47 +08:00
{
Vec3Array* vertices = geom.getVertexArray();
if (!vertices || vertices->empty() || geom.getPrimitiveList().empty()) return;
2001-09-20 05:19:47 +08:00
int noPrimitiveAtStart = geom.getPrimitiveList().size();
for(int primNo=0;primNo<noPrimitiveAtStart;++primNo)
2001-09-20 05:19:47 +08:00
{
osg::Primitive* primitive = geom.getPrimitiveList()[primNo].get();
if (primitive->getMode()==osg::Primitive::POLYGON)
2001-09-20 05:19:47 +08:00
{
beginTesselation();
beginContour();
switch(primitive->getType())
2001-09-20 05:19:47 +08:00
{
case(osg::Primitive::DrawArraysPrimitiveType):
{
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::DrawElementsUBytePrimitiveType):
2001-09-20 05:19:47 +08:00
{
osg::DrawElementsUByte* drawElements = static_cast<osg::DrawElementsUByte*>(primitive);
for(osg::DrawElementsUByte::iterator indexItr=drawElements->begin();
indexItr!=drawElements->end();
++indexItr)
{
addVertex(&((*vertices)[*indexItr]));
}
break;
}
case(osg::Primitive::DrawElementsUShortPrimitiveType):
{
osg::DrawElementsUShort* drawElements = static_cast<osg::DrawElementsUShort*>(primitive);
for(osg::DrawElementsUShort::iterator indexItr=drawElements->begin();
indexItr!=drawElements->end();
++indexItr)
{
addVertex(&((*vertices)[*indexItr]));
}
break;
}
case(osg::Primitive::DrawElementsUIntPrimitiveType):
{
osg::DrawElementsUInt* drawElements = static_cast<osg::DrawElementsUInt*>(primitive);
for(osg::DrawElementsUInt::iterator indexItr=drawElements->begin();
indexItr!=drawElements->end();
++indexItr)
{
addVertex(&((*vertices)[*indexItr]));
}
break;
2001-09-20 05:19:47 +08:00
}
default:
break;
2001-09-20 05:19:47 +08:00
}
endContour();
endTesselation();
Vec3* vbase = &(vertices->front());
Vec3* vtop = &(vertices->back());
for(PrimList::iterator primItr=_primList.begin();
primItr!=_primList.end();
++primItr)
2001-09-20 05:19:47 +08:00
{
Prim* prim = primItr->get();
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(prim->_mode);
for(Prim::VecList::iterator vitr=prim->_vertices.begin();
vitr!=prim->_vertices.end();
++vitr)
2001-09-20 05:19:47 +08:00
{
if (*vitr<vbase || *vitr>vtop)
2001-09-20 05:19:47 +08:00
{
// new vertex.
std::cout<<"Ooohhh we're getting funky, extra vertices need to be inserted"<<std::endl;
2001-09-20 05:19:47 +08:00
}
else
{
// old vertex.
unsigned int i=*vitr-vbase;
elements->push_back(i);
2001-09-20 05:19:47 +08:00
}
}
if (primItr==_primList.begin())
{
// first new primitive so overwrite the previous polygon.
geom.getPrimitiveList()[primNo] = elements;
}
else
2001-09-20 05:19:47 +08:00
{
// subsequence primtives add to the back of the primitive list.
geom.addPrimitive(elements);
2001-09-20 05:19:47 +08:00
}
}
2001-09-20 05:19:47 +08:00
}
2001-09-20 05:19:47 +08:00
}
}
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);
}