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

Revision 11725, 25.8 kB (checked in by robert, 4 years ago)

Implemented the shell geometry code

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/CullFace>
23#include <osg/TriangleIndexFunctor>
24#include <osg/PositionAttitudeTransform>
25#include <osgUtil/SmoothingVisitor>
26#include <osgText/Font3D>
27#include <osgDB/WriteFile>
28#include <osgGA/StateSetManipulator>
29#include <osgUtil/Tessellator>
30#include <osgViewer/Viewer>
31#include <osgViewer/ViewerEventHandlers>
32#include <osg/io_utils>
33
34#include "GlyphGeometry.h"
35
36extern int main_orig(int, char**);
37extern int main_test(int, char**);
38
39
40
41class Boundary
42{
43public:
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
334osg::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
372osg::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
438struct 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
459osg::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
503osg::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
550osg::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}
573
574int main(int argc, char** argv)
575{
576    osg::ArgumentParser arguments(&argc, argv);
577
578    if (arguments.read("--test"))
579    {
580        return main_test(argc,argv);
581    }
582    else if (arguments.read("--original") || arguments.read("--orig"))
583    {
584        return main_orig(argc,argv);
585    }
586
587    std::string fontFile("arial.ttf");
588    while(arguments.read("-f",fontFile)) {}
589
590    std::string word("This is a simple test");
591
592    while(arguments.read("--ascii"))
593    {
594        word.clear();
595        for(unsigned int c=' '; c<=127;++c)
596        {
597            word.push_back(c);
598        }
599    }
600
601    while(arguments.read("-w",word)) {}
602
603    osg::ref_ptr<osgText::Font3D> font = osgText::readFont3DFile(fontFile);
604    if (!font) return 1;
605    OSG_NOTICE<<"Read font "<<fontFile<<" font="<<font.get()<<std::endl;
606
607    bool useTessellator = true;
608    while(arguments.read("-t") || arguments.read("--tessellate")) { useTessellator = true; }
609    while(arguments.read("--no-tessellate")) { useTessellator = false; }
610
611    float thickness = 5.0;
612    while(arguments.read("--thickness",thickness)) {}
613
614    float width = 20.0;
615    while(arguments.read("--width",width)) {}
616
617    float creaseAngle = 30.0f;
618    while(arguments.read("--crease-angle",creaseAngle)) {}
619
620    OSG_NOTICE<<"creaseAngle="<<creaseAngle<<std::endl;
621
622    osgText::BevelProfile profile;
623    float ratio = 0.5;
624    while(arguments.read("--rounded",ratio)) { profile.roundedBevel(ratio); }
625    while(arguments.read("--rounded2",ratio)) { profile.roundedBevel2(ratio); }
626    while(arguments.read("--flat",ratio)) { profile.flatBevel(ratio); }
627
628    profile.print(std::cout);
629
630
631    osg::ref_ptr<osg::Group> group = new osg::Group;
632    osg::Vec3 position;
633
634
635
636    for(unsigned int i=0; i<word.size(); ++i)
637    {
638        osg::ref_ptr<osgText::Font3D::Glyph3D> glyph = font->getGlyph(word[i]);
639        if (!glyph) return 1;
640
641        osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
642        transform->setPosition(position);
643        transform->setAttitude(osg::Quat(osg::inDegrees(90.0),osg::Vec3d(1.0,0.0,0.0)));
644
645        position.x() += glyph->getHorizontalWidth();
646
647        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
648
649#if 1
650        osg::ref_ptr<osg::Geometry> glyphGeometry = osgText::computeGlyphGeometry(glyph.get(), thickness, width);
651        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);
653        if (textGeometry.valid()) geode->addDrawable(textGeometry.get());
654        if (shellGeometry.valid()) geode->addDrawable(shellGeometry.get());
655
656        // create the normals
657        if (true)
658        {
659            osgUtil::SmoothingVisitor smoother;
660            smoother.setCreaseAngle(osg::DegreesToRadians(creaseAngle));
661            geode->accept(smoother);
662        }
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
717
718        transform->addChild(geode.get());
719
720        group->addChild(transform.get());
721    }
722
723    std::string filename;
724    if (arguments.read("-o", filename)) osgDB::writeNodeFile(*group, filename);
725
726    osgViewer::Viewer viewer(arguments);
727    viewer.setSceneData(group.get());
728    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
729    return viewer.run();
730}
Note: See TracBrowser for help on using the browser.