Added osg::Drawable::PrimitiveFunctor and TriangleFunctor subclass for

querrying the primitive data inside Drawables.  Moved various support
classes over from being osg::GeoSet based to osg::Geometry based.
This commit is contained in:
Robert Osfield
2002-06-25 20:27:51 +00:00
parent 336c47e5fe
commit cbeeeefdab
20 changed files with 737 additions and 651 deletions

View File

@@ -27,7 +27,7 @@ Hit::Hit(const Hit& hit)
_localLineSegment = hit._localLineSegment;
_nodePath = hit._nodePath;
_geode = hit._geode;
_geoset = hit._geoset;
_drawable = hit._drawable;
_matrix = hit._matrix;
_inverse = hit._inverse;
@@ -58,7 +58,7 @@ Hit& Hit::operator = (const Hit& hit)
_localLineSegment = hit._localLineSegment;
_nodePath = hit._nodePath;
_geode = hit._geode;
_geoset = hit._geoset;
_drawable = hit._drawable;
_vecIndexList = hit._vecIndexList;
_primitiveIndex = hit._primitiveIndex;
@@ -180,7 +180,8 @@ void IntersectVisitor::addLineSegment(LineSegment* seg)
if (!seg->valid())
{
notify(WARN)<<"Warning: invalid line segment passed to IntersectVisitor::addLineSegment(..), segment ignored.."<< std::endl;
notify(WARN)<<"Warning: invalid line segment passed to IntersectVisitor::addLineSegment(..)"<<std::endl;
notify(WARN)<<" "<<seg->start()<<" "<<seg->end()<<" segment ignored.."<< std::endl;
return;
}
@@ -304,7 +305,16 @@ struct TriangleIntersect
typedef std::multimap<float,std::pair<int,osg::Vec3> > TriangleHitList;
TriangleHitList _thl;
TriangleIntersect()
{
}
TriangleIntersect(const LineSegment& seg,float ratio=FLT_MAX)
{
set(seg,ratio);
}
void set(const LineSegment& seg,float ratio=FLT_MAX)
{
_seg=new LineSegment(seg);
_hit=false;
@@ -315,7 +325,6 @@ struct TriangleIntersect
_d = _seg->end()-_seg->start();
_length = _d.length();
_d /= _length;
}
// bool intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r)
@@ -408,6 +417,14 @@ struct TriangleIntersect
float r = d/_length;
if (!in.valid())
{
osg::notify(WARN)<<"Warning:: Picked up error in TriangleIntersect"<<std::endl;
osg::notify(WARN)<<" ("<<v1<<",\t"<<v2<<",\t"<<v3<<")"<<std::endl;
osg::notify(WARN)<<" ("<<r1<<",\t"<<r2<<",\t"<<r3<<")"<<std::endl;
return;
}
_thl.insert(std::pair<const float,std::pair<int,osg::Vec3> > (r,std::pair<int,osg::Vec3>(_index-1,normal)));
_hit = true;
@@ -415,13 +432,13 @@ struct TriangleIntersect
};
bool IntersectVisitor::intersect(GeoSet& gset)
bool IntersectVisitor::intersect(Drawable& drawable)
{
bool hitFlag = false;
IntersectState* cis = _intersectStateStack.back().get();
const BoundingBox& bb = gset.getBound();
const BoundingBox& bb = drawable.getBound();
for(IntersectState::LineSegmentList::iterator sitr=cis->_segList.begin();
sitr!=cis->_segList.end();
@@ -429,8 +446,10 @@ bool IntersectVisitor::intersect(GeoSet& gset)
{
if (sitr->second->intersect(bb))
{
TriangleIntersect ti(*sitr->second);
for_each_triangle(gset,ti);
TriangleFunctor<TriangleIntersect> ti;
ti.set(*sitr->second);
drawable.applyPrimitiveOperation(ti);
if (ti._hit)
{
@@ -442,7 +461,7 @@ bool IntersectVisitor::intersect(GeoSet& gset)
hit._nodePath = _nodePath;
hit._matrix = cis->_matrix;
hit._inverse = cis->_inverse;
hit._geoset = &gset;
hit._drawable = &drawable;
if (_nodePath.empty()) hit._geode = NULL;
else hit._geode = dynamic_cast<Geode*>(_nodePath.back());
@@ -470,49 +489,13 @@ bool IntersectVisitor::intersect(GeoSet& gset)
}
void IntersectVisitor::apply(Geode& geode)
{
if (!enterNode(geode)) return;
for(int i = 0; i < geode.getNumDrawables(); i++ )
{
osg::GeoSet* gset = dynamic_cast<osg::GeoSet*>(geode.getDrawable(i));
if (gset) intersect(*gset);
else
{
IntersectState* cis = _intersectStateStack.back().get();
// simply default to intersecting with bounding box.
for(IntersectState::LineSegmentList::iterator sitr=cis->_segList.begin();
sitr!=cis->_segList.end();
++sitr)
{
if (sitr->second->intersect(geode.getDrawable(i)->getBound()))
{
Hit hit;
hit._nodePath = _nodePath;
hit._matrix = cis->_matrix;
hit._inverse = cis->_inverse;
hit._geoset = NULL;
if (_nodePath.empty()) hit._geode = NULL;
else hit._geode = dynamic_cast<Geode*>(_nodePath.back());
hit._ratio = 0.0f;
hit._primitiveIndex = -1;
hit._originalLineSegment = sitr->first;
hit._localLineSegment = sitr->second;
hit._intersectPoint = geode.getDrawable(i)->getBound().center();
hit._intersectNormal.set(0.0,0.0,1.0);
_segHitList[sitr->first.get()].push_back(hit);
std::sort(_segHitList[sitr->first.get()].begin(),_segHitList[sitr->first.get()].end());
}
}
}
intersect(*geode.getDrawable(i));
}
leaveNode();

View File

@@ -64,9 +64,9 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
}
// // convert the old style GeoSet to Geometry
// ConvertGeoSetsToGeometryVisitor cgtg;
// node->accept(cgtg);
// convert the old style GeoSet to Geometry
// ConvertGeoSetsToGeometryVisitor cgtg;
// node->accept(cgtg);
if (options & SHARE_DUPLICATE_STATE)

View File

@@ -22,7 +22,7 @@ struct LessPtr
};
// triangle functor.
struct TriangleFunctor
struct SmoothTriangleFunctor
{
osg::Vec3 *_coordBase;
@@ -31,7 +31,7 @@ struct TriangleFunctor
typedef std::multiset<const osg::Vec3*,LessPtr> CoordinateSet;
CoordinateSet _coordSet;
TriangleFunctor(osg::Vec3 *cb,int noVertices, osg::Vec3 *nb) : _coordBase(cb),_normalBase(nb)
SmoothTriangleFunctor(osg::Vec3 *cb,int noVertices, osg::Vec3 *nb) : _coordBase(cb),_normalBase(nb)
{
osg::Vec3* vptr = cb;
for(int i=0;i<noVertices;++i)
@@ -116,7 +116,7 @@ void SmoothingVisitor::smooth(osg::GeoSet& gset)
norms[j].set(0.0f,0.0f,0.0f);
}
TriangleFunctor tf(coords,ncoords,norms);
SmoothTriangleFunctor tf(coords,ncoords,norms);
for_each_triangle( gset, tf );
for(j = 0; j < ncoords; j++ )

View File

@@ -1,16 +1,11 @@
#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 <stdio.h>
#include "NvTriStripObjects.h"
using namespace osg;
@@ -23,7 +18,9 @@ struct TriangleAcumulatorFunctor
WordVec in_indices;
const Vec3* _vbase;
TriangleAcumulatorFunctor( const Vec3* vbase ) : _vbase(vbase) {}
TriangleAcumulatorFunctor() : _vbase(0) {}
void setCoords( const Vec3* vbase ) { _vbase = vbase; }
inline void operator() ( const Vec3 &v1, const Vec3 &v2, const Vec3 &v3 )
{
@@ -37,267 +34,172 @@ struct TriangleAcumulatorFunctor
}
};
void createStrips(
NvStripInfoVec& strips,
NvFaceInfoVec& leftoverFaces,
int& noPrims,
int **lens,
osg::ushort **osg_indices)
void TriStripVisitor::stripify(Geometry& geom)
{
int nStripCount = strips.size();
assert(nStripCount > 0);
noPrims = strips.size()+leftoverFaces.size();
*lens = osgNew int [noPrims];
unsigned int numSurfacePrimitives = 0;
unsigned int numNonSurfacePrimitives = 0;
int* lensPtr = *lens;
unsigned int i;
int noIndices = 0;
for (i = 0; i < strips.size(); i++)
Geometry::PrimitiveList& primitives = geom.getPrimitiveList();
Geometry::PrimitiveList::iterator itr;
for(itr=primitives.begin();
itr!=primitives.end();
++itr)
{
noIndices += strips[i]->m_faces.size()+2;
}
noIndices += leftoverFaces.size()*3;
*osg_indices = osgNew 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
switch((*itr)->getMode())
{
NvFaceInfo tFirstFace(strip->m_faces[0]->m_v0, strip->m_faces[0]->m_v1, strip->m_faces[0]->m_v2);
case(Primitive::TRIANGLES):
case(Primitive::TRIANGLE_STRIP):
case(Primitive::TRIANGLE_FAN):
case(Primitive::QUADS):
case(Primitive::QUAD_STRIP):
case(Primitive::POLYGON):
++numSurfacePrimitives;
break;
default:
++numNonSurfacePrimitives;
break;
}
}
if (!numSurfacePrimitives) return;
TriangleFunctor<TriangleAcumulatorFunctor> taf;
// If there is a second face, reorder vertices such that the
// unique vertex is first
if (nStripFaceCount > 1)
Geometry::PrimitiveList new_primitives;
new_primitives.reserve(primitives.size());
for(itr=primitives.begin();
itr!=primitives.end();
++itr)
{
switch((*itr)->getMode())
{
case(Primitive::TRIANGLES):
case(Primitive::TRIANGLE_STRIP):
case(Primitive::TRIANGLE_FAN):
case(Primitive::QUADS):
case(Primitive::QUAD_STRIP):
case(Primitive::POLYGON):
(*itr)->applyPrimitiveOperation(taf);
break;
default:
new_primitives.push_back(*itr);
break;
}
}
if (!taf.in_indices.empty())
{
int in_numVertices = -1;
for(WordVec::iterator itr=taf.in_indices.begin();
itr!=taf.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 = 2;
NvStripInfoVec strips;
NvFaceInfoVec leftoverFaces;
NvStripifier stripifier;
stripifier.Stripify(taf.in_indices,
in_numVertices,
in_cacheSize,
in_minStripLength,
strips,
leftoverFaces);
unsigned int i;
for (i = 0; i < strips.size(); ++i)
{
NvStripInfo *strip = strips[i];
int nStripFaceCount = strip->m_faces.size();
osg::UShortDrawElements* elements = osgNew osg::UShortDrawElements(osg::Primitive::TRIANGLE_STRIP);
elements->reserve(nStripFaceCount+2);
new_primitives.push_back(elements);
NvFaceInfo tLastFace(0, 0, 0);
// Handle the first face in the strip
{
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);
}
NvFaceInfo tFirstFace(strip->m_faces[0]->m_v0, strip->m_faces[0]->m_v1, strip->m_faces[0]->m_v2);
// If there is a third face, reorder vertices such that the
// shared vertex is last
if (nStripFaceCount > 2)
// If there is a second face, reorder vertices such that the
// unique vertex is first
if (nStripFaceCount > 1)
{
int nShared = NvStripifier::GetSharedVertex(strip->m_faces[2], &tFirstFace);
if (nShared == tFirstFace.m_v1)
int nUnique = NvStripifier::GetUniqueVertexInB(strip->m_faces[1], &tFirstFace);
if (nUnique == tFirstFace.m_v1)
{
std::swap(tFirstFace.m_v1, tFirstFace.m_v2);
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;
elements->push_back(tFirstFace.m_v0);
elements->push_back(tFirstFace.m_v1);
elements->push_back(tFirstFace.m_v2);
// Update last face info
tLastFace.m_v0 = tLastFace.m_v1;
tLastFace.m_v1 = tLastFace.m_v2;
tLastFace.m_v2 = nUnique;
tLastFace = tFirstFace;
}
for (int j = 1; j < nStripFaceCount; j++)
{
int nUnique = NvStripifier::GetUniqueVertexInB(&tLastFace, strip->m_faces[j]);
if (nUnique != -1)
{
elements->push_back(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())
if (leftoverFaces.size())
{
int in_numVertices = -1;
for(WordVec::iterator itr=tt.in_indices.begin();
itr!=tt.in_indices.end();
++itr)
osg::UShortDrawElements* triangles = osgNew osg::UShortDrawElements(osg::Primitive::TRIANGLES);
triangles->reserve(leftoverFaces.size()*3);
new_primitives.push_back(triangles);
for (i = 0; i < leftoverFaces.size(); ++i)
{
if (*itr>in_numVertices) in_numVertices=*itr;
triangles->push_back(leftoverFaces[i]->m_v0);
triangles->push_back(leftoverFaces[i]->m_v1);
triangles->push_back(leftoverFaces[i]->m_v2);
}
// 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.computeNumVerts();
gset.dirtyDisplayList();
gset.dirtyBound();
}
else
{
notify(INFO) << "No triangles to stripify"<< std::endl;
}
geom.setPrimitiveList(new_primitives);
}
}
@@ -306,7 +208,7 @@ 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);
osg::Geometry* geom = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
if (geom) stripify(*geom);
}
}