More clean up for synch with 0.8.42

This commit is contained in:
Don BURNS
2001-09-19 21:19:47 +00:00
parent 2462c6273c
commit 7e81f6cfa6
292 changed files with 39673 additions and 0 deletions

View File

View File

@@ -0,0 +1,20 @@
#!smake
include ../../../Make/makedefs
C++FILES = \
osgreflect.cpp \
TARGET = ../../../bin/osgreflect
TARGET_BIN_FILES = osgreflect
#note, use this library list when using the Performer osgPlugin.
#LIBS = ${PFLIBS} -losgGLUT -losgUtil -losgDB -losg $(GLUTLIB) -lGLU -lGL -lm -lXmu -lX11 -lXi
#note, standard library list.
LIBS = -losgGLUT -losgUtil -losgDB -losg $(GLUTLIB) -lGLU -lGL -lm -lXmu -lX11 -lXi
C++FLAGS += -I../../../include
LDFLAGS += -L../../../lib
include ../../../Make/makerules

View File

@@ -0,0 +1,484 @@
#include <osg/Node>
#include <osg/GeoSet>
#include <osg/Notify>
#include <osg/Transform>
#include <osg/Texture>
#include <osg/Transparency>
#include <osg/Stencil>
#include <osg/ColorMask>
#include <osg/Depth>
#include <osg/ClipPlane>
#include <osgUtil/TrackballManipulator>
#include <osgUtil/FlightManipulator>
#include <osgUtil/DriveManipulator>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <GL/glut.h>
#include <osgGLUT/Viewer>
//
// A simple demo demonstrating planer reflections using multiple renderings
// of a subgraph, overriding of state attribures and use of the stencil buffer.
//
// The multipass system implemented here is a variation if Mark Kilgard's
// paper "Improving Shadows and Reflections via the Stencil Buffer" which
// can be found on the developer parts of the NVidia web site.
//
// The variations comes from the fact that the mirrors stencil values
// are done on the first pass, rather than the second as in Mark's paper.
// The second pass is now Mark's first pass - drawing the unreflected scene,
// but also unsets the stencil buffer. This variation stops the unreflected
// world poking through the mirror to be seen in the final rendering and
// also obscures the world correctly when on the reverse side of the mirror.
// Although there is still some unresolved issue with the clip plane needing
// to be flipped when looking at the reverse side of the mirror. Niether
// of these issues are mentioned in the Mark's paper, but trip us up when
// we apply them.
// create an app visitor, to be used on each frame update,
// the below app visitor rotates the loaded model.
class AppVisitor : public osg::NodeVisitor {
public:
bool _haveDoneTransformTransform;
float _delta_angle;
float _angular_velocity;
osg::Vec3 _pivotPoint;
osg::Transform* _modifyTransform;
osg::Timer _timer;
osg::Timer_t _previous_t;
AppVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
_haveDoneTransformTransform = true;
_modifyTransform = NULL;
_delta_angle = 0;
_angular_velocity = 45; //degrees a sec.
_previous_t = _timer.tick();
}
virtual void reset()
{
// set to no transform done so far in this new traversal.
_haveDoneTransformTransform = false;
// update angle of rotation.
osg::Timer_t new_t = _timer.tick();
_delta_angle = _angular_velocity*_timer.delta_s(_previous_t,new_t);
_previous_t = new_t;
}
virtual void apply(osg::Transform& visitor_dcs)
{
if (&visitor_dcs == _modifyTransform && !_haveDoneTransformTransform)
{
// update the specified dcs.
visitor_dcs.preTranslate(_pivotPoint[0],_pivotPoint[1],_pivotPoint[2]);
visitor_dcs.preRotate(_delta_angle,0.0f,0.0f,1.0f);
visitor_dcs.preTranslate(-_pivotPoint[0],-_pivotPoint[1],-_pivotPoint[2]);
// set to true to prevent applying rotation more than once
// since the subgraph appears twice in the overall scene.
_haveDoneTransformTransform = true;
}
}
};
/*
* Function to read several files (typically one) as specified on the command
* line, and return them in an osg::Node
*/
osg::Node* getNodeFromFiles(int argc,char **argv)
{
osg::Node *rootnode = new osg::Node;
int i;
typedef std::vector<osg::Node*> NodeList;
NodeList nodeList;
for( i = 1; i < argc; i++ )
{
if (argv[i][0]=='-')
{
switch(argv[i][1])
{
case('l'):
++i;
if (i<argc)
{
osgDB::Registry::instance()->loadLibrary(argv[i]);
}
break;
case('e'):
++i;
if (i<argc)
{
std::string libName = osgDB::Registry::instance()->createLibraryNameForExt(argv[i]);
osgDB::Registry::instance()->loadLibrary(libName);
}
break;
}
} else
{
osg::Node *node = osgDB::readNodeFile( argv[i] );
if( node != (osg::Node *)0L )
{
if (node->getName().empty()) node->setName( argv[i] );
nodeList.push_back(node);
}
}
}
if (nodeList.size()==0)
{
osg::notify(osg::WARN) << "No data loaded."<<endl;
exit(0);
}
if (nodeList.size()==1)
{
rootnode = nodeList.front();
}
else // size >1
{
osg::Group* group = new osg::Group();
for(NodeList::iterator itr=nodeList.begin();
itr!=nodeList.end();
++itr)
{
group->addChild(*itr);
}
rootnode = group;
}
return rootnode;
}
osg::StateSet* createMirrorTexturedState(const std::string& filename)
{
osg::StateSet* dstate = new osg::StateSet;
dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
// set up the texture.
osg::Image* image = osgDB::readImageFile(filename.c_str());
if (image)
{
osg::Texture* texture = new osg::Texture;
texture->setImage(image);
dstate->setAttributeAndModes(texture,osg::StateAttribute::ON);
}
return dstate;
}
osg::Drawable* createMirrorSurface(float xMin,float xMax,float yMin,float yMax,float z)
{
// set up the drawstate.
// set up the geoset.
osg::GeoSet* gset = new osg::GeoSet;
osg::Vec3* coords = new osg::Vec3 [4];
coords[0].set(xMin,yMax,z);
coords[1].set(xMin,yMin,z);
coords[2].set(xMax,yMin,z);
coords[3].set(xMax,yMax,z);
gset->setCoords(coords);
osg::Vec3* norms = new osg::Vec3 [1];
norms[0].set(0.0f,0.0f,1.0f);
gset->setNormals(norms);
gset->setNormalBinding(osg::GeoSet::BIND_OVERALL);
osg::Vec2* tcoords = new osg::Vec2 [4];
tcoords[0].set(0.0f,1.0f);
tcoords[1].set(0.0f,0.0f);
tcoords[2].set(1.0f,0.0f);
tcoords[3].set(1.0f,1.0f);
gset->setTextureCoords(tcoords);
gset->setTextureBinding(osg::GeoSet::BIND_PERVERTEX);
osg::Vec4* colours = new osg::Vec4;
colours->set(1.0f,1.0f,1.0,1.0f);
gset->setColors(colours);
gset->setColorBinding(osg::GeoSet::BIND_OVERALL);
gset->setNumPrims(1);
gset->setPrimType(osg::GeoSet::QUADS);
return gset;
}
void write_usage()
{
osg::notify(osg::NOTICE)<<endl;
osg::notify(osg::NOTICE)<<"usage:"<<endl;
osg::notify(osg::NOTICE)<<" osgreflect [options] infile1 [infile2 ...]"<<endl;
osg::notify(osg::NOTICE)<<endl;
osg::notify(osg::NOTICE)<<"options:"<<endl;
osg::notify(osg::NOTICE)<<" -l libraryName - load plugin of name libraryName"<<endl;
osg::notify(osg::NOTICE)<<" i.e. -l osgdb_pfb"<<endl;
osg::notify(osg::NOTICE)<<" Useful for loading reader/writers which can load"<<endl;
osg::notify(osg::NOTICE)<<" other file formats in addition to its extension."<<endl;
osg::notify(osg::NOTICE)<<" -e extensionName - load reader/wrter plugin for file extension"<<endl;
osg::notify(osg::NOTICE)<<" i.e. -e pfb"<<endl;
osg::notify(osg::NOTICE)<<" Useful short hand for specifying full library name as"<<endl;
osg::notify(osg::NOTICE)<<" done with -l above, as it automatically expands to the"<<endl;
osg::notify(osg::NOTICE)<<" full library name appropriate for each platform."<<endl;
osg::notify(osg::NOTICE)<<endl;
}
int main( int argc, char **argv )
{
// initialize the GLUT
glutInit( &argc, argv );
if (argc<2)
{
write_usage();
return 0;
}
// load a model from file, and add it into the root group node.
osg::Node* loadedModel = getNodeFromFiles( argc, argv);
if (!loadedModel)
{
write_usage();
return 1;
}
osg::Transform* loadedModelTransform = new osg::Transform;
loadedModelTransform->addChild(loadedModel);
// calculate where to place the mirror according to the
// loaded models bounding sphere.
const osg::BoundingSphere& bs = loadedModelTransform->getBound();
float width_factor = 1.5;
float height_factor = 0.3;
float xMin = bs.center().x()-bs.radius()*width_factor;
float xMax = bs.center().x()+bs.radius()*width_factor;
float yMin = bs.center().y()-bs.radius()*width_factor;
float yMax = bs.center().y()+bs.radius()*width_factor;
float z = bs.center().z()-bs.radius()*height_factor;
// create a textured, transparent node at the appropriate place.
osg::Drawable* mirror = createMirrorSurface(xMin,xMax,yMin,yMax,z);
osg::Group* rootNode = new osg::Group;
// make sure that the global color mask exists.
osg::ColorMask* rootColorMask = new osg::ColorMask;
rootColorMask->setMask(true,true,true,true);
// set up depth so all writing to depth goes to maximum depth.
osg::Depth* rootDepth = new osg::Depth;
rootDepth->setFunction(osg::Depth::LESS);
rootDepth->setRange(0.0,1.0);
osg::StateSet* rootStateSet = new osg::StateSet();
rootStateSet->setAttribute(rootColorMask);
rootStateSet->setAttribute(rootDepth);
rootNode->setStateSet(rootStateSet);
// bin1 - set up the stencil values and depth for mirror.
{
// set up the stencil ops so that the stencil buffer get set at
// the mirror plane
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::ALWAYS,1,~0);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::REPLACE);
// switch off the writing to the color bit planes.
osg::ColorMask* colorMask = new osg::ColorMask;
colorMask->setMask(false,false,false,false);
osg::StateSet* statesetBin1 = new osg::StateSet();
statesetBin1->setRenderBinDetails(1,"RenderBin");
statesetBin1->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
statesetBin1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
statesetBin1->setAttribute(colorMask);
// set up the mirror geode.
osg::Geode* geode = new osg::Geode;
geode->addDrawable(mirror);
geode->setStateSet(statesetBin1);
rootNode->addChild(geode);
}
// bin one - draw scene without mirror or reflection, unset
// stencil values where scene is infront of mirror and hence
// occludes the mirror.
{
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::ALWAYS,0,~0);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::REPLACE);
osg::StateSet* statesetBin2 = new osg::StateSet();
statesetBin2->setRenderBinDetails(2,"RenderBin");
statesetBin2->setAttributeAndModes(stencil,osg::StateAttribute::ON);
osg::Group* groupBin2 = new osg::Group();
groupBin2->setStateSet(statesetBin2);
groupBin2->addChild(loadedModelTransform);
rootNode->addChild(groupBin2);
}
// bin3 - set up the depth to the furthest depth value
{
// set up the stencil ops so that only operator on this mirrors stencil value.
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::EQUAL,1,~0);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
// switch off the writing to the color bit planes.
osg::ColorMask* colorMask = new osg::ColorMask;
colorMask->setMask(false,false,false,false);
// set up depth so all writing to depth goes to maximum depth.
osg::Depth* depth = new osg::Depth;
depth->setFunction(osg::Depth::ALWAYS);
depth->setRange(1.0,1.0);
osg::StateSet* statesetBin3 = new osg::StateSet();
statesetBin3->setRenderBinDetails(3,"RenderBin");
statesetBin3->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
statesetBin3->setAttributeAndModes(stencil,osg::StateAttribute::ON);
statesetBin3->setAttribute(colorMask);
statesetBin3->setAttribute(depth);
// set up the mirror geode.
osg::Geode* geode = new osg::Geode;
geode->addDrawable(mirror);
geode->setStateSet(statesetBin3);
rootNode->addChild(geode);
}
// bin4 - draw the reflection.
{
// now create the 'reflection' of the loaded model by applying
// create a Transform which flips the loaded model about the z axis
// relative to the mirror node, the loadedModel is added to the
// Transform so now appears twice in the scene, but is shared so there
// is negligable memory overhead. Also use an osg::StateSet
// attached to the Transform to override the face culling on the subgraph
// to prevert an 'inside' out view of the reflected model.
// set up the stencil ops so that only operator on this mirrors stencil value.
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::EQUAL,1,~0);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
// this clip plane removes any of the scene which when mirror would
// poke through the mirror. However, this clip plane should really
// flip sides once the eye point goes to the back of the mirror...
osg::ClipPlane* clipplane = new osg::ClipPlane;
clipplane->setClipPlane(osg::Vec4(0.0f,0.0f,-1.0f,z));
clipplane->setClipPlaneNum(0);
osg::StateSet* dstate = new osg::StateSet;
dstate->setRenderBinDetails(4,"RenderBin");
dstate->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE_OFF);
dstate->setAttributeAndModes(stencil,osg::StateAttribute::ON);
dstate->setAttributeAndModes(clipplane,osg::StateAttribute::ON);
osg::Transform* dcs = new osg::Transform;
dcs->setStateSet(dstate);
dcs->preTranslate(0.0f,0.0f,z);
dcs->preScale(1.0f,1.0f,-1.0f);
dcs->preTranslate(0.0f,0.0f,-z);
dcs->addChild(loadedModelTransform);
rootNode->addChild(dcs);
}
// bin5 - draw the textured mirror and blend it with the reflection.
{
// set up depth so all writing to depth goes to maximum depth.
osg::Depth* depth = new osg::Depth;
depth->setFunction(osg::Depth::ALWAYS);
osg::Stencil* stencil = new osg::Stencil;
stencil->setFunction(osg::Stencil::EQUAL,1,~0);
stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::ZERO);
// set up additive blending.
osg::Transparency* trans = new osg::Transparency;
trans->setFunction(osg::Transparency::ONE,osg::Transparency::ONE);
osg::StateSet* statesetBin5 = createMirrorTexturedState("tank.rgb");
statesetBin5->setRenderBinDetails(5,"RenderBin");
statesetBin5->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
statesetBin5->setAttributeAndModes(stencil,osg::StateAttribute::ON);
statesetBin5->setAttributeAndModes(trans,osg::StateAttribute::ON);
statesetBin5->setAttribute(depth);
// set up the mirror geode.
osg::Geode* geode = new osg::Geode;
geode->addDrawable(mirror);
geode->setStateSet(statesetBin5);
rootNode->addChild(geode);
}
// initialize the viewer.
osgGLUT::Viewer viewer;
viewer.addViewport( rootNode );
// create and register the app visitor.
AppVisitor* appVisitor = new AppVisitor();
appVisitor->_modifyTransform = loadedModelTransform;
appVisitor->_pivotPoint = bs.center();
viewer.getViewportSceneView(0)->setAppVisitor(appVisitor);
// register trackball, flight and drive.
viewer.registerCameraManipulator(new osgUtil::TrackballManipulator);
viewer.registerCameraManipulator(new osgUtil::FlightManipulator);
viewer.registerCameraManipulator(new osgUtil::DriveManipulator);
viewer.open();
viewer.run();
return 0;
}

26
src/Demos/sgv/README Normal file
View File

@@ -0,0 +1,26 @@
Note: Using sgv with Peformer (for IRIX and Linux users only)
=============================================================
If you find problems with loading .pfb files its likely that its due to undefined
symbols. This isn't a problem with the OSG implementation, but alas the only
current solution is to directly link you app with the Performer libraries. The
Makefile contains two library list. In Makefile you'll see something like :
#note, use this library list when using the Performer osgPlugin.
#LIBS = ${PFLIBS} -losgGLUT -losgDB -losg -lGLU -lGL -lm -lXmu -lX11 -lXi
#note, standard library list.
LIBS = -losgGLUT -losgDB -losg -lGLU -lGL -lm -lXmu -lX11 -lXi
Simple comment in the LIBS line with PFLIBS and comment out the standard LIBS,
then :
make clean
make
Hopefully the Performer distribution will eventually work as a dynamic plugin
but until that day we're stuck with this 'hack'...
Robert Osfield,
March 20001.

98
src/osg/ClipPlane.cpp Normal file
View File

@@ -0,0 +1,98 @@
#include <osg/ClipPlane>
#include <osg/Notify>
using namespace osg;
ClipPlane::ClipPlane()
{
_clipPlane = new double[4];
_clipPlane[0] = 0.0;
_clipPlane[1] = 0.0;
_clipPlane[2] = 0.0;
_clipPlane[3] = 0.0;
_clipPlaneNum = 0;
}
ClipPlane::~ClipPlane()
{
delete _clipPlane;
}
void ClipPlane::setClipPlane(const Vec4& plane)
{
_clipPlane[0] = plane[0];
_clipPlane[1] = plane[1];
_clipPlane[2] = plane[2];
_clipPlane[3] = plane[3];
}
void ClipPlane::setClipPlane(const Plane& plane)
{
_clipPlane[0] = plane[0];
_clipPlane[1] = plane[1];
_clipPlane[2] = plane[2];
_clipPlane[3] = plane[3];
}
void ClipPlane::setClipPlane(const double* plane)
{
if (plane)
{
_clipPlane[0] = plane[0];
_clipPlane[1] = plane[1];
_clipPlane[2] = plane[2];
_clipPlane[3] = plane[3];
}
else
{
notify(WARN)<<"Warning: ClipPlane::setClipPlane() passed NULL plane array, ignoring operation."<<endl;
}
}
void ClipPlane::getClipPlane(Vec4& plane) const
{
plane[0] = (float)_clipPlane[0];
plane[1] = (float)_clipPlane[1];
plane[2] = (float)_clipPlane[2];
plane[3] = (float)_clipPlane[3];
}
void ClipPlane::getClipPlane(Plane& plane) const
{
plane[0] = _clipPlane[0];
plane[1] = _clipPlane[1];
plane[2] = _clipPlane[2];
plane[3] = _clipPlane[3];
}
void ClipPlane::getClipPlane(double* plane) const
{
if (plane)
{
plane[0] = _clipPlane[0];
plane[1] = _clipPlane[1];
plane[2] = _clipPlane[2];
plane[3] = _clipPlane[3];
}
else
{
notify(WARN)<<"Warning: ClipPlane::getClipPlane() passed NULL plane array, ignoring operation."<<endl;
}
}
void ClipPlane::setClipPlaneNum(const unsigned int num)
{
_clipPlaneNum = num;
}
const unsigned int ClipPlane::getClipPlaneNum() const
{
return _clipPlaneNum;
}
void ClipPlane::apply(State&) const
{
glClipPlane((GLenum)(GL_CLIP_PLANE0+_clipPlaneNum),_clipPlane);
}

23
src/osg/ColorMask.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include <osg/ColorMask>
using namespace osg;
ColorMask::ColorMask()
{
// set up same defaults as glColorMask.
_red = true;
_green = true;
_blue = true;
_alpha = true;
}
ColorMask::~ColorMask()
{
}
void ColorMask::apply(State&) const
{
glColorMask((GLboolean)_red,(GLboolean)_green,(GLboolean)_blue,(GLboolean)_alpha);
}

25
src/osg/Depth.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include <osg/Depth>
using namespace osg;
Depth::Depth()
{
_func = LESS;
_depthWriteMask = true;
_zNear = 0.0;
_zFar = 1.0;
}
Depth::~Depth()
{
}
void Depth::apply(State&) const
{
glDepthFunc((GLenum)_func);
glDepthMask((GLboolean)_depthWriteMask);
glDepthRange(_zNear,_zFar);
}

159
src/osg/Drawable.cpp Normal file
View File

@@ -0,0 +1,159 @@
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <osg/Drawable>
#include <osg/State>
#include <osg/Notify>
using namespace osg;
Drawable::DeletedDisplayListCache Drawable::s_deletedDisplayListCache;
Drawable::Drawable()
{
_bbox_computed = false;
// Note, if your are defining a subclass from drawable which is
// dynamically updated then you should set both the following to
// to false in your constructor. This will prevent any display
// lists from being automatically created and safeguard the
// dynamic updating of data.
_supportsDisplayList = true;
_useDisplayList = true;
}
Drawable::~Drawable()
{
dirtyDisplayList();
}
void Drawable::compile(State& state)
{
if (!_useDisplayList) return;
// get the contextID (user defined ID of 0 upwards) for the
// current OpenGL context.
uint contextID = state.getContextID();
// fill in array if required.
while (_globjList.size()<=contextID) _globjList.push_back(0);
// get the globj for the current contextID.
uint& globj = _globjList[contextID];
// call the globj if already set otherwise comple and execute.
if( globj != 0 )
{
glDeleteLists( globj, 1 );
}
if (_dstate.valid())
{
_dstate->compile(state);
}
globj = glGenLists( 1 );
glNewList( globj, GL_COMPILE );
drawImmediateMode(state);
glEndList();
}
void Drawable::setSupportsDisplayList(const bool flag)
{
// if value unchanged simply return.
if (_supportsDisplayList==flag) return;
// if previously set to true then need to check about display lists.
if (_supportsDisplayList)
{
if (_useDisplayList)
{
// used to support display lists and display lists switched
// on so now delete them and turn useDisplayList off.
dirtyDisplayList();
_useDisplayList = false;
}
}
// set with new value.
_supportsDisplayList=flag;
}
void Drawable::setUseDisplayList(const bool flag)
{
// if value unchanged simply return.
if (_useDisplayList==flag) return;
// if was previously set to true, remove display list.
if (_useDisplayList)
{
dirtyDisplayList();
}
if (_supportsDisplayList)
{
// set with new value.
_useDisplayList = flag;
}
else // does not support display lists.
{
if (flag)
{
notify(WARN)<<"Warning: attempt to setUseDisplayList(true) on a drawable with does not support display lists."<<endl;
}
else
{
// set with new value.
_useDisplayList = false;
}
}
}
void Drawable::dirtyDisplayList()
{
for(uint i=0;i<_globjList.size();++i)
{
if (_globjList[i] != 0)
{
Drawable::deleteDisplayList(i,_globjList[i]);
_globjList[i] = 0;
}
}
}
void Drawable::deleteDisplayList(uint contextID,uint globj)
{
if (globj!=0)
{
// insert the globj into the cache for the appropriate context.
s_deletedDisplayListCache[contextID].insert(globj);
}
}
/** flush all the cached display list which need to be deleted
* in the OpenGL context related to contextID.*/
void Drawable::flushDeletedDisplayLists(uint contextID)
{
DeletedDisplayListCache::iterator citr = s_deletedDisplayListCache.find(contextID);
if (citr!=s_deletedDisplayListCache.end())
{
std::set<uint>& displayListSet = citr->second;
for(std::set<uint>::iterator gitr=displayListSet.begin();
gitr!=displayListSet.end();
++gitr)
{
glDeleteLists(*gitr,1);
}
s_deletedDisplayListCache.erase(citr);
}
}

19
src/osg/FrontFace.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include "osg/GL"
#include "osg/FrontFace"
using namespace osg;
FrontFace::FrontFace()
{
_mode = COUNTER_CLOCKWISE;
}
FrontFace::~FrontFace()
{
}
void FrontFace::apply(State&) const
{
glFrontFace((GLenum)_mode);
}

74
src/osg/GLExtensions.cpp Normal file
View File

