osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthFeatures/StencilVolumeNode.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2009 Pelican Ventures, Inc.
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include <osgEarthFeatures/StencilVolumeNode>
00020 #include <osg/Stencil>
00021 #include <osg/StencilTwoSided>
00022 #include <osg/Depth>
00023 #include <osg/Drawable>
00024 #include <osg/CopyOp>
00025 #include <osg/CullFace>
00026 #include <osg/MatrixTransform>
00027 #include <osg/Projection>
00028 #include <osg/GLExtensions>
00029 #include <osg/Geode>
00030 #include <osg/Notify>
00031 #include <osgUtil/Tessellator>
00032 #include <algorithm>
00033 
00034 #define ON_AND_PROTECTED  osg::StateAttribute::ON | osg::StateAttribute::PROTECTED
00035 #define OFF_AND_PROTECTED osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED
00036 
00037 using namespace osgEarth;
00038 using namespace osgEarth::Features;
00039 
00040 
00041 StencilVolumeNode::StencilVolumeNode( bool preRenderChildrenToDepthBuffer, bool inverted ) :
00042 osgEarth::MaskNode(),
00043 _preRenderChildrenToDepthBuffer( preRenderChildrenToDepthBuffer ),
00044 _inverted( inverted ),
00045 _stencilGroup1( 0L ),
00046 _stencilGroup2( 0L ),
00047 _depthPass( 0L ),
00048 _renderPass( 0L )
00049 {
00050     init();
00051 }
00052 
00053 StencilVolumeNode::StencilVolumeNode(const StencilVolumeNode& rhs,
00054                                      const osg::CopyOp& op) :
00055 osgEarth::MaskNode( rhs, op ),
00056 _root( rhs._root.get() ),
00057 _stencilGroup1( rhs._stencilGroup1 ),
00058 _stencilGroup2( rhs._stencilGroup2 ),
00059 _depthPass( rhs._depthPass ),
00060 _renderPass( rhs._renderPass ),
00061 _inverted( rhs._inverted ),
00062 _preRenderChildrenToDepthBuffer( rhs._preRenderChildrenToDepthBuffer )
00063 {
00064     //nop
00065 }
00066 
00067 int
00068 StencilVolumeNode::setBaseRenderBin( int bin )
00069 {
00070     if ( _depthPass )
00071     {
00072         _depthPass->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00073     }
00074     if ( _stencilGroup1 )
00075     {
00076         _stencilGroup1->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00077     }
00078     if ( _stencilGroup2 )
00079     {
00080         _stencilGroup2->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00081     }
00082     if ( _renderPass )
00083     {
00084         _renderPass->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00085     }
00086     return bin;
00087 }
00088 
00089 void
00090 StencilVolumeNode::addVolumes( osg::Node* node )
00091 {
00092     if ( _stencilGroup1 )
00093         _stencilGroup1->addChild( node );
00094     if ( _stencilGroup2 )
00095         _stencilGroup2->addChild( node );
00096 }
00097 
00100 bool 
00101 StencilVolumeNode::addChild( Node *child ) {
00102     if ( !child ) return false;
00103     dirtyBound();
00104     if ( _depthPass )  _depthPass->addChild( child );
00105     return _renderPass->addChild( child );
00106 }
00107 bool 
00108 StencilVolumeNode::insertChild( unsigned int index, Node *child ) {
00109     if ( !child ) return false;
00110     dirtyBound();
00111     if ( _depthPass ) _depthPass->insertChild( index, child );
00112     return _renderPass->insertChild( index, child );
00113 }
00114 bool 
00115 StencilVolumeNode::removeChildren(unsigned int pos,unsigned int numChildrenToRemove) {
00116     dirtyBound();
00117     if ( _depthPass ) _depthPass->removeChildren( pos, numChildrenToRemove );
00118     return _renderPass->removeChildren( pos, numChildrenToRemove );
00119 }
00120 bool 
00121 StencilVolumeNode::replaceChild( Node *origChild, Node* newChild ) {
00122     dirtyBound();
00123     if ( _depthPass ) _depthPass->replaceChild( origChild, newChild );
00124     return _renderPass->replaceChild( origChild, newChild );
00125 }
00126 bool 
00127 StencilVolumeNode::setChild( unsigned  int i, Node* node ) {
00128     dirtyBound();
00129     if ( _depthPass ) _depthPass->setChild( i, node );
00130     return _renderPass->setChild( i, node );
00131 }
00132 
00133 osg::BoundingSphere
00134 StencilVolumeNode::computeBound() const {
00135     if ( _depthPass ) return _depthPass->computeBound();
00136     else return _renderPass->computeBound();
00137 }
00138 
00139 
00140 void
00141 StencilVolumeNode::traverse( osg::NodeVisitor& nv )
00142 {
00143     _root->accept( nv );
00144 }
00145 
00146 void
00147 StencilVolumeNode::init()
00148 {
00149     _root = new osg::Group();
00150     int baseBin = 100;
00151 
00152     // First, if we need to render the children to the depth buffer, create a depth
00153     // buffer only pass. This is necessary if we are masking out terrain, for example. We have
00154     // to populate the depth buffer before this algoritm can work.
00155     if ( _preRenderChildrenToDepthBuffer )
00156     {
00157         _depthPass = new osg::Group();
00158         _depthPass->setName( "StencilVolumeNode::depth_pass" );
00159         osg::StateSet* ss = _depthPass->getOrCreateStateSet();
00160         ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00161         //ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
00162         ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS), ON_AND_PROTECTED);
00163         ss->setRenderBinDetails( baseBin++, "RenderBin" );
00164 
00165         _root->addChild( _depthPass );
00166     }
00167 
00168     // Create the stenciled geometry pass:
00169 
00170     // For now we are hard-coding these to what are hopefully "safe" values.
00171     // In the future we hope to rewrite this as a custom StencilVolumeNode that 
00172     // will automatically detect extension availability at draw time and choose
00173     // the optimal GL rendering path.
00174     static bool s_EXT_stencil_wrap     = true; //osg::isGLExtensionSupported(0, "GL_EXT_stencil_wrap");
00175     static bool s_EXT_stencil_two_side = false; //osg::isGLExtensionSupported(0, "GL_EXT_stencil_two_side");
00176 
00177 
00178     // zFail=true if more compute intensive, but lets you get inside the volume.
00179     // Again, a custom node will give us a better opportunity to choose between zFail and zPass based on
00180     // the eye location (you only need zFail if you camera is inside the volume).
00181     bool zFail = true;
00182 
00183     OE_INFO << "Stencil buffer wrap = " << s_EXT_stencil_wrap << std::endl;
00184 
00185     if ( s_EXT_stencil_two_side )
00186     {
00187         OE_INFO << "Two-sided stenciling" << std::endl;
00188 
00189         osg::StencilTwoSided::Operation incrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::INCR_WRAP : osg::StencilTwoSided::INCR;
00190         osg::StencilTwoSided::Operation decrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::DECR_WRAP : osg::StencilTwoSided::DECR;
00191         _stencilGroup1 = new osg::Group();
00192         //osg::Group* stencil_group = new osg::Group();
00193         osg::StateSet* ss = _stencilGroup1->getOrCreateStateSet();
00194         ss->setRenderBinDetails( baseBin++, "RenderBin" );
00195 
00196         if ( zFail )
00197         {
00198             osg::StencilTwoSided* stencil = new osg::StencilTwoSided();
00199             stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00200             stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, incrOp, osg::StencilTwoSided::KEEP);
00201 
00202             stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00203             stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, decrOp, osg::StencilTwoSided::KEEP);
00204             ss->setAttributeAndModes( stencil, ON_AND_PROTECTED );
00205         }
00206         else
00207         {
00208             osg::StencilTwoSided* stencil = new osg::StencilTwoSided();
00209             stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00210             stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, incrOp);
00211 
00212             stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00213             stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, decrOp);
00214             ss->setAttributeAndModes( stencil, ON_AND_PROTECTED );
00215         }
00216 
00217         ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00218         ss->setAttributeAndModes(new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00219 
00220         _root->addChild( _stencilGroup1 );
00221     }
00222     else
00223     {
00224         OE_INFO << "One-sided stenciling" << std::endl;
00225 
00226         if ( !zFail )  // Z-Pass
00227         {
00228             _stencilGroup1 = new osg::Group();
00229             osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet();
00230             front_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00231 
00232             // incrementing stencil op for front faces:
00233             osg::Stencil* front_stencil = new osg::Stencil();
00234             front_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u );
00235             osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR;
00236             front_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, incrOp );
00237             front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED );
00238 
00239             front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00240             front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
00241             front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00242 
00243             _root->addChild( _stencilGroup1 );
00244 
00245             // decrementing stencil op for back faces:
00246             _stencilGroup2 = new osg::Group();
00247             osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet();
00248             back_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00249 
00250             osg::Stencil* back_stencil = new osg::Stencil();
00251             back_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u );
00252             osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR;
00253             back_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, decrOp );
00254             back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED );
00255 
00256             back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00257             back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED);
00258             back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00259 
00260             _root->addChild( _stencilGroup2 );    
00261         }
00262         else
00263         {
00264             // incrementing stencil op for back faces:
00265             {
00266                 _stencilGroup1 = new osg::Group();
00267                 osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet();
00268                 front_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00269 
00270                 osg::Stencil* front_stencil = new osg::Stencil();
00271                 front_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u );
00272                 osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR;
00273                 front_stencil->setOperation( osg::Stencil::KEEP, incrOp, osg::Stencil::KEEP );
00274                 front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED );
00275 
00276                 front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00277                 front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED);
00278                 front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00279 
00280                 _root->addChild( _stencilGroup1 );
00281             }
00282 
00283             // decrementing stencil buf for front faces
00284             {
00285                 _stencilGroup2 = new osg::Group();
00286                 osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet();
00287                 back_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00288 
00289                 osg::Stencil* back_stencil = new osg::Stencil();
00290                 back_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u );
00291                 osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR;
00292                 back_stencil->setOperation( osg::Stencil::KEEP, decrOp, osg::Stencil::KEEP );
00293                 back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED );
00294 
00295                 back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00296                 back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
00297                 back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00298 
00299                 _root->addChild( _stencilGroup2 );
00300             }
00301         }
00302     }
00303     
00304 
00305     // NOW build the full-screen quad mask that will paint the volume:
00306 
00307     _renderPass = new osg::Group();
00308     _renderPass->setName( "StencilVolumeNode::render_pass" );
00309 
00310     osg::Stencil* quad_stencil = new osg::Stencil();
00311     osg::Stencil::Function func = _inverted ? osg::Stencil::EQUAL : osg::Stencil::NOTEQUAL;
00312     quad_stencil->setFunction( func, 128, (unsigned int)~0 );
00313     // this will conveniently re-clear the stencil buffer in prep for the next pass:
00314     quad_stencil->setOperation( osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE );
00315 
00316     osg::StateSet* renderSS = _renderPass->getOrCreateStateSet();
00317     renderSS->setAttributeAndModes( quad_stencil, ON_AND_PROTECTED );
00318     renderSS->setRenderBinDetails( baseBin++, "RenderBin" );
00319 
00320     // if we did a pre-render depth pass, adjust the depth buffer function to account for that
00321     if ( _preRenderChildrenToDepthBuffer )
00322     {
00323         renderSS->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL ), osg::StateAttribute::ON );
00324     }
00325 
00326     // testing
00327     //renderSS->setMode( GL_DEPTH_TEST, OFF_AND_PROTECTED );
00328     //renderSS->setAttributeAndModes( new osg::Depth( osg::Depth::ALWAYS ), ON_AND_PROTECTED );
00329 
00330     _root->addChild( _renderPass );
00331 }
00332 
00333 
00334 static
00335 void tessellate( osg::Geometry* geom )
00336 {
00337     osgUtil::Tessellator tess;
00338     tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
00339     tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
00340 //    tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE );
00341     tess.retessellatePolygons( *geom );
00342 }
00343 
00344 osg::Geode*
00345 StencilVolumeFactory::createVolume(Geometry*            geom,
00346                                    double               offset,
00347                                    double               height,
00348                                    const FilterContext& context )
00349 {
00350     if ( !geom ) return 0L;
00351 
00352     int numRings = 0;
00353 
00354     // start by offsetting the input data and counting the number of rings
00355     {
00356         GeometryIterator i( geom );
00357         i.traverseMultiGeometry() = true;
00358         i.traversePolygonHoles() = true;
00359         while( i.hasMore() )
00360         {
00361             Geometry* part = i.next();
00362 
00363             if (offset != 0.0)
00364             {
00365                 for( osg::Vec3dArray::iterator j = part->begin(); j != part->end(); j++ )
00366                 {
00367                     if ( context.isGeocentric() )
00368                     {
00369                         osg::Vec3d world = context.toWorld( *j );
00370                         // TODO: get the proper up vector; this is spherical.. or does it really matter for
00371                         // stencil volumes?
00372                         osg::Vec3d offset_vec = world;
00373                         offset_vec.normalize();
00374                         *j = context.toLocal( world + offset_vec * offset ); //(*j) += offset_vec * offset;
00375                     }
00376                     else
00377                     {
00378                         (*j).z() += offset;
00379                     }
00380                 }
00381             }
00382 
00383             // in the meantime, count the # of closed geoms. We will need to know this in 
00384             // order to pre-allocate the proper # of verts.
00385             if ( part->getType() == Geometry::TYPE_POLYGON || part->getType() == Geometry::TYPE_RING )
00386             {
00387                 numRings++;
00388             }
00389         }
00390     }
00391 
00392     // now, go thru and remove any coplanar segments from the geometry. The tesselator will
00393     // not work include a vert connecting two colinear segments in the tesselation, and this
00394     // will break the stenciling logic.
00395 #define PARALLEL_EPSILON 0.01
00396     GeometryIterator i( geom );
00397     i.traverseMultiGeometry() = true;
00398     i.traversePolygonHoles() = true;
00399     while( i.hasMore() )
00400     {
00401         Geometry* part = i.next();
00402         if ( part->size() >= 3 )
00403         {
00404             osg::Vec3d prevVec = part->front() - part->back();
00405             prevVec.normalize();
00406 
00407             for( osg::Vec3dArray::iterator j = part->begin(); part->size() >= 3 && j != part->end(); )
00408             {
00409                 osg::Vec3d& p0 = *j;
00410                 osg::Vec3d& p1 = j+1 != part->end() ? *(j+1) : part->front();
00411                 osg::Vec3d vec = p1-p0; vec.normalize();
00412 
00413                 // if the vectors are essentially parallel, remove the extraneous vertex.
00414                 if ( (prevVec ^ vec).length() < PARALLEL_EPSILON )
00415                 {
00416                     j = part->erase( j );
00417                     //OE_NOTICE << "removed colinear segment" << std::endl;
00418                 }
00419                 else
00420                 {
00421                     ++j;
00422                     prevVec = vec;
00423                 }
00424             }
00425         }
00426     }
00427 
00428 
00429     bool made_geom = true;
00430     const SpatialReference* srs = context.profile()->getSRS();
00431 
00432     // total up all the points so we can pre-allocate the vertex arrays.
00433     int num_cap_verts = geom->getTotalPointCount();
00434     int num_wall_verts = 2 * (num_cap_verts + numRings); // add in numRings b/c we need to close each wall
00435 
00436     osg::Geometry* walls = new osg::Geometry();
00437     osg::Vec3Array* verts = new osg::Vec3Array( num_wall_verts );
00438     walls->setVertexArray( verts );
00439 
00440     osg::Geometry* top_cap = new osg::Geometry();
00441     osg::Vec3Array* top_verts = new osg::Vec3Array( num_cap_verts );
00442     top_cap->setVertexArray( top_verts );
00443 
00444     osg::Geometry* bottom_cap = new osg::Geometry();
00445     osg::Vec3Array* bottom_verts = new osg::Vec3Array( num_cap_verts );
00446     bottom_cap->setVertexArray( bottom_verts );
00447 
00448     int wall_vert_ptr = 0;
00449     int top_vert_ptr = 0;
00450     int bottom_vert_ptr = 0;
00451 
00452     //double target_len = height;
00453 
00454     // now generate the extruded geometry.
00455     GeometryIterator k( geom );
00456     while( k.hasMore() )
00457     {
00458         Geometry* part = k.next();
00459 
00460         unsigned int wall_part_ptr = wall_vert_ptr;
00461         unsigned int top_part_ptr = top_vert_ptr;
00462         unsigned int bottom_part_ptr = bottom_vert_ptr;
00463         double part_len = 0.0;
00464 
00465         GLenum prim_type = part->getType() == Geometry::TYPE_POINTSET ? GL_LINES : GL_TRIANGLE_STRIP;
00466 
00467         for( osg::Vec3dArray::const_iterator m = part->begin(); m != part->end(); ++m )
00468         {
00469             osg::Vec3d extrude_vec;
00470 
00471             if ( srs )
00472             {
00473                 osg::Vec3d m_world = context.toWorld( *m ); //*m * context.inverseReferenceFrame();
00474                 if ( context.isGeocentric() )
00475                 {
00476                     osg::Vec3d p_vec = m_world; // todo: not exactly right; spherical
00477 
00478                     osg::Vec3d unit_vec = p_vec; 
00479                     unit_vec.normalize();
00480                     p_vec = p_vec + unit_vec*height;
00481 
00482                     extrude_vec = context.toLocal( p_vec ); //p_vec * context.referenceFrame();
00483                 }
00484                 else
00485                 {
00486                     extrude_vec.set( m_world.x(), m_world.y(), height );
00487                     extrude_vec = context.toLocal( extrude_vec ); //extrude_vec * context.referenceFrame();
00488                 }
00489             }
00490             else
00491             {
00492                 extrude_vec.set( m->x(), m->y(), height );
00493             }
00494 
00495             (*top_verts)[top_vert_ptr++] = extrude_vec;
00496             (*bottom_verts)[bottom_vert_ptr++] = *m;
00497              
00498             part_len += wall_vert_ptr > wall_part_ptr?
00499                 (extrude_vec - (*verts)[wall_vert_ptr-2]).length() :
00500                 0.0;
00501 
00502             int p;
00503 
00504             p = wall_vert_ptr++;
00505             (*verts)[p] = extrude_vec;
00506 
00507             p = wall_vert_ptr++;
00508             (*verts)[p] = *m;
00509         }
00510 
00511         // close the wall if it's a ring/poly:
00512         if ( part->getType() == Geometry::TYPE_RING || part->getType() == Geometry::TYPE_POLYGON )
00513         {
00514             part_len += wall_vert_ptr > wall_part_ptr?
00515                 ((*verts)[wall_part_ptr] - (*verts)[wall_vert_ptr-2]).length() :
00516                 0.0;
00517 
00518             int p;
00519 
00520             p = wall_vert_ptr++;
00521             (*verts)[p] = (*verts)[wall_part_ptr];
00522 
00523             p = wall_vert_ptr++;
00524             (*verts)[p] = (*verts)[wall_part_ptr+1];
00525         }
00526 
00527         walls->addPrimitiveSet( new osg::DrawArrays(
00528             prim_type,
00529             wall_part_ptr, wall_vert_ptr - wall_part_ptr ) );
00530 
00531         top_cap->addPrimitiveSet( new osg::DrawArrays(
00532             osg::PrimitiveSet::LINE_LOOP,
00533             top_part_ptr, top_vert_ptr - top_part_ptr ) );
00534 
00535         // reverse the bottom verts so the front face is down:
00536         std::reverse( bottom_verts->begin()+bottom_part_ptr, bottom_verts->begin()+bottom_vert_ptr );
00537 
00538         bottom_cap->addPrimitiveSet( new osg::DrawArrays(
00539             osg::PrimitiveSet::LINE_LOOP,
00540             bottom_part_ptr, bottom_vert_ptr - bottom_part_ptr ) );
00541     }
00542 
00543     // build solid surfaces for the caps:
00544     tessellate( top_cap );
00545     tessellate( bottom_cap );
00546 
00547     osg::Geode* geode = new osg::Geode();
00548     geode->addDrawable( walls );
00549     geode->addDrawable( top_cap );
00550     geode->addDrawable( bottom_cap );
00551 
00552     return geode;
00553 }
00554 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines