Added 'normals' pseudoloader

This commit is contained in:
Don BURNS 2006-02-06 19:40:45 +00:00
parent 6624f3aa62
commit da9de96fae
4 changed files with 417 additions and 0 deletions

View File

@ -0,0 +1,14 @@
TOPDIR = ../../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
ReaderWriterNormals.cpp\
Normals.cpp\
LIBS += $(OSG_LIBS) $(OTHER_LIBS) $(SOCKET_LIBS)
TARGET_BASENAME = normals
include $(TOPDIR)/Make/cygwin_plugin_def
PLUGIN = $(PLUGIN_PREFIX)$(TARGET_BASENAME).$(PLUGIN_EXT)
include $(TOPDIR)/Make/makerules

View File

@ -0,0 +1,230 @@
#include "Normals.h"
using namespace osg;
Normals::Normals( Node *node, float scale, Mode mode )
{
MakeNormalsVisitor mnv(scale);
mnv.setMode( 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, Normals::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_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

View File

@ -0,0 +1,78 @@
#ifndef NORMALS_DEF
#define NORMALS_DEF
//#define DEBUG 1
#ifdef DEBUG
#include <iostream>
#endif
#include <stack>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/NodeVisitor>
#include <osg/MatrixTransform>
class Normals: public osg::Geode
{
public:
enum Mode {
SurfaceNormals,
VertexNormals
};
Normals( osg::Node *node, float scale=1.0, Mode mode=SurfaceNormals );
private:
class MakeNormalsVisitor : public osg::NodeVisitor
{
public:
MakeNormalsVisitor(float normalScale=1.0, Normals::Mode=Normals::SurfaceNormals );
void setMode( Mode mode ) { _mode = mode; }
virtual void apply(osg::MatrixTransform& tx);
virtual void apply( osg::Geode &geode );
osg::Vec3Array *getCoords() { return _local_coords.get(); }
private:
osg::ref_ptr<osg::Vec3Array> _local_coords;
float _normal_scale;
Mode _mode;
osg::Matrix _mat;
std::stack<osg::Matrix> _matStack;
void _processPrimitive( unsigned int nv,
osg::Vec3Array::iterator coords,
osg::Vec3Array::iterator normals,
osg::Geometry::AttributeBinding binding );
};
#ifdef DEBUG
static void _printPrimitiveType( osg::PrimitiveSet *pset );
#endif
};
class SurfaceNormals: public Normals
{
public:
SurfaceNormals( Node *node, float scale=1.0 ):
Normals( node, scale, Normals::SurfaceNormals ) {}
};
class VertexNormals: public Normals
{
public:
VertexNormals( Node *node, float scale=1.0 ):
Normals( node, scale, Normals::VertexNormals ) {}
};
#endif

View File

@ -0,0 +1,95 @@
#include <iostream>
#include <sstream>
#include <math.h>
#include <osg/Notify>
#include <osg/Group>
#include <osgDB/ReadFile>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
#include "Normals.h"
class NormalsReader: public osgDB::ReaderWriter
{
public:
NormalsReader() {}
virtual const char* className() { return "Normals Pseudo Loader"; }
virtual bool acceptsExtension(const std::string& extension) const
{
return osgDB::equalCaseInsensitive(extension,"normals");
}
virtual ReadResult readObject(const std::string& fileName, const Options* opt) const
{ return readNode(fileName,opt); }
virtual ReadResult readNode(const std::string& fileName, const Options* options) const
{
std::string ext = osgDB::getFileExtension(fileName);
if (!acceptsExtension(ext))
return ReadResult::FILE_NOT_HANDLED;
float scale = 1.0;
Normals::Mode mode = Normals::VertexNormals;
if (options)
{
std::istringstream iss(options->getOptionString());
std::string opt;
while (iss >> opt)
{
if( opt == "help" || opt == "HELP" )
{
osg::notify( osg::INFO ) <<
"Normals Plugin usage: <application> [-O options] <model.ext>.normals\n"
" options: \"scale=<scale>\" (default = 1.0)\n"
" \"mode=<VertexNormals|SurfaceNormals>\" (default = VertexNormals)" << std::endl;
}
else
{
int index = opt.find( "=" );
if( opt.substr( 0, index ) == "scale" ||
opt.substr( 0, index ) == "SCALE" )
{
scale = atof( opt.substr( index+1 ).c_str() );
}
else if( opt.substr( 0, index ) == "mode" || opt.substr( 0, index ) == "MODE" )
{
std::string modestr = opt.substr(index+1);
if( modestr == "VertexNormals" )
mode = Normals::VertexNormals;
else if( modestr == "SurfaceNormals" )
mode = Normals::SurfaceNormals;
else
mode = Normals::VertexNormals;
}
}
}
}
std::string nodeName = osgDB::getNameLessExtension( fileName );
if( !nodeName.empty() )
{
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile( nodeName );
if( node.valid() )
{
osg::ref_ptr<osg::Group> group = new osg::Group;
group->addChild( node.get() );
if( mode == Normals::VertexNormals )
group->addChild( new VertexNormals( node.get(), scale ));
else if( mode == Normals::SurfaceNormals )
group->addChild( new SurfaceNormals( node.get(), scale ));
return group.get();
}
}
return 0L;
}
};
osgDB::RegisterReaderWriterProxy<NormalsReader> g_normalsReader_Proxy;