@@ -0,0 +1,74 @@
#ifdef _WIN32
#include <windows.h>
#elif !defined macintosh
#include <dlfcn.h>
#endif
#include "osg/GL"
#include "osg/GLExtensions"
#include "osg/Notify"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <set>
const bool osg::isGLExtensionSupported(const char *extension)
{
typedef std::set<std::string> ExtensionSet;
static ExtensionSet s_extensionSet;
static const char* s_extensions = NULL;
if (s_extensions==NULL)
{
// get the extension list from OpenGL.
s_extensions = (const char*)glGetString(GL_EXTENSIONS);
if (s_extensions==NULL) return false;
// insert the ' ' delimiated extensions words into the extensionSet.
const char *startOfWord = s_extensions;
const char *endOfWord;
while ((endOfWord = strchr(startOfWord,' '))!=NULL)
{
s_extensionSet.insert(std::string(startOfWord,endOfWord));
startOfWord = endOfWord+1;
}
if (*startOfWord!=0) s_extensionSet.insert(std::string(startOfWord));
osg::notify(INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<<endl;
for(ExtensionSet::iterator itr=s_extensionSet.begin();
itr!=s_extensionSet.end();
++itr)
{
osg::notify(INFO)<<" "<<*itr<<endl;
}
}
// true if extension found in extensionSet.
bool result = s_extensionSet.find(extension)!=s_extensionSet.end();
if (result) osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is supported."<<endl;
else osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is not supported."<<endl;
return result;
}
void* osg::getGLExtensionFuncPtr(const char *funcName)
{
#if defined(_WIN32)
return wglGetProcAddress(funcName);
#elif defined(macintosh)
return NULL;
#else
static void *lib = dlopen("libGL.so", RTLD_LAZY);
if (lib)
return dlsym(lib, funcName);
else
return NULL;
#endif
}

64
src/osg/Impostor.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include "osg/Impostor"
#include <algorithm>
using namespace osg;
Impostor::Impostor()
{
_impostorThreshold = -1.0f;
}
ImpostorSprite* Impostor::findBestImpostorSprite(const osg::Vec3& currLocalEyePoint)
{
float min_distance2 = FLT_MAX;
ImpostorSprite* impostorSprite = NULL;
for(ImpostorSpriteList::iterator itr=_impostorSpriteList.begin();
itr!=_impostorSpriteList.end();
++itr)
{
float distance2 = (currLocalEyePoint-(*itr)->getStoredLocalEyePoint()).length2();
if (distance2<min_distance2)
{
min_distance2 = distance2;
impostorSprite = itr->get();
}
}
return impostorSprite;
}
void Impostor::addImpostorSprite(ImpostorSprite* is)
{
if (is && is->getParent()!=this)
{
// add it to my impostor list first, so it remains referenced
// when its reference in the previous_owner is removed.
_impostorSpriteList.push_back(is);
if (is->getParent())
{
Impostor* previous_owner = is->getParent();
ImpostorSpriteList& isl = previous_owner->_impostorSpriteList;
// find and erase reference to is.
for(ImpostorSpriteList::iterator itr=isl.begin();
itr!=isl.end();
++itr)
{
if ((*itr)==is)
{
isl.erase(itr);
break;
}
}
}
is->setParent(this);
}
}
const bool Impostor::computeBound() const
{
return LOD::computeBound();
}

273
src/osg/ImpostorSprite.cpp Normal file
View File

@@ -0,0 +1,273 @@
#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <osg/ImpostorSprite>
#include <osg/Texture>
#include <osg/TexEnv>
#include <osg/AlphaFunc>
#include <osg/Notify>
using namespace osg;
ImpostorSprite::ImpostorSprite()
{
// don't use display list since we will be updating the geometry.
_useDisplayList = false;
_parent = NULL;
_ism = NULL;
_previous = NULL;
_next = NULL;
_texture = NULL;
_s = 0;
_t = 0;
}
ImpostorSprite::~ImpostorSprite()
{
if (_ism)
{
_ism->remove(this);
}
}
const float ImpostorSprite::calcPixelError(const Camera& camera,const int* viewport,const osg::Matrix* matrix) const
{
// find the maximum screen space pixel error between the control coords and the quad coners.
float max_error_sqrd = 0.0f;
for(int i=0;i<4;++i)
{
Vec3 projected_coord;
Vec3 projected_control;
if (matrix)
{
// project the coords of the quad into screen space.
camera.project(_coords[i]*(*matrix),viewport,projected_coord);
// project the controls coords into screen space.
camera.project(_controlcoords[i]*(*matrix),viewport,projected_control);
}
else
{
// project the coords of the quad into screen space.
camera.project(_coords[i],viewport,projected_coord);
// project the controls coords into screen space.
camera.project(_controlcoords[i],viewport,projected_control);
}
float dx = (projected_coord.x()-projected_control.x());
float dy = (projected_coord.y()-projected_control.y());
float error_sqrd = dx*dx+dy*dy;
if (error_sqrd > max_error_sqrd) max_error_sqrd = error_sqrd;
}
return sqrtf(max_error_sqrd);
}
void ImpostorSprite::drawImmediateMode(State&)
{
// when the tex env is set to REPLACE, and the
// texture is set up correctly the color has no effect.
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glBegin( GL_QUADS );
glTexCoord2fv( (GLfloat *)&_texcoords[0] );
glVertex3fv( (GLfloat *)&_coords[0] );
glTexCoord2fv( (GLfloat *)&_texcoords[1] );
glVertex3fv( (GLfloat *)&_coords[1] );
glTexCoord2fv( (GLfloat *)&_texcoords[2] );
glVertex3fv( (GLfloat *)&_coords[2] );
glTexCoord2fv( (GLfloat *)&_texcoords[3] );
glVertex3fv( (GLfloat *)&_coords[3] );
glEnd();
}
const bool ImpostorSprite::computeBound() const
{
_bbox.init();
_bbox.expandBy(_coords[0]);
_bbox.expandBy(_coords[1]);
_bbox.expandBy(_coords[2]);
_bbox.expandBy(_coords[3]);
_bbox_computed=true;
if (!_bbox.isValid())
{
cout << "******* ImpostorSprite::computeBound() problem"<<endl;
cout << "******* = "<<_coords[0]<<endl;
cout << "******* = "<<_coords[1]<<endl;
cout << "******* = "<<_coords[2]<<endl;
cout << "******* = "<<_coords[3]<<endl;
}
return true;
}
void ImpostorSprite::setTexture(Texture* tex,int s,int t)
{
_texture = tex;
_s = s;
_t = t;
}
///////////////////////////////////////////////////////////////////////////
// Helper class for managing the reuse of ImpostorSprite resources.
///////////////////////////////////////////////////////////////////////////
ImpostorSpriteManager::ImpostorSpriteManager()
{
_first = NULL;
_last = NULL;
}
ImpostorSpriteManager::~ImpostorSpriteManager()
{
while (_first)
{
ImpostorSprite* next = _first->_next;
_first->_ism = NULL;
_first->_previous = NULL;
_first->_next = NULL;
_first = next;
}
}
void ImpostorSpriteManager::push_back(ImpostorSprite* is)
{
if (is==NULL || is==_last) return;
// remove entry for exisiting position in linked list
// if it is already inserted.
if (is->_previous)
{
(is->_previous)->_next = is->_next;
}
if (is->_next)
{
(is->_next)->_previous = is->_previous;
}
if (_first==is) _first = is->_next;
if (empty())
{
_first = is;
_last = is;
is->_ism = this;
is->_previous = NULL;
is->_next = NULL;
}
else
{
// now add the element into the list.
ImpostorSprite* previous_last = _last;
previous_last->_next = is;
_last = is;
_last->_ism = this;
_last->_previous = previous_last;
_last->_next = NULL;
}
}
void ImpostorSpriteManager::remove(ImpostorSprite* is)
{
if (is==NULL) return;
// remove entry for exisiting position in linked list
// if it is already inserted.
if (is->_previous)
{
(is->_previous)->_next = is->_next;
}
if (is->_next)
{
(is->_next)->_previous = is->_previous;
}
if (_first==is) _first = is->_next;
if (_last==is) _last = is->_previous;
}
ImpostorSprite* ImpostorSpriteManager::createOrReuseImpostorSprite(int s,int t,int frameNumber)
{
if (!empty())
{
// search for a valid impostor to reuse.
ImpostorSprite* curr = _first;
while (curr)
{
if (curr->getLastFrameUsed()<=frameNumber &&
curr->s()==s &&
curr->t()==t)
{
push_back(curr);
return curr;
}
else
{
curr = curr->_next;
}
}
}
// creating new impostor sprite.
StateSet* stateset = new StateSet;
stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
Texture* texture = new Texture;
stateset->setAttributeAndModes(texture,StateAttribute::ON);
TexEnv* texenv = new TexEnv;
texenv->setMode(TexEnv::REPLACE);
stateset->setAttribute(texenv);
AlphaFunc* alphafunc = new osg::AlphaFunc;
alphafunc->setFunction( AlphaFunc::GREATER, 0.000f );
stateset->setAttributeAndModes( alphafunc, StateAttribute::ON );
// stateset->setMode( GL_ALPHA_TEST, StateAttribute::OFF );
ImpostorSprite* is = new ImpostorSprite;
is->setStateSet(stateset);
is->setTexture(texture,s,t);
push_back(is);
return is;
}

287
src/osg/LineSegment.cpp Normal file
View File

@@ -0,0 +1,287 @@
#include "osg/LineSegment"
using namespace osg;
const bool LineSegment::intersectAndClip(Vec3& s,Vec3& e,const BoundingBox& bb)
{
// compate s and e against the xMin to xMax range of bb.
if (s.x()<=e.x())
{
// trivial reject of segment wholely outside.
if (e.x()<bb.xMin()) return false;
if (s.x()>bb.xMax()) return false;
if (s.x()<bb.xMin())
{
// clip s to xMin.
s = s+(e-s)*(bb.xMin()-s.x())/(e.x()-s.x());
}
if (e.x()>bb.xMax())
{
// clip e to xMax.
e = s+(e-s)*(bb.xMax()-s.x())/(e.x()-s.x());
}
}
else
{
if (s.x()<bb.xMin()) return false;
if (e.x()>bb.xMax()) return false;
if (e.x()<bb.xMin())
{
// clip s to xMin.
e = s+(e-s)*(bb.xMin()-s.x())/(e.x()-s.x());
}
if (s.x()>bb.xMax())
{
// clip e to xMax.
s = s+(e-s)*(bb.xMax()-s.x())/(e.x()-s.x());
}
}
// compate s and e against the yMin to yMax range of bb.
if (s.y()<=e.y())
{
// trivial reject of segment wholely outside.
if (e.y()<bb.yMin()) return false;
if (s.y()>bb.yMax()) return false;
if (s.y()<bb.yMin())
{
// clip s to yMin.
s = s+(e-s)*(bb.yMin()-s.y())/(e.y()-s.y());
}
if (e.y()>bb.yMax())
{
// clip e to yMax.
e = s+(e-s)*(bb.yMax()-s.y())/(e.y()-s.y());
}
}
else
{
if (s.y()<bb.yMin()) return false;
if (e.y()>bb.yMax()) return false;
if (e.y()<bb.yMin())
{
// clip s to yMin.
e = s+(e-s)*(bb.yMin()-s.y())/(e.y()-s.y());
}
if (s.y()>bb.yMax())
{
// clip e to yMax.
s = s+(e-s)*(bb.yMax()-s.y())/(e.y()-s.y());
}
}
// compate s and e against the zMin to zMax range of bb.
if (s.z()<=e.z())
{
// trivial reject of segment wholely outside.
if (e.z()<bb.zMin()) return false;
if (s.z()>bb.zMax()) return false;
if (s.z()<bb.zMin())
{
// clip s to zMin.
s = s+(e-s)*(bb.zMin()-s.z())/(e.z()-s.z());
}
if (e.z()>bb.zMax())
{
// clip e to zMax.
e = s+(e-s)*(bb.zMax()-s.z())/(e.z()-s.z());
}
}
else
{
if (s.z()<bb.zMin()) return false;
if (e.z()>bb.zMax()) return false;
if (e.z()<bb.zMin())
{
// clip s to zMin.
e = s+(e-s)*(bb.zMin()-s.z())/(e.z()-s.z());
}
if (s.z()>bb.zMax())
{
// clip e to zMax.
s = s+(e-s)*(bb.zMax()-s.z())/(e.z()-s.z());
}
}
return true;
}
const bool LineSegment::intersect(const BoundingBox& bb) const
{
if (!bb.isValid()) return false;
Vec3 s=_s,e=_e;
return intersectAndClip(s,e,bb);
}
const bool LineSegment::intersect(const BoundingBox& bb,float& r1,float& r2) const
{
if (!bb.isValid()) return false;
Vec3 s=_s,e=_e;
bool result = intersectAndClip(s,e,bb);
if (result)
{
float len = (_e-_s).length();
if (len>0.0f)
{
float inv_len = 1.0f/len;
r1 = (s-_s).length()*inv_len;
r2 = (e-_e).length()*inv_len;
}
else
{
r1 = 0.0f;
r2 = 0.0f;
}
}
return result;
}
const bool LineSegment::intersect(const BoundingSphere& bs,float& r1,float& r2) const
{
Vec3 sm = _s-bs._center;
float c = sm.length2()-bs._radius*bs._radius;
Vec3 se = _e-_s;
float a = se.length2();
float b = sm*se*2.0f;
float d = b*b-4.0f*a*c;
if (d<0.0f) return false;
d = sqrtf(d);
float div = 1.0f/(2.0f*a);
r1 = (-b-d)*div;
r2 = (-b+d)*div;
if (r1<=0.0f && r2<=0.0f) return false;
if (r1>=1.0f && r2>=1.0f) return false;
return true;
}
const bool LineSegment::intersect(const BoundingSphere& bs) const
{
Vec3 sm = _s-bs._center;
float c = sm.length2()-bs._radius*bs._radius;
if (c<0.0f) return true;
Vec3 se = _e-_s;
float a = se.length2();
float b = (sm*se)*2.0f;
float d = b*b-4.0f*a*c;
if (d<0.0f) return false;
d = sqrtf(d);
float div = 1.0f/(2.0f*a);
float r1 = (-b-d)*div;
float r2 = (-b+d)*div;
if (r1<=0.0f && r2<=0.0f) return false;
if (r1>=1.0f && r2>=1.0f) return false;
return true;
}
const bool LineSegment::intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r)
{
if (v1==v2 || v2==v3 || v1==v3) return false;
Vec3 vse = _e-_s;
Vec3 v12 = v2-v1;
Vec3 n12 = v12^vse;
float ds12 = (_s-v1)*n12;
float d312 = (v3-v1)*n12;
if (d312>=0.0f)
{
if (ds12<0.0f) return false;
if (ds12>d312) return false;
}
else // d312 < 0
{
if (ds12>0.0f) return false;
if (ds12<d312) return false;
}
Vec3 v23 = v3-v2;
Vec3 n23 = v23^vse;
float ds23 = (_s-v2)*n23;
float d123 = (v1-v2)*n23;
if (d123>=0.0f)
{
if (ds23<0.0f) return false;
if (ds23>d123) return false;
}
else // d123 < 0
{
if (ds23>0.0f) return false;
if (ds23<d123) return false;
}
Vec3 v31 = v1-v3;
Vec3 n31 = v31^vse;
float ds31 = (_s-v3)*n31;
float d231 = (v2-v3)*n31;
if (d231>=0.0f)
{
if (ds31<0.0f) return false;
if (ds31>d231) return false;
}
else // d231 < 0
{
if (ds31>0.0f) return false;
if (ds31<d231) return false;
}
float r3 = ds12/d312;
float r1 = ds23/d123;
float r2 = ds31/d231;
// float rt = r1+r2+r3;
Vec3 in = v1*r1+v2*r2+v3*r3;
float length = vse.length();
vse /= length;
float d = (in-_s)*vse;
if (d<0.0f) return false;
if (d>length) return false;
r = d/length;
return true;
}

0
src/osg/Makedepend Normal file
View File

68
src/osg/PolygonMode.cpp Normal file
View File

@@ -0,0 +1,68 @@
#include "osg/GL"
#include "osg/PolygonMode"
#include "osg/Notify"
using namespace osg;
PolygonMode::PolygonMode()
{
_frontAndBack = true;
_modeFront = FILL;
_modeBack = FILL;
}
PolygonMode::~PolygonMode()
{
}
void PolygonMode::setMode(const Face face,const Mode mode)
{
switch(face)
{
case(FRONT):
_frontAndBack = false;
_modeFront = mode;
break;
case(BACK):
_frontAndBack = false;
_modeBack = mode;
break;
case(FRONT_AND_BACK):
_frontAndBack = true;
_modeFront = mode;
_modeBack = mode;
break;
}
}
const PolygonMode::Mode PolygonMode::getMode(const Face face) const
{
switch(face)
{
case(FRONT):
return _modeFront;
break;
case(BACK):
return _modeBack;
break;
case(FRONT_AND_BACK):
return _modeFront;
}
notify(WARN)<<"Warning : invalid Face passed to PolygonMode::getMode(Face face)"<<endl;
return _modeFront;
}
void PolygonMode::apply(State&) const
{
if (_frontAndBack)
{
glPolygonMode(GL_FRONT_AND_BACK,(GLenum)_modeFront);
}
else
{
glPolygonMode(GL_FRONT,(GLenum)_modeFront);
glPolygonMode(GL_BACK,(GLenum)_modeBack);
}
}

488
src/osg/State.cpp Normal file
View File

