Files
OpenSceneGraph/src/osgUtil/TriStripVisitor.cpp
2001-12-15 10:00:43 +00:00

312 lines
9.3 KiB
C++

#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <stdio.h>
#include <osg/GeoSet>
#include <osg/Geode>
#include <osg/Types>
#include <osg/Notify>
#include <osgUtil/TriStripVisitor>
#include "NvTriStripObjects.h"
using namespace osg;
using namespace osgUtil;
// triangle functor.
struct TriangleAcumulatorFunctor
{
WordVec in_indices;
const Vec3* _vbase;
TriangleAcumulatorFunctor( const Vec3* vbase ) : _vbase(vbase) {}
inline void operator() ( const Vec3 &v1, const Vec3 &v2, const Vec3 &v3 )
{
int p1 = (int)(&v1-_vbase);
int p2 = (int)(&v2-_vbase);
int p3 = (int)(&v3-_vbase);
if (p1==p2 || p1==p3 || p2==p3) return;
in_indices.push_back(p1);
in_indices.push_back(p2);
in_indices.push_back(p3);
}
};
void createStrips(
NvStripInfoVec& strips,
NvFaceInfoVec& leftoverFaces,
int& noPrims,
int **lens,
osg::ushort **osg_indices)
{
int nStripCount = strips.size();
assert(nStripCount > 0);
noPrims = strips.size()+leftoverFaces.size();
*lens = new int [noPrims];
int* lensPtr = *lens;
unsigned int i;
int noIndices = 0;
for (i = 0; i < strips.size(); i++)
{
noIndices += strips[i]->m_faces.size()+2;
}
noIndices += leftoverFaces.size()*3;
*osg_indices = new osg::ushort[noIndices];
osg::ushort *osg_indicesPtr = *osg_indices;
for (i = 0; i < strips.size(); i++)
{
NvStripInfo *strip = strips[i];
int nStripFaceCount = strip->m_faces.size();
*(lensPtr++) = nStripFaceCount+2;
NvFaceInfo tLastFace(0, 0, 0);
// Handle the first face in the strip
{
NvFaceInfo tFirstFace(strip->m_faces[0]->m_v0, strip->m_faces[0]->m_v1, strip->m_faces[0]->m_v2);
// If there is a second face, reorder vertices such that the
// unique vertex is first
if (nStripFaceCount > 1)
{
int nUnique = NvStripifier::GetUniqueVertexInB(strip->m_faces[1], &tFirstFace);
if (nUnique == tFirstFace.m_v1)
{
std::swap(tFirstFace.m_v0, tFirstFace.m_v1);
}
else if (nUnique == tFirstFace.m_v2)
{
std::swap(tFirstFace.m_v0, tFirstFace.m_v2);
}
// If there is a third face, reorder vertices such that the
// shared vertex is last
if (nStripFaceCount > 2)
{
int nShared = NvStripifier::GetSharedVertex(strip->m_faces[2], &tFirstFace);
if (nShared == tFirstFace.m_v1)
{
std::swap(tFirstFace.m_v1, tFirstFace.m_v2);
}
}
}
*(osg_indicesPtr++) = tFirstFace.m_v0;
*(osg_indicesPtr++) = tFirstFace.m_v1;
*(osg_indicesPtr++) = tFirstFace.m_v2;
// Update last face info
tLastFace = tFirstFace;
}
for (int j = 1; j < nStripFaceCount; j++)
{
int nUnique = NvStripifier::GetUniqueVertexInB(&tLastFace, strip->m_faces[j]);
if (nUnique != -1)
{
*(osg_indicesPtr++) = nUnique;
// Update last face info
tLastFace.m_v0 = tLastFace.m_v1;
tLastFace.m_v1 = tLastFace.m_v2;
tLastFace.m_v2 = nUnique;
}
}
}
for (i = 0; i < leftoverFaces.size(); ++i)
{
*(lensPtr++) = 3;
*(osg_indicesPtr++) = leftoverFaces[i]->m_v0;
*(osg_indicesPtr++) = leftoverFaces[i]->m_v1;
*(osg_indicesPtr++) = leftoverFaces[i]->m_v2;
}
}
void TriStripVisitor::stripify(GeoSet& gset)
{
GeoSet::PrimitiveType primTypeIn = gset.getPrimType();
GeoSet::PrimitiveType primTypeOut = gset.getPrimType();
// determine whether to do smoothing or not, and if
// the primitive type needs to be modified enable smoothed normals.
bool doStripify;
switch(primTypeIn)
{
case(GeoSet::QUADS):
case(GeoSet::QUAD_STRIP):
case(GeoSet::POLYGON):
case(GeoSet::TRIANGLES):
case(GeoSet::TRIANGLE_STRIP):
case(GeoSet::TRIANGLE_FAN):
primTypeOut = GeoSet::TRIANGLE_STRIP;
doStripify = true;
break;
case(GeoSet::FLAT_TRIANGLE_STRIP):
case(GeoSet::FLAT_TRIANGLE_FAN):
// comment out for time being since per vertex colors and normals need
// to take account of the osg::GeoSet::_flat_shaded_skip
// primTypeOut = GeoSet::FLAT_TRIANGLE_STRIP;
// doStripify = true;
// break;
default: // points and lines etc.
doStripify = false;
break;
}
if (doStripify)
{
TriangleAcumulatorFunctor tt(gset.getCoords());
for_each_triangle( gset, tt );
if (!tt.in_indices.empty())
{
int in_numVertices = -1;
for(WordVec::iterator itr=tt.in_indices.begin();
itr!=tt.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;
int in_cacheSize = 16;
int in_minStripLength = 1;
NvStripInfoVec strips;
NvFaceInfoVec leftoverFaces;
NvStripifier stripifier;
stripifier.Stripify(tt.in_indices,
in_numVertices,
in_cacheSize,
in_minStripLength,
strips,
leftoverFaces);
int noPrims;
int *lens;
osg::ushort* osg_indices;
createStrips(strips,leftoverFaces,noPrims,&lens,&osg_indices);
if (primTypeIn!=primTypeOut)
gset.setPrimType( primTypeOut );
gset.setPrimLengths(lens);
gset.setNumPrims(noPrims);
gset.setCoords(gset.getCoords(),osg_indices);
if (gset.getTextureCoords())
{
switch(gset.getTextureBinding())
{
case(GeoSet::BIND_OVERALL):
// leave as before
break;
case(GeoSet::BIND_PERPRIM):
// switch off tex coords..
gset.setTextureBinding(GeoSet::BIND_OFF);
gset.setTextureCoords(NULL);
break;
case(GeoSet::BIND_PERVERTEX):
// set up the indexing.
gset.setTextureCoords(gset.getTextureCoords(),osg_indices);
break;
case(GeoSet::BIND_OFF):
case(GeoSet::BIND_DEFAULT):
// switch off tex coords..
gset.setTextureCoords(NULL);
break;
}
}
if (gset.getColors())
{
switch(gset.getColorBinding())
{
case(GeoSet::BIND_OVERALL):
// leave as before
break;
case(GeoSet::BIND_PERPRIM):
// switch off colors..
gset.setColorBinding(GeoSet::BIND_OFF);
gset.setColors(NULL);
break;
case(GeoSet::BIND_PERVERTEX):
// set up the indexing.
gset.setColors(gset.getColors(),osg_indices);
break;
case(GeoSet::BIND_OFF):
case(GeoSet::BIND_DEFAULT):
// switch off colors..
gset.setColors(NULL);
break;
}
}
if (gset.getNormals())
{
switch(gset.getNormalBinding())
{
case(GeoSet::BIND_OVERALL):
// leave as before
break;
case(GeoSet::BIND_PERPRIM):
// switch off normals..
gset.setNormalBinding(GeoSet::BIND_OFF);
gset.setNormals(NULL);
break;
case(GeoSet::BIND_PERVERTEX):
// set up the indexing.
gset.setNormals(gset.getNormals(),osg_indices);
break;
case(GeoSet::BIND_OFF):
case(GeoSet::BIND_DEFAULT):
// switch off normals..
gset.setNormals(NULL);
break;
}
}
gset.dirtyDisplayList();
}
else
{
notify(INFO) << "No triangles to stripify"<< std::endl;
}
}
}
void TriStripVisitor::apply(Geode& geode)
{
for(int i = 0; i < geode.getNumDrawables(); ++i )
{
osg::GeoSet* gset = dynamic_cast<osg::GeoSet*>(geode.getDrawable(i));
if (gset) stripify(*gset);
}
}