2001-09-20 05:19:47 +08:00
|
|
|
#include <osg/GL>
|
2001-10-04 05:44:07 +08:00
|
|
|
#include <osg/GLU>
|
|
|
|
|
2001-09-20 05:19:47 +08:00
|
|
|
#include <osg/Notify>
|
|
|
|
#include <osgUtil/Tesselator>
|
|
|
|
|
|
|
|
using namespace osg;
|
|
|
|
using namespace osgUtil;
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
Tesselator::Tesselator()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
_tobj = 0;
|
|
|
|
_errorCode = 0;
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
Tesselator::~Tesselator()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
if (_tobj) gluDeleteTess(_tobj);
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
void Tesselator::beginTesselation()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
reset();
|
2001-09-20 05:19:47 +08:00
|
|
|
|
2002-06-29 06:42:02 +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);
|
2002-07-20 23:00:47 +08:00
|
|
|
gluTessCallback(_tobj, GLU_TESS_COMBINE_DATA,(GLvoid (CALLBACK*)()) combineCallback);
|
2002-06-29 06:42:02 +08:00
|
|
|
gluTessCallback(_tobj, GLU_TESS_ERROR_DATA, (GLvoid (CALLBACK*)()) errorCallback);
|
2001-09-20 05:19:47 +08:00
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
gluTessBeginPolygon(_tobj,this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tesselator::beginContour()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
if (_tobj)
|
2002-06-24 05:43:46 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
gluTessBeginContour(_tobj);
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
}
|
2002-06-29 06:42:02 +08:00
|
|
|
|
|
|
|
void Tesselator::addVertex(osg::Vec3* vertex)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
if (_tobj)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
void Tesselator::endContour()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
if (_tobj)
|
|
|
|
{
|
|
|
|
gluTessEndContour(_tobj);
|
|
|
|
}
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
void Tesselator::endTesselation()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
if (_tobj)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
gluTessEndPolygon(_tobj);
|
|
|
|
gluDeleteTess(_tobj);
|
|
|
|
_tobj = 0;
|
2001-09-20 05:19:47 +08:00
|
|
|
|
2002-06-29 06:42:02 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
void Tesselator::reset()
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
if (_tobj)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
gluDeleteTess(_tobj);
|
|
|
|
_tobj = 0;
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
2002-06-29 06:42:02 +08:00
|
|
|
_primList.clear();
|
|
|
|
_coordData.clear();
|
2002-07-16 06:23:57 +08:00
|
|
|
_newVertexList.clear();
|
2002-06-29 06:42:02 +08:00
|
|
|
_errorCode = 0;
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
|
2002-07-16 06:23:57 +08:00
|
|
|
class InsertNewVertices : public osg::ArrayVisitor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
float _f1,_f2,_f3,_f4;
|
|
|
|
unsigned int _i1,_i2,_i3,_i4;
|
|
|
|
|
|
|
|
InsertNewVertices(float f1,unsigned int i1,
|
|
|
|
float f2,unsigned int i2,
|
|
|
|
float f3,unsigned int i3,
|
|
|
|
float f4,unsigned int i4):
|
|
|
|
_f1(f1),_f2(f2),_f3(f3),_f4(f4),
|
|
|
|
_i1(i1),_i2(i2),_i3(i3),_i4(i4){}
|
|
|
|
|
2002-07-16 23:28:25 +08:00
|
|
|
template <class ARRAY,class TYPE>
|
|
|
|
void apply_imp(ARRAY& array,TYPE initialValue)
|
2002-07-16 06:23:57 +08:00
|
|
|
{
|
2002-07-16 23:28:25 +08:00
|
|
|
TYPE val = initialValue;
|
|
|
|
if (_f1) val += static_cast<TYPE>(array[_i1] * _f1);
|
|
|
|
if (_f2) val += static_cast<TYPE>(array[_i2] * _f2);
|
|
|
|
if (_f3) val += static_cast<TYPE>(array[_i3] * _f3);
|
|
|
|
if (_f4) val += static_cast<TYPE>(array[_i4] * _f4);
|
2002-07-16 06:23:57 +08:00
|
|
|
|
|
|
|
array.push_back(val);
|
|
|
|
}
|
|
|
|
|
2002-07-16 23:28:25 +08:00
|
|
|
virtual void apply(osg::ByteArray& ba) { apply_imp(ba,GLbyte(0)); }
|
|
|
|
virtual void apply(osg::ShortArray& ba) { apply_imp(ba,GLshort(0)); }
|
|
|
|
virtual void apply(osg::IntArray& ba) { apply_imp(ba,GLint(0)); }
|
|
|
|
virtual void apply(osg::UByteArray& ba) { apply_imp(ba,GLubyte(0)); }
|
|
|
|
virtual void apply(osg::UShortArray& ba) { apply_imp(ba,GLushort(0)); }
|
|
|
|
virtual void apply(osg::UIntArray& ba) { apply_imp(ba,GLuint(0)); }
|
|
|
|
virtual void apply(osg::UByte4Array& ba) { apply_imp(ba,UByte4()); }
|
|
|
|
virtual void apply(osg::FloatArray& ba) { apply_imp(ba,float(0)); }
|
|
|
|
virtual void apply(osg::Vec2Array& ba) { apply_imp(ba,Vec2()); }
|
|
|
|
virtual void apply(osg::Vec3Array& ba) { apply_imp(ba,Vec3()); }
|
|
|
|
virtual void apply(osg::Vec4Array& ba) { apply_imp(ba,Vec4()); }
|
2002-07-16 06:23:57 +08:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
void Tesselator::retesselatePolygons(osg::Geometry& geom)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
Vec3Array* vertices = geom.getVertexArray();
|
|
|
|
if (!vertices || vertices->empty() || geom.getPrimitiveList().empty()) return;
|
2001-09-20 05:19:47 +08:00
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
int noPrimitiveAtStart = geom.getPrimitiveList().size();
|
|
|
|
for(int primNo=0;primNo<noPrimitiveAtStart;++primNo)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
osg::Primitive* primitive = geom.getPrimitiveList()[primNo].get();
|
|
|
|
if (primitive->getMode()==osg::Primitive::POLYGON)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +08:00
|
|
|
beginTesselation();
|
|
|
|
beginContour();
|
|
|
|
|
|
|
|
switch(primitive->getType())
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-06-29 06:42:02 +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;
|
|
|
|
}
|
2002-07-07 22:40:41 +08:00
|
|
|
case(osg::Primitive::DrawElementsUBytePrimitiveType):
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-07-07 22:40:41 +08:00
|
|
|
osg::DrawElementsUByte* drawElements = static_cast<osg::DrawElementsUByte*>(primitive);
|
|
|
|
for(osg::DrawElementsUByte::iterator indexItr=drawElements->begin();
|
2002-06-29 06:42:02 +08:00
|
|
|
indexItr!=drawElements->end();
|
|
|
|
++indexItr)
|
|
|
|
{
|
|
|
|
addVertex(&((*vertices)[*indexItr]));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2002-07-07 22:40:41 +08:00
|
|
|
case(osg::Primitive::DrawElementsUShortPrimitiveType):
|
2002-06-29 06:42:02 +08:00
|
|
|
{
|
2002-07-07 22:40:41 +08:00
|
|
|
osg::DrawElementsUShort* drawElements = static_cast<osg::DrawElementsUShort*>(primitive);
|
|
|
|
for(osg::DrawElementsUShort::iterator indexItr=drawElements->begin();
|
2002-06-29 06:42:02 +08:00
|
|
|
indexItr!=drawElements->end();
|
|
|
|
++indexItr)
|
|
|
|
{
|
|
|
|
addVertex(&((*vertices)[*indexItr]));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2002-07-07 22:40:41 +08:00
|
|
|
case(osg::Primitive::DrawElementsUIntPrimitiveType):
|
2002-06-29 06:42:02 +08:00
|
|
|
{
|
2002-07-07 22:40:41 +08:00
|
|
|
osg::DrawElementsUInt* drawElements = static_cast<osg::DrawElementsUInt*>(primitive);
|
|
|
|
for(osg::DrawElementsUInt::iterator indexItr=drawElements->begin();
|
2002-06-29 06:42:02 +08:00
|
|
|
indexItr!=drawElements->end();
|
|
|
|
++indexItr)
|
|
|
|
{
|
|
|
|
addVertex(&((*vertices)[*indexItr]));
|
|
|
|
}
|
|
|
|
break;
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
2002-07-14 05:17:40 +08:00
|
|
|
default:
|
|
|
|
break;
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
2002-06-29 06:42:02 +08:00
|
|
|
|
|
|
|
endContour();
|
|
|
|
endTesselation();
|
|
|
|
|
2002-07-16 06:23:57 +08:00
|
|
|
typedef std::map<osg::Vec3*,unsigned int> VertexPtrToIndexMap;
|
|
|
|
VertexPtrToIndexMap vertexPtrToIndexMap;
|
|
|
|
|
|
|
|
// populate the VertexPtrToIndexMap.
|
|
|
|
for(unsigned int vi=0;vi<vertices->size();++vi)
|
|
|
|
{
|
|
|
|
vertexPtrToIndexMap[&((*vertices)[vi])] = vi;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_newVertexList.empty())
|
|
|
|
{
|
|
|
|
|
|
|
|
osg::Vec3Array* normals = NULL;
|
|
|
|
if (geom.getNormalBinding()==osg::Geometry::BIND_PER_VERTEX)
|
|
|
|
{
|
|
|
|
normals = geom.getNormalArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef std::vector<osg::Array*> ArrayList;
|
|
|
|
ArrayList arrays;
|
|
|
|
|
|
|
|
if (geom.getColorBinding()==osg::Geometry::BIND_PER_VERTEX)
|
|
|
|
{
|
|
|
|
arrays.push_back(geom.getColorArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::Geometry::TexCoordArrayList& tcal = geom.getTexCoordArrayList();
|
|
|
|
for(osg::Geometry::TexCoordArrayList::iterator tcalItr=tcal.begin();
|
|
|
|
tcalItr!=tcal.end();
|
|
|
|
++tcalItr)
|
|
|
|
{
|
|
|
|
if (tcalItr->valid())
|
|
|
|
{
|
|
|
|
arrays.push_back(tcalItr->get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now add any new vertices that are required.
|
|
|
|
for(NewVertexList::iterator itr=_newVertexList.begin();
|
|
|
|
itr!=_newVertexList.end();
|
|
|
|
++itr)
|
|
|
|
{
|
|
|
|
osg::Vec3* vertex = itr->first;
|
|
|
|
NewVertex& newVertex = itr->second;
|
|
|
|
|
|
|
|
// assign vertex.
|
|
|
|
vertexPtrToIndexMap[vertex]=vertices->size();
|
|
|
|
vertices->push_back(*vertex);
|
|
|
|
|
|
|
|
// assign normals
|
|
|
|
if (normals)
|
|
|
|
{
|
|
|
|
osg::Vec3 norm(0.0f,0.0f,0.0f);
|
|
|
|
if (newVertex._v1) norm += (*normals)[vertexPtrToIndexMap[newVertex._v1]] * newVertex._f1;
|
|
|
|
if (newVertex._v2) norm += (*normals)[vertexPtrToIndexMap[newVertex._v2]] * newVertex._f2;
|
|
|
|
if (newVertex._v3) norm += (*normals)[vertexPtrToIndexMap[newVertex._v3]] * newVertex._f3;
|
|
|
|
if (newVertex._v4) norm += (*normals)[vertexPtrToIndexMap[newVertex._v4]] * newVertex._f4;
|
|
|
|
norm.normalize();
|
|
|
|
normals->push_back(norm);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!arrays.empty())
|
|
|
|
{
|
|
|
|
InsertNewVertices inv(newVertex._f1,vertexPtrToIndexMap[newVertex._v1],
|
|
|
|
newVertex._f2,vertexPtrToIndexMap[newVertex._v2],
|
|
|
|
newVertex._f3,vertexPtrToIndexMap[newVertex._v3],
|
|
|
|
newVertex._f4,vertexPtrToIndexMap[newVertex._v4]);
|
|
|
|
|
|
|
|
// assign the rest of the attributes.
|
|
|
|
for(ArrayList::iterator aItr=arrays.begin();
|
|
|
|
aItr!=arrays.end();
|
|
|
|
++aItr)
|
|
|
|
{
|
|
|
|
(*aItr)->accept(inv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-09-05 19:42:55 +08:00
|
|
|
osg::Vec3Array* normals = NULL; // GWM Sep 2002 - add normals for extra facets
|
|
|
|
int iprim=0;
|
|
|
|
if (geom.getNormalBinding()==osg::Geometry::BIND_PER_PRIMITIVE)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-09-05 19:42:55 +08:00
|
|
|
normals = geom.getNormalArray(); // GWM Sep 2002
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
2002-09-05 19:42:55 +08:00
|
|
|
for(PrimList::iterator primItr=_primList.begin();
|
|
|
|
primItr!=_primList.end();
|
|
|
|
++primItr)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-09-05 19:42:55 +08:00
|
|
|
Prim* prim = primItr->get();
|
|
|
|
osg::Vec3 norm(0.0f,0.0f,0.0f);
|
|
|
|
|
|
|
|
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(prim->_mode);
|
|
|
|
for(Prim::VecList::iterator vitr=prim->_vertices.begin();
|
|
|
|
vitr!=prim->_vertices.end();
|
|
|
|
++vitr)
|
|
|
|
{
|
|
|
|
elements->push_back(vertexPtrToIndexMap[*vitr]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (primItr==_primList.begin())
|
|
|
|
{
|
|
|
|
// first new primitive so overwrite the previous polygon.
|
|
|
|
geom.getPrimitiveList()[primNo] = elements;
|
|
|
|
if (normals) {
|
|
|
|
norm=(*normals)[iprim]; // GWM Sep 2002 the flat shaded normal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// subsequence primitives add to the back of the primitive list.
|
|
|
|
geom.addPrimitive(elements);
|
|
|
|
if (normals) normals->push_back(norm); // GWM Sep 2002 add flat shaded normal for new facet
|
|
|
|
}
|
|
|
|
iprim++; // GWM Sep 2002 count which normal we should use
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
}
|
2002-06-29 06:42:02 +08:00
|
|
|
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
2002-06-29 06:42:02 +08:00
|
|
|
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 06:42:02 +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);
|
2002-07-16 06:23:57 +08:00
|
|
|
|
2002-06-29 06:42:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-16 06:23:57 +08:00
|
|
|
void Tesselator::combine(osg::Vec3* vertex,void* vertex_data[4],GLfloat weight[4])
|
2002-06-29 06:42:02 +08:00
|
|
|
{
|
2002-07-16 06:23:57 +08:00
|
|
|
_newVertexList[vertex]=NewVertex(weight[0],(Vec3*)vertex_data[0],
|
|
|
|
weight[1],(Vec3*)vertex_data[1],
|
|
|
|
weight[2],(Vec3*)vertex_data[2],
|
|
|
|
weight[3],(Vec3*)vertex_data[3]);
|
2002-06-29 06:42:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2002-07-16 06:23:57 +08:00
|
|
|
void CALLBACK Tesselator::combineCallback(GLdouble coords[3], void* vertex_data[4],
|
|
|
|
GLfloat weight[4], void** outData,
|
2002-07-20 23:00:47 +08:00
|
|
|
void* userData)
|
2002-06-29 06:42:02 +08:00
|
|
|
{
|
2002-07-16 06:23:57 +08:00
|
|
|
Vec3* newData = new osg::Vec3(coords[0],coords[1],coords[2]);
|
2002-06-29 06:42:02 +08:00
|
|
|
*outData = newData;
|
2002-07-20 23:00:47 +08:00
|
|
|
((Tesselator*)userData)->combine(newData,vertex_data,weight);
|
2002-06-29 06:42:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CALLBACK Tesselator::errorCallback(GLenum errorCode, void* userData)
|
|
|
|
{
|
|
|
|
((Tesselator*)userData)->error(errorCode);
|
|
|
|
}
|