Files
OpenSceneGraph/src/osgPlugins/normals/Normals.cpp
2012-03-21 17:36:20 +00:00

252 lines
9.3 KiB
C++

#include "Normals.h"
using namespace osg;
Normals::Normals( Node *node, float scale, Mode mode )
{
setName(mode == VertexNormals ? "VertexNormals" : "SurfaceNormals");
MakeNormalsVisitor mnv(scale,mode);
node->accept( mnv );
ref_ptr<Vec3Array> coords = mnv.getCoords();
ref_ptr<Vec4Array> colors = new Vec4Array;
if( mode == SurfaceNormals )
colors->push_back( Vec4( 0, 1, 0, 1 ));
else if( mode == VertexNormals )
colors->push_back( Vec4( 1, 0, 0, 1 ));
ref_ptr<Geometry> geom = new Geometry;
geom->setVertexArray( coords.get() );
geom->setColorArray( colors.get() );
geom->setColorBinding( Geometry::BIND_OVERALL );
geom->addPrimitiveSet( new DrawArrays( PrimitiveSet::LINES, 0, coords->size()));
StateSet *sset = new StateSet;
sset->setMode( GL_LIGHTING, StateAttribute::OFF);
geom->setStateSet( sset );
addDrawable( geom.get() );
}
Normals::MakeNormalsVisitor::MakeNormalsVisitor( float normalScale, Mode mode):
NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
_normal_scale(normalScale),
_mode(mode)
{
_local_coords = new Vec3Array;
_mat = osg::Matrix::identity();
}
void Normals::MakeNormalsVisitor::apply(osg::MatrixTransform& tx)
{
_matStack.push( _mat );
_mat = _mat * tx.getMatrix();
traverse( tx );
_mat = _matStack.top();
_matStack.pop();
}
void Normals::MakeNormalsVisitor::apply( Geode &geode )
{
for( unsigned int i = 0; i < geode.getNumDrawables(); i++ )
{
Geometry *geom = dynamic_cast<Geometry *>(geode.getDrawable(i));
if( geom )
{
Vec3Array *coords = dynamic_cast<Vec3Array*>(geom->getVertexArray());
if( coords == 0L )
continue;
Vec3Array *normals = dynamic_cast<Vec3Array*>(geom->getNormalArray());
if( normals == 0L )
continue;
Geometry::AttributeBinding binding = geom->getNormalBinding();
if( binding == Geometry::BIND_OFF )
continue;
if( binding == Geometry::BIND_OVERALL )
{
Vec3 v(0,0,0);
Vec3 n = normals->front();
Vec3Array::iterator coord_index = coords->begin();
while( coord_index != coords->end() )
v += *(coord_index++) * _mat;
v /= (float)(coords->size());
n *= _normal_scale;
_local_coords->push_back( v );
_local_coords->push_back( (v + n));
}
else // BIND_PER_PRIMITIVE_SET, BIND_PER_PRIMITIVE, BIND_PER_VERTEX
{
Geometry::PrimitiveSetList& primitiveSets = geom->getPrimitiveSetList();
Geometry::PrimitiveSetList::iterator itr;
Vec3Array::iterator coord_index = coords->begin();
Vec3Array::iterator normals_index = normals->begin();
for(itr=primitiveSets.begin(); itr!=primitiveSets.end(); ++itr)
{
#ifdef DEBUG
_printPrimitiveType( (*itr).get() );
#endif
if( binding == Geometry::BIND_PER_PRIMITIVE_SET )
{
Vec3 v(0,0,0);
Vec3 n = *(normals_index++);
int ni = (*itr)->getNumIndices();
for( int i = 0; i < ni; i++ )
v += *(coord_index++) * _mat;
v /= (float)(ni);
n *= _normal_scale;
_local_coords->push_back( v );
_local_coords->push_back( (v + n));
}
else
{
switch((*itr)->getMode())
{
case(PrimitiveSet::TRIANGLES):
{
for( unsigned int j = 0; j < (*itr)->getNumPrimitives(); j++ )
{
_processPrimitive( 3, coord_index, normals_index, binding );
coord_index += 3;
if( binding == Geometry::BIND_PER_PRIMITIVE )
normals_index++;
else
normals_index+=3;
}
break;
}
case(PrimitiveSet::TRIANGLE_STRIP):
{
for( unsigned int j = 0; j < (*itr)->getNumIndices()-2; j++ )
{
_processPrimitive( 3, coord_index, normals_index, binding );
coord_index++;
normals_index++;
}
coord_index += 2;
if( binding == Geometry::BIND_PER_VERTEX )
normals_index += 2;
break;
}
case(PrimitiveSet::TRIANGLE_FAN):
break;
case(PrimitiveSet::QUADS):
{
for( unsigned int j = 0; j < (*itr)->getNumPrimitives(); j++ )
{
_processPrimitive( 4, coord_index, normals_index, binding );
coord_index += 4;
if( binding == Geometry::BIND_PER_PRIMITIVE )
normals_index++;
else
normals_index+=4;
}
break;
}
case(PrimitiveSet::QUAD_STRIP):
break;
case(PrimitiveSet::POLYGON):
{
DrawArrayLengths* dal = dynamic_cast<DrawArrayLengths*>((*itr).get());
if (dal) {
for (unsigned int j = 0; j < dal->size(); ++j) {
unsigned int num_prim = (*dal)[j];
//OSG_WARN << "j=" << j << " num_prim=" << num_prim << std::endl;
_processPrimitive(num_prim, coord_index, normals_index, binding);
coord_index += num_prim;
if (binding == Geometry::BIND_PER_PRIMITIVE) {
++normals_index;
} else {
normals_index += num_prim;
}
}
}
break;
}
default:
break;
}
}
}
}
}
}
traverse( geode );
}
void Normals::MakeNormalsVisitor::_processPrimitive( unsigned int nv,
Vec3Array::iterator coords,
Vec3Array::iterator normals,
Geometry::AttributeBinding binding )
{
Vec3 v(0,0,0);
Vec3 n(0,0,0);
if( _mode == SurfaceNormals || binding == Geometry::BIND_PER_PRIMITIVE )
{
if( binding == Geometry::BIND_PER_PRIMITIVE )
{
n = *(normals++);
}
else if( binding == Geometry::BIND_PER_VERTEX )
{
for( unsigned int i = 0; i < nv; i++ )
n += *(normals++);
n /= (float)(nv);
}
for( unsigned int i = 0; i < nv; i++ )
v += *(coords++) * _mat;
v /= (float)(nv);
n *= _normal_scale;
_local_coords->push_back( v );
_local_coords->push_back( (v + n));
}
else if( _mode == VertexNormals )
{
for( unsigned int i = 0; i < nv; i++ )
{
v = *(coords++) * _mat;
n = *(normals++);
n *= _normal_scale;
_local_coords->push_back( v );
_local_coords->push_back( (v + n));
}
}
}
#ifdef DEBUG
void Normals::_printPrimitiveType( osg::PrimitiveSet *pset )
{
std::cout << (
pset->getMode() == PrimitiveSet::POINTS ? "POINTS" :
pset->getMode() == PrimitiveSet::LINES ? "LINES" :
pset->getMode() == PrimitiveSet::LINE_STRIP ? "LINE_STRIP" :
pset->getMode() == PrimitiveSet::LINE_LOOP ? "LINE_LOOP" :
pset->getMode() == PrimitiveSet::TRIANGLES ? "TRIANGLES" :
pset->getMode() == PrimitiveSet::TRIANGLE_STRIP ? "TRIANGLE_STRIP" :
pset->getMode() == PrimitiveSet::TRIANGLE_FAN ? "TRIANGLE_FAN" :
pset->getMode() == PrimitiveSet::QUADS ? "QUADS" :
pset->getMode() == PrimitiveSet::QUAD_STRIP ? "QUAD_STRIP" :
pset->getMode() == PrimitiveSet::POLYGON ? "POLYGON" : "Dunno" ) << std::endl;
}
#endif