root/OpenSceneGraph/trunk/examples/osgtext3D/osgtext3D.cpp @ 11721

Revision 11721, 23.4 kB (checked in by robert, 4 years ago)

Implemented generation of front, back and bevel geometries to complete the 3d glyphs.

Line 
1/* OpenSceneGraph example, osgtext.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osg/ArgumentParser>
20#include <osg/Geode>
21#include <osg/Geometry>
22#include <osg/TriangleIndexFunctor>
23#include <osg/PositionAttitudeTransform>
24#include <osgUtil/SmoothingVisitor>
25#include <osgText/Font3D>
26#include <osgDB/WriteFile>
27#include <osgGA/StateSetManipulator>
28#include <osgUtil/Tessellator>
29#include <osgViewer/Viewer>
30#include <osgViewer/ViewerEventHandlers>
31#include <osg/io_utils>
32
33extern int main_orig(int, char**);
34extern int main_test(int, char**);
35
36
37class BevelProfile
38{
39    public:
40
41        typedef std::vector<osg::Vec2> Vertices;
42
43        BevelProfile()
44        {
45            flatBevel();
46        }
47
48        void flatBevel(float width=0.25f)
49        {
50            _vertices.clear();
51
52            if (width>0.5f) width = 0.5f;
53
54            _vertices.push_back(osg::Vec2(0.0f,0.0f));
55
56            _vertices.push_back(osg::Vec2(width,1.0f));
57
58            if (width<0.5f) _vertices.push_back(osg::Vec2(1-width,1.0f));
59
60            _vertices.push_back(osg::Vec2(1.0f,0.0f));
61        }
62
63        void roundedBevel(float width=0.5f, unsigned int numSteps=10)
64        {
65            _vertices.clear();
66
67            if (width>0.5f) width = 0.5f;
68
69            unsigned int i = 0;
70            for(; i<=numSteps; ++i)
71            {
72                float angle = float(osg::PI)*0.5f*(float(i)/float(numSteps));
73                _vertices.push_back( osg::Vec2((1.0f-cosf(angle))*width, sinf(angle)) );
74            }
75
76            // start the second half one into the curve if the width is half way across
77            i = width<0.5f ? 0 : 1;
78            for(; i<=numSteps; ++i)
79            {
80                float angle = float(osg::PI)*0.5f*(float(numSteps-i)/float(numSteps));
81                _vertices.push_back( osg::Vec2(1.0-(1.0f-cosf(angle))*width, sin(angle)) );
82            }
83        }
84
85        void print(std::ostream& fout)
86        {
87            OSG_NOTICE<<"print bevel"<<std::endl;
88            for(Vertices::iterator itr = _vertices.begin();
89                itr != _vertices.end();
90                ++itr)
91            {
92                OSG_NOTICE<<"  "<<*itr<<std::endl;
93            }
94        }
95
96        Vertices& getVertices() { return _vertices; }
97
98    protected:
99
100        Vertices _vertices;
101};
102
103class Boundary
104{
105public:
106
107    typedef std::pair<unsigned int, unsigned int> Segment;
108    typedef std::vector<Segment>  Segments;
109    osg::ref_ptr<osg::Vec3Array> _vertices;
110    unsigned int _start;
111    unsigned int _count;
112    Segments _segments;
113
114    Boundary(osg::Vec3Array* vertices, unsigned int start, unsigned int count)
115    {
116        _vertices = vertices;
117        _start = start;
118        _count = count;
119
120        if ((*_vertices)[start]==(*_vertices)[start+count-1])
121        {
122            // OSG_NOTICE<<"Boundary is a line loop"<<std::endl;
123        }
124        else
125        {
126            OSG_NOTICE<<"Boundary is not a line loop"<<std::endl;
127        }
128
129        _segments.reserve(count-1);
130        for(unsigned int i=start; i<start+count-2; ++i)
131        {
132            _segments.push_back(Segment(i,i+1));
133        }
134        _segments.push_back(Segment(start+count-2,start));
135
136    }
137
138    osg::Vec3 computeRayIntersectionPoint(const osg::Vec3& a, const osg::Vec3& an, const osg::Vec3& c, const osg::Vec3& cn)
139    {
140        float denominator = ( cn.x() * an.y() - cn.y() * an.x());
141        if (denominator==0.0f)
142        {
143            //OSG_NOTICE<<"computeRayIntersectionPoint()<<denominator==0.0"<<std::endl;
144            // line segments must be parallel.
145            return (a+c)*0.5f;
146        }
147
148        float t = ((a.x()-c.x())*an.y() - (a.y()-c.y())*an.x()) / denominator;
149        return c + cn*t;
150    }
151
152    osg::Vec3 computeIntersectionPoint(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
153    {
154        return computeRayIntersectionPoint(a, b-a, c, d-c);
155    }
156
157    osg::Vec3 computeBisectorNormal(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
158    {
159        osg::Vec2 ab(a.x()-b.x(), a.y()-b.y());
160        osg::Vec2 dc(d.x()-c.x(), d.y()-c.y());
161        /*float length_ab =*/ ab.normalize();
162        /*float length_dc =*/ dc.normalize();
163
164        float e = dc.y() - ab.y();
165        float f = ab.x() - dc.x();
166        float denominator = sqrtf(e*e + f*f);
167        float nx = e / denominator;
168        float ny = f / denominator;
169        if (( ab.x()*ny - ab.y()*nx) > 0.0f)
170        {
171            // OSG_NOTICE<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" no need to swap"<<std::endl;
172            return osg::Vec3(nx,ny,0.0f);
173        }
174        else
175        {
176            OSG_NOTICE<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" need to swap!!!"<<std::endl;
177            return osg::Vec3(-nx,-ny,0.0f);
178        }
179    }
180
181    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)
182    {
183        osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
184        osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
185        osg::Vec3 intersection_cdef = computeIntersectionPoint(c,d,e,f);
186        osg::Vec3 bisector_cdef = computeBisectorNormal(c,d,e,f);
187        if (bisector_abcd==bisector_cdef)
188        {
189            //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
190            //OSG_NOTICE<<"   bisectors parallel, thickness = "<<FLT_MAX<<std::endl;
191            return FLT_MAX;
192        }
193
194        osg::Vec3 bisector_intersection = computeRayIntersectionPoint(intersection_abcd,bisector_abcd, intersection_cdef, bisector_cdef);
195        osg::Vec3 normal(d.y()-c.y(), c.x()-d.x(), 0.0);
196        float cd_length = normal.normalize();
197        if (cd_length==0)
198        {
199            //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
200            //OSG_NOTICE<<"   segment length==0, thickness = "<<FLT_MAX<<std::endl;
201            return FLT_MAX;
202        }
203
204        float thickness = (bisector_intersection - c) * normal;
205    #if 0
206        OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
207        OSG_NOTICE<<"   bisector_abcd = "<<bisector_abcd<<", bisector_cdef="<<bisector_cdef<<std::endl;
208        OSG_NOTICE<<"   bisector_intersection = "<<bisector_intersection<<", thickness = "<<thickness<<std::endl;
209    #endif
210        return thickness;
211    }
212
213
214    float computeThickness(unsigned int i)
215    {
216        Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
217        Segment& seg_target = _segments[ (i) % _segments.size() ];
218        Segment& seg_after =  _segments[ (i+1) % _segments.size() ];
219        return computeBisectorIntersectorThickness(
220            (*_vertices)[seg_before.first], (*_vertices)[seg_before.second],
221            (*_vertices)[seg_target.first], (*_vertices)[seg_target.second],
222            (*_vertices)[seg_after.first], (*_vertices)[seg_after.second]);
223    }
224
225    void computeAllThickness()
226    {
227        for(unsigned int i=0; i<_segments.size(); ++i)
228        {
229            computeThickness(i);
230        }
231    }
232
233
234    bool findMinThickness(unsigned int& minThickness_i, float& minThickness)
235    {
236        minThickness_i = _segments.size();
237        for(unsigned int i=0; i<_segments.size(); ++i)
238        {
239            float thickness = computeThickness(i);
240            if (thickness>0.0 && thickness <  minThickness)
241            {
242                minThickness = thickness;
243                minThickness_i = i;
244            }
245        }
246
247        return minThickness_i != _segments.size();
248    }
249
250    void removeAllSegmentsBelowThickness(float targetThickness)
251    {
252        // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
253        for(;;)
254        {
255            unsigned int minThickness_i = _segments.size();
256            float minThickness = targetThickness;
257            if (!findMinThickness(minThickness_i,minThickness)) break;
258
259            // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
260            _segments.erase(_segments.begin()+minThickness_i);
261        }
262    }
263
264    osg::Vec3 computeBisectorPoint(unsigned int i, float targetThickness)
265    {
266        Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
267        Segment& seg_target = _segments[ (i) % _segments.size() ];
268        osg::Vec3& a = (*_vertices)[seg_before.first];
269        osg::Vec3& b = (*_vertices)[seg_before.second];
270        osg::Vec3& c = (*_vertices)[seg_target.first];
271        osg::Vec3& d = (*_vertices)[seg_target.second];
272        osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
273        osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
274        osg::Vec3 ab_sidevector(b.y()-a.y(), a.x()-b.x(), 0.0);
275        ab_sidevector.normalize();
276        float scale_factor = 1.0/ (bisector_abcd*ab_sidevector);
277        osg::Vec3 new_vertex = intersection_abcd + bisector_abcd*(scale_factor*targetThickness);
278
279        // OSG_NOTICE<<"bisector_abcd = "<<bisector_abcd<<", ab_sidevector="<<ab_sidevector<<", b-a="<<b-a<<", scale_factor="<<scale_factor<<std::endl;
280        return new_vertex;
281    }
282
283    void addBoundaryToGeometry(osg::Geometry* geometry, float targetThickness)
284    {
285        if (_segments.empty()) return;
286
287        if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array);
288        osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
289
290        // allocate the primitive set to store the face geometry
291        osg::DrawElementsUShort* face = new osg::DrawElementsUShort(GL_POLYGON);
292        face->setName("face");
293
294        // reserve enough space in the vertex array to accomodate the vertices associated with the segments
295        new_vertices->reserve(new_vertices->size() + _segments.size()+1 + _count);
296
297        // create vertices
298        unsigned int previous_second = _segments[0].second;
299        osg::Vec3 newPoint = computeBisectorPoint(0, targetThickness);
300        unsigned int first = new_vertices->size();
301        new_vertices->push_back(newPoint);
302
303        if (_segments[0].first != _start)
304        {
305            //OSG_NOTICE<<"We have pruned from the start"<<std::endl;
306            for(unsigned int j=_start; j<=_segments[0].first;++j)
307            {
308                face->push_back(first);
309            }
310        }
311        else
312        {
313            face->push_back(first);
314        }
315
316
317        for(unsigned int i=1; i<_segments.size(); ++i)
318        {
319            newPoint = computeBisectorPoint(i, targetThickness);
320            unsigned int vi = new_vertices->size();
321            new_vertices->push_back(newPoint);
322
323            if (previous_second != _segments[i].first)
324            {
325                //OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl;
326                for(unsigned int j=previous_second; j<=_segments[i].first;++j)
327                {
328                    face->push_back(vi);
329                }
330            }
331            else
332            {
333                face->push_back(vi);
334            }
335
336            previous_second = _segments[i].second;
337        }
338
339        // fill the end of the polygon with repititions of the first index in the polygon to ensure
340        // that the orignal and new boundary polygons have the same number and pairing of indices.
341        // This ensures that the bevel can be created coherently.
342        while(face->size() < _count)
343        {
344            face->push_back(first);
345        }
346
347        // add face primitive set for polygon
348        geometry->addPrimitiveSet(face);
349
350        osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
351        bevel->setName("bevel");
352        bevel->reserve(_count*2);
353        for(unsigned int i=0; i<_count; ++i)
354        {
355            unsigned int vi = new_vertices->size();
356            new_vertices->push_back((*_vertices)[_start+i]);
357            bevel->push_back(vi);
358            bevel->push_back((*face)[i]);
359        }
360        geometry->addPrimitiveSet(bevel);
361    }
362
363};
364
365osg::Geometry* getGeometryComponent(osg::Geometry* geometry, bool bevel)
366{
367    osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
368    if (!vertices) return 0;
369
370    osg::Geometry* new_geometry = new osg::Geometry;
371    osg::Vec3Array* new_vertices = new osg::Vec3Array(*vertices);
372    new_geometry->setVertexArray(new_vertices);
373
374    for(unsigned int i=0; i<geometry->getNumPrimitiveSets(); ++i)
375    {
376        osg::PrimitiveSet* primitiveSet = geometry->getPrimitiveSet(i);
377        if (primitiveSet->getName()=="bevel")
378        {
379            if (bevel) new_geometry->addPrimitiveSet(primitiveSet);
380        }
381        else
382        {
383            if (!bevel) new_geometry->addPrimitiveSet(primitiveSet);
384        }
385    }
386
387    osg::Vec4Array* new_colours = new osg::Vec4Array;
388    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));
389    new_geometry->setColorArray(new_colours);
390    new_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
391
392    if (!bevel)
393    {
394        osg::Vec3Array* normals = new osg::Vec3Array;
395        normals->push_back(osg::Vec3(0.0,0.0,1.0));
396        new_geometry->setNormalArray(normals);
397        new_geometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
398    }
399
400    return new_geometry;
401}
402
403osg::Geometry* computeBevelGeometry(osg::Geometry* geometry, BevelProfile& profile, float width)
404{
405    if (!geometry) return 0;
406
407    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
408    if (!orig_vertices) return 0;
409
410    if (geometry->getNumPrimitiveSets()==0) return 0;
411
412    osg::Geometry* new_geometry = new osg::Geometry;
413
414    osg::Vec3Array* new_vertices = new osg::Vec3Array;
415    new_geometry->setVertexArray(new_vertices);
416
417    osg::Vec3 forward(0.0f, 0.0f, -width);
418
419    for(unsigned int prim_i=0; prim_i<geometry->getNumPrimitiveSets(); ++prim_i)
420    {
421        osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(geometry->getPrimitiveSet(prim_i));
422        if (!bevel) continue;
423
424        unsigned int no_vertices_on_boundary = bevel->size()/2;
425
426        BevelProfile::Vertices& profileVertices = profile.getVertices();
427        unsigned int no_vertices_on_bevel = profileVertices.size();
428
429        unsigned int start = new_vertices->size();
430
431        // populate vertices
432        for(unsigned int i=0; i<bevel->size()-1;)
433        {
434            osg::Vec3& top_vertex = (*orig_vertices)[ (*bevel)[i++] ];
435            osg::Vec3& base_vertex = (*orig_vertices)[ (*bevel)[i++] ];
436            osg::Vec3 up = top_vertex-base_vertex;
437            for(unsigned int j=0; j<no_vertices_on_bevel; ++j)
438            {
439                osg::Vec2& pv = profileVertices[j];
440                osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
441                new_vertices->push_back(pos);
442            }
443        }
444
445        osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES);
446        for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i)
447        {
448            for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j)
449            {
450                unsigned int base = start + i*no_vertices_on_bevel + j;
451                unsigned int next = base + no_vertices_on_bevel;
452
453                elements->push_back(base);
454                elements->push_back(next);
455                elements->push_back(base+1);
456
457                elements->push_back(base+1);
458                elements->push_back(next);
459                elements->push_back(next+1);
460            }
461        }
462
463        new_geometry->addPrimitiveSet(elements);
464    }
465
466    return new_geometry;
467}
468
469struct CollectTriangleIndicesFunctor
470{
471    CollectTriangleIndicesFunctor() {}
472
473    typedef std::vector<unsigned int> Indices;
474    Indices _indices;
475
476    void operator() (unsigned int p1, unsigned int p2, unsigned int p3)
477    {
478        if (p1==p2 || p2==p3 || p1==p3)
479        {
480            return;
481        }
482
483        _indices.push_back(p1);
484        _indices.push_back(p3);
485        _indices.push_back(p2);
486
487    }
488};
489
490osg::Geometry* computeFrontAndBackGeometry(osg::Geometry* geometry, float width)
491{
492    if (!geometry) return 0;
493
494    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
495    if (!orig_vertices) return 0;
496
497    if (geometry->getNumPrimitiveSets()==0) return 0;
498
499    osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
500    geometry->accept(ctif);
501    CollectTriangleIndicesFunctor::Indices& face = ctif._indices;
502
503    osg::Geometry* new_geometry = new osg::Geometry;
504
505    osg::Vec3Array* new_vertices = new osg::Vec3Array;
506    new_geometry->setVertexArray(new_vertices);
507
508    osg::Vec3 forward(0.0f, 0.0f, -width);
509
510    // front face
511    osg::DrawElementsUShort* front_face = new osg::DrawElementsUShort(GL_TRIANGLES);
512    new_geometry->addPrimitiveSet(front_face);
513    for(unsigned int i=0; i<face.size();++i)
514    {
515        osg::Vec3& vertex = (*orig_vertices)[ face[i] ];
516        front_face->push_back(new_vertices->size());
517        new_vertices->push_back(vertex);
518    }
519
520    // back face
521    osg::DrawElementsUShort* back_face = new osg::DrawElementsUShort(GL_TRIANGLES);
522    new_geometry->addPrimitiveSet(back_face);
523    for(unsigned int i=0; i<face.size();++i)
524    {
525        osg::Vec3 vertex = (*orig_vertices)[ face[face.size()-i-1] ] + forward;
526        back_face->push_back(new_vertices->size());
527        new_vertices->push_back(vertex);
528    }
529
530    return new_geometry;
531}
532
533osg::Geometry* computeThickness(osg::Geometry* orig_geometry, float thickness)
534{
535    // OSG_NOTICE<<"computeThickness("<<orig_geometry<<")"<<std::endl;
536    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(orig_geometry->getVertexArray());
537    osg::Geometry::PrimitiveSetList& orig_primitives = orig_geometry->getPrimitiveSetList();
538
539    osg::Geometry* new_geometry = new osg::Geometry;
540
541    for(osg::Geometry::PrimitiveSetList::iterator itr = orig_primitives.begin();
542        itr != orig_primitives.end();
543        ++itr)
544    {
545        osg::DrawArrays* drawArray = dynamic_cast<osg::DrawArrays*>(itr->get());
546        if (drawArray && drawArray->getMode()==GL_POLYGON)
547        {
548            Boundary boundary(orig_vertices, drawArray->getFirst(), drawArray->getCount());
549            boundary.removeAllSegmentsBelowThickness(thickness);
550            boundary.addBoundaryToGeometry(new_geometry, thickness);
551        }
552    }
553    return new_geometry;
554}
555
556int main(int argc, char** argv)
557{
558    osg::ArgumentParser arguments(&argc, argv);
559
560    if (arguments.read("--test"))
561    {
562        return main_test(argc,argv);
563    }
564    else if (arguments.read("--original") || arguments.read("--orig"))
565    {
566        return main_orig(argc,argv);
567    }
568
569    std::string fontFile("arial.ttf");
570    while(arguments.read("-f",fontFile)) {}
571
572    std::string word("This is a simple test");
573
574    while(arguments.read("--ascii"))
575    {
576        word.clear();
577        for(unsigned int c=' '; c<=127;++c)
578        {
579            word.push_back(c);
580        }
581    }
582
583    while(arguments.read("-w",word)) {}
584
585    osg::ref_ptr<osgText::Font3D> font = osgText::readFont3DFile(fontFile);
586    if (!font) return 1;
587    OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
588
589    bool useTessellator = true;
590    while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
591    while(arguments.read("--no-tessellate")) { useTessellator = false; }
592
593    float thickness = 5.0;
594    while(arguments.read("--thickness",thickness)) {}
595
596    float width = 20.0;
597    while(arguments.read("--width",width)) {}
598
599    float creaseAngle = 10.0f;
600    while(arguments.read("--crease-angle",creaseAngle)) {}
601
602    OSG_NOTICE<<"creaseAngle="<<creaseAngle<<std::endl;
603
604    BevelProfile profile;
605    float ratio = 0.5;
606    while(arguments.read("--rounded",ratio)) { profile.roundedBevel(ratio); }
607    while(arguments.read("--flat",ratio)) { profile.flatBevel(ratio); }
608
609    profile.print(std::cout);
610
611
612    osg::ref_ptr<osg::Group> group = new osg::Group;
613    osg::Vec3 position;
614
615
616
617    for(unsigned int i=0; i<word.size(); ++i)
618    {
619        osg::ref_ptr<osgText::Font3D::Glyph3D> glyph = font->getGlyph(word[i]);
620        if (!glyph) return 1;
621
622        osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
623        transform->setPosition(position);
624        transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
625
626        position.x() += glyph->getHorizontalWidth();
627
628        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
629
630        osg::Vec3Array* vertices = glyph->getRawVertexArray();
631        osg::Geometry::PrimitiveSetList& primitives = glyph->getRawFacePrimitiveSetList();
632
633        osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
634        geometry->setVertexArray(vertices);
635        geometry->setPrimitiveSetList(primitives);
636        osg::Vec4Array* colours = new osg::Vec4Array;
637        colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0));
638        geometry->setColorArray(colours);
639        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
640
641        osg::ref_ptr<osg::Geometry> face_and_bevel = computeThickness(geometry, thickness);
642
643        osg::ref_ptr<osg::Geometry> face = getGeometryComponent(face_and_bevel, false);
644
645        if (face.valid())
646        {
647            osgUtil::Tessellator ts;
648            ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
649            ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
650            ts.retessellatePolygons(*face);
651
652            osg::ref_ptr<osg::Geometry> faces = computeFrontAndBackGeometry(face.get(), width);
653            if (faces.valid()) geode->addDrawable(faces.get());
654        }
655
656        osg::ref_ptr<osg::Geometry> bevel_strip = getGeometryComponent(face_and_bevel, true);
657        osg::ref_ptr<osg::Geometry> bevel = computeBevelGeometry(bevel_strip, profile, width);
658
659        if (bevel.valid())
660        {
661            geode->addDrawable(bevel.get());
662        }
663
664        osgUtil::SmoothingVisitor smoother;
665        smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle));
666        geode->accept(smoother);
667
668        transform->addChild(geode.get());
669
670        group->addChild(transform.get());
671    }
672
673    std::string filename;
674    if (arguments.read("-o", filename)) osgDB::writeNodeFile(*group, filename);
675
676    osgViewer::Viewer viewer(arguments);
677    viewer.setSceneData(group.get());
678    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
679    return viewer.run();
680}
Note: See TracBrowser for help on using the browser.