Show
Ignore:
Timestamp:
08/25/10 13:07:30 (4 years ago)
Author:
robert
Message:

Cleaned up main and introduced --samples <num>, --flat, --smooth command line controls.

Add StatsHandler? to viewer to enable review of different settings on number vertices/triangles.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgtext3D/osgtext3D.cpp

    r11725 r11727  
    3636extern int main_orig(int, char**); 
    3737extern int main_test(int, char**); 
    38  
    39  
    40  
    41 class Boundary 
    42 { 
    43 public: 
    44  
    45     typedef std::pair<unsigned int, unsigned int> Segment; 
    46     typedef std::vector<Segment>  Segments; 
    47     osg::ref_ptr<osg::Vec3Array> _vertices; 
    48     unsigned int _start; 
    49     unsigned int _count; 
    50     Segments _segments; 
    51  
    52     Boundary(osg::Vec3Array* vertices, unsigned int start, unsigned int count) 
    53     { 
    54         _vertices = vertices; 
    55         _start = start; 
    56         _count = count; 
    57  
    58         if ((*_vertices)[start]==(*_vertices)[start+count-1]) 
    59         { 
    60             // OSG_NOTICE<<"Boundary is a line loop"<<std::endl; 
    61         } 
    62         else 
    63         { 
    64             OSG_NOTICE<<"Boundary is not a line loop"<<std::endl; 
    65         } 
    66  
    67         _segments.reserve(count-1); 
    68         for(unsigned int i=start; i<start+count-2; ++i) 
    69         { 
    70             _segments.push_back(Segment(i,i+1)); 
    71         } 
    72         _segments.push_back(Segment(start+count-2,start)); 
    73  
    74     } 
    75  
    76     osg::Vec3 computeRayIntersectionPoint(const osg::Vec3& a, const osg::Vec3& an, const osg::Vec3& c, const osg::Vec3& cn) 
    77     { 
    78         float denominator = ( cn.x() * an.y() - cn.y() * an.x()); 
    79         if (denominator==0.0f) 
    80         { 
    81             //OSG_NOTICE<<"computeRayIntersectionPoint()<<denominator==0.0"<<std::endl; 
    82             // line segments must be parallel. 
    83             return (a+c)*0.5f; 
    84         } 
    85  
    86         float t = ((a.x()-c.x())*an.y() - (a.y()-c.y())*an.x()) / denominator; 
    87         return c + cn*t; 
    88     } 
    89  
    90     osg::Vec3 computeIntersectionPoint(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d) 
    91     { 
    92         return computeRayIntersectionPoint(a, b-a, c, d-c); 
    93     } 
    94  
    95     osg::Vec3 computeBisectorNormal(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d) 
    96     { 
    97         osg::Vec2 ab(a.x()-b.x(), a.y()-b.y()); 
    98         osg::Vec2 dc(d.x()-c.x(), d.y()-c.y()); 
    99         /*float length_ab =*/ ab.normalize(); 
    100         /*float length_dc =*/ dc.normalize(); 
    101  
    102         float e = dc.y() - ab.y(); 
    103         float f = ab.x() - dc.x(); 
    104         float denominator = sqrtf(e*e + f*f); 
    105         float nx = e / denominator; 
    106         float ny = f / denominator; 
    107         if (( ab.x()*ny - ab.y()*nx) > 0.0f) 
    108         { 
    109             // OSG_NOTICE<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" no need to swap"<<std::endl; 
    110             return osg::Vec3(nx,ny,0.0f); 
    111         } 
    112         else 
    113         { 
    114             OSG_NOTICE<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" need to swap!!!"<<std::endl; 
    115             return osg::Vec3(-nx,-ny,0.0f); 
    116         } 
    117     } 
    118  
    119     float computeBisectorIntersectorThickness(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d, const osg::Vec3& e, const osg::Vec3& f) 
    120     { 
    121         osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d); 
    122         osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d); 
    123         osg::Vec3 intersection_cdef = computeIntersectionPoint(c,d,e,f); 
    124         osg::Vec3 bisector_cdef = computeBisectorNormal(c,d,e,f); 
    125         if (bisector_abcd==bisector_cdef) 
    126         { 
    127             //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl; 
    128             //OSG_NOTICE<<"   bisectors parallel, thickness = "<<FLT_MAX<<std::endl; 
    129             return FLT_MAX; 
    130         } 
    131  
    132         osg::Vec3 bisector_intersection = computeRayIntersectionPoint(intersection_abcd,bisector_abcd, intersection_cdef, bisector_cdef); 
    133         osg::Vec3 normal(d.y()-c.y(), c.x()-d.x(), 0.0); 
    134         float cd_length = normal.normalize(); 
    135         if (cd_length==0) 
    136         { 
    137             //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl; 
    138             //OSG_NOTICE<<"   segment length==0, thickness = "<<FLT_MAX<<std::endl; 
    139             return FLT_MAX; 
    140         } 
    141  
    142         float thickness = (bisector_intersection - c) * normal; 
    143     #if 0 
    144         OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl; 
    145         OSG_NOTICE<<"   bisector_abcd = "<<bisector_abcd<<", bisector_cdef="<<bisector_cdef<<std::endl; 
    146         OSG_NOTICE<<"   bisector_intersection = "<<bisector_intersection<<", thickness = "<<thickness<<std::endl; 
    147     #endif 
    148         return thickness; 
    149     } 
    150  
    151  
    152     float computeThickness(unsigned int i) 
    153     { 
    154         Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ]; 
    155         Segment& seg_target = _segments[ (i) % _segments.size() ]; 
    156         Segment& seg_after =  _segments[ (i+1) % _segments.size() ]; 
    157         return computeBisectorIntersectorThickness( 
    158             (*_vertices)[seg_before.first], (*_vertices)[seg_before.second], 
    159             (*_vertices)[seg_target.first], (*_vertices)[seg_target.second], 
    160             (*_vertices)[seg_after.first], (*_vertices)[seg_after.second]); 
    161     } 
    162  
    163     void computeAllThickness() 
    164     { 
    165         for(unsigned int i=0; i<_segments.size(); ++i) 
    166         { 
    167             computeThickness(i); 
    168         } 
    169     } 
    170  
    171  
    172     bool findMinThickness(unsigned int& minThickness_i, float& minThickness) 
    173     { 
    174         minThickness_i = _segments.size(); 
    175         for(unsigned int i=0; i<_segments.size(); ++i) 
    176         { 
    177             float thickness = computeThickness(i); 
    178             if (thickness>0.0 && thickness <  minThickness) 
    179             { 
    180                 minThickness = thickness; 
    181                 minThickness_i = i; 
    182             } 
    183         } 
    184  
    185         return minThickness_i != _segments.size(); 
    186     } 
    187  
    188     void removeAllSegmentsBelowThickness(float targetThickness) 
    189     { 
    190         // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl; 
    191         for(;;) 
    192         { 
    193             unsigned int minThickness_i = _segments.size(); 
    194             float minThickness = targetThickness; 
    195             if (!findMinThickness(minThickness_i,minThickness)) break; 
    196  
    197             // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl; 
    198             _segments.erase(_segments.begin()+minThickness_i); 
    199         } 
    200     } 
    201  
    202     bool findMaxThickness(unsigned int& maxThickness_i, float& maxThickness) 
    203     { 
    204         maxThickness_i = _segments.size(); 
    205         for(unsigned int i=0; i<_segments.size(); ++i) 
    206         { 
    207             float thickness = computeThickness(i); 
    208             if (thickness<0.0 && thickness >  maxThickness) 
    209             { 
    210                 maxThickness = thickness; 
    211                 maxThickness_i = i; 
    212             } 
    213         } 
    214  
    215         return maxThickness_i != _segments.size(); 
    216     } 
    217  
    218  
    219     void removeAllSegmentsAboveThickness(float targetThickness) 
    220     { 
    221         // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl; 
    222         for(;;) 
    223         { 
    224             unsigned int maxThickness_i = _segments.size(); 
    225             float maxThickness = targetThickness; 
    226             if (!findMaxThickness(maxThickness_i,maxThickness)) break; 
    227  
    228             // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl; 
    229             _segments.erase(_segments.begin()+maxThickness_i); 
    230         } 
    231     } 
    232  
    233     osg::Vec3 computeBisectorPoint(unsigned int i, float targetThickness) 
    234     { 
    235         Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ]; 
    236         Segment& seg_target = _segments[ (i) % _segments.size() ]; 
    237         osg::Vec3& a = (*_vertices)[seg_before.first]; 
    238         osg::Vec3& b = (*_vertices)[seg_before.second]; 
    239         osg::Vec3& c = (*_vertices)[seg_target.first]; 
    240         osg::Vec3& d = (*_vertices)[seg_target.second]; 
    241         osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d); 
    242         osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d); 
    243         osg::Vec3 ab_sidevector(b.y()-a.y(), a.x()-b.x(), 0.0); 
    244         ab_sidevector.normalize(); 
    245         float scale_factor = 1.0/ (bisector_abcd*ab_sidevector); 
    246         osg::Vec3 new_vertex = intersection_abcd + bisector_abcd*(scale_factor*targetThickness); 
    247  
    248         // OSG_NOTICE<<"bisector_abcd = "<<bisector_abcd<<", ab_sidevector="<<ab_sidevector<<", b-a="<<b-a<<", scale_factor="<<scale_factor<<std::endl; 
    249         return new_vertex; 
    250     } 
    251  
    252     void addBoundaryToGeometry(osg::Geometry* geometry, float targetThickness) 
    253     { 
    254         if (_segments.empty()) return; 
    255  
    256         if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array); 
    257         osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); 
    258  
    259         // allocate the primitive set to store the face geometry 
    260         osg::DrawElementsUShort* face = new osg::DrawElementsUShort(GL_POLYGON); 
    261         face->setName("face"); 
    262  
    263         // reserve enough space in the vertex array to accomodate the vertices associated with the segments 
    264         new_vertices->reserve(new_vertices->size() + _segments.size()+1 + _count); 
    265  
    266         // create vertices 
    267         unsigned int previous_second = _segments[0].second; 
    268         osg::Vec3 newPoint = computeBisectorPoint(0, targetThickness); 
    269         unsigned int first = new_vertices->size(); 
    270         new_vertices->push_back(newPoint); 
    271  
    272         if (_segments[0].first != _start) 
    273         { 
    274             //OSG_NOTICE<<"We have pruned from the start"<<std::endl; 
    275             for(unsigned int j=_start; j<=_segments[0].first;++j) 
    276             { 
    277                 face->push_back(first); 
    278             } 
    279         } 
    280         else 
    281         { 
    282             face->push_back(first); 
    283         } 
    284  
    285  
    286         for(unsigned int i=1; i<_segments.size(); ++i) 
    287         { 
    288             newPoint = computeBisectorPoint(i, targetThickness); 
    289             unsigned int vi = new_vertices->size(); 
    290             new_vertices->push_back(newPoint); 
    291  
    292             if (previous_second != _segments[i].first) 
    293             { 
    294                 //OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl; 
    295                 for(unsigned int j=previous_second; j<=_segments[i].first;++j) 
    296                 { 
    297                     face->push_back(vi); 
    298                 } 
    299             } 
    300             else 
    301             { 
    302                 face->push_back(vi); 
    303             } 
    304  
    305             previous_second = _segments[i].second; 
    306         } 
    307  
    308         // fill the end of the polygon with repititions of the first index in the polygon to ensure 
    309         // that the orignal and new boundary polygons have the same number and pairing of indices. 
    310         // This ensures that the bevel can be created coherently. 
    311         while(face->size() < _count) 
    312         { 
    313             face->push_back(first); 
    314         } 
    315  
    316         // add face primitive set for polygon 
    317         geometry->addPrimitiveSet(face); 
    318  
    319         osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP); 
    320         bevel->setName("bevel"); 
    321         bevel->reserve(_count*2); 
    322         for(unsigned int i=0; i<_count; ++i) 
    323         { 
    324             unsigned int vi = new_vertices->size(); 
    325             new_vertices->push_back((*_vertices)[_start+i]); 
    326             bevel->push_back(vi); 
    327             bevel->push_back((*face)[i]); 
    328         } 
    329         geometry->addPrimitiveSet(bevel); 
    330     } 
    331  
    332 }; 
    333  
    334 osg::Geometry* getGeometryComponent(osg::Geometry* geometry, bool bevel) 
    335 { 
    336     osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); 
    337     if (!vertices) return 0; 
    338  
    339     osg::Geometry* new_geometry = new osg::Geometry; 
    340     osg::Vec3Array* new_vertices = new osg::Vec3Array(*vertices); 
    341     new_geometry->setVertexArray(new_vertices); 
    342  
    343     for(unsigned int i=0; i<geometry->getNumPrimitiveSets(); ++i) 
    344     { 
    345         osg::PrimitiveSet* primitiveSet = geometry->getPrimitiveSet(i); 
    346         if (primitiveSet->getName()=="bevel") 
    347         { 
    348             if (bevel) new_geometry->addPrimitiveSet(primitiveSet); 
    349         } 
    350         else 
    351         { 
    352             if (!bevel) new_geometry->addPrimitiveSet(primitiveSet); 
    353         } 
    354     } 
    355  
    356     osg::Vec4Array* new_colours = new osg::Vec4Array; 
    357     new_colours->push_back(bevel ? osg::Vec4(1.0,1.0,0.0,1.0) : osg::Vec4(1.0,0.0,0.0,1.0)); 
    358     new_geometry->setColorArray(new_colours); 
    359     new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL); 
    360  
    361     if (!bevel) 
    362     { 
    363         osg::Vec3Array* normals = new osg::Vec3Array; 
    364         normals->push_back(osg::Vec3(0.0,0.0,1.0)); 
    365         new_geometry->setNormalArray(normals); 
    366         new_geometry->setNormalBinding(osg::Geometry::BIND_OVERALL); 
    367     } 
    368  
    369     return new_geometry; 
    370 } 
    371  
    372 osg::Geometry* computeBevelGeometry(osg::Geometry* geometry, osgText::BevelProfile& profile, float width) 
    373 { 
    374     if (!geometry) return 0; 
    375  
    376     osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); 
    377     if (!orig_vertices) return 0; 
    378  
    379     if (geometry->getNumPrimitiveSets()==0) return 0; 
    380  
    381     osg::Geometry* new_geometry = new osg::Geometry; 
    382  
    383     osg::Vec3Array* new_vertices = new osg::Vec3Array; 
    384     new_geometry->setVertexArray(new_vertices); 
    385  
    386     osg::Vec3 forward(0.0f, 0.0f, -width); 
    387  
    388     for(unsigned int prim_i=0; prim_i<geometry->getNumPrimitiveSets(); ++prim_i) 
    389     { 
    390         osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(geometry->getPrimitiveSet(prim_i)); 
    391         if (!bevel) continue; 
    392  
    393         unsigned int no_vertices_on_boundary = bevel->size()/2; 
    394  
    395         osgText::BevelProfile::Vertices& profileVertices = profile.getVertices(); 
    396         unsigned int no_vertices_on_bevel = profileVertices.size(); 
    397  
    398         unsigned int start = new_vertices->size(); 
    399  
    400         // populate vertices 
    401         for(unsigned int i=0; i<bevel->size()-1;) 
    402         { 
    403             osg::Vec3& top_vertex = (*orig_vertices)[ (*bevel)[i++] ]; 
    404             osg::Vec3& base_vertex = (*orig_vertices)[ (*bevel)[i++] ]; 
    405             osg::Vec3 up = top_vertex-base_vertex; 
    406             for(unsigned int j=0; j<no_vertices_on_bevel; ++j) 
    407             { 
    408                 osg::Vec2& pv = profileVertices[j]; 
    409                 osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) ); 
    410                 new_vertices->push_back(pos); 
    411             } 
    412         } 
    413  
    414         osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES); 
    415         for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i) 
    416         { 
    417             for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j) 
    418             { 
    419                 unsigned int base = start + i*no_vertices_on_bevel + j; 
    420                 unsigned int next = base + no_vertices_on_bevel; 
    421  
    422                 elements->push_back(base); 
    423                 elements->push_back(next); 
    424                 elements->push_back(base+1); 
    425  
    426                 elements->push_back(base+1); 
    427                 elements->push_back(next); 
    428                 elements->push_back(next+1); 
    429             } 
    430         } 
    431  
    432         new_geometry->addPrimitiveSet(elements); 
    433     } 
    434  
    435     return new_geometry; 
    436 } 
    437  
    438 struct CollectTriangleIndicesFunctor 
    439 { 
    440     CollectTriangleIndicesFunctor() {} 
    441  
    442     typedef std::vector<unsigned int> Indices; 
    443     Indices _indices; 
    444  
    445     void operator() (unsigned int p1, unsigned int p2, unsigned int p3) 
    446     { 
    447         if (p1==p2 || p2==p3 || p1==p3) 
    448         { 
    449             return; 
    450         } 
    451  
    452         _indices.push_back(p1); 
    453         _indices.push_back(p3); 
    454         _indices.push_back(p2); 
    455  
    456     } 
    457 }; 
    458  
    459 osg::Geometry* computeFrontAndBackGeometry(osg::Geometry* geometry, float width) 
    460 { 
    461     if (!geometry) return 0; 
    462  
    463     osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); 
    464     if (!orig_vertices) return 0; 
    465  
    466     if (geometry->getNumPrimitiveSets()==0) return 0; 
    467  
    468     osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif; 
    469     geometry->accept(ctif); 
    470     CollectTriangleIndicesFunctor::Indices& face = ctif._indices; 
    471  
    472     osg::Geometry* new_geometry = new osg::Geometry; 
    473  
    474     osg::Vec3Array* new_vertices = new osg::Vec3Array; 
    475     new_geometry->setVertexArray(new_vertices); 
    476  
    477     osg::Vec3 forward(0.0f, 0.0f, -width); 
    478  
    479     // front face 
    480     osg::DrawElementsUShort* front_face = new osg::DrawElementsUShort(GL_TRIANGLES); 
    481     new_geometry->addPrimitiveSet(front_face); 
    482     for(unsigned int i=0; i<face.size();++i) 
    483     { 
    484         osg::Vec3& vertex = (*orig_vertices)[ face[i] ]; 
    485         front_face->push_back(new_vertices->size()); 
    486         new_vertices->push_back(vertex); 
    487     } 
    488  
    489     // back face 
    490     osg::DrawElementsUShort* back_face = new osg::DrawElementsUShort(GL_TRIANGLES); 
    491     new_geometry->addPrimitiveSet(back_face); 
    492     for(unsigned int i=0; i<face.size();++i) 
    493     { 
    494         osg::Vec3 vertex = (*orig_vertices)[ face[face.size()-i-1] ] + forward; 
    495         back_face->push_back(new_vertices->size()); 
    496         new_vertices->push_back(vertex); 
    497     } 
    498  
    499     return new_geometry; 
    500 } 
    501  
    502  
    503 osg::Geometry* createShell(osg::Geometry* geometry, float distance) 
    504 { 
    505     if (!geometry) return 0; 
    506  
    507     osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); 
    508     if (!orig_vertices) return 0; 
    509  
    510     osg::Vec3Array* orig_normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray()); 
    511     if (!orig_normals) return 0; 
    512  
    513     if (orig_vertices->size() != orig_normals->size()) return 0; 
    514  
    515     osg::Geometry* new_geometry = new osg::Geometry; 
    516     osg::Vec3Array* new_vertices = new osg::Vec3Array(orig_vertices->size()); 
    517     for(unsigned int i=0; i<orig_vertices->size(); ++i) 
    518     { 
    519         (*new_vertices)[i] = (*orig_vertices)[i] + (*orig_normals)[i]*distance; 
    520     } 
    521  
    522     new_geometry->setVertexArray(new_vertices); 
    523  
    524     osg::Vec4Array* new_colours = new osg::Vec4Array; 
    525     new_colours->push_back(osg::Vec4(1.0,1.0,1.0,0.2)); 
    526     new_geometry->setColorArray(new_colours); 
    527     new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL); 
    528  
    529     osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif; 
    530     geometry->accept(ctif); 
    531  
    532     // front face 
    533     osg::DrawElementsUInt* shell = new osg::DrawElementsUInt(GL_TRIANGLES); 
    534     new_geometry->addPrimitiveSet(shell); 
    535     CollectTriangleIndicesFunctor::Indices& face = ctif._indices; 
    536     for(unsigned int i=0; i<face.size();++i) 
    537     { 
    538         shell->push_back(face[i]); 
    539     } 
    540  
    541     osg::StateSet* stateset = new_geometry->getOrCreateStateSet(); 
    542     stateset->setMode(GL_BLEND, osg::StateAttribute::ON); 
    543     stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); 
    544     stateset->setAttributeAndModes(new osg::CullFace, osg::StateAttribute::ON); 
    545     stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); 
    546     return new_geometry; 
    547 } 
    548  
    549  
    550 osg::Geometry* computeThickness(osg::Geometry* orig_geometry, float thickness) 
    551 { 
    552     // OSG_NOTICE<<"computeThickness("<<orig_geometry<<")"<<std::endl; 
    553     osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(orig_geometry->getVertexArray()); 
    554     osg::Geometry::PrimitiveSetList& orig_primitives = orig_geometry->getPrimitiveSetList(); 
    555  
    556     osg::Geometry* new_geometry = new osg::Geometry; 
    557  
    558     for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin(); 
    559         itr != orig_primitives.end(); 
    560         ++itr) 
    561     { 
    562         osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get()); 
    563         if (drawArray && drawArray->getMode()==GL_POLYGON) 
    564         { 
    565             Boundary boundary(orig_vertices, drawArray->getFirst(), drawArray->getCount()); 
    566             if (thickness>0.0f) boundary.removeAllSegmentsBelowThickness(thickness); 
    567             else if (thickness<0.0f) boundary.removeAllSegmentsAboveThickness(thickness); 
    568             boundary.addBoundaryToGeometry(new_geometry, thickness); 
    569         } 
    570     } 
    571     return new_geometry; 
    572 } 
    57338 
    57439int main(int argc, char** argv) 
     
    62691    while(arguments.read("--flat",ratio)) { profile.flatBevel(ratio); } 
    62792 
     93    bool outline = false; 
     94    while(arguments.read("--outline")) { outline = true; } 
     95    while(arguments.read("--no-outline")) { outline = false; } 
     96 
     97    bool smooth = true; 
     98    while(arguments.read("--flat")) { smooth = false; } 
     99    while(arguments.read("--smooth")) { smooth = false; } 
     100 
     101    unsigned int numSamples = 10; 
     102    while(arguments.read("--samples", numSamples)) {} 
     103    font->setNumberCurveSamples(numSamples); 
     104 
    628105    profile.print(std::cout); 
    629106 
     
    631108    osg::ref_ptr<osg::Group> group = new osg::Group; 
    632109    osg::Vec3 position; 
    633  
    634  
    635110 
    636111    for(unsigned int i=0; i<word.size(); ++i) 
     
    647122        osg::ref_ptr<osg::Geode> geode = new osg::Geode; 
    648123 
    649 #if 1 
    650124        osg::ref_ptr<osg::Geometry> glyphGeometry = osgText::computeGlyphGeometry(glyph.get(), thickness, width); 
    651125        osg::ref_ptr<osg::Geometry> textGeometry = osgText::computeTextGeometry(glyphGeometry.get(), profile, width); 
    652         osg::ref_ptr<osg::Geometry> shellGeometry = osgText::computeShellGeometry(glyphGeometry.get(), profile, width); 
     126        osg::ref_ptr<osg::Geometry> shellGeometry = outline ? osgText::computeShellGeometry(glyphGeometry.get(), profile, width) : 0; 
    653127        if (textGeometry.valid()) geode->addDrawable(textGeometry.get()); 
    654128        if (shellGeometry.valid()) geode->addDrawable(shellGeometry.get()); 
    655129 
    656130        // create the normals 
    657         if (true) 
     131        if (smooth && textGeometry.valid()) 
    658132        { 
    659             osgUtil::SmoothingVisitor smoother; 
    660             smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle)); 
    661             geode->accept(smoother); 
     133            osgUtil::SmoothingVisitor::smooth(*textGeometry, osg::DegreesToRadians(creaseAngle)); 
    662134        } 
    663 #else 
    664         osg::Vec3Array* vertices = glyph->getRawVertexArray(); 
    665         osg::Geometry::PrimitiveSetList& primitives = glyph->getRawFacePrimitiveSetList(); 
    666  
    667         osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry; 
    668         geometry->setVertexArray(vertices); 
    669         geometry->setPrimitiveSetList(primitives); 
    670         osg::Vec4Array* colours = new osg::Vec4Array; 
    671         colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0)); 
    672         geometry->setColorArray(colours); 
    673         geometry->setColorBinding(osg::Geometry::BIND_OVERALL); 
    674  
    675         osg::ref_ptr<osg::Geometry> face_and_bevel = computeThickness(geometry, thickness); 
    676  
    677         osg::ref_ptr<osg::Geometry> face = getGeometryComponent(face_and_bevel, false); 
    678  
    679         if (face.valid()) 
    680         { 
    681             osgUtil::Tessellator ts; 
    682             ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE); 
    683             ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY); 
    684             ts.retessellatePolygons(*face); 
    685  
    686             osg::ref_ptr<osg::Geometry> faces = computeFrontAndBackGeometry(face.get(), width); 
    687             if (faces.valid()) geode->addDrawable(faces.get()); 
    688         } 
    689  
    690         osg::ref_ptr<osg::Geometry> bevel_strip = getGeometryComponent(face_and_bevel, true); 
    691         osg::ref_ptr<osg::Geometry> bevel = computeBevelGeometry(bevel_strip, profile, width); 
    692  
    693         if (bevel.valid()) 
    694         { 
    695             geode->addDrawable(bevel.get()); 
    696         } 
    697  
    698         // create the normals 
    699         { 
    700             osgUtil::SmoothingVisitor smoother; 
    701             geode->accept(smoother); 
    702         } 
    703  
    704         osg::ref_ptr<osg::Geometry> shell = createShell(bevel.get(), width); 
    705  
    706         { 
    707             osgUtil::SmoothingVisitor smoother; 
    708             smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle)); 
    709             geode->accept(smoother); 
    710         } 
    711  
    712         if (shell.valid()) 
    713         { 
    714             geode->addDrawable(shell.get()); 
    715         } 
    716 #endif 
    717135 
    718136        transform->addChild(geode.get()); 
     
    727145    viewer.setSceneData(group.get()); 
    728146    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); 
     147    viewer.addEventHandler(new osgViewer::StatsHandler); 
    729148    return viewer.run(); 
    730149}