root/OpenSceneGraph/trunk/src/osgText/GlyphGeometry.cpp @ 13041

Revision 13041, 39.1 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include "GlyphGeometry.h"
15
16#include <osg/io_utils>
17#include <osg/TriangleIndexFunctor>
18#include <osg/LineWidth>
19#include <osgUtil/Tessellator>
20#include <osg/CullFace>
21
22#include <limits.h>
23
24namespace osgText
25{
26
27/////////////////////////////////////////////////////////////////////////////////////////
28//
29// Boundary
30//
31class Boundary
32{
33public:
34
35    typedef std::pair<unsigned int, unsigned int> Segment;
36    typedef std::vector<Segment>  Segments;
37    osg::ref_ptr<const osg::Vec3Array> _vertices;
38    osg::ref_ptr<const osg::DrawElementsUShort> _elements;
39    Segments _segments;
40
41    Boundary(const osg::Vec3Array* vertices, const osg::PrimitiveSet* primitiveSet)
42    {
43        const osg::DrawArrays* drawArrays = dynamic_cast<const osg::DrawArrays*>(primitiveSet);
44        if (drawArrays)
45        {
46            set(vertices, drawArrays->getFirst(), drawArrays->getCount());
47        }
48        else
49        {
50            const osg::DrawElementsUShort* elements = dynamic_cast<const osg::DrawElementsUShort*>(primitiveSet);
51            if (elements) set(vertices, elements);
52        }
53    }
54
55    void set(const osg::Vec3Array* vertices, unsigned int start, unsigned int count)
56    {
57        osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::POLYGON);
58        for(unsigned int i=start; i<start+count; ++i)
59        {
60            elements->push_back(i);
61        }
62
63        set(vertices, elements);
64    }
65
66    void set(const osg::Vec3Array* vertices, const osg::DrawElementsUShort* elements)
67    {
68        _vertices = vertices;
69        _elements = elements;
70
71        _segments.clear();
72
73        if (elements->empty()) return;
74
75        _segments.reserve(elements->size()-1);
76        for(unsigned int i=0; i<elements->size()-1; ++i)
77        {
78            _segments.push_back(Segment((*elements)[i],(*elements)[i+1]));
79        }
80    }
81
82    osg::Vec3 computeRayIntersectionPoint(const osg::Vec3& a, const osg::Vec3& an, const osg::Vec3& c, const osg::Vec3& cn)
83    {
84        float denominator = ( cn.x() * an.y() - cn.y() * an.x());
85        if (denominator==0.0f)
86        {
87            //OSG_NOTICE<<"computeRayIntersectionPoint()<<denominator==0.0"<<std::endl;
88            // line segments must be parallel.
89            return (a+c)*0.5f;
90        }
91
92        float t = ((a.x()-c.x())*an.y() - (a.y()-c.y())*an.x()) / denominator;
93        return c + cn*t;
94    }
95
96    osg::Vec3 computeIntersectionPoint(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
97    {
98        return computeRayIntersectionPoint(a, b-a, c, d-c);
99    }
100
101    osg::Vec3 computeBisectorNormal(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c, const osg::Vec3& d)
102    {
103        osg::Vec2 ab(a.x()-b.x(), a.y()-b.y());
104        osg::Vec2 dc(d.x()-c.x(), d.y()-c.y());
105        /*float length_ab =*/ ab.normalize();
106        /*float length_dc =*/ dc.normalize();
107
108        float e = dc.y() - ab.y();
109        float f = ab.x() - dc.x();
110        float denominator = sqrtf(e*e + f*f);
111        float nx = e / denominator;
112        float ny = f / denominator;
113        if (( ab.x()*ny - ab.y()*nx) > 0.0f)
114        {
115            // OSG_NOTICE<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" no need to swap"<<std::endl;
116            return osg::Vec3(nx,ny,0.0f);
117        }
118        else
119        {
120            OSG_INFO<<"   computeBisectorNormal(a=["<<a<<"], b=["<<b<<"], c=["<<c<<"], d=["<<d<<"]), nx="<<nx<<", ny="<<ny<<", denominator="<<denominator<<" need to swap!!!"<<std::endl;
121            return osg::Vec3(-nx,-ny,0.0f);
122        }
123    }
124
125    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)
126    {
127        osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
128        osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
129        osg::Vec3 intersection_cdef = computeIntersectionPoint(c,d,e,f);
130        osg::Vec3 bisector_cdef = computeBisectorNormal(c,d,e,f);
131        if (bisector_abcd==bisector_cdef)
132        {
133            //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
134            //OSG_NOTICE<<"   bisectors parallel, thickness = "<<FLT_MAX<<std::endl;
135            return FLT_MAX;
136        }
137
138        osg::Vec3 bisector_intersection = computeRayIntersectionPoint(intersection_abcd,bisector_abcd, intersection_cdef, bisector_cdef);
139        osg::Vec3 normal(d.y()-c.y(), c.x()-d.x(), 0.0);
140        float cd_length = normal.normalize();
141        if (cd_length==0)
142        {
143            //OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
144            //OSG_NOTICE<<"   segment length==0, thickness = "<<FLT_MAX<<std::endl;
145            return FLT_MAX;
146        }
147
148        float thickness = (bisector_intersection - c) * normal;
149    #if 0
150        OSG_NOTICE<<"computeBisectorIntersector(["<<a<<"], ["<<b<<"], ["<<c<<"], ["<<d<<"], ["<<e<<"], ["<<f<<"[)"<<std::endl;
151        OSG_NOTICE<<"   bisector_abcd = "<<bisector_abcd<<", bisector_cdef="<<bisector_cdef<<std::endl;
152        OSG_NOTICE<<"   bisector_intersection = "<<bisector_intersection<<", thickness = "<<thickness<<std::endl;
153    #endif
154        return thickness;
155    }
156
157
158    float computeThickness(unsigned int i)
159    {
160        Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
161        Segment& seg_target = _segments[ (i) % _segments.size() ];
162        Segment& seg_after =  _segments[ (i+1) % _segments.size() ];
163        return computeBisectorIntersectorThickness(
164            (*_vertices)[seg_before.first], (*_vertices)[seg_before.second],
165            (*_vertices)[seg_target.first], (*_vertices)[seg_target.second],
166            (*_vertices)[seg_after.first], (*_vertices)[seg_after.second]);
167    }
168
169    void computeAllThickness()
170    {
171        for(unsigned int i=0; i<_segments.size(); ++i)
172        {
173            computeThickness(i);
174        }
175    }
176
177
178    bool findMinThickness(unsigned int& minThickness_i, float& minThickness)
179    {
180        minThickness_i = _segments.size();
181        for(unsigned int i=0; i<_segments.size(); ++i)
182        {
183            float thickness = computeThickness(i);
184            if (thickness>0.0 && thickness <  minThickness)
185            {
186                minThickness = thickness;
187                minThickness_i = i;
188            }
189        }
190
191        return minThickness_i != _segments.size();
192    }
193
194    void removeAllSegmentsBelowThickness(float targetThickness)
195    {
196        // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
197        for(;;)
198        {
199            unsigned int minThickness_i = _segments.size();
200            float minThickness = targetThickness;
201            if (!findMinThickness(minThickness_i,minThickness)) break;
202
203            // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
204            _segments.erase(_segments.begin()+minThickness_i);
205        }
206    }
207
208    bool findMaxThickness(unsigned int& maxThickness_i, float& maxThickness)
209    {
210        maxThickness_i = _segments.size();
211        for(unsigned int i=0; i<_segments.size(); ++i)
212        {
213            float thickness = computeThickness(i);
214            if (thickness<0.0 && thickness >  maxThickness)
215            {
216                maxThickness = thickness;
217                maxThickness_i = i;
218            }
219        }
220
221        return maxThickness_i != _segments.size();
222    }
223
224
225    void removeAllSegmentsAboveThickness(float targetThickness)
226    {
227        // OSG_NOTICE<<"removeAllSegmentsBelowThickness("<<targetThickness<<")"<<std::endl;
228        for(;;)
229        {
230            unsigned int maxThickness_i = _segments.size();
231            float maxThickness = targetThickness;
232            if (!findMaxThickness(maxThickness_i,maxThickness)) break;
233
234            // OSG_NOTICE<<"  removing segment _segments["<<minThickness_i<<"] ("<<_segments[minThickness_i].first<<", "<<_segments[minThickness_i].second<<" with thickness="<<minThickness<<" "<<std::endl;
235            _segments.erase(_segments.begin()+maxThickness_i);
236        }
237    }
238
239    osg::Vec3 computeBisectorPoint(unsigned int i, float targetThickness)
240    {
241        Segment& seg_before = _segments[ (i+_segments.size()-1) % _segments.size() ];
242        Segment& seg_target = _segments[ (i) % _segments.size() ];
243        const osg::Vec3& a = (*_vertices)[seg_before.first];
244        const osg::Vec3& b = (*_vertices)[seg_before.second];
245        const osg::Vec3& c = (*_vertices)[seg_target.first];
246        const osg::Vec3& d = (*_vertices)[seg_target.second];
247        osg::Vec3 intersection_abcd = computeIntersectionPoint(a,b,c,d);
248        osg::Vec3 bisector_abcd = computeBisectorNormal(a,b,c,d);
249        osg::Vec3 ab_sidevector(b.y()-a.y(), a.x()-b.x(), 0.0);
250        ab_sidevector.normalize();
251        float scale_factor = 1.0/ (bisector_abcd*ab_sidevector);
252        osg::Vec3 new_vertex = intersection_abcd + bisector_abcd*(scale_factor*targetThickness);
253
254        // OSG_NOTICE<<"bisector_abcd = "<<bisector_abcd<<", ab_sidevector="<<ab_sidevector<<", b-a="<<b-a<<", scale_factor="<<scale_factor<<std::endl;
255        return new_vertex;
256    }
257
258    void addBoundaryToGeometry(osg::Geometry* geometry, float targetThickness, bool requireFace)
259    {
260        if (_segments.empty()) return;
261
262        if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array);
263        osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
264
265        // allocate the primitive set to store the face geometry
266        osg::ref_ptr<osg::DrawElementsUShort> face = new osg::DrawElementsUShort(GL_POLYGON);
267        face->setName("face");
268
269        // reserve enough space in the vertex array to accomodate the vertices associated with the segments
270        new_vertices->reserve(new_vertices->size() + _segments.size()+1 + _elements->size());
271
272        // create vertices
273        unsigned int previous_second = _segments[0].second;
274        osg::Vec3 newPoint = computeBisectorPoint(0, targetThickness);
275        unsigned int first = new_vertices->size();
276        new_vertices->push_back(newPoint);
277
278        unsigned int start = (*_elements)[0];
279        unsigned int count = _elements->size();
280
281        if (_segments[0].first != start)
282        {
283            //OSG_NOTICE<<"We have pruned from the start"<<std::endl;
284            for(unsigned int j=start; j<=_segments[0].first;++j)
285            {
286                face->push_back(first);
287            }
288        }
289        else
290        {
291            face->push_back(first);
292        }
293
294
295        for(unsigned int i=1; i<_segments.size(); ++i)
296        {
297            newPoint = computeBisectorPoint(i, targetThickness);
298            unsigned int vi = new_vertices->size();
299            new_vertices->push_back(newPoint);
300
301            if (previous_second != _segments[i].first)
302            {
303                //OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl;
304                for(unsigned int j=previous_second; j<=_segments[i].first;++j)
305                {
306                    face->push_back(vi);
307                }
308            }
309            else
310            {
311                face->push_back(vi);
312            }
313
314            previous_second = _segments[i].second;
315        }
316
317        // fill the end of the polygon with repititions of the first index in the polygon to ensure
318        // that the orignal and new boundary polygons have the same number and pairing of indices.
319        // This ensures that the bevel can be created coherently.
320        while(face->size() < count)
321        {
322            face->push_back(first);
323        }
324
325
326        if (requireFace)
327        {
328            // add face primitive set for polygon
329            geometry->addPrimitiveSet(face.get());
330        }
331
332
333        osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
334        bevel->setName("bevel");
335        bevel->reserve(count*2);
336        for(unsigned int i=0; i<count; ++i)
337        {
338            unsigned int vi = new_vertices->size();
339            new_vertices->push_back((*_vertices)[(*_elements)[i]]);
340            bevel->push_back(vi);
341            bevel->push_back((*face)[i]);
342        }
343        geometry->addPrimitiveSet(bevel);
344    }
345
346    void newAddBoundaryToGeometry(osg::Geometry* geometry, float targetThickness, const std::string& faceName, const std::string& bevelName)
347    {
348        if (_segments.empty()) return;
349
350        unsigned int start = (*_elements)[0];
351        unsigned int count = _elements->size();
352
353        if (geometry->getVertexArray()==0) geometry->setVertexArray(new osg::Vec3Array(*_vertices));
354        osg::Vec3Array* new_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
355
356        // allocate the primitive set to store the face geometry
357        osg::ref_ptr<osg::DrawElementsUShort> face = new osg::DrawElementsUShort(GL_POLYGON);
358        face->setName(faceName);
359
360        // reserve enough space in the vertex array to accomodate the vertices associated with the segments
361        new_vertices->reserve(new_vertices->size() + _segments.size()+1 + count);
362
363        // create vertices
364        unsigned int previous_second = _segments[0].second;
365        osg::Vec3 newPoint = computeBisectorPoint(0, targetThickness);
366        unsigned int first = new_vertices->size();
367        new_vertices->push_back(newPoint);
368
369        if (_segments[0].first != start)
370        {
371            //OSG_NOTICE<<"We have pruned from the start"<<std::endl;
372            for(unsigned int j=start; j<=_segments[0].first;++j)
373            {
374                face->push_back(first);
375            }
376        }
377        else
378        {
379            face->push_back(first);
380        }
381
382
383        for(unsigned int i=1; i<_segments.size(); ++i)
384        {
385            newPoint = computeBisectorPoint(i, targetThickness);
386            unsigned int vi = new_vertices->size();
387            new_vertices->push_back(newPoint);
388
389            if (previous_second != _segments[i].first)
390            {
391                //OSG_NOTICE<<"Gap in boundary"<<previous_second<<" to "<<_segments[i].first<<std::endl;
392                for(unsigned int j=previous_second; j<=_segments[i].first;++j)
393                {
394                    face->push_back(vi);
395                }
396            }
397            else
398            {
399                face->push_back(vi);
400            }
401
402            previous_second = _segments[i].second;
403        }
404
405        // fill the end of the polygon with repititions of the first index in the polygon to ensure
406        // that the orignal and new boundary polygons have the same number and pairing of indices.
407        // This ensures that the bevel can be created coherently.
408        while(face->size() < count)
409        {
410            face->push_back(first);
411        }
412
413        if (!faceName.empty())
414        {
415            // add face primitive set for polygon
416            geometry->addPrimitiveSet(face.get());
417        }
418
419        osg::DrawElementsUShort* bevel = new osg::DrawElementsUShort(GL_QUAD_STRIP);
420        bevel->setName(bevelName);
421        bevel->reserve(count*2);
422        for(unsigned int i=0; i<count; ++i)
423        {
424            bevel->push_back((*_elements)[i]);
425            bevel->push_back((*face)[i]);
426        }
427        geometry->addPrimitiveSet(bevel);
428    }
429};
430
431
432/////////////////////////////////////////////////////////////////////////////////////////
433//
434// computeGlyphGeometry
435//
436struct CollectTriangleIndicesFunctor
437{
438    CollectTriangleIndicesFunctor() {}
439
440    typedef std::vector<unsigned int> Indices;
441    Indices _indices;
442
443    void operator() (unsigned int p1, unsigned int p2, unsigned int p3)
444    {
445        if (p1==p2 || p2==p3 || p1==p3)
446        {
447            return;
448        }
449
450        _indices.push_back(p1);
451        _indices.push_back(p3);
452        _indices.push_back(p2);
453
454    }
455};
456
457
458OSGTEXT_EXPORT osg::Geometry* computeGlyphGeometry(const osgText::Glyph3D* glyph, float bevelThickness, float shellThickness)
459{
460    const osg::Vec3Array* orig_vertices = glyph->getRawVertexArray();
461    const osg::Geometry::PrimitiveSetList& orig_primitives = glyph->getRawFacePrimitiveSetList();
462
463    osg::ref_ptr<osg::Geometry> new_geometry = new osg::Geometry;
464
465    for(osg::Geometry::PrimitiveSetList::const_iterator itr = orig_primitives.begin();
466        itr != orig_primitives.end();
467        ++itr)
468    {
469        if ((*itr)->getMode()==GL_POLYGON)
470        {
471            Boundary boundaryInner(orig_vertices, itr->get());
472            boundaryInner.removeAllSegmentsBelowThickness(bevelThickness);
473            boundaryInner.newAddBoundaryToGeometry(new_geometry.get(), bevelThickness, "face", "bevel");
474
475            Boundary boundaryOuter(orig_vertices, itr->get());
476            boundaryOuter.removeAllSegmentsAboveThickness(-shellThickness);
477            boundaryOuter.newAddBoundaryToGeometry(new_geometry.get(), -shellThickness, "", "shell");
478        }
479
480    }
481
482    osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(new_geometry->getVertexArray());
483
484    // need to tessellate the inner boundary
485    {
486        osg::ref_ptr<osg::Geometry> face_geometry = new osg::Geometry;
487        face_geometry->setVertexArray(vertices);
488
489        osg::CopyOp copyop(osg::CopyOp::DEEP_COPY_ALL);
490
491        osg::Geometry::PrimitiveSetList primitiveSets;
492
493        for(osg::Geometry::PrimitiveSetList::iterator itr = new_geometry->getPrimitiveSetList().begin();
494            itr != new_geometry->getPrimitiveSetList().end();
495            ++itr)
496        {
497            osg::PrimitiveSet* prim = itr->get();
498            if (prim->getName()=="face")  face_geometry->addPrimitiveSet(copyop(itr->get()));
499            else primitiveSets.push_back(prim);
500        }
501
502        osgUtil::Tessellator ts;
503        ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
504        ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
505        ts.retessellatePolygons(*face_geometry);
506
507        osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
508        face_geometry->accept(ctif);
509        CollectTriangleIndicesFunctor::Indices& indices = ctif._indices;
510
511        // remove the previous primitive sets
512        new_geometry->getPrimitiveSetList().clear();
513
514        // create a front face using triangle indices
515        osg::DrawElementsUShort* front_face = new osg::DrawElementsUShort(GL_TRIANGLES);
516        front_face->setName("face");
517        new_geometry->addPrimitiveSet(front_face);
518        for(unsigned int i=0; i<indices.size();++i)
519        {
520            front_face->push_back(indices[i]);
521        }
522
523        for(osg::Geometry::PrimitiveSetList::iterator itr = primitiveSets.begin();
524            itr != primitiveSets.end();
525            ++itr)
526        {
527            osg::PrimitiveSet* prim = itr->get();
528            if (prim->getName()!="face")  new_geometry->addPrimitiveSet(prim);
529        }
530    }
531
532    return new_geometry.release();
533}
534
535/////////////////////////////////////////////////////////////////////////////////////////
536//
537// computeTextGeometry
538//
539OSGTEXT_EXPORT osg::Geometry* computeTextGeometry(const osgText::Glyph3D* glyph, float width)
540{
541    const osg::Vec3Array* orig_vertices = glyph->getRawVertexArray();
542    const osg::Geometry::PrimitiveSetList& orig_primitives = glyph->getRawFacePrimitiveSetList();
543
544    osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
545    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array((*orig_vertices));
546
547    text_geometry->setVertexArray(vertices.get());
548    text_geometry->setPrimitiveSetList(orig_primitives);
549
550    osgUtil::Tessellator ts;
551    ts.setWindingType(osgUtil::Tessellator::TESS_WINDING_POSITIVE);
552    ts.setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
553    ts.retessellatePolygons(*text_geometry);
554
555    osg::TriangleIndexFunctor<CollectTriangleIndicesFunctor> ctif;
556    text_geometry->accept(ctif);
557    CollectTriangleIndicesFunctor::Indices& indices = ctif._indices;
558
559    // remove the previous primitive sets
560    text_geometry->getPrimitiveSetList().clear();
561
562    if (indices.empty()) return 0;
563
564
565    // create a front face using triangle indices
566    osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
567    frontFace->setName("front");
568    text_geometry->addPrimitiveSet(frontFace);
569    for(unsigned int i=0; i<indices.size();++i)
570    {
571        frontFace->push_back(indices[i]);
572    }
573
574    typedef std::vector<unsigned int> Indices;
575    const unsigned int NULL_VALUE = UINT_MAX;
576    Indices back_indices;
577    back_indices.resize(vertices->size(), NULL_VALUE);
578    osg::Vec3 forward(0,0,-width);
579
580    // build up the vertices primitives for the back face, and record the indices
581    // for later use, and to ensure sharing of vertices in the face primitive set
582    // the order of the triangle indices are flipped to make sure that the triangles are back face
583    osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
584    backFace->setName("back");
585    text_geometry->addPrimitiveSet(backFace);
586    for(unsigned int i=0; i<indices.size()-2;)
587    {
588        unsigned int p1 = indices[i++];
589        unsigned int p2 = indices[i++];
590        unsigned int p3 = indices[i++];
591        if (back_indices[p1]==NULL_VALUE)
592        {
593            back_indices[p1] = vertices->size();
594            vertices->push_back((*vertices)[p1]+forward);
595        }
596
597        if (back_indices[p2]==NULL_VALUE)
598        {
599            back_indices[p2] = vertices->size();
600            vertices->push_back((*vertices)[p2]+forward);
601        }
602
603        if (back_indices[p3]==NULL_VALUE)
604        {
605            back_indices[p3] = vertices->size();
606            vertices->push_back((*vertices)[p3]+forward);
607        }
608
609        backFace->push_back(back_indices[p1]);
610        backFace->push_back(back_indices[p3]);
611        backFace->push_back(back_indices[p2]);
612    }
613
614    unsigned int orig_size = orig_vertices->size();
615    Indices frontedge_indices, backedge_indices;
616    frontedge_indices.resize(orig_size, NULL_VALUE);
617    backedge_indices.resize(orig_size, NULL_VALUE);
618
619
620    for(osg::Geometry::PrimitiveSetList::const_iterator itr = orig_primitives.begin();
621        itr != orig_primitives.end();
622        ++itr)
623    {
624        osg::DrawElementsUShort* edging = new osg::DrawElementsUShort(osg::PrimitiveSet::QUAD_STRIP);
625        edging->setName("wall");
626        text_geometry->addPrimitiveSet(edging);
627
628        osg::DrawElementsUShort* elements = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
629        if (elements)
630        {
631            for(unsigned int i=0; i<elements->size(); ++i)
632            {
633                unsigned int ei = (*elements)[i];
634                if (frontedge_indices[ei]==NULL_VALUE)
635                {
636                    frontedge_indices[ei] = vertices->size();
637                    vertices->push_back((*orig_vertices)[ei]);
638                }
639                if (backedge_indices[ei]==NULL_VALUE)
640                {
641                    backedge_indices[ei] = vertices->size();
642                    vertices->push_back((*orig_vertices)[ei]+forward);
643                }
644
645                edging->push_back(backedge_indices[ei]);
646                edging->push_back(frontedge_indices[ei]);
647            }
648        }
649    }
650
651    return text_geometry.release();
652}
653
654/////////////////////////////////////////////////////////////////////////////////////////
655//
656// computeTextGeometry
657//
658OSGTEXT_EXPORT osg::Geometry* computeTextGeometry(osg::Geometry* glyphGeometry, const osgText::Bevel& profile, float width)
659{
660    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(glyphGeometry->getVertexArray());
661    if (!orig_vertices)
662    {
663        OSG_INFO<<"computeTextGeometry(..): No vertices on glyphGeometry."<<std::endl;
664        return 0;
665    }
666
667    osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
668    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
669    text_geometry->setVertexArray(vertices.get());
670
671    typedef std::vector<unsigned int> Indices;
672    const unsigned int NULL_VALUE = UINT_MAX;
673    Indices front_indices, back_indices;
674    front_indices.resize(orig_vertices->size(), NULL_VALUE);
675    back_indices.resize(orig_vertices->size(), NULL_VALUE);
676
677    osg::DrawElementsUShort* face = 0;
678    osg::Geometry::PrimitiveSetList bevelPrimitiveSets;
679    osg::Vec3 forward(0,0,-width);
680
681    // collect bevels and face primitive sets
682    for(osg::Geometry::PrimitiveSetList::iterator itr = glyphGeometry->getPrimitiveSetList().begin();
683        itr != glyphGeometry->getPrimitiveSetList().end();
684        ++itr)
685    {
686        osg::PrimitiveSet* prim = itr->get();
687        if (prim->getName()=="face") face = dynamic_cast<osg::DrawElementsUShort*>(prim);
688        else if (prim->getName()=="bevel") bevelPrimitiveSets.push_back(prim);
689    }
690
691    // if we don't have a face we can't create any 3d text
692    if (!face) return 0;
693
694    // face doesn't have enough vertices on it to represent a polygon.
695    if (face->size()<3)
696    {
697        OSG_NOTICE<<"Face does not have enough elements to be able to represent a polygon, face->size() = "<<face->size()<<std::endl;
698        return 0;
699    }
700
701    // build up the vertices primitives for the front face, and record the indices
702    // for later use, and to ensure sharing of vertices in the face primitive set
703    osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
704    frontFace->setName("front");
705    text_geometry->addPrimitiveSet(frontFace);
706    for(unsigned int i=0; i<face->size();)
707    {
708        unsigned int pi = (*face)[i++];
709        if (front_indices[pi]==NULL_VALUE)
710        {
711            front_indices[pi] = vertices->size();
712            vertices->push_back((*orig_vertices)[pi]);
713        }
714        frontFace->push_back(front_indices[pi]);
715    }
716
717
718    // build up the vertices primitives for the back face, and record the indices
719    // for later use, and to ensure sharing of vertices in the face primitive set
720    // the order of the triangle indices are flipped to make sure that the triangles are back face
721    osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
722    backFace->setName("back");
723    text_geometry->addPrimitiveSet(backFace);
724    for(unsigned int i=0; i<face->size()-2;)
725    {
726        unsigned int p1 = (*face)[i++];
727        unsigned int p2 = (*face)[i++];
728        unsigned int p3 = (*face)[i++];
729        if (back_indices[p1]==NULL_VALUE)
730        {
731            back_indices[p1] = vertices->size();
732            vertices->push_back((*orig_vertices)[p1]+forward);
733        }
734
735        if (back_indices[p2]==NULL_VALUE)
736        {
737            back_indices[p2] = vertices->size();
738            vertices->push_back((*orig_vertices)[p2]+forward);
739        }
740
741        if (back_indices[p3]==NULL_VALUE)
742        {
743            back_indices[p3] = vertices->size();
744            vertices->push_back((*orig_vertices)[p3]+forward);
745        }
746
747        backFace->push_back(back_indices[p1]);
748        backFace->push_back(back_indices[p3]);
749        backFace->push_back(back_indices[p2]);
750    }
751
752    bool shareVerticesWithFaces = true;
753
754    // now build up the bevel
755    for(osg::Geometry::PrimitiveSetList::iterator itr = bevelPrimitiveSets.begin();
756        itr != bevelPrimitiveSets.end();
757        ++itr)
758    {
759        osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
760        if (!bevel) continue;
761
762        unsigned int no_vertices_on_boundary = bevel->size()/2;
763
764        const osgText::Bevel::Vertices& profileVertices = profile.getVertices();
765        unsigned int no_vertices_on_bevel = profileVertices.size();
766
767        Indices bevelIndices;
768        bevelIndices.resize(no_vertices_on_boundary*no_vertices_on_bevel, NULL_VALUE);
769
770        // populate vertices
771        for(unsigned int i=0; i<no_vertices_on_boundary; ++i)
772        {
773            unsigned int topi = (*bevel)[i*2];
774            unsigned int basei = (*bevel)[i*2+1];
775
776            osg::Vec3& top_vertex = (*orig_vertices)[ topi ];
777            osg::Vec3& base_vertex = (*orig_vertices)[ basei ];
778            osg::Vec3 up = top_vertex-base_vertex;
779
780            if (shareVerticesWithFaces)
781            {
782                if (front_indices[basei]==NULL_VALUE)
783                {
784                    front_indices[basei] = vertices->size();
785                    vertices->push_back(base_vertex);
786                }
787
788                bevelIndices[i*no_vertices_on_bevel + 0] = front_indices[basei];
789
790                for(unsigned int j=1; j<no_vertices_on_bevel-1; ++j)
791                {
792                    const osg::Vec2& pv = profileVertices[j];
793                    osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
794                    bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
795                    vertices->push_back(pos);
796                }
797
798                if (back_indices[basei]==NULL_VALUE)
799                {
800                    back_indices[basei] = vertices->size();
801                    vertices->push_back(base_vertex + forward);
802                }
803
804                bevelIndices[i*no_vertices_on_bevel + no_vertices_on_bevel-1] = back_indices[basei];
805            }
806            else
807            {
808                for(unsigned int j=0; j<no_vertices_on_bevel; ++j)
809                {
810                    const osg::Vec2& pv = profileVertices[j];
811                    osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
812                    bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
813                    vertices->push_back(pos);
814                }
815            }
816        }
817
818        osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES);
819        elements->setName("wall");
820        unsigned int base, next;
821        for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i)
822        {
823            for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j)
824            {
825                base = i*no_vertices_on_bevel + j;
826                next = base + no_vertices_on_bevel;
827
828                elements->push_back(bevelIndices[base]);
829                elements->push_back(bevelIndices[next]);
830                elements->push_back(bevelIndices[base+1]);
831
832                elements->push_back(bevelIndices[base+1]);
833                elements->push_back(bevelIndices[next]);
834                elements->push_back(bevelIndices[next+1]);
835            }
836        }
837
838        text_geometry->addPrimitiveSet(elements);
839    }
840
841    return text_geometry.release();
842}
843
844/////////////////////////////////////////////////////////////////////////////////////////
845//
846// computeShellGeometry
847//
848OSGTEXT_EXPORT osg::Geometry* computeShellGeometry(osg::Geometry* glyphGeometry, const osgText::Bevel& profile, float width)
849{
850    osg::Vec3Array* orig_vertices = dynamic_cast<osg::Vec3Array*>(glyphGeometry->getVertexArray());
851    if (!orig_vertices)
852    {
853        OSG_NOTICE<<"computeTextGeometry(..): No vertices on glyphGeometry."<<std::endl;
854        return 0;
855    }
856
857    osg::ref_ptr<osg::Geometry> text_geometry = new osg::Geometry;
858    osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
859    text_geometry->setVertexArray(vertices.get());
860
861    typedef std::vector<unsigned int> Indices;
862    const unsigned int NULL_VALUE = UINT_MAX;
863    Indices front_indices, back_indices;
864    front_indices.resize(orig_vertices->size(), NULL_VALUE);
865    back_indices.resize(orig_vertices->size(), NULL_VALUE);
866
867    osg::DrawElementsUShort* face = 0;
868    osg::Geometry::PrimitiveSetList bevelPrimitiveSets;
869    osg::Geometry::PrimitiveSetList shellPrimitiveSets;
870    osg::Vec3 frontOffset(0,0,width);
871    osg::Vec3 backOffset(0,0,-2.0*width);
872    osg::Vec3 forward(backOffset-frontOffset);
873
874    // collect bevels and face primitive sets
875    for(osg::Geometry::PrimitiveSetList::iterator itr = glyphGeometry->getPrimitiveSetList().begin();
876        itr != glyphGeometry->getPrimitiveSetList().end();
877        ++itr)
878    {
879        osg::PrimitiveSet* prim = itr->get();
880        if (prim->getName()=="face") face = dynamic_cast<osg::DrawElementsUShort*>(prim);
881        else if (prim->getName()=="bevel") bevelPrimitiveSets.push_back(prim);
882        else if (prim->getName()=="shell") shellPrimitiveSets.push_back(prim);
883    }
884
885    // if we don't have a face we can't create any 3d text
886    if (!face) return 0;
887
888    // build up the vertices primitives for the front face, and record the indices
889    // for later use, and to ensure sharing of vertices in the face primitive set
890    // the order of the triangle indices are flipped to make sure that the triangles are back face
891    osg::DrawElementsUShort* frontFace = new osg::DrawElementsUShort(GL_TRIANGLES);
892    text_geometry->addPrimitiveSet(frontFace);
893    for(unsigned int i=0; i<face->size()-2;)
894    {
895        unsigned int p1 = (*face)[i++];
896        unsigned int p2 = (*face)[i++];
897        unsigned int p3 = (*face)[i++];
898        if (front_indices[p1]==NULL_VALUE)
899        {
900            front_indices[p1] = vertices->size();
901            vertices->push_back((*orig_vertices)[p1]+frontOffset);
902        }
903
904        if (front_indices[p2]==NULL_VALUE)
905        {
906            front_indices[p2] = vertices->size();
907            vertices->push_back((*orig_vertices)[p2]+frontOffset);
908        }
909
910        if (front_indices[p3]==NULL_VALUE)
911        {
912            front_indices[p3] = vertices->size();
913            vertices->push_back((*orig_vertices)[p3]+frontOffset);
914        }
915
916        frontFace->push_back(front_indices[p1]);
917        frontFace->push_back(front_indices[p3]);
918        frontFace->push_back(front_indices[p2]);
919    }
920
921
922    // build up the vertices primitives for the back face, and record the indices
923    // for later use, and to ensure sharing of vertices in the face primitive set
924    osg::DrawElementsUShort* backFace = new osg::DrawElementsUShort(GL_TRIANGLES);
925    text_geometry->addPrimitiveSet(backFace);
926    for(unsigned int i=0; i<face->size();)
927    {
928        unsigned int pi = (*face)[i++];
929        if (back_indices[pi]==NULL_VALUE)
930        {
931            back_indices[pi] = vertices->size();
932            vertices->push_back((*orig_vertices)[pi]+backOffset);
933        }
934        backFace->push_back(back_indices[pi]);
935    }
936
937    for(osg::Geometry::PrimitiveSetList::iterator itr = bevelPrimitiveSets.begin();
938        itr != bevelPrimitiveSets.end();
939        ++itr)
940    {
941        osg::DrawElementsUShort* strip = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
942        if (!strip) continue;
943
944        osg::CopyOp copyop(osg::CopyOp::DEEP_COPY_ALL);
945
946        osg::DrawElementsUShort* front_strip = dynamic_cast<osg::DrawElementsUShort*>(copyop(strip));
947        text_geometry->addPrimitiveSet(front_strip);
948        for(unsigned int i=0; i<front_strip->size(); ++i)
949        {
950            unsigned short& pi  = (*front_strip)[i];
951            if (front_indices[pi]==NULL_VALUE)
952            {
953                front_indices[pi] = vertices->size();
954                vertices->push_back((*orig_vertices)[pi]+frontOffset);
955            }
956            pi = front_indices[pi];
957        }
958
959        for(unsigned int i=0; i<front_strip->size()-1;)
960        {
961            unsigned short& p1  = (*front_strip)[i++];
962            unsigned short& p2  = (*front_strip)[i++];
963            std::swap(p1,p2);
964        }
965
966        osg::DrawElementsUShort* back_strip = dynamic_cast<osg::DrawElementsUShort*>(copyop(strip));
967        text_geometry->addPrimitiveSet(back_strip);
968        for(unsigned int i=0; i<back_strip->size(); ++i)
969        {
970            unsigned short& pi  = (*back_strip)[i];
971            if (back_indices[pi]==NULL_VALUE)
972            {
973                back_indices[pi] = vertices->size();
974                vertices->push_back((*orig_vertices)[pi]+backOffset);
975            }
976            pi = back_indices[pi];
977        }
978    }
979
980
981    // now build up the shell
982    for(osg::Geometry::PrimitiveSetList::iterator itr = shellPrimitiveSets.begin();
983        itr != shellPrimitiveSets.end();
984        ++itr)
985    {
986        osg::DrawElementsUShort* bevel = dynamic_cast<osg::DrawElementsUShort*>(itr->get());
987        if (!bevel) continue;
988
989        unsigned int no_vertices_on_boundary = bevel->size()/2;
990
991        const osgText::Bevel::Vertices& profileVertices = profile.getVertices();
992        unsigned int no_vertices_on_bevel = profileVertices.size();
993
994        Indices bevelIndices;
995        bevelIndices.resize(no_vertices_on_boundary*no_vertices_on_bevel, NULL_VALUE);
996
997        // populate vertices
998        for(unsigned int i=0; i<no_vertices_on_boundary; ++i)
999        {
1000            unsigned int topi = (*bevel)[i*2+1];
1001            unsigned int basei = (*bevel)[i*2];
1002
1003            osg::Vec3 top_vertex = (*orig_vertices)[ topi ] + frontOffset;
1004            osg::Vec3 base_vertex = (*orig_vertices)[ basei ] + frontOffset;
1005            osg::Vec3 up = top_vertex-base_vertex;
1006
1007            if (front_indices[basei]==NULL_VALUE)
1008            {
1009                front_indices[basei] = vertices->size();
1010                vertices->push_back(base_vertex);
1011            }
1012
1013            bevelIndices[i*no_vertices_on_bevel + 0] = front_indices[basei];
1014
1015            for(unsigned int j=1; j<no_vertices_on_bevel-1; ++j)
1016            {
1017                const osg::Vec2& pv = profileVertices[j];
1018                osg::Vec3 pos( base_vertex + (forward * pv.x()) + (up * pv.y()) );
1019                bevelIndices[i*no_vertices_on_bevel + j] = vertices->size();
1020                vertices->push_back(pos);
1021            }
1022
1023            if (back_indices[basei]==NULL_VALUE)
1024            {
1025                back_indices[basei] = vertices->size();
1026                vertices->push_back(base_vertex + forward);
1027            }
1028
1029            bevelIndices[i*no_vertices_on_bevel + no_vertices_on_bevel-1] = back_indices[basei];
1030        }
1031
1032        osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(GL_TRIANGLES);
1033        unsigned int base, next;
1034        for(unsigned int i = 0; i< no_vertices_on_boundary-1; ++i)
1035        {
1036            for(unsigned int j=0; j<no_vertices_on_bevel-1; ++j)
1037            {
1038                base = i*no_vertices_on_bevel + j;
1039                next = base + no_vertices_on_bevel;
1040
1041                elements->push_back(bevelIndices[base]);
1042                elements->push_back(bevelIndices[base+1]);
1043                elements->push_back(bevelIndices[next]);
1044
1045                elements->push_back(bevelIndices[base+1]);
1046                elements->push_back(bevelIndices[next+1]);
1047                elements->push_back(bevelIndices[next]);
1048            }
1049        }
1050
1051        text_geometry->addPrimitiveSet(elements);
1052    }
1053
1054#if 1
1055    osg::Vec4Array* new_colours = new osg::Vec4Array;
1056    new_colours->push_back(osg::Vec4(1.0,1.0,1.0,0.2));
1057    text_geometry->setColorArray(new_colours);
1058    text_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
1059
1060
1061    osg::StateSet* stateset = text_geometry->getOrCreateStateSet();
1062    stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
1063    stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
1064    stateset->setAttributeAndModes(new osg::CullFace, osg::StateAttribute::ON);
1065    //stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1066    stateset->setRenderBinDetails(11, "SORT_FRONT_TO_BACK");
1067#endif
1068    return text_geometry.release();
1069}
1070
1071}
Note: See TracBrowser for help on using the browser.