From ccc8a922a66196eef1244cc23325cf3402fc9d8e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 18 Jan 2007 22:32:18 +0000 Subject: [PATCH] Added osg::StencilTwoSided state attribute to wrap up the stencil_two_sided extension. Added path in osgShadow work for using StencilTwoSided to accelerate shadow volume rendering. --- VisualStudio/osg/osg.dsp | 8 ++ examples/osgshadow/osgshadow.cpp | 120 ++++++++++------- include/osg/StencilTwoSided | 201 +++++++++++++++++++++++++++++ include/osgShadow/OccluderGeometry | 10 ++ src/osg/GNUmakefile | 1 + src/osg/StencilTwoSided.cpp | 160 +++++++++++++++++++++++ src/osgShadow/OccluderGeometry.cpp | 79 +++++++++--- 7 files changed, 514 insertions(+), 65 deletions(-) create mode 100644 include/osg/StencilTwoSided create mode 100644 src/osg/StencilTwoSided.cpp diff --git a/VisualStudio/osg/osg.dsp b/VisualStudio/osg/osg.dsp index d0e68db12..1a37637de 100755 --- a/VisualStudio/osg/osg.dsp +++ b/VisualStudio/osg/osg.dsp @@ -528,6 +528,10 @@ SOURCE=..\..\src\osg\Stencil.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\StencilTwoSided.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\Switch.cpp # End Source File # Begin Source File @@ -1040,6 +1044,10 @@ SOURCE=..\..\Include\Osg\Stencil # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\StencilTwoSided +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\Switch # End Source File # Begin Source File diff --git a/examples/osgshadow/osgshadow.cpp b/examples/osgshadow/osgshadow.cpp index 454d847fd..1ea19dfda 100644 --- a/examples/osgshadow/osgshadow.cpp +++ b/examples/osgshadow/osgshadow.cpp @@ -5,16 +5,19 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include @@ -47,6 +50,12 @@ public: polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) ); } + void getBase(osg::Polytope& polytope, float margin=0.1) const + { + float delta = _bb.radius()*margin; + polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) ); + } + void apply(osg::Node& node) { traverse(node); @@ -152,6 +161,19 @@ int main(int argc, char** argv) bool doShadow = true; while (arguments.read("--noShadow")) doShadow = false; + + osgShadow::ShadowVolumeGeometry::DrawMode drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS; + while (arguments.read("--two-sided")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED; + + + std::string pathfile; + while (arguments.read("-p",pathfile)) + { + osg::ref_ptr apm = new osgGA::AnimationPathManipulator(pathfile); + if (apm->valid()) viewer.setCameraManipulator(apm.get()); + } + + if (!viewer.getCameraManipulator()) viewer.setCameraManipulator( new osgGA::TrackballManipulator() ); // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); @@ -204,7 +226,8 @@ int main(int argc, char** argv) // set up the occluder osg::ref_ptr occluder = new osgShadow::OccluderGeometry; occluder->computeOccluderGeometry(model.get()); - cbbv.getPolytope(occluder->getBoundingPolytope(),0.001); +// cbbv.getPolytope(occluder->getBoundingPolytope(),0.001); + cbbv.getBase(occluder->getBoundingPolytope(),0.001); if (addOccluderToScene) { @@ -215,7 +238,8 @@ int main(int argc, char** argv) osg::ref_ptr shadowVolume = new osgShadow::ShadowVolumeGeometry; - shadowVolume->setUseDisplayList(!updateLightPosition); + // shadowVolume->setUseDisplayList(!updateLightPosition); + shadowVolume->setUseDisplayList(false); osg::Vec4 lightpos; @@ -251,7 +275,7 @@ int main(int argc, char** argv) osg::Vec4 diffuse(0.8,0.8,0.8,1.0); osg::Vec4 zero_colour(0.0,0.0,0.0,1.0); - // first group + // first group, render the depth buffer + ambient light contribution { osg::Group* first_model_group = new osg::Group; @@ -291,50 +315,58 @@ int main(int argc, char** argv) { osg::ref_ptr geode = new osg::Geode; occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume); - geode->addDrawable(shadowVolume.get()); - - // switch off the writing to the color bit planes. - osg::ColorMask* colourMask = new osg::ColorMask; - colourMask->setMask(false,false,false,false); - - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(osg::Stencil::ALWAYS,0,~0u); - stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::INCR); - - osg::StateSet* ss_sv1 = geode->getOrCreateStateSet(); - ss_sv1->setRenderBinDetails(0, "RenderBin"); - ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON); - ss_sv1->setAttribute(colourMask); + shadowVolume->setDrawMode(drawMode); - ss_sv1->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - camera->addChild(geode.get()); - } - - if (true) - { - osg::ref_ptr geode = new osg::Geode; - occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume); - geode->addDrawable(shadowVolume.get()); + if (drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED) + { + osg::notify(osg::NOTICE)<<"STENCIL_TWO_SIDED seleteced"<setMask(false,false,false,false); + osg::StencilTwoSided* stencil = new osg::StencilTwoSided; + stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u); + stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP); + stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u); + stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP); - osg::Stencil* stencil = new osg::Stencil; - stencil->setFunction(osg::Stencil::ALWAYS,0,~0u); - stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::DECR); - osg::StateSet* ss_sv1 = geode->getOrCreateStateSet(); - ss_sv1->setRenderBinDetails(1, "RenderBin"); - ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON); - ss_sv1->setAttribute(colourMask); - - ss_sv1->setAttributeAndModes(new osg::CullFace(osg::CullFace::FRONT), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false); + + osg::StateSet* ss_sv1 = geode->getOrCreateStateSet(); + ss_sv1->setRenderBinDetails(0, "RenderBin"); + ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON); + ss_sv1->setAttribute(colourMask); + ss_sv1->setMode(GL_CULL_FACE,osg::StateAttribute::OFF); + + geode->addDrawable(shadowVolume.get()); + + camera->addChild(geode.get()); + + } + else + { + osg::notify(osg::NOTICE)<<"STENCIL_TWO_PASSES seleteced"<setFunction(osg::Stencil::ALWAYS,0,~0u); + stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP); + + osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false); + + osg::StateSet* ss_sv1 = geode->getOrCreateStateSet(); + ss_sv1->setRenderBinDetails(0, "RenderBin"); + ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON); + ss_sv1->setAttribute(colourMask); + ss_sv1->setMode(GL_CULL_FACE,osg::StateAttribute::ON); + + geode->addDrawable(shadowVolume.get()); + + camera->addChild(geode.get()); + } - camera->addChild(geode.get()); } + + // render scene graph adding contribution of light { osg::Group* second_model_group = new osg::Group; second_model_group->addChild(model.get()); @@ -363,7 +395,6 @@ int main(int argc, char** argv) stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP); ss1->setAttributeAndModes(stencil,osg::StateAttribute::ON); - osg::BlendFunc* blend = new osg::BlendFunc; blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE); ss1->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); @@ -381,16 +412,11 @@ int main(int argc, char** argv) viewer.setSceneData(group.get()); - - viewer.setCameraManipulator(new osgGA::TrackballManipulator()); - - - osg::notify(osg::NOTICE)<<"Warning: Stencil buffer required, but not yet switched on."< + +namespace osg { + +#ifndef GL_STENCIL_TEST_TWO_SIDE +#define GL_STENCIL_TEST_TWO_SIDE 0x8910 +#endif + +/** Encapsulate OpenGL two sided glStencilFunc/Op/Mask functions. +*/ +class OSG_EXPORT StencilTwoSided : public StateAttribute +{ + public : + + + StencilTwoSided(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + StencilTwoSided(const StencilTwoSided& stencil,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + META_StateAttribute(osg, StencilTwoSided, STENCIL); + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + virtual int compare(const StateAttribute& sa) const; + + virtual bool getModeUsage(ModeUsage& usage) const + { + usage.usesMode(GL_STENCIL_TEST); + usage.usesMode(GL_STENCIL_TEST_TWO_SIDE); + return true; + } + + enum Face + { + FRONT = 0, + BACK = 1 + }; + + enum Function + { + NEVER = GL_NEVER, + LESS = GL_LESS, + EQUAL = GL_EQUAL, + LEQUAL = GL_LEQUAL, + GREATER = GL_GREATER, + NOTEQUAL = GL_NOTEQUAL, + GEQUAL = GL_GEQUAL, + ALWAYS = GL_ALWAYS + }; + + inline void setFunction(Face face, Function func,int ref,unsigned int mask) + { + _func[face] = func; + _funcRef[face] = ref; + _funcMask[face] = mask; + } + + inline void setFunction(Face face, Function func) { _func[face] = func; } + inline Function getFunction(Face face) const { return _func[face]; } + + inline void setFunctionRef(Face face, int ref) { _funcRef[face]=ref; } + inline int getFunctionRef(Face face) const { return _funcRef[face]; } + + inline void setFunctionMask(Face face, unsigned int mask) { _funcMask[face]=mask; } + inline unsigned int getFunctionMask(Face face) const { return _funcMask[face]; } + + + enum Operation + { + KEEP = GL_KEEP, + ZERO = GL_ZERO, + REPLACE = GL_REPLACE, + INCR = GL_INCR, + DECR = GL_DECR, + INVERT = GL_INVERT, + INCR_WRAP = GL_INCR_WRAP, + DECR_WRAP = GL_DECR_WRAP + }; + + /** set the operations to apply when the various stencil and depth + * tests fail or pass. First parameter is to control the operation + * when the stencil test fails. The second parameter is to control the + * operation when the stencil test passes, but depth test fails. The + * third parameter controls the operation when both the stencil test + * and depth pass. Ordering of parameter is the same as if using + * glStencilOp(,,).*/ + inline void setOperation(Face face, Operation sfail, Operation zfail, Operation zpass) + { + _sfail[face] = sfail; + _zfail[face] = zfail; + _zpass[face] = zpass; + } + + /** set the operation when the stencil test fails.*/ + inline void setStencilFailOperation(Face face, Operation sfail) { _sfail[face] = sfail; } + + /** get the operation when the stencil test fails.*/ + inline Operation getStencilFailOperation(Face face) const { return _sfail[face]; } + + /** set the operation when the stencil test passes but the depth test fails.*/ + inline void setStencilPassAndDepthFailOperation(Face face, Operation zfail) { _zfail[face]=zfail; } + + /** get the operation when the stencil test passes but the depth test fails.*/ + inline Operation getStencilPassAndDepthFailOperation(Face face) const { return _zfail[face]; } + + /** set the operation when both the stencil test and the depth test pass.*/ + inline void setStencilPassAndDepthPassOperation(Face face, Operation zpass) { _zpass[face]=zpass; } + + /** get the operation when both the stencil test and the depth test pass.*/ + inline Operation getStencilPassAndDepthPassOperation(Face face) const { return _zpass[face]; } + + + inline void setWriteMask(Face face, unsigned int mask) { _writeMask[face] = mask; } + + inline unsigned int getWriteMask(Face face) const { return _writeMask[face]; } + + + virtual void apply(State& state) const; + + public: + + /** Extensions class which encapsulates the querying of extensions and + * associated function pointers, and provide convenience wrappers to + * check for the extensions or use the associated functions. + */ + class OSG_EXPORT Extensions : public osg::Referenced + { + public: + Extensions(unsigned int contextID); + + Extensions(const Extensions& rhs); + + void lowestCommonDenominator(const Extensions& rhs); + + void setupGLExtenions(unsigned int contextID); + + void setStencilTwoSidedSupported(bool flag) { _isStencilTwoSidedSupported=flag; } + bool isStencilTwoSidedSupported() const { return _isStencilTwoSidedSupported; } + + void glActiveStencilFace(GLenum face) const; + + protected: + + ~Extensions() {} + + bool _isStencilTwoSidedSupported; + + void* _glActiveStencilFace; + }; + + /** Function to call to get the extension of a specified context. + * If the Exentsion object for that context has not yet been created + * and the 'createIfNotInitalized' flag been set to false then returns NULL. + * If 'createIfNotInitalized' is true then the Extensions object is + * automatically created. However, in this case the extension object + * will only be created with the graphics context associated with ContextID. + */ + static Extensions* getExtensions(unsigned int contextID,bool createIfNotInitalized); + + /** The setExtensions method allows users to override the extensions across graphics contexts. + * Typically used when you have different extensions supported across graphics pipes + * but need to ensure that they all use the same low common denominator extensions. + */ + static void setExtensions(unsigned int contextID,Extensions* extensions); + + + protected: + + virtual ~StencilTwoSided(); + + Function _func[2]; + int _funcRef[2]; + unsigned int _funcMask[2]; + + Operation _sfail[2]; + Operation _zfail[2]; + Operation _zpass[2]; + + unsigned int _writeMask[2]; + +}; + +} + +#endif diff --git a/include/osgShadow/OccluderGeometry b/include/osgShadow/OccluderGeometry index bed45c168..f036453f9 100644 --- a/include/osgShadow/OccluderGeometry +++ b/include/osgShadow/OccluderGeometry @@ -197,7 +197,16 @@ class OSGSHADOW_EXPORT ShadowVolumeGeometry : public osg::Drawable virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } virtual const char* libraryName() const { return "osgShadow"; } virtual const char* className() const { return "ShadowVolumeGeometry"; } + + enum DrawMode + { + GEOMETRY, + STENCIL_TWO_PASS, + STENCIL_TWO_SIDED + }; + void setDrawMode(DrawMode mode) { _drawMode = mode; } + DrawMode getDrawMode() const { return _drawMode; } typedef std::vector Vec3List; typedef std::vector UIntList; @@ -223,6 +232,7 @@ class OSGSHADOW_EXPORT ShadowVolumeGeometry : public osg::Drawable virtual ~ShadowVolumeGeometry() {} + DrawMode _drawMode; Vec3List _vertices; Vec3List _normals; UIntList _indices; diff --git a/src/osg/GNUmakefile b/src/osg/GNUmakefile index 5f6a74dfd..b53452a71 100644 --- a/src/osg/GNUmakefile +++ b/src/osg/GNUmakefile @@ -95,6 +95,7 @@ CXXFILES =\ StateAttribute.cpp\ StateSet.cpp\ Stencil.cpp\ + StencilTwoSided.cpp\ Switch.cpp\ TexEnvCombine.cpp\ TexEnv.cpp\ diff --git a/src/osg/StencilTwoSided.cpp b/src/osg/StencilTwoSided.cpp new file mode 100644 index 000000000..e45b163a8 --- /dev/null +++ b/src/osg/StencilTwoSided.cpp @@ -0,0 +1,160 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include +#include +#include +#include + +using namespace osg; + +StencilTwoSided::StencilTwoSided() +{ + // set up same defaults as glStencilFunc. + _func[FRONT] = _func[BACK] = ALWAYS; + _funcRef[FRONT] = _funcRef[BACK] = 0; + _funcMask[FRONT] = _funcMask[BACK] = ~0u; + + // set up same defaults as glStencilOp. + _sfail[FRONT] = _sfail[BACK] = KEEP; + _zfail[FRONT] = _zfail[BACK] = KEEP; + _zpass[FRONT] = _zpass[BACK] = KEEP; + + _writeMask[FRONT] = _writeMask[BACK] = ~0u; +} + +StencilTwoSided::StencilTwoSided(const StencilTwoSided& stencil,const CopyOp& copyop): + StateAttribute(stencil,copyop) +{ + _func[FRONT] = stencil._func[FRONT]; + _funcRef[FRONT] = stencil._funcRef[FRONT]; + _funcMask[FRONT] = stencil._funcMask[FRONT]; + _sfail[FRONT] = stencil._sfail[FRONT]; + _zfail[FRONT] = stencil._zfail[FRONT]; + _zpass[FRONT] = stencil._zpass[FRONT]; + _writeMask[FRONT] = stencil._writeMask[FRONT]; + + _func[BACK] = stencil._func[BACK]; + _funcRef[BACK] = stencil._funcRef[BACK]; + _funcMask[BACK] = stencil._funcMask[BACK]; + _sfail[BACK] = stencil._sfail[BACK]; + _zfail[BACK] = stencil._zfail[BACK]; + _zpass[BACK] = stencil._zpass[BACK]; + _writeMask[BACK] = stencil._writeMask[BACK]; +} + +StencilTwoSided::~StencilTwoSided() +{ +} + +int StencilTwoSided::compare(const StateAttribute& sa) const +{ + // check the types are equal and then create the rhs variable + // used by the COMPARE_StateAttribute_Parameter macro's below. + COMPARE_StateAttribute_Types(StencilTwoSided,sa) + + // compare each parameter in turn against the rhs. + COMPARE_StateAttribute_Parameter(_func[FRONT]) + COMPARE_StateAttribute_Parameter(_funcRef[FRONT]) + COMPARE_StateAttribute_Parameter(_funcMask[FRONT]) + COMPARE_StateAttribute_Parameter(_sfail[FRONT]) + COMPARE_StateAttribute_Parameter(_zfail[FRONT]) + COMPARE_StateAttribute_Parameter(_zpass[FRONT]) + COMPARE_StateAttribute_Parameter(_writeMask[FRONT]) + + COMPARE_StateAttribute_Parameter(_func[BACK]) + COMPARE_StateAttribute_Parameter(_funcRef[BACK]) + COMPARE_StateAttribute_Parameter(_funcMask[BACK]) + COMPARE_StateAttribute_Parameter(_sfail[BACK]) + COMPARE_StateAttribute_Parameter(_zfail[BACK]) + COMPARE_StateAttribute_Parameter(_zpass[BACK]) + COMPARE_StateAttribute_Parameter(_writeMask[BACK]) + + return 0; // passed all the above comparison macro's, must be equal. +} + +void StencilTwoSided::apply(State& state) const +{ + const unsigned int contextID = state.getContextID(); + const Extensions* extensions = getExtensions(contextID,true); + + if (!extensions->isStencilTwoSidedSupported()) + return; + + extensions->glActiveStencilFace(GL_BACK); + glStencilOp((GLenum)_sfail[BACK],(GLenum)_zfail[BACK],(GLenum)_zpass[BACK]); + glStencilMask(_writeMask[BACK]); + glStencilFunc((GLenum)_func[BACK],_funcRef[BACK],_funcMask[BACK]); + + extensions->glActiveStencilFace(GL_FRONT); + glStencilOp((GLenum)_sfail[FRONT],(GLenum)_zfail[FRONT],(GLenum)_zpass[FRONT]); + glStencilMask(_writeMask[FRONT]); + glStencilFunc((GLenum)_func[FRONT],_funcRef[FRONT],_funcMask[FRONT]); +} + + +typedef buffered_value< ref_ptr > BufferedExtensions; +static BufferedExtensions s_extensions; + +StencilTwoSided::Extensions* StencilTwoSided::getExtensions(unsigned int contextID,bool createIfNotInitalized) +{ + if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID); + return s_extensions[contextID].get(); +} + +void StencilTwoSided::setExtensions(unsigned int contextID,Extensions* extensions) +{ + s_extensions[contextID] = extensions; +} + +StencilTwoSided::Extensions::Extensions(unsigned int contextID) +{ + setupGLExtenions(contextID); +} + +StencilTwoSided::Extensions::Extensions(const Extensions& rhs): + Referenced() +{ + _isStencilTwoSidedSupported = rhs._isStencilTwoSidedSupported; + _glActiveStencilFace = rhs._glActiveStencilFace; +} + + +void StencilTwoSided::Extensions::lowestCommonDenominator(const Extensions& rhs) +{ + if (!rhs._isStencilTwoSidedSupported) _isStencilTwoSidedSupported = false; + + if (!rhs._glActiveStencilFace) _glActiveStencilFace = 0; + +} + +void StencilTwoSided::Extensions::setupGLExtenions(unsigned int contextID) +{ + _isStencilTwoSidedSupported = isGLExtensionSupported(contextID,"GL_EXT_stencil_two_side"); + + _glActiveStencilFace = osg::getGLExtensionFuncPtr("glActiveStencilFace","glActiveStencilFaceEXT"); +} + +void StencilTwoSided::Extensions::glActiveStencilFace(GLenum face) const +{ + if (_glActiveStencilFace) + { + typedef void (APIENTRY * ActiveStencilFaceProc) (GLenum); + ((ActiveStencilFaceProc)_glActiveStencilFace)(face); + } + else + { + notify(WARN)<<"Error: glActiveStencilFace not supported by OpenGL driver"< +#include + #include #include @@ -23,6 +27,7 @@ #include + using namespace osgShadow; OccluderGeometry::OccluderGeometry() @@ -762,7 +767,7 @@ void OccluderGeometry::computeShadowVolumeGeometry(const osg::Vec4& lightpos, Sh // directional light. osg::Vec3 lightdirection( -lightpos.x(), -lightpos.y(), -lightpos.z()); - osg::notify(osg::NOTICE)<<"Directional light"<delta_m(t0,t1)<<" ms"<delta_m(t0,t1)<<" ms"<disableAllVertexArrays(); - - renderInfo.getState()->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) ); - - if (!_normals.empty()) + if (_drawMode==GEOMETRY) { - renderInfo.getState()->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) ); + osg::State* state = renderInfo.getState(); + + state->disableAllVertexArrays(); + + state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) ); + + if (!_normals.empty()) + { + state->setNormalPointer( GL_FLOAT, 0, &(_normals.front()) ); + } + else + { + glNormal3f(0.0f, 0.0f, 0.0f); + } + + + glColor4f(0.5f, 1.0f, 1.0f, 1.0f); + + glDrawArrays( GL_QUADS, 0, _vertices.size() ); } - else + else if (_drawMode==STENCIL_TWO_PASS) { - glNormal3f(0.0f, 0.0f, 0.0f); + osg::State* state = renderInfo.getState(); + + state->disableAllVertexArrays(); + state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) ); + + // draw front faces of shadow volume + glCullFace(GL_BACK); + glStencilOp( GL_KEEP, GL_KEEP, GL_INCR); + + glDrawArrays( GL_QUADS, 0, _vertices.size() ); + + // draw back faces of shadow volume + glCullFace(GL_FRONT); + glStencilOp( GL_KEEP, GL_KEEP, GL_DECR); + + glDrawArrays( GL_QUADS, 0, _vertices.size() ); + + state->haveAppliedAttribute(osg::StateAttribute::CULLFACE); + state->haveAppliedAttribute(osg::StateAttribute::STENCIL); + } + else // stencil two sided, note state all set up separately. + { + osg::State* state = renderInfo.getState(); + + state->disableAllVertexArrays(); + state->setVertexPointer( 3, GL_FLOAT, 0, &(_vertices.front()) ); - - glColor4f(0.5f, 1.0f, 1.0f, 1.0f); - - glDrawArrays( GL_QUADS, 0, _vertices.size() ); + glDrawArrays( GL_QUADS, 0, _vertices.size() ); + } } osg::BoundingBox ShadowVolumeGeometry::computeBound() const