@@ -0,0 +1,488 @@
#include <osg/State>
#include <osg/Notify>
#include <GL/glu.h>
using namespace osg;
State::State()
{
_contextID = 0;
_frameNumber = 0;
_fineGrainedErrorDetection = true;
}
State::~State()
{
}
void State::reset()
{
_modeMap.clear();
_attributeMap.clear();
_drawStateStack.clear();
}
void State::pushStateSet(const StateSet* dstate)
{
_drawStateStack.push_back(dstate);
if (dstate)
{
// iterator through all OpenGL modes in incomming StateSet
// for each GLMode entry push it to the back of the appropriate
// mode stack, taking into consideration current override status.
const StateSet::ModeList& ds_modeList = dstate->getModeList();
for(StateSet::ModeList::const_iterator mitr=ds_modeList.begin();
mitr!=ds_modeList.end();
++mitr)
{
// get the mode stack for incomming GLmode {mitr->first}.
ModeStack& ms = _modeMap[mitr->first];
if (ms.valueVec.empty())
{
// first pair so simply push incomming pair to back.
ms.valueVec.push_back(mitr->second);
}
else if (ms.valueVec.back() & StateAttribute::OVERRIDE) // check the existing override flag
{
// push existing back since override keeps the previoius value.
ms.valueVec.push_back(ms.valueVec.back());
}
else
{
// no override on so simply push incomming pair to back.
ms.valueVec.push_back(mitr->second);
}
ms.changed = true;
}
// iterator through all StateAttribute's in incomming StateSet
// for each Type entry push it to the back of the appropriate
// attribute stack, taking into consideration current override status.
const StateSet::AttributeList& ds_attributeList = dstate->getAttributeList();
for(StateSet::AttributeList::const_iterator aitr=ds_attributeList.begin();
aitr!=ds_attributeList.end();
++aitr)
{
// get the attribute stack for incomming type {aitr->first}.
AttributeStack& as = _attributeMap[aitr->first];
if (as.attributeVec.empty())
{
// first pair so simply push incomming pair to back.
as.attributeVec.push_back(
AttributePair(aitr->second.first.get(),aitr->second.second));
}
else if (as.attributeVec.back().second & StateAttribute::OVERRIDE) // check the existing override flag
{
// push existing back since override keeps the previoius value.
as.attributeVec.push_back(as.attributeVec.back());
}
else
{
// no override on so simply push incomming pair to back.
as.attributeVec.push_back(
AttributePair(aitr->second.first.get(),aitr->second.second));
}
as.changed = true;
}
}
}
void State::popStateSet()
{
if (_drawStateStack.empty()) return;
const StateSet* dstate = _drawStateStack.back().get();
if (dstate)
{
// iterator through all OpenGL modes in incomming StateSet
// for each GLMode entry pop_back of the appropriate
// mode stack.
const StateSet::ModeList& ds_modeList = dstate->getModeList();
for(StateSet::ModeList::const_iterator mitr=ds_modeList.begin();
mitr!=ds_modeList.end();
++mitr)
{
// get the mode stack for incomming GLmode {mitr->first}.
ModeStack& ms = _modeMap[mitr->first];
if (!ms.valueVec.empty())
{
ms.valueVec.pop_back();
}
ms.changed = true;
}
// iterator through all StateAttribute's in incomming StateSet
// for each Type entry pop_back of the appropriate
// attribute stack.
const StateSet::AttributeList& ds_attributeList = dstate->getAttributeList();
for(StateSet::AttributeList::const_iterator aitr=ds_attributeList.begin();
aitr!=ds_attributeList.end();
++aitr)
{
// get the attribute stack for incomming type {aitr->first}.
AttributeStack& as = _attributeMap[aitr->first];
if (!as.attributeVec.empty())
{
as.attributeVec.pop_back();
}
as.changed = true;
}
}
// remove the top draw state from the stack.
_drawStateStack.pop_back();
}
void State::apply(const StateSet* dstate)
{
// equivilant to:
//pushStateSet(dstate);
//apply();
//popStateSet();
if (dstate)
{
// first handle mode changes.
{
const StateSet::ModeList& ds_modeList = dstate->getModeList();
StateSet::ModeList::const_iterator ds_mitr = ds_modeList.begin();
ModeMap::iterator this_mitr=_modeMap.begin();
while (this_mitr!=_modeMap.end() && ds_mitr!=ds_modeList.end())
{
if (this_mitr->first<ds_mitr->first)
{
// note GLMode = this_mitr->first
ModeStack& ms = this_mitr->second;
if (ms.changed)
{
ms.changed = false;
if (!ms.valueVec.empty())
{
bool new_value = ms.valueVec.back() & StateAttribute::ON;
apply_mode(this_mitr->first,new_value,ms);
}
else
{
// assume default of disabled.
apply_mode(this_mitr->first,false,ms);
}
}
++this_mitr;
}
else if (ds_mitr->first<this_mitr->first)
{
// ds_mitr->first is a new mode, therefore
// need to insert a new mode entry for ds_mistr->first.
ModeStack& ms = _modeMap[ds_mitr->first];
bool new_value = ds_mitr->second & StateAttribute::ON;
apply_mode(ds_mitr->first,new_value,ms);
// will need to disable this mode on next apply so set it to changed.
ms.changed = true;
++ds_mitr;
}
else
{
// this_mitr & ds_mitr refer to the same mode, check the overide
// if any otherwise just apply the incomming mode.
ModeStack& ms = this_mitr->second;
if (!ms.valueVec.empty() && ms.valueVec.back() & StateAttribute::OVERRIDE)
{
// override is on, there just treat as a normal apply on modes.
if (ms.changed)
{
ms.changed = false;
bool new_value = ms.valueVec.back() & StateAttribute::ON;
apply_mode(this_mitr->first,new_value,ms);
}
}
else
{
// no override on or no previous entry, therefore consider incomming mode.
bool new_value = ds_mitr->second & StateAttribute::ON;
if (apply_mode(ds_mitr->first,new_value,ms))
{
ms.changed = true;
}
}
++this_mitr;
++ds_mitr;
}
}
// iterator over the remaining state modes to apply any previous changes.
for(;
this_mitr!=_modeMap.end();
++this_mitr)
{
// note GLMode = this_mitr->first
ModeStack& ms = this_mitr->second;
if (ms.changed)
{
ms.changed = false;
if (!ms.valueVec.empty())
{
bool new_value = ms.valueVec.back() & StateAttribute::ON;
apply_mode(this_mitr->first,new_value,ms);
}
else
{
// assume default of disabled.
apply_mode(this_mitr->first,false,ms);
}
}
}
// iterator over the remaining incomming modes to apply any new mode.
for(;
ds_mitr!=ds_modeList.end();
++ds_mitr)
{
ModeStack& ms = _modeMap[ds_mitr->first];
bool new_value = ds_mitr->second & StateAttribute::ON;
apply_mode(ds_mitr->first,new_value,ms);
// will need to disable this mode on next apply so set it to changed.
ms.changed = true;
}
}
// now handle attribute changes
{
const StateSet::AttributeList& ds_attributeList = dstate->getAttributeList();
StateSet::AttributeList::const_iterator ds_aitr=ds_attributeList.begin();
AttributeMap::iterator this_aitr=_attributeMap.begin();
while (this_aitr!=_attributeMap.end() && ds_aitr!=ds_attributeList.end())
{
if (this_aitr->first<ds_aitr->first)
{
// note attribute type = this_aitr->first
AttributeStack& as = this_aitr->second;
if (as.changed)
{
as.changed = false;
if (!as.attributeVec.empty())
{
const StateAttribute* new_attr = as.attributeVec.back().first;
apply_attribute(new_attr,as);
}
else
{
// this is really an error state, in theory we *should* have a
// global state attribute set for all types.
//notify(WARN)<<" No global StateAttribute set for type"<<(int)aitr->first<<endl;
}
}
++this_aitr;
}
else if (ds_aitr->first<this_aitr->first)
{
// ds_mitr->first is a new attribute, therefore
// need to insert a new attribute entry for ds_aistr->first.
AttributeStack& as = _attributeMap[ds_aitr->first];
const StateAttribute* new_attr = ds_aitr->second.first.get();
apply_attribute(new_attr,as);
// will need to disable this mode on next apply so set it to changed.
as.changed = true;
++ds_aitr;
}
else
{
// this_mitr & ds_mitr refer to the same mode, check the overide
// if any otherwise just apply the incomming mode.
AttributeStack& as = this_aitr->second;
if (!as.attributeVec.empty() && as.attributeVec.back().second)
{
// override is os, there just treat as a normal apply on modes.
if (as.changed)
{
as.changed = false;
const StateAttribute* new_attr = as.attributeVec.back().first;
apply_attribute(new_attr,as);
}
}
else
{
// no override on or no previous entry, therefore consider incomming mode.
const StateAttribute* new_attr = ds_aitr->second.first.get();
if (apply_attribute(new_attr,as))
{
as.changed = true;
}
}
++this_aitr;
++ds_aitr;
}
}
// iterator over the remaining state modes to apply any previous changes.
for(;
this_aitr!=_attributeMap.end();
++this_aitr)
{
// note attribute type = this_aitr->first
AttributeStack& as = this_aitr->second;
if (as.changed)
{
as.changed = false;
if (!as.attributeVec.empty())
{
const StateAttribute* new_attr = as.attributeVec.back().first;
apply_attribute(new_attr,as);
}
else
{
// this is really an error state, in theory we *should* have a
// global state attribute set for all types.
//notify(WARN)<<" No global StateAttribute set for type"<<(int)aitr->first<<endl;
}
}
}
// iterator over the remaining incomming modes to apply any new mode.
for(;
ds_aitr!=ds_attributeList.end();
++ds_aitr)
{
// ds_mitr->first is a new attribute, therefore
// need to insert a new attribute entry for ds_aistr->first.
AttributeStack& as = _attributeMap[ds_aitr->first];
const StateAttribute* new_attr = ds_aitr->second.first.get();
apply_attribute(new_attr,as);
// will need to update this attribute on next apply so set it to changed.
as.changed = true;
}
}
}
else
{
// no incomming stateset, so simply apply state.
apply();
}
}
void State::apply()
{
// go through all active OpenGL modes, enabling/disable where
// appropriate.
for(ModeMap::iterator mitr=_modeMap.begin();
mitr!=_modeMap.end();
++mitr)
{
// note GLMode = mitr->first
ModeStack& ms = mitr->second;
if (ms.changed)
{
ms.changed = false;
if (!ms.valueVec.empty())
{
bool new_value = ms.valueVec.back() & StateAttribute::ON;
apply_mode(mitr->first,new_value,ms);
}
else
{
// assume default of disabled.
apply_mode(mitr->first,false,ms);
}
}
}
// go through all active StateAttribute's, applying where appropriate.
for(AttributeMap::iterator aitr=_attributeMap.begin();
aitr!=_attributeMap.end();
++aitr)
{
AttributeStack& as = aitr->second;
if (as.changed)
{
as.changed = false;
if (!as.attributeVec.empty())
{
const StateAttribute* new_attr = as.attributeVec.back().first;
apply_attribute(new_attr,as);
}
else
{
// this is really an error state, in theory we *should* have a
// global state attribute set for all types.
//notify(WARN)<<" No global StateAttribute set for type"<<(int)aitr->first<<endl;
}
}
}
}
/** mode has been set externally, update state to reflect this setting.*/
void State::have_applied(const StateAttribute::GLMode mode,const StateAttribute::GLModeValue value)
{
ModeStack& ms = _modeMap[mode];
ms.last_applied_value = value & StateAttribute::ON;
// will need to disable this mode on next apply so set it to changed.
ms.changed = true;
}
/** attribute has been applied externally, update state to reflect this setting.*/
void State::have_applied(const StateAttribute* attribute)
{
if (attribute)
{
AttributeStack& as = _attributeMap[attribute->getType()];
as.last_applied_attribute = attribute;
// will need to update this attribute on next apply so set it to changed.
as.changed = true;
}
}

208
src/osg/StateSet.cpp Normal file
View File

@@ -0,0 +1,208 @@
#include <stdio.h>
#include <osg/StateSet>
#include <osg/State>
#include <osg/Notify>
#include <osg/AlphaFunc>
#include <osg/Material>
#include <osg/CullFace>
#include <osg/FrontFace>
#include <osg/PolygonMode>
#include <osg/Transparency>
using namespace osg;
StateSet::StateSet()
{
_renderingHint = DEFAULT_BIN;
setRendingBinToInherit();
}
StateSet::~StateSet()
{
// note, all attached state attributes will be automatically
// unreferenced by ref_ptr<> and therefore there is no need to
// delete the memory manually.
}
void StateSet::setGlobalDefaults()
{
_renderingHint = DEFAULT_BIN;
setRendingBinToInherit();
setMode(GL_LIGHTING,StateAttribute::OFF);
setMode(GL_FOG,StateAttribute::OFF);
setMode(GL_POINT_SMOOTH,StateAttribute::OFF);
setMode(GL_TEXTURE_2D,StateAttribute::OFF);
setMode(GL_TEXTURE_GEN_S,StateAttribute::OFF);
setMode(GL_TEXTURE_GEN_T,StateAttribute::OFF);
setMode(GL_TEXTURE_GEN_R,StateAttribute::OFF);
setMode(GL_TEXTURE_GEN_Q,StateAttribute::OFF);
setAttributeAndModes(new AlphaFunc,StateAttribute::OFF);
setAttributeAndModes(new CullFace,StateAttribute::ON);
setAttributeAndModes(new FrontFace,StateAttribute::ON);
Material *material = new Material;
material->setColorMode(Material::AMBIENT_AND_DIFFUSE);
setAttributeAndModes(material,StateAttribute::ON);
setAttributeAndModes(new PolygonMode,StateAttribute::OFF);
setAttributeAndModes(new Transparency,StateAttribute::OFF);
}
void StateSet::setAllToInherit()
{
_renderingHint = DEFAULT_BIN;
setRendingBinToInherit();
_modeList.clear();
_attributeList.clear();
}
void StateSet::setMode(const StateAttribute::GLMode mode, const StateAttribute::GLModeValue value)
{
if ((value&StateAttribute::INHERIT)) setModeToInherit(mode);
else _modeList[mode] = value;
}
void StateSet::setModeToInherit(const StateAttribute::GLMode mode)
{
ModeList::iterator itr = _modeList.find(mode);
if (itr!=_modeList.end())
{
_modeList.erase(itr);
}
}
const StateAttribute::GLModeValue StateSet::getMode(const StateAttribute::GLMode mode) const
{
ModeList::const_iterator itr = _modeList.find(mode);
if (itr!=_modeList.end())
{
return itr->second;
}
else
return StateAttribute::INHERIT;
}
void StateSet::setAttribute(StateAttribute *attribute, const StateAttribute::OverrideValue value)
{
if (attribute)
{
if ((value&StateAttribute::INHERIT)) setAttributeToInherit(attribute->getType());
else _attributeList[attribute->getType()] = RefAttributePair(attribute,value&StateAttribute::OVERRIDE);
}
}
void StateSet::setAttributeAndModes(StateAttribute *attribute, const StateAttribute::GLModeValue value)
{
if (attribute)
{
_attributeList[attribute->getType()] = RefAttributePair(attribute,value&StateAttribute::OVERRIDE);
attribute->setStateSetModes(*this,value);
}
}
void StateSet::setAttributeToInherit(const StateAttribute::Type type)
{
AttributeList::iterator itr = _attributeList.find(type);
if (itr!=_attributeList.end())
{
itr->second.first->setStateSetModes(*this,StateAttribute::INHERIT);
_attributeList.erase(itr);
}
}
const StateAttribute* StateSet::getAttribute(const StateAttribute::Type type) const
{
AttributeList::const_iterator itr = _attributeList.find(type);
if (itr!=_attributeList.end())
{
return itr->second.first.get();
}
else
return NULL;
}
const StateSet::RefAttributePair* StateSet::getAttributePair(const StateAttribute::Type type) const
{
AttributeList::const_iterator itr = _attributeList.find(type);
if (itr!=_attributeList.end())
{
return &(itr->second);
}
else
return NULL;
}
void StateSet::compile(State& state) const
{
for(AttributeList::const_iterator itr = _attributeList.begin();
itr!=_attributeList.end();
++itr)
{
itr->second.first->compile(state);
}
}
const StateSet::ModeVector StateSet::getModeVector() const
{
ModeVector vec;
for (ModeList::const_iterator itr = _modeList.begin();
itr!=_modeList.end();
++itr)
{
vec.push_back(*itr);
}
return vec;
}
const StateSet::AttributeVector StateSet::getAttributeVector() const
{
AttributeVector vec;
for (AttributeList::const_iterator itr = _attributeList.begin();
itr!=_attributeList.end();
++itr)
{
vec.push_back(itr->second.first.get());
}
return vec;
}
void StateSet::setRenderingHint(const int hint)
{
_renderingHint = hint;
// temporary hack to get new render bins working.
if (_renderingHint==TRANSPARENT_BIN)
{
_binMode = USE_RENDERBIN_DETAILS;
_binNum = 1;
_binName = "DepthSortedBin";
// _binName = "RenderBin";
}
}
void StateSet::setRenderBinDetails(const int binNum,const std::string& binName,const RenderBinMode mode)
{
_binMode = mode;
_binNum = binNum;
_binName = binName;
}
void StateSet::setRendingBinToInherit()
{
_binMode = INHERIT_RENDERBIN_DETAILS;
_binNum = 0;
_binName = "";
}

32
src/osg/Stencil.cpp Normal file
View File

@@ -0,0 +1,32 @@
#include <osg/Stencil>
using namespace osg;
Stencil::Stencil()
{
// set up same defaults as glStencilFunc.
_func = ALWAYS;
_funcRef = 0;
_funcMask = ~0;
// set up same defaults as glStencilOp.
_sfail = KEEP;
_zfail = KEEP;
_zpass = KEEP;
// set up same defaults as glStencilMask.
_writeMask = ~0;
}
Stencil::~Stencil()
{
}
void Stencil::apply(State&) const
{
glStencilFunc((GLenum)_func,_funcRef,_funcMask);
glStencilOp((GLenum)_sfail,(GLenum)_zfail,(GLenum)_zpass);
glStencilMask(_writeMask);
}

87
src/osg/Transform.cpp Normal file
View File

