#include "Normals.h" using namespace osg; Normals::Normals( Node *node, float scale, Mode mode ) { MakeNormalsVisitor mnv(scale,mode); node->accept( mnv ); ref_ptr coords = mnv.getCoords(); ref_ptr 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 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(geode.getDrawable(i)); if( geom ) { Vec3Array *coords = dynamic_cast(geom->getVertexArray()); if( coords == 0L ) continue; Vec3Array *normals = dynamic_cast(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_PRIMTIVE_SET, BIND_PER_PRIMTITIV, 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): case(PrimitiveSet::POLYGON): 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