@@ -0,0 +1,87 @@
#include "osg/Transform"
using namespace osg;
Transform::Transform()
{
_matrix = new osg::Matrix();
_matrix->makeIdent();
}
Transform::Transform(const Matrix& mat )
{
(*_matrix) = mat;
}
Transform::~Transform()
{
}
void Transform::setMatrix(const Matrix& mat )
{
(*_matrix) = mat;
dirtyBound();
}
void Transform::preMult( const Matrix& mat )
{
_matrix->preMult( mat );
dirtyBound();
}
void Transform::preScale( const float sx, const float sy, const float sz )
{
_matrix->preScale( sx, sy, sz );
dirtyBound();
}
void Transform::preTranslate( const float tx, const float ty, const float tz )
{
_matrix->preTrans( tx, ty, tz );
dirtyBound();
}
void Transform::preRotate( const float deg, const float x, const float y, const float z )
{
_matrix->preRot( deg, x, y, z );
dirtyBound();
}
const bool Transform::computeBound() const
{
if (!Group::computeBound()) return false;
Vec3 xdash = _bsphere._center;
xdash.x() += _bsphere._radius;
xdash = xdash*(*_matrix);
Vec3 ydash = _bsphere._center;
ydash.y() += _bsphere._radius;
ydash = ydash*(*_matrix);
Vec3 zdash = _bsphere._center;
zdash.y() += _bsphere._radius;
zdash = zdash*(*_matrix);
_bsphere._center = _bsphere._center*(*_matrix);
xdash -= _bsphere._center;
float len_xdash = xdash.length();
ydash -= _bsphere._center;
float len_ydash = ydash.length();
zdash -= _bsphere._center;
float len_zdash = zdash.length();
_bsphere._radius = len_xdash;
if (_bsphere._radius<len_ydash) _bsphere._radius = len_ydash;
if (_bsphere._radius<len_zdash) _bsphere._radius = len_zdash;
return true;
}

View File

@@ -0,0 +1,43 @@
// OldMaterialPaletteRecord.cpp
#include "flt.h"
#include "Registry.h"
#include "OldMaterialPaletteRecord.h"
using namespace flt;
////////////////////////////////////////////////////////////////////
//
// OldMaterialPaletteRecord
//
////////////////////////////////////////////////////////////////////
RegisterRecordProxy<OldMaterialPaletteRecord> g_OldMaterialPaletteProxy;
OldMaterialPaletteRecord::OldMaterialPaletteRecord()
{
}
// virtual
OldMaterialPaletteRecord::~OldMaterialPaletteRecord()
{
}
// virtual
void OldMaterialPaletteRecord::endian()
{
SOldMaterial *pSMaterial = (SOldMaterial*)getData();
for (int i=0; i < 64; i++)
{
pSMaterial->mat[i].Ambient.endian();
pSMaterial->mat[i].Diffuse.endian();
pSMaterial->mat[i].Specular.endian();
pSMaterial->mat[i].Emissive.endian();
ENDIAN( pSMaterial->mat[i].sfShininess );
ENDIAN( pSMaterial->mat[i].sfAlpha );
ENDIAN( pSMaterial->mat[i].diFlags );
}
}

View File

@@ -0,0 +1,61 @@
// OldMaterialPaletteRecord.h
#ifndef __FLT_OLD_MATERIAL_PALETTE_RECORD_H
#define __FLT_OLD_MATERIAL_PALETTE_RECORD_H
#include "opcodes.h"
#include "Record.h"
#include "RecordVisitor.h"
namespace flt {
struct SOldMaterial
{
SRecHeader RecHeader;
struct
{
float32x3 Ambient; // Ambient component of material
float32x3 Diffuse; // Diffuse component of material
float32x3 Specular; // Specular component of material
float32x3 Emissive; // Emissive component of material
float32 sfShininess; // Shininess. [0.0-128.0]
float32 sfAlpha; // Alpha. [0.0-1.0], where 1.0 is opaque
uint32 diFlags; // bit 0 Materials used
// bit 1-31 Spare
uint32 spares[31]; // Spares for material
} mat[64];
};
class OldMaterialPaletteRecord : public AncillaryRecord
{
public:
OldMaterialPaletteRecord();
virtual Record* clone() const { return new OldMaterialPaletteRecord(); }
virtual const char* className() const { return "OldMaterialPaletteRecord"; }
virtual int classOpcode() const { return OLD_MATERIAL_PALETTE_OP; }
virtual int sizeofData() const { return sizeof(SOldMaterial); }
virtual void accept(RecordVisitor& rv) { rv.apply(*this); }
// virtual void traverse(RecordVisitor& rv);
protected:
virtual ~OldMaterialPaletteRecord();
virtual void endian();
// virtual void decode();
// virtual bool readLocalData(Input& fr);
// virtual bool writeLocalData(Output& fw);
};
}; // end namespace flt
#endif

View File

@@ -0,0 +1,114 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Notify>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#ifdef _WIN32
#include <direct.h>
#else
#include <unistd.h>
#endif
using namespace osg;
class sgReaderWriterOSGTGZ : public osgDB::ReaderWriter
{
public:
virtual const char* className() { return "OSGTGZ Database Reader/Writer"; }
virtual bool acceptsExtension(const std::string& extension)
{
return osgDB::equalCaseInsensitive(extension,"osgtgz");
}
virtual Node* readNode(const std::string& fileName)
{
std::string ext = osgDB::getFileExtension(fileName);
if (!acceptsExtension(ext)) return NULL;
osg::notify(osg::INFO)<<"sgReaderWriterOSGTGZ::readNode( "<<fileName.c_str()<<" )\n";
char dirname[128];
char command[1024];
#ifdef _WIN32
sprintf( dirname, "C:/Windows/Temp/.osgdb_osgtgz");
// note, the following C option under windows does not seem to work...
// will pursue an better tar.exe later. RO.
sprintf( command,
"tar xfCz %s %s",
fileName.c_str(), dirname );
mkdir( dirname);
#endif
#ifdef __linux
sprintf( dirname, "/tmp/.osg%06d", getpid());
sprintf( command,
"tar xfCz %s %s",
fileName.c_str(), dirname );
mkdir( dirname, 0700 );
#endif
#ifdef __sgi
sprintf( dirname, "/tmp/.osg%06d", getpid());
sprintf( command,
"cp %s %s; cd %s;"
"gzcat %s | tar xf -",
fileName.c_str(), dirname, dirname,
fileName.c_str() );
mkdir( dirname, 0700 );
#endif
system( command );
osg::Group *grp = new osg::Group;
osgDB::setFilePath( dirname );
osgDB::DirectoryContents contents = osgDB::getDirectoryContents(dirname);
for(osgDB::DirectoryContents::iterator itr = contents.begin();
itr != contents.end();
++itr)
{
std::string file_ext = osgDB::getLowerCaseFileExtension(*itr);
if (osgDB::equalCaseInsensitive(file_ext,"osg"))
{
osg::Node *node = osgDB::readNodeFile( *itr );
grp->addChild( node );
}
}
#ifdef _WIN32
// note, is this the right command for windows?
// is there any way of overiding the Y/N option? RO.
sprintf( command, "erase %s", dirname );
system( command );
#else
sprintf( command, "rm -rf %s", dirname );
system( command );
#endif
if( grp->getNumChildren() == 0 )
{
grp->unref();
return NULL;
}
return grp;
}
};
// now register with sgRegistry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<sgReaderWriterOSGTGZ> g_readerWriter_OSGTGZ_Proxy;

View File

@@ -0,0 +1,330 @@
#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
/****************************************************************************
*
* Follows is code extracted from the simage library. Original Authors:
*
* Systems in Motion,
* <URL:http://www.sim.no>
*
* Peder Blekken <pederb@sim.no>
* Morten Eriksen <mortene@sim.no>
* Marius Bugge Monsen <mariusbu@sim.no>
*
* The original COPYING notice
*
* All files in this library are public domain, except simage_rgb.cpp which is
* Copyright (c) Mark J Kilgard <mjk@nvidia.com>. I will contact Mark
* very soon to hear if this source also can become public domain.
*
* Please send patches for bugs and new features to: <pederb@sim.no>.
*
* Peder Blekken
*
*
* Ported into the OSG as a plugin, Robert Osfield Decemeber 2000.
* Note, reference above to license of simage_rgb is not relevent to the OSG
* as the OSG does not use it. Also for patches, bugs and new features
* please send them direct to the OSG dev team rather than address above.
*
**********************************************************************/
/*
* Based on example code found in the libjpeg archive
*
*/
using namespace osg;
extern "C"
{
#include <png.h>
}
#define ERR_NO_ERROR 0
#define ERR_OPEN 1
#define ERR_MEM 2
#define ERR_PNGLIB 3
static int pngerror = ERR_NO_ERROR;
/* my setjmp buffer */
static jmp_buf setjmp_buffer;
/* called my libpng */
static void
warn_callback(png_structp /*ps*/, png_const_charp pc)
{
/*FIXME: notify? */
osg::notify(osg::WARN)<<"Warning in .png reader: ";
if (pc) osg::notify(osg::WARN)<< pc;
osg::notify(osg::WARN)<<endl;
}
static void
err_callback(png_structp /*ps*/, png_const_charp pc)
{
/* FIXME: store error message? */
longjmp(setjmp_buffer, 1);
osg::notify(osg::WARN)<<"Error in .png reader: ";
if (pc) osg::notify(osg::WARN)<< pc;
osg::notify(osg::WARN)<<endl;
}
int
simage_png_error(char * buffer, int buflen)
{
switch (pngerror) {
case ERR_OPEN:
strncpy(buffer, "PNG loader: Error opening file", buflen);
break;
case ERR_MEM:
strncpy(buffer, "PNG loader: Out of memory error", buflen);
break;
case ERR_PNGLIB:
strncpy(buffer, "PNG loader: Illegal png file", buflen);
break;
}
return pngerror;
}
int
simage_png_identify(const char * /*ptr*/,
const unsigned char *header,
int headerlen)
{
static unsigned char pngcmp[] = {0x89, 'P', 'N', 'G', 0xd, 0xa, 0x1a, 0xa};
if (headerlen < 8) return 0;
if (memcmp((const void*)header,
(const void*)pngcmp, 8) == 0) return 1;
return 0;
}
unsigned char *
simage_png_load(const char *filename,
int *width_ret,
int *height_ret,
int *numComponents_ret)
{
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
FILE *fp;
unsigned char *buffer;
int bytes_per_row;
int number_passes;
int channels;
int format;
if ((fp = fopen(filename, "rb")) == NULL) {
pngerror = ERR_OPEN;
return NULL;
}
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also supply the
* the compiler header file version, so that we know if the application
* was compiled with a compatible version of the library. REQUIRED
*/
/*png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
(void *)user_error_ptr, user_error_fn, user_warning_fn);*/
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, err_callback, warn_callback);
if (png_ptr == NULL) {
pngerror = ERR_MEM;
fclose(fp);
return 0;
}
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
pngerror = ERR_MEM;
fclose(fp);
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return 0;
}
/* Set error handling if you are using the setjmp/longjmp method (this is
* the normal method of doing things with libpng). REQUIRED unless you
* set up your own error handlers in the png_create_read_struct() earlier.
*/
buffer = NULL;
if (setjmp(setjmp_buffer)) {
pngerror = ERR_PNGLIB;
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
fclose(fp);
/* If we get here, we had a problem reading the file */
if (buffer) free(buffer);
return NULL;
}
/* Set up the input control if you are using standard C streams */
png_init_io(png_ptr, fp);
/* The call to png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk). REQUIRED
*/
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
/**** Set up the data transformations you want. Note that these are all
**** optional. Only call them if you want/need them. Many of the
**** transformations only work on specific types of images, and many
**** are mutually exclusive.
****/
/* tell libpng to strip 16 bit/color files down to 8 bits/color */
png_set_strip_16(png_ptr);
/* strip alpha bytes from the input data without combining with th
* background (not recommended) */
/* png_set_strip_alpha(png_ptr); */
/* extract multiple pixels with bit depths of 1, 2, and 4 from a single
* byte into separate bytes (useful for paletted and grayscale images).
*/
/* png_set_packing(png_ptr); */
/* change the order of packed pixels to least significant bit first
* (not useful if you are using png_set_packing). */
/* png_set_packswap(png_ptr); */
/* expand paletted colors into true RGB triplets */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
/* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png_ptr);
/* expand paletted or RGB images with transparency to full alpha channels
* so the data will be available as RGBA quartets */
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand(png_ptr);
/* Add filler (or alpha) byte (before/after each RGB triplet) */
/* png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); */
/* Turn on interlace handling. REQUIRED if you are not using
* png_read_image(). To see how to handle interlacing passes,
* see the png_read_row() method below.
*/
png_read_update_info(png_ptr, info_ptr);
number_passes = png_set_interlace_handling(png_ptr);
channels = png_get_channels(png_ptr, info_ptr);
/* allocate the memory to hold the image using the fields of info_ptr. */
bytes_per_row = png_get_rowbytes(png_ptr, info_ptr);
buffer = (unsigned char*) malloc(bytes_per_row*height);
format = channels; /* this is safer than the above */
if (buffer) {
int pass, y;
unsigned char *dummytab[1];
for (pass = 0; pass < number_passes; pass++) {
for ( y = 0; (unsigned int) y < height; y++ ) {
/* flips image upside down */
dummytab[0] = &buffer[bytes_per_row*(height-1-y)];
png_read_rows(png_ptr, dummytab, NULL, 1);
}
}
/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(png_ptr, info_ptr);
}
/* clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
/* close the file */
fclose(fp);
/* that's it */
if (buffer) {
*width_ret = width;
*height_ret = height;
*numComponents_ret = format;
pngerror = ERR_NO_ERROR;
}
else {
pngerror = ERR_MEM;
}
return buffer;
}
class ReaderWriterPNG : public osgDB::ReaderWriter
{
public:
virtual const char* className() { return "PNG Image Reader"; }
virtual bool acceptsExtension(const std::string& extension)
{
return osgDB::equalCaseInsensitive(extension,"png");
}
virtual osg::Image* readImage(const std::string& fileName)
{
unsigned char *imageData = NULL;
int width_ret;
int height_ret;
int numComponents_ret;
imageData = simage_png_load(fileName.c_str(),&width_ret,&height_ret,&numComponents_ret);
if (imageData==NULL) return NULL;
int s = width_ret;
int t = height_ret;
int r = 1;
int internalFormat = numComponents_ret;
unsigned int pixelFormat =
numComponents_ret == 1 ? GL_LUMINANCE :
numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
numComponents_ret == 3 ? GL_RGB :
numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
unsigned int dataType = GL_UNSIGNED_BYTE;
osg::Image* pOsgImage = new osg::Image;
pOsgImage->setFileName(fileName.c_str());
pOsgImage->setImage(s,t,r,
internalFormat,
pixelFormat,
dataType,
imageData);
return pOsgImage;
}
};
// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterPNG> g_readerWriter_PNG_Proxy;

View File

@@ -0,0 +1,170 @@
#include <osg/Image>
#include "osg/Notify"
#include <osg/Geode>
#include "osg/GL"
#include "osgDB/Registry"
using namespace osg;
extern "C"
{
#include <png.h>
}
/* Transparency parameters */
#define PNG_ALPHA -2 /* Use alpha channel in PNG file, if there is one */
#define PNG_SOLID -1 /* No transparency */
#define PNG_STENCIL 0 /* Sets alpha to 0 for r=g=b=0, 1 otherwise */
typedef struct
{
unsigned int Width;
unsigned int Height;
unsigned int Depth;
unsigned int Alpha;
} pngInfo;
class ReaderWriterPNG : public osgDB::ReaderWriter
{
public:
virtual const char* className() { return "PNG Image Reader/Writer"; }
virtual bool acceptsExtension(const std::string& extension) { return extension=="png"; }
virtual Image* readImage(const std::string& fileName)
{
int trans = PNG_ALPHA;
FILE *fp = NULL;
pngInfo pInfo;
pngInfo *pinfo = &pInfo;
unsigned char header[8];
png_structp png;
png_infop info;
png_infop endinfo;
png_bytep data; //, data2;
png_bytep *row_p;
double fileGamma;
png_uint_32 width, height;
int depth, color;
png_uint_32 i;
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info = png_create_info_struct(png);
endinfo = png_create_info_struct(png);
fp = fopen(fileName.c_str(), "rb");
if (fp && fread(header, 1, 8, fp) && png_check_sig(header, 8))
png_init_io(png, fp);
else
{
png_destroy_read_struct(&png, &info, &endinfo);
return NULL;
}
png_set_sig_bytes(png, 8);
png_read_info(png, info);
png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);
if (pinfo != NULL)
{
pinfo->Width = width;
pinfo->Height = height;
pinfo->Depth = depth;
}
if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA)
{
png_set_strip_alpha(png);
color &= ~PNG_COLOR_MASK_ALPHA;
}
// if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID))
if (color == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png);
/*--GAMMA--*/
// checkForGammaEnv();
double screenGamma = 2.2 / 1.0;
if (png_get_gAMA(png, info, &fileGamma))
png_set_gamma(png, screenGamma, fileGamma);
else
png_set_gamma(png, screenGamma, 1.0/2.2);
png_read_update_info(png, info);
data = (png_bytep) malloc(png_get_rowbytes(png, info)*height);
row_p = (png_bytep *) malloc(sizeof(png_bytep)*height);
bool StandardOrientation = false;
for (i = 0; i < height; i++)
{
if (StandardOrientation)
row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i];
else
row_p[i] = &data[png_get_rowbytes(png, info)*i];
}
png_read_image(png, row_p);
free(row_p);
int iBitCount;
if (trans == PNG_SOLID || trans == PNG_ALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA)
{
switch (color)
{
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_PALETTE:
iBitCount = 24;
if (pinfo != NULL) pinfo->Alpha = 0;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
case PNG_COLOR_TYPE_RGB_ALPHA:
iBitCount = 32;
if (pinfo != NULL) pinfo->Alpha = 8;
break;
default:
return NULL;
}
}
png_read_end(png, endinfo);
png_destroy_read_struct(&png, &info, &endinfo);
// free(data);
if (fp)
fclose(fp);
osg::Image* pOsgImage = new osg::Image();
pOsgImage->setFileName(fileName.c_str());
if (iBitCount == 24)
pOsgImage->setImage(width, height, 1,
iBitCount / 8,// int internalFormat,
GL_RGB, // unsigned int pixelFormat
GL_UNSIGNED_BYTE,// unsigned int dataType
data);
else
pOsgImage->setImage(width, height, 1,
iBitCount / 8,// int internalFormat,
GL_RGBA, // unsigned int pixelFormat
GL_UNSIGNED_BYTE,// unsigned int dataType
data);
return pOsgImage;
}
};
// now register with Registry to instantiate the above
// reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterPNG> g_readerWriter_PNG_Proxy;

View File

@@ -0,0 +1,32 @@
#include "osg/Transform"
#include "osg/Geode"
#include "osg/LOD"
#include "osg/Billboard"
#include "osg/LightSource"
#include "osg/Impostor"
#include "osg/Notify"
#include "osgUtil/CullViewState"
#include <float.h>
using namespace osg;
using namespace osgUtil;
//#define USE_OLD_CULL
CullViewState::CullViewState()
{
_matrix = NULL;
_inverse = NULL;
_ratio2 = 0.002f*0.002f;
_bbCornerNear = 8; // note this is an error value, valid range is 0..7
_bbCornerFar = 8; // these error values are used to show a unset corner.
}
CullViewState::~CullViewState()
{
}

1209
src/osgUtil/CullVisitor.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
#include <osgUtil/DepthSortedBin>
#include <osgUtil/RenderStage>
#include <algorithm>
using namespace osg;
using namespace osgUtil;
// register a RenderStage prototype with the RenderBin prototype list.
RegisterRenderBinProxy<DepthSortedBin> s_registerDepthSortedBinProxy;
DepthSortedBin::DepthSortedBin()
{
_drawOrder = BACK_TO_FRONT;
}
DepthSortedBin::~DepthSortedBin()
{
}
void DepthSortedBin::reset()
{
RenderBin::reset();
_renderLeafList.clear();
}
struct DepthSortFunctor2
{
const bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs)
{
return (lhs->_depth<rhs->_depth);
}
};
void DepthSortedBin::sort_local()
{
_renderLeafList.clear();
int totalsize=0;
RenderGraphList::iterator itr;
for(itr=_renderGraphList.begin();
itr!=_renderGraphList.end();
++itr)
{
totalsize += (*itr)->_leaves.size();
}
_renderLeafList.reserve(totalsize);
// first copy all the leaves from the render graphs into the leaf list.
for(itr=_renderGraphList.begin();
itr!=_renderGraphList.end();
++itr)
{
for(RenderGraph::LeafList::iterator dw_itr = (*itr)->_leaves.begin();
dw_itr != (*itr)->_leaves.end();
++dw_itr)
{
_renderLeafList.push_back(dw_itr->get());
}
}
// now sort the list into acending depth order.
std::sort(_renderLeafList.begin(),_renderLeafList.end(),DepthSortFunctor2());
}
void DepthSortedBin::draw_local(osg::State& state,RenderLeaf*& previous)
{
if (_drawOrder==BACK_TO_FRONT)
{
// render the bin from back to front.
for(RenderLeafList::reverse_iterator itr= _renderLeafList.rbegin();
itr!= _renderLeafList.rend();
++itr)
{
RenderLeaf* rl = *itr;
rl->render(state,previous);
previous = rl;
}
}
else
{
// render the from front to back.
for(RenderLeafList::iterator itr= _renderLeafList.begin();
itr!= _renderLeafList.end();
++itr)
{
RenderLeaf* rl = *itr;
rl->render(state,previous);
previous = rl;
}
}
}

View File

@@ -0,0 +1,176 @@
#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <osgUtil/InsertImpostorsVisitor>
#include <algorithm>
using namespace osg;
using namespace osgUtil;
InsertImpostorsVisitor::InsertImpostorsVisitor()
{
setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
_impostorThresholdRatio = 10.0f;
_maximumNumNestedImpostors = 3;
_numNestedImpostors = 0;
}
void InsertImpostorsVisitor::reset()
{
_groupList.clear();
_lodList.clear();
_numNestedImpostors = 0;
}
void InsertImpostorsVisitor::apply(Node& node)
{
traverse(node);
}
void InsertImpostorsVisitor::apply(Group& node)
{
_groupList.push_back(&node);
++_numNestedImpostors;
if (_numNestedImpostors<_maximumNumNestedImpostors)
{
traverse(node);
}
--_numNestedImpostors;
}
void InsertImpostorsVisitor::apply(LOD& node)
{
_lodList.push_back(&node);
++_numNestedImpostors;
if (_numNestedImpostors<_maximumNumNestedImpostors)
{
traverse(node);
}
--_numNestedImpostors;
}
void InsertImpostorsVisitor::apply(Impostor& node)
{
++_numNestedImpostors;
if (_numNestedImpostors<_maximumNumNestedImpostors)
{
traverse(node);
}
--_numNestedImpostors;
}
/* insert the required impostors into the scene graph.*/
void InsertImpostorsVisitor::insertImpostors()
{
bool _insertImpostorsAboveGroups = true;
bool _replaceLODsByImpostors = true;
// handle group's
if (_insertImpostorsAboveGroups)
{
std::sort(_groupList.begin(),_groupList.end());
Group* previousGroup = NULL;
for(GroupList::iterator itr=_groupList.begin();
itr!=_groupList.end();
++itr)
{
Group* group = (*itr);
if (group!=previousGroup)
{
const BoundingSphere& bs = group->getBound();
if (bs.isValid())
{
// take a copy of the original parent list
// before we change it around by adding the group
// to an impostor.
Node::ParentList parentList = group->getParents();
Impostor* impostor = new Impostor;
// standard LOD settings
impostor->addChild(group);
impostor->setRange(0,0.0f);
impostor->setRange(1,1e7f);
impostor->setCenter(bs.center());
// impostor specfic settings.
impostor->setImpostorThresholdToBound(_impostorThresholdRatio);
// now replace the group by the new impostor in all of the
// group's original parent list.
for(Node::ParentList::iterator pitr=parentList.begin();
pitr!=parentList.end();
++pitr)
{
(*pitr)->replaceChild(group,impostor);
}
}
}
}
}
// handle LOD's
if (_replaceLODsByImpostors)
{
std::sort(_lodList.begin(),_lodList.end());
LOD* previousLOD = NULL;
for(LODList::iterator itr=_lodList.begin();
itr!=_lodList.end();
++itr)
{
osg::LOD* lod = (*itr);
if (lod!=previousLOD)
{
const osg::BoundingSphere& bs = lod->getBound();
if (bs.isValid())
{
// take a copy of the original parent list
// before we change it around by adding the lod
// to an impostor.
Node::ParentList parentList = lod->getParents();
osg::Impostor* impostor = new Impostor;
// standard LOD settings
for(int ci=0;ci<lod->getNumChildren();++ci)
{
impostor->addChild(lod->getChild(ci));
}
for(int ri=0;ri<lod->getNumRanges();++ri)
{
impostor->setRange(ri,lod->getRange(ri));
}
impostor->setCenter(lod->getCenter());
// impostor specfic settings.
impostor->setImpostorThresholdToBound(_impostorThresholdRatio);
// now replace the lod by the new impostor in all of the
// lod's original parent list.
for(Node::ParentList::iterator pitr=parentList.begin();
pitr!=parentList.end();
++pitr)
{
(*pitr)->replaceChild(lod,impostor);
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
#ifndef NV_TRISTRIP_OBJECTS_H
#define NV_TRISTRIP_OBJECTS_H
#include <assert.h>
#include <vector>
#include <list>
/////////////////////////////////////////////////////////////////////////////////
//
// Types defined for stripification
//
/////////////////////////////////////////////////////////////////////////////////
typedef int WORD;
typedef unsigned int UINT;
struct MyVertex
{
float x, y, z;
float nx, ny, nz;
};
typedef MyVertex MyVector;
struct MyFace
{
int v1, v2, v3;
float nx, ny, nz;
};
class VertexCache
{
public:
VertexCache(int size);
VertexCache();
~VertexCache();
bool InCache(int entry);
int AddEntry(int entry);
void Clear();
void Copy(VertexCache* inVcache);
int At(int index);
void Set(int index, int value);
private:
int *entries;
int numEntries;
};
inline bool VertexCache::InCache(int entry)
{
bool returnVal = false;
for(int i = 0; i < numEntries; i++)
{
if(entries[i] == entry)
{
returnVal = true;
break;
}
}
return returnVal;
}
inline int VertexCache::AddEntry(int entry)
{
int removed;
removed = entries[numEntries - 1];
//push everything right one
for(int i = numEntries - 2; i >= 0; i--)
{
entries[i + 1] = entries[i];
}
entries[0] = entry;
return removed;
}
class NvFaceInfo
{
public:
// vertex indices
NvFaceInfo(int v0, int v1, int v2)
{
m_v0 = v0; m_v1 = v1; m_v2 = v2;
m_stripId = -1;
m_testStripId = -1;
m_experimentId = -1;
}
// data members are left public
int m_v0, m_v1, m_v2;
int m_stripId; // real strip Id
int m_testStripId; // strip Id in an experiment
int m_experimentId; // in what experiment was it given an experiment Id?
};
// nice and dumb edge class that points knows its
// indices, the two faces, and the next edge using
// the lesser of the indices
class NvEdgeInfo
{
public:
// constructor puts 1 ref on us
NvEdgeInfo (int v0, int v1)
{
m_v0 = v0;
m_v1 = v1;
m_face0 = NULL;
m_face1 = NULL;
m_nextV0 = NULL;
m_nextV1 = NULL;
// we will appear in 2 lists. this is a good
// way to make sure we delete it the second time
// we hit it in the edge infos
m_refCount = 2;
}
// ref and unref
void Unref () { if (--m_refCount == 0) delete this; }
// data members are left public
UINT m_refCount;
NvFaceInfo *m_face0, *m_face1;
int m_v0, m_v1;
NvEdgeInfo *m_nextV0, *m_nextV1;
};
// This class is a quick summary of parameters used
// to begin a triangle strip. Some operations may
// want to create lists of such items, so they were
// pulled out into a class
class NvStripStartInfo
{
public:
NvStripStartInfo(NvFaceInfo *startFace, NvEdgeInfo *startEdge, bool toV1)
{
m_startFace = startFace;
m_startEdge = startEdge;
m_toV1 = toV1;
}
NvFaceInfo *m_startFace;
NvEdgeInfo *m_startEdge;
bool m_toV1;
};
typedef std::vector<NvFaceInfo*> NvFaceInfoVec;
typedef std::list <NvFaceInfo*> NvFaceInfoList;
typedef std::list <NvFaceInfoVec*> NvStripList;
typedef std::vector<NvEdgeInfo*> NvEdgeInfoVec;
typedef std::vector<WORD> WordVec;
typedef std::vector<MyVertex> MyVertexVec;
typedef std::vector<MyFace> MyFaceVec;
// This is a summary of a strip that has been built
class NvStripInfo
{
public:
// A little information about the creation of the triangle strips
NvStripInfo(const NvStripStartInfo &startInfo, int stripId, int experimentId = -1) :
m_startInfo(startInfo)
{
m_stripId = stripId;
m_experimentId = experimentId;
visited = false;
}
// This is an experiment if the experiment id is >= 0
inline bool IsExperiment () const { return m_experimentId >= 0; }
inline bool IsInStrip (const NvFaceInfo *faceInfo) const
{
if(faceInfo == NULL)
return false;
return (m_experimentId >= 0 ? faceInfo->m_testStripId == m_stripId : faceInfo->m_stripId == m_stripId);
}
bool SharesEdge(const NvFaceInfo* faceInfo, NvEdgeInfoVec &edgeInfos);
// take the given forward and backward strips and combine them together
void Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward);
//returns true if the face is "unique", i.e. has a vertex which doesn't exist in the faceVec
bool Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face);
// mark the triangle as taken by this strip
bool IsMarked (NvFaceInfo *faceInfo);
void MarkTriangle(NvFaceInfo *faceInfo);
// build the strip
void Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos);
// public data members
NvStripStartInfo m_startInfo;
NvFaceInfoVec m_faces;
int m_stripId;
int m_experimentId;
bool visited;
};
typedef std::vector<NvStripInfo*> NvStripInfoVec;
//The actual stripifier
class NvStripifier
{
public:
// Constructor
NvStripifier();
~NvStripifier();
//the target vertex cache size, the structure to place the strips in, and the input indices
void Stripify(const WordVec &in_indices, const int in_numVertices, const int in_cacheSize, const int in_minStripLength,
NvStripInfoVec &allStrips, NvFaceInfoVec &allFaces);
static int GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB);
static int GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB);
static bool NextIsCW(const int numIndices);
static bool IsCW(NvFaceInfo *faceInfo, int v0, int v1);
void CreateStrips(NvStripInfoVec& strips,
NvFaceInfoVec& leftoverFaces,
WordVec& stripIndices);
void OptimizeVertices(NvStripInfoVec& strips,
NvFaceInfoVec& leftoverFaces,
WordVec& stripIndices,
MyVertexVec& vertices,
MyVertexVec& optimizedVerts);
protected:
WordVec indices;
int cacheSize;
unsigned int minStripLength;
float meshJump;
bool bFirstTimeResetPoint;
/////////////////////////////////////////////////////////////////////////////////
//
// Big mess of functions called during stripification
//
/////////////////////////////////////////////////////////////////////////////////
static int GetNextIndex(const WordVec &indices, NvFaceInfo *face);
static NvEdgeInfo *FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1);
static NvFaceInfo *FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo);
NvFaceInfo *FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
void FindAllStrips(NvStripInfoVec &allStrips, NvFaceInfoVec &allFaceInfos, NvEdgeInfoVec &allEdgeInfos, int numSamples);
void SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips, NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList);
void RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList);
bool FindTraversal(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, NvStripInfo *strip, NvStripStartInfo &startInfo);
int CountRemainingTris(std::list<NvStripInfo*>::iterator iter, std::list<NvStripInfo*>::iterator end);
void CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips);
float AvgStripSize(const NvStripInfoVec &strips);
int FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
void UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip);
void UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face);
float CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip);
int CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face);
int NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec);
void BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const int numVertices);
bool AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos);
// let our strip info classes and the other classes get
// to these protected stripificaton methods if they want
friend NvStripInfo;
};
#endif

179
src/osgUtil/RenderBin.cpp Normal file
View File

@@ -0,0 +1,179 @@
#include <osgUtil/RenderBin>
#include <osgUtil/RenderStage>
using namespace osg;
using namespace osgUtil;
// register a RenderStage prototype with the RenderBin prototype list.
RegisterRenderBinProxy<RenderBin> s_registerRenderBinProxy;
typedef std::map< std::string, osg::ref_ptr<RenderBin> > RenderBinPrototypeList;
RenderBinPrototypeList* renderBinPrototypeList()
{
static RenderBinPrototypeList s_renderBinPrototypeList;
return &s_renderBinPrototypeList;
}
RenderBin* RenderBin::createRenderBin(const std::string& binName)
{
// cout << "creating RB "<<binName<<endl;
RenderBinPrototypeList::iterator itr = renderBinPrototypeList()->find(binName);
if (itr != renderBinPrototypeList()->end()) return dynamic_cast<RenderBin*>(itr->second->clone());
else return NULL;
}
void RenderBin::addRenderBinPrototype(RenderBin* proto)
{
if (proto)
{
(*renderBinPrototypeList())[proto->className()] = proto;
// cout << "Adding RB "<<proto->className()<<endl;
}
}
void RenderBin::removeRenderBinPrototype(RenderBin* proto)
{
if (proto)
{
RenderBinPrototypeList::iterator itr = renderBinPrototypeList()->find(proto->className());
if (itr != renderBinPrototypeList()->end()) renderBinPrototypeList()->erase(itr);
}
}
RenderBin::RenderBin()
{
_binNum = 0;
_parent = NULL;
_stage = NULL;
}
RenderBin::~RenderBin()
{
}
void RenderBin::reset()
{
_renderGraphList.clear();
_bins.clear();
}
void RenderBin::sort()
{
for(RenderBinList::iterator itr = _bins.begin();
itr!=_bins.end();
++itr)
{
itr->second->sort();
}
sort_local();
}
RenderBin* RenderBin::find_or_insert(int binNum,const std::string& binName)
{
// search for appropriate bin.
RenderBinList::iterator itr = _bins.find(binNum);
if (itr!=_bins.end()) return itr->second.get();
// create a renderin bin and insert into bin list.
RenderBin* rb = RenderBin::createRenderBin(binName);
if (rb)
{
RenderStage* rs = dynamic_cast<RenderStage*>(rb);
if (rs)
{
rs->_binNum = binNum;
rs->_parent = NULL;
rs->_stage = rs;
_stage->addToDependencyList(rs);
}
else
{
rb->_binNum = binNum;
rb->_parent = this;
rb->_stage = _stage;
_bins[binNum] = rb;
}
}
return rb;
}
void RenderBin::draw(osg::State& state,RenderLeaf*& previous)
{
// draw first set of draw bins.
RenderBinList::iterator itr;
for(itr = _bins.begin();
itr->first<0 && itr!=_bins.end();
++itr)
{
itr->second->draw(state,previous);
}
draw_local(state,previous);
for(;
itr!=_bins.end();
++itr)
{
itr->second->draw(state,previous);
}
}
void RenderBin::draw_local(osg::State& state,RenderLeaf*& previous)
{
// draw local bin.
for(RenderGraphList::iterator oitr=_renderGraphList.begin();
oitr!=_renderGraphList.end();
++oitr)
{
for(RenderGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
dw_itr != (*oitr)->_leaves.end();
++dw_itr)
{
RenderLeaf* rl = dw_itr->get();
rl->render(state,previous);
previous = rl;
}
}
}
// stats
#include <osg/GeoSet>
void RenderBin::getPrims(Statistics *primStats)
{
for(RenderBinList::iterator itr = _bins.begin();
itr!=_bins.end();
++itr)
{
primStats->nbins++;
}
for(RenderGraphList::iterator oitr=_renderGraphList.begin();
oitr!=_renderGraphList.end();
++oitr)
{
for(RenderGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
dw_itr != (*oitr)->_leaves.end();
++dw_itr)
{
RenderLeaf* rl = dw_itr->get();
Drawable* dw= rl->_drawable;
primStats->numOpaque++; // number of geosets
if (rl->_matrix.get()) primStats->nummat++; // number of matrices
if (dw) { // then tot up the types 1-14
GeoSet *gs=dynamic_cast<osg::GeoSet*>(dw);
if (gs)
{
primStats->addstat(gs);
// rl->getPrims(state,previous);??
// previous = rl;
}
}
}
}
}

View File

@@ -0,0 +1,62 @@
#include "osgUtil/RenderGraph"
#include "osg/Notify"
using namespace osg;
using namespace osgUtil;
void RenderGraph::reset()
{
_parent = NULL;
_stateset = NULL;
_depth = 0;
_children.clear();
_leaves.clear();
}
/** recursively clean the RenderGraph of all its drawables, lights and depths.
* Leaves children intact, and ready to be populated again.*/
void RenderGraph::clean()
{
// clean local drawables etc.
_leaves.clear();
// call clean on all children.
for(ChildList::iterator itr=_children.begin();
itr!=_children.end();
++itr)
{
itr->second->clean();
}
}
/** recursively prune the RenderGraph of empty children.*/
void RenderGraph::prune()
{
std::vector<const osg::StateSet*> toEraseList;
// call prune on all children.
for(ChildList::iterator citr=_children.begin();
citr!=_children.end();
++citr)
{
citr->second->prune();
if (citr->second->empty())
{
toEraseList.push_back(citr->first);
}
}
for(std::vector<const osg::StateSet*>::iterator eitr=toEraseList.begin();
eitr!=toEraseList.end();
++eitr)
{
_children.erase(*eitr);
}
}

View File

@@ -0,0 +1,63 @@
#include <osgUtil/RenderLeaf>
#include <osgUtil/RenderGraph>
using namespace osg;
using namespace osgUtil;
void RenderLeaf::render(State& state,RenderLeaf* previous)
{
if (previous)
{
RenderGraph* prev_rg = previous->_parent;
RenderGraph* prev_rg_parent = prev_rg->_parent;
RenderGraph* rg = _parent;
if (prev_rg_parent!=rg->_parent)
{
RenderGraph::moveRenderGraph(state,prev_rg_parent,rg->_parent);
// send state changes and matrix changes to OpenGL.
state.apply(rg->_stateset.get());
}
else if (rg!=prev_rg)
{
// send state changes and matrix changes to OpenGL.
state.apply(rg->_stateset.get());
}
Matrix* prev_matrix = previous->_matrix.get();
if (_matrix != prev_matrix)
{
if (prev_matrix) glPopMatrix();
if (_matrix.valid())
{
glPushMatrix();
glMultMatrixf((GLfloat*)_matrix->_mat);
}
}
_drawable->draw(state);
}
else
{
RenderGraph::moveRenderGraph(state,NULL,_parent->_parent);
// send state changes and matrix changes to OpenGL.
state.apply(_parent->_stateset.get());
if (_matrix.valid())
{
glPushMatrix();
glMultMatrixf((GLfloat*)_matrix->_mat);
}
_drawable->draw(state);
}
}

134
src/osgUtil/RenderStage.cpp Normal file
View File

@@ -0,0 +1,134 @@
#include <osgUtil/RenderStage>
using namespace osg;
using namespace osgUtil;
// register a RenderStage prototype with the RenderBin prototype list.
//RegisterRenderBinProxy<RenderStage> s_registerRenderStageProxy;
RenderStage::RenderStage()
{
// point RenderBin's _stage to this to ensure that references to
// stage don't go tempted away to any other stage.
_stage = this;
_stageDrawnThisFrame = false;
_clearMask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
_clearColor.set(0.0f,0.0f,0.0f,0.0f);
_clearAccum.set(0.0f,0.0f,0.0f,0.0f);
_clearDepth = 1.0;
_clearStencil = 0;
}
RenderStage::~RenderStage()
{
}
void RenderStage::reset()
{
_dependencyList.clear();
_stageDrawnThisFrame = false;
if (_renderStageLighting.valid()) _renderStageLighting->reset();
RenderBin::reset();
}
void RenderStage::addToDependencyList(RenderStage* rs)
{
if (rs) _dependencyList.push_back(rs);
}
void RenderStage::draw(osg::State& state,RenderLeaf*& previous)
{
if (_stageDrawnThisFrame) return;
_stageDrawnThisFrame = true;
for(DependencyList::iterator itr=_dependencyList.begin();
itr!=_dependencyList.end();
++itr)
{
(*itr)->draw(state,previous);
}
// set up the back buffer.
#define USE_SISSOR_TEST
#ifdef USE_SISSOR_TEST
glScissor( _view[0], _view[1], _view[2], _view[3] );
glEnable( GL_SCISSOR_TEST );
#endif
glViewport( _view[0], _view[1], _view[2], _view[3] );
// glEnable( GL_DEPTH_TEST );
if (_clearMask & GL_COLOR_BUFFER_BIT)
glClearColor( _clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]);
if (_clearMask & GL_DEPTH_BUFFER_BIT)
glClearDepth( _clearDepth);
if (_clearMask & GL_STENCIL_BUFFER_BIT)
glClearStencil( _clearStencil);
if (_clearMask & GL_ACCUM_BUFFER_BIT)
glClearAccum( _clearAccum[0], _clearAccum[1], _clearAccum[2], _clearAccum[3]);
// clear a color bit planes - osg::ColorMask could also be used here.
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
glClear( _clearMask );
#ifdef USE_SISSOR_TEST
glDisable( GL_SCISSOR_TEST );
#endif
// set up projection
const Matrix& projectionMat = _camera->getProjectionMatrix();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glMultMatrixf((GLfloat*)projectionMat._mat);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
Light* light = getLight();
if (getLightingMode()==RenderStageLighting::HEADLIGHT && light)
{
light->apply(state);
}
// set up camera modelview.
const Matrix& modelView = _camera->getModelViewMatrix();
glMultMatrixf((GLfloat*)modelView._mat);
if (getLightingMode()==RenderStageLighting::SKY_LIGHT && light)
{
light->apply(state);
}
// apply the lights.
if (_renderStageLighting.valid()) _renderStageLighting->draw(state,previous);
// draw the children and local.
RenderBin::draw(state,previous);
// now reset the state so its back in its default state.
if (previous)
{
RenderGraph::moveToRootRenderGraph(state,previous->_parent);
state.apply();
if (previous->_matrix.valid()) glPopMatrix();
previous = NULL;
}
}
// Statistics features
void RenderStage::getPrims(Statistics *primStats)
{
if (_renderStageLighting.valid()) primStats->nlights+=_renderStageLighting->_lightList.size();
RenderBin::getPrims(primStats);
}

View File

@@ -0,0 +1,61 @@
#include <osgUtil/RenderStageLighting>
using namespace osg;
using namespace osgUtil;
// register a RenderStageLighting prototype with the RenderBin prototype list.
//RegisterRenderBinProxy<RenderStageLighting> s_registerRenderStageLightingProxy;
RenderStageLighting::RenderStageLighting()
{
}
RenderStageLighting::~RenderStageLighting()
{
}
void RenderStageLighting::reset()
{
_lightList.clear();
}
void RenderStageLighting::draw(osg::State& state,RenderLeaf*& previous)
{
if (previous)
{
RenderGraph::moveToRootRenderGraph(state,previous->_parent);
state.apply();
if (previous->_matrix.valid()) glPopMatrix();
previous = NULL;
}
Matrix* prev_matrix = NULL;
// apply the light list.
for(LightList::iterator litr=_lightList.begin();
litr!=_lightList.end();
++litr)
{
Matrix* matrix = (*litr).second.get();
if (matrix != prev_matrix)
{
if (prev_matrix) glPopMatrix();
if (matrix)
{
glPushMatrix();
glMultMatrixf((GLfloat*)matrix->_mat);
}
prev_matrix = matrix;
}
// apply the light source.
litr->first->apply(state);
}
// clean up matrix stack.
if (prev_matrix) glPopMatrix();
}

View File

@@ -0,0 +1,32 @@
#include <osgUtil/RenderToTextureStage>
#include <osgDB/ReadFile>
using namespace osg;
using namespace osgUtil;
// register a RenderToTextureStage prototype with the RenderBin prototype list.
//RegisterRenderBinProxy<RenderToTextureStage> s_registerRenderToTextureStageProxy;
RenderToTextureStage::RenderToTextureStage()
{
}
RenderToTextureStage::~RenderToTextureStage()
{
}
void RenderToTextureStage::reset()
{
RenderStage::reset();
}
void RenderToTextureStage::draw(osg::State& state,RenderLeaf*& previous)
{
RenderStage::draw(state,previous);
// now copy the rendered image to attached texture.
if (_texture.valid()) _texture->copyTexImage2D(state,_view[0],_view[1],_view[2],_view[3]);
}

View File

@@ -0,0 +1,39 @@
#include <osgUtil/SceneViewManipulator>
#include <osgUtil/TrackballManipulator>
using namespace osgUtil;
SceneViewManipulator::SceneViewManipulator():
_cm(new TrackballManipulator),
_gm(new StateSetManipulator)
{
}
SceneViewManipulator::~SceneViewManipulator()
{
}
void SceneViewManipulator::setSceneView(SceneView* sv)
{
_sv=sv;
_cm->setNode(sv->getSceneData());
_cm->setCamera(sv->getCamera());
_gm->setStateSet(sv->getGlobalState());
}
SceneView *SceneViewManipulator::getSceneView()
{
return _sv.get();
}
const SceneView *SceneViewManipulator::getSceneView() const
{
return _sv.get();
}
bool SceneViewManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa)
{
if(_cm->handle(ea,aa)) return true;
if(_gm->handle(ea,aa)) return true;
return false;
}

View File

@@ -0,0 +1,155 @@
#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <stdio.h>
#include <list>
#include <set>
#include <osg/GeoSet>
#include <osgUtil/SmoothingVisitor>
using namespace osg;
using namespace osgUtil;
struct LessPtr
{
inline bool operator() (const osg::Vec3* lhs,const osg::Vec3* rhs) const
{
return *lhs<*rhs;
}
};
// triangle functor.
struct TriangleFunctor
{
osg::Vec3 *_coordBase;
osg::Vec3 *_normalBase;
typedef std::multiset<const osg::Vec3*,LessPtr> CoordinateSet;
CoordinateSet _coordSet;
TriangleFunctor(osg::Vec3 *cb,int noVertices, osg::Vec3 *nb) : _coordBase(cb),_normalBase(nb)
{
osg::Vec3* vptr = cb;
for(int i=0;i<noVertices;++i)
{
_coordSet.insert(vptr++);
}
}
inline void updateNormal(const osg::Vec3& normal,const osg::Vec3* vptr)
{
std::pair<CoordinateSet::iterator,CoordinateSet::iterator> p =
_coordSet.equal_range(vptr);
for(CoordinateSet::iterator itr=p.first;
itr!=p.second;
++itr)
{
osg::Vec3* nptr = _normalBase + (*itr-_coordBase);
(*nptr) += normal;
}
}
inline void operator() ( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3 )
{
// calc orientation of triangle.
osg::Vec3 normal = (v2-v1)^(v3-v1);
// normal.normalize();
updateNormal(normal,&v1);
updateNormal(normal,&v2);
updateNormal(normal,&v3);
}
};
void SmoothingVisitor::smooth(osg::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 doSmoothing;
switch(primTypeIn)
{
case(GeoSet::TRIANGLES):
case(GeoSet::TRIANGLE_STRIP):
case(GeoSet::TRIANGLE_FAN):
doSmoothing = true;
break;
case(GeoSet::FLAT_TRIANGLE_STRIP):
primTypeOut = GeoSet::TRIANGLE_STRIP;
doSmoothing = true;
break;
case(GeoSet::FLAT_TRIANGLE_FAN):
primTypeOut = GeoSet::TRIANGLE_FAN;
doSmoothing = true;
break;
case(GeoSet::QUADS):
case(GeoSet::QUAD_STRIP):
case(GeoSet::POLYGON):
doSmoothing = true;
break;
default: // points and lines etc.
doSmoothing = false;
break;
}
if (doSmoothing)
{
gset.computeNumVerts();
int ncoords = gset.getNumCoords();
osg::Vec3 *coords = gset.getCoords();
osg::GeoSet::IndexPointer cindex = gset.getCoordIndices();
osg::Vec3 *norms = new osg::Vec3[ncoords];
int j;
for(j = 0; j < ncoords; j++ )
{
norms[j].set(0.0f,0.0f,0.0f);
}
TriangleFunctor tf(coords,ncoords,norms);
for_each_triangle( gset, tf );
for(j = 0; j < ncoords; j++ )
{
norms[j].normalize();
}
gset.setNormalBinding(osg::GeoSet::BIND_PERVERTEX);
if (cindex.valid())
{
if (cindex._is_ushort)
gset.setNormals( norms, cindex._ptr._ushort );
else
gset.setNormals( norms, cindex._ptr._uint );
}
else
{
gset.setNormals( norms );
}
if (primTypeIn!=primTypeOut)
gset.setPrimType( primTypeOut );
gset.dirtyDisplayList();
}
}
void SmoothingVisitor::apply(osg::Geode& geode)
{
for(int i = 0; i < geode.getNumDrawables(); i++ )
{
osg::GeoSet* gset = dynamic_cast<osg::GeoSet*>(geode.getDrawable(i));
if (gset) smooth(*gset);
}
}

View File

@@ -0,0 +1,68 @@
#include <osgUtil/StateSetManipulator>
using namespace osg;
using namespace osgUtil;
StateSetManipulator::StateSetManipulator(): _drawState(NULL)
{
}
StateSetManipulator::~StateSetManipulator()
{
}
void StateSetManipulator::setStateSet(StateSet *drawState)
{
_drawState=drawState;
if(!_drawState.valid()) return;
_backface = (_drawState->getMode(GL_CULL_FACE)==osg::StateAttribute::ON);
_lighting =(_drawState->getMode(GL_LIGHTING)==osg::StateAttribute::ON);
_texture =(_drawState->getMode(GL_TEXTURE_2D)==osg::StateAttribute::ON);
}
StateSet *StateSetManipulator::getStateSet()
{
return _drawState.get();
}
const StateSet *StateSetManipulator::getStateSet() const
{
return _drawState.get();
}
bool StateSetManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& aa)
{
if(!_drawState.valid()) return false;
if(ea.getEventType()==GUIEventAdapter::KEYBOARD){
switch( ea.getKey() ){
case 'b' :
_backface = !_backface;
if( _backface ) _drawState->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
else _drawState->setMode(GL_CULL_FACE,osg::StateAttribute::OVERRIDE_OFF);
aa.requestRedraw();
return true;
break;
case 'l' :
_lighting = !_lighting ;
if( _lighting ) _drawState->setMode(GL_LIGHTING,osg::StateAttribute::ON);
else _drawState->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE_OFF);
aa.requestRedraw();
return true;
break;
case 't' :
_texture = !_texture;
if (_texture) _drawState->setMode(GL_TEXTURE_2D,osg::StateAttribute::INHERIT);
else _drawState->setMode(GL_TEXTURE_2D,osg::StateAttribute::OVERRIDE_OFF);
aa.requestRedraw();
return true;
break;
}
}
return false;
}

262
src/osgUtil/Tesselator.cpp Normal file
View File

@@ -0,0 +1,262 @@
#include <osg/GL>
#include <osg/Notify>
#include <osgUtil/Tesselator>
#include <GL/glu.h>
using namespace osg;
using namespace osgUtil;
/* Win32 calling conventions. (or a least thats what the GLUT example tess.c uses.)*/
#ifndef CALLBACK
#define CALLBACK
#endif
static Tesselator* s_tesselator = NULL;
void CALLBACK beginCallback(GLenum which)
{
s_tesselator->beginPrimitive(which);
}
void CALLBACK errorCallback(GLenum errorCode)
{
s_tesselator->_errorCode = errorCode;
}
void CALLBACK endCallback()
{
s_tesselator->endPrimitive();
}
void CALLBACK vertexCallback(GLvoid *data)
{
Tesselator::VertexIndexSet* vip = (Tesselator::VertexIndexSet*)data;
vip->accumulate();
}
Tesselator::Tesselator()
{
}
Tesselator::~Tesselator()
{
}
void Tesselator::tesselate(osg::Vec3* coords,int numIndices, int* indices,InputBoundaryDirection ibd)
{
init();
_coordVec.reserve(numIndices);
if (ibd==COUNTER_CLOCK_WISE)
{
for(int i=0;i<numIndices;++i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
else
{
for(int i=numIndices-1;i>=0;--i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
do_it();
}
void Tesselator::tesselate(osg::Vec3* coords,int numIndices, osg::ushort* indices,InputBoundaryDirection ibd)
{
init();
_coordVec.reserve(numIndices);
if (ibd==COUNTER_CLOCK_WISE)
{
for(int i=0;i<numIndices;++i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
else
{
for(int i=numIndices-1;i>=0;--i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
do_it();
}
void Tesselator::tesselate(osg::Vec3* coords,int numIndices, osg::uint* indices,InputBoundaryDirection ibd)
{
init();
_coordVec.reserve(numIndices);
if (ibd==COUNTER_CLOCK_WISE)
{
for(int i=0;i<numIndices;++i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
else
{
for(int i=numIndices-1;i>=0;--i)
{
_coordVec.push_back(VertexIndexSet(this,coords[indices[i]],indices[i]));
}
}
do_it();
}
void Tesselator::init()
{
_errorCode = 0;
_coordVec.clear();
_acummulated_indices.clear();
_tesselated_indices.clear();
_currentPrimtiveType=0;
}
#ifdef GLU_VERSION_1_2
void Tesselator::do_it()
{
GLUtesselator *tobj = gluNewTess();
gluTessCallback(tobj, (GLenum)GLU_TESS_VERTEX,
(GLvoid (CALLBACK*) ()) (&vertexCallback));
gluTessCallback(tobj, (GLenum)GLU_TESS_BEGIN,
(GLvoid (CALLBACK*) ()) (&beginCallback));
gluTessCallback(tobj, (GLenum)GLU_TESS_END,
(GLvoid (CALLBACK*) ()) (&endCallback));
gluTessCallback(tobj, (GLenum)GLU_TESS_ERROR,
(GLvoid (CALLBACK*) ()) (&errorCallback));
s_tesselator = this;
gluTessBeginPolygon(tobj,NULL);
gluTessBeginContour(tobj);
for(CoordVec::iterator itr=_coordVec.begin();
itr!=_coordVec.end();
++itr)
{
gluTessVertex(tobj,itr->_vertex,itr->_vertex);
}
gluTessEndContour(tobj);
gluTessEndPolygon(tobj);
gluDeleteTess(tobj);
if (_errorCode!=0)
{
const GLubyte *estring = gluErrorString((GLenum)_errorCode);
osg::notify(osg::WARN)<<"Tessellation Error: "<<estring<<endl;
osg::notify(osg::WARN)<<" Num indices created = "<<_tesselated_indices.size()<<endl;
}
}
#else
// old style glu tesseleation.
void Tesselator::do_it()
{
GLUtriangulatorObj *tobj = gluNewTess();
gluTessCallback(tobj, (GLenum)GLU_VERTEX,
(GLvoid (CALLBACK*) ()) (&vertexCallback));
gluTessCallback(tobj, (GLenum)GLU_BEGIN,
(GLvoid (CALLBACK*) ()) (&beginCallback));
gluTessCallback(tobj, (GLenum)GLU_END,
(GLvoid (CALLBACK*) ()) (&endCallback));
gluTessCallback(tobj, (GLenum)GLU_ERROR,
(GLvoid (CALLBACK*) ()) (&errorCallback));
s_tesselator = this;
gluBeginPolygon(tobj);
for(CoordVec::iterator itr=_coordVec.begin();
itr!=_coordVec.end();
++itr)
{
gluTessVertex(tobj,itr->_vertex,itr->_vertex);
}
gluEndPolygon(tobj);
gluDeleteTess(tobj);
if (_errorCode!=0)
{
const GLubyte *estring = gluErrorString((GLenum)_errorCode);
osg::notify(osg::WARN)<<"Tessellation Error: "<<estring<<endl;
osg::notify(osg::WARN)<<" Num indices created = "<<_tesselated_indices.size()<<endl;
}
}
#endif
void Tesselator::beginPrimitive(int primitiveType)
{
_currentPrimtiveType = primitiveType;
}
void Tesselator::endPrimitive()
{
if (_acummulated_indices.size()>=3)
{
switch(_currentPrimtiveType)
{
case(GL_TRIANGLE_FAN):
{
osg::uint first = _acummulated_indices[0];
for(unsigned int i=2;i<_acummulated_indices.size();++i)
{
_tesselated_indices.push_back(first);
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i]);
}
}
break;
case(GL_TRIANGLE_STRIP):
{
for(unsigned int i=2;i<_acummulated_indices.size();++i)
{
if (i%2)
{
// i == 3,5,7 etc
// add in order.
_tesselated_indices.push_back(_acummulated_indices[i-2]);
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i]);
}
else
{
// i == 2,4,6 etc
// add in flipping orde to preserve anticlockwise direction.
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i-2]);
_tesselated_indices.push_back(_acummulated_indices[i]);
}
}
}
break;
case(GL_TRIANGLES):
{
for(unsigned int i=2;i<_acummulated_indices.size();i+=3)
{
_tesselated_indices.push_back(_acummulated_indices[i-2]);
_tesselated_indices.push_back(_acummulated_indices[i-1]);
_tesselated_indices.push_back(_acummulated_indices[i]);
}
}
break;
}
}
_acummulated_indices.clear();
}

View File

@@ -0,0 +1,310 @@
#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <stdio.h>
#include <osg/GeoSet>
#include <osg/Geode>
#include <osg/Types>
#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
{
cout << "No triangles to stripify"<<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);
}
}

View File

@@ -0,0 +1,64 @@
#if defined(_MSC_VER)
#pragma warning( disable : 4786 )
#endif
#include <stdio.h>
#include <list>
#include <set>
#include <osg/GeoSet>
#include <osgUtil/VisualsRequirementsVisitor>
using namespace osg;
using namespace osgUtil;
VisualsRequirementsVisitor::VisualsRequirementsVisitor()
{
setTraversalMode(NodeVisitor::TRAVERSE_ALL_CHILDREN);
_requiresDoubleBuffer = true;
_requiresRBG = true;
_requiresDepthBuffer = true;
_minimumNumberAlphaBits = 0;
_minimumNumberStencilBits = 0;
}
void VisualsRequirementsVisitor::applyStateSet(StateSet& stateset)
{
if (stateset.getMode(GL_STENCIL_TEST) & StateAttribute::ON)
{
_minimumNumberStencilBits = 1;
}
if (stateset.getAttribute(StateAttribute::STENCIL))
{
_minimumNumberStencilBits = 1;
}
}
void VisualsRequirementsVisitor::apply(Node& node)
{
osg::StateSet* stateset = node.getStateSet();
if (stateset) applyStateSet(*stateset);
traverse(node);
}
void VisualsRequirementsVisitor::apply(Geode& geode)
{
osg::StateSet* geode_stateset = geode.getStateSet();
if (geode_stateset) applyStateSet(*geode_stateset);
for(int i = 0; i < geode.getNumDrawables(); i++ )
{
osg::StateSet* stateset = geode.getDrawable(i)->getStateSet();
if (stateset) applyStateSet(*stateset);
}
}
void VisualsRequirementsVisitor::apply(Impostor& impostor)
{
_minimumNumberAlphaBits = 1;
apply((Node&)impostor